@warlock.js/cache 4.0.171 → 4.1.1
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 +85 -0
- package/cjs/index.cjs +4088 -0
- package/cjs/index.cjs.map +1 -0
- package/esm/cache-manager.d.mts +314 -0
- package/esm/cache-manager.d.mts.map +1 -0
- package/esm/cache-manager.mjs +486 -0
- package/esm/cache-manager.mjs.map +1 -0
- package/esm/cached/auto-key.d.mts +25 -0
- package/esm/cached/auto-key.d.mts.map +1 -0
- package/esm/cached/auto-key.mjs +55 -0
- package/esm/cached/auto-key.mjs.map +1 -0
- package/esm/cached/cached.d.mts +54 -0
- package/esm/cached/cached.d.mts.map +1 -0
- package/esm/cached/cached.mjs +25 -0
- package/esm/cached/cached.mjs.map +1 -0
- package/esm/cached/index.d.mts +3 -0
- package/esm/cached/index.mjs +5 -0
- package/esm/cached/normalize-args.d.mts +51 -0
- package/esm/cached/normalize-args.d.mts.map +1 -0
- package/esm/cached/normalize-args.mjs +26 -0
- package/esm/cached/normalize-args.mjs.map +1 -0
- package/esm/drivers/base-cache-driver.d.mts +322 -0
- package/esm/drivers/base-cache-driver.d.mts.map +1 -0
- package/esm/drivers/base-cache-driver.mjs +522 -0
- package/esm/drivers/base-cache-driver.mjs.map +1 -0
- package/esm/drivers/file-cache-driver.d.mts +68 -0
- package/esm/drivers/file-cache-driver.d.mts.map +1 -0
- package/esm/drivers/file-cache-driver.mjs +174 -0
- package/esm/drivers/file-cache-driver.mjs.map +1 -0
- package/esm/drivers/index.d.mts +9 -0
- package/esm/drivers/index.mjs +11 -0
- package/esm/drivers/lru-memory-cache-driver.d.mts +136 -0
- package/esm/drivers/lru-memory-cache-driver.d.mts.map +1 -0
- package/esm/drivers/lru-memory-cache-driver.mjs +317 -0
- package/esm/drivers/lru-memory-cache-driver.mjs.map +1 -0
- package/esm/drivers/memory-cache-driver.d.mts +112 -0
- package/esm/drivers/memory-cache-driver.d.mts.map +1 -0
- package/esm/drivers/memory-cache-driver.mjs +241 -0
- package/esm/drivers/memory-cache-driver.mjs.map +1 -0
- package/esm/drivers/memory-extended-cache-driver.d.mts +17 -0
- package/esm/drivers/memory-extended-cache-driver.d.mts.map +1 -0
- package/esm/drivers/memory-extended-cache-driver.mjs +34 -0
- package/esm/drivers/memory-extended-cache-driver.mjs.map +1 -0
- package/esm/drivers/mock-cache-driver.d.mts +137 -0
- package/esm/drivers/mock-cache-driver.d.mts.map +1 -0
- package/esm/drivers/mock-cache-driver.mjs +226 -0
- package/esm/drivers/mock-cache-driver.mjs.map +1 -0
- package/esm/drivers/null-cache-driver.d.mts +69 -0
- package/esm/drivers/null-cache-driver.d.mts.map +1 -0
- package/esm/drivers/null-cache-driver.mjs +92 -0
- package/esm/drivers/null-cache-driver.mjs.map +1 -0
- package/esm/drivers/pg-cache-driver.d.mts +148 -0
- package/esm/drivers/pg-cache-driver.d.mts.map +1 -0
- package/esm/drivers/pg-cache-driver.mjs +437 -0
- package/esm/drivers/pg-cache-driver.mjs.map +1 -0
- package/esm/drivers/redis-cache-driver.d.mts +86 -0
- package/esm/drivers/redis-cache-driver.d.mts.map +1 -0
- package/esm/drivers/redis-cache-driver.mjs +312 -0
- package/esm/drivers/redis-cache-driver.mjs.map +1 -0
- package/esm/index.d.mts +21 -0
- package/esm/index.mjs +24 -0
- package/esm/list/index.d.mts +1 -0
- package/esm/list/memory-cache-list.d.mts +77 -0
- package/esm/list/memory-cache-list.d.mts.map +1 -0
- package/esm/list/memory-cache-list.mjs +119 -0
- package/esm/list/memory-cache-list.mjs.map +1 -0
- package/esm/metrics.d.mts +118 -0
- package/esm/metrics.d.mts.map +1 -0
- package/esm/metrics.mjs +197 -0
- package/esm/metrics.mjs.map +1 -0
- package/esm/scoped-cache.d.mts +205 -0
- package/esm/scoped-cache.d.mts.map +1 -0
- package/esm/scoped-cache.mjs +274 -0
- package/esm/scoped-cache.mjs.map +1 -0
- package/esm/tagged-cache.d.mts +89 -0
- package/esm/tagged-cache.d.mts.map +1 -0
- package/esm/tagged-cache.mjs +147 -0
- package/esm/tagged-cache.mjs.map +1 -0
- package/esm/tagged-scoped-cache.d.mts +111 -0
- package/esm/tagged-scoped-cache.d.mts.map +1 -0
- package/esm/tagged-scoped-cache.mjs +142 -0
- package/esm/tagged-scoped-cache.mjs.map +1 -0
- package/esm/types.d.mts +1067 -0
- package/esm/types.d.mts.map +1 -0
- package/esm/types.mjs +62 -0
- package/esm/types.mjs.map +1 -0
- package/esm/utils.d.mts +161 -0
- package/esm/utils.d.mts.map +1 -0
- package/esm/utils.mjs +222 -0
- package/esm/utils.mjs.map +1 -0
- package/llms-full.txt +2071 -0
- package/llms.txt +28 -0
- package/package.json +53 -39
- package/skills/apply-cache-patterns/SKILL.md +97 -0
- package/skills/cache-basics/SKILL.md +121 -0
- package/skills/configure-pg-cache/SKILL.md +115 -0
- package/skills/configure-set-options/SKILL.md +96 -0
- package/skills/handle-cache-errors/SKILL.md +91 -0
- package/skills/observe-cache/SKILL.md +103 -0
- package/skills/overview/SKILL.md +69 -0
- package/skills/pick-cache-driver/SKILL.md +115 -0
- package/skills/test-cache-code/SKILL.md +219 -0
- package/skills/use-cache-atomic/SKILL.md +67 -0
- package/skills/use-cache-bulk/SKILL.md +57 -0
- package/skills/use-cache-list/SKILL.md +85 -0
- package/skills/use-cache-lock/SKILL.md +104 -0
- package/skills/use-cache-namespace/SKILL.md +88 -0
- package/skills/use-cache-similarity/SKILL.md +94 -0
- package/skills/use-cache-tags/SKILL.md +85 -0
- package/skills/use-cache-update-merge/SKILL.md +84 -0
- package/skills/use-cache-utils/SKILL.md +89 -0
- package/skills/use-cached-hof/SKILL.md +102 -0
- package/skills/use-swr/SKILL.md +104 -0
- package/cjs/cache-manager.d.ts +0 -163
- package/cjs/cache-manager.d.ts.map +0 -1
- package/cjs/cache-manager.js +0 -322
- package/cjs/cache-manager.js.map +0 -1
- package/cjs/drivers/base-cache-driver.d.ts +0 -152
- package/cjs/drivers/base-cache-driver.d.ts.map +0 -1
- package/cjs/drivers/base-cache-driver.js +0 -321
- package/cjs/drivers/base-cache-driver.js.map +0 -1
- package/cjs/drivers/file-cache-driver.d.ts +0 -45
- package/cjs/drivers/file-cache-driver.d.ts.map +0 -1
- package/cjs/drivers/file-cache-driver.js +0 -133
- package/cjs/drivers/file-cache-driver.js.map +0 -1
- package/cjs/drivers/index.d.ts +0 -8
- package/cjs/drivers/index.d.ts.map +0 -1
- package/cjs/drivers/lru-memory-cache-driver.d.ts +0 -98
- package/cjs/drivers/lru-memory-cache-driver.d.ts.map +0 -1
- package/cjs/drivers/lru-memory-cache-driver.js +0 -252
- package/cjs/drivers/lru-memory-cache-driver.js.map +0 -1
- package/cjs/drivers/memory-cache-driver.d.ts +0 -82
- package/cjs/drivers/memory-cache-driver.d.ts.map +0 -1
- package/cjs/drivers/memory-cache-driver.js +0 -218
- package/cjs/drivers/memory-cache-driver.js.map +0 -1
- package/cjs/drivers/memory-extended-cache-driver.d.ts +0 -13
- package/cjs/drivers/memory-extended-cache-driver.d.ts.map +0 -1
- package/cjs/drivers/memory-extended-cache-driver.js +0 -25
- package/cjs/drivers/memory-extended-cache-driver.js.map +0 -1
- package/cjs/drivers/null-cache-driver.d.ts +0 -58
- package/cjs/drivers/null-cache-driver.d.ts.map +0 -1
- package/cjs/drivers/null-cache-driver.js +0 -84
- package/cjs/drivers/null-cache-driver.js.map +0 -1
- package/cjs/drivers/redis-cache-driver.d.ts +0 -57
- package/cjs/drivers/redis-cache-driver.d.ts.map +0 -1
- package/cjs/drivers/redis-cache-driver.js +0 -263
- package/cjs/drivers/redis-cache-driver.js.map +0 -1
- package/cjs/index.d.ts +0 -6
- package/cjs/index.d.ts.map +0 -1
- package/cjs/index.js +0 -1
- package/cjs/index.js.map +0 -1
- package/cjs/tagged-cache.d.ts +0 -77
- package/cjs/tagged-cache.d.ts.map +0 -1
- package/cjs/tagged-cache.js +0 -160
- package/cjs/tagged-cache.js.map +0 -1
- package/cjs/types.d.ts +0 -391
- package/cjs/types.d.ts.map +0 -1
- package/cjs/types.js +0 -36
- package/cjs/types.js.map +0 -1
- package/cjs/utils.d.ts +0 -50
- package/cjs/utils.d.ts.map +0 -1
- package/cjs/utils.js +0 -55
- package/cjs/utils.js.map +0 -1
- package/esm/cache-manager.d.ts +0 -163
- package/esm/cache-manager.d.ts.map +0 -1
- package/esm/cache-manager.js +0 -322
- package/esm/cache-manager.js.map +0 -1
- package/esm/drivers/base-cache-driver.d.ts +0 -152
- package/esm/drivers/base-cache-driver.d.ts.map +0 -1
- package/esm/drivers/base-cache-driver.js +0 -321
- package/esm/drivers/base-cache-driver.js.map +0 -1
- package/esm/drivers/file-cache-driver.d.ts +0 -45
- package/esm/drivers/file-cache-driver.d.ts.map +0 -1
- package/esm/drivers/file-cache-driver.js +0 -133
- package/esm/drivers/file-cache-driver.js.map +0 -1
- package/esm/drivers/index.d.ts +0 -8
- package/esm/drivers/index.d.ts.map +0 -1
- package/esm/drivers/lru-memory-cache-driver.d.ts +0 -98
- package/esm/drivers/lru-memory-cache-driver.d.ts.map +0 -1
- package/esm/drivers/lru-memory-cache-driver.js +0 -252
- package/esm/drivers/lru-memory-cache-driver.js.map +0 -1
- package/esm/drivers/memory-cache-driver.d.ts +0 -82
- package/esm/drivers/memory-cache-driver.d.ts.map +0 -1
- package/esm/drivers/memory-cache-driver.js +0 -218
- package/esm/drivers/memory-cache-driver.js.map +0 -1
- package/esm/drivers/memory-extended-cache-driver.d.ts +0 -13
- package/esm/drivers/memory-extended-cache-driver.d.ts.map +0 -1
- package/esm/drivers/memory-extended-cache-driver.js +0 -25
- package/esm/drivers/memory-extended-cache-driver.js.map +0 -1
- package/esm/drivers/null-cache-driver.d.ts +0 -58
- package/esm/drivers/null-cache-driver.d.ts.map +0 -1
- package/esm/drivers/null-cache-driver.js +0 -84
- package/esm/drivers/null-cache-driver.js.map +0 -1
- package/esm/drivers/redis-cache-driver.d.ts +0 -57
- package/esm/drivers/redis-cache-driver.d.ts.map +0 -1
- package/esm/drivers/redis-cache-driver.js +0 -263
- package/esm/drivers/redis-cache-driver.js.map +0 -1
- package/esm/index.d.ts +0 -6
- package/esm/index.d.ts.map +0 -1
- package/esm/index.js +0 -1
- package/esm/index.js.map +0 -1
- package/esm/tagged-cache.d.ts +0 -77
- package/esm/tagged-cache.d.ts.map +0 -1
- package/esm/tagged-cache.js +0 -160
- package/esm/tagged-cache.js.map +0 -1
- package/esm/types.d.ts +0 -391
- package/esm/types.d.ts.map +0 -1
- package/esm/types.js +0 -36
- package/esm/types.js.map +0 -1
- package/esm/utils.d.ts +0 -50
- package/esm/utils.d.ts.map +0 -1
- package/esm/utils.js +0 -55
- package/esm/utils.js.map +0 -1
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
import { BaseCacheDriver } from "./base-cache-driver.mjs";
|
|
2
|
+
|
|
3
|
+
//#region ../../@warlock.js/cache/src/drivers/mock-cache-driver.ts
|
|
4
|
+
/**
|
|
5
|
+
* In-memory cache driver with introspection helpers, intended for use as a
|
|
6
|
+
* test double in downstream packages.
|
|
7
|
+
*
|
|
8
|
+
* **Role.** Drop-in replacement for any real driver in test setups, with
|
|
9
|
+
* extra surface that makes behavioral assertions easy: every public op gets
|
|
10
|
+
* recorded into {@link MockCacheDriver.callLog}, and {@link wasCalled} /
|
|
11
|
+
* {@link getStored} / {@link reset} let tests verify side effects without
|
|
12
|
+
* pulling in a real Redis / Postgres / file system.
|
|
13
|
+
*
|
|
14
|
+
* **Responsibility.**
|
|
15
|
+
* - Owns: in-memory storage backed by a `Map`, the `callLog`, TTL handling
|
|
16
|
+
* via `parseCachedData`, `onConflict` policies, and tag-index storage.
|
|
17
|
+
* - Does NOT own: similarity retrieval (vectors are recorded into the
|
|
18
|
+
* `callLog` but `similar()` throws — use `MemoryCacheDriver` for tests
|
|
19
|
+
* that need real nearest-neighbor scoring), connection lifecycle
|
|
20
|
+
* (no-op `connect`/`disconnect`), or eviction (no `maxSize`).
|
|
21
|
+
*
|
|
22
|
+
* Register it like any other driver — sub-paths are not part of the
|
|
23
|
+
* package's export convention; the same single barrel ships it next to
|
|
24
|
+
* the production drivers.
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* import { cache, MockCacheDriver } from "@warlock.js/cache";
|
|
28
|
+
*
|
|
29
|
+
* beforeEach(async () => {
|
|
30
|
+
* cache.setCacheConfigurations({
|
|
31
|
+
* default: "mock",
|
|
32
|
+
* drivers: { mock: MockCacheDriver },
|
|
33
|
+
* options: { mock: {} },
|
|
34
|
+
* });
|
|
35
|
+
* await cache.init();
|
|
36
|
+
* });
|
|
37
|
+
*
|
|
38
|
+
* it("invalidates the user cache after update", async () => {
|
|
39
|
+
* await userService.update(42, { name: "Jane" });
|
|
40
|
+
*
|
|
41
|
+
* const driver = cache.currentDriver as MockCacheDriver;
|
|
42
|
+
* expect(driver.wasCalled("remove", "users.42")).toBe(true);
|
|
43
|
+
* });
|
|
44
|
+
*/
|
|
45
|
+
var MockCacheDriver = class extends BaseCacheDriver {
|
|
46
|
+
constructor(..._args) {
|
|
47
|
+
super(..._args);
|
|
48
|
+
this.name = "mock";
|
|
49
|
+
this.options = {};
|
|
50
|
+
this.storage = /* @__PURE__ */ new Map();
|
|
51
|
+
this.callLog = [];
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Standard driver setup. Mirrors the null driver — no connection, no
|
|
55
|
+
* resources to release.
|
|
56
|
+
*/
|
|
57
|
+
async connect() {
|
|
58
|
+
this.recordCall("connect", void 0);
|
|
59
|
+
await super.connect();
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Standard driver teardown.
|
|
63
|
+
*/
|
|
64
|
+
async disconnect() {
|
|
65
|
+
this.recordCall("disconnect", void 0);
|
|
66
|
+
await super.disconnect();
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Wipe everything under `namespace`. Matches `MemoryCacheDriver` semantics
|
|
70
|
+
* — the namespace itself and any key with the namespace prefix is removed.
|
|
71
|
+
*/
|
|
72
|
+
async removeNamespace(namespace) {
|
|
73
|
+
const parsed = this.parseKey(namespace);
|
|
74
|
+
this.recordCall("removeNamespace", parsed, [namespace]);
|
|
75
|
+
this.log("clearing", parsed);
|
|
76
|
+
const prefix = parsed + ".";
|
|
77
|
+
for (const key of [...this.storage.keys()]) if (key === parsed || key.startsWith(prefix)) this.storage.delete(key);
|
|
78
|
+
this.log("cleared", parsed);
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Standard `set` with full `onConflict` support. Honors scope-default TTL
|
|
82
|
+
* via {@link BaseCacheDriver.resolveSetOptions}.
|
|
83
|
+
*/
|
|
84
|
+
async set(key, value, ttlOrOptions) {
|
|
85
|
+
const parsedKey = this.parseKey(key);
|
|
86
|
+
const { ttl, tags, onConflict, staleAt } = this.resolveSetOptions(ttlOrOptions);
|
|
87
|
+
this.recordCall("set", parsedKey, [value, ttlOrOptions]);
|
|
88
|
+
this.log("caching", parsedKey);
|
|
89
|
+
const existing = onConflict === "upsert" ? null : await this.get(key);
|
|
90
|
+
const exists = existing !== null;
|
|
91
|
+
if (onConflict === "create" && exists) return {
|
|
92
|
+
wasSet: false,
|
|
93
|
+
existing
|
|
94
|
+
};
|
|
95
|
+
if (onConflict === "update" && !exists) return {
|
|
96
|
+
wasSet: false,
|
|
97
|
+
existing: null
|
|
98
|
+
};
|
|
99
|
+
const data = this.prepareDataForStorage(value, ttl, staleAt);
|
|
100
|
+
this.storage.set(parsedKey, data);
|
|
101
|
+
if (tags && tags.length > 0) await this.applyTags(parsedKey, tags);
|
|
102
|
+
this.log("cached", parsedKey);
|
|
103
|
+
await this.emit("set", {
|
|
104
|
+
key: parsedKey,
|
|
105
|
+
value,
|
|
106
|
+
ttl
|
|
107
|
+
});
|
|
108
|
+
if (onConflict === "create" || onConflict === "update") return {
|
|
109
|
+
wasSet: true,
|
|
110
|
+
existing: null
|
|
111
|
+
};
|
|
112
|
+
return value;
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Standard `get` with TTL handling. Emits `hit` / `miss` events to keep
|
|
116
|
+
* downstream metrics tests realistic.
|
|
117
|
+
*/
|
|
118
|
+
async get(key) {
|
|
119
|
+
const parsedKey = this.parseKey(key);
|
|
120
|
+
this.recordCall("get", parsedKey);
|
|
121
|
+
this.log("fetching", parsedKey);
|
|
122
|
+
const data = this.storage.get(parsedKey);
|
|
123
|
+
if (!data) {
|
|
124
|
+
this.log("notFound", parsedKey);
|
|
125
|
+
await this.emit("miss", { key: parsedKey });
|
|
126
|
+
return null;
|
|
127
|
+
}
|
|
128
|
+
const value = await this.parseCachedData(parsedKey, data);
|
|
129
|
+
if (value === null) {
|
|
130
|
+
this.storage.delete(parsedKey);
|
|
131
|
+
await this.emit("miss", { key: parsedKey });
|
|
132
|
+
return null;
|
|
133
|
+
}
|
|
134
|
+
await this.emit("hit", {
|
|
135
|
+
key: parsedKey,
|
|
136
|
+
value
|
|
137
|
+
});
|
|
138
|
+
return value;
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Read the raw {@link CacheData} wrapper from the in-memory `Map`,
|
|
142
|
+
* including `staleAt` metadata. Returns `null` for missing or expired
|
|
143
|
+
* entries — `swr()` consumes this to branch on freshness.
|
|
144
|
+
*/
|
|
145
|
+
async getEntry(key) {
|
|
146
|
+
const parsedKey = this.parseKey(key);
|
|
147
|
+
const entry = this.storage.get(parsedKey);
|
|
148
|
+
if (!entry) return null;
|
|
149
|
+
if (entry.expiresAt !== void 0 && entry.expiresAt <= Date.now()) return null;
|
|
150
|
+
return entry;
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Standard `remove` — drops the entry and emits the `removed` event.
|
|
154
|
+
*/
|
|
155
|
+
async remove(key) {
|
|
156
|
+
const parsedKey = this.parseKey(key);
|
|
157
|
+
this.recordCall("remove", parsedKey);
|
|
158
|
+
this.log("removing", parsedKey);
|
|
159
|
+
this.storage.delete(parsedKey);
|
|
160
|
+
this.log("removed", parsedKey);
|
|
161
|
+
await this.emit("removed", { key: parsedKey });
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Standard `flush` — wipes the entire mock store + tag index. Does NOT
|
|
165
|
+
* touch the call log; use {@link reset} to clear that as well.
|
|
166
|
+
*/
|
|
167
|
+
async flush() {
|
|
168
|
+
this.recordCall("flush", void 0);
|
|
169
|
+
this.log("flushing");
|
|
170
|
+
this.storage.clear();
|
|
171
|
+
this.log("flushed");
|
|
172
|
+
await this.emit("flushed");
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Was a given operation invoked? When `key` is provided, the match is
|
|
176
|
+
* post-`parseKey` so callers pass the same key shape they used at the
|
|
177
|
+
* call site — strings or objects, both resolve to the same parsed key.
|
|
178
|
+
*
|
|
179
|
+
* @example
|
|
180
|
+
* driver.wasCalled("set"); // any set
|
|
181
|
+
* driver.wasCalled("set", "users.42"); // set on this specific key
|
|
182
|
+
* driver.wasCalled("set", { id: 42 }); // same — object key normalized
|
|
183
|
+
*/
|
|
184
|
+
wasCalled(operation, key) {
|
|
185
|
+
if (key === void 0) return this.callLog.some((call) => call.operation === operation);
|
|
186
|
+
const parsedKey = this.parseKey(key);
|
|
187
|
+
return this.callLog.some((call) => call.operation === operation && call.key === parsedKey);
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* Return the raw stored value for `key`, bypassing TTL handling and clone
|
|
191
|
+
* protection. Useful when a test wants to assert on the persisted shape
|
|
192
|
+
* (or assert that an entry expired without going through `get`).
|
|
193
|
+
*
|
|
194
|
+
* Returns `undefined` when the key isn't present.
|
|
195
|
+
*/
|
|
196
|
+
getStored(key) {
|
|
197
|
+
const parsedKey = this.parseKey(key);
|
|
198
|
+
const entry = this.storage.get(parsedKey);
|
|
199
|
+
if (!entry) return;
|
|
200
|
+
return entry.data;
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* Wipe everything — storage, tag index, and the call log. Pair with
|
|
204
|
+
* Vitest's `beforeEach` to get clean isolation between tests.
|
|
205
|
+
*/
|
|
206
|
+
reset() {
|
|
207
|
+
this.storage.clear();
|
|
208
|
+
this.callLog.length = 0;
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* Append a row to {@link callLog}. Internal helper called by every
|
|
212
|
+
* recorded op before the actual work runs.
|
|
213
|
+
*/
|
|
214
|
+
recordCall(operation, key, args = []) {
|
|
215
|
+
this.callLog.push({
|
|
216
|
+
operation,
|
|
217
|
+
key,
|
|
218
|
+
args,
|
|
219
|
+
timestamp: Date.now()
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
};
|
|
223
|
+
|
|
224
|
+
//#endregion
|
|
225
|
+
export { MockCacheDriver };
|
|
226
|
+
//# sourceMappingURL=mock-cache-driver.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mock-cache-driver.mjs","names":[],"sources":["../../../../../../@warlock.js/cache/src/drivers/mock-cache-driver.ts"],"sourcesContent":["import type {\n CacheCall,\n CacheData,\n CacheDriver,\n CacheKey,\n CacheSetOptions,\n CacheSetResult,\n CacheTtl,\n MockCacheOptions,\n} from \"../types\";\nimport { BaseCacheDriver } from \"./base-cache-driver\";\n\n/**\n * In-memory cache driver with introspection helpers, intended for use as a\n * test double in downstream packages.\n *\n * **Role.** Drop-in replacement for any real driver in test setups, with\n * extra surface that makes behavioral assertions easy: every public op gets\n * recorded into {@link MockCacheDriver.callLog}, and {@link wasCalled} /\n * {@link getStored} / {@link reset} let tests verify side effects without\n * pulling in a real Redis / Postgres / file system.\n *\n * **Responsibility.**\n * - Owns: in-memory storage backed by a `Map`, the `callLog`, TTL handling\n * via `parseCachedData`, `onConflict` policies, and tag-index storage.\n * - Does NOT own: similarity retrieval (vectors are recorded into the\n * `callLog` but `similar()` throws — use `MemoryCacheDriver` for tests\n * that need real nearest-neighbor scoring), connection lifecycle\n * (no-op `connect`/`disconnect`), or eviction (no `maxSize`).\n *\n * Register it like any other driver — sub-paths are not part of the\n * package's export convention; the same single barrel ships it next to\n * the production drivers.\n *\n * @example\n * import { cache, MockCacheDriver } from \"@warlock.js/cache\";\n *\n * beforeEach(async () => {\n * cache.setCacheConfigurations({\n * default: \"mock\",\n * drivers: { mock: MockCacheDriver },\n * options: { mock: {} },\n * });\n * await cache.init();\n * });\n *\n * it(\"invalidates the user cache after update\", async () => {\n * await userService.update(42, { name: \"Jane\" });\n *\n * const driver = cache.currentDriver as MockCacheDriver;\n * expect(driver.wasCalled(\"remove\", \"users.42\")).toBe(true);\n * });\n */\nexport class MockCacheDriver\n extends BaseCacheDriver<MockCacheDriver, MockCacheOptions>\n implements CacheDriver<MockCacheDriver, MockCacheOptions>\n{\n /**\n * {@inheritdoc}\n */\n public name = \"mock\";\n\n /**\n * {@inheritdoc}\n */\n public options: MockCacheOptions = {};\n\n /**\n * Storage backing the mock — keyed by post-`parseKey` string. Public-readonly\n * so tests can introspect raw entries when {@link getStored} isn't enough.\n */\n public readonly storage: Map<string, CacheData> = new Map();\n\n /**\n * Ordered record of every public operation routed through this driver.\n * Pushed to before each op runs; tests assert via {@link wasCalled} or by\n * inspecting the array directly.\n */\n public readonly callLog: CacheCall[] = [];\n\n /**\n * Standard driver setup. Mirrors the null driver — no connection, no\n * resources to release.\n */\n public async connect(): Promise<void> {\n this.recordCall(\"connect\", undefined);\n await super.connect();\n }\n\n /**\n * Standard driver teardown.\n */\n public async disconnect(): Promise<void> {\n this.recordCall(\"disconnect\", undefined);\n await super.disconnect();\n }\n\n /**\n * Wipe everything under `namespace`. Matches `MemoryCacheDriver` semantics\n * — the namespace itself and any key with the namespace prefix is removed.\n */\n public async removeNamespace(namespace: string): Promise<void> {\n const parsed = this.parseKey(namespace);\n\n this.recordCall(\"removeNamespace\", parsed, [namespace]);\n this.log(\"clearing\", parsed);\n\n const prefix = parsed + \".\";\n\n for (const key of [...this.storage.keys()]) {\n if (key === parsed || key.startsWith(prefix)) {\n this.storage.delete(key);\n }\n }\n\n this.log(\"cleared\", parsed);\n }\n\n /**\n * Standard `set` with full `onConflict` support. Honors scope-default TTL\n * via {@link BaseCacheDriver.resolveSetOptions}.\n */\n public async set(\n key: CacheKey,\n value: any,\n ttlOrOptions?: CacheTtl | CacheSetOptions,\n ): Promise<any> {\n const parsedKey = this.parseKey(key);\n const { ttl, tags, onConflict, staleAt } = this.resolveSetOptions(ttlOrOptions);\n\n this.recordCall(\"set\", parsedKey, [value, ttlOrOptions]);\n this.log(\"caching\", parsedKey);\n\n const existing = onConflict === \"upsert\" ? null : await this.get(key);\n const exists = existing !== null;\n\n if (onConflict === \"create\" && exists) {\n const result: CacheSetResult = { wasSet: false, existing };\n\n return result;\n }\n\n if (onConflict === \"update\" && !exists) {\n const result: CacheSetResult = { wasSet: false, existing: null };\n\n return result;\n }\n\n const data = this.prepareDataForStorage(value, ttl, staleAt);\n this.storage.set(parsedKey, data);\n\n if (tags && tags.length > 0) {\n await this.applyTags(parsedKey, tags);\n }\n\n this.log(\"cached\", parsedKey);\n await this.emit(\"set\", { key: parsedKey, value, ttl });\n\n if (onConflict === \"create\" || onConflict === \"update\") {\n const result: CacheSetResult = { wasSet: true, existing: null };\n\n return result;\n }\n\n return value;\n }\n\n /**\n * Standard `get` with TTL handling. Emits `hit` / `miss` events to keep\n * downstream metrics tests realistic.\n */\n public async get<T = any>(key: CacheKey): Promise<T | null> {\n const parsedKey = this.parseKey(key);\n\n this.recordCall(\"get\", parsedKey);\n this.log(\"fetching\", parsedKey);\n\n const data = this.storage.get(parsedKey);\n\n if (!data) {\n this.log(\"notFound\", parsedKey);\n await this.emit(\"miss\", { key: parsedKey });\n\n return null;\n }\n\n const value = await this.parseCachedData(parsedKey, data);\n\n if (value === null) {\n // expired — the parse helper already logged + queued the cleanup\n this.storage.delete(parsedKey);\n await this.emit(\"miss\", { key: parsedKey });\n\n return null;\n }\n\n await this.emit(\"hit\", { key: parsedKey, value });\n\n return value as T;\n }\n\n /**\n * Read the raw {@link CacheData} wrapper from the in-memory `Map`,\n * including `staleAt` metadata. Returns `null` for missing or expired\n * entries — `swr()` consumes this to branch on freshness.\n */\n protected async getEntry(key: CacheKey): Promise<CacheData | null> {\n const parsedKey = this.parseKey(key);\n const entry = this.storage.get(parsedKey);\n\n if (!entry) {\n return null;\n }\n\n if (entry.expiresAt !== undefined && entry.expiresAt <= Date.now()) {\n return null;\n }\n\n return entry;\n }\n\n /**\n * Standard `remove` — drops the entry and emits the `removed` event.\n */\n public async remove(key: CacheKey): Promise<void> {\n const parsedKey = this.parseKey(key);\n\n this.recordCall(\"remove\", parsedKey);\n this.log(\"removing\", parsedKey);\n\n this.storage.delete(parsedKey);\n\n this.log(\"removed\", parsedKey);\n await this.emit(\"removed\", { key: parsedKey });\n }\n\n /**\n * Standard `flush` — wipes the entire mock store + tag index. Does NOT\n * touch the call log; use {@link reset} to clear that as well.\n */\n public async flush(): Promise<void> {\n this.recordCall(\"flush\", undefined);\n this.log(\"flushing\");\n\n this.storage.clear();\n\n this.log(\"flushed\");\n await this.emit(\"flushed\");\n }\n\n /**\n * Was a given operation invoked? When `key` is provided, the match is\n * post-`parseKey` so callers pass the same key shape they used at the\n * call site — strings or objects, both resolve to the same parsed key.\n *\n * @example\n * driver.wasCalled(\"set\"); // any set\n * driver.wasCalled(\"set\", \"users.42\"); // set on this specific key\n * driver.wasCalled(\"set\", { id: 42 }); // same — object key normalized\n */\n public wasCalled(operation: string, key?: CacheKey): boolean {\n if (key === undefined) {\n return this.callLog.some((call) => call.operation === operation);\n }\n\n const parsedKey = this.parseKey(key);\n\n return this.callLog.some(\n (call) => call.operation === operation && call.key === parsedKey,\n );\n }\n\n /**\n * Return the raw stored value for `key`, bypassing TTL handling and clone\n * protection. Useful when a test wants to assert on the persisted shape\n * (or assert that an entry expired without going through `get`).\n *\n * Returns `undefined` when the key isn't present.\n */\n public getStored<T = any>(key: CacheKey): T | undefined {\n const parsedKey = this.parseKey(key);\n const entry = this.storage.get(parsedKey);\n\n if (!entry) {\n return undefined;\n }\n\n return entry.data as T;\n }\n\n /**\n * Wipe everything — storage, tag index, and the call log. Pair with\n * Vitest's `beforeEach` to get clean isolation between tests.\n */\n public reset(): void {\n this.storage.clear();\n this.callLog.length = 0;\n }\n\n /**\n * Append a row to {@link callLog}. Internal helper called by every\n * recorded op before the actual work runs.\n */\n protected recordCall(\n operation: string,\n key: string | undefined,\n args: unknown[] = [],\n ): void {\n this.callLog.push({\n operation,\n key,\n args,\n timestamp: Date.now(),\n });\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAqDA,IAAa,kBAAb,cACU,gBAEV;;;cAIgB;iBAKqB,CAAC;iCAMc,IAAI,IAAI;iBAOnB,CAAC;;;;;;CAMxC,MAAa,UAAyB;EACpC,KAAK,WAAW,WAAW,MAAS;EACpC,MAAM,MAAM,QAAQ;CACtB;;;;CAKA,MAAa,aAA4B;EACvC,KAAK,WAAW,cAAc,MAAS;EACvC,MAAM,MAAM,WAAW;CACzB;;;;;CAMA,MAAa,gBAAgB,WAAkC;EAC7D,MAAM,SAAS,KAAK,SAAS,SAAS;EAEtC,KAAK,WAAW,mBAAmB,QAAQ,CAAC,SAAS,CAAC;EACtD,KAAK,IAAI,YAAY,MAAM;EAE3B,MAAM,SAAS,SAAS;EAExB,KAAK,MAAM,OAAO,CAAC,GAAG,KAAK,QAAQ,KAAK,CAAC,GACvC,IAAI,QAAQ,UAAU,IAAI,WAAW,MAAM,GACzC,KAAK,QAAQ,OAAO,GAAG;EAI3B,KAAK,IAAI,WAAW,MAAM;CAC5B;;;;;CAMA,MAAa,IACX,KACA,OACA,cACc;EACd,MAAM,YAAY,KAAK,SAAS,GAAG;EACnC,MAAM,EAAE,KAAK,MAAM,YAAY,YAAY,KAAK,kBAAkB,YAAY;EAE9E,KAAK,WAAW,OAAO,WAAW,CAAC,OAAO,YAAY,CAAC;EACvD,KAAK,IAAI,WAAW,SAAS;EAE7B,MAAM,WAAW,eAAe,WAAW,OAAO,MAAM,KAAK,IAAI,GAAG;EACpE,MAAM,SAAS,aAAa;EAE5B,IAAI,eAAe,YAAY,QAG7B,OAAO;GAF0B,QAAQ;GAAO;EAEpC;EAGd,IAAI,eAAe,YAAY,CAAC,QAG9B,OAAO;GAF0B,QAAQ;GAAO,UAAU;EAE9C;EAGd,MAAM,OAAO,KAAK,sBAAsB,OAAO,KAAK,OAAO;EAC3D,KAAK,QAAQ,IAAI,WAAW,IAAI;EAEhC,IAAI,QAAQ,KAAK,SAAS,GACxB,MAAM,KAAK,UAAU,WAAW,IAAI;EAGtC,KAAK,IAAI,UAAU,SAAS;EAC5B,MAAM,KAAK,KAAK,OAAO;GAAE,KAAK;GAAW;GAAO;EAAI,CAAC;EAErD,IAAI,eAAe,YAAY,eAAe,UAG5C,OAAO;GAF0B,QAAQ;GAAM,UAAU;EAE7C;EAGd,OAAO;CACT;;;;;CAMA,MAAa,IAAa,KAAkC;EAC1D,MAAM,YAAY,KAAK,SAAS,GAAG;EAEnC,KAAK,WAAW,OAAO,SAAS;EAChC,KAAK,IAAI,YAAY,SAAS;EAE9B,MAAM,OAAO,KAAK,QAAQ,IAAI,SAAS;EAEvC,IAAI,CAAC,MAAM;GACT,KAAK,IAAI,YAAY,SAAS;GAC9B,MAAM,KAAK,KAAK,QAAQ,EAAE,KAAK,UAAU,CAAC;GAE1C,OAAO;EACT;EAEA,MAAM,QAAQ,MAAM,KAAK,gBAAgB,WAAW,IAAI;EAExD,IAAI,UAAU,MAAM;GAElB,KAAK,QAAQ,OAAO,SAAS;GAC7B,MAAM,KAAK,KAAK,QAAQ,EAAE,KAAK,UAAU,CAAC;GAE1C,OAAO;EACT;EAEA,MAAM,KAAK,KAAK,OAAO;GAAE,KAAK;GAAW;EAAM,CAAC;EAEhD,OAAO;CACT;;;;;;CAOA,MAAgB,SAAS,KAA0C;EACjE,MAAM,YAAY,KAAK,SAAS,GAAG;EACnC,MAAM,QAAQ,KAAK,QAAQ,IAAI,SAAS;EAExC,IAAI,CAAC,OACH,OAAO;EAGT,IAAI,MAAM,cAAc,UAAa,MAAM,aAAa,KAAK,IAAI,GAC/D,OAAO;EAGT,OAAO;CACT;;;;CAKA,MAAa,OAAO,KAA8B;EAChD,MAAM,YAAY,KAAK,SAAS,GAAG;EAEnC,KAAK,WAAW,UAAU,SAAS;EACnC,KAAK,IAAI,YAAY,SAAS;EAE9B,KAAK,QAAQ,OAAO,SAAS;EAE7B,KAAK,IAAI,WAAW,SAAS;EAC7B,MAAM,KAAK,KAAK,WAAW,EAAE,KAAK,UAAU,CAAC;CAC/C;;;;;CAMA,MAAa,QAAuB;EAClC,KAAK,WAAW,SAAS,MAAS;EAClC,KAAK,IAAI,UAAU;EAEnB,KAAK,QAAQ,MAAM;EAEnB,KAAK,IAAI,SAAS;EAClB,MAAM,KAAK,KAAK,SAAS;CAC3B;;;;;;;;;;;CAYA,AAAO,UAAU,WAAmB,KAAyB;EAC3D,IAAI,QAAQ,QACV,OAAO,KAAK,QAAQ,MAAM,SAAS,KAAK,cAAc,SAAS;EAGjE,MAAM,YAAY,KAAK,SAAS,GAAG;EAEnC,OAAO,KAAK,QAAQ,MACjB,SAAS,KAAK,cAAc,aAAa,KAAK,QAAQ,SACzD;CACF;;;;;;;;CASA,AAAO,UAAmB,KAA8B;EACtD,MAAM,YAAY,KAAK,SAAS,GAAG;EACnC,MAAM,QAAQ,KAAK,QAAQ,IAAI,SAAS;EAExC,IAAI,CAAC,OACH;EAGF,OAAO,MAAM;CACf;;;;;CAMA,AAAO,QAAc;EACnB,KAAK,QAAQ,MAAM;EACnB,KAAK,QAAQ,SAAS;CACxB;;;;;CAMA,AAAU,WACR,WACA,KACA,OAAkB,CAAC,GACb;EACN,KAAK,QAAQ,KAAK;GAChB;GACA;GACA;GACA,WAAW,KAAK,IAAI;EACtB,CAAC;CACH;AACF"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { BaseCacheDriver } from "./base-cache-driver.mjs";
|
|
2
|
+
import { CacheDriver, CacheKey, CacheSetOptions, CacheTtl, NullCacheDriverOptions } from "../types.mjs";
|
|
3
|
+
import { GenericObject } from "@mongez/reinforcements";
|
|
4
|
+
|
|
5
|
+
//#region ../../@warlock.js/cache/src/drivers/null-cache-driver.d.ts
|
|
6
|
+
declare class NullCacheDriver extends BaseCacheDriver<NullCacheDriver, NullCacheDriverOptions> implements CacheDriver<NullCacheDriver, NullCacheDriverOptions> {
|
|
7
|
+
/**
|
|
8
|
+
* Options list
|
|
9
|
+
*/
|
|
10
|
+
options: GenericObject;
|
|
11
|
+
/**
|
|
12
|
+
* {@inheritdoc}
|
|
13
|
+
*/
|
|
14
|
+
name: string;
|
|
15
|
+
/**
|
|
16
|
+
* Cached data
|
|
17
|
+
*/
|
|
18
|
+
data: GenericObject;
|
|
19
|
+
/**
|
|
20
|
+
* {@inheritdoc}
|
|
21
|
+
*/
|
|
22
|
+
get client(): this;
|
|
23
|
+
/**
|
|
24
|
+
* Constructor
|
|
25
|
+
*/
|
|
26
|
+
constructor(options?: GenericObject);
|
|
27
|
+
/**
|
|
28
|
+
* {@inheritdoc}
|
|
29
|
+
*/
|
|
30
|
+
setOptions(options: GenericObject): this;
|
|
31
|
+
/**
|
|
32
|
+
* {@inheritdoc}
|
|
33
|
+
*/
|
|
34
|
+
parseKey(_key: CacheKey): string;
|
|
35
|
+
/**
|
|
36
|
+
* {@inheritdoc}
|
|
37
|
+
*/
|
|
38
|
+
removeNamespace(namespace: string): Promise<this>;
|
|
39
|
+
/**
|
|
40
|
+
* {@inheritdoc}
|
|
41
|
+
*/
|
|
42
|
+
set(key: CacheKey, _value: any, _ttlOrOptions?: CacheTtl | CacheSetOptions): Promise<any>;
|
|
43
|
+
/**
|
|
44
|
+
* {@inheritdoc}
|
|
45
|
+
*/
|
|
46
|
+
get(key: CacheKey): Promise<null>;
|
|
47
|
+
/**
|
|
48
|
+
* {@inheritdoc}
|
|
49
|
+
*/
|
|
50
|
+
remove(key: CacheKey): Promise<void>;
|
|
51
|
+
/**
|
|
52
|
+
* {@inheritdoc}
|
|
53
|
+
*/
|
|
54
|
+
flush(): Promise<void>;
|
|
55
|
+
/**
|
|
56
|
+
* {@inheritdoc}
|
|
57
|
+
*
|
|
58
|
+
* The null driver is a black-hole — `similar()` mirrors `get()` and returns
|
|
59
|
+
* an empty result set rather than throwing.
|
|
60
|
+
*/
|
|
61
|
+
similar(): Promise<any[]>;
|
|
62
|
+
/**
|
|
63
|
+
* {@inheritdoc}
|
|
64
|
+
*/
|
|
65
|
+
connect(): Promise<void>;
|
|
66
|
+
}
|
|
67
|
+
//#endregion
|
|
68
|
+
export { NullCacheDriver };
|
|
69
|
+
//# sourceMappingURL=null-cache-driver.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"null-cache-driver.d.mts","names":[],"sources":["../../../../../../@warlock.js/cache/src/drivers/null-cache-driver.ts"],"mappings":";;;;;cAWa,eAAA,SACH,eAAA,CAAgB,eAAA,EAAiB,sBAAA,aAC9B,WAAA,CAAY,eAAA,EAAiB,sBAAA;;AAF1C;;EAOS,OAAA,EAAS,aAAA;EANQ;;;EAWjB,IAAA;EALS;;;EAUT,IAAA,EAAM,aAAA;EA4BS;;;EAAA,IAvBX,MAAA,CAAA;EA4CkB;;;cArCV,OAAA,GAAS,aAAA;EA4DH;;;EApDlB,UAAA,CAAW,OAAA,EAAS,aAAA;EAgFP;;;EAxEb,QAAA,CAAS,IAAA,EAAM,QAAA;EA3CA;;;EAkDT,eAAA,CAAgB,SAAA,WAAiB,OAAA;EAlDnC;;;EA6DE,GAAA,CACX,GAAA,EAAK,QAAA,EACL,MAAA,OACA,aAAA,GAAgB,QAAA,GAAW,eAAA,GAC1B,OAAA;EA5Da;;;EAuEH,GAAA,CAAI,GAAA,EAAK,QAAA,GAAQ,OAAA;EAxDnB;;;EAmEE,MAAA,CAAO,GAAA,EAAK,QAAA,GAAQ,OAAA;EApD1B;;;EA6DM,KAAA,CAAA,GAAK,OAAA;EArDI;;;;;;EAiET,OAAA,CAAA,GAAW,OAAA;EA9CtB;;;EAqDW,OAAA,CAAA,GAAO,OAAA;AAAA"}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { BaseCacheDriver } from "./base-cache-driver.mjs";
|
|
2
|
+
import { log } from "@warlock.js/logger";
|
|
3
|
+
|
|
4
|
+
//#region ../../@warlock.js/cache/src/drivers/null-cache-driver.ts
|
|
5
|
+
var NullCacheDriver = class extends BaseCacheDriver {
|
|
6
|
+
/**
|
|
7
|
+
* {@inheritdoc}
|
|
8
|
+
*/
|
|
9
|
+
get client() {
|
|
10
|
+
return this;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Constructor
|
|
14
|
+
*/
|
|
15
|
+
constructor(options = {}) {
|
|
16
|
+
super();
|
|
17
|
+
this.options = {};
|
|
18
|
+
this.name = "null";
|
|
19
|
+
this.data = {};
|
|
20
|
+
this.setOptions(options);
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* {@inheritdoc}
|
|
24
|
+
*/
|
|
25
|
+
setOptions(options) {
|
|
26
|
+
this.options = options;
|
|
27
|
+
return this;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* {@inheritdoc}
|
|
31
|
+
*/
|
|
32
|
+
parseKey(_key) {
|
|
33
|
+
return "";
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* {@inheritdoc}
|
|
37
|
+
*/
|
|
38
|
+
async removeNamespace(namespace) {
|
|
39
|
+
log.info("cache", "clearing namespace", namespace);
|
|
40
|
+
log.success("cache", "namespace cleared", namespace);
|
|
41
|
+
return this;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* {@inheritdoc}
|
|
45
|
+
*/
|
|
46
|
+
async set(key, _value, _ttlOrOptions) {
|
|
47
|
+
log.info("cache", "setting key", key);
|
|
48
|
+
log.success("cache", "key set", key);
|
|
49
|
+
return this;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* {@inheritdoc}
|
|
53
|
+
*/
|
|
54
|
+
async get(key) {
|
|
55
|
+
log.info("cache", "fetching", key);
|
|
56
|
+
log.success("cache", "fetched", key);
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* {@inheritdoc}
|
|
61
|
+
*/
|
|
62
|
+
async remove(key) {
|
|
63
|
+
log.info("cache", "removing", key);
|
|
64
|
+
log.success("cache", "removed", key);
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* {@inheritdoc}
|
|
68
|
+
*/
|
|
69
|
+
async flush() {
|
|
70
|
+
log.info("cache", "flushing", "all");
|
|
71
|
+
log.success("cache", "flushed", "all");
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* {@inheritdoc}
|
|
75
|
+
*
|
|
76
|
+
* The null driver is a black-hole — `similar()` mirrors `get()` and returns
|
|
77
|
+
* an empty result set rather than throwing.
|
|
78
|
+
*/
|
|
79
|
+
async similar() {
|
|
80
|
+
return [];
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* {@inheritdoc}
|
|
84
|
+
*/
|
|
85
|
+
async connect() {
|
|
86
|
+
log.success("cache", "connected", "Connected to null cache driver");
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
//#endregion
|
|
91
|
+
export { NullCacheDriver };
|
|
92
|
+
//# sourceMappingURL=null-cache-driver.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"null-cache-driver.mjs","names":[],"sources":["../../../../../../@warlock.js/cache/src/drivers/null-cache-driver.ts"],"sourcesContent":["import type { GenericObject } from \"@mongez/reinforcements\";\r\nimport { log } from \"@warlock.js/logger\";\r\nimport type {\r\n CacheDriver,\r\n CacheKey,\r\n CacheSetOptions,\r\n CacheTtl,\r\n NullCacheDriverOptions,\r\n} from \"../types\";\r\nimport { BaseCacheDriver } from \"./base-cache-driver\";\r\n\r\nexport class NullCacheDriver\r\n extends BaseCacheDriver<NullCacheDriver, NullCacheDriverOptions>\r\n implements CacheDriver<NullCacheDriver, NullCacheDriverOptions>\r\n{\r\n /**\r\n * Options list\r\n */\r\n public options: GenericObject = {};\r\n\r\n /**\r\n * {@inheritdoc}\r\n */\r\n public name = \"null\";\r\n\r\n /**\r\n * Cached data\r\n */\r\n public data: GenericObject = {};\r\n\r\n /**\r\n * {@inheritdoc}\r\n */\r\n public get client() {\r\n return this;\r\n }\r\n\r\n /**\r\n * Constructor\r\n */\r\n public constructor(options: GenericObject = {}) {\r\n super();\r\n this.setOptions(options);\r\n }\r\n\r\n /**\r\n * {@inheritdoc}\r\n */\r\n public setOptions(options: GenericObject) {\r\n this.options = options;\r\n return this;\r\n }\r\n\r\n /**\r\n * {@inheritdoc}\r\n */\r\n public parseKey(_key: CacheKey) {\r\n return \"\";\r\n }\r\n\r\n /**\r\n * {@inheritdoc}\r\n */\r\n public async removeNamespace(namespace: string) {\r\n log.info(\"cache\", \"clearing namespace\", namespace);\r\n\r\n log.success(\"cache\", \"namespace cleared\", namespace);\r\n\r\n return this;\r\n }\r\n\r\n /**\r\n * {@inheritdoc}\r\n */\r\n public async set(\r\n key: CacheKey,\r\n _value: any,\r\n _ttlOrOptions?: CacheTtl | CacheSetOptions,\r\n ): Promise<any> {\r\n log.info(\"cache\", \"setting key\", key);\r\n\r\n log.success(\"cache\", \"key set\", key);\r\n\r\n return this;\r\n }\r\n\r\n /**\r\n * {@inheritdoc}\r\n */\r\n public async get(key: CacheKey) {\r\n log.info(\"cache\", \"fetching\", key);\r\n\r\n log.success(\"cache\", \"fetched\", key);\r\n\r\n return null;\r\n }\r\n\r\n /**\r\n * {@inheritdoc}\r\n */\r\n public async remove(key: CacheKey) {\r\n log.info(\"cache\", \"removing\", key);\r\n\r\n log.success(\"cache\", \"removed\", key);\r\n }\r\n\r\n /**\r\n * {@inheritdoc}\r\n */\r\n public async flush() {\r\n log.info(\"cache\", \"flushing\", \"all\");\r\n\r\n log.success(\"cache\", \"flushed\", \"all\");\r\n }\r\n\r\n /**\r\n * {@inheritdoc}\r\n *\r\n * The null driver is a black-hole — `similar()` mirrors `get()` and returns\r\n * an empty result set rather than throwing.\r\n */\r\n public async similar(): Promise<any[]> {\r\n return [];\r\n }\r\n\r\n /**\r\n * {@inheritdoc}\r\n */\r\n public async connect() {\r\n log.success(\"cache\", \"connected\", \"Connected to null cache driver\");\r\n }\r\n}\r\n"],"mappings":";;;;AAWA,IAAa,kBAAb,cACU,gBAEV;;;;CAmBE,IAAW,SAAS;EAClB,OAAO;CACT;;;;CAKA,AAAO,YAAY,UAAyB,CAAC,GAAG;EAC9C,MAAM;iBAvBwB,CAAC;cAKnB;cAKe,CAAC;EAc5B,KAAK,WAAW,OAAO;CACzB;;;;CAKA,AAAO,WAAW,SAAwB;EACxC,KAAK,UAAU;EACf,OAAO;CACT;;;;CAKA,AAAO,SAAS,MAAgB;EAC9B,OAAO;CACT;;;;CAKA,MAAa,gBAAgB,WAAmB;EAC9C,IAAI,KAAK,SAAS,sBAAsB,SAAS;EAEjD,IAAI,QAAQ,SAAS,qBAAqB,SAAS;EAEnD,OAAO;CACT;;;;CAKA,MAAa,IACX,KACA,QACA,eACc;EACd,IAAI,KAAK,SAAS,eAAe,GAAG;EAEpC,IAAI,QAAQ,SAAS,WAAW,GAAG;EAEnC,OAAO;CACT;;;;CAKA,MAAa,IAAI,KAAe;EAC9B,IAAI,KAAK,SAAS,YAAY,GAAG;EAEjC,IAAI,QAAQ,SAAS,WAAW,GAAG;EAEnC,OAAO;CACT;;;;CAKA,MAAa,OAAO,KAAe;EACjC,IAAI,KAAK,SAAS,YAAY,GAAG;EAEjC,IAAI,QAAQ,SAAS,WAAW,GAAG;CACrC;;;;CAKA,MAAa,QAAQ;EACnB,IAAI,KAAK,SAAS,YAAY,KAAK;EAEnC,IAAI,QAAQ,SAAS,WAAW,KAAK;CACvC;;;;;;;CAQA,MAAa,UAA0B;EACrC,OAAO,CAAC;CACV;;;;CAKA,MAAa,UAAU;EACrB,IAAI,QAAQ,SAAS,aAAa,gCAAgC;CACpE;AACF"}
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import { BaseCacheDriver } from "./base-cache-driver.mjs";
|
|
2
|
+
import { CacheData, CacheDriver, CacheKey, CacheSetOptions, CacheSimilarHit, CacheSimilarOptions, CacheTtl, PgCacheOptions, PgClientLike } from "../types.mjs";
|
|
3
|
+
|
|
4
|
+
//#region ../../@warlock.js/cache/src/drivers/pg-cache-driver.d.ts
|
|
5
|
+
/**
|
|
6
|
+
* Postgres cache driver with optional pgvector similarity support.
|
|
7
|
+
*
|
|
8
|
+
* Connection lifecycle is the caller's responsibility — pass an already-built
|
|
9
|
+
* `pg.Pool` or `pg.Client` via the `client` option. The driver never closes it
|
|
10
|
+
* on `cache.disconnect()`, so the same pool can serve queries elsewhere in
|
|
11
|
+
* the app.
|
|
12
|
+
*
|
|
13
|
+
* Schema is not auto-migrated. Call `driver.schema()` to get the DDL string
|
|
14
|
+
* and run it through whichever migration tool you use.
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* import { Pool } from "pg";
|
|
18
|
+
* import { cache, PgCacheDriver } from "@warlock.js/cache";
|
|
19
|
+
*
|
|
20
|
+
* const pool = new Pool({ connectionString: process.env.DATABASE_URL });
|
|
21
|
+
*
|
|
22
|
+
* cache.setCacheConfigurations({
|
|
23
|
+
* default: "pg",
|
|
24
|
+
* drivers: { pg: PgCacheDriver },
|
|
25
|
+
* options: { pg: { client: pool, table: "warlock_cache", ttl: "1h" } },
|
|
26
|
+
* });
|
|
27
|
+
*
|
|
28
|
+
* await cache.init();
|
|
29
|
+
*
|
|
30
|
+
* // Run once, via your own migration tooling:
|
|
31
|
+
* // await pool.query(driver.schema());
|
|
32
|
+
*/
|
|
33
|
+
declare class PgCacheDriver extends BaseCacheDriver<PgClientLike, PgCacheOptions> implements CacheDriver<PgClientLike, PgCacheOptions> {
|
|
34
|
+
/**
|
|
35
|
+
* {@inheritdoc}
|
|
36
|
+
*/
|
|
37
|
+
name: string;
|
|
38
|
+
/**
|
|
39
|
+
* Cached result of the pgvector extension check. Populated lazily on first
|
|
40
|
+
* vector op so the driver doesn't probe the database at construction time.
|
|
41
|
+
*/
|
|
42
|
+
protected vectorReady?: boolean;
|
|
43
|
+
/**
|
|
44
|
+
* {@inheritdoc}
|
|
45
|
+
*
|
|
46
|
+
* Validates `client` presence and the table name before storing options.
|
|
47
|
+
*/
|
|
48
|
+
setOptions(options: PgCacheOptions): this;
|
|
49
|
+
/**
|
|
50
|
+
* Lazy pgvector availability check. Runs once on the first vector op and
|
|
51
|
+
* caches the result — subsequent ops are zero-overhead. Throws
|
|
52
|
+
* {@link CacheConfigurationError} if the extension isn't installed; throws
|
|
53
|
+
* {@link CacheUnsupportedError} if `vector` config wasn't provided at all.
|
|
54
|
+
*/
|
|
55
|
+
protected ensureVectorReady(): Promise<void>;
|
|
56
|
+
/**
|
|
57
|
+
* Format a numeric vector for pgvector ingestion. The `vector` type accepts
|
|
58
|
+
* a string literal `'[1,2,3]'` cast via `::vector` — this avoids depending
|
|
59
|
+
* on the binary protocol and works against any pg client.
|
|
60
|
+
*/
|
|
61
|
+
protected formatVector(vector: number[]): string;
|
|
62
|
+
/**
|
|
63
|
+
* Resolved table name. Always defined post-`setOptions` — the validator
|
|
64
|
+
* fills in the default.
|
|
65
|
+
*/
|
|
66
|
+
protected get table(): string;
|
|
67
|
+
/**
|
|
68
|
+
* The user-supplied `pg.Pool` / `pg.Client`. Use this rather than `this.client`
|
|
69
|
+
* (which has a generic fallback to `this`) for actual queries.
|
|
70
|
+
*/
|
|
71
|
+
protected get pgClient(): PgClientLike;
|
|
72
|
+
/**
|
|
73
|
+
* Compute an absolute `expires_at` Date for the given relative TTL in seconds,
|
|
74
|
+
* or `null` when the entry should not expire (`Infinity` / 0 / undefined).
|
|
75
|
+
*/
|
|
76
|
+
protected ttlToExpiresAt(ttl?: number): Date | null;
|
|
77
|
+
/**
|
|
78
|
+
* Return the SQL needed to provision the cache table + index. Run once via
|
|
79
|
+
* the caller's migration tooling — the driver never auto-migrates.
|
|
80
|
+
*
|
|
81
|
+
* @example
|
|
82
|
+
* await pool.query(driver.schema());
|
|
83
|
+
*/
|
|
84
|
+
schema(): string;
|
|
85
|
+
/**
|
|
86
|
+
* {@inheritdoc}
|
|
87
|
+
*/
|
|
88
|
+
connect(): Promise<void>;
|
|
89
|
+
/**
|
|
90
|
+
* {@inheritdoc}
|
|
91
|
+
*
|
|
92
|
+
* Does NOT close the user-supplied client — lifecycle stays with the caller.
|
|
93
|
+
*/
|
|
94
|
+
disconnect(): Promise<void>;
|
|
95
|
+
/**
|
|
96
|
+
* {@inheritdoc}
|
|
97
|
+
*/
|
|
98
|
+
set(key: CacheKey, value: any, ttlOrOptions?: CacheTtl | CacheSetOptions): Promise<any>;
|
|
99
|
+
/**
|
|
100
|
+
* {@inheritdoc}
|
|
101
|
+
*/
|
|
102
|
+
get(key: CacheKey): Promise<any>;
|
|
103
|
+
/**
|
|
104
|
+
* Read the raw {@link CacheData} wrapper, including `staleAt` metadata.
|
|
105
|
+
* Returns `null` for missing or expired rows — `swr()` consumes this to
|
|
106
|
+
* branch on freshness without going through `get()`'s clone-and-emit path.
|
|
107
|
+
*/
|
|
108
|
+
protected getEntry(key: CacheKey): Promise<CacheData | null>;
|
|
109
|
+
/**
|
|
110
|
+
* {@inheritdoc}
|
|
111
|
+
*/
|
|
112
|
+
remove(key: CacheKey): Promise<void>;
|
|
113
|
+
/**
|
|
114
|
+
* {@inheritdoc}
|
|
115
|
+
*
|
|
116
|
+
* Deletes all rows whose key equals the namespace exactly or starts with
|
|
117
|
+
* `<namespace>.` — same boundary semantics as the other drivers.
|
|
118
|
+
*/
|
|
119
|
+
removeNamespace(namespace: string): Promise<this>;
|
|
120
|
+
/**
|
|
121
|
+
* {@inheritdoc}
|
|
122
|
+
*
|
|
123
|
+
* Honors `globalPrefix` — when configured, scopes the flush to entries
|
|
124
|
+
* under the prefix rather than truncating the entire table (which could
|
|
125
|
+
* wipe sibling tenants sharing the same Postgres database).
|
|
126
|
+
*/
|
|
127
|
+
flush(): Promise<void>;
|
|
128
|
+
/**
|
|
129
|
+
* {@inheritdoc}
|
|
130
|
+
*
|
|
131
|
+
* pgvector-backed similarity. Uses the `<=>` cosine-distance operator
|
|
132
|
+
* (lower distance = higher similarity) and converts to cosine similarity
|
|
133
|
+
* as `1 - distance` so the returned `score` matches the rest of the
|
|
134
|
+
* package (`[0, 1]`, higher is more similar).
|
|
135
|
+
*
|
|
136
|
+
* Honors `topK`, `threshold`, and an optional `tags` filter (native
|
|
137
|
+
* `tags && $tags` overlap query — much faster than the meta-key path).
|
|
138
|
+
*
|
|
139
|
+
* Throws {@link CacheUnsupportedError} when `options.vector` was not
|
|
140
|
+
* configured at driver setup; throws {@link CacheConfigurationError} when
|
|
141
|
+
* the pgvector extension is missing or the query vector's dimension count
|
|
142
|
+
* doesn't match the configured one.
|
|
143
|
+
*/
|
|
144
|
+
similar<T = any>(vector: number[], options: CacheSimilarOptions): Promise<CacheSimilarHit<T>[]>;
|
|
145
|
+
}
|
|
146
|
+
//#endregion
|
|
147
|
+
export { PgCacheDriver };
|
|
148
|
+
//# sourceMappingURL=pg-cache-driver.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pg-cache-driver.d.mts","names":[],"sources":["../../../../../../@warlock.js/cache/src/drivers/pg-cache-driver.ts"],"mappings":";;;;;;AAkDA;;;;;;;;;;;;;;;;;;;;;;;;;;cAAa,aAAA,SACH,eAAA,CAAgB,YAAA,EAAc,cAAA,aAC3B,WAAA,CAAY,YAAA,EAAc,cAAA;EA2eV;;;EAtepB,IAAA;EALI;;;;EAAA,UAWD,WAAA;EAZ4B;;;;;EAmB/B,UAAA,CAAW,OAAA,EAAS,cAAA;EAApB;;;;;;EAAA,UAsCS,iBAAA,CAAA,GAAqB,OAAA;EAqCvB;;;;;EAAA,UARJ,YAAA,CAAa,MAAA;EAuChB;;;;EAAA,cA/BO,KAAA,CAAA;EA2FD;;;;EAAA,cAnFC,QAAA,CAAA,GAAY,YAAA;EAsFE;;;;EAAA,UA9ElB,cAAA,CAAe,GAAA,YAAe,IAAA;EA6MvB;;;;;;;EA9LV,MAAA,CAAA;EAkSkB;;;EA3PZ,OAAA,CAAA,GAAO,OAAA;EA4QS;;;;;EA/PhB,UAAA,CAAA,GAAU,OAAA;EAyTrB;;;EAjTW,GAAA,CACX,GAAA,EAAK,QAAA,EACL,KAAA,OACA,YAAA,GAAe,QAAA,GAAW,eAAA,GACzB,OAAA;EA+SQ;;;EAjLE,GAAA,CAAI,GAAA,EAAK,QAAA,GAAQ,OAAA;;;;;;YAwDd,QAAA,CAAS,GAAA,EAAK,QAAA,GAAW,OAAA,CAAQ,SAAA;;;;EA4CpC,MAAA,CAAO,GAAA,EAAK,QAAA,GAAQ,OAAA;;;;;;;EAiBpB,eAAA,CAAgB,SAAA,WAAiB,OAAA;;;;;;;;EA4BjC,KAAA,CAAA,GAAK,OAAA;;;;;;;;;;;;;;;;;EA6BL,OAAA,SAAA,CACX,MAAA,YACA,OAAA,EAAS,mBAAA,GACR,OAAA,CAAQ,eAAA,CAAgB,CAAA;AAAA"}
|