@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/CHANGELOG.md +666 -0
- package/THIRD-PARTY-NOTICES.md +1 -1
- package/dist/Cache.js +89 -0
- package/dist/CacheStore.js +5 -0
- package/dist/_virtual/_rolldown/runtime.js +11 -0
- package/dist/backendMemory.js +114 -0
- package/dist/backendRedis.js +56 -0
- package/dist/errors.js +9 -0
- package/dist/index.js +9 -406
- package/dist/invalidationBus.js +14 -0
- package/dist/layer.js +25 -0
- package/dist/semantic.js +131 -0
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -1,406 +1,9 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
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 };
|
package/dist/semantic.js
ADDED
|
@@ -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.
|
|
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.
|
|
36
|
+
"@voltro/kv": "0.86.0"
|
|
37
37
|
},
|
|
38
38
|
"peerDependencies": {
|
|
39
39
|
"effect": "4.0.1"
|