@boredland/node-ts-cache 4.4.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/README.md +101 -0
- package/dist/cache-container/cache-container-types.d.ts +18 -0
- package/dist/cache-container/cache-container-types.js +2 -0
- package/dist/cache-container/cache-container.d.ts +11 -0
- package/dist/cache-container/cache-container.js +56 -0
- package/dist/cache-container/index.d.ts +2 -0
- package/dist/cache-container/index.js +18 -0
- package/dist/decorator/cache-decorator.d.ts +2 -0
- package/dist/decorator/cache-decorator.js +67 -0
- package/dist/decorator/index.d.ts +1 -0
- package/dist/decorator/index.js +17 -0
- package/dist/hasher.d.ts +3 -0
- package/dist/hasher.js +9 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +20 -0
- package/dist/storage/index.d.ts +1 -0
- package/dist/storage/index.js +17 -0
- package/dist/storage/storage-types.d.ts +6 -0
- package/dist/storage/storage-types.js +2 -0
- package/dist/withCache.d.ts +12 -0
- package/dist/withCache.js +24 -0
- package/package.json +47 -0
package/README.md
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
# boredland/node-ts-cache
|
|
2
|
+
|
|
3
|
+
[](https://github.com/boredland/node-ts-cache/actions/workflows/ci.yml)
|
|
4
|
+
[](http://opensource.org/licenses/MIT)
|
|
5
|
+
|
|
6
|
+
Simple and extensible caching module supporting decorators.
|
|
7
|
+
|
|
8
|
+
## Install
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
yarn add boredland/node-ts-cache
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
_Note: The underlying storage layer must be installed separately._
|
|
15
|
+
|
|
16
|
+
## Storage
|
|
17
|
+
|
|
18
|
+
| Storage | Install |
|
|
19
|
+
|-----------------------------------------------------------------------|-------------------------------------------------|
|
|
20
|
+
| [memory](https://www.npmjs.com/package/boredland/node-ts-cache-storage-memory)| ```yarn add boredland/node-ts-cache-storage-memory```|
|
|
21
|
+
| [node-fs](https://www.npmjs.com/package/boredland/node-ts-cache-storage-node-fs)| ```yarn add boredland/node-ts-cache-storage-node-fs```|
|
|
22
|
+
| [ioredis](https://www.npmjs.com/package/boredland/node-ts-cache-storage-ioredis)| ```yarn add boredland/node-ts-cache-storage-ioredis```|
|
|
23
|
+
|
|
24
|
+
## Usage
|
|
25
|
+
|
|
26
|
+
## With decorator
|
|
27
|
+
|
|
28
|
+
Caches function response using the given options.
|
|
29
|
+
Works with the above listed storages.
|
|
30
|
+
By default, uses all arguments to build an unique key.
|
|
31
|
+
|
|
32
|
+
`@Cache(container, options)`
|
|
33
|
+
|
|
34
|
+
- `options`:
|
|
35
|
+
- `ttl`: _(Default: 60)_ Number of seconds to expire the cachte item
|
|
36
|
+
- `isLazy`: _(Default: true)_ If true, expired cache entries will be deleted on touch. If false, entries will be deleted after the given _ttl_.
|
|
37
|
+
- `isCachedForever`: _(Default: false)_ If true, cache entry has no expiration.
|
|
38
|
+
- `calculateKey(data => string)`: _(Default: JSON.stringify combination of className, methodName and call args)_
|
|
39
|
+
- `data`:
|
|
40
|
+
- `className`: The class name for the method being decorated
|
|
41
|
+
- `methodName`: The method name being decorated
|
|
42
|
+
- `args`: The arguments passed to the method when called
|
|
43
|
+
|
|
44
|
+
_Note: @Cache will consider the return type of the function. If the return type is a thenable, it will stay that way, otherwise not._
|
|
45
|
+
|
|
46
|
+
```ts
|
|
47
|
+
import { Cache, CacheContainer } from '@boredland/node-ts-cache'
|
|
48
|
+
import { MemoryStorage } from '@boredland/node-ts-cache-storage-memory'
|
|
49
|
+
|
|
50
|
+
const userCache = new CacheContainer(new MemoryStorage())
|
|
51
|
+
|
|
52
|
+
class MyService {
|
|
53
|
+
@Cache(userCache, {ttl: 60})
|
|
54
|
+
public async getUsers(): Promise<string[]> {
|
|
55
|
+
return ["Max", "User"]
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Directly
|
|
61
|
+
|
|
62
|
+
```ts
|
|
63
|
+
import { CacheContainer } from '@boredland/node-ts-cache'
|
|
64
|
+
import { MemoryStorage } from '@boredland/node-ts-cache-storage-memory'
|
|
65
|
+
|
|
66
|
+
const myCache = new CacheContainer(new MemoryStorage())
|
|
67
|
+
|
|
68
|
+
class MyService {
|
|
69
|
+
public async getUsers(): Promise<string[]> {
|
|
70
|
+
const cachedUsers = await myCache.getItem<string[]>("users")
|
|
71
|
+
|
|
72
|
+
if (cachedUsers) {
|
|
73
|
+
return cachedUsers
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const newUsers = ["Max", "User"]
|
|
77
|
+
|
|
78
|
+
await myCache.setItem("users", newUsers, {ttl: 60})
|
|
79
|
+
|
|
80
|
+
return newUsers
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## Logging
|
|
86
|
+
|
|
87
|
+
This project uses [debug](https://github.com/visionmedia/debug) to log useful caching information.
|
|
88
|
+
Set environment variable **DEBUG=node-ts-cache** to enable logging.
|
|
89
|
+
|
|
90
|
+
## Development & Testing
|
|
91
|
+
|
|
92
|
+
This project follows the monorepo architecture using yarn workspaces.
|
|
93
|
+
|
|
94
|
+
To start development and run tests for all the packages, run:
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
cd node-ts-cache
|
|
98
|
+
yarn
|
|
99
|
+
yarn build
|
|
100
|
+
yarn test
|
|
101
|
+
```
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export declare type CachedItem<T = any> = {
|
|
2
|
+
content: T;
|
|
3
|
+
meta: {
|
|
4
|
+
createdAt: number;
|
|
5
|
+
ttl: number;
|
|
6
|
+
isLazy: boolean;
|
|
7
|
+
};
|
|
8
|
+
};
|
|
9
|
+
export declare type CachingOptions = {
|
|
10
|
+
ttl: number;
|
|
11
|
+
isLazy: boolean;
|
|
12
|
+
isCachedForever: boolean;
|
|
13
|
+
calculateKey: (data: {
|
|
14
|
+
className: string;
|
|
15
|
+
methodName: string;
|
|
16
|
+
args: any[];
|
|
17
|
+
}) => string;
|
|
18
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { IStorage } from "../storage";
|
|
2
|
+
import type { CachingOptions } from "./cache-container-types";
|
|
3
|
+
export declare class CacheContainer {
|
|
4
|
+
private storage;
|
|
5
|
+
constructor(storage: IStorage);
|
|
6
|
+
getItem<T>(key: string): Promise<T | undefined>;
|
|
7
|
+
setItem(key: string, content: any, options: Partial<CachingOptions>): Promise<void>;
|
|
8
|
+
clear(): Promise<void>;
|
|
9
|
+
private isItemExpired;
|
|
10
|
+
private unsetKey;
|
|
11
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.CacheContainer = void 0;
|
|
7
|
+
const debug_1 = __importDefault(require("debug"));
|
|
8
|
+
const debug = (0, debug_1.default)("node-ts-cache");
|
|
9
|
+
const DEFAULT_TTL_SECONDS = 60;
|
|
10
|
+
class CacheContainer {
|
|
11
|
+
storage;
|
|
12
|
+
constructor(storage) {
|
|
13
|
+
this.storage = storage;
|
|
14
|
+
}
|
|
15
|
+
async getItem(key) {
|
|
16
|
+
const item = await this.storage.getItem(key);
|
|
17
|
+
if (item?.meta?.ttl && this.isItemExpired(item)) {
|
|
18
|
+
await this.unsetKey(key);
|
|
19
|
+
return undefined;
|
|
20
|
+
}
|
|
21
|
+
return item ? item.content : undefined;
|
|
22
|
+
}
|
|
23
|
+
async setItem(key, content, options) {
|
|
24
|
+
const finalOptions = {
|
|
25
|
+
ttl: DEFAULT_TTL_SECONDS,
|
|
26
|
+
isLazy: true,
|
|
27
|
+
isCachedForever: false,
|
|
28
|
+
...options
|
|
29
|
+
};
|
|
30
|
+
const meta = {
|
|
31
|
+
createdAt: Date.now(),
|
|
32
|
+
isLazy: finalOptions.isLazy,
|
|
33
|
+
ttl: finalOptions.isCachedForever ? Infinity : finalOptions.ttl * 1000
|
|
34
|
+
};
|
|
35
|
+
if (!finalOptions.isCachedForever && !finalOptions.isLazy) {
|
|
36
|
+
setTimeout(() => {
|
|
37
|
+
this.unsetKey(key);
|
|
38
|
+
debug(`Expired key ${key} removed from cache`);
|
|
39
|
+
}, meta.ttl);
|
|
40
|
+
}
|
|
41
|
+
await this.storage.setItem(key, { meta, content });
|
|
42
|
+
}
|
|
43
|
+
async clear() {
|
|
44
|
+
await this.storage.clear();
|
|
45
|
+
debug("Cleared cache");
|
|
46
|
+
}
|
|
47
|
+
isItemExpired(item) {
|
|
48
|
+
if (item.meta.ttl === Infinity)
|
|
49
|
+
return false;
|
|
50
|
+
return Date.now() > item.meta.createdAt + item.meta.ttl;
|
|
51
|
+
}
|
|
52
|
+
async unsetKey(key) {
|
|
53
|
+
await this.storage.setItem(key, undefined);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
exports.CacheContainer = CacheContainer;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./cache-container"), exports);
|
|
18
|
+
__exportStar(require("./cache-container-types"), exports);
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.Cache = void 0;
|
|
7
|
+
const debug_1 = __importDefault(require("debug"));
|
|
8
|
+
const debug = (0, debug_1.default)("node-ts-cache");
|
|
9
|
+
const jsonCalculateKey = (data) => {
|
|
10
|
+
return `${data.className}:${data.methodName}:${JSON.stringify(data.args)}`;
|
|
11
|
+
};
|
|
12
|
+
function Cache(container, options) {
|
|
13
|
+
return function (target, methodName, descriptor) {
|
|
14
|
+
const originalMethod = descriptor.value;
|
|
15
|
+
const className = target.constructor.name;
|
|
16
|
+
descriptor.value = async function (...args) {
|
|
17
|
+
options ??= {};
|
|
18
|
+
const keyOptions = {
|
|
19
|
+
args,
|
|
20
|
+
methodName: methodName,
|
|
21
|
+
className
|
|
22
|
+
};
|
|
23
|
+
const cacheKey = options.calculateKey
|
|
24
|
+
? options.calculateKey(keyOptions)
|
|
25
|
+
: jsonCalculateKey(keyOptions);
|
|
26
|
+
const runOriginalMethod = async () => {
|
|
27
|
+
const methodCall = originalMethod.apply(this, args);
|
|
28
|
+
const isAsync = methodCall?.constructor?.name === "AsyncFunction" ||
|
|
29
|
+
methodCall?.constructor?.name === "Promise";
|
|
30
|
+
if (isAsync) {
|
|
31
|
+
return await methodCall;
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
return methodCall;
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
if (!target.__node_ts_cache_method_run_queue) {
|
|
38
|
+
target.__node_ts_cache_method_run_queue = {};
|
|
39
|
+
}
|
|
40
|
+
if (target.__node_ts_cache_method_run_queue[cacheKey]) {
|
|
41
|
+
debug(`Method is already enqueued ${cacheKey}`);
|
|
42
|
+
return target.__node_ts_cache_method_run_queue[cacheKey];
|
|
43
|
+
}
|
|
44
|
+
target.__node_ts_cache_method_run_queue[cacheKey] = (async () => {
|
|
45
|
+
try {
|
|
46
|
+
const entry = await container.getItem(cacheKey);
|
|
47
|
+
if (entry) {
|
|
48
|
+
debug(`Cache HIT ${cacheKey}`);
|
|
49
|
+
return entry;
|
|
50
|
+
}
|
|
51
|
+
debug(`Cache MISS ${cacheKey}`);
|
|
52
|
+
const methodResult = await runOriginalMethod();
|
|
53
|
+
await container.setItem(cacheKey, methodResult, options);
|
|
54
|
+
return methodResult;
|
|
55
|
+
}
|
|
56
|
+
finally {
|
|
57
|
+
target.__node_ts_cache_method_run_queue[cacheKey] =
|
|
58
|
+
undefined;
|
|
59
|
+
}
|
|
60
|
+
})();
|
|
61
|
+
return target.__node_ts_cache_method_run_queue[cacheKey];
|
|
62
|
+
};
|
|
63
|
+
debug(`Added caching for method ${className}:${methodName.toString()}`);
|
|
64
|
+
return descriptor;
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
exports.Cache = Cache;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./cache-decorator";
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./cache-decorator"), exports);
|
package/dist/hasher.d.ts
ADDED
package/dist/hasher.js
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.hash = void 0;
|
|
7
|
+
const node_object_hash_1 = __importDefault(require("node-object-hash"));
|
|
8
|
+
const { hash } = (0, node_object_hash_1.default)();
|
|
9
|
+
exports.hash = hash;
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./decorator"), exports);
|
|
18
|
+
__exportStar(require("./storage"), exports);
|
|
19
|
+
__exportStar(require("./cache-container"), exports);
|
|
20
|
+
__exportStar(require("./withCache"), exports);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./storage-types";
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./storage-types"), exports);
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { CacheContainer, CachingOptions } from "./cache-container";
|
|
2
|
+
declare type WithCacheOptions<Parameters> = Partial<Omit<CachingOptions, 'calculateKey'>> & {
|
|
3
|
+
prefix: string;
|
|
4
|
+
calculateKey?: (prefix: string, input: Parameters) => string;
|
|
5
|
+
};
|
|
6
|
+
/**
|
|
7
|
+
* wrapped function factory
|
|
8
|
+
* @param container - cache container to create the fn for
|
|
9
|
+
* @returns a wrapped function
|
|
10
|
+
*/
|
|
11
|
+
export declare const withCacheFactory: (container: CacheContainer) => <Parameters_1 extends unknown[], Result extends Promise<unknown>>(operation: (...parameters: Parameters_1) => Result, { calculateKey, prefix, ...options }: WithCacheOptions<Parameters_1>) => (...parameters: Parameters_1) => Promise<Result>;
|
|
12
|
+
export {};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.withCacheFactory = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* wrapped function factory
|
|
6
|
+
* @param container - cache container to create the fn for
|
|
7
|
+
* @returns a wrapped function
|
|
8
|
+
*/
|
|
9
|
+
const withCacheFactory = (container) => {
|
|
10
|
+
const withCache = (operation, { calculateKey, prefix, ...options }) => {
|
|
11
|
+
return async (...parameters) => {
|
|
12
|
+
const key = calculateKey ? calculateKey(prefix, parameters) : `${prefix}_${JSON.stringify(parameters)}`;
|
|
13
|
+
const cachedResponse = await container.getItem(key);
|
|
14
|
+
if (cachedResponse) {
|
|
15
|
+
return cachedResponse;
|
|
16
|
+
}
|
|
17
|
+
const result = await operation(...parameters);
|
|
18
|
+
await container.setItem(key, result, options);
|
|
19
|
+
return result;
|
|
20
|
+
};
|
|
21
|
+
};
|
|
22
|
+
return withCache;
|
|
23
|
+
};
|
|
24
|
+
exports.withCacheFactory = withCacheFactory;
|
package/package.json
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@boredland/node-ts-cache",
|
|
3
|
+
"description": "Simple and extensible caching module supporting decorators",
|
|
4
|
+
"version": "4.4.0",
|
|
5
|
+
"private": false,
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"files": [
|
|
9
|
+
"dist"
|
|
10
|
+
],
|
|
11
|
+
"scripts": {
|
|
12
|
+
"build": "tsc -p tsconfig-build.json",
|
|
13
|
+
"prepublishOnly": "cp ../../README.md ."
|
|
14
|
+
},
|
|
15
|
+
"repository": {
|
|
16
|
+
"type": "git",
|
|
17
|
+
"url": "git+https://github.com/boredland/node-ts-cache.git"
|
|
18
|
+
},
|
|
19
|
+
"keywords": [
|
|
20
|
+
"node",
|
|
21
|
+
"nodejs",
|
|
22
|
+
"cache",
|
|
23
|
+
"typescript",
|
|
24
|
+
"ts",
|
|
25
|
+
"caching",
|
|
26
|
+
"memcache",
|
|
27
|
+
"memory-cache",
|
|
28
|
+
"redis-cache",
|
|
29
|
+
"redis",
|
|
30
|
+
"cache",
|
|
31
|
+
"file-cache",
|
|
32
|
+
"node-cache",
|
|
33
|
+
"ts-cache"
|
|
34
|
+
],
|
|
35
|
+
"author": "Himmet Avsar <avsar.himmet1@gmail.com>",
|
|
36
|
+
"license": "MIT",
|
|
37
|
+
"bugs": {
|
|
38
|
+
"url": "https://github.com/boredland/node-ts-cache/issues"
|
|
39
|
+
},
|
|
40
|
+
"homepage": "https://github.com/boredland/node-ts-cache#readme",
|
|
41
|
+
"dependencies": {
|
|
42
|
+
"debug": "4.3.4"
|
|
43
|
+
},
|
|
44
|
+
"devDependencies": {
|
|
45
|
+
"@types/debug": "^4.1.7"
|
|
46
|
+
}
|
|
47
|
+
}
|