embed-cache 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 ADDED
@@ -0,0 +1,91 @@
1
+ # embed-cache
2
+
3
+ Content-addressable embedding cache with deduplication, LRU eviction, TTL support, and batch optimization. Zero external runtime dependencies — caller supplies the embedder function.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ npm install embed-cache
9
+ ```
10
+
11
+ ## Quick start
12
+
13
+ ```typescript
14
+ import { createCache } from 'embed-cache'
15
+
16
+ // Provide your own embedder function
17
+ const cache = createCache({
18
+ embedder: async (texts) => {
19
+ // call OpenAI, Cohere, or any embedding API
20
+ const resp = await openai.embeddings.create({ model: 'text-embedding-3-small', input: texts })
21
+ return resp.data.map(d => d.embedding)
22
+ },
23
+ model: 'text-embedding-3-small',
24
+ maxSize: 50000,
25
+ ttl: 60 * 60 * 1000, // 1 hour
26
+ })
27
+
28
+ // Single embed — repeated calls never call the embedder twice for the same text
29
+ const vec = await cache.embed('Hello world')
30
+
31
+ // Batch embed — collects all cache misses and makes ONE embedder call
32
+ const vecs = await cache.embedBatch(['Hello', 'World', 'Hello'])
33
+ // ^ only calls embedder with ['World'] if 'Hello' is already cached
34
+ ```
35
+
36
+ ## Batch optimization
37
+
38
+ `embedBatch()` separates hits from misses before calling the embedder:
39
+
40
+ 1. Check the cache for every text in the batch.
41
+ 2. Collect all misses into a single array.
42
+ 3. Call `embedder(missTexts)` once.
43
+ 4. Store the new vectors and return the full results in original order.
44
+
45
+ This minimises API calls when a batch contains repeated or previously seen texts.
46
+
47
+ ## Stats
48
+
49
+ ```typescript
50
+ const s = cache.stats()
51
+ console.log(s.hitRate) // 0–1
52
+ console.log(s.tokensEstimatedSaved) // rough token count saved via cache hits
53
+ console.log(s.costEstimatedSaved) // USD saved (uses modelPricePerMillion option)
54
+ ```
55
+
56
+ ## Change detection
57
+
58
+ Track documents so you can skip re-indexing when content has not changed:
59
+
60
+ ```typescript
61
+ await cache.trackDocument('doc-42', content)
62
+
63
+ // later...
64
+ if (await cache.hasChanged('doc-42', newContent)) {
65
+ // re-index
66
+ await cache.trackDocument('doc-42', newContent)
67
+ }
68
+ ```
69
+
70
+ ## Options
71
+
72
+ | Option | Type | Default | Description |
73
+ |---|---|---|---|
74
+ | `embedder` | `(texts: string[]) => Promise<number[][]>` | required | Embedding function |
75
+ | `model` | `string` | required | Model identifier (used as part of cache key) |
76
+ | `ttl` | `number` | none | Milliseconds before an entry expires |
77
+ | `maxSize` | `number` | `10000` | Maximum number of entries (LRU eviction) |
78
+ | `modelPricePerMillion` | `number` | `0.1` | USD per 1M tokens (for cost estimation) |
79
+ | `algorithm` | `'sha256'\|'sha1'\|'md5'` | `'sha256'` | Hash algorithm for key derivation |
80
+ | `normalizeText` | `boolean` | `true` | NFC + trim + collapse whitespace before hashing |
81
+
82
+ ## Per-call options
83
+
84
+ ```typescript
85
+ await cache.embed(text, { bypassCache: true }) // always call embedder
86
+ await cache.embed(text, { ttl: 5000 }) // override TTL for this entry
87
+ ```
88
+
89
+ ## License
90
+
91
+ MIT
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=cache.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/cache.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,202 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const vitest_1 = require("vitest");
4
+ const cache_1 = require("../cache");
5
+ function makeEmbedder(dim = 4) {
6
+ let count = 0;
7
+ let last = [];
8
+ const fn = async (texts) => {
9
+ count++;
10
+ last = texts;
11
+ return texts.map((t, i) => Array.from({ length: dim }, (_, j) => (i + 1) * (j + 1) + t.length * 0.001));
12
+ };
13
+ return { fn, callCount: () => count, lastInput: () => last };
14
+ }
15
+ (0, vitest_1.describe)('embed()', () => {
16
+ (0, vitest_1.it)('caches result: second call does not invoke embedder', async () => {
17
+ const { fn, callCount } = makeEmbedder();
18
+ const cache = (0, cache_1.createCache)({ embedder: fn, model: 'test-model' });
19
+ const v1 = await cache.embed('hello');
20
+ const v2 = await cache.embed('hello');
21
+ (0, vitest_1.expect)(callCount()).toBe(1);
22
+ (0, vitest_1.expect)(v1).toEqual(v2);
23
+ });
24
+ (0, vitest_1.it)('different text triggers a cache miss', async () => {
25
+ const { fn, callCount } = makeEmbedder();
26
+ const cache = (0, cache_1.createCache)({ embedder: fn, model: 'test-model' });
27
+ await cache.embed('hello');
28
+ await cache.embed('world');
29
+ (0, vitest_1.expect)(callCount()).toBe(2);
30
+ });
31
+ (0, vitest_1.it)('same text different case maps to same key when normalize=true', async () => {
32
+ const { fn, callCount } = makeEmbedder();
33
+ const cache = (0, cache_1.createCache)({ embedder: fn, model: 'test-model', normalizeText: true });
34
+ await cache.embed(' Hello ');
35
+ await cache.embed('Hello');
36
+ // both normalize to "Hello" so second call is a hit
37
+ (0, vitest_1.expect)(callCount()).toBe(1);
38
+ });
39
+ (0, vitest_1.it)('bypassCache always calls embedder', async () => {
40
+ const { fn, callCount } = makeEmbedder();
41
+ const cache = (0, cache_1.createCache)({ embedder: fn, model: 'test-model' });
42
+ await cache.embed('hello');
43
+ await cache.embed('hello', { bypassCache: true });
44
+ (0, vitest_1.expect)(callCount()).toBe(2);
45
+ });
46
+ });
47
+ (0, vitest_1.describe)('embedBatch()', () => {
48
+ (0, vitest_1.it)('collects misses: 3 texts with 1 cached → embedder called with 2 texts', async () => {
49
+ const { fn, callCount, lastInput } = makeEmbedder();
50
+ const cache = (0, cache_1.createCache)({ embedder: fn, model: 'test-model' });
51
+ // pre-warm 'alpha'
52
+ await cache.embed('alpha');
53
+ (0, vitest_1.expect)(callCount()).toBe(1);
54
+ const results = await cache.embedBatch(['alpha', 'beta', 'gamma']);
55
+ (0, vitest_1.expect)(callCount()).toBe(2);
56
+ (0, vitest_1.expect)(lastInput()).toEqual(['beta', 'gamma']);
57
+ (0, vitest_1.expect)(results).toHaveLength(3);
58
+ (0, vitest_1.expect)(results[0]).toBeDefined();
59
+ (0, vitest_1.expect)(results[1]).toBeDefined();
60
+ (0, vitest_1.expect)(results[2]).toBeDefined();
61
+ });
62
+ (0, vitest_1.it)('bypassCache calls embedder for all texts', async () => {
63
+ const { fn, callCount } = makeEmbedder();
64
+ const cache = (0, cache_1.createCache)({ embedder: fn, model: 'test-model' });
65
+ await cache.embedBatch(['a', 'b']);
66
+ await cache.embedBatch(['a', 'b'], { bypassCache: true });
67
+ (0, vitest_1.expect)(callCount()).toBe(2);
68
+ });
69
+ (0, vitest_1.it)('returns vectors in correct order', async () => {
70
+ const embedder = async (texts) => texts.map((t) => [t.length]);
71
+ const cache = (0, cache_1.createCache)({ embedder, model: 'test-model' });
72
+ const results = await cache.embedBatch(['ab', 'abc', 'abcd']);
73
+ (0, vitest_1.expect)(results[0]).toEqual([2]);
74
+ (0, vitest_1.expect)(results[1]).toEqual([3]);
75
+ (0, vitest_1.expect)(results[2]).toEqual([4]);
76
+ });
77
+ });
78
+ (0, vitest_1.describe)('stats', () => {
79
+ (0, vitest_1.it)('tracks hits, misses and hitRate correctly', async () => {
80
+ const { fn } = makeEmbedder();
81
+ const cache = (0, cache_1.createCache)({ embedder: fn, model: 'my-model' });
82
+ await cache.embed('x'); // miss
83
+ await cache.embed('x'); // hit
84
+ await cache.embed('x'); // hit
85
+ await cache.embed('y'); // miss
86
+ const s = cache.stats();
87
+ (0, vitest_1.expect)(s.hits).toBe(2);
88
+ (0, vitest_1.expect)(s.misses).toBe(2);
89
+ (0, vitest_1.expect)(s.totalRequests).toBe(4);
90
+ (0, vitest_1.expect)(s.hitRate).toBeCloseTo(0.5);
91
+ (0, vitest_1.expect)(s.model).toBe('my-model');
92
+ });
93
+ (0, vitest_1.it)('reports size and token/cost estimates', async () => {
94
+ const { fn } = makeEmbedder();
95
+ const cache = (0, cache_1.createCache)({ embedder: fn, model: 'my-model', modelPricePerMillion: 2.0 });
96
+ await cache.embed('hello'); // miss
97
+ await cache.embed('hello'); // hit — 'hello'.length / 4 = ~1 token saved
98
+ const s = cache.stats();
99
+ (0, vitest_1.expect)(s.size).toBe(1);
100
+ (0, vitest_1.expect)(s.tokensEstimatedSaved).toBeGreaterThan(0);
101
+ (0, vitest_1.expect)(s.costEstimatedSaved).toBeGreaterThan(0);
102
+ (0, vitest_1.expect)(typeof s.createdAt).toBe('string');
103
+ });
104
+ });
105
+ (0, vitest_1.describe)('clear()', () => {
106
+ (0, vitest_1.it)('resets cache entries and stats', async () => {
107
+ const { fn, callCount } = makeEmbedder();
108
+ const cache = (0, cache_1.createCache)({ embedder: fn, model: 'test-model' });
109
+ await cache.embed('hello');
110
+ (0, vitest_1.expect)(cache.size).toBe(1);
111
+ cache.clear();
112
+ (0, vitest_1.expect)(cache.size).toBe(0);
113
+ await cache.embed('hello');
114
+ (0, vitest_1.expect)(callCount()).toBe(2); // had to re-embed after clear
115
+ const s = cache.stats();
116
+ (0, vitest_1.expect)(s.hits).toBe(0);
117
+ (0, vitest_1.expect)(s.misses).toBe(1);
118
+ });
119
+ });
120
+ (0, vitest_1.describe)('hasChanged / trackDocument', () => {
121
+ (0, vitest_1.it)('hasChanged returns true for unseen docId', async () => {
122
+ const { fn } = makeEmbedder();
123
+ const cache = (0, cache_1.createCache)({ embedder: fn, model: 'test-model' });
124
+ (0, vitest_1.expect)(await cache.hasChanged('doc-1', 'content')).toBe(true);
125
+ });
126
+ (0, vitest_1.it)('hasChanged returns false after trackDocument with same content', async () => {
127
+ const { fn } = makeEmbedder();
128
+ const cache = (0, cache_1.createCache)({ embedder: fn, model: 'test-model' });
129
+ await cache.trackDocument('doc-1', 'content');
130
+ (0, vitest_1.expect)(await cache.hasChanged('doc-1', 'content')).toBe(false);
131
+ });
132
+ (0, vitest_1.it)('hasChanged returns true after content changes', async () => {
133
+ const { fn } = makeEmbedder();
134
+ const cache = (0, cache_1.createCache)({ embedder: fn, model: 'test-model' });
135
+ await cache.trackDocument('doc-1', 'original');
136
+ (0, vitest_1.expect)(await cache.hasChanged('doc-1', 'modified')).toBe(true);
137
+ });
138
+ });
139
+ (0, vitest_1.describe)('size property', () => {
140
+ (0, vitest_1.it)('reflects number of cached entries', async () => {
141
+ const { fn } = makeEmbedder();
142
+ const cache = (0, cache_1.createCache)({ embedder: fn, model: 'test-model' });
143
+ (0, vitest_1.expect)(cache.size).toBe(0);
144
+ await cache.embed('a');
145
+ (0, vitest_1.expect)(cache.size).toBe(1);
146
+ await cache.embed('b');
147
+ (0, vitest_1.expect)(cache.size).toBe(2);
148
+ await cache.embed('a');
149
+ (0, vitest_1.expect)(cache.size).toBe(2);
150
+ });
151
+ });
152
+ (0, vitest_1.describe)('serialize()', () => {
153
+ (0, vitest_1.it)('returns valid JSON with entries and model', async () => {
154
+ const { fn } = makeEmbedder();
155
+ const cache = (0, cache_1.createCache)({ embedder: fn, model: 'test-model' });
156
+ await cache.embed('hello');
157
+ const raw = cache.serialize();
158
+ const parsed = JSON.parse(raw);
159
+ (0, vitest_1.expect)(parsed.model).toBe('test-model');
160
+ (0, vitest_1.expect)(parsed.version).toBe(1);
161
+ (0, vitest_1.expect)(Array.isArray(parsed.entries)).toBe(true);
162
+ (0, vitest_1.expect)(parsed.entries).toHaveLength(1);
163
+ (0, vitest_1.expect)(parsed.entries[0]).toHaveProperty('key');
164
+ (0, vitest_1.expect)(Array.isArray(parsed.entries[0].vector)).toBe(true);
165
+ });
166
+ });
167
+ (0, vitest_1.describe)('LRU eviction', () => {
168
+ (0, vitest_1.it)('evicts least recently used entry when maxSize is exceeded', async () => {
169
+ const calls = [];
170
+ const embedder = async (texts) => {
171
+ calls.push(texts);
172
+ return texts.map(() => [1, 2, 3]);
173
+ };
174
+ const cache = (0, cache_1.createCache)({ embedder, model: 'test-model', maxSize: 2 });
175
+ await cache.embed('a');
176
+ await cache.embed('b');
177
+ (0, vitest_1.expect)(cache.size).toBe(2);
178
+ // access 'a' to make it MRU, 'b' becomes LRU
179
+ await cache.embed('a');
180
+ // adding 'c' should evict 'b'
181
+ await cache.embed('c');
182
+ (0, vitest_1.expect)(cache.size).toBe(2);
183
+ // 'b' was evicted so embedding it again calls embedder
184
+ const beforeCount = calls.length;
185
+ await cache.embed('b');
186
+ (0, vitest_1.expect)(calls.length).toBe(beforeCount + 1);
187
+ });
188
+ });
189
+ (0, vitest_1.describe)('TTL', () => {
190
+ (0, vitest_1.it)('entry expires after TTL and re-embeds on next call', async () => {
191
+ vitest_1.vi.useFakeTimers();
192
+ const { fn, callCount } = makeEmbedder();
193
+ const cache = (0, cache_1.createCache)({ embedder: fn, model: 'test-model', ttl: 100 });
194
+ await cache.embed('hello');
195
+ (0, vitest_1.expect)(callCount()).toBe(1);
196
+ vitest_1.vi.advanceTimersByTime(200);
197
+ await cache.embed('hello');
198
+ (0, vitest_1.expect)(callCount()).toBe(2);
199
+ vitest_1.vi.useRealTimers();
200
+ });
201
+ });
202
+ //# sourceMappingURL=cache.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache.test.js","sourceRoot":"","sources":["../../src/__tests__/cache.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { EmbedCacheOptions, EmbedCache } from './types';
2
+ export declare function createCache(options: EmbedCacheOptions): EmbedCache;
3
+ //# sourceMappingURL=cache.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../src/cache.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,iBAAiB,EAAgB,UAAU,EAAE,MAAM,SAAS,CAAA;AAE1E,wBAAgB,WAAW,CAAC,OAAO,EAAE,iBAAiB,GAAG,UAAU,CAqGlE"}
package/dist/cache.js ADDED
@@ -0,0 +1,97 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createCache = createCache;
4
+ const store_1 = require("./store");
5
+ const stats_1 = require("./stats");
6
+ const key_1 = require("./key");
7
+ function createCache(options) {
8
+ const store = new store_1.MemoryStore(options.maxSize ?? 10000);
9
+ const statsTracker = new stats_1.StatsTracker();
10
+ const algorithm = options.algorithm ?? 'sha256';
11
+ const normalize = options.normalizeText !== false;
12
+ const pricePerMillion = options.modelPricePerMillion ?? 0.1;
13
+ const docHashes = new Map();
14
+ function getKey(text) {
15
+ return (0, key_1.computeKey)(text, options.model, algorithm, normalize);
16
+ }
17
+ function estimateTokens(text) {
18
+ return Math.ceil(text.length / 4);
19
+ }
20
+ return {
21
+ async embed(text, embedOptions) {
22
+ if (embedOptions?.bypassCache) {
23
+ const [vec] = await options.embedder([text]);
24
+ return vec;
25
+ }
26
+ const key = getKey(text);
27
+ const cached = store.get(key);
28
+ if (cached) {
29
+ statsTracker.recordHit(estimateTokens(text));
30
+ return cached;
31
+ }
32
+ statsTracker.recordMiss();
33
+ const [vec] = await options.embedder([text]);
34
+ store.set(key, vec, { ttl: embedOptions?.ttl ?? options.ttl });
35
+ return store.get(key) ?? vec;
36
+ },
37
+ async embedBatch(texts, embedOptions) {
38
+ if (embedOptions?.bypassCache) {
39
+ return options.embedder(texts);
40
+ }
41
+ const results = new Array(texts.length);
42
+ const missIndices = [];
43
+ const missTexts = [];
44
+ for (let i = 0; i < texts.length; i++) {
45
+ const key = getKey(texts[i]);
46
+ const cached = store.get(key);
47
+ if (cached) {
48
+ results[i] = cached;
49
+ statsTracker.recordHit(estimateTokens(texts[i]));
50
+ }
51
+ else {
52
+ missIndices.push(i);
53
+ missTexts.push(texts[i]);
54
+ statsTracker.recordMiss();
55
+ }
56
+ }
57
+ if (missTexts.length > 0) {
58
+ const newVectors = await options.embedder(missTexts);
59
+ for (let j = 0; j < missIndices.length; j++) {
60
+ const i = missIndices[j];
61
+ store.set(getKey(texts[i]), newVectors[j], { ttl: embedOptions?.ttl ?? options.ttl });
62
+ results[i] = store.get(getKey(texts[i])) ?? newVectors[j];
63
+ }
64
+ }
65
+ return results;
66
+ },
67
+ async hasChanged(docId, content) {
68
+ const newHash = (0, key_1.computeKey)(content, 'doc', 'sha256', normalize);
69
+ const oldHash = docHashes.get(docId);
70
+ return oldHash !== newHash;
71
+ },
72
+ async trackDocument(docId, content) {
73
+ const hash = (0, key_1.computeKey)(content, 'doc', 'sha256', normalize);
74
+ docHashes.set(docId, hash);
75
+ },
76
+ stats() {
77
+ return statsTracker.get(options.model, store.size(), pricePerMillion);
78
+ },
79
+ serialize() {
80
+ const entries = [];
81
+ for (const key of store.keys()) {
82
+ const v = store.get(key);
83
+ if (v)
84
+ entries.push({ key, vector: v });
85
+ }
86
+ return JSON.stringify({ entries, model: options.model, version: 1 });
87
+ },
88
+ clear() {
89
+ store.clear();
90
+ statsTracker.reset();
91
+ },
92
+ get size() {
93
+ return store.size();
94
+ },
95
+ };
96
+ }
97
+ //# sourceMappingURL=cache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache.js","sourceRoot":"","sources":["../src/cache.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ export { createCache } from './cache';
2
+ export type { EmbedderFn, EmbedCacheOptions, EmbedOptions, CacheStats, EmbedCache } from './types';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,SAAS,CAAA;AACrC,YAAY,EAAE,UAAU,EAAE,iBAAiB,EAAE,YAAY,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,SAAS,CAAA"}
package/dist/index.js ADDED
@@ -0,0 +1,7 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createCache = void 0;
4
+ // embed-cache - Content-addressable embedding cache with deduplication and TTL
5
+ var cache_1 = require("./cache");
6
+ Object.defineProperty(exports, "createCache", { enumerable: true, get: function () { return cache_1.createCache; } });
7
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,+EAA+E;AAC/E,iCAAqC;AAA5B,oGAAA,WAAW,OAAA"}
package/dist/key.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ export declare function computeKey(text: string, model: string, algorithm: 'sha256' | 'sha1' | 'md5', normalize: boolean): string;
2
+ //# sourceMappingURL=key.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"key.d.ts","sourceRoot":"","sources":["../src/key.ts"],"names":[],"mappings":"AAGA,wBAAgB,UAAU,CACxB,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,QAAQ,GAAG,MAAM,GAAG,KAAK,EACpC,SAAS,EAAE,OAAO,GACjB,MAAM,CAKR"}
package/dist/key.js ADDED
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.computeKey = computeKey;
4
+ const crypto_1 = require("crypto");
5
+ const normalize_1 = require("./normalize");
6
+ function computeKey(text, model, algorithm, normalize) {
7
+ const normalizedText = normalize ? (0, normalize_1.normalizeText)(text) : text;
8
+ const canonicalModel = (0, normalize_1.canonicalizeModel)(model);
9
+ const input = `${normalizedText}\x00${canonicalModel}`;
10
+ return (0, crypto_1.createHash)(algorithm).update(input, 'utf8').digest('hex');
11
+ }
12
+ //# sourceMappingURL=key.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"key.js","sourceRoot":"","sources":["../src/key.ts"],"names":[],"mappings":";;AAGA,gCAUC;AAbD,mCAAmC;AACnC,2CAA8D;AAE9D,SAAgB,UAAU,CACxB,IAAY,EACZ,KAAa,EACb,SAAoC,EACpC,SAAkB;IAElB,MAAM,cAAc,GAAG,SAAS,CAAC,CAAC,CAAC,IAAA,yBAAa,EAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAA;IAC7D,MAAM,cAAc,GAAG,IAAA,6BAAiB,EAAC,KAAK,CAAC,CAAA;IAC/C,MAAM,KAAK,GAAG,GAAG,cAAc,OAAO,cAAc,EAAE,CAAA;IACtD,OAAO,IAAA,mBAAU,EAAC,SAAS,CAAC,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;AAClE,CAAC"}
@@ -0,0 +1,3 @@
1
+ export declare function normalizeText(text: string): string;
2
+ export declare function canonicalizeModel(model: string): string;
3
+ //# sourceMappingURL=normalize.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"normalize.d.ts","sourceRoot":"","sources":["../src/normalize.ts"],"names":[],"mappings":"AAAA,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAElD;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CASvD"}
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.normalizeText = normalizeText;
4
+ exports.canonicalizeModel = canonicalizeModel;
5
+ function normalizeText(text) {
6
+ return text.normalize('NFC').trim().replace(/\s+/g, ' ');
7
+ }
8
+ function canonicalizeModel(model) {
9
+ const KNOWN = {
10
+ 'text-embedding-3-small': 'openai/text-embedding-3-small',
11
+ 'text-embedding-3-large': 'openai/text-embedding-3-large',
12
+ 'text-embedding-ada-002': 'openai/text-embedding-ada-002',
13
+ 'embed-english-v3.0': 'cohere/embed-english-v3.0',
14
+ 'embed-multilingual-v3.0': 'cohere/embed-multilingual-v3.0',
15
+ };
16
+ return KNOWN[model] ?? model.toLowerCase();
17
+ }
18
+ //# sourceMappingURL=normalize.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"normalize.js","sourceRoot":"","sources":["../src/normalize.ts"],"names":[],"mappings":";;AAAA,sCAEC;AAED,8CASC;AAbD,SAAgB,aAAa,CAAC,IAAY;IACxC,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;AAC1D,CAAC;AAED,SAAgB,iBAAiB,CAAC,KAAa;IAC7C,MAAM,KAAK,GAA2B;QACpC,wBAAwB,EAAE,+BAA+B;QACzD,wBAAwB,EAAE,+BAA+B;QACzD,wBAAwB,EAAE,+BAA+B;QACzD,oBAAoB,EAAE,2BAA2B;QACjD,yBAAyB,EAAE,gCAAgC;KAC5D,CAAA;IACD,OAAO,KAAK,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,WAAW,EAAE,CAAA;AAC5C,CAAC"}
@@ -0,0 +1,13 @@
1
+ import type { CacheStats } from './types';
2
+ export declare class StatsTracker {
3
+ private _hits;
4
+ private _misses;
5
+ private _totalRequests;
6
+ private _tokensEstimated;
7
+ private createdAt;
8
+ recordHit(estimatedTokens: number): void;
9
+ recordMiss(): void;
10
+ get(model: string, size: number, pricePerMillion: number): CacheStats;
11
+ reset(): void;
12
+ }
13
+ //# sourceMappingURL=stats.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stats.d.ts","sourceRoot":"","sources":["../src/stats.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,SAAS,CAAA;AAEzC,qBAAa,YAAY;IACvB,OAAO,CAAC,KAAK,CAAI;IACjB,OAAO,CAAC,OAAO,CAAI;IACnB,OAAO,CAAC,cAAc,CAAI;IAC1B,OAAO,CAAC,gBAAgB,CAAI;IAC5B,OAAO,CAAC,SAAS,CAA2B;IAE5C,SAAS,CAAC,eAAe,EAAE,MAAM,GAAG,IAAI;IAMxC,UAAU,IAAI,IAAI;IAKlB,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,GAAG,UAAU;IAcrE,KAAK,IAAI,IAAI;CAMd"}
package/dist/stats.js ADDED
@@ -0,0 +1,40 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.StatsTracker = void 0;
4
+ class StatsTracker {
5
+ _hits = 0;
6
+ _misses = 0;
7
+ _totalRequests = 0;
8
+ _tokensEstimated = 0;
9
+ createdAt = new Date().toISOString();
10
+ recordHit(estimatedTokens) {
11
+ this._hits++;
12
+ this._totalRequests++;
13
+ this._tokensEstimated += estimatedTokens;
14
+ }
15
+ recordMiss() {
16
+ this._misses++;
17
+ this._totalRequests++;
18
+ }
19
+ get(model, size, pricePerMillion) {
20
+ return {
21
+ totalRequests: this._totalRequests,
22
+ hits: this._hits,
23
+ misses: this._misses,
24
+ hitRate: this._totalRequests > 0 ? this._hits / this._totalRequests : 0,
25
+ size,
26
+ tokensEstimatedSaved: this._tokensEstimated,
27
+ costEstimatedSaved: (this._tokensEstimated / 1_000_000) * pricePerMillion,
28
+ model,
29
+ createdAt: this.createdAt,
30
+ };
31
+ }
32
+ reset() {
33
+ this._hits = 0;
34
+ this._misses = 0;
35
+ this._totalRequests = 0;
36
+ this._tokensEstimated = 0;
37
+ }
38
+ }
39
+ exports.StatsTracker = StatsTracker;
40
+ //# sourceMappingURL=stats.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stats.js","sourceRoot":"","sources":["../src/stats.ts"],"names":[],"mappings":";;;AAEA,MAAa,YAAY;IACf,KAAK,GAAG,CAAC,CAAA;IACT,OAAO,GAAG,CAAC,CAAA;IACX,cAAc,GAAG,CAAC,CAAA;IAClB,gBAAgB,GAAG,CAAC,CAAA;IACpB,SAAS,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAA;IAE5C,SAAS,CAAC,eAAuB;QAC/B,IAAI,CAAC,KAAK,EAAE,CAAA;QACZ,IAAI,CAAC,cAAc,EAAE,CAAA;QACrB,IAAI,CAAC,gBAAgB,IAAI,eAAe,CAAA;IAC1C,CAAC;IAED,UAAU;QACR,IAAI,CAAC,OAAO,EAAE,CAAA;QACd,IAAI,CAAC,cAAc,EAAE,CAAA;IACvB,CAAC;IAED,GAAG,CAAC,KAAa,EAAE,IAAY,EAAE,eAAuB;QACtD,OAAO;YACL,aAAa,EAAE,IAAI,CAAC,cAAc;YAClC,IAAI,EAAE,IAAI,CAAC,KAAK;YAChB,MAAM,EAAE,IAAI,CAAC,OAAO;YACpB,OAAO,EAAE,IAAI,CAAC,cAAc,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC;YACvE,IAAI;YACJ,oBAAoB,EAAE,IAAI,CAAC,gBAAgB;YAC3C,kBAAkB,EAAE,CAAC,IAAI,CAAC,gBAAgB,GAAG,SAAS,CAAC,GAAG,eAAe;YACzE,KAAK;YACL,SAAS,EAAE,IAAI,CAAC,SAAS;SAC1B,CAAA;IACH,CAAC;IAED,KAAK;QACH,IAAI,CAAC,KAAK,GAAG,CAAC,CAAA;QACd,IAAI,CAAC,OAAO,GAAG,CAAC,CAAA;QAChB,IAAI,CAAC,cAAc,GAAG,CAAC,CAAA;QACvB,IAAI,CAAC,gBAAgB,GAAG,CAAC,CAAA;IAC3B,CAAC;CACF;AAtCD,oCAsCC"}
@@ -0,0 +1,22 @@
1
+ export declare class MemoryStore {
2
+ private maxSize;
3
+ private entries;
4
+ private nodes;
5
+ private head;
6
+ private tail;
7
+ constructor(maxSize: number);
8
+ get(key: string): number[] | null;
9
+ set(key: string, vector: number[], options?: {
10
+ ttl?: number;
11
+ }): void;
12
+ has(key: string): boolean;
13
+ delete(key: string): void;
14
+ clear(): void;
15
+ size(): number;
16
+ keys(): string[];
17
+ private addToFront;
18
+ private removeNode;
19
+ private moveToFront;
20
+ private evictLRU;
21
+ }
22
+ //# sourceMappingURL=store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../src/store.ts"],"names":[],"mappings":"AAWA,qBAAa,WAAW;IAMV,OAAO,CAAC,OAAO;IAL3B,OAAO,CAAC,OAAO,CAAgC;IAC/C,OAAO,CAAC,KAAK,CAA6B;IAC1C,OAAO,CAAC,IAAI,CAAsB;IAClC,OAAO,CAAC,IAAI,CAAsB;gBAEd,OAAO,EAAE,MAAM;IAEnC,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,IAAI;IAYjC,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,OAAO,CAAC,EAAE;QAAE,GAAG,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI;IAgBpE,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAIzB,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAKzB,KAAK,IAAI,IAAI;IAOb,IAAI,IAAI,MAAM;IAId,IAAI,IAAI,MAAM,EAAE;IAIhB,OAAO,CAAC,UAAU;IAalB,OAAO,CAAC,UAAU;IAkBlB,OAAO,CAAC,WAAW;IAMnB,OAAO,CAAC,QAAQ;CAMjB"}
package/dist/store.js ADDED
@@ -0,0 +1,109 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.MemoryStore = void 0;
4
+ class MemoryStore {
5
+ maxSize;
6
+ entries = new Map();
7
+ nodes = new Map();
8
+ head = null; // MRU
9
+ tail = null; // LRU
10
+ constructor(maxSize) {
11
+ this.maxSize = maxSize;
12
+ }
13
+ get(key) {
14
+ const entry = this.entries.get(key);
15
+ if (!entry)
16
+ return null;
17
+ if (entry.ttl != null && Date.now() > entry.createdAt + entry.ttl) {
18
+ this.removeNode(key);
19
+ this.entries.delete(key);
20
+ return null;
21
+ }
22
+ this.moveToFront(key);
23
+ return Array.from(entry.vector);
24
+ }
25
+ set(key, vector, options) {
26
+ if (this.entries.has(key)) {
27
+ this.moveToFront(key);
28
+ return;
29
+ }
30
+ if (this.entries.size >= this.maxSize) {
31
+ this.evictLRU();
32
+ }
33
+ this.entries.set(key, {
34
+ vector: new Float32Array(vector),
35
+ createdAt: Date.now(),
36
+ ttl: options?.ttl,
37
+ });
38
+ this.addToFront(key);
39
+ }
40
+ has(key) {
41
+ return this.get(key) !== null;
42
+ }
43
+ delete(key) {
44
+ this.removeNode(key);
45
+ this.entries.delete(key);
46
+ }
47
+ clear() {
48
+ this.entries.clear();
49
+ this.nodes.clear();
50
+ this.head = null;
51
+ this.tail = null;
52
+ }
53
+ size() {
54
+ return this.entries.size;
55
+ }
56
+ keys() {
57
+ return Array.from(this.entries.keys());
58
+ }
59
+ addToFront(key) {
60
+ const node = { prev: null, next: this.head };
61
+ this.nodes.set(key, node);
62
+ if (this.head !== null) {
63
+ const headNode = this.nodes.get(this.head);
64
+ if (headNode)
65
+ headNode.prev = key;
66
+ }
67
+ this.head = key;
68
+ if (this.tail === null) {
69
+ this.tail = key;
70
+ }
71
+ }
72
+ removeNode(key) {
73
+ const node = this.nodes.get(key);
74
+ if (!node)
75
+ return;
76
+ if (node.prev !== null) {
77
+ const prevNode = this.nodes.get(node.prev);
78
+ if (prevNode)
79
+ prevNode.next = node.next;
80
+ }
81
+ else {
82
+ this.head = node.next;
83
+ }
84
+ if (node.next !== null) {
85
+ const nextNode = this.nodes.get(node.next);
86
+ if (nextNode)
87
+ nextNode.prev = node.prev;
88
+ }
89
+ else {
90
+ this.tail = node.prev;
91
+ }
92
+ this.nodes.delete(key);
93
+ }
94
+ moveToFront(key) {
95
+ if (this.head === key)
96
+ return;
97
+ this.removeNode(key);
98
+ this.addToFront(key);
99
+ }
100
+ evictLRU() {
101
+ if (this.tail === null)
102
+ return;
103
+ const lruKey = this.tail;
104
+ this.removeNode(lruKey);
105
+ this.entries.delete(lruKey);
106
+ }
107
+ }
108
+ exports.MemoryStore = MemoryStore;
109
+ //# sourceMappingURL=store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store.js","sourceRoot":"","sources":["../src/store.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,36 @@
1
+ export type EmbedderFn = (texts: string[]) => Promise<number[][]>;
2
+ export interface EmbedCacheOptions {
3
+ embedder: EmbedderFn;
4
+ model: string;
5
+ ttl?: number;
6
+ maxSize?: number;
7
+ modelPricePerMillion?: number;
8
+ algorithm?: 'sha256' | 'sha1' | 'md5';
9
+ normalizeText?: boolean;
10
+ }
11
+ export interface EmbedOptions {
12
+ ttl?: number;
13
+ bypassCache?: boolean;
14
+ }
15
+ export interface CacheStats {
16
+ totalRequests: number;
17
+ hits: number;
18
+ misses: number;
19
+ hitRate: number;
20
+ size: number;
21
+ tokensEstimatedSaved: number;
22
+ costEstimatedSaved: number;
23
+ model: string;
24
+ createdAt: string;
25
+ }
26
+ export interface EmbedCache {
27
+ embed(text: string, options?: EmbedOptions): Promise<number[]>;
28
+ embedBatch(texts: string[], options?: EmbedOptions): Promise<number[][]>;
29
+ hasChanged(docId: string, content: string): Promise<boolean>;
30
+ trackDocument(docId: string, content: string): Promise<void>;
31
+ stats(): CacheStats;
32
+ serialize(): string;
33
+ clear(): void;
34
+ readonly size: number;
35
+ }
36
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,UAAU,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAA;AAEjE,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,UAAU,CAAA;IACpB,KAAK,EAAE,MAAM,CAAA;IACb,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,oBAAoB,CAAC,EAAE,MAAM,CAAA;IAC7B,SAAS,CAAC,EAAE,QAAQ,GAAG,MAAM,GAAG,KAAK,CAAA;IACrC,aAAa,CAAC,EAAE,OAAO,CAAA;CACxB;AAED,MAAM,WAAW,YAAY;IAC3B,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,WAAW,CAAC,EAAE,OAAO,CAAA;CACtB;AAED,MAAM,WAAW,UAAU;IACzB,aAAa,EAAE,MAAM,CAAA;IACrB,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,MAAM,CAAA;IACd,OAAO,EAAE,MAAM,CAAA;IACf,IAAI,EAAE,MAAM,CAAA;IACZ,oBAAoB,EAAE,MAAM,CAAA;IAC5B,kBAAkB,EAAE,MAAM,CAAA;IAC1B,KAAK,EAAE,MAAM,CAAA;IACb,SAAS,EAAE,MAAM,CAAA;CAClB;AAED,MAAM,WAAW,UAAU;IACzB,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAAA;IAC9D,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,OAAO,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAA;IACxE,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;IAC5D,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAC5D,KAAK,IAAI,UAAU,CAAA;IACnB,SAAS,IAAI,MAAM,CAAA;IACnB,KAAK,IAAI,IAAI,CAAA;IACb,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CACtB"}
package/dist/types.js ADDED
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
package/package.json ADDED
@@ -0,0 +1,33 @@
1
+ {
2
+ "name": "embed-cache",
3
+ "version": "0.1.0",
4
+ "description": "Content-addressable embedding cache with deduplication and TTL",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "files": [
8
+ "dist"
9
+ ],
10
+ "scripts": {
11
+ "build": "tsc",
12
+ "test": "vitest run",
13
+ "lint": "eslint src/",
14
+ "prepublishOnly": "npm run build"
15
+ },
16
+ "keywords": [],
17
+ "author": "",
18
+ "license": "MIT",
19
+ "engines": {
20
+ "node": ">=18"
21
+ },
22
+ "publishConfig": {
23
+ "access": "public"
24
+ },
25
+ "devDependencies": {
26
+ "@types/node": "^25.5.0",
27
+ "@typescript-eslint/eslint-plugin": "^8.57.1",
28
+ "@typescript-eslint/parser": "^8.57.1",
29
+ "eslint": "^10.1.0",
30
+ "typescript": "^5.9.3",
31
+ "vitest": "^4.1.0"
32
+ }
33
+ }