@voltro/cache 0.85.0 → 0.86.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/dist/index.js CHANGED
@@ -1,406 +1,9 @@
1
- import { Clock as e, Config as t, Context as n, Deferred as r, Effect as i, HashMap as a, HashSet as o, Layer as s, Metric as c, Option as l, PubSub as u, Ref as d, Schema as f, Scope as p, Stream as m, SynchronizedRef as h } from "effect";
2
- import { commandRetry as g, connect as _ } from "@voltro/kv/connection";
3
- //#region \0rolldown/runtime.js
4
- var v = Object.defineProperty, y = (e, t) => {
5
- let n = {};
6
- for (var r in e) v(n, r, {
7
- get: e[r],
8
- enumerable: !0
9
- });
10
- return t || v(n, Symbol.toStringTag, { value: "Module" }), n;
11
- }, b = class extends f.TaggedError()("CacheError", {
12
- operation: f.String,
13
- key: f.String,
14
- cause: f.String
15
- }) {}, x = class extends n.Service()("@voltro/CacheStore") {}, S = {
16
- entries: a.empty(),
17
- tagIndex: a.empty(),
18
- seq: 0,
19
- oldest: void 0,
20
- newest: void 0
21
- }, C = (e, t, n) => {
22
- let r = e;
23
- for (let e of n) {
24
- let n = a.get(r, e);
25
- if (l.isNone(n)) continue;
26
- let i = o.remove(n.value, t);
27
- r = o.size(i) === 0 ? a.remove(r, e) : a.set(r, e, i);
28
- }
29
- return r;
30
- }, w = (e, t) => {
31
- let n = a.get(e.entries, t);
32
- if (l.isNone(n)) return e;
33
- let { older: r, newer: i } = n.value, o = a.remove(e.entries, t);
34
- if (r !== void 0) {
35
- let e = a.get(o, r);
36
- l.isSome(e) && (o = a.set(o, r, {
37
- ...e.value,
38
- newer: i
39
- }));
40
- }
41
- if (i !== void 0) {
42
- let e = a.get(o, i);
43
- l.isSome(e) && (o = a.set(o, i, {
44
- ...e.value,
45
- older: r
46
- }));
47
- }
48
- return {
49
- entries: o,
50
- tagIndex: C(e.tagIndex, t, n.value.tags),
51
- seq: e.seq,
52
- oldest: r === void 0 ? i : e.oldest,
53
- newest: i === void 0 ? r : e.newest
54
- };
55
- }, T = (e, t, n) => {
56
- let r = a.get(e, t), i = l.isSome(r) ? o.add(r.value, n) : o.make(n);
57
- return a.set(e, t, i);
58
- }, E = (e, t) => {
59
- let n = a.size(e.entries) - t;
60
- if (n <= 0) return e;
61
- let r = e;
62
- for (let e = 0; e < n; e++) {
63
- let e = r.oldest;
64
- if (e === void 0) break;
65
- r = w(r, e);
66
- }
67
- return r;
68
- }, D = (e, t, n, r, i, o) => {
69
- let s = w(e, t), c = s.seq + 1, u = s.tagIndex;
70
- for (let e of i) u = T(u, e, t);
71
- let d = a.set(s.entries, t, {
72
- value: n,
73
- expiresAt: r,
74
- tags: i,
75
- seq: c,
76
- older: s.newest,
77
- newer: void 0
78
- });
79
- if (s.newest !== void 0) {
80
- let e = a.get(d, s.newest);
81
- l.isSome(e) && (d = a.set(d, s.newest, {
82
- ...e.value,
83
- newer: t
84
- }));
85
- }
86
- let f = {
87
- entries: d,
88
- tagIndex: u,
89
- seq: c,
90
- oldest: s.oldest ?? t,
91
- newest: t
92
- };
93
- return o === void 0 ? f : E(f, o);
94
- }, O = (e, t) => t === void 0 ? Infinity : e + t, k = (t) => i.gen(function* () {
95
- let n = yield* d.make(S), r = t.maxEntries, o = t.now === void 0 ? e.currentTimeMillis : i.sync(t.now);
96
- return {
97
- get: (e) => o.pipe(i.flatMap((t) => d.modify(n, (n) => {
98
- let r = a.get(n.entries, e);
99
- return l.isNone(r) ? [l.none(), n] : r.value.expiresAt <= t ? [l.none(), w(n, e)] : [l.some(r.value.value), n];
100
- }))),
101
- set: (e, t, a) => o.pipe(i.flatMap((i) => d.update(n, (n) => D(n, e, t, O(i, a?.ttlMs), [], r)))),
102
- setWithTags: (e, t, a) => o.pipe(i.flatMap((i) => d.update(n, (n) => D(n, e, t, O(i, a.ttlMs), a.tags ?? [], r)))),
103
- remove: (e) => o.pipe(i.flatMap((t) => d.modify(n, (n) => {
104
- let r = a.get(n.entries, e);
105
- return l.isNone(r) ? [!1, n] : [r.value.expiresAt > t, w(n, e)];
106
- }))),
107
- has: (e) => o.pipe(i.flatMap((t) => d.modify(n, (n) => {
108
- let r = a.get(n.entries, e);
109
- return l.isNone(r) ? [!1, n] : r.value.expiresAt <= t ? [!1, w(n, e)] : [!0, n];
110
- }))),
111
- clear: () => d.set(n, S),
112
- invalidateTag: (e) => d.modify(n, (t) => {
113
- let n = a.get(t.tagIndex, e);
114
- if (l.isNone(n)) return [0, t];
115
- let r = t, i = 0;
116
- for (let e of n.value) r = w(r, e), i += 1;
117
- return [i, {
118
- ...r,
119
- tagIndex: a.remove(r.tagIndex, e)
120
- }];
121
- })
122
- };
123
- }), A = (e = {}) => s.effect(x, k(e)), j = (e) => _({
124
- url: e.url,
125
- driver: e.driver,
126
- ...e.token === void 0 ? {} : { token: e.token }
127
- }).pipe(i.mapError((e) => new b({
128
- operation: "connect",
129
- key: "",
130
- cause: String(e)
131
- }))), M = "\nlocal NOEXP = 9000000000000000\nlocal ttl = tonumber(ARGV[1])\nlocal now = tonumber(ARGV[2])\nlocal score\nif ttl < 0 then score = NOEXP else score = now + ttl end\nredis.call('ZADD', KEYS[1], score, ARGV[3])\nlocal top = redis.call('ZREVRANGE', KEYS[1], 0, 0, 'WITHSCORES')\nlocal maxScore = tonumber(top[2])\nif maxScore >= NOEXP then\n redis.call('PERSIST', KEYS[1])\nelse\n local rem = maxScore - now\n if rem < 1 then rem = 1 end\n redis.call('PEXPIRE', KEYS[1], rem)\nend\nreturn 1\n", N = (t) => i.gen(function* () {
132
- let n = yield* i.acquireRelease(j(t), (e) => i.promise(() => e.close().catch(() => void 0))), r = t.keyPrefix ?? "voltro:cache", a = (e) => `${r}:v:${e}`, o = (e) => `${r}:t:${e}`, s = (e, t, r) => i.tryPromise({
133
- try: () => r(n),
134
- catch: (n) => new b({
135
- operation: e,
136
- key: t,
137
- cause: String(n)
138
- })
139
- }).pipe(i.retry(g)), c = (e, t) => i.try({
140
- try: () => JSON.stringify(t),
141
- catch: (t) => new b({
142
- operation: "serialize",
143
- key: e,
144
- cause: String(t)
145
- })
146
- }), u = (e, t) => i.try({
147
- try: () => l.some(JSON.parse(t)),
148
- catch: (t) => new b({
149
- operation: "deserialize",
150
- key: e,
151
- cause: String(t)
152
- })
153
- }), d = (e) => s("clear", "", (t) => t.scan(e, `${r}:*`, 200)).pipe(i.flatMap(({ cursor: e, keys: t }) => (t.length > 0 ? s("clear", "", (e) => e.del(t)) : i.succeed(0)).pipe(i.flatMap(() => e === "0" ? i.void : d(e))))), f = (e, t, n) => c(e, t).pipe(i.flatMap((t) => n !== void 0 && n > 0 ? s("set", e, (r) => r.psetex(a(e), Math.ceil(n), t)) : s("set", e, (n) => n.set(a(e), t))), i.asVoid);
154
- return {
155
- get: (e) => s("get", e, (t) => t.get(a(e))).pipe(i.flatMap((t) => t === null ? i.succeed(l.none()) : u(e, t))),
156
- set: (e, t, n) => f(e, t, n?.ttlMs),
157
- setWithTags: (t, n, r) => f(t, n, r.ttlMs).pipe(i.flatMap(() => {
158
- let n = r.tags ?? [];
159
- if (n.length === 0) return i.void;
160
- let a = r.ttlMs !== void 0 && r.ttlMs > 0 ? Math.ceil(r.ttlMs) : -1;
161
- return e.currentTimeMillis.pipe(i.flatMap((e) => i.forEach(n, (n) => s("setWithTags", t, (r) => r.eval(M, 1, o(n), a, e, t)), { discard: !0 })));
162
- })),
163
- remove: (e) => s("remove", e, (t) => t.del([a(e)])).pipe(i.map((e) => e > 0)),
164
- has: (e) => s("has", e, (t) => t.exists(a(e))).pipe(i.map((e) => e > 0)),
165
- clear: () => d("0"),
166
- invalidateTag: (e) => s("invalidateTag", e, (t) => t.zrange(o(e))).pipe(i.flatMap((t) => s("invalidateTag", e, async (n) => {
167
- let r = t.map(a), i = r.length > 0 ? await n.del(r) : 0;
168
- return await n.del([o(e)]), i;
169
- })))
170
- };
171
- }), P = (e) => s.effect(x, N(e)), F = (e) => typeof e == "object" && !!e && e._voltroSwr === 1, I = class t extends n.Service()("@voltro/Cache", { make: i.gen(function* () {
172
- let t = yield* x, n = yield* h.make(a.empty()), o = c.counter("voltro_cache_hits"), s = c.counter("voltro_cache_misses"), u = (n, r, a) => {
173
- let o = a.tags === void 0 ? {} : { tags: a.tags }, s = a.swrMs;
174
- if (s !== void 0) {
175
- let c = a.ttlMs ?? 0;
176
- return e.currentTimeMillis.pipe(i.flatMap((e) => t.setWithTags(n, {
177
- _voltroSwr: 1,
178
- v: r,
179
- freshUntil: e + c
180
- }, {
181
- ttlMs: c + s,
182
- ...o
183
- })));
184
- }
185
- let c = a.ttlMs === void 0 ? {} : { ttlMs: a.ttlMs };
186
- return t.setWithTags(n, r, {
187
- ...c,
188
- ...o
189
- });
190
- }, d = (e, t, n) => n.pipe(i.tap((n) => u(e, n, t))), f = (e, t) => h.modifyEffect(n, (t) => {
191
- let n = a.get(t, e);
192
- return l.isSome(n) ? i.succeed([{
193
- kind: "await",
194
- deferred: n.value
195
- }, t]) : r.make().pipe(i.map((n) => [{
196
- kind: "own",
197
- deferred: n
198
- }, a.set(t, e, n)]));
199
- }).pipe(i.flatMap((o) => {
200
- if (o.kind === "await") return r.await(o.deferred);
201
- let s = o.deferred;
202
- return t.pipe(i.onExit((t) => r.done(s, t).pipe(i.andThen(h.update(n, (t) => a.remove(t, e))))));
203
- })), p = (n, r, a) => t.get(n).pipe(i.flatMap((t) => {
204
- if (l.isSome(t)) {
205
- let s = t.value;
206
- return F(s) ? c.update(o, 1).pipe(i.andThen(e.currentTimeMillis), i.flatMap((e) => {
207
- if (e < s.freshUntil) return i.succeed(s.v);
208
- let t = f(n, d(n, r, a)).pipe(i.catchCause(() => i.void));
209
- return i.forkDetach(t).pipe(i.as(s.v));
210
- })) : c.update(o, 1).pipe(i.as(s));
211
- }
212
- return c.update(s, 1).pipe(i.andThen(f(n, d(n, r, a))));
213
- }));
214
- return {
215
- get: (e) => t.get(e),
216
- set: (e, n, r) => t.set(e, n, r),
217
- setWithTags: (e, n, r) => t.setWithTags(e, n, r),
218
- put: (e, t, n) => u(e, n, t),
219
- remove: t.remove,
220
- has: t.has,
221
- clear: t.clear,
222
- invalidateTag: t.invalidateTag,
223
- wrap: p,
224
- partition: (e, n = {}) => {
225
- let r = (t) => `${e}:${t}`, i = (e) => ({
226
- ...n.ttlMs === void 0 ? {} : { ttlMs: n.ttlMs },
227
- ...n.swrMs === void 0 ? {} : { swrMs: n.swrMs },
228
- ...n.tags === void 0 ? {} : { tags: n.tags },
229
- ...e
230
- });
231
- return {
232
- get: (e) => t.get(r(e)),
233
- set: (e, i, a) => t.set(r(e), i, a ?? (n.ttlMs === void 0 ? void 0 : { ttlMs: n.ttlMs })),
234
- has: (e) => t.has(r(e)),
235
- remove: (e) => t.remove(r(e)),
236
- wrap: (e, t, n) => p(r(e), i(t), n),
237
- invalidateTag: (e) => t.invalidateTag(e)
238
- };
239
- },
240
- stats: () => i.all({
241
- hits: c.value(o),
242
- misses: c.value(s)
243
- }).pipe(i.map(({ hits: e, misses: t }) => {
244
- let n = Number(e.count), r = Number(t.count), i = n + r;
245
- return {
246
- hits: n,
247
- misses: r,
248
- hitRate: i === 0 ? 0 : n / i
249
- };
250
- }))
251
- };
252
- }) }) {
253
- static layer = s.effect(t, t.make);
254
- }, L = (e, t) => `row:${e}:${t}`, R = (e) => `table:${e}`, z = (e) => {
255
- let t = R(e.table);
256
- return e.op === "insert" || e.id === void 0 ? [t] : [L(e.table, e.id), t];
257
- }, B = (e, t) => {
258
- let n = Math.min(e.length, t.length), r = 0, i = 0, a = 0;
259
- for (let o = 0; o < n; o++) {
260
- let n = e[o], s = t[o];
261
- r += n * s, i += n * n, a += s * s;
262
- }
263
- let o = Math.sqrt(i) * Math.sqrt(a);
264
- return o === 0 ? 0 : r / o;
265
- }, V = (e) => {
266
- let t = 2166136261;
267
- for (let n of e) {
268
- let e = Math.round(n * 1e6) | 0;
269
- for (let n = 0; n < 32; n += 8) t ^= e >>> n & 255, t = Math.imul(t, 16777619);
270
- }
271
- return `sem:${(t >>> 0).toString(36)}`;
272
- }, H = {
273
- entries: a.empty(),
274
- byDep: a.empty(),
275
- hits: 0,
276
- misses: 0
277
- }, U = (e, t, n) => {
278
- let r = e;
279
- for (let e of n) {
280
- let n = a.get(r, e);
281
- if (l.isNone(n)) continue;
282
- let i = o.remove(n.value, t);
283
- r = o.size(i) === 0 ? a.remove(r, e) : a.set(r, e, i);
284
- }
285
- return r;
286
- }, W = (e, t) => {
287
- let n = a.get(e.entries, t);
288
- return l.isNone(n) ? e : {
289
- ...e,
290
- entries: a.remove(e.entries, t),
291
- byDep: U(e.byDep, t, n.value.deps)
292
- };
293
- }, G = (e, t) => {
294
- let n = W(e, t.key), r = n.byDep;
295
- for (let e of t.deps) {
296
- let n = a.get(r, e);
297
- r = a.set(r, e, l.isSome(n) ? o.add(n.value, t.key) : o.make(t.key));
298
- }
299
- return {
300
- ...n,
301
- entries: a.set(n.entries, t.key, t),
302
- byDep: r
303
- };
304
- }, K = (e, t = {}) => i.gen(function* () {
305
- let t = yield* d.make(H), n = (n, r) => i.gen(function* () {
306
- let i = yield* d.get(t), a = [], o = 0;
307
- for (let [, e] of i.entries) {
308
- let t = B(n, e.embedding);
309
- t >= r.threshold && a.push([
310
- e,
311
- t,
312
- o
313
- ]), o++;
314
- }
315
- let s = (e, t) => e[1] > t[1] || e[1] === t[1] && e[2] < t[2], c = (e) => {
316
- let t = a[e];
317
- for (; e * 2 + 1 < a.length;) {
318
- let n = e * 2 + 1;
319
- if (n + 1 < a.length && s(a[n + 1], a[n]) && n++, !s(a[n], t)) break;
320
- a[e] = a[n], e = n;
321
- }
322
- a[e] = t;
323
- };
324
- for (let e = Math.floor(a.length / 2) - 1; e >= 0; e--) c(e);
325
- for (; a.length > 0;) {
326
- let [n] = a[0], r = a.pop();
327
- a.length > 0 && (a[0] = r, c(0));
328
- let i = yield* e.get(n.key);
329
- if (l.isSome(i)) return yield* d.update(t, (e) => ({
330
- ...e,
331
- hits: e.hits + 1
332
- })), l.some(i.value);
333
- yield* d.update(t, (e) => W(e, n.key));
334
- }
335
- return yield* d.update(t, (e) => ({
336
- ...e,
337
- misses: e.misses + 1
338
- })), l.none();
339
- }), r = (n, r, a) => i.gen(function* () {
340
- let i = a.key ?? V(n), o = {
341
- tags: a.deps,
342
- ...a.ttlMs === void 0 ? {} : { ttlMs: a.ttlMs }
343
- };
344
- yield* e.setWithTags(i, r, o), yield* d.update(t, (e) => G(e, {
345
- key: i,
346
- embedding: n,
347
- deps: a.deps
348
- }));
349
- }), o = (n) => i.gen(function* () {
350
- let r = yield* d.get(t), i = /* @__PURE__ */ new Set();
351
- for (let e of n) {
352
- let t = a.get(r.byDep, e);
353
- if (l.isSome(t)) for (let e of t.value) i.add(e);
354
- }
355
- for (let t of n) yield* e.invalidateTag(t);
356
- return yield* d.update(t, (e) => {
357
- let t = e;
358
- for (let e of i) t = W(t, e);
359
- return t;
360
- }), i.size;
361
- });
362
- return {
363
- lookup: n,
364
- put: r,
365
- evict: o,
366
- onSourceChange: (e) => o(z(e)),
367
- onTableChange: (e) => o([R(e)]),
368
- clear: () => e.clear().pipe(i.andThen(d.set(t, H))),
369
- stats: () => d.get(t).pipe(i.map((e) => ({
370
- hits: e.hits,
371
- misses: e.misses,
372
- size: a.size(e.entries)
373
- })))
374
- };
375
- }), q = class e extends n.Service()("@voltro/SemanticCache", { make: i.gen(function* () {
376
- return yield* K(yield* x);
377
- }) }) {
378
- static layer = s.effect(e, e.make);
379
- }, J = class e extends n.Service()("@voltro/InvalidationBus", { make: i.gen(function* () {
380
- let e = yield* u.unbounded(), t = yield* i.scope;
381
- return {
382
- publish: (t) => u.publish(e, t).pipe(i.asVoid),
383
- changes: m.fromPubSub(e),
384
- addSink: (n) => p.provide(u.subscribe(e), t).pipe(i.flatMap((e) => m.fromSubscription(e).pipe(m.runForEach((e) => n(e).pipe(i.ignore)), i.forkIn(t))), i.asVoid)
385
- };
386
- }) }) {
387
- static layer = s.effect(e, e.make);
388
- }, Y = /* @__PURE__ */ y({
389
- layer: () => $,
390
- storeLayer: () => Q
391
- }), X = i.gen(function* () {
392
- let e = yield* t.Int("CACHE_MAX_ENTRIES").pipe(t.option);
393
- return A(l.isSome(e) ? { maxEntries: e.value } : {});
394
- }), Z = i.gen(function* () {
395
- let e = yield* t.String("CACHE_REDIS_URL").pipe(t.orElse(() => t.String("REDIS_URL"))), n = yield* t.Literals(["resp", "http"], "CACHE_REDIS_DRIVER").pipe(t.withDefault("resp")), r = yield* t.String("CACHE_REDIS_TOKEN").pipe(t.orElse(() => t.String("UPSTASH_REDIS_REST_TOKEN")), t.option), i = yield* t.String("CACHE_KEY_PREFIX").pipe(t.option);
396
- return P({
397
- driver: n,
398
- url: e,
399
- ...l.isSome(r) ? { token: r.value } : {},
400
- ...l.isSome(i) ? { keyPrefix: i.value } : {}
401
- });
402
- }), Q = s.unwrap(i.gen(function* () {
403
- return (yield* t.Literals(["memory", "redis"], "CACHE_BACKEND").pipe(t.withDefault("memory"))) === "redis" ? yield* Z : yield* X;
404
- })), $ = I.layer.pipe(s.provide(Q));
405
- //#endregion
406
- export { I as Cache, b as CacheError, Y as CacheLayer, x as CacheStore, J as InvalidationBus, q as SemanticCache, B as cosineSimilarity, z as depsForChange, A as layerMemory, P as layerRedis, K as makeSemanticCache, L as rowDep, R as tableDep };
1
+ import { CacheError as e } from "./errors.js";
2
+ import { CacheStore as t } from "./CacheStore.js";
3
+ import { layerMemory as n } from "./backendMemory.js";
4
+ import { layerRedis as r } from "./backendRedis.js";
5
+ import { Cache as i } from "./Cache.js";
6
+ import { SemanticCache as a, cosineSimilarity as o, depsForChange as s, makeSemanticCache as c, rowDep as l, tableDep as u } from "./semantic.js";
7
+ import { InvalidationBus as d } from "./invalidationBus.js";
8
+ import { layer_exports as f } from "./layer.js";
9
+ export { i as Cache, e as CacheError, f as CacheLayer, t as CacheStore, d as InvalidationBus, a as SemanticCache, o as cosineSimilarity, s as depsForChange, n as layerMemory, r as layerRedis, c as makeSemanticCache, l as rowDep, u as tableDep };
@@ -0,0 +1,14 @@
1
+ import { Context as e, Effect as t, Layer as n, PubSub as r, Scope as i, Stream as a } from "effect";
2
+ //#region src/invalidationBus.ts
3
+ var o = class o extends e.Service()("@voltro/InvalidationBus", { make: t.gen(function* () {
4
+ let e = yield* r.unbounded(), n = yield* t.scope;
5
+ return {
6
+ publish: (n) => r.publish(e, n).pipe(t.asVoid),
7
+ changes: a.fromPubSub(e),
8
+ addSink: (o) => i.provide(r.subscribe(e), n).pipe(t.flatMap((e) => a.fromSubscription(e).pipe(a.runForEach((e) => o(e).pipe(t.ignore)), t.forkIn(n))), t.asVoid)
9
+ };
10
+ }) }) {
11
+ static layer = n.effect(o, o.make);
12
+ };
13
+ //#endregion
14
+ export { o as InvalidationBus };
package/dist/layer.js ADDED
@@ -0,0 +1,25 @@
1
+ import { __exportAll as e } from "./_virtual/_rolldown/runtime.js";
2
+ import { layerMemory as t } from "./backendMemory.js";
3
+ import { layerRedis as n } from "./backendRedis.js";
4
+ import { Cache as r } from "./Cache.js";
5
+ import { Config as i, Effect as a, Layer as o, Option as s } from "effect";
6
+ //#region src/layer.ts
7
+ var c = /* @__PURE__ */ e({
8
+ layer: () => f,
9
+ storeLayer: () => d
10
+ }), l = a.gen(function* () {
11
+ let e = yield* i.Int("CACHE_MAX_ENTRIES").pipe(i.option), n = s.isSome(e) ? { maxEntries: e.value } : {};
12
+ return t(n);
13
+ }), u = a.gen(function* () {
14
+ let e = yield* i.String("CACHE_REDIS_URL").pipe(i.orElse(() => i.String("REDIS_URL"))), t = yield* i.Literals(["resp", "http"], "CACHE_REDIS_DRIVER").pipe(i.withDefault("resp")), r = yield* i.String("CACHE_REDIS_TOKEN").pipe(i.orElse(() => i.String("UPSTASH_REDIS_REST_TOKEN")), i.option), a = yield* i.String("CACHE_KEY_PREFIX").pipe(i.option), o = {
15
+ driver: t,
16
+ url: e,
17
+ ...s.isSome(r) ? { token: r.value } : {},
18
+ ...s.isSome(a) ? { keyPrefix: a.value } : {}
19
+ };
20
+ return n(o);
21
+ }), d = o.unwrap(a.gen(function* () {
22
+ return (yield* i.Literals(["memory", "redis"], "CACHE_BACKEND").pipe(i.withDefault("memory"))) === "redis" ? yield* u : yield* l;
23
+ })), f = r.layer.pipe(o.provide(d));
24
+ //#endregion
25
+ export { f as layer, c as layer_exports, d as storeLayer };
@@ -0,0 +1,131 @@
1
+ import { CacheStore as e } from "./CacheStore.js";
2
+ import { Context as t, Effect as n, HashMap as r, HashSet as i, Layer as a, Option as o, Ref as s } from "effect";
3
+ //#region src/semantic.ts
4
+ var c = (e, t) => `row:${e}:${t}`, l = (e) => `table:${e}`, u = (e) => {
5
+ let t = l(e.table);
6
+ return e.op === "insert" || e.id === void 0 ? [t] : [c(e.table, e.id), t];
7
+ }, d = (e, t) => {
8
+ let n = Math.min(e.length, t.length), r = 0, i = 0, a = 0;
9
+ for (let o = 0; o < n; o++) {
10
+ let n = e[o], s = t[o];
11
+ r += n * s, i += n * n, a += s * s;
12
+ }
13
+ let o = Math.sqrt(i) * Math.sqrt(a);
14
+ return o === 0 ? 0 : r / o;
15
+ }, f = (e) => {
16
+ let t = 2166136261;
17
+ for (let n of e) {
18
+ let e = Math.round(n * 1e6) | 0;
19
+ for (let n = 0; n < 32; n += 8) t ^= e >>> n & 255, t = Math.imul(t, 16777619);
20
+ }
21
+ return `sem:${(t >>> 0).toString(36)}`;
22
+ }, p = {
23
+ entries: r.empty(),
24
+ byDep: r.empty(),
25
+ hits: 0,
26
+ misses: 0
27
+ }, m = (e, t, n) => {
28
+ let a = e;
29
+ for (let e of n) {
30
+ let n = r.get(a, e);
31
+ if (o.isNone(n)) continue;
32
+ let s = i.remove(n.value, t);
33
+ a = i.size(s) === 0 ? r.remove(a, e) : r.set(a, e, s);
34
+ }
35
+ return a;
36
+ }, h = (e, t) => {
37
+ let n = r.get(e.entries, t);
38
+ return o.isNone(n) ? e : {
39
+ ...e,
40
+ entries: r.remove(e.entries, t),
41
+ byDep: m(e.byDep, t, n.value.deps)
42
+ };
43
+ }, g = (e, t) => {
44
+ let n = h(e, t.key), a = n.byDep;
45
+ for (let e of t.deps) {
46
+ let n = r.get(a, e);
47
+ a = r.set(a, e, o.isSome(n) ? i.add(n.value, t.key) : i.make(t.key));
48
+ }
49
+ return {
50
+ ...n,
51
+ entries: r.set(n.entries, t.key, t),
52
+ byDep: a
53
+ };
54
+ }, _ = (e, t = {}) => n.gen(function* () {
55
+ let t = yield* s.make(p), i = (r, i) => n.gen(function* () {
56
+ let n = yield* s.get(t), a = [], c = 0;
57
+ for (let [, e] of n.entries) {
58
+ let t = d(r, e.embedding);
59
+ t >= i.threshold && a.push([
60
+ e,
61
+ t,
62
+ c
63
+ ]), c++;
64
+ }
65
+ let l = (e, t) => e[1] > t[1] || e[1] === t[1] && e[2] < t[2], u = (e) => {
66
+ let t = a[e];
67
+ for (; e * 2 + 1 < a.length;) {
68
+ let n = e * 2 + 1;
69
+ if (n + 1 < a.length && l(a[n + 1], a[n]) && n++, !l(a[n], t)) break;
70
+ a[e] = a[n], e = n;
71
+ }
72
+ a[e] = t;
73
+ };
74
+ for (let e = Math.floor(a.length / 2) - 1; e >= 0; e--) u(e);
75
+ for (; a.length > 0;) {
76
+ let [n] = a[0], r = a.pop();
77
+ a.length > 0 && (a[0] = r, u(0));
78
+ let i = yield* e.get(n.key);
79
+ if (o.isSome(i)) return yield* s.update(t, (e) => ({
80
+ ...e,
81
+ hits: e.hits + 1
82
+ })), o.some(i.value);
83
+ yield* s.update(t, (e) => h(e, n.key));
84
+ }
85
+ return yield* s.update(t, (e) => ({
86
+ ...e,
87
+ misses: e.misses + 1
88
+ })), o.none();
89
+ }), a = (r, i, a) => n.gen(function* () {
90
+ let n = a.key ?? f(r), o = {
91
+ tags: a.deps,
92
+ ...a.ttlMs === void 0 ? {} : { ttlMs: a.ttlMs }
93
+ };
94
+ yield* e.setWithTags(n, i, o), yield* s.update(t, (e) => g(e, {
95
+ key: n,
96
+ embedding: r,
97
+ deps: a.deps
98
+ }));
99
+ }), c = (i) => n.gen(function* () {
100
+ let n = yield* s.get(t), a = /* @__PURE__ */ new Set();
101
+ for (let e of i) {
102
+ let t = r.get(n.byDep, e);
103
+ if (o.isSome(t)) for (let e of t.value) a.add(e);
104
+ }
105
+ for (let t of i) yield* e.invalidateTag(t);
106
+ return yield* s.update(t, (e) => {
107
+ let t = e;
108
+ for (let e of a) t = h(t, e);
109
+ return t;
110
+ }), a.size;
111
+ });
112
+ return {
113
+ lookup: i,
114
+ put: a,
115
+ evict: c,
116
+ onSourceChange: (e) => c(u(e)),
117
+ onTableChange: (e) => c([l(e)]),
118
+ clear: () => e.clear().pipe(n.andThen(s.set(t, p))),
119
+ stats: () => s.get(t).pipe(n.map((e) => ({
120
+ hits: e.hits,
121
+ misses: e.misses,
122
+ size: r.size(e.entries)
123
+ })))
124
+ };
125
+ }), v = class r extends t.Service()("@voltro/SemanticCache", { make: n.gen(function* () {
126
+ return yield* _(yield* e);
127
+ }) }) {
128
+ static layer = a.effect(r, r.make);
129
+ };
130
+ //#endregion
131
+ export { v as SemanticCache, d as cosineSimilarity, u as depsForChange, _ as makeSemanticCache, c as rowDep, l as tableDep };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@voltro/cache",
3
- "version": "0.85.0",
3
+ "version": "0.86.0",
4
4
  "description": "Effect-native cache primitive — memory + RESP (Redis/Valkey/KeyDB/Dragonfly/Upstash) backends, tag invalidation, single-flight wrap.",
5
5
  "keywords": [
6
6
  "voltro",
@@ -33,7 +33,7 @@
33
33
  "node": ">=24.0.0"
34
34
  },
35
35
  "dependencies": {
36
- "@voltro/kv": "0.85.0"
36
+ "@voltro/kv": "0.86.0"
37
37
  },
38
38
  "peerDependencies": {
39
39
  "effect": "4.0.1"