@prairielearn/cache 1.0.2 → 1.1.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/CHANGELOG.md +14 -0
- package/README.md +11 -14
- package/dist/index.d.ts +1 -2
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
- package/src/index.ts +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# @prairielearn/cache
|
|
2
2
|
|
|
3
|
+
## 1.1.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 3ef2b1d: Export the `Cache` class
|
|
8
|
+
|
|
9
|
+
## 1.0.3
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- Updated dependencies [c7e6553]
|
|
14
|
+
- @prairielearn/logger@1.0.15
|
|
15
|
+
- @prairielearn/sentry@1.2.4
|
|
16
|
+
|
|
3
17
|
## 1.0.2
|
|
4
18
|
|
|
5
19
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -4,36 +4,33 @@ Utilities to help connect to and store information in a cache. This package _doe
|
|
|
4
4
|
|
|
5
5
|
## Usage
|
|
6
6
|
|
|
7
|
-
First, you will need to initialize the library with the cache type that you are intending to use, a prefix that will be the start of all of your cache keys, and optionally, a
|
|
7
|
+
First, you will need to initialize the library with the cache type that you are intending to use, a prefix that will be the start of all of your cache keys, and optionally, a Redis server URL if that is the cache type being used:
|
|
8
8
|
|
|
9
9
|
```ts
|
|
10
10
|
import { cache } from '@prairielearn/cache';
|
|
11
|
-
import { config } from 'lib/config.js';
|
|
12
11
|
|
|
13
12
|
await cache.init({
|
|
14
|
-
type:
|
|
15
|
-
keyPrefix:
|
|
16
|
-
redisUrl:
|
|
13
|
+
type: 'redis',
|
|
14
|
+
keyPrefix: 'my-app:',
|
|
15
|
+
redisUrl: 'redis://localhost:6379/',
|
|
17
16
|
});
|
|
18
17
|
```
|
|
19
18
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
Additionally, the cache package can be used as a class to construct multiple instances. To do so, you must first contsruct a new cache. You can then pass is your arguments and initalize a new cache:
|
|
19
|
+
Alternatively, you can create new instances of the `Cache` class instead of using the global `cache` object:
|
|
23
20
|
|
|
24
21
|
```ts
|
|
25
|
-
import {
|
|
22
|
+
import { Cache } from '@prairielearn/cache';
|
|
26
23
|
|
|
27
|
-
const myCache = new
|
|
24
|
+
const myCache = new Cache();
|
|
28
25
|
|
|
29
|
-
myCache.init({
|
|
30
|
-
|
|
31
|
-
|
|
26
|
+
await myCache.init({
|
|
27
|
+
type: 'redis',
|
|
28
|
+
keyPrefix: 'my-app:',
|
|
32
29
|
redisUrl: 'redis://localhost:6379/',
|
|
33
30
|
});
|
|
34
31
|
```
|
|
35
32
|
|
|
36
|
-
After initializing,
|
|
33
|
+
After initializing, you can use `set`, `get`, `del`, `reset` or `close` functions to interact with the cache. Note that `set`, `get`, and `del` have required arguments. Calling `set` will require the intended KEY, VALUE, and length of time to store the data (in milliseconds). Calling `get` or `del` will require the KEY for the intended result.
|
|
37
34
|
|
|
38
35
|
The following example will store `foo: bar` for 10 minutes:
|
|
39
36
|
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Redis } from 'ioredis';
|
|
2
2
|
import { LRUCache } from 'lru-cache';
|
|
3
|
-
declare class Cache {
|
|
3
|
+
export declare class Cache {
|
|
4
4
|
enabled: boolean;
|
|
5
5
|
type: string;
|
|
6
6
|
memoryCache?: LRUCache<string, string>;
|
|
@@ -27,4 +27,3 @@ declare class Cache {
|
|
|
27
27
|
close(): Promise<void>;
|
|
28
28
|
}
|
|
29
29
|
export declare const cache: Cache;
|
|
30
|
-
export {};
|
package/dist/index.js
CHANGED
|
@@ -26,7 +26,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
26
26
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
27
27
|
};
|
|
28
28
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
|
-
exports.cache = void 0;
|
|
29
|
+
exports.cache = exports.Cache = void 0;
|
|
30
30
|
const ioredis_1 = require("ioredis");
|
|
31
31
|
const lru_cache_1 = require("lru-cache");
|
|
32
32
|
const logger_1 = require("@prairielearn/logger");
|
|
@@ -180,5 +180,6 @@ class Cache {
|
|
|
180
180
|
}
|
|
181
181
|
}
|
|
182
182
|
}
|
|
183
|
+
exports.Cache = Cache;
|
|
183
184
|
exports.cache = new Cache();
|
|
184
185
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,qCAAgC;AAChC,yCAAqC;AACrC,iDAA8C;AAC9C,6DAA+C;AAC/C,8DAAiC;AAEjC,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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","sourcesContent":["import { Redis } from 'ioredis';\nimport { LRUCache } from 'lru-cache';\nimport { logger } from '@prairielearn/logger';\nimport * as Sentry from '@prairielearn/sentry';\nimport assert from 'node:assert';\n\nexport class Cache {\n enabled = false;\n type = 'none';\n memoryCache?: LRUCache<string, string>;\n redisClient?: Redis;\n keyPrefix = '';\n\n async init(config: {\n type: 'none' | 'memory' | 'redis';\n keyPrefix: string;\n redisUrl?: string | null;\n }) {\n this.type = config.type;\n this.keyPrefix = config.keyPrefix;\n if (!this.type || this.type === 'none') {\n // No caching\n this.enabled = false;\n return;\n }\n\n if (this.type === 'redis') {\n if (!config.redisUrl) throw new Error('redisUrl not set in config');\n this.enabled = true;\n this.redisClient = new Redis(config.redisUrl);\n this.redisClient.on('error', (err) => {\n logger.error('Redis error', err);\n Sentry.captureException(err);\n });\n } else if (this.type === 'memory') {\n this.enabled = true;\n this.memoryCache = new LRUCache({\n // The in-memory cache is really only suited for development, so we'll\n // hardcode a relatively low limit here.\n max: 1000,\n });\n } else {\n throw new Error(`Unknown cache type \"${this.type}\"`);\n }\n }\n\n set(key: string, value: any, maxAgeMS: number) {\n if (!this.enabled) return;\n\n const scopedKey = this.keyPrefix + key;\n\n switch (this.type) {\n case 'memory': {\n assert(this.memoryCache, 'Memory cache is enabled but not configured');\n this.memoryCache.set(scopedKey, JSON.stringify(value), { ttl: maxAgeMS });\n break;\n }\n\n case 'redis': {\n // This returns a promise, but we don't want to wait for this data\n // to reach the cache before continuing, and we don't *really*\n // care if it errors.\n //\n // We don't log the error because it contains the cached value,\n // which can be huge and which fills up the logs.\n assert(this.redisClient, 'Redis client is enabled but not configured');\n this.redisClient\n .set(scopedKey, JSON.stringify(value), 'PX', maxAgeMS)\n .catch((_err) => logger.error('Cache set error', { key, scopedKey, maxAgeMS }));\n break;\n }\n }\n }\n\n async del(key: string) {\n if (!this.enabled) return;\n\n const scopedKey = this.keyPrefix + key;\n\n switch (this.type) {\n case 'memory': {\n assert(this.memoryCache, 'Memory cache is enabled but not configured');\n this.memoryCache.delete(scopedKey);\n break;\n }\n\n case 'redis': {\n assert(this.redisClient, 'Redis client is enabled but not configured');\n await this.redisClient.del(scopedKey);\n break;\n }\n }\n }\n\n /**\n * Returns the value for the corresponding key if it exists in the cache; null otherwise.\n */\n async get(key: string): Promise<any> {\n if (!this.enabled) return null;\n\n const scopedKey = this.keyPrefix + key;\n\n switch (this.type) {\n case 'memory': {\n assert(this.memoryCache, 'Memory cache is enabled but not configured');\n const value = this.memoryCache.get(scopedKey);\n if (typeof value === 'string') {\n return JSON.parse(value);\n }\n return undefined;\n }\n\n case 'redis': {\n assert(this.redisClient, 'Redis client is enabled but not configured');\n const value = await this.redisClient.get(scopedKey);\n if (typeof value === 'string') {\n return JSON.parse(value);\n }\n return undefined;\n }\n\n default: {\n return null;\n }\n }\n }\n\n /**\n * Clear all entries from the cache.\n */\n async reset() {\n if (!this.enabled) return;\n\n switch (this.type) {\n case 'memory': {\n assert(this.memoryCache, 'Memory cache is enabled but not configured');\n this.memoryCache.clear();\n break;\n }\n\n case 'redis': {\n let cursor = '0';\n do {\n assert(this.redisClient, 'Redis client is enabled but not configured');\n const reply = await this.redisClient.scan(\n cursor,\n 'MATCH',\n `${this.keyPrefix}*`,\n 'COUNT',\n 1000,\n );\n cursor = reply[0];\n\n const keys = reply[1];\n if (keys.length > 0) {\n assert(this.redisClient, 'Redis client is enabled but not configured');\n await this.redisClient.del(keys);\n }\n } while (cursor !== '0');\n break;\n }\n }\n }\n /**\n * Releases any connections associated with the cache.\n */\n async close() {\n if (!this.enabled) return;\n this.enabled = false;\n\n if (this.type === 'redis') {\n assert(this.redisClient, 'Redis client is enabled but not configured');\n await this.redisClient.quit();\n }\n }\n}\n\nexport const cache = new Cache();\n"]}
|
package/package.json
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@prairielearn/cache",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"build": "tsc",
|
|
7
7
|
"dev": "tsc --watch --preserveWatchOutput"
|
|
8
8
|
},
|
|
9
9
|
"dependencies": {
|
|
10
|
-
"@prairielearn/logger": "^1.0.
|
|
11
|
-
"@prairielearn/sentry": "^1.2.
|
|
10
|
+
"@prairielearn/logger": "^1.0.15",
|
|
11
|
+
"@prairielearn/sentry": "^1.2.4",
|
|
12
12
|
"ioredis": "^5.3.2",
|
|
13
13
|
"lru-cache": "^10.2.0",
|
|
14
14
|
"zod": "^3.22.4"
|
package/src/index.ts
CHANGED