@prairielearn/cache 1.1.0 → 2.0.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.
- package/CHANGELOG.md +21 -0
- package/dist/index.js +21 -51
- package/dist/index.js.map +1 -1
- package/package.json +8 -7
- package/src/index.ts +3 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,26 @@
|
|
|
1
1
|
# @prairielearn/cache
|
|
2
2
|
|
|
3
|
+
## 2.0.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 901fce8: Upgrade all JavaScript dependencies
|
|
8
|
+
- Updated dependencies [901fce8]
|
|
9
|
+
- @prairielearn/logger@2.0.1
|
|
10
|
+
- @prairielearn/sentry@2.0.1
|
|
11
|
+
|
|
12
|
+
## 2.0.0
|
|
13
|
+
|
|
14
|
+
### Major Changes
|
|
15
|
+
|
|
16
|
+
- 4f30b7e: Publish as native ESM
|
|
17
|
+
|
|
18
|
+
### Patch Changes
|
|
19
|
+
|
|
20
|
+
- Updated dependencies [4f30b7e]
|
|
21
|
+
- @prairielearn/logger@2.0.0
|
|
22
|
+
- @prairielearn/sentry@2.0.0
|
|
23
|
+
|
|
3
24
|
## 1.1.0
|
|
4
25
|
|
|
5
26
|
### Minor Changes
|
package/dist/index.js
CHANGED
|
@@ -1,38 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
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 __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
-
}) : function(o, v) {
|
|
16
|
-
o["default"] = v;
|
|
17
|
-
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
-
if (mod && mod.__esModule) return mod;
|
|
20
|
-
var result = {};
|
|
21
|
-
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
-
__setModuleDefault(result, mod);
|
|
23
|
-
return result;
|
|
24
|
-
};
|
|
25
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
26
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
27
|
-
};
|
|
28
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
|
-
exports.cache = exports.Cache = void 0;
|
|
30
|
-
const ioredis_1 = require("ioredis");
|
|
31
|
-
const lru_cache_1 = require("lru-cache");
|
|
32
|
-
const logger_1 = require("@prairielearn/logger");
|
|
33
|
-
const Sentry = __importStar(require("@prairielearn/sentry"));
|
|
34
|
-
const node_assert_1 = __importDefault(require("node:assert"));
|
|
35
|
-
class Cache {
|
|
1
|
+
import assert from 'node:assert';
|
|
2
|
+
import { Redis } from 'ioredis';
|
|
3
|
+
import { LRUCache } from 'lru-cache';
|
|
4
|
+
import { logger } from '@prairielearn/logger';
|
|
5
|
+
import * as Sentry from '@prairielearn/sentry';
|
|
6
|
+
export class Cache {
|
|
36
7
|
enabled = false;
|
|
37
8
|
type = 'none';
|
|
38
9
|
memoryCache;
|
|
@@ -50,15 +21,15 @@ class Cache {
|
|
|
50
21
|
if (!config.redisUrl)
|
|
51
22
|
throw new Error('redisUrl not set in config');
|
|
52
23
|
this.enabled = true;
|
|
53
|
-
this.redisClient = new
|
|
24
|
+
this.redisClient = new Redis(config.redisUrl);
|
|
54
25
|
this.redisClient.on('error', (err) => {
|
|
55
|
-
|
|
26
|
+
logger.error('Redis error', err);
|
|
56
27
|
Sentry.captureException(err);
|
|
57
28
|
});
|
|
58
29
|
}
|
|
59
30
|
else if (this.type === 'memory') {
|
|
60
31
|
this.enabled = true;
|
|
61
|
-
this.memoryCache = new
|
|
32
|
+
this.memoryCache = new LRUCache({
|
|
62
33
|
// The in-memory cache is really only suited for development, so we'll
|
|
63
34
|
// hardcode a relatively low limit here.
|
|
64
35
|
max: 1000,
|
|
@@ -74,7 +45,7 @@ class Cache {
|
|
|
74
45
|
const scopedKey = this.keyPrefix + key;
|
|
75
46
|
switch (this.type) {
|
|
76
47
|
case 'memory': {
|
|
77
|
-
(
|
|
48
|
+
assert(this.memoryCache, 'Memory cache is enabled but not configured');
|
|
78
49
|
this.memoryCache.set(scopedKey, JSON.stringify(value), { ttl: maxAgeMS });
|
|
79
50
|
break;
|
|
80
51
|
}
|
|
@@ -85,10 +56,10 @@ class Cache {
|
|
|
85
56
|
//
|
|
86
57
|
// We don't log the error because it contains the cached value,
|
|
87
58
|
// which can be huge and which fills up the logs.
|
|
88
|
-
(
|
|
59
|
+
assert(this.redisClient, 'Redis client is enabled but not configured');
|
|
89
60
|
this.redisClient
|
|
90
61
|
.set(scopedKey, JSON.stringify(value), 'PX', maxAgeMS)
|
|
91
|
-
.catch((_err) =>
|
|
62
|
+
.catch((_err) => logger.error('Cache set error', { key, scopedKey, maxAgeMS }));
|
|
92
63
|
break;
|
|
93
64
|
}
|
|
94
65
|
}
|
|
@@ -99,12 +70,12 @@ class Cache {
|
|
|
99
70
|
const scopedKey = this.keyPrefix + key;
|
|
100
71
|
switch (this.type) {
|
|
101
72
|
case 'memory': {
|
|
102
|
-
(
|
|
73
|
+
assert(this.memoryCache, 'Memory cache is enabled but not configured');
|
|
103
74
|
this.memoryCache.delete(scopedKey);
|
|
104
75
|
break;
|
|
105
76
|
}
|
|
106
77
|
case 'redis': {
|
|
107
|
-
(
|
|
78
|
+
assert(this.redisClient, 'Redis client is enabled but not configured');
|
|
108
79
|
await this.redisClient.del(scopedKey);
|
|
109
80
|
break;
|
|
110
81
|
}
|
|
@@ -119,7 +90,7 @@ class Cache {
|
|
|
119
90
|
const scopedKey = this.keyPrefix + key;
|
|
120
91
|
switch (this.type) {
|
|
121
92
|
case 'memory': {
|
|
122
|
-
(
|
|
93
|
+
assert(this.memoryCache, 'Memory cache is enabled but not configured');
|
|
123
94
|
const value = this.memoryCache.get(scopedKey);
|
|
124
95
|
if (typeof value === 'string') {
|
|
125
96
|
return JSON.parse(value);
|
|
@@ -127,7 +98,7 @@ class Cache {
|
|
|
127
98
|
return undefined;
|
|
128
99
|
}
|
|
129
100
|
case 'redis': {
|
|
130
|
-
(
|
|
101
|
+
assert(this.redisClient, 'Redis client is enabled but not configured');
|
|
131
102
|
const value = await this.redisClient.get(scopedKey);
|
|
132
103
|
if (typeof value === 'string') {
|
|
133
104
|
return JSON.parse(value);
|
|
@@ -147,19 +118,19 @@ class Cache {
|
|
|
147
118
|
return;
|
|
148
119
|
switch (this.type) {
|
|
149
120
|
case 'memory': {
|
|
150
|
-
(
|
|
121
|
+
assert(this.memoryCache, 'Memory cache is enabled but not configured');
|
|
151
122
|
this.memoryCache.clear();
|
|
152
123
|
break;
|
|
153
124
|
}
|
|
154
125
|
case 'redis': {
|
|
155
126
|
let cursor = '0';
|
|
156
127
|
do {
|
|
157
|
-
(
|
|
128
|
+
assert(this.redisClient, 'Redis client is enabled but not configured');
|
|
158
129
|
const reply = await this.redisClient.scan(cursor, 'MATCH', `${this.keyPrefix}*`, 'COUNT', 1000);
|
|
159
130
|
cursor = reply[0];
|
|
160
131
|
const keys = reply[1];
|
|
161
132
|
if (keys.length > 0) {
|
|
162
|
-
(
|
|
133
|
+
assert(this.redisClient, 'Redis client is enabled but not configured');
|
|
163
134
|
await this.redisClient.del(keys);
|
|
164
135
|
}
|
|
165
136
|
} while (cursor !== '0');
|
|
@@ -175,11 +146,10 @@ class Cache {
|
|
|
175
146
|
return;
|
|
176
147
|
this.enabled = false;
|
|
177
148
|
if (this.type === 'redis') {
|
|
178
|
-
(
|
|
149
|
+
assert(this.redisClient, 'Redis client is enabled but not configured');
|
|
179
150
|
await this.redisClient.quit();
|
|
180
151
|
}
|
|
181
152
|
}
|
|
182
153
|
}
|
|
183
|
-
|
|
184
|
-
exports.cache = new Cache();
|
|
154
|
+
export const cache = new Cache();
|
|
185
155
|
//# 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":"
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,aAAa,CAAC;AAEjC,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAChC,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAErC,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAC9C,OAAO,KAAK,MAAM,MAAM,sBAAsB,CAAC;AAE/C,MAAM,OAAO,KAAK;IAChB,OAAO,GAAG,KAAK,CAAC;IAChB,IAAI,GAAG,MAAM,CAAC;IACd,WAAW,CAA4B;IACvC,WAAW,CAAS;IACpB,SAAS,GAAG,EAAE,CAAC;IAEf,KAAK,CAAC,IAAI,CAAC,MAIV;QACC,IAAI,CAAC,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC;QACxB,IAAI,CAAC,SAAS,GAAG,MAAM,CAAC,SAAS,CAAC;QAClC,IAAI,CAAC,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;YACvC,aAAa;YACb,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC;YACrB,OAAO;QACT,CAAC;QAED,IAAI,IAAI,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;YAC1B,IAAI,CAAC,MAAM,CAAC,QAAQ;gBAAE,MAAM,IAAI,KAAK,CAAC,4BAA4B,CAAC,CAAC;YACpE,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;YACpB,IAAI,CAAC,WAAW,GAAG,IAAI,KAAK,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;YAC9C,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE;gBACnC,MAAM,CAAC,KAAK,CAAC,aAAa,EAAE,GAAG,CAAC,CAAC;gBACjC,MAAM,CAAC,gBAAgB,CAAC,GAAG,CAAC,CAAC;YAC/B,CAAC,CAAC,CAAC;QACL,CAAC;aAAM,IAAI,IAAI,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YAClC,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;YACpB,IAAI,CAAC,WAAW,GAAG,IAAI,QAAQ,CAAC;gBAC9B,sEAAsE;gBACtE,wCAAwC;gBACxC,GAAG,EAAE,IAAI;aACV,CAAC,CAAC;QACL,CAAC;aAAM,CAAC;YACN,MAAM,IAAI,KAAK,CAAC,uBAAuB,IAAI,CAAC,IAAI,GAAG,CAAC,CAAC;QACvD,CAAC;IACH,CAAC;IAED,GAAG,CAAC,GAAW,EAAE,KAAU,EAAE,QAAgB;QAC3C,IAAI,CAAC,IAAI,CAAC,OAAO;YAAE,OAAO;QAE1B,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,GAAG,GAAG,CAAC;QAEvC,QAAQ,IAAI,CAAC,IAAI,EAAE,CAAC;YAClB,KAAK,QAAQ,CAAC,CAAC,CAAC;gBACd,MAAM,CAAC,IAAI,CAAC,WAAW,EAAE,4CAA4C,CAAC,CAAC;gBACvE,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,SAAS,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,EAAE,GAAG,EAAE,QAAQ,EAAE,CAAC,CAAC;gBAC1E,MAAM;YACR,CAAC;YAED,KAAK,OAAO,CAAC,CAAC,CAAC;gBACb,kEAAkE;gBAClE,8DAA8D;gBAC9D,qBAAqB;gBACrB,EAAE;gBACF,+DAA+D;gBAC/D,iDAAiD;gBACjD,MAAM,CAAC,IAAI,CAAC,WAAW,EAAE,4CAA4C,CAAC,CAAC;gBACvE,IAAI,CAAC,WAAW;qBACb,GAAG,CAAC,SAAS,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,IAAI,EAAE,QAAQ,CAAC;qBACrD,KAAK,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,iBAAiB,EAAE,EAAE,GAAG,EAAE,SAAS,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC;gBAClF,MAAM;YACR,CAAC;QACH,CAAC;IACH,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,GAAW;QACnB,IAAI,CAAC,IAAI,CAAC,OAAO;YAAE,OAAO;QAE1B,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,GAAG,GAAG,CAAC;QAEvC,QAAQ,IAAI,CAAC,IAAI,EAAE,CAAC;YAClB,KAAK,QAAQ,CAAC,CAAC,CAAC;gBACd,MAAM,CAAC,IAAI,CAAC,WAAW,EAAE,4CAA4C,CAAC,CAAC;gBACvE,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;gBACnC,MAAM;YACR,CAAC;YAED,KAAK,OAAO,CAAC,CAAC,CAAC;gBACb,MAAM,CAAC,IAAI,CAAC,WAAW,EAAE,4CAA4C,CAAC,CAAC;gBACvE,MAAM,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;gBACtC,MAAM;YACR,CAAC;QACH,CAAC;IACH,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,GAAG,CAAC,GAAW;QACnB,IAAI,CAAC,IAAI,CAAC,OAAO;YAAE,OAAO,IAAI,CAAC;QAE/B,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,GAAG,GAAG,CAAC;QAEvC,QAAQ,IAAI,CAAC,IAAI,EAAE,CAAC;YAClB,KAAK,QAAQ,CAAC,CAAC,CAAC;gBACd,MAAM,CAAC,IAAI,CAAC,WAAW,EAAE,4CAA4C,CAAC,CAAC;gBACvE,MAAM,KAAK,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;gBAC9C,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;oBAC9B,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;gBAC3B,CAAC;gBACD,OAAO,SAAS,CAAC;YACnB,CAAC;YAED,KAAK,OAAO,CAAC,CAAC,CAAC;gBACb,MAAM,CAAC,IAAI,CAAC,WAAW,EAAE,4CAA4C,CAAC,CAAC;gBACvE,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;gBACpD,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;oBAC9B,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;gBAC3B,CAAC;gBACD,OAAO,SAAS,CAAC;YACnB,CAAC;YAED,OAAO,CAAC,CAAC,CAAC;gBACR,OAAO,IAAI,CAAC;YACd,CAAC;QACH,CAAC;IACH,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,KAAK;QACT,IAAI,CAAC,IAAI,CAAC,OAAO;YAAE,OAAO;QAE1B,QAAQ,IAAI,CAAC,IAAI,EAAE,CAAC;YAClB,KAAK,QAAQ,CAAC,CAAC,CAAC;gBACd,MAAM,CAAC,IAAI,CAAC,WAAW,EAAE,4CAA4C,CAAC,CAAC;gBACvE,IAAI,CAAC,WAAW,CAAC,KAAK,EAAE,CAAC;gBACzB,MAAM;YACR,CAAC;YAED,KAAK,OAAO,CAAC,CAAC,CAAC;gBACb,IAAI,MAAM,GAAG,GAAG,CAAC;gBACjB,GAAG,CAAC;oBACF,MAAM,CAAC,IAAI,CAAC,WAAW,EAAE,4CAA4C,CAAC,CAAC;oBACvE,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,WAAW,CAAC,IAAI,CACvC,MAAM,EACN,OAAO,EACP,GAAG,IAAI,CAAC,SAAS,GAAG,EACpB,OAAO,EACP,IAAI,CACL,CAAC;oBACF,MAAM,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;oBAElB,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;oBACtB,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;wBACpB,MAAM,CAAC,IAAI,CAAC,WAAW,EAAE,4CAA4C,CAAC,CAAC;wBACvE,MAAM,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;oBACnC,CAAC;gBACH,CAAC,QAAQ,MAAM,KAAK,GAAG,EAAE;gBACzB,MAAM;YACR,CAAC;QACH,CAAC;IACH,CAAC;IACD;;OAEG;IACH,KAAK,CAAC,KAAK;QACT,IAAI,CAAC,IAAI,CAAC,OAAO;YAAE,OAAO;QAC1B,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC;QAErB,IAAI,IAAI,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;YAC1B,MAAM,CAAC,IAAI,CAAC,WAAW,EAAE,4CAA4C,CAAC,CAAC;YACvE,MAAM,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE,CAAC;QAChC,CAAC;IACH,CAAC;CACF;AAED,MAAM,CAAC,MAAM,KAAK,GAAG,IAAI,KAAK,EAAE,CAAC","sourcesContent":["import assert from 'node:assert';\n\nimport { Redis } from 'ioredis';\nimport { LRUCache } from 'lru-cache';\n\nimport { logger } from '@prairielearn/logger';\nimport * as Sentry from '@prairielearn/sentry';\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,20 +1,21 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@prairielearn/cache",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.1",
|
|
4
|
+
"type": "module",
|
|
4
5
|
"main": "dist/index.js",
|
|
5
6
|
"scripts": {
|
|
6
7
|
"build": "tsc",
|
|
7
8
|
"dev": "tsc --watch --preserveWatchOutput"
|
|
8
9
|
},
|
|
9
10
|
"dependencies": {
|
|
10
|
-
"@prairielearn/logger": "^
|
|
11
|
-
"@prairielearn/sentry": "^
|
|
12
|
-
"ioredis": "^5.
|
|
13
|
-
"lru-cache": "^10.2.
|
|
14
|
-
"zod": "^3.
|
|
11
|
+
"@prairielearn/logger": "^2.0.1",
|
|
12
|
+
"@prairielearn/sentry": "^2.0.1",
|
|
13
|
+
"ioredis": "^5.4.1",
|
|
14
|
+
"lru-cache": "^10.2.2",
|
|
15
|
+
"zod": "^3.23.8"
|
|
15
16
|
},
|
|
16
17
|
"devDependencies": {
|
|
17
18
|
"@prairielearn/tsconfig": "*",
|
|
18
|
-
"typescript": "^5.4.
|
|
19
|
+
"typescript": "^5.4.5"
|
|
19
20
|
}
|
|
20
21
|
}
|
package/src/index.ts
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
|
+
import assert from 'node:assert';
|
|
2
|
+
|
|
1
3
|
import { Redis } from 'ioredis';
|
|
2
4
|
import { LRUCache } from 'lru-cache';
|
|
5
|
+
|
|
3
6
|
import { logger } from '@prairielearn/logger';
|
|
4
7
|
import * as Sentry from '@prairielearn/sentry';
|
|
5
|
-
import assert from 'node:assert';
|
|
6
8
|
|
|
7
9
|
export class Cache {
|
|
8
10
|
enabled = false;
|