@tsed/platform-cache 7.0.0-alpha.2 → 7.0.0-beta.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.
Files changed (42) hide show
  1. package/lib/cjs/decorators/useCache.js +11 -0
  2. package/lib/cjs/decorators/useCache.js.map +1 -0
  3. package/lib/cjs/index.js +7 -0
  4. package/lib/cjs/index.js.map +1 -0
  5. package/lib/cjs/interceptors/PlatformCacheInterceptor.js +134 -0
  6. package/lib/cjs/interceptors/PlatformCacheInterceptor.js.map +1 -0
  7. package/lib/cjs/interfaces/PlatformCacheOptions.js +3 -0
  8. package/lib/cjs/interfaces/PlatformCacheOptions.js.map +1 -0
  9. package/lib/cjs/interfaces/PlatformCachedObject.js +3 -0
  10. package/lib/cjs/interfaces/PlatformCachedObject.js.map +1 -0
  11. package/lib/cjs/interfaces/index.js +5 -0
  12. package/lib/cjs/interfaces/index.js.map +1 -0
  13. package/lib/cjs/services/PlatformCache.js +96 -0
  14. package/lib/cjs/services/PlatformCache.js.map +1 -0
  15. package/lib/esm/decorators/useCache.js +7 -0
  16. package/lib/esm/decorators/useCache.js.map +1 -0
  17. package/lib/esm/index.js +4 -0
  18. package/lib/esm/index.js.map +1 -0
  19. package/lib/esm/interceptors/PlatformCacheInterceptor.js +131 -0
  20. package/lib/esm/interceptors/PlatformCacheInterceptor.js.map +1 -0
  21. package/lib/esm/interfaces/PlatformCacheOptions.js +2 -0
  22. package/lib/esm/interfaces/PlatformCacheOptions.js.map +1 -0
  23. package/lib/esm/interfaces/PlatformCachedObject.js +2 -0
  24. package/lib/esm/interfaces/PlatformCachedObject.js.map +1 -0
  25. package/lib/esm/interfaces/index.js +2 -0
  26. package/lib/esm/interfaces/index.js.map +1 -0
  27. package/lib/esm/services/PlatformCache.js +93 -0
  28. package/lib/esm/services/PlatformCache.js.map +1 -0
  29. package/lib/{decorators → types/decorators}/useCache.d.ts +0 -0
  30. package/lib/{index.d.ts → types/index.d.ts} +0 -1
  31. package/lib/{interceptors → types/interceptors}/PlatformCacheInterceptor.d.ts +0 -0
  32. package/lib/{interfaces → types/interfaces}/PlatformCacheOptions.d.ts +1 -1
  33. package/lib/{interfaces → types/interfaces}/PlatformCachedObject.d.ts +0 -0
  34. package/lib/{interfaces → types/interfaces}/index.d.ts +2 -2
  35. package/lib/{services → types/services}/PlatformCache.d.ts +5 -3
  36. package/package.json +21 -20
  37. package/tsconfig.compile.esm.json +23 -0
  38. package/lib/PlatformCacheModule.d.ts +0 -5
  39. package/lib/index.js +0 -348
  40. package/lib/index.js.map +0 -1
  41. package/lib/index.modern.js +0 -345
  42. package/lib/index.modern.js.map +0 -1
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.UseCache = void 0;
4
+ const core_1 = require("@tsed/core");
5
+ const di_1 = require("@tsed/di");
6
+ const PlatformCacheInterceptor_1 = require("../interceptors/PlatformCacheInterceptor");
7
+ function UseCache(options = {}) {
8
+ return (0, core_1.useDecorators)((0, di_1.Intercept)(PlatformCacheInterceptor_1.PlatformCacheInterceptor, options));
9
+ }
10
+ exports.UseCache = UseCache;
11
+ //# sourceMappingURL=useCache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useCache.js","sourceRoot":"","sources":["../../../src/decorators/useCache.ts"],"names":[],"mappings":";;;AAAA,qCAAyC;AACzC,iCAAmC;AACnC,uFAAkF;AAGlF,SAAgB,QAAQ,CAAC,UAAgC,EAAE;IACzD,OAAO,IAAA,oBAAa,EAAC,IAAA,cAAS,EAAC,mDAAwB,EAAE,OAAO,CAAC,CAAC,CAAC;AACrE,CAAC;AAFD,4BAEC","sourcesContent":["import {useDecorators} from \"@tsed/core\";\nimport {Intercept} from \"@tsed/di\";\nimport {PlatformCacheInterceptor} from \"../interceptors/PlatformCacheInterceptor\";\nimport {PlatformCacheOptions} from \"../interfaces/PlatformCacheOptions\";\n\nexport function UseCache(options: PlatformCacheOptions = {}) {\n return useDecorators(Intercept(PlatformCacheInterceptor, options));\n}\n"]}
@@ -0,0 +1,7 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const tslib_1 = require("tslib");
4
+ (0, tslib_1.__exportStar)(require("./interfaces"), exports);
5
+ (0, tslib_1.__exportStar)(require("./services/PlatformCache"), exports);
6
+ (0, tslib_1.__exportStar)(require("./decorators/useCache"), exports);
7
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";;;AAAA,4DAA6B;AAC7B,wEAAyC;AACzC,qEAAsC","sourcesContent":["export * from \"./interfaces\";\nexport * from \"./services/PlatformCache\";\nexport * from \"./decorators/useCache\";\n"]}
@@ -0,0 +1,134 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PlatformCacheInterceptor = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const core_1 = require("@tsed/core");
6
+ const di_1 = require("@tsed/di");
7
+ const json_mapper_1 = require("@tsed/json-mapper");
8
+ const schema_1 = require("@tsed/schema");
9
+ const http_1 = require("http");
10
+ const PlatformCache_1 = require("../services/PlatformCache");
11
+ const cleanHeaders = (headers) => {
12
+ return Object.entries(headers)
13
+ .filter(([key]) => !["content-length", "x-request-id", "cache-control"].includes(key))
14
+ .reduce((headers, [key, value]) => {
15
+ return {
16
+ ...headers,
17
+ [key]: value
18
+ };
19
+ }, {});
20
+ };
21
+ /**
22
+ * @platform
23
+ */
24
+ let PlatformCacheInterceptor = class PlatformCacheInterceptor {
25
+ async intercept(context, next) {
26
+ if (this.cache.disabled()) {
27
+ return next();
28
+ }
29
+ if (!this.isEndpoint(context)) {
30
+ return this.cacheMethod(context, next);
31
+ }
32
+ return this.cacheResponse(context, next);
33
+ }
34
+ getArgs(context) {
35
+ return context.args.reduce((args, arg) => {
36
+ if (arg instanceof di_1.DIContext || arg instanceof http_1.IncomingMessage || arg instanceof http_1.ServerResponse) {
37
+ return args;
38
+ }
39
+ if ((0, core_1.isClass)(arg)) {
40
+ return args.concat((0, json_mapper_1.serialize)(arg));
41
+ }
42
+ return args.concat(arg);
43
+ }, []);
44
+ }
45
+ getOptions(context) {
46
+ const { ttl, type, collectionType, key: k = this.cache.defaultKeyResolver() } = context.options || {};
47
+ const args = this.getArgs(context);
48
+ const keyArgs = (0, core_1.isString)(k) ? k : k(args);
49
+ return { ttl, type, args, collectionType, keyArgs };
50
+ }
51
+ isEndpoint({ target, propertyKey }) {
52
+ return core_1.Store.fromMethod(target, propertyKey).has(schema_1.JsonEntityStore);
53
+ }
54
+ async cacheMethod(context, next) {
55
+ const { ttl, type, collectionType, keyArgs, args } = this.getOptions(context);
56
+ const key = [(0, core_1.nameOf)(context.target), context.propertyKey, keyArgs].join(":");
57
+ const cachedObject = await this.cache.get(key);
58
+ if (cachedObject) {
59
+ const { data } = cachedObject;
60
+ return (0, json_mapper_1.deserialize)(JSON.parse(data), { collectionType, type });
61
+ }
62
+ const result = await next();
63
+ const calculatedTtl = this.cache.ttl(result, ttl);
64
+ await this.cache.set(key, {
65
+ ttl: calculatedTtl,
66
+ args,
67
+ data: JSON.stringify((0, json_mapper_1.serialize)(result, { type, collectionType }))
68
+ }, {
69
+ ttl: calculatedTtl
70
+ });
71
+ return result;
72
+ }
73
+ async cacheResponse(context, next) {
74
+ const $ctx = context.args[context.args.length - 1];
75
+ const { request, response } = $ctx;
76
+ if (request.method !== "GET") {
77
+ return next();
78
+ }
79
+ const { ttl, args, keyArgs } = this.getOptions(context);
80
+ const key = [request.method, request.url, keyArgs].join(":");
81
+ const cachedObject = await this.cache.get(key);
82
+ if (cachedObject && !(response.get("cache-control") === "no-cache")) {
83
+ return this.sendResponse(cachedObject, $ctx);
84
+ }
85
+ const result = await next();
86
+ const calculatedTtl = this.cache.ttl(result, ttl);
87
+ const expires = calculatedTtl + Date.now() / 1000;
88
+ $ctx.response.setHeaders({
89
+ "cache-control": `max-age=${calculatedTtl}`
90
+ });
91
+ // cache final response with his headers and body
92
+ response.onEnd(async () => {
93
+ const data = JSON.stringify(response.getBody());
94
+ const headers = cleanHeaders(response.getHeaders());
95
+ await this.cache.set(key, {
96
+ ttl: calculatedTtl,
97
+ args,
98
+ data,
99
+ expires,
100
+ headers
101
+ }, {
102
+ ttl: calculatedTtl
103
+ });
104
+ });
105
+ return result;
106
+ }
107
+ sendResponse(cachedObject, $ctx) {
108
+ const { headers, ttl } = cachedObject;
109
+ const { request, response } = $ctx;
110
+ const requestEtag = request.get("if-none-match");
111
+ if (requestEtag && headers.etag === requestEtag) {
112
+ response.status(304).setHeaders(headers).body(undefined);
113
+ return undefined;
114
+ }
115
+ const data = JSON.parse(cachedObject.data);
116
+ $ctx.response
117
+ .setHeaders({
118
+ ...headers,
119
+ "x-cached": "true",
120
+ "cache-control": `max-age=${ttl}`
121
+ })
122
+ .body(data);
123
+ return data;
124
+ }
125
+ };
126
+ (0, tslib_1.__decorate)([
127
+ (0, di_1.Inject)(),
128
+ (0, tslib_1.__metadata)("design:type", PlatformCache_1.PlatformCache)
129
+ ], PlatformCacheInterceptor.prototype, "cache", void 0);
130
+ PlatformCacheInterceptor = (0, tslib_1.__decorate)([
131
+ (0, di_1.Interceptor)()
132
+ ], PlatformCacheInterceptor);
133
+ exports.PlatformCacheInterceptor = PlatformCacheInterceptor;
134
+ //# sourceMappingURL=PlatformCacheInterceptor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PlatformCacheInterceptor.js","sourceRoot":"","sources":["../../../src/interceptors/PlatformCacheInterceptor.ts"],"names":[],"mappings":"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","sourcesContent":["import {isClass, isString, nameOf, Store} from \"@tsed/core\";\nimport {BaseContext, DIContext, Inject, Interceptor, InterceptorContext, InterceptorMethods, InterceptorNext} from \"@tsed/di\";\nimport {deserialize, serialize} from \"@tsed/json-mapper\";\nimport {JsonEntityStore} from \"@tsed/schema\";\nimport {IncomingMessage, ServerResponse} from \"http\";\nimport {PlatformCachedObject} from \"../interfaces/PlatformCachedObject\";\nimport {PlatformCacheOptions} from \"../interfaces/PlatformCacheOptions\";\nimport {PlatformCache} from \"../services/PlatformCache\";\n\nconst cleanHeaders = (headers: Record<string, unknown>) => {\n return Object.entries(headers)\n .filter(([key]) => ![\"content-length\", \"x-request-id\", \"cache-control\"].includes(key))\n .reduce((headers, [key, value]) => {\n return {\n ...headers,\n [key]: value\n };\n }, {});\n};\n\n/**\n * @platform\n */\n@Interceptor()\nexport class PlatformCacheInterceptor implements InterceptorMethods {\n @Inject()\n protected cache: PlatformCache;\n\n async intercept(context: InterceptorContext<any, PlatformCacheOptions>, next: InterceptorNext) {\n if (this.cache.disabled()) {\n return next();\n }\n\n if (!this.isEndpoint(context)) {\n return this.cacheMethod(context, next);\n }\n\n return this.cacheResponse(context, next);\n }\n\n protected getArgs(context: InterceptorContext<unknown, PlatformCacheOptions>) {\n return context.args.reduce((args, arg) => {\n if (arg instanceof DIContext || arg instanceof IncomingMessage || arg instanceof ServerResponse) {\n return args;\n }\n\n if (isClass(arg)) {\n return args.concat(serialize(arg));\n }\n\n return args.concat(arg);\n }, []);\n }\n\n protected getOptions(context: InterceptorContext<any, PlatformCacheOptions>) {\n const {ttl, type, collectionType, key: k = this.cache.defaultKeyResolver()} = context.options || {};\n\n const args = this.getArgs(context);\n const keyArgs = isString(k) ? k : k(args);\n\n return {ttl, type, args, collectionType, keyArgs};\n }\n\n protected isEndpoint({target, propertyKey}: InterceptorContext<any, PlatformCacheOptions>) {\n return Store.fromMethod(target, propertyKey).has(JsonEntityStore);\n }\n\n protected async cacheMethod(context: InterceptorContext<any, PlatformCacheOptions>, next: InterceptorNext) {\n const {ttl, type, collectionType, keyArgs, args} = this.getOptions(context);\n const key = [nameOf(context.target), context.propertyKey, keyArgs].join(\":\");\n\n const cachedObject = await this.cache.get<PlatformCachedObject>(key);\n\n if (cachedObject) {\n const {data} = cachedObject;\n\n return deserialize(JSON.parse(data), {collectionType, type});\n }\n\n const result = await next();\n const calculatedTtl = this.cache.ttl(result, ttl);\n\n await this.cache.set<PlatformCachedObject>(\n key,\n {\n ttl: calculatedTtl,\n args,\n data: JSON.stringify(serialize(result, {type, collectionType}))\n },\n {\n ttl: calculatedTtl\n }\n );\n\n return result;\n }\n\n protected async cacheResponse(context: InterceptorContext<any, PlatformCacheOptions>, next: InterceptorNext) {\n const $ctx: BaseContext = context.args[context.args.length - 1];\n const {request, response} = $ctx;\n\n if (request.method !== \"GET\") {\n return next();\n }\n\n const {ttl, args, keyArgs} = this.getOptions(context);\n\n const key = [request.method, request.url, keyArgs].join(\":\");\n\n const cachedObject = await this.cache.get<PlatformCachedObject>(key);\n\n if (cachedObject && !(response.get(\"cache-control\") === \"no-cache\")) {\n return this.sendResponse(cachedObject, $ctx);\n }\n\n const result = await next();\n\n const calculatedTtl = this.cache.ttl(result, ttl);\n const expires = calculatedTtl + Date.now() / 1000;\n $ctx.response.setHeaders({\n \"cache-control\": `max-age=${calculatedTtl}`\n });\n\n // cache final response with his headers and body\n response.onEnd(async () => {\n const data = JSON.stringify(response.getBody());\n const headers = cleanHeaders(response.getHeaders());\n\n await this.cache.set<PlatformCachedObject>(\n key,\n {\n ttl: calculatedTtl,\n args,\n data,\n expires,\n headers\n },\n {\n ttl: calculatedTtl\n }\n );\n });\n\n return result;\n }\n\n protected sendResponse(cachedObject: PlatformCachedObject, $ctx: BaseContext) {\n const {headers, ttl} = cachedObject;\n const {request, response} = $ctx;\n\n const requestEtag = request.get(\"if-none-match\");\n\n if (requestEtag && headers.etag === requestEtag) {\n response.status(304).setHeaders(headers).body(undefined);\n\n return undefined;\n }\n\n const data = JSON.parse(cachedObject.data);\n\n $ctx.response\n .setHeaders({\n ...headers,\n \"x-cached\": \"true\",\n \"cache-control\": `max-age=${ttl}`\n })\n .body(data);\n\n return data;\n }\n}\n"]}
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=PlatformCacheOptions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PlatformCacheOptions.js","sourceRoot":"","sources":["../../../src/interfaces/PlatformCacheOptions.ts"],"names":[],"mappings":"","sourcesContent":["import {MetadataTypes} from \"@tsed/core\";\nimport {BaseContext} from \"@tsed/di\";\nimport type {TtlFunction} from \"cache-manager\";\n\nexport interface PlatformCacheOptions extends MetadataTypes {\n ttl?: number | TtlFunction;\n key?: string | ((args: any[], ctx?: BaseContext) => string);\n}\n"]}
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=PlatformCachedObject.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PlatformCachedObject.js","sourceRoot":"","sources":["../../../src/interfaces/PlatformCachedObject.ts"],"names":[],"mappings":"","sourcesContent":["export interface PlatformCachedObject {\n ttl: number;\n args: any[];\n data: any;\n expires: number;\n headers: Record<string, number | string | string[]>;\n}\n"]}
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const tslib_1 = require("tslib");
4
+ (0, tslib_1.__exportStar)(require("./PlatformCachedObject"), exports);
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/interfaces/index.ts"],"names":[],"mappings":";;;AAGA,sEAAuC","sourcesContent":["import type {BaseContext} from \"@tsed/di\";\nimport type {Cache, CacheOptions, CachingConfig, Store} from \"cache-manager\";\n\nexport * from \"./PlatformCachedObject\";\n\nexport interface PlatformCacheSettings extends CacheOptions, CachingConfig {\n caches?: Cache[];\n store?:\n | \"memory\"\n | \"none\"\n | Store\n | {\n create(...args: any[]): Store;\n }\n | (() => any);\n max?: number;\n keyResolver?: (args: any[], ctx: BaseContext) => string;\n\n /**\n * You may pass in any other arguments these will be passed on to the `create` method of your store,\n * otherwise they will be ignored.\n */\n [key: string]: any;\n}\n\ndeclare global {\n // eslint-disable-next-line @typescript-eslint/no-namespace\n namespace TsED {\n interface Configuration {\n cache?: PlatformCacheSettings | false;\n }\n }\n}\n"]}
@@ -0,0 +1,96 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PlatformCache = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const core_1 = require("@tsed/core");
6
+ const di_1 = require("@tsed/di");
7
+ const json_mapper_1 = require("@tsed/json-mapper");
8
+ const defaultKeyResolver = (args) => {
9
+ return args.map((arg) => ((0, core_1.isClass)(arg) ? JSON.stringify((0, json_mapper_1.serialize)(arg)) : arg)).join(":");
10
+ };
11
+ /**
12
+ * @platform
13
+ */
14
+ let PlatformCache = class PlatformCache {
15
+ disabled() {
16
+ return !this.settings.get("cache");
17
+ }
18
+ async $onInit() {
19
+ const settings = this.settings.get("cache");
20
+ if (settings) {
21
+ this.cache = await this.createCacheManager(settings);
22
+ }
23
+ }
24
+ defaultKeyResolver() {
25
+ return this.settings.get("cache.keyResolver", defaultKeyResolver);
26
+ }
27
+ defaultTtl() {
28
+ return this.settings.get("cache.ttl");
29
+ }
30
+ ttl(result, currentTtl) {
31
+ const ttl = currentTtl === undefined ? this.defaultTtl() : currentTtl;
32
+ return (0, core_1.isFunction)(ttl) ? ttl(result) : ttl;
33
+ }
34
+ wrap(key, fetch, options) {
35
+ var _a;
36
+ if (!this.cache) {
37
+ return fetch();
38
+ }
39
+ return (_a = this.cache) === null || _a === void 0 ? void 0 : _a.wrap(key, fetch, options);
40
+ }
41
+ async get(key, options = {}) {
42
+ var _a;
43
+ return (0, json_mapper_1.deserialize)((_a = this.cache) === null || _a === void 0 ? void 0 : _a.get(key), options);
44
+ }
45
+ async set(key, value, options) {
46
+ var _a;
47
+ return (_a = this.cache) === null || _a === void 0 ? void 0 : _a.set(key, value, options);
48
+ }
49
+ async del(key) {
50
+ var _a;
51
+ await ((_a = this.cache) === null || _a === void 0 ? void 0 : _a.del(key));
52
+ }
53
+ async reset() {
54
+ var _a;
55
+ // @ts-ignore
56
+ await ((_a = this.cache) === null || _a === void 0 ? void 0 : _a.reset());
57
+ }
58
+ async keys() {
59
+ var _a;
60
+ if ((_a = this.cache) === null || _a === void 0 ? void 0 : _a.keys) {
61
+ return this.cache.keys();
62
+ }
63
+ // istanbul ignore next
64
+ return [];
65
+ }
66
+ async getMatchingKeys(patterns) {
67
+ const [keys, { default: micromatch }] = await Promise.all([this.keys(), Promise.resolve().then(() => (0, tslib_1.__importStar)(require("micromatch")))]);
68
+ return micromatch(keys, patterns);
69
+ }
70
+ async deleteMatchingKeys(patterns) {
71
+ const keys = await this.getMatchingKeys(patterns);
72
+ await Promise.all(keys.map((key) => this.del(key)));
73
+ return keys;
74
+ }
75
+ async createCacheManager(settings) {
76
+ const { caches, store = "memory", ttl, ...props } = settings;
77
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
78
+ const { default: cacheManager } = await Promise.resolve().then(() => (0, tslib_1.__importStar)(require("cache-manager")));
79
+ return (caches === null || caches === void 0 ? void 0 : caches.length)
80
+ ? cacheManager.multiCaching(caches, { ...props })
81
+ : cacheManager.caching({
82
+ ...props,
83
+ ttl,
84
+ store: (0, core_1.isFunction)(store) ? await store() : store
85
+ });
86
+ }
87
+ };
88
+ (0, tslib_1.__decorate)([
89
+ (0, di_1.Configuration)(),
90
+ (0, tslib_1.__metadata)("design:type", Object)
91
+ ], PlatformCache.prototype, "settings", void 0);
92
+ PlatformCache = (0, tslib_1.__decorate)([
93
+ (0, di_1.Module)()
94
+ ], PlatformCache);
95
+ exports.PlatformCache = PlatformCache;
96
+ //# sourceMappingURL=PlatformCache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PlatformCache.js","sourceRoot":"","sources":["../../../src/services/PlatformCache.ts"],"names":[],"mappings":"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","sourcesContent":["import {isClass, isFunction} from \"@tsed/core\";\nimport {Configuration, Module} from \"@tsed/di\";\nimport {deserialize, JsonDeserializerOptions, serialize} from \"@tsed/json-mapper\";\nimport type {Cache, CachingConfig, MultiCache, TtlFunction} from \"cache-manager\";\nimport {PlatformCacheSettings} from \"../interfaces\";\n\nconst defaultKeyResolver = (args: any[]) => {\n return args.map((arg: any) => (isClass(arg) ? JSON.stringify(serialize(arg)) : arg)).join(\":\");\n};\n\nexport type CacheManager = (Cache | MultiCache) & {\n keys?(): Promise<string[]>;\n};\n\n/**\n * @platform\n */\n@Module()\nexport class PlatformCache {\n @Configuration()\n settings: Configuration;\n\n cache: CacheManager | undefined;\n\n disabled(): boolean {\n return !this.settings.get<PlatformCacheSettings>(\"cache\");\n }\n\n async $onInit() {\n const settings = this.settings.get<PlatformCacheSettings>(\"cache\");\n\n if (settings) {\n this.cache = await this.createCacheManager(settings);\n }\n }\n\n defaultKeyResolver() {\n return this.settings.get<(args: any[], ctx?: any) => string>(\"cache.keyResolver\", defaultKeyResolver);\n }\n\n defaultTtl() {\n return this.settings.get<number | TtlFunction>(\"cache.ttl\");\n }\n\n ttl(result?: any, currentTtl?: number | TtlFunction) {\n const ttl = currentTtl === undefined ? this.defaultTtl() : currentTtl;\n\n return isFunction(ttl) ? ttl(result) : ttl;\n }\n\n wrap<T>(key: string, fetch: () => Promise<T>, options?: CachingConfig): Promise<T> {\n if (!this.cache) {\n return fetch();\n }\n\n return this.cache?.wrap<T>(key, fetch, options as any);\n }\n\n async get<T>(key: string, options: JsonDeserializerOptions = {}): Promise<T | undefined> {\n return deserialize(this.cache?.get<T>(key), options);\n }\n\n async set<T>(key: string, value: any, options?: CachingConfig): Promise<T | undefined> {\n return this.cache?.set<T>(key, value, options);\n }\n\n async del(key: string): Promise<void> {\n await this.cache?.del(key);\n }\n\n async reset(): Promise<void> {\n // @ts-ignore\n await this.cache?.reset();\n }\n\n async keys(): Promise<string[]> {\n if (this.cache?.keys) {\n return this.cache.keys();\n }\n // istanbul ignore next\n return [];\n }\n\n async getMatchingKeys(patterns: string): Promise<string[]> {\n const [keys, {default: micromatch}] = await Promise.all([this.keys(), import(\"micromatch\")]);\n\n return micromatch(keys, patterns);\n }\n\n async deleteMatchingKeys(patterns: string): Promise<string[]> {\n const keys = await this.getMatchingKeys(patterns);\n\n await Promise.all(keys.map((key: string) => this.del(key)));\n\n return keys;\n }\n\n protected async createCacheManager(settings: PlatformCacheSettings) {\n const {caches, store = \"memory\", ttl, ...props} = settings;\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n const {default: cacheManager} = await import(\"cache-manager\");\n\n return caches?.length\n ? cacheManager.multiCaching(caches, {...props})\n : cacheManager.caching({\n ...props,\n ttl,\n store: isFunction(store) ? await store() : store\n });\n }\n}\n"]}
@@ -0,0 +1,7 @@
1
+ import { useDecorators } from "@tsed/core";
2
+ import { Intercept } from "@tsed/di";
3
+ import { PlatformCacheInterceptor } from "../interceptors/PlatformCacheInterceptor";
4
+ export function UseCache(options = {}) {
5
+ return useDecorators(Intercept(PlatformCacheInterceptor, options));
6
+ }
7
+ //# sourceMappingURL=useCache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useCache.js","sourceRoot":"","sources":["../../../src/decorators/useCache.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,aAAa,EAAC,MAAM,YAAY,CAAC;AACzC,OAAO,EAAC,SAAS,EAAC,MAAM,UAAU,CAAC;AACnC,OAAO,EAAC,wBAAwB,EAAC,MAAM,0CAA0C,CAAC;AAGlF,MAAM,UAAU,QAAQ,CAAC,UAAgC,EAAE;IACzD,OAAO,aAAa,CAAC,SAAS,CAAC,wBAAwB,EAAE,OAAO,CAAC,CAAC,CAAC;AACrE,CAAC","sourcesContent":["import {useDecorators} from \"@tsed/core\";\nimport {Intercept} from \"@tsed/di\";\nimport {PlatformCacheInterceptor} from \"../interceptors/PlatformCacheInterceptor\";\nimport {PlatformCacheOptions} from \"../interfaces/PlatformCacheOptions\";\n\nexport function UseCache(options: PlatformCacheOptions = {}) {\n return useDecorators(Intercept(PlatformCacheInterceptor, options));\n}\n"]}
@@ -0,0 +1,4 @@
1
+ export * from "./interfaces";
2
+ export * from "./services/PlatformCache";
3
+ export * from "./decorators/useCache";
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAC;AAC7B,cAAc,0BAA0B,CAAC;AACzC,cAAc,uBAAuB,CAAC","sourcesContent":["export * from \"./interfaces\";\nexport * from \"./services/PlatformCache\";\nexport * from \"./decorators/useCache\";\n"]}
@@ -0,0 +1,131 @@
1
+ import { __decorate, __metadata } from "tslib";
2
+ import { isClass, isString, nameOf, Store } from "@tsed/core";
3
+ import { DIContext, Inject, Interceptor } from "@tsed/di";
4
+ import { deserialize, serialize } from "@tsed/json-mapper";
5
+ import { JsonEntityStore } from "@tsed/schema";
6
+ import { IncomingMessage, ServerResponse } from "http";
7
+ import { PlatformCache } from "../services/PlatformCache";
8
+ const cleanHeaders = (headers) => {
9
+ return Object.entries(headers)
10
+ .filter(([key]) => !["content-length", "x-request-id", "cache-control"].includes(key))
11
+ .reduce((headers, [key, value]) => {
12
+ return {
13
+ ...headers,
14
+ [key]: value
15
+ };
16
+ }, {});
17
+ };
18
+ /**
19
+ * @platform
20
+ */
21
+ let PlatformCacheInterceptor = class PlatformCacheInterceptor {
22
+ async intercept(context, next) {
23
+ if (this.cache.disabled()) {
24
+ return next();
25
+ }
26
+ if (!this.isEndpoint(context)) {
27
+ return this.cacheMethod(context, next);
28
+ }
29
+ return this.cacheResponse(context, next);
30
+ }
31
+ getArgs(context) {
32
+ return context.args.reduce((args, arg) => {
33
+ if (arg instanceof DIContext || arg instanceof IncomingMessage || arg instanceof ServerResponse) {
34
+ return args;
35
+ }
36
+ if (isClass(arg)) {
37
+ return args.concat(serialize(arg));
38
+ }
39
+ return args.concat(arg);
40
+ }, []);
41
+ }
42
+ getOptions(context) {
43
+ const { ttl, type, collectionType, key: k = this.cache.defaultKeyResolver() } = context.options || {};
44
+ const args = this.getArgs(context);
45
+ const keyArgs = isString(k) ? k : k(args);
46
+ return { ttl, type, args, collectionType, keyArgs };
47
+ }
48
+ isEndpoint({ target, propertyKey }) {
49
+ return Store.fromMethod(target, propertyKey).has(JsonEntityStore);
50
+ }
51
+ async cacheMethod(context, next) {
52
+ const { ttl, type, collectionType, keyArgs, args } = this.getOptions(context);
53
+ const key = [nameOf(context.target), context.propertyKey, keyArgs].join(":");
54
+ const cachedObject = await this.cache.get(key);
55
+ if (cachedObject) {
56
+ const { data } = cachedObject;
57
+ return deserialize(JSON.parse(data), { collectionType, type });
58
+ }
59
+ const result = await next();
60
+ const calculatedTtl = this.cache.ttl(result, ttl);
61
+ await this.cache.set(key, {
62
+ ttl: calculatedTtl,
63
+ args,
64
+ data: JSON.stringify(serialize(result, { type, collectionType }))
65
+ }, {
66
+ ttl: calculatedTtl
67
+ });
68
+ return result;
69
+ }
70
+ async cacheResponse(context, next) {
71
+ const $ctx = context.args[context.args.length - 1];
72
+ const { request, response } = $ctx;
73
+ if (request.method !== "GET") {
74
+ return next();
75
+ }
76
+ const { ttl, args, keyArgs } = this.getOptions(context);
77
+ const key = [request.method, request.url, keyArgs].join(":");
78
+ const cachedObject = await this.cache.get(key);
79
+ if (cachedObject && !(response.get("cache-control") === "no-cache")) {
80
+ return this.sendResponse(cachedObject, $ctx);
81
+ }
82
+ const result = await next();
83
+ const calculatedTtl = this.cache.ttl(result, ttl);
84
+ const expires = calculatedTtl + Date.now() / 1000;
85
+ $ctx.response.setHeaders({
86
+ "cache-control": `max-age=${calculatedTtl}`
87
+ });
88
+ // cache final response with his headers and body
89
+ response.onEnd(async () => {
90
+ const data = JSON.stringify(response.getBody());
91
+ const headers = cleanHeaders(response.getHeaders());
92
+ await this.cache.set(key, {
93
+ ttl: calculatedTtl,
94
+ args,
95
+ data,
96
+ expires,
97
+ headers
98
+ }, {
99
+ ttl: calculatedTtl
100
+ });
101
+ });
102
+ return result;
103
+ }
104
+ sendResponse(cachedObject, $ctx) {
105
+ const { headers, ttl } = cachedObject;
106
+ const { request, response } = $ctx;
107
+ const requestEtag = request.get("if-none-match");
108
+ if (requestEtag && headers.etag === requestEtag) {
109
+ response.status(304).setHeaders(headers).body(undefined);
110
+ return undefined;
111
+ }
112
+ const data = JSON.parse(cachedObject.data);
113
+ $ctx.response
114
+ .setHeaders({
115
+ ...headers,
116
+ "x-cached": "true",
117
+ "cache-control": `max-age=${ttl}`
118
+ })
119
+ .body(data);
120
+ return data;
121
+ }
122
+ };
123
+ __decorate([
124
+ Inject(),
125
+ __metadata("design:type", PlatformCache)
126
+ ], PlatformCacheInterceptor.prototype, "cache", void 0);
127
+ PlatformCacheInterceptor = __decorate([
128
+ Interceptor()
129
+ ], PlatformCacheInterceptor);
130
+ export { PlatformCacheInterceptor };
131
+ //# sourceMappingURL=PlatformCacheInterceptor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PlatformCacheInterceptor.js","sourceRoot":"","sources":["../../../src/interceptors/PlatformCacheInterceptor.ts"],"names":[],"mappings":"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","sourcesContent":["import {isClass, isString, nameOf, Store} from \"@tsed/core\";\nimport {BaseContext, DIContext, Inject, Interceptor, InterceptorContext, InterceptorMethods, InterceptorNext} from \"@tsed/di\";\nimport {deserialize, serialize} from \"@tsed/json-mapper\";\nimport {JsonEntityStore} from \"@tsed/schema\";\nimport {IncomingMessage, ServerResponse} from \"http\";\nimport {PlatformCachedObject} from \"../interfaces/PlatformCachedObject\";\nimport {PlatformCacheOptions} from \"../interfaces/PlatformCacheOptions\";\nimport {PlatformCache} from \"../services/PlatformCache\";\n\nconst cleanHeaders = (headers: Record<string, unknown>) => {\n return Object.entries(headers)\n .filter(([key]) => ![\"content-length\", \"x-request-id\", \"cache-control\"].includes(key))\n .reduce((headers, [key, value]) => {\n return {\n ...headers,\n [key]: value\n };\n }, {});\n};\n\n/**\n * @platform\n */\n@Interceptor()\nexport class PlatformCacheInterceptor implements InterceptorMethods {\n @Inject()\n protected cache: PlatformCache;\n\n async intercept(context: InterceptorContext<any, PlatformCacheOptions>, next: InterceptorNext) {\n if (this.cache.disabled()) {\n return next();\n }\n\n if (!this.isEndpoint(context)) {\n return this.cacheMethod(context, next);\n }\n\n return this.cacheResponse(context, next);\n }\n\n protected getArgs(context: InterceptorContext<unknown, PlatformCacheOptions>) {\n return context.args.reduce((args, arg) => {\n if (arg instanceof DIContext || arg instanceof IncomingMessage || arg instanceof ServerResponse) {\n return args;\n }\n\n if (isClass(arg)) {\n return args.concat(serialize(arg));\n }\n\n return args.concat(arg);\n }, []);\n }\n\n protected getOptions(context: InterceptorContext<any, PlatformCacheOptions>) {\n const {ttl, type, collectionType, key: k = this.cache.defaultKeyResolver()} = context.options || {};\n\n const args = this.getArgs(context);\n const keyArgs = isString(k) ? k : k(args);\n\n return {ttl, type, args, collectionType, keyArgs};\n }\n\n protected isEndpoint({target, propertyKey}: InterceptorContext<any, PlatformCacheOptions>) {\n return Store.fromMethod(target, propertyKey).has(JsonEntityStore);\n }\n\n protected async cacheMethod(context: InterceptorContext<any, PlatformCacheOptions>, next: InterceptorNext) {\n const {ttl, type, collectionType, keyArgs, args} = this.getOptions(context);\n const key = [nameOf(context.target), context.propertyKey, keyArgs].join(\":\");\n\n const cachedObject = await this.cache.get<PlatformCachedObject>(key);\n\n if (cachedObject) {\n const {data} = cachedObject;\n\n return deserialize(JSON.parse(data), {collectionType, type});\n }\n\n const result = await next();\n const calculatedTtl = this.cache.ttl(result, ttl);\n\n await this.cache.set<PlatformCachedObject>(\n key,\n {\n ttl: calculatedTtl,\n args,\n data: JSON.stringify(serialize(result, {type, collectionType}))\n },\n {\n ttl: calculatedTtl\n }\n );\n\n return result;\n }\n\n protected async cacheResponse(context: InterceptorContext<any, PlatformCacheOptions>, next: InterceptorNext) {\n const $ctx: BaseContext = context.args[context.args.length - 1];\n const {request, response} = $ctx;\n\n if (request.method !== \"GET\") {\n return next();\n }\n\n const {ttl, args, keyArgs} = this.getOptions(context);\n\n const key = [request.method, request.url, keyArgs].join(\":\");\n\n const cachedObject = await this.cache.get<PlatformCachedObject>(key);\n\n if (cachedObject && !(response.get(\"cache-control\") === \"no-cache\")) {\n return this.sendResponse(cachedObject, $ctx);\n }\n\n const result = await next();\n\n const calculatedTtl = this.cache.ttl(result, ttl);\n const expires = calculatedTtl + Date.now() / 1000;\n $ctx.response.setHeaders({\n \"cache-control\": `max-age=${calculatedTtl}`\n });\n\n // cache final response with his headers and body\n response.onEnd(async () => {\n const data = JSON.stringify(response.getBody());\n const headers = cleanHeaders(response.getHeaders());\n\n await this.cache.set<PlatformCachedObject>(\n key,\n {\n ttl: calculatedTtl,\n args,\n data,\n expires,\n headers\n },\n {\n ttl: calculatedTtl\n }\n );\n });\n\n return result;\n }\n\n protected sendResponse(cachedObject: PlatformCachedObject, $ctx: BaseContext) {\n const {headers, ttl} = cachedObject;\n const {request, response} = $ctx;\n\n const requestEtag = request.get(\"if-none-match\");\n\n if (requestEtag && headers.etag === requestEtag) {\n response.status(304).setHeaders(headers).body(undefined);\n\n return undefined;\n }\n\n const data = JSON.parse(cachedObject.data);\n\n $ctx.response\n .setHeaders({\n ...headers,\n \"x-cached\": \"true\",\n \"cache-control\": `max-age=${ttl}`\n })\n .body(data);\n\n return data;\n }\n}\n"]}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=PlatformCacheOptions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PlatformCacheOptions.js","sourceRoot":"","sources":["../../../src/interfaces/PlatformCacheOptions.ts"],"names":[],"mappings":"","sourcesContent":["import {MetadataTypes} from \"@tsed/core\";\nimport {BaseContext} from \"@tsed/di\";\nimport type {TtlFunction} from \"cache-manager\";\n\nexport interface PlatformCacheOptions extends MetadataTypes {\n ttl?: number | TtlFunction;\n key?: string | ((args: any[], ctx?: BaseContext) => string);\n}\n"]}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=PlatformCachedObject.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PlatformCachedObject.js","sourceRoot":"","sources":["../../../src/interfaces/PlatformCachedObject.ts"],"names":[],"mappings":"","sourcesContent":["export interface PlatformCachedObject {\n ttl: number;\n args: any[];\n data: any;\n expires: number;\n headers: Record<string, number | string | string[]>;\n}\n"]}
@@ -0,0 +1,2 @@
1
+ export * from "./PlatformCachedObject";
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/interfaces/index.ts"],"names":[],"mappings":"AAGA,cAAc,wBAAwB,CAAC","sourcesContent":["import type {BaseContext} from \"@tsed/di\";\nimport type {Cache, CacheOptions, CachingConfig, Store} from \"cache-manager\";\n\nexport * from \"./PlatformCachedObject\";\n\nexport interface PlatformCacheSettings extends CacheOptions, CachingConfig {\n caches?: Cache[];\n store?:\n | \"memory\"\n | \"none\"\n | Store\n | {\n create(...args: any[]): Store;\n }\n | (() => any);\n max?: number;\n keyResolver?: (args: any[], ctx: BaseContext) => string;\n\n /**\n * You may pass in any other arguments these will be passed on to the `create` method of your store,\n * otherwise they will be ignored.\n */\n [key: string]: any;\n}\n\ndeclare global {\n // eslint-disable-next-line @typescript-eslint/no-namespace\n namespace TsED {\n interface Configuration {\n cache?: PlatformCacheSettings | false;\n }\n }\n}\n"]}
@@ -0,0 +1,93 @@
1
+ import { __decorate, __metadata } from "tslib";
2
+ import { isClass, isFunction } from "@tsed/core";
3
+ import { Configuration, Module } from "@tsed/di";
4
+ import { deserialize, serialize } from "@tsed/json-mapper";
5
+ const defaultKeyResolver = (args) => {
6
+ return args.map((arg) => (isClass(arg) ? JSON.stringify(serialize(arg)) : arg)).join(":");
7
+ };
8
+ /**
9
+ * @platform
10
+ */
11
+ let PlatformCache = class PlatformCache {
12
+ disabled() {
13
+ return !this.settings.get("cache");
14
+ }
15
+ async $onInit() {
16
+ const settings = this.settings.get("cache");
17
+ if (settings) {
18
+ this.cache = await this.createCacheManager(settings);
19
+ }
20
+ }
21
+ defaultKeyResolver() {
22
+ return this.settings.get("cache.keyResolver", defaultKeyResolver);
23
+ }
24
+ defaultTtl() {
25
+ return this.settings.get("cache.ttl");
26
+ }
27
+ ttl(result, currentTtl) {
28
+ const ttl = currentTtl === undefined ? this.defaultTtl() : currentTtl;
29
+ return isFunction(ttl) ? ttl(result) : ttl;
30
+ }
31
+ wrap(key, fetch, options) {
32
+ var _a;
33
+ if (!this.cache) {
34
+ return fetch();
35
+ }
36
+ return (_a = this.cache) === null || _a === void 0 ? void 0 : _a.wrap(key, fetch, options);
37
+ }
38
+ async get(key, options = {}) {
39
+ var _a;
40
+ return deserialize((_a = this.cache) === null || _a === void 0 ? void 0 : _a.get(key), options);
41
+ }
42
+ async set(key, value, options) {
43
+ var _a;
44
+ return (_a = this.cache) === null || _a === void 0 ? void 0 : _a.set(key, value, options);
45
+ }
46
+ async del(key) {
47
+ var _a;
48
+ await ((_a = this.cache) === null || _a === void 0 ? void 0 : _a.del(key));
49
+ }
50
+ async reset() {
51
+ var _a;
52
+ // @ts-ignore
53
+ await ((_a = this.cache) === null || _a === void 0 ? void 0 : _a.reset());
54
+ }
55
+ async keys() {
56
+ var _a;
57
+ if ((_a = this.cache) === null || _a === void 0 ? void 0 : _a.keys) {
58
+ return this.cache.keys();
59
+ }
60
+ // istanbul ignore next
61
+ return [];
62
+ }
63
+ async getMatchingKeys(patterns) {
64
+ const [keys, { default: micromatch }] = await Promise.all([this.keys(), import("micromatch")]);
65
+ return micromatch(keys, patterns);
66
+ }
67
+ async deleteMatchingKeys(patterns) {
68
+ const keys = await this.getMatchingKeys(patterns);
69
+ await Promise.all(keys.map((key) => this.del(key)));
70
+ return keys;
71
+ }
72
+ async createCacheManager(settings) {
73
+ const { caches, store = "memory", ttl, ...props } = settings;
74
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
75
+ const { default: cacheManager } = await import("cache-manager");
76
+ return (caches === null || caches === void 0 ? void 0 : caches.length)
77
+ ? cacheManager.multiCaching(caches, { ...props })
78
+ : cacheManager.caching({
79
+ ...props,
80
+ ttl,
81
+ store: isFunction(store) ? await store() : store
82
+ });
83
+ }
84
+ };
85
+ __decorate([
86
+ Configuration(),
87
+ __metadata("design:type", Object)
88
+ ], PlatformCache.prototype, "settings", void 0);
89
+ PlatformCache = __decorate([
90
+ Module()
91
+ ], PlatformCache);
92
+ export { PlatformCache };
93
+ //# sourceMappingURL=PlatformCache.js.map