@geekmidas/cache 0.0.6 → 0.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/README.md +68 -3
- package/dist/{chunk-DWy1uDak.cjs → chunk-CUT6urMc.cjs} +0 -9
- package/dist/expo.cjs +4 -3
- package/dist/expo.cjs.map +1 -0
- package/dist/expo.d.cts +6 -5
- package/dist/expo.d.mts +6 -5
- package/dist/expo.mjs +3 -2
- package/dist/expo.mjs.map +1 -0
- package/dist/{index-B6eF5Yxi.d.cts → index-CExVL1mV.d.cts} +7 -5
- package/dist/{index-Bv61mxVT.d.mts → index-M02PehQA.d.mts} +7 -5
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.mts +1 -1
- package/dist/index.mjs +1 -1
- package/dist/memory.cjs +35 -3
- package/dist/memory.cjs.map +1 -0
- package/dist/memory.d.cts +6 -5
- package/dist/memory.d.mts +6 -5
- package/dist/memory.mjs +34 -3
- package/dist/memory.mjs.map +1 -0
- package/dist/{src-DVpoP03o.mjs → src-CrE4Nl5T.mjs} +2 -1
- package/dist/src-CrE4Nl5T.mjs.map +1 -0
- package/dist/{src-C7d6HaTp.cjs → src-zfYb7mdS.cjs} +3 -2
- package/dist/src-zfYb7mdS.cjs.map +1 -0
- package/dist/upstash.cjs +32 -2
- package/dist/upstash.cjs.map +1 -0
- package/dist/upstash.d.cts +6 -5
- package/dist/upstash.d.mts +6 -5
- package/dist/upstash.mjs +31 -2
- package/dist/upstash.mjs.map +1 -0
- package/package.json +6 -2
- package/src/__benchmarks__/memory.bench.ts +51 -0
- package/src/__tests__/cache.spec.ts +31 -35
- package/src/__tests__/integration.spec.ts +32 -23
- package/src/__tests__/memory.spec.ts +1 -1
- package/src/__tests__/upstash.spec.ts +1 -1
- package/src/expo.ts +3 -4
- package/src/index.ts +5 -4
- package/src/memory.ts +6 -5
- package/src/upstash.ts +4 -4
- package/dist/__tests__/cache.spec.cjs +0 -77
- package/dist/__tests__/cache.spec.d.cts +0 -1
- package/dist/__tests__/cache.spec.d.mts +0 -1
- package/dist/__tests__/cache.spec.mjs +0 -77
- package/dist/__tests__/integration.spec.cjs +0 -235
- package/dist/__tests__/integration.spec.d.cts +0 -1
- package/dist/__tests__/integration.spec.d.mts +0 -1
- package/dist/__tests__/integration.spec.mjs +0 -235
- package/dist/__tests__/memory.spec.cjs +0 -126
- package/dist/__tests__/memory.spec.d.cts +0 -1
- package/dist/__tests__/memory.spec.d.mts +0 -1
- package/dist/__tests__/memory.spec.mjs +0 -126
- package/dist/__tests__/upstash.spec.cjs +0 -201
- package/dist/__tests__/upstash.spec.d.cts +0 -1
- package/dist/__tests__/upstash.spec.d.mts +0 -1
- package/dist/__tests__/upstash.spec.mjs +0 -201
- package/dist/magic-string.es-CBih0MJw.mjs +0 -1014
- package/dist/magic-string.es-KiPEzMtt.cjs +0 -1015
- package/dist/memory-Csy6J-Ak.cjs +0 -39
- package/dist/memory-QDTnSEX5.mjs +0 -33
- package/dist/upstash-CXy_duOa.mjs +0 -31
- package/dist/upstash-u8Hs4sZG.cjs +0 -37
- package/dist/vi.bdSIJ99Y-B-qkABPq.cjs +0 -14955
- package/dist/vi.bdSIJ99Y-CB5havZF.mjs +0 -14951
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { bench, describe } from 'vitest';
|
|
2
|
+
import { InMemoryCache } from '../memory';
|
|
3
|
+
|
|
4
|
+
describe('InMemoryCache', () => {
|
|
5
|
+
const cache = new InMemoryCache<string>();
|
|
6
|
+
|
|
7
|
+
bench('set with TTL', async () => {
|
|
8
|
+
await cache.set('key', 'value', 3600);
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
bench('get (cache hit)', async () => {
|
|
12
|
+
await cache.set('hit-key', 'value', 3600);
|
|
13
|
+
await cache.get('hit-key');
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
bench('get (cache miss)', async () => {
|
|
17
|
+
await cache.get('nonexistent-key');
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
bench('delete', async () => {
|
|
21
|
+
await cache.set('delete-key', 'value', 3600);
|
|
22
|
+
await cache.delete('delete-key');
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
bench('set + get cycle', async () => {
|
|
26
|
+
const key = `cycle-${Math.random()}`;
|
|
27
|
+
await cache.set(key, 'value', 3600);
|
|
28
|
+
await cache.get(key);
|
|
29
|
+
});
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
describe('InMemoryCache - Large Scale', () => {
|
|
33
|
+
bench('1000 sequential sets', async () => {
|
|
34
|
+
const cache = new InMemoryCache<string>();
|
|
35
|
+
for (let i = 0; i < 1000; i++) {
|
|
36
|
+
await cache.set(`key-${i}`, `value-${i}`, 3600);
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
bench('1000 sequential gets', async () => {
|
|
41
|
+
const cache = new InMemoryCache<string>();
|
|
42
|
+
// Pre-populate
|
|
43
|
+
for (let i = 0; i < 1000; i++) {
|
|
44
|
+
await cache.set(`key-${i}`, `value-${i}`, 3600);
|
|
45
|
+
}
|
|
46
|
+
// Benchmark gets
|
|
47
|
+
for (let i = 0; i < 1000; i++) {
|
|
48
|
+
await cache.get(`key-${i}`);
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
});
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { describe, expect, it } from 'vitest';
|
|
2
|
-
import type { Cache } from '../
|
|
2
|
+
import type { Cache } from '../';
|
|
3
3
|
import { InMemoryCache } from '../memory';
|
|
4
4
|
import { UpstashCache } from '../upstash';
|
|
5
5
|
|
|
6
6
|
describe('Cache Interface', () => {
|
|
7
7
|
describe('interface compliance', () => {
|
|
8
8
|
it('InMemoryCache should implement Cache interface', () => {
|
|
9
|
-
const cache: Cache
|
|
9
|
+
const cache: Cache = new InMemoryCache();
|
|
10
10
|
|
|
11
11
|
expect(typeof cache.get).toBe('function');
|
|
12
12
|
expect(typeof cache.set).toBe('function');
|
|
@@ -14,7 +14,10 @@ describe('Cache Interface', () => {
|
|
|
14
14
|
});
|
|
15
15
|
|
|
16
16
|
it('UpstashCache should implement Cache interface', () => {
|
|
17
|
-
const cache = new UpstashCache(
|
|
17
|
+
const cache: Cache = new UpstashCache(
|
|
18
|
+
'http://localhost:8079',
|
|
19
|
+
'example_token',
|
|
20
|
+
);
|
|
18
21
|
|
|
19
22
|
expect(typeof cache.get).toBe('function');
|
|
20
23
|
expect(typeof cache.set).toBe('function');
|
|
@@ -23,22 +26,16 @@ describe('Cache Interface', () => {
|
|
|
23
26
|
});
|
|
24
27
|
|
|
25
28
|
describe('method signatures', () => {
|
|
26
|
-
interface TestCache extends Cache<any> {
|
|
27
|
-
get(key: string): Promise<any>;
|
|
28
|
-
set(key: string, value: any): Promise<void>;
|
|
29
|
-
delete(key: string): Promise<void>;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
29
|
it('should have correct get method signature', () => {
|
|
33
|
-
const cache = new InMemoryCache()
|
|
30
|
+
const cache: Cache = new InMemoryCache();
|
|
34
31
|
|
|
35
32
|
// These should compile without errors
|
|
36
|
-
const getResult: Promise<
|
|
33
|
+
const getResult: Promise<unknown> = cache.get('test');
|
|
37
34
|
expect(getResult).toBeInstanceOf(Promise);
|
|
38
35
|
});
|
|
39
36
|
|
|
40
37
|
it('should have correct set method signature', () => {
|
|
41
|
-
const cache = new InMemoryCache()
|
|
38
|
+
const cache: Cache = new InMemoryCache();
|
|
42
39
|
|
|
43
40
|
// These should compile without errors
|
|
44
41
|
const setResult: Promise<void> = cache.set('test', 'value');
|
|
@@ -46,7 +43,7 @@ describe('Cache Interface', () => {
|
|
|
46
43
|
});
|
|
47
44
|
|
|
48
45
|
it('should have correct delete method signature', () => {
|
|
49
|
-
const cache = new InMemoryCache()
|
|
46
|
+
const cache: Cache = new InMemoryCache();
|
|
50
47
|
|
|
51
48
|
// These should compile without errors
|
|
52
49
|
const deleteResult: Promise<void> = cache.delete('test');
|
|
@@ -54,36 +51,36 @@ describe('Cache Interface', () => {
|
|
|
54
51
|
});
|
|
55
52
|
});
|
|
56
53
|
|
|
57
|
-
describe('generic type support', () => {
|
|
58
|
-
it('should support string types', async () => {
|
|
59
|
-
const cache: Cache
|
|
54
|
+
describe('function-level generic type support', () => {
|
|
55
|
+
it('should support string types with function-level generics', async () => {
|
|
56
|
+
const cache: Cache = new InMemoryCache();
|
|
60
57
|
|
|
61
|
-
await cache.set('key', 'value');
|
|
62
|
-
const result = await cache.get('key');
|
|
58
|
+
await cache.set<string>('key', 'value');
|
|
59
|
+
const result = await cache.get<string>('key');
|
|
63
60
|
|
|
64
61
|
expect(typeof result === 'string' || result === undefined).toBe(true);
|
|
65
62
|
});
|
|
66
63
|
|
|
67
|
-
it('should support number types', async () => {
|
|
68
|
-
const cache: Cache
|
|
64
|
+
it('should support number types with function-level generics', async () => {
|
|
65
|
+
const cache: Cache = new InMemoryCache();
|
|
69
66
|
|
|
70
|
-
await cache.set('key', 42);
|
|
71
|
-
const result = await cache.get('key');
|
|
67
|
+
await cache.set<number>('key', 42);
|
|
68
|
+
const result = await cache.get<number>('key');
|
|
72
69
|
|
|
73
70
|
expect(typeof result === 'number' || result === undefined).toBe(true);
|
|
74
71
|
});
|
|
75
72
|
|
|
76
|
-
it('should support object types', async () => {
|
|
73
|
+
it('should support object types with function-level generics', async () => {
|
|
77
74
|
interface User {
|
|
78
75
|
id: number;
|
|
79
76
|
name: string;
|
|
80
77
|
}
|
|
81
78
|
|
|
82
|
-
const cache: Cache
|
|
79
|
+
const cache: Cache = new InMemoryCache();
|
|
83
80
|
const user: User = { id: 1, name: 'John' };
|
|
84
81
|
|
|
85
|
-
await cache.set('user', user);
|
|
86
|
-
const result = await cache.get('user');
|
|
82
|
+
await cache.set<User>('user', user);
|
|
83
|
+
const result = await cache.get<User>('user');
|
|
87
84
|
|
|
88
85
|
expect(
|
|
89
86
|
result === undefined ||
|
|
@@ -91,17 +88,16 @@ describe('Cache Interface', () => {
|
|
|
91
88
|
).toBe(true);
|
|
92
89
|
});
|
|
93
90
|
|
|
94
|
-
it('should support
|
|
95
|
-
|
|
96
|
-
const cache: Cache<CacheValue> = new InMemoryCache<CacheValue>();
|
|
91
|
+
it('should support mixed types in same cache instance', async () => {
|
|
92
|
+
const cache: Cache = new InMemoryCache();
|
|
97
93
|
|
|
98
|
-
await cache.set('string', 'text');
|
|
99
|
-
await cache.set('number', 42);
|
|
100
|
-
await cache.set('boolean', true);
|
|
94
|
+
await cache.set<string>('string', 'text');
|
|
95
|
+
await cache.set<number>('number', 42);
|
|
96
|
+
await cache.set<boolean>('boolean', true);
|
|
101
97
|
|
|
102
|
-
const stringResult = await cache.get('string');
|
|
103
|
-
const numberResult = await cache.get('number');
|
|
104
|
-
const booleanResult = await cache.get('boolean');
|
|
98
|
+
const stringResult = await cache.get<string>('string');
|
|
99
|
+
const numberResult = await cache.get<number>('number');
|
|
100
|
+
const booleanResult = await cache.get<boolean>('boolean');
|
|
105
101
|
|
|
106
102
|
expect(stringResult).toBe('text');
|
|
107
103
|
expect(numberResult).toBe(42);
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { beforeEach, describe, expect, it } from 'vitest';
|
|
2
|
-
import type { Cache } from '../
|
|
2
|
+
import type { Cache } from '../';
|
|
3
3
|
import { InMemoryCache } from '../memory';
|
|
4
4
|
|
|
5
5
|
describe('Cache Integration Tests', () => {
|
|
6
|
-
let memoryCache: Cache
|
|
6
|
+
let memoryCache: Cache;
|
|
7
7
|
|
|
8
8
|
beforeEach(() => {
|
|
9
9
|
memoryCache = new InMemoryCache();
|
|
@@ -16,7 +16,7 @@ describe('Cache Integration Tests', () => {
|
|
|
16
16
|
|
|
17
17
|
testCases.forEach(({ name, cache }) => {
|
|
18
18
|
describe(name, () => {
|
|
19
|
-
let cacheInstance: Cache
|
|
19
|
+
let cacheInstance: Cache;
|
|
20
20
|
|
|
21
21
|
beforeEach(() => {
|
|
22
22
|
cacheInstance = cache();
|
|
@@ -106,8 +106,8 @@ describe('Cache Integration Tests', () => {
|
|
|
106
106
|
|
|
107
107
|
describe('cache migration scenarios', () => {
|
|
108
108
|
it('should support migrating data between cache implementations', async () => {
|
|
109
|
-
const sourceCache = new InMemoryCache
|
|
110
|
-
const targetCache = new InMemoryCache
|
|
109
|
+
const sourceCache = new InMemoryCache();
|
|
110
|
+
const targetCache = new InMemoryCache();
|
|
111
111
|
|
|
112
112
|
// Populate source cache
|
|
113
113
|
const testData = {
|
|
@@ -139,39 +139,44 @@ describe('Cache Integration Tests', () => {
|
|
|
139
139
|
|
|
140
140
|
describe('cache abstraction patterns', () => {
|
|
141
141
|
it('should support cache factory pattern', async () => {
|
|
142
|
-
const createCache =
|
|
142
|
+
const createCache = (type: 'memory'): Cache => {
|
|
143
143
|
switch (type) {
|
|
144
144
|
case 'memory':
|
|
145
|
-
return new InMemoryCache
|
|
145
|
+
return new InMemoryCache();
|
|
146
146
|
default:
|
|
147
147
|
throw new Error(`Unknown cache type: ${type}`);
|
|
148
148
|
}
|
|
149
149
|
};
|
|
150
150
|
|
|
151
|
-
const userCache = createCache
|
|
152
|
-
const sessionCache = createCache
|
|
151
|
+
const userCache = createCache('memory');
|
|
152
|
+
const sessionCache = createCache('memory');
|
|
153
153
|
|
|
154
|
-
await userCache.set
|
|
155
|
-
|
|
154
|
+
await userCache.set<{ id: number; name: string }>('user:1', {
|
|
155
|
+
id: 1,
|
|
156
|
+
name: 'John',
|
|
157
|
+
});
|
|
158
|
+
await sessionCache.set<string>('session:abc', 'active');
|
|
156
159
|
|
|
157
|
-
expect(
|
|
158
|
-
|
|
160
|
+
expect(
|
|
161
|
+
await userCache.get<{ id: number; name: string }>('user:1'),
|
|
162
|
+
).toEqual({ id: 1, name: 'John' });
|
|
163
|
+
expect(await sessionCache.get<string>('session:abc')).toBe('active');
|
|
159
164
|
});
|
|
160
165
|
|
|
161
166
|
it('should support cache wrapper pattern', async () => {
|
|
162
|
-
class LoggingCache
|
|
167
|
+
class LoggingCache implements Cache {
|
|
163
168
|
private logs: string[] = [];
|
|
164
169
|
|
|
165
|
-
constructor(private underlying: Cache
|
|
170
|
+
constructor(private underlying: Cache) {}
|
|
166
171
|
|
|
167
|
-
async get(key: string): Promise<T | undefined> {
|
|
172
|
+
async get<T>(key: string): Promise<T | undefined> {
|
|
168
173
|
this.logs.push(`GET ${key}`);
|
|
169
|
-
return this.underlying.get(key);
|
|
174
|
+
return this.underlying.get<T>(key);
|
|
170
175
|
}
|
|
171
176
|
|
|
172
|
-
async set(key: string, value: T): Promise<void> {
|
|
177
|
+
async set<T>(key: string, value: T, ttl?: number): Promise<void> {
|
|
173
178
|
this.logs.push(`SET ${key}`);
|
|
174
|
-
return this.underlying.set(key, value);
|
|
179
|
+
return this.underlying.set<T>(key, value, ttl);
|
|
175
180
|
}
|
|
176
181
|
|
|
177
182
|
async delete(key: string): Promise<void> {
|
|
@@ -179,12 +184,16 @@ describe('Cache Integration Tests', () => {
|
|
|
179
184
|
return this.underlying.delete(key);
|
|
180
185
|
}
|
|
181
186
|
|
|
187
|
+
async ttl(key: string): Promise<number> {
|
|
188
|
+
return this.underlying.ttl(key);
|
|
189
|
+
}
|
|
190
|
+
|
|
182
191
|
getLogs(): string[] {
|
|
183
192
|
return [...this.logs];
|
|
184
193
|
}
|
|
185
194
|
}
|
|
186
195
|
|
|
187
|
-
const baseCache = new InMemoryCache
|
|
196
|
+
const baseCache = new InMemoryCache();
|
|
188
197
|
const loggingCache = new LoggingCache(baseCache);
|
|
189
198
|
|
|
190
199
|
await loggingCache.set('test', 'value');
|
|
@@ -198,7 +207,7 @@ describe('Cache Integration Tests', () => {
|
|
|
198
207
|
|
|
199
208
|
describe('performance and stress tests', () => {
|
|
200
209
|
it('should handle large number of operations', async () => {
|
|
201
|
-
const cache = new InMemoryCache
|
|
210
|
+
const cache = new InMemoryCache();
|
|
202
211
|
const operationCount = 1000;
|
|
203
212
|
|
|
204
213
|
// Bulk insert
|
|
@@ -230,7 +239,7 @@ describe('Cache Integration Tests', () => {
|
|
|
230
239
|
});
|
|
231
240
|
|
|
232
241
|
it('should handle large objects efficiently', async () => {
|
|
233
|
-
const cache = new InMemoryCache
|
|
242
|
+
const cache = new InMemoryCache();
|
|
234
243
|
|
|
235
244
|
const largeObject = {
|
|
236
245
|
id: 1,
|
|
@@ -256,7 +265,7 @@ describe('Cache Integration Tests', () => {
|
|
|
256
265
|
|
|
257
266
|
describe('error scenarios', () => {
|
|
258
267
|
it('should handle operations after errors gracefully', async () => {
|
|
259
|
-
const cache = new InMemoryCache
|
|
268
|
+
const cache = new InMemoryCache();
|
|
260
269
|
|
|
261
270
|
// Successful operations
|
|
262
271
|
await cache.set('valid-key', 'valid-value');
|
|
@@ -2,7 +2,7 @@ import { afterEach, beforeEach, describe, expect, it } from 'vitest';
|
|
|
2
2
|
import { UpstashCache } from '../upstash';
|
|
3
3
|
|
|
4
4
|
describe('UpstashCache', () => {
|
|
5
|
-
let cache: UpstashCache
|
|
5
|
+
let cache: UpstashCache;
|
|
6
6
|
const testKeyPrefix = `test:${Date.now()}:`;
|
|
7
7
|
let testKeys: string[] = [];
|
|
8
8
|
|
package/src/expo.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { addSeconds } from 'date-fns';
|
|
|
2
2
|
import * as SecureStore from 'expo-secure-store';
|
|
3
3
|
import { type Cache, getExpirationInSeconds } from './index';
|
|
4
4
|
|
|
5
|
-
export class ExpoSecureCache
|
|
5
|
+
export class ExpoSecureCache implements Cache {
|
|
6
6
|
static getExpiryKey(key: string): string {
|
|
7
7
|
return `${key}:expiresAt`;
|
|
8
8
|
}
|
|
@@ -20,8 +20,7 @@ export class ExpoSecureCache<T> implements Cache<T> {
|
|
|
20
20
|
return Math.max(secondsLeft, 0);
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
-
|
|
24
|
-
async get(key: string): Promise<T | undefined> {
|
|
23
|
+
async get<T>(key: string): Promise<T | undefined> {
|
|
25
24
|
const result = await SecureStore.getItemAsync(key);
|
|
26
25
|
if (!result) {
|
|
27
26
|
return undefined;
|
|
@@ -35,7 +34,7 @@ export class ExpoSecureCache<T> implements Cache<T> {
|
|
|
35
34
|
return JSON.parse(result) as T;
|
|
36
35
|
}
|
|
37
36
|
|
|
38
|
-
async set(key: string, value: T, ttl: number = 600): Promise<void> {
|
|
37
|
+
async set<T>(key: string, value: T, ttl: number = 600): Promise<void> {
|
|
39
38
|
const expiresAt = addSeconds(new Date(), ttl).toISOString();
|
|
40
39
|
await SecureStore.setItemAsync(key, JSON.stringify(value));
|
|
41
40
|
await SecureStore.setItemAsync(
|
package/src/index.ts
CHANGED
|
@@ -15,13 +15,14 @@ export const getExpirationInSeconds = (
|
|
|
15
15
|
return Math.max(secondsLeft, 0);
|
|
16
16
|
};
|
|
17
17
|
|
|
18
|
-
export interface Cache
|
|
18
|
+
export interface Cache {
|
|
19
19
|
/**
|
|
20
20
|
* Retrieves a value from the cache.
|
|
21
21
|
*
|
|
22
22
|
* @param key The key to retrieve the value for.
|
|
23
|
+
* @returns The cached value, or undefined if not found.
|
|
23
24
|
*/
|
|
24
|
-
get(key: string): Promise<T | undefined>;
|
|
25
|
+
get<T>(key: string): Promise<T | undefined>;
|
|
25
26
|
/**
|
|
26
27
|
* Sets a value in the cache.
|
|
27
28
|
*
|
|
@@ -29,7 +30,7 @@ export interface Cache<T> {
|
|
|
29
30
|
* @param value The value to cache.
|
|
30
31
|
* @param ttl Optional time-to-live in seconds. If not provided, the value will not expire.
|
|
31
32
|
*/
|
|
32
|
-
set(key: string, value: T, ttl?: number): Promise<void>;
|
|
33
|
+
set<T>(key: string, value: T, ttl?: number): Promise<void>;
|
|
33
34
|
/**
|
|
34
35
|
* Deletes a value from the cache.
|
|
35
36
|
*
|
|
@@ -41,7 +42,7 @@ export interface Cache<T> {
|
|
|
41
42
|
* Retrieves the time-to-live (TTL) for a cached value.
|
|
42
43
|
*
|
|
43
44
|
* @param key The key to retrieve the TTL for.
|
|
44
|
-
* @returns The TTL in seconds, or
|
|
45
|
+
* @returns The TTL in seconds, or 0 if the key does not exist.
|
|
45
46
|
*/
|
|
46
47
|
ttl(key: string): Promise<number>;
|
|
47
48
|
}
|
package/src/memory.ts
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
import { addSeconds } from 'date-fns';
|
|
2
2
|
import { type Cache, getExpirationInSeconds } from './';
|
|
3
3
|
|
|
4
|
-
export class InMemoryCache
|
|
5
|
-
private store: Map<string,
|
|
4
|
+
export class InMemoryCache implements Cache {
|
|
5
|
+
private store: Map<string, unknown> = new Map();
|
|
6
6
|
private expirations: Map<string, Date> = new Map();
|
|
7
7
|
|
|
8
|
-
async get(key: string): Promise<T | undefined> {
|
|
8
|
+
async get<T>(key: string): Promise<T | undefined> {
|
|
9
9
|
const expiration = await this.ttl(key);
|
|
10
10
|
if (!expiration) {
|
|
11
11
|
await this.delete(key);
|
|
12
12
|
return undefined;
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
-
return this.store.get(key);
|
|
15
|
+
return this.store.get(key) as T | undefined;
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
async ttl(key: string): Promise<number> {
|
|
@@ -24,7 +24,7 @@ export class InMemoryCache<T> implements Cache<T> {
|
|
|
24
24
|
return getExpirationInSeconds(expiration);
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
-
async set(key: string, value: T, ttl: number = 600): Promise<void> {
|
|
27
|
+
async set<T>(key: string, value: T, ttl: number = 600): Promise<void> {
|
|
28
28
|
this.store.set(key, value);
|
|
29
29
|
const now = new Date();
|
|
30
30
|
const expiresAt = addSeconds(now, ttl);
|
|
@@ -33,5 +33,6 @@ export class InMemoryCache<T> implements Cache<T> {
|
|
|
33
33
|
|
|
34
34
|
async delete(key: string): Promise<void> {
|
|
35
35
|
this.store.delete(key);
|
|
36
|
+
this.expirations.delete(key);
|
|
36
37
|
}
|
|
37
38
|
}
|
package/src/upstash.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Redis } from '@upstash/redis';
|
|
2
2
|
import type { Cache } from './';
|
|
3
3
|
|
|
4
|
-
export class UpstashCache
|
|
4
|
+
export class UpstashCache implements Cache {
|
|
5
5
|
private client: Redis;
|
|
6
6
|
|
|
7
7
|
constructor(url: string, token: string) {
|
|
@@ -21,17 +21,17 @@ export class UpstashCache<T> implements Cache<T> {
|
|
|
21
21
|
return ttl; // Returns TTL in seconds
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
async get(key: string): Promise<T | undefined> {
|
|
24
|
+
async get<T>(key: string): Promise<T | undefined> {
|
|
25
25
|
const v = await this.client.get(key);
|
|
26
26
|
|
|
27
27
|
if (v === null) {
|
|
28
28
|
return undefined;
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
-
return v as T;
|
|
31
|
+
return v as T;
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
-
async set(key: string, value: T, ttl = 3600): Promise<void> {
|
|
34
|
+
async set<T>(key: string, value: T, ttl = 3600): Promise<void> {
|
|
35
35
|
await this.client.set(key, value, { ex: ttl });
|
|
36
36
|
}
|
|
37
37
|
|
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
require('../src-C7d6HaTp.cjs');
|
|
2
|
-
const require_memory = require('../memory-Csy6J-Ak.cjs');
|
|
3
|
-
const require_upstash = require('../upstash-u8Hs4sZG.cjs');
|
|
4
|
-
const require_vi_bdSIJ99Y = require('../vi.bdSIJ99Y-B-qkABPq.cjs');
|
|
5
|
-
|
|
6
|
-
//#region src/__tests__/cache.spec.ts
|
|
7
|
-
require_vi_bdSIJ99Y.describe("Cache Interface", () => {
|
|
8
|
-
require_vi_bdSIJ99Y.describe("interface compliance", () => {
|
|
9
|
-
require_vi_bdSIJ99Y.it("InMemoryCache should implement Cache interface", () => {
|
|
10
|
-
const cache = new require_memory.InMemoryCache();
|
|
11
|
-
require_vi_bdSIJ99Y.globalExpect(typeof cache.get).toBe("function");
|
|
12
|
-
require_vi_bdSIJ99Y.globalExpect(typeof cache.set).toBe("function");
|
|
13
|
-
require_vi_bdSIJ99Y.globalExpect(typeof cache.delete).toBe("function");
|
|
14
|
-
});
|
|
15
|
-
require_vi_bdSIJ99Y.it("UpstashCache should implement Cache interface", () => {
|
|
16
|
-
const cache = new require_upstash.UpstashCache("http://localhost:8079", "example_token");
|
|
17
|
-
require_vi_bdSIJ99Y.globalExpect(typeof cache.get).toBe("function");
|
|
18
|
-
require_vi_bdSIJ99Y.globalExpect(typeof cache.set).toBe("function");
|
|
19
|
-
require_vi_bdSIJ99Y.globalExpect(typeof cache.delete).toBe("function");
|
|
20
|
-
});
|
|
21
|
-
});
|
|
22
|
-
require_vi_bdSIJ99Y.describe("method signatures", () => {
|
|
23
|
-
require_vi_bdSIJ99Y.it("should have correct get method signature", () => {
|
|
24
|
-
const cache = new require_memory.InMemoryCache();
|
|
25
|
-
const getResult = cache.get("test");
|
|
26
|
-
require_vi_bdSIJ99Y.globalExpect(getResult).toBeInstanceOf(Promise);
|
|
27
|
-
});
|
|
28
|
-
require_vi_bdSIJ99Y.it("should have correct set method signature", () => {
|
|
29
|
-
const cache = new require_memory.InMemoryCache();
|
|
30
|
-
const setResult = cache.set("test", "value");
|
|
31
|
-
require_vi_bdSIJ99Y.globalExpect(setResult).toBeInstanceOf(Promise);
|
|
32
|
-
});
|
|
33
|
-
require_vi_bdSIJ99Y.it("should have correct delete method signature", () => {
|
|
34
|
-
const cache = new require_memory.InMemoryCache();
|
|
35
|
-
const deleteResult = cache.delete("test");
|
|
36
|
-
require_vi_bdSIJ99Y.globalExpect(deleteResult).toBeInstanceOf(Promise);
|
|
37
|
-
});
|
|
38
|
-
});
|
|
39
|
-
require_vi_bdSIJ99Y.describe("generic type support", () => {
|
|
40
|
-
require_vi_bdSIJ99Y.it("should support string types", async () => {
|
|
41
|
-
const cache = new require_memory.InMemoryCache();
|
|
42
|
-
await cache.set("key", "value");
|
|
43
|
-
const result = await cache.get("key");
|
|
44
|
-
require_vi_bdSIJ99Y.globalExpect(typeof result === "string" || result === void 0).toBe(true);
|
|
45
|
-
});
|
|
46
|
-
require_vi_bdSIJ99Y.it("should support number types", async () => {
|
|
47
|
-
const cache = new require_memory.InMemoryCache();
|
|
48
|
-
await cache.set("key", 42);
|
|
49
|
-
const result = await cache.get("key");
|
|
50
|
-
require_vi_bdSIJ99Y.globalExpect(typeof result === "number" || result === void 0).toBe(true);
|
|
51
|
-
});
|
|
52
|
-
require_vi_bdSIJ99Y.it("should support object types", async () => {
|
|
53
|
-
const cache = new require_memory.InMemoryCache();
|
|
54
|
-
const user = {
|
|
55
|
-
id: 1,
|
|
56
|
-
name: "John"
|
|
57
|
-
};
|
|
58
|
-
await cache.set("user", user);
|
|
59
|
-
const result = await cache.get("user");
|
|
60
|
-
require_vi_bdSIJ99Y.globalExpect(result === void 0 || typeof result === "object" && "id" in result && "name" in result).toBe(true);
|
|
61
|
-
});
|
|
62
|
-
require_vi_bdSIJ99Y.it("should support union types", async () => {
|
|
63
|
-
const cache = new require_memory.InMemoryCache();
|
|
64
|
-
await cache.set("string", "text");
|
|
65
|
-
await cache.set("number", 42);
|
|
66
|
-
await cache.set("boolean", true);
|
|
67
|
-
const stringResult = await cache.get("string");
|
|
68
|
-
const numberResult = await cache.get("number");
|
|
69
|
-
const booleanResult = await cache.get("boolean");
|
|
70
|
-
require_vi_bdSIJ99Y.globalExpect(stringResult).toBe("text");
|
|
71
|
-
require_vi_bdSIJ99Y.globalExpect(numberResult).toBe(42);
|
|
72
|
-
require_vi_bdSIJ99Y.globalExpect(booleanResult).toBe(true);
|
|
73
|
-
});
|
|
74
|
-
});
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
//#endregion
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { };
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { };
|
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
import { describe, globalExpect, it } from "../vi.bdSIJ99Y-CB5havZF.mjs";
|
|
2
|
-
import "../src-DVpoP03o.mjs";
|
|
3
|
-
import { InMemoryCache } from "../memory-QDTnSEX5.mjs";
|
|
4
|
-
import { UpstashCache } from "../upstash-CXy_duOa.mjs";
|
|
5
|
-
|
|
6
|
-
//#region src/__tests__/cache.spec.ts
|
|
7
|
-
describe("Cache Interface", () => {
|
|
8
|
-
describe("interface compliance", () => {
|
|
9
|
-
it("InMemoryCache should implement Cache interface", () => {
|
|
10
|
-
const cache = new InMemoryCache();
|
|
11
|
-
globalExpect(typeof cache.get).toBe("function");
|
|
12
|
-
globalExpect(typeof cache.set).toBe("function");
|
|
13
|
-
globalExpect(typeof cache.delete).toBe("function");
|
|
14
|
-
});
|
|
15
|
-
it("UpstashCache should implement Cache interface", () => {
|
|
16
|
-
const cache = new UpstashCache("http://localhost:8079", "example_token");
|
|
17
|
-
globalExpect(typeof cache.get).toBe("function");
|
|
18
|
-
globalExpect(typeof cache.set).toBe("function");
|
|
19
|
-
globalExpect(typeof cache.delete).toBe("function");
|
|
20
|
-
});
|
|
21
|
-
});
|
|
22
|
-
describe("method signatures", () => {
|
|
23
|
-
it("should have correct get method signature", () => {
|
|
24
|
-
const cache = new InMemoryCache();
|
|
25
|
-
const getResult = cache.get("test");
|
|
26
|
-
globalExpect(getResult).toBeInstanceOf(Promise);
|
|
27
|
-
});
|
|
28
|
-
it("should have correct set method signature", () => {
|
|
29
|
-
const cache = new InMemoryCache();
|
|
30
|
-
const setResult = cache.set("test", "value");
|
|
31
|
-
globalExpect(setResult).toBeInstanceOf(Promise);
|
|
32
|
-
});
|
|
33
|
-
it("should have correct delete method signature", () => {
|
|
34
|
-
const cache = new InMemoryCache();
|
|
35
|
-
const deleteResult = cache.delete("test");
|
|
36
|
-
globalExpect(deleteResult).toBeInstanceOf(Promise);
|
|
37
|
-
});
|
|
38
|
-
});
|
|
39
|
-
describe("generic type support", () => {
|
|
40
|
-
it("should support string types", async () => {
|
|
41
|
-
const cache = new InMemoryCache();
|
|
42
|
-
await cache.set("key", "value");
|
|
43
|
-
const result = await cache.get("key");
|
|
44
|
-
globalExpect(typeof result === "string" || result === void 0).toBe(true);
|
|
45
|
-
});
|
|
46
|
-
it("should support number types", async () => {
|
|
47
|
-
const cache = new InMemoryCache();
|
|
48
|
-
await cache.set("key", 42);
|
|
49
|
-
const result = await cache.get("key");
|
|
50
|
-
globalExpect(typeof result === "number" || result === void 0).toBe(true);
|
|
51
|
-
});
|
|
52
|
-
it("should support object types", async () => {
|
|
53
|
-
const cache = new InMemoryCache();
|
|
54
|
-
const user = {
|
|
55
|
-
id: 1,
|
|
56
|
-
name: "John"
|
|
57
|
-
};
|
|
58
|
-
await cache.set("user", user);
|
|
59
|
-
const result = await cache.get("user");
|
|
60
|
-
globalExpect(result === void 0 || typeof result === "object" && "id" in result && "name" in result).toBe(true);
|
|
61
|
-
});
|
|
62
|
-
it("should support union types", async () => {
|
|
63
|
-
const cache = new InMemoryCache();
|
|
64
|
-
await cache.set("string", "text");
|
|
65
|
-
await cache.set("number", 42);
|
|
66
|
-
await cache.set("boolean", true);
|
|
67
|
-
const stringResult = await cache.get("string");
|
|
68
|
-
const numberResult = await cache.get("number");
|
|
69
|
-
const booleanResult = await cache.get("boolean");
|
|
70
|
-
globalExpect(stringResult).toBe("text");
|
|
71
|
-
globalExpect(numberResult).toBe(42);
|
|
72
|
-
globalExpect(booleanResult).toBe(true);
|
|
73
|
-
});
|
|
74
|
-
});
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
//#endregion
|