@notkannan/cache-with-persistence 1.0.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/LICENSE ADDED
@@ -0,0 +1,13 @@
1
+ Copyright (c) 2026, Kannan Karthikeyan
2
+
3
+ Permission to use, copy, modify, and/or distribute this software for any
4
+ purpose with or without fee is hereby granted, provided that the above
5
+ copyright notice and this permission notice appear in all copies.
6
+
7
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
8
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
10
+ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
12
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
13
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,42 @@
1
+ # @notkannan/cache-with-persistence
2
+
3
+ Redis-inspired in-memory key-value store with append-only file persistence.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ npm install @notkannan/cache-with-persistence
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ ```ts
14
+ import { Store } from '@notkannan/cache-with-persistence';
15
+
16
+ const store = new Store('./data');
17
+
18
+ store.set('user:1', 'alice');
19
+ store.set('session', 'abc', 3600); // expires in 1 hour
20
+
21
+ store.get('user:1'); // 'alice'
22
+ store.del('user:1'); // true
23
+ store.exists('user:1'); // false
24
+ store.ttl('session'); // remaining ms, -1 if no expiry, -2 if missing
25
+ ```
26
+
27
+ Operations are written to a WAL (`store.aof`) and replayed on startup.
28
+
29
+ ## API
30
+
31
+ | Method | Description |
32
+ |--------|-------------|
33
+ | `new Store(dataDir?)` | Create store; defaults to `./data` |
34
+ | `set(key, value, ttlSeconds?)` | Set a key, optional TTL |
35
+ | `get(key)` | Get value, or `null` if missing/expired |
36
+ | `del(key)` | Delete key; returns `true` if it existed |
37
+ | `exists(key)` | Check if key exists |
38
+ | `ttl(key)` | Remaining ms, `-1` (no expiry), or `-2` (missing) |
39
+
40
+ ## License
41
+
42
+ ISC
@@ -0,0 +1,14 @@
1
+ export declare class HashMap<V> {
2
+ private buckets;
3
+ private size;
4
+ private capacity;
5
+ constructor(capacity?: number);
6
+ private hash;
7
+ set(key: string, value: V): void;
8
+ get(key: string): V | undefined;
9
+ delete(key: string): boolean;
10
+ has(key: string): boolean;
11
+ getSize(): number;
12
+ debug(): void;
13
+ }
14
+ //# sourceMappingURL=HashMap.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"HashMap.d.ts","sourceRoot":"","sources":["../src/HashMap.ts"],"names":[],"mappings":"AAOA,qBAAa,OAAO,CAAC,CAAC;IAClB,OAAO,CAAC,OAAO,CAAyB;IACxC,OAAO,CAAC,IAAI,CAAS;IACrB,OAAO,CAAC,QAAQ,CAAS;gBAEb,QAAQ,SAAK;IAOzB,OAAO,CAAC,IAAI;IAKZ,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,GAAG,IAAI;IAyBhC,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,CAAC,GAAG,SAAS;IAa/B,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAuB5B,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAIzB,OAAO,IAAI,MAAM;IAKjB,KAAK,IAAI,IAAI;CAUhB"}
@@ -0,0 +1,90 @@
1
+ export class HashMap {
2
+ buckets;
3
+ size; // how many key/value pairs are stored
4
+ capacity; // number of buckets in the HashMap
5
+ constructor(capacity = 16) {
6
+ this.capacity = capacity;
7
+ this.size = 0;
8
+ this.buckets = new Array(capacity).fill(null);
9
+ }
10
+ // Hash function
11
+ hash(key) {
12
+ return 1;
13
+ }
14
+ // Set function
15
+ set(key, value) {
16
+ const index = this.hash(key); // get the index by hashing to the bucket array
17
+ let entry = this.buckets[index] ?? null;
18
+ while (entry !== null) {
19
+ if (entry.key === key) {
20
+ entry.value = value;
21
+ return;
22
+ }
23
+ entry = entry.next;
24
+ }
25
+ // Key not found — prepend a new entry at the head of the chain
26
+ // (prepending is O(1); appending would require walking to the end)
27
+ const newEntry = {
28
+ key,
29
+ value,
30
+ next: this.buckets[index] ?? null, // new entry points to the old head
31
+ };
32
+ this.buckets[index] = newEntry; // new entry becomes the new head
33
+ this.size++;
34
+ }
35
+ // get function
36
+ get(key) {
37
+ const index = this.hash(key);
38
+ let entry = this.buckets[index] ?? null;
39
+ // Walk the chain until we find the key or run out
40
+ while (entry !== null) {
41
+ if (entry.key === key)
42
+ return entry.value;
43
+ entry = entry.next;
44
+ }
45
+ return undefined; // key doesn't exist
46
+ }
47
+ delete(key) {
48
+ const index = this.hash(key);
49
+ let entry = this.buckets[index] ?? null;
50
+ let prev = null;
51
+ while (entry !== null) {
52
+ if (entry.key === key) {
53
+ // Stitch the chain back together, skipping this entry
54
+ if (prev === null) {
55
+ this.buckets[index] = entry.next; // it was the head
56
+ }
57
+ else {
58
+ prev.next = entry.next; // bypass this node
59
+ }
60
+ this.size--;
61
+ return true;
62
+ }
63
+ prev = entry;
64
+ entry = entry.next;
65
+ }
66
+ return false; // not found
67
+ }
68
+ // HELPER FUNCTION
69
+ has(key) {
70
+ return this.get(key) !== undefined;
71
+ }
72
+ getSize() {
73
+ return this.size;
74
+ }
75
+ // For debugging — lets you see the raw bucket structure
76
+ debug() {
77
+ this.buckets.forEach((entry, i) => {
78
+ if (entry === null)
79
+ return;
80
+ const chain = [];
81
+ let e = entry;
82
+ while (e) {
83
+ chain.push(`${e.key}:${e.value}`);
84
+ e = e.next;
85
+ }
86
+ console.log(`bucket[${i}] → ${chain.join(' → ')}`);
87
+ });
88
+ }
89
+ }
90
+ //# sourceMappingURL=HashMap.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"HashMap.js","sourceRoot":"","sources":["../src/HashMap.ts"],"names":[],"mappings":"AAOA,MAAM,OAAO,OAAO;IACR,OAAO,CAAyB;IAChC,IAAI,CAAS,CAAC,sCAAsC;IACpD,QAAQ,CAAS,CAAC,mCAAmC;IAE7D,YAAY,QAAQ,GAAG,EAAE;QACrB,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;QACzB,IAAI,CAAC,IAAI,GAAG,CAAC,CAAC;QACd,IAAI,CAAC,OAAO,GAAG,IAAI,KAAK,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAClD,CAAC;IAED,gBAAgB;IACR,IAAI,CAAC,GAAW;QACpB,OAAO,CAAC,CAAA;IACZ,CAAC;IAED,eAAe;IACf,GAAG,CAAC,GAAW,EAAE,KAAQ;QAErB,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,+CAA+C;QAC7E,IAAI,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,IAAI,CAAC;QAExC,OAAO,KAAK,KAAK,IAAI,EAAE,CAAC;YACpB,IAAI,KAAK,CAAC,GAAG,KAAK,GAAG,EAAE,CAAC;gBACpB,KAAK,CAAC,KAAK,GAAG,KAAK,CAAC;gBACpB,OAAO;YACX,CAAC;YACD,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC;QACvB,CAAC;QAED,+DAA+D;QAC/D,mEAAmE;QACnE,MAAM,QAAQ,GAAa;YACvB,GAAG;YACH,KAAK;YACL,IAAI,EAAE,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,IAAI,EAAU,mCAAmC;SACjF,CAAC;QACF,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,QAAQ,CAAC,CAAM,iCAAiC;QACtE,IAAI,CAAC,IAAI,EAAE,CAAC;IAChB,CAAC;IAED,eAAe;IACf,GAAG,CAAC,GAAW;QACX,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAC7B,IAAI,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,IAAI,CAAC;QAExC,kDAAkD;QAClD,OAAO,KAAK,KAAK,IAAI,EAAE,CAAC;YACtB,IAAI,KAAK,CAAC,GAAG,KAAK,GAAG;gBAAE,OAAO,KAAK,CAAC,KAAK,CAAC;YAC1C,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC;QACrB,CAAC;QACD,OAAO,SAAS,CAAC,CAAC,oBAAoB;IAC1C,CAAC;IAGD,MAAM,CAAC,GAAW;QACd,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAC7B,IAAI,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,IAAI,CAAC;QACxC,IAAI,IAAI,GAAoB,IAAI,CAAC;QAEjC,OAAO,KAAK,KAAK,IAAI,EAAE,CAAC;YACpB,IAAI,KAAK,CAAC,GAAG,KAAK,GAAG,EAAE,CAAC;gBACxB,sDAAsD;gBACtD,IAAI,IAAI,KAAK,IAAI,EAAE,CAAC;oBAChB,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,kBAAkB;gBACxD,CAAC;qBAAM,CAAC;oBACJ,IAAI,CAAC,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,CAAW,mBAAmB;gBACzD,CAAC;gBACD,IAAI,CAAC,IAAI,EAAE,CAAC;gBACZ,OAAO,IAAI,CAAC;YACZ,CAAC;YACD,IAAI,GAAG,KAAK,CAAC;YACb,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC;QACvB,CAAC;QACD,OAAO,KAAK,CAAC,CAAC,YAAY;IAC9B,CAAC;IAED,kBAAkB;IAClB,GAAG,CAAC,GAAW;QACX,OAAO,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,SAAS,CAAC;IACvC,CAAC;IAED,OAAO;QACH,OAAO,IAAI,CAAC,IAAI,CAAC;IACrB,CAAC;IAED,wDAAwD;IACxD,KAAK;QACD,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,CAAC,EAAE,EAAE;YAClC,IAAI,KAAK,KAAK,IAAI;gBAAE,OAAO;YAC3B,MAAM,KAAK,GAAa,EAAE,CAAC;YAC3B,IAAI,CAAC,GAAoB,KAAK,CAAC;YAC/B,OAAO,CAAC,EAAE,CAAC;gBAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC;gBAAC,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;YAAC,CAAC;YAC5D,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,OAAO,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QACnD,CAAC,CAAC,CAAC;IACP,CAAC;CAEJ"}
@@ -0,0 +1,12 @@
1
+ export declare class Store {
2
+ private map;
3
+ private wal;
4
+ constructor(dataDir?: string);
5
+ private recover;
6
+ set(key: string, value: string, ttlSeconds?: number): void;
7
+ get(key: string): string | null;
8
+ del(key: string): boolean;
9
+ exists(key: string): boolean;
10
+ ttl(key: string): number;
11
+ }
12
+ //# sourceMappingURL=Store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Store.d.ts","sourceRoot":"","sources":["../src/Store.ts"],"names":[],"mappings":"AASA,qBAAa,KAAK;IAChB,OAAO,CAAC,GAAG,CAAsB;IACjC,OAAO,CAAC,GAAG,CAAM;gBAEL,OAAO,GAAE,MAAgB;IAQrC,OAAO,CAAC,OAAO;IAqBf,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI;IAkB1D,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAc/B,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAMzB,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAK5B,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM;CAOzB"}
package/dist/Store.js ADDED
@@ -0,0 +1,76 @@
1
+ import * as fs from 'fs';
2
+ import { HashMap } from './HashMap.js';
3
+ import { WAL } from './WAL.js';
4
+ export class Store {
5
+ map;
6
+ wal;
7
+ constructor(dataDir = './data') {
8
+ this.map = new HashMap();
9
+ this.wal = new WAL(dataDir);
10
+ this.recover();
11
+ }
12
+ recover() {
13
+ const entries = this.wal.readAll();
14
+ if (entries.length === 0)
15
+ return; // clean WAL file
16
+ for (const entry of entries) {
17
+ if (entry.op === 'SET') {
18
+ const expiresAt = entry.ttlSeconds
19
+ ? entry.timestamp + entry.ttlSeconds * 1000
20
+ : null;
21
+ if (expiresAt !== null && Date.now() > expiresAt)
22
+ continue;
23
+ this.map.set(entry.key, { value: entry.value, expiresAt });
24
+ }
25
+ else if (entry.op === 'DEL') {
26
+ this.map.delete(entry.key);
27
+ }
28
+ }
29
+ }
30
+ // SET key value [EX seconds]
31
+ set(key, value, ttlSeconds) {
32
+ this.wal.append({
33
+ op: 'SET',
34
+ key,
35
+ value,
36
+ timestamp: Date.now(),
37
+ ...(ttlSeconds !== undefined && { ttlSeconds })
38
+ });
39
+ const expiresAt = ttlSeconds
40
+ ? Date.now() + ttlSeconds * 1000
41
+ : null;
42
+ this.map.set(key, { value, expiresAt });
43
+ }
44
+ // GET key → returns the value, or null if missing/expired
45
+ get(key) {
46
+ const entry = this.map.get(key);
47
+ if (!entry)
48
+ return null;
49
+ // Lazy expiry — we check on read, not on a background timer
50
+ if (entry.expiresAt !== null && Date.now() > entry.expiresAt) {
51
+ this.map.delete(key); // clean up expired key
52
+ return null;
53
+ }
54
+ return entry.value;
55
+ }
56
+ // DEL key → returns true if deleted, false if key didn't exist
57
+ del(key) {
58
+ this.wal.append({ op: 'DEL', key, timestamp: Date.now() });
59
+ return this.map.delete(key);
60
+ }
61
+ // EXISTS key
62
+ exists(key) {
63
+ return this.get(key) !== null; // reuses expiry logic from get()
64
+ }
65
+ // TTL key → remaining milliseconds, -1 if no expiry, -2 if not found
66
+ ttl(key) {
67
+ const entry = this.map.get(key);
68
+ if (!entry)
69
+ return -2;
70
+ if (entry.expiresAt === null)
71
+ return -1;
72
+ const remaining = entry.expiresAt - Date.now();
73
+ return remaining > 0 ? remaining : -2;
74
+ }
75
+ }
76
+ //# sourceMappingURL=Store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Store.js","sourceRoot":"","sources":["../src/Store.ts"],"names":[],"mappings":"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"}
package/dist/WAL.d.ts ADDED
@@ -0,0 +1,14 @@
1
+ export interface WALEntry {
2
+ op: 'SET' | 'DEL';
3
+ key: string;
4
+ value?: string;
5
+ ttlSeconds?: number;
6
+ timestamp: number;
7
+ }
8
+ export declare class WAL {
9
+ private filePath;
10
+ constructor(dataDir: string);
11
+ append(entry: WALEntry): void;
12
+ readAll(): WALEntry[];
13
+ }
14
+ //# sourceMappingURL=WAL.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"WAL.d.ts","sourceRoot":"","sources":["../src/WAL.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,QAAQ;IACrB,EAAE,EAAE,KAAK,GAAG,KAAK,CAAC;IAClB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;CACrB;AAED,qBAAa,GAAG;IACZ,OAAO,CAAC,QAAQ,CAAS;gBAEb,OAAO,EAAE,MAAM;IAK3B,MAAM,CAAC,KAAK,EAAE,QAAQ,GAAG,IAAI;IAK7B,OAAO,IAAI,QAAQ,EAAE;CAiBxB"}
package/dist/WAL.js ADDED
@@ -0,0 +1,31 @@
1
+ import * as fs from 'fs';
2
+ import * as path from 'path';
3
+ export class WAL {
4
+ filePath;
5
+ constructor(dataDir) {
6
+ fs.mkdirSync(dataDir, { recursive: true });
7
+ this.filePath = path.join(dataDir, 'store.aof');
8
+ }
9
+ append(entry) {
10
+ const line = JSON.stringify(entry) + '\n';
11
+ fs.appendFileSync(this.filePath, line, 'utf8');
12
+ }
13
+ readAll() {
14
+ if (!fs.existsSync(this.filePath))
15
+ return [];
16
+ const raw = fs.readFileSync(this.filePath, 'utf8');
17
+ const entries = [];
18
+ for (const line of raw.split('\n')) {
19
+ if (!line.trim())
20
+ continue; // skip blank lines
21
+ try {
22
+ entries.push(JSON.parse(line));
23
+ }
24
+ catch {
25
+ console.warn('[WAL] Skipping malformed line:', line);
26
+ }
27
+ }
28
+ return entries;
29
+ }
30
+ }
31
+ //# sourceMappingURL=WAL.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"WAL.js","sourceRoot":"","sources":["../src/WAL.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAU7B,MAAM,OAAO,GAAG;IACJ,QAAQ,CAAS;IAEzB,YAAY,OAAe;QACvB,EAAE,CAAC,SAAS,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC3C,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC;IACpD,CAAC;IAED,MAAM,CAAC,KAAe;QAClB,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC;QAC1C,EAAE,CAAC,cAAc,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;IACnD,CAAC;IAED,OAAO;QACH,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,QAAQ,CAAC;YAAE,OAAO,EAAE,CAAC;QAE7C,MAAM,GAAG,GAAG,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;QACnD,MAAM,OAAO,GAAe,EAAE,CAAC;QAE/B,KAAK,MAAM,IAAI,IAAI,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;YACnC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE;gBAAE,SAAS,CAAC,mBAAmB;YAC/C,IAAI,CAAC;gBACH,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAa,CAAC,CAAC;YAC7C,CAAC;YAAC,MAAM,CAAC;gBACP,OAAO,CAAC,IAAI,CAAC,gCAAgC,EAAE,IAAI,CAAC,CAAC;YACvD,CAAC;QACH,CAAC;QAED,OAAO,OAAO,CAAC;IACnB,CAAC;CACJ"}
@@ -0,0 +1,3 @@
1
+ export { Store } from './Store.js';
2
+ export { WAL, type WALEntry } from './WAL.js';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,GAAG,EAAE,KAAK,QAAQ,EAAE,MAAM,UAAU,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,3 @@
1
+ export { Store } from './Store.js';
2
+ export { WAL } from './WAL.js';
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,GAAG,EAAiB,MAAM,UAAU,CAAC"}
package/package.json ADDED
@@ -0,0 +1,36 @@
1
+ {
2
+ "name": "@notkannan/cache-with-persistence",
3
+ "version": "1.0.0",
4
+ "publishConfig": {
5
+ "access": "public"
6
+ },
7
+ "description": "A Redis-inspired in-memory key-value store with persistence",
8
+ "type": "module",
9
+ "main": "./dist/index.js",
10
+ "types": "./dist/index.d.ts",
11
+ "exports": {
12
+ ".": {
13
+ "types": "./dist/index.d.ts",
14
+ "import": "./dist/index.js"
15
+ }
16
+ },
17
+ "repository": {
18
+ "type": "git",
19
+ "url": "https://github.com/notkannan/cache-with-persistence.git"
20
+ },
21
+ "author": "Kannan Karthikeyan",
22
+ "files": ["dist", "README.md", "LICENSE"],
23
+ "scripts": {
24
+ "build": "tsc",
25
+ "prepublishOnly": "npm run build"
26
+ },
27
+ "keywords": ["redis", "in-memory", "key-value", "store", "wal", "persistence"],
28
+ "license": "ISC",
29
+ "engines": {
30
+ "node": ">=18"
31
+ },
32
+ "devDependencies": {
33
+ "@types/node": "^25.9.3",
34
+ "typescript": "^6.0.3"
35
+ }
36
+ }