@forklaunch/infrastructure-redis 1.3.15 → 1.4.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/lib/eject/infrastructure/redis.ts +105 -186
- package/lib/index.d.mts +14 -149
- package/lib/index.d.ts +14 -149
- package/lib/index.js +61 -178
- package/lib/index.js.map +1 -1
- package/lib/index.mjs +61 -180
- package/lib/index.mjs.map +1 -1
- package/package.json +5 -5
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
import { safeParse, safeStringify } from '@forklaunch/common';
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
type ComplianceContext,
|
|
4
|
+
TtlCache,
|
|
5
|
+
TtlCacheRecord
|
|
6
|
+
} from '@forklaunch/core/cache';
|
|
3
7
|
import {
|
|
4
8
|
evaluateTelemetryOptions,
|
|
5
9
|
MetricsDefinition,
|
|
6
10
|
OpenTelemetryCollector,
|
|
7
11
|
TelemetryOptions
|
|
8
12
|
} from '@forklaunch/core/http';
|
|
9
|
-
import {
|
|
10
|
-
getCurrentTenantId,
|
|
11
|
-
type FieldEncryptor
|
|
12
|
-
} from '@forklaunch/core/persistence';
|
|
13
|
+
import { type FieldEncryptor } from '@forklaunch/core/persistence';
|
|
13
14
|
import { createClient, RedisClientOptions } from 'redis';
|
|
14
15
|
|
|
15
16
|
/**
|
|
@@ -37,22 +38,19 @@ function isEncrypted(value: string): boolean {
|
|
|
37
38
|
export interface RedisCacheEncryptionOptions {
|
|
38
39
|
/** The FieldEncryptor instance to use for encrypting cache values. */
|
|
39
40
|
encryptor: FieldEncryptor;
|
|
40
|
-
/** Set to true to disable encryption. Defaults to false (encryption enabled). */
|
|
41
|
-
disabled?: boolean;
|
|
42
41
|
}
|
|
43
42
|
|
|
44
43
|
/**
|
|
45
44
|
* Class representing a Redis-based TTL (Time-To-Live) cache.
|
|
46
45
|
* Implements the TtlCache interface to provide caching functionality with automatic expiration.
|
|
47
46
|
*
|
|
48
|
-
* Encryption is
|
|
49
|
-
*
|
|
47
|
+
* Encryption is activated per-operation when a `compliance` context is provided.
|
|
48
|
+
* Without it, values are stored and read as plaintext.
|
|
50
49
|
*/
|
|
51
50
|
export class RedisTtlCache implements TtlCache {
|
|
52
51
|
private client;
|
|
53
52
|
private telemetryOptions;
|
|
54
53
|
private encryptor?: FieldEncryptor;
|
|
55
|
-
private encryptionDisabled: boolean;
|
|
56
54
|
|
|
57
55
|
/**
|
|
58
56
|
* Creates an instance of RedisTtlCache.
|
|
@@ -61,7 +59,7 @@ export class RedisTtlCache implements TtlCache {
|
|
|
61
59
|
* @param {OpenTelemetryCollector<MetricsDefinition>} openTelemetryCollector - Collector for OpenTelemetry metrics
|
|
62
60
|
* @param {RedisClientOptions} options - Configuration options for the Redis client
|
|
63
61
|
* @param {TelemetryOptions} telemetryOptions - Configuration options for telemetry
|
|
64
|
-
* @param {RedisCacheEncryptionOptions} encryption - Encryption configuration
|
|
62
|
+
* @param {RedisCacheEncryptionOptions} encryption - Encryption configuration
|
|
65
63
|
*/
|
|
66
64
|
constructor(
|
|
67
65
|
private ttlMilliseconds: number,
|
|
@@ -73,7 +71,6 @@ export class RedisTtlCache implements TtlCache {
|
|
|
73
71
|
this.telemetryOptions = evaluateTelemetryOptions(telemetryOptions);
|
|
74
72
|
this.client = createClient(options);
|
|
75
73
|
this.encryptor = encryption.encryptor;
|
|
76
|
-
this.encryptionDisabled = encryption.disabled ?? false;
|
|
77
74
|
if (this.telemetryOptions.enabled.logging) {
|
|
78
75
|
this.client.on('error', (err) => this.openTelemetryCollector.error(err));
|
|
79
76
|
this.client.connect().catch(this.openTelemetryCollector.error);
|
|
@@ -81,41 +78,39 @@ export class RedisTtlCache implements TtlCache {
|
|
|
81
78
|
}
|
|
82
79
|
|
|
83
80
|
// ---------------------------------------------------------------------------
|
|
84
|
-
// Encryption helpers
|
|
81
|
+
// Encryption helpers — only active when compliance context is provided
|
|
85
82
|
// ---------------------------------------------------------------------------
|
|
86
83
|
|
|
87
|
-
private encryptValue(
|
|
88
|
-
|
|
84
|
+
private encryptValue(
|
|
85
|
+
serialized: string,
|
|
86
|
+
compliance?: ComplianceContext
|
|
87
|
+
): string {
|
|
88
|
+
if (!compliance || !this.encryptor) return serialized;
|
|
89
89
|
return (
|
|
90
|
-
this.encryptor.encrypt(serialized,
|
|
90
|
+
this.encryptor.encrypt(serialized, compliance.tenantId) ?? serialized
|
|
91
91
|
);
|
|
92
92
|
}
|
|
93
93
|
|
|
94
|
-
private decryptValue(value: string): string {
|
|
95
|
-
if (!
|
|
94
|
+
private decryptValue(value: string, compliance?: ComplianceContext): string {
|
|
95
|
+
if (!compliance || !this.encryptor) return value;
|
|
96
96
|
if (!isEncrypted(value)) return value;
|
|
97
97
|
try {
|
|
98
|
-
return this.encryptor.decrypt(value,
|
|
98
|
+
return this.encryptor.decrypt(value, compliance.tenantId) ?? value;
|
|
99
99
|
} catch {
|
|
100
100
|
return value;
|
|
101
101
|
}
|
|
102
102
|
}
|
|
103
103
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
* @template T - The expected type of the parsed value
|
|
109
|
-
* @param {RedisCommandRawReply} value - The raw value from Redis to parse
|
|
110
|
-
* @returns {T} The parsed value cast to type T
|
|
111
|
-
*/
|
|
112
|
-
private parseValue<T>(value: RedisCommandRawReply): T {
|
|
104
|
+
private parseValue<T>(
|
|
105
|
+
value: RedisCommandRawReply,
|
|
106
|
+
compliance?: ComplianceContext
|
|
107
|
+
): T {
|
|
113
108
|
if (value == null) {
|
|
114
109
|
return null as T;
|
|
115
110
|
}
|
|
116
111
|
|
|
117
112
|
if (Array.isArray(value)) {
|
|
118
|
-
return value.map((v) => this.parseValue<T>(v)) as T;
|
|
113
|
+
return value.map((v) => this.parseValue<T>(v, compliance)) as T;
|
|
119
114
|
}
|
|
120
115
|
|
|
121
116
|
if (Buffer.isBuffer(value)) {
|
|
@@ -125,96 +120,75 @@ export class RedisTtlCache implements TtlCache {
|
|
|
125
120
|
switch (typeof value) {
|
|
126
121
|
case 'object':
|
|
127
122
|
case 'string':
|
|
128
|
-
return safeParse(this.decryptValue(String(value))) as T;
|
|
123
|
+
return safeParse(this.decryptValue(String(value), compliance)) as T;
|
|
129
124
|
case 'number':
|
|
130
125
|
return value as T;
|
|
131
126
|
}
|
|
132
127
|
}
|
|
133
128
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
* @returns {Promise<void>} A promise that resolves when the value is cached
|
|
143
|
-
*/
|
|
144
|
-
async putRecord<T>({
|
|
145
|
-
key,
|
|
146
|
-
value,
|
|
147
|
-
ttlMilliseconds = this.ttlMilliseconds
|
|
148
|
-
}: TtlCacheRecord<T>): Promise<void> {
|
|
129
|
+
// ---------------------------------------------------------------------------
|
|
130
|
+
// TtlCache implementation
|
|
131
|
+
// ---------------------------------------------------------------------------
|
|
132
|
+
|
|
133
|
+
async putRecord<T>(
|
|
134
|
+
{ key, value, ttlMilliseconds = this.ttlMilliseconds }: TtlCacheRecord<T>,
|
|
135
|
+
compliance?: ComplianceContext
|
|
136
|
+
): Promise<void> {
|
|
149
137
|
if (this.telemetryOptions.enabled.logging) {
|
|
150
138
|
this.openTelemetryCollector.info(`Putting record into cache: ${key}`);
|
|
151
139
|
}
|
|
152
|
-
await this.client.set(
|
|
153
|
-
|
|
154
|
-
|
|
140
|
+
await this.client.set(
|
|
141
|
+
key,
|
|
142
|
+
this.encryptValue(safeStringify(value), compliance),
|
|
143
|
+
{ PX: ttlMilliseconds }
|
|
144
|
+
);
|
|
155
145
|
}
|
|
156
146
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
* @param {TtlCacheRecord<T>[]} cacheRecords - Array of cache records to store
|
|
162
|
-
* @returns {Promise<void>} A promise that resolves when all values are cached
|
|
163
|
-
*/
|
|
164
|
-
async putBatchRecords<T>(cacheRecords: TtlCacheRecord<T>[]): Promise<void> {
|
|
147
|
+
async putBatchRecords<T>(
|
|
148
|
+
cacheRecords: TtlCacheRecord<T>[],
|
|
149
|
+
compliance?: ComplianceContext
|
|
150
|
+
): Promise<void> {
|
|
165
151
|
const multiCommand = this.client.multi();
|
|
166
152
|
for (const { key, value, ttlMilliseconds } of cacheRecords) {
|
|
167
|
-
multiCommand.set(
|
|
168
|
-
|
|
169
|
-
|
|
153
|
+
multiCommand.set(
|
|
154
|
+
key,
|
|
155
|
+
this.encryptValue(safeStringify(value), compliance),
|
|
156
|
+
{ PX: ttlMilliseconds || this.ttlMilliseconds }
|
|
157
|
+
);
|
|
170
158
|
}
|
|
171
159
|
await multiCommand.exec();
|
|
172
160
|
}
|
|
173
161
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
await this.client.lPush(queueName, this.encryptValue(safeStringify(value)));
|
|
162
|
+
async enqueueRecord<T>(
|
|
163
|
+
queueName: string,
|
|
164
|
+
value: T,
|
|
165
|
+
compliance?: ComplianceContext
|
|
166
|
+
): Promise<void> {
|
|
167
|
+
await this.client.lPush(
|
|
168
|
+
queueName,
|
|
169
|
+
this.encryptValue(safeStringify(value), compliance)
|
|
170
|
+
);
|
|
184
171
|
}
|
|
185
172
|
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
* @param {T[]} values - Array of values to add to the list
|
|
192
|
-
* @returns {Promise<void>} A promise that resolves when all values are enqueued
|
|
193
|
-
*/
|
|
194
|
-
async enqueueBatchRecords<T>(queueName: string, values: T[]): Promise<void> {
|
|
173
|
+
async enqueueBatchRecords<T>(
|
|
174
|
+
queueName: string,
|
|
175
|
+
values: T[],
|
|
176
|
+
compliance?: ComplianceContext
|
|
177
|
+
): Promise<void> {
|
|
195
178
|
const multiCommand = this.client.multi();
|
|
196
179
|
for (const value of values) {
|
|
197
|
-
multiCommand.lPush(
|
|
180
|
+
multiCommand.lPush(
|
|
181
|
+
queueName,
|
|
182
|
+
this.encryptValue(safeStringify(value), compliance)
|
|
183
|
+
);
|
|
198
184
|
}
|
|
199
185
|
await multiCommand.exec();
|
|
200
186
|
}
|
|
201
187
|
|
|
202
|
-
/**
|
|
203
|
-
* Deletes a record from the Redis cache.
|
|
204
|
-
*
|
|
205
|
-
* @param {string} cacheRecordKey - The key of the record to delete
|
|
206
|
-
* @returns {Promise<void>} A promise that resolves when the record is deleted
|
|
207
|
-
*/
|
|
208
188
|
async deleteRecord(cacheRecordKey: string): Promise<void> {
|
|
209
189
|
await this.client.del(cacheRecordKey);
|
|
210
190
|
}
|
|
211
191
|
|
|
212
|
-
/**
|
|
213
|
-
* Deletes multiple records from the Redis cache in a single transaction.
|
|
214
|
-
*
|
|
215
|
-
* @param {string[]} cacheRecordKeys - Array of keys to delete
|
|
216
|
-
* @returns {Promise<void>} A promise that resolves when all records are deleted
|
|
217
|
-
*/
|
|
218
192
|
async deleteBatchRecords(cacheRecordKeys: string[]): Promise<void> {
|
|
219
193
|
const multiCommand = this.client.multi();
|
|
220
194
|
for (const key of cacheRecordKeys) {
|
|
@@ -223,33 +197,21 @@ export class RedisTtlCache implements TtlCache {
|
|
|
223
197
|
await multiCommand.exec();
|
|
224
198
|
}
|
|
225
199
|
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
* @param {string} queueName - The name of the Redis list
|
|
231
|
-
* @returns {Promise<T>} A promise that resolves with the dequeued value
|
|
232
|
-
* @throws {Error} If the queue is empty
|
|
233
|
-
*/
|
|
234
|
-
async dequeueRecord<T>(queueName: string): Promise<T> {
|
|
200
|
+
async dequeueRecord<T>(
|
|
201
|
+
queueName: string,
|
|
202
|
+
compliance?: ComplianceContext
|
|
203
|
+
): Promise<T> {
|
|
235
204
|
const value = await this.client.rPop(queueName);
|
|
236
205
|
if (value === null) {
|
|
237
206
|
throw new Error(`Queue is empty: ${queueName}`);
|
|
238
207
|
}
|
|
239
|
-
return safeParse(this.decryptValue(value)) as T;
|
|
208
|
+
return safeParse(this.decryptValue(value, compliance)) as T;
|
|
240
209
|
}
|
|
241
210
|
|
|
242
|
-
/**
|
|
243
|
-
* Removes and returns multiple elements from the right end of a Redis list.
|
|
244
|
-
*
|
|
245
|
-
* @template T - The type of values being dequeued
|
|
246
|
-
* @param {string} queueName - The name of the Redis list
|
|
247
|
-
* @param {number} pageSize - Maximum number of elements to dequeue
|
|
248
|
-
* @returns {Promise<T[]>} A promise that resolves with an array of dequeued values
|
|
249
|
-
*/
|
|
250
211
|
async dequeueBatchRecords<T>(
|
|
251
212
|
queueName: string,
|
|
252
|
-
pageSize: number
|
|
213
|
+
pageSize: number,
|
|
214
|
+
compliance?: ComplianceContext
|
|
253
215
|
): Promise<T[]> {
|
|
254
216
|
const multiCommand = this.client.multi();
|
|
255
217
|
for (let i = 0; i < pageSize; i++) {
|
|
@@ -258,20 +220,15 @@ export class RedisTtlCache implements TtlCache {
|
|
|
258
220
|
const values = await multiCommand.exec();
|
|
259
221
|
return values
|
|
260
222
|
.map((value) =>
|
|
261
|
-
this.parseValue<T>(value as unknown as RedisCommandRawReply)
|
|
223
|
+
this.parseValue<T>(value as unknown as RedisCommandRawReply, compliance)
|
|
262
224
|
)
|
|
263
225
|
.filter(Boolean);
|
|
264
226
|
}
|
|
265
227
|
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
* @param {string} cacheRecordKey - The key of the record to read
|
|
271
|
-
* @returns {Promise<TtlCacheRecord<T>>} A promise that resolves with the cache record
|
|
272
|
-
* @throws {Error} If the record is not found
|
|
273
|
-
*/
|
|
274
|
-
async readRecord<T>(cacheRecordKey: string): Promise<TtlCacheRecord<T>> {
|
|
228
|
+
async readRecord<T>(
|
|
229
|
+
cacheRecordKey: string,
|
|
230
|
+
compliance?: ComplianceContext
|
|
231
|
+
): Promise<TtlCacheRecord<T>> {
|
|
275
232
|
const [value, ttl] = await this.client
|
|
276
233
|
.multi()
|
|
277
234
|
.get(cacheRecordKey)
|
|
@@ -283,21 +240,21 @@ export class RedisTtlCache implements TtlCache {
|
|
|
283
240
|
|
|
284
241
|
return {
|
|
285
242
|
key: cacheRecordKey,
|
|
286
|
-
value: this.parseValue<T>(
|
|
243
|
+
value: this.parseValue<T>(
|
|
244
|
+
value as unknown as RedisCommandRawReply,
|
|
245
|
+
compliance
|
|
246
|
+
),
|
|
287
247
|
ttlMilliseconds:
|
|
288
|
-
this.parseValue<number>(
|
|
248
|
+
this.parseValue<number>(
|
|
249
|
+
ttl as unknown as RedisCommandRawReply,
|
|
250
|
+
compliance
|
|
251
|
+
) * 1000
|
|
289
252
|
};
|
|
290
253
|
}
|
|
291
254
|
|
|
292
|
-
/**
|
|
293
|
-
* Reads multiple records from the Redis cache.
|
|
294
|
-
*
|
|
295
|
-
* @template T - The type of values being read
|
|
296
|
-
* @param {string[] | string} cacheRecordKeysOrPrefix - Array of keys to read, or a prefix pattern
|
|
297
|
-
* @returns {Promise<TtlCacheRecord<T>[]>} A promise that resolves with an array of cache records
|
|
298
|
-
*/
|
|
299
255
|
async readBatchRecords<T>(
|
|
300
|
-
cacheRecordKeysOrPrefix: string[] | string
|
|
256
|
+
cacheRecordKeysOrPrefix: string[] | string,
|
|
257
|
+
compliance?: ComplianceContext
|
|
301
258
|
): Promise<TtlCacheRecord<T>[]> {
|
|
302
259
|
const keys = Array.isArray(cacheRecordKeysOrPrefix)
|
|
303
260
|
? cacheRecordKeysOrPrefix
|
|
@@ -311,10 +268,12 @@ export class RedisTtlCache implements TtlCache {
|
|
|
311
268
|
return values.reduce<TtlCacheRecord<T>[]>((acc, value, index) => {
|
|
312
269
|
if (index % 2 === 0) {
|
|
313
270
|
const maybeValue = this.parseValue<T>(
|
|
314
|
-
value as unknown as RedisCommandRawReply
|
|
271
|
+
value as unknown as RedisCommandRawReply,
|
|
272
|
+
compliance
|
|
315
273
|
);
|
|
316
274
|
const ttl = this.parseValue<number>(
|
|
317
|
-
values[index + 1] as unknown as RedisCommandRawReply
|
|
275
|
+
values[index + 1] as unknown as RedisCommandRawReply,
|
|
276
|
+
compliance
|
|
318
277
|
);
|
|
319
278
|
if (maybeValue && ttl) {
|
|
320
279
|
acc.push({
|
|
@@ -328,34 +287,15 @@ export class RedisTtlCache implements TtlCache {
|
|
|
328
287
|
}, []);
|
|
329
288
|
}
|
|
330
289
|
|
|
331
|
-
/**
|
|
332
|
-
* Lists all keys in the Redis cache that match a pattern prefix.
|
|
333
|
-
*
|
|
334
|
-
* @param {string} pattern_prefix - The prefix pattern to match keys against
|
|
335
|
-
* @returns {Promise<string[]>} A promise that resolves with an array of matching keys
|
|
336
|
-
*/
|
|
337
290
|
async listKeys(pattern_prefix: string): Promise<string[]> {
|
|
338
|
-
|
|
339
|
-
return keys;
|
|
291
|
+
return this.client.keys(pattern_prefix + '*');
|
|
340
292
|
}
|
|
341
293
|
|
|
342
|
-
/**
|
|
343
|
-
* Checks if a record exists in the Redis cache.
|
|
344
|
-
*
|
|
345
|
-
* @param {string} cacheRecordKey - The key to check
|
|
346
|
-
* @returns {Promise<boolean>} A promise that resolves with true if the record exists, false otherwise
|
|
347
|
-
*/
|
|
348
294
|
async peekRecord(cacheRecordKey: string): Promise<boolean> {
|
|
349
295
|
const result = await this.client.exists(cacheRecordKey);
|
|
350
296
|
return result === 1;
|
|
351
297
|
}
|
|
352
298
|
|
|
353
|
-
/**
|
|
354
|
-
* Checks if multiple records exist in the Redis cache.
|
|
355
|
-
*
|
|
356
|
-
* @param {string[] | string} cacheRecordKeysOrPrefix - Array of keys to check, or a prefix pattern
|
|
357
|
-
* @returns {Promise<boolean[]>} A promise that resolves with an array of existence booleans
|
|
358
|
-
*/
|
|
359
299
|
async peekBatchRecords(
|
|
360
300
|
cacheRecordKeysOrPrefix: string[] | string
|
|
361
301
|
): Promise<boolean[]> {
|
|
@@ -370,54 +310,33 @@ export class RedisTtlCache implements TtlCache {
|
|
|
370
310
|
return results.map((result) => (result as unknown as number) === 1);
|
|
371
311
|
}
|
|
372
312
|
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
* @param {string} queueName - The name of the Redis queue
|
|
378
|
-
* @returns {Promise<T>} A promise that resolves with the peeked value
|
|
379
|
-
*/
|
|
380
|
-
async peekQueueRecord<T>(queueName: string): Promise<T> {
|
|
313
|
+
async peekQueueRecord<T>(
|
|
314
|
+
queueName: string,
|
|
315
|
+
compliance?: ComplianceContext
|
|
316
|
+
): Promise<T> {
|
|
381
317
|
const value = await this.client.lRange(queueName, 0, 0);
|
|
382
|
-
return this.parseValue<T>(value[0]);
|
|
318
|
+
return this.parseValue<T>(value[0], compliance);
|
|
383
319
|
}
|
|
384
320
|
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
* @param {number} pageSize - The number of records to peek at
|
|
391
|
-
* @returns {Promise<T[]>} A promise that resolves with an array of peeked values
|
|
392
|
-
*/
|
|
393
|
-
async peekQueueRecords<T>(queueName: string, pageSize: number): Promise<T[]> {
|
|
321
|
+
async peekQueueRecords<T>(
|
|
322
|
+
queueName: string,
|
|
323
|
+
pageSize: number,
|
|
324
|
+
compliance?: ComplianceContext
|
|
325
|
+
): Promise<T[]> {
|
|
394
326
|
const values = await this.client.lRange(queueName, 0, pageSize - 1);
|
|
395
|
-
return values
|
|
327
|
+
return values
|
|
328
|
+
.map((value) => this.parseValue<T>(value, compliance))
|
|
329
|
+
.filter(Boolean);
|
|
396
330
|
}
|
|
397
331
|
|
|
398
|
-
/**
|
|
399
|
-
* Gracefully disconnects from the Redis server.
|
|
400
|
-
*
|
|
401
|
-
* @returns {Promise<void>} A promise that resolves when the connection is closed
|
|
402
|
-
*/
|
|
403
332
|
async disconnect(): Promise<void> {
|
|
404
333
|
await this.client.quit();
|
|
405
334
|
}
|
|
406
335
|
|
|
407
|
-
/**
|
|
408
|
-
* Gets the default Time-To-Live value in milliseconds.
|
|
409
|
-
*
|
|
410
|
-
* @returns {number} The default TTL in milliseconds
|
|
411
|
-
*/
|
|
412
336
|
getTtlMilliseconds(): number {
|
|
413
337
|
return this.ttlMilliseconds;
|
|
414
338
|
}
|
|
415
339
|
|
|
416
|
-
/**
|
|
417
|
-
* Gets the underlying Redis client instance.
|
|
418
|
-
*
|
|
419
|
-
* @returns {typeof this.client} The Redis client instance
|
|
420
|
-
*/
|
|
421
340
|
getClient(): typeof this.client {
|
|
422
341
|
return this.client;
|
|
423
342
|
}
|
package/lib/index.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { TtlCache, TtlCacheRecord } from '@forklaunch/core/cache';
|
|
1
|
+
import { TtlCache, TtlCacheRecord, ComplianceContext } from '@forklaunch/core/cache';
|
|
2
2
|
import { OpenTelemetryCollector, MetricsDefinition, TelemetryOptions } from '@forklaunch/core/http';
|
|
3
3
|
import { FieldEncryptor } from '@forklaunch/core/persistence';
|
|
4
4
|
import { RedisClientOptions } from 'redis';
|
|
@@ -10,15 +10,13 @@ import { RedisClientOptions } from 'redis';
|
|
|
10
10
|
interface RedisCacheEncryptionOptions {
|
|
11
11
|
/** The FieldEncryptor instance to use for encrypting cache values. */
|
|
12
12
|
encryptor: FieldEncryptor;
|
|
13
|
-
/** Set to true to disable encryption. Defaults to false (encryption enabled). */
|
|
14
|
-
disabled?: boolean;
|
|
15
13
|
}
|
|
16
14
|
/**
|
|
17
15
|
* Class representing a Redis-based TTL (Time-To-Live) cache.
|
|
18
16
|
* Implements the TtlCache interface to provide caching functionality with automatic expiration.
|
|
19
17
|
*
|
|
20
|
-
* Encryption is
|
|
21
|
-
*
|
|
18
|
+
* Encryption is activated per-operation when a `compliance` context is provided.
|
|
19
|
+
* Without it, values are stored and read as plaintext.
|
|
22
20
|
*/
|
|
23
21
|
declare class RedisTtlCache implements TtlCache {
|
|
24
22
|
private ttlMilliseconds;
|
|
@@ -26,7 +24,6 @@ declare class RedisTtlCache implements TtlCache {
|
|
|
26
24
|
private client;
|
|
27
25
|
private telemetryOptions;
|
|
28
26
|
private encryptor?;
|
|
29
|
-
private encryptionDisabled;
|
|
30
27
|
/**
|
|
31
28
|
* Creates an instance of RedisTtlCache.
|
|
32
29
|
*
|
|
@@ -34,161 +31,29 @@ declare class RedisTtlCache implements TtlCache {
|
|
|
34
31
|
* @param {OpenTelemetryCollector<MetricsDefinition>} openTelemetryCollector - Collector for OpenTelemetry metrics
|
|
35
32
|
* @param {RedisClientOptions} options - Configuration options for the Redis client
|
|
36
33
|
* @param {TelemetryOptions} telemetryOptions - Configuration options for telemetry
|
|
37
|
-
* @param {RedisCacheEncryptionOptions} encryption - Encryption configuration
|
|
34
|
+
* @param {RedisCacheEncryptionOptions} encryption - Encryption configuration
|
|
38
35
|
*/
|
|
39
36
|
constructor(ttlMilliseconds: number, openTelemetryCollector: OpenTelemetryCollector<MetricsDefinition>, options: RedisClientOptions, telemetryOptions: TelemetryOptions, encryption: RedisCacheEncryptionOptions);
|
|
40
37
|
private encryptValue;
|
|
41
38
|
private decryptValue;
|
|
42
|
-
/**
|
|
43
|
-
* Parses a raw Redis reply into the expected type.
|
|
44
|
-
* Handles null values, arrays, buffers, and JSON strings.
|
|
45
|
-
*
|
|
46
|
-
* @template T - The expected type of the parsed value
|
|
47
|
-
* @param {RedisCommandRawReply} value - The raw value from Redis to parse
|
|
48
|
-
* @returns {T} The parsed value cast to type T
|
|
49
|
-
*/
|
|
50
39
|
private parseValue;
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
* @param {TtlCacheRecord<T>} param0 - The cache record containing key, value and optional TTL
|
|
56
|
-
* @param {string} param0.key - The key to store the value under
|
|
57
|
-
* @param {T} param0.value - The value to cache
|
|
58
|
-
* @param {number} [param0.ttlMilliseconds] - Optional TTL in milliseconds, defaults to constructor value
|
|
59
|
-
* @returns {Promise<void>} A promise that resolves when the value is cached
|
|
60
|
-
*/
|
|
61
|
-
putRecord<T>({ key, value, ttlMilliseconds }: TtlCacheRecord<T>): Promise<void>;
|
|
62
|
-
/**
|
|
63
|
-
* Puts multiple records into the Redis cache in a single transaction.
|
|
64
|
-
*
|
|
65
|
-
* @template T - The type of values being cached
|
|
66
|
-
* @param {TtlCacheRecord<T>[]} cacheRecords - Array of cache records to store
|
|
67
|
-
* @returns {Promise<void>} A promise that resolves when all values are cached
|
|
68
|
-
*/
|
|
69
|
-
putBatchRecords<T>(cacheRecords: TtlCacheRecord<T>[]): Promise<void>;
|
|
70
|
-
/**
|
|
71
|
-
* Adds a value to the left end of a Redis list.
|
|
72
|
-
*
|
|
73
|
-
* @template T - The type of value being enqueued
|
|
74
|
-
* @param {string} queueName - The name of the Redis list
|
|
75
|
-
* @param {T} value - The value to add to the list
|
|
76
|
-
* @returns {Promise<void>} A promise that resolves when the value is enqueued
|
|
77
|
-
*/
|
|
78
|
-
enqueueRecord<T>(queueName: string, value: T): Promise<void>;
|
|
79
|
-
/**
|
|
80
|
-
* Adds multiple values to the left end of a Redis list in a single transaction.
|
|
81
|
-
*
|
|
82
|
-
* @template T - The type of values being enqueued
|
|
83
|
-
* @param {string} queueName - The name of the Redis list
|
|
84
|
-
* @param {T[]} values - Array of values to add to the list
|
|
85
|
-
* @returns {Promise<void>} A promise that resolves when all values are enqueued
|
|
86
|
-
*/
|
|
87
|
-
enqueueBatchRecords<T>(queueName: string, values: T[]): Promise<void>;
|
|
88
|
-
/**
|
|
89
|
-
* Deletes a record from the Redis cache.
|
|
90
|
-
*
|
|
91
|
-
* @param {string} cacheRecordKey - The key of the record to delete
|
|
92
|
-
* @returns {Promise<void>} A promise that resolves when the record is deleted
|
|
93
|
-
*/
|
|
40
|
+
putRecord<T>({ key, value, ttlMilliseconds }: TtlCacheRecord<T>, compliance?: ComplianceContext): Promise<void>;
|
|
41
|
+
putBatchRecords<T>(cacheRecords: TtlCacheRecord<T>[], compliance?: ComplianceContext): Promise<void>;
|
|
42
|
+
enqueueRecord<T>(queueName: string, value: T, compliance?: ComplianceContext): Promise<void>;
|
|
43
|
+
enqueueBatchRecords<T>(queueName: string, values: T[], compliance?: ComplianceContext): Promise<void>;
|
|
94
44
|
deleteRecord(cacheRecordKey: string): Promise<void>;
|
|
95
|
-
/**
|
|
96
|
-
* Deletes multiple records from the Redis cache in a single transaction.
|
|
97
|
-
*
|
|
98
|
-
* @param {string[]} cacheRecordKeys - Array of keys to delete
|
|
99
|
-
* @returns {Promise<void>} A promise that resolves when all records are deleted
|
|
100
|
-
*/
|
|
101
45
|
deleteBatchRecords(cacheRecordKeys: string[]): Promise<void>;
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
* @param {string} queueName - The name of the Redis list
|
|
107
|
-
* @returns {Promise<T>} A promise that resolves with the dequeued value
|
|
108
|
-
* @throws {Error} If the queue is empty
|
|
109
|
-
*/
|
|
110
|
-
dequeueRecord<T>(queueName: string): Promise<T>;
|
|
111
|
-
/**
|
|
112
|
-
* Removes and returns multiple elements from the right end of a Redis list.
|
|
113
|
-
*
|
|
114
|
-
* @template T - The type of values being dequeued
|
|
115
|
-
* @param {string} queueName - The name of the Redis list
|
|
116
|
-
* @param {number} pageSize - Maximum number of elements to dequeue
|
|
117
|
-
* @returns {Promise<T[]>} A promise that resolves with an array of dequeued values
|
|
118
|
-
*/
|
|
119
|
-
dequeueBatchRecords<T>(queueName: string, pageSize: number): Promise<T[]>;
|
|
120
|
-
/**
|
|
121
|
-
* Reads a record from the Redis cache.
|
|
122
|
-
*
|
|
123
|
-
* @template T - The type of value being read
|
|
124
|
-
* @param {string} cacheRecordKey - The key of the record to read
|
|
125
|
-
* @returns {Promise<TtlCacheRecord<T>>} A promise that resolves with the cache record
|
|
126
|
-
* @throws {Error} If the record is not found
|
|
127
|
-
*/
|
|
128
|
-
readRecord<T>(cacheRecordKey: string): Promise<TtlCacheRecord<T>>;
|
|
129
|
-
/**
|
|
130
|
-
* Reads multiple records from the Redis cache.
|
|
131
|
-
*
|
|
132
|
-
* @template T - The type of values being read
|
|
133
|
-
* @param {string[] | string} cacheRecordKeysOrPrefix - Array of keys to read, or a prefix pattern
|
|
134
|
-
* @returns {Promise<TtlCacheRecord<T>[]>} A promise that resolves with an array of cache records
|
|
135
|
-
*/
|
|
136
|
-
readBatchRecords<T>(cacheRecordKeysOrPrefix: string[] | string): Promise<TtlCacheRecord<T>[]>;
|
|
137
|
-
/**
|
|
138
|
-
* Lists all keys in the Redis cache that match a pattern prefix.
|
|
139
|
-
*
|
|
140
|
-
* @param {string} pattern_prefix - The prefix pattern to match keys against
|
|
141
|
-
* @returns {Promise<string[]>} A promise that resolves with an array of matching keys
|
|
142
|
-
*/
|
|
46
|
+
dequeueRecord<T>(queueName: string, compliance?: ComplianceContext): Promise<T>;
|
|
47
|
+
dequeueBatchRecords<T>(queueName: string, pageSize: number, compliance?: ComplianceContext): Promise<T[]>;
|
|
48
|
+
readRecord<T>(cacheRecordKey: string, compliance?: ComplianceContext): Promise<TtlCacheRecord<T>>;
|
|
49
|
+
readBatchRecords<T>(cacheRecordKeysOrPrefix: string[] | string, compliance?: ComplianceContext): Promise<TtlCacheRecord<T>[]>;
|
|
143
50
|
listKeys(pattern_prefix: string): Promise<string[]>;
|
|
144
|
-
/**
|
|
145
|
-
* Checks if a record exists in the Redis cache.
|
|
146
|
-
*
|
|
147
|
-
* @param {string} cacheRecordKey - The key to check
|
|
148
|
-
* @returns {Promise<boolean>} A promise that resolves with true if the record exists, false otherwise
|
|
149
|
-
*/
|
|
150
51
|
peekRecord(cacheRecordKey: string): Promise<boolean>;
|
|
151
|
-
/**
|
|
152
|
-
* Checks if multiple records exist in the Redis cache.
|
|
153
|
-
*
|
|
154
|
-
* @param {string[] | string} cacheRecordKeysOrPrefix - Array of keys to check, or a prefix pattern
|
|
155
|
-
* @returns {Promise<boolean[]>} A promise that resolves with an array of existence booleans
|
|
156
|
-
*/
|
|
157
52
|
peekBatchRecords(cacheRecordKeysOrPrefix: string[] | string): Promise<boolean[]>;
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
*
|
|
161
|
-
* @template T - The type of value being peeked at
|
|
162
|
-
* @param {string} queueName - The name of the Redis queue
|
|
163
|
-
* @returns {Promise<T>} A promise that resolves with the peeked value
|
|
164
|
-
*/
|
|
165
|
-
peekQueueRecord<T>(queueName: string): Promise<T>;
|
|
166
|
-
/**
|
|
167
|
-
* Peeks at multiple records in the Redis cache.
|
|
168
|
-
*
|
|
169
|
-
* @template T - The type of values being peeked at
|
|
170
|
-
* @param {string} queueName - The name of the Redis queue
|
|
171
|
-
* @param {number} pageSize - The number of records to peek at
|
|
172
|
-
* @returns {Promise<T[]>} A promise that resolves with an array of peeked values
|
|
173
|
-
*/
|
|
174
|
-
peekQueueRecords<T>(queueName: string, pageSize: number): Promise<T[]>;
|
|
175
|
-
/**
|
|
176
|
-
* Gracefully disconnects from the Redis server.
|
|
177
|
-
*
|
|
178
|
-
* @returns {Promise<void>} A promise that resolves when the connection is closed
|
|
179
|
-
*/
|
|
53
|
+
peekQueueRecord<T>(queueName: string, compliance?: ComplianceContext): Promise<T>;
|
|
54
|
+
peekQueueRecords<T>(queueName: string, pageSize: number, compliance?: ComplianceContext): Promise<T[]>;
|
|
180
55
|
disconnect(): Promise<void>;
|
|
181
|
-
/**
|
|
182
|
-
* Gets the default Time-To-Live value in milliseconds.
|
|
183
|
-
*
|
|
184
|
-
* @returns {number} The default TTL in milliseconds
|
|
185
|
-
*/
|
|
186
56
|
getTtlMilliseconds(): number;
|
|
187
|
-
/**
|
|
188
|
-
* Gets the underlying Redis client instance.
|
|
189
|
-
*
|
|
190
|
-
* @returns {typeof this.client} The Redis client instance
|
|
191
|
-
*/
|
|
192
57
|
getClient(): typeof this.client;
|
|
193
58
|
}
|
|
194
59
|
|