@baeta/cache 2.0.0-next.14 → 2.0.0-next.16
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 +166 -7
- package/README.md +31 -23
- package/dist/index.d.ts +2 -2
- package/dist/index.js +30 -7
- package/dist/index.js.map +1 -1
- package/dist/sdk/index.js.map +1 -1
- package/package.json +11 -10
- package/sdk/package.json +0 -5
package/CHANGELOG.md
CHANGED
|
@@ -1,15 +1,174 @@
|
|
|
1
1
|
# @baeta/cache
|
|
2
2
|
|
|
3
|
-
## 2.0.0-next.
|
|
3
|
+
## 2.0.0-next.16
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
### Major Changes
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
- The cache system has been fully rewritten and split out of the GraphQL framework into a standalone `@baeta/cache` package. It no longer depends on `@baeta/core` or `graphql` and can be used on its own. by [@andreisergiu98](https://github.com/andreisergiu98) in [#290](https://github.com/andreisergiu98/baeta/pull/290)
|
|
8
|
+
|
|
9
|
+
The biggest conceptual change: the old GraphQL extension API is gone. There is no more `cacheExtension(...)`, `$createCache`, `$useCache`, `$cacheRef`, `$cacheRevision`, or `$cacheClear`. You no longer register a cache as a Baeta extension. Instead you build a cache object directly with `createCache(client, options)`, declare cached queries with `defineQuery`, and wire it into resolvers with the normal resolver builder (`.map()` / `.resolve()`) — the cache is just a library you call.
|
|
10
|
+
|
|
11
|
+
#### Building a cache
|
|
12
|
+
|
|
13
|
+
In v1 the storage adapter wrapped a client and you created per-type caches off a GraphQL type via the extension:
|
|
14
|
+
|
|
15
|
+
```typescript
|
|
16
|
+
// v1
|
|
17
|
+
import { cacheExtension } from "@baeta/extension-cache";
|
|
18
|
+
import { RedisStore } from "@baeta/extension-cache-redis";
|
|
19
|
+
import Redis from "ioredis";
|
|
20
|
+
|
|
21
|
+
const redis = new Redis("redis://localhost:6379");
|
|
22
|
+
const redisStore = new RedisStore(redis);
|
|
23
|
+
|
|
24
|
+
export const cacheExt = cacheExtension(redisStore, { ttl: 3600 });
|
|
25
|
+
|
|
26
|
+
// in a module
|
|
27
|
+
const userCache = User.$createCache({ revision: 2 });
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
In v2 you pass a `CacheClient` (the adapter) directly to `createCache`, give the cache a `name`, and provide `parse`/`serialize`. `parse`/`serialize` are now required, which lets you validate cached values on read (e.g. with Zod). TTL is now in milliseconds (`ttlMs`) instead of seconds (`ttl`):
|
|
31
|
+
|
|
32
|
+
```typescript
|
|
33
|
+
// v2
|
|
34
|
+
import { createCache, defineQuery } from "@baeta/cache";
|
|
35
|
+
import { RedisCacheClient } from "@baeta/cache-ioredis";
|
|
36
|
+
import Redis from "ioredis";
|
|
37
|
+
import { z } from "zod";
|
|
38
|
+
|
|
39
|
+
const redis = new Redis("redis://localhost:6379");
|
|
40
|
+
const redisClient = new RedisCacheClient(redis);
|
|
41
|
+
|
|
42
|
+
const UserSchema = z.object({
|
|
43
|
+
id: z.string(),
|
|
44
|
+
email: z.string(),
|
|
45
|
+
name: z.string(),
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
export const userCache = createCache(redisClient, {
|
|
49
|
+
name: "UserCache",
|
|
50
|
+
revision: 2,
|
|
51
|
+
ttlMs: 60 * 60 * 1000, // defaults to 1 hour
|
|
52
|
+
parse: (value) => UserSchema.parse(JSON.parse(value)),
|
|
53
|
+
serialize: (value) => JSON.stringify(value),
|
|
54
|
+
})
|
|
55
|
+
.withQueries({
|
|
56
|
+
findUser: defineQuery({
|
|
57
|
+
resolve: async (args: { id: string | null; email: string | null }) => {
|
|
58
|
+
return db.user.findUnique({
|
|
59
|
+
where: { id: args.id ?? undefined, email: args.email ?? undefined },
|
|
60
|
+
});
|
|
61
|
+
},
|
|
62
|
+
}),
|
|
63
|
+
findUsers: defineQuery({
|
|
64
|
+
resolve: async () => db.user.findMany(),
|
|
65
|
+
}),
|
|
66
|
+
})
|
|
67
|
+
.build();
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
`createCache(...)` returns a factory: call `.build()` for an item-only cache, or `.withQueries({...}).build()` to attach typed, cached queries. By default `getRef` extracts the `id` field; pass `getRef` for items keyed differently.
|
|
71
|
+
|
|
72
|
+
#### Reading through the cache
|
|
8
73
|
|
|
9
|
-
|
|
74
|
+
`$useCache(...)` as a resolver middleware is gone. A cached query is just an async function (`userCache.queries.findUser(args)`) that you call from a normal resolver. The resolver builder's `.map()` turns resolver params into query args:
|
|
10
75
|
|
|
11
|
-
|
|
76
|
+
```typescript
|
|
77
|
+
// v1
|
|
78
|
+
Query.user.$useCache(userCache);
|
|
12
79
|
|
|
13
|
-
|
|
80
|
+
// v2
|
|
81
|
+
export default Query.$fields({
|
|
82
|
+
user: Query.user.map(({ args }) =>
|
|
83
|
+
userCache.queries.findUser({
|
|
84
|
+
id: args.where.id,
|
|
85
|
+
email: args.where.email,
|
|
86
|
+
})
|
|
87
|
+
),
|
|
88
|
+
users: Query.users
|
|
89
|
+
.map(() => userCache.queries.findUsers({}))
|
|
90
|
+
.map(({ source }) => source ?? []),
|
|
91
|
+
});
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
#### Reconciling on mutations
|
|
95
|
+
|
|
96
|
+
The single `save()` method is replaced by explicit `insert()` (new items), `update()` (existing items) and `delete()`. These give the cache enough information to reconcile every related query automatically, instead of manually clearing query results:
|
|
97
|
+
|
|
98
|
+
```typescript
|
|
99
|
+
// v1
|
|
100
|
+
Mutation.updateUser.$use(async (params, next) => {
|
|
101
|
+
const user = await next();
|
|
102
|
+
await userCache.save(user);
|
|
103
|
+
return user;
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
// v2
|
|
107
|
+
const createUserMutation = Mutation.createUser.resolve(async ({ args }) => {
|
|
108
|
+
const user = await db.user.create({ data: args.data });
|
|
109
|
+
await userCache.insert(user); // new item
|
|
110
|
+
return user;
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
const updateUserMutation = Mutation.updateUser
|
|
114
|
+
.$use(async (next) => {
|
|
115
|
+
const user = await next();
|
|
116
|
+
if (user) {
|
|
117
|
+
await userCache.update(user); // existing item — updates all queries
|
|
118
|
+
}
|
|
119
|
+
return user;
|
|
120
|
+
})
|
|
121
|
+
.resolve(({ args }) =>
|
|
122
|
+
db.user.update({ where: { id: args.where.id }, data: args.data })
|
|
123
|
+
);
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
#### Targeted invalidation with `indexArgsBy`
|
|
127
|
+
|
|
128
|
+
Relationship queries ("all photos for user X") can declare `indexArgsBy` so invalidation is surgical. `defineQuery` also accepts per-query `onInsert` / `onUpdate` / `onDelete` hooks, which receive `helpers` (`invalidateAll`, `invalidateByArgs`) to invalidate only the matching index keys:
|
|
129
|
+
|
|
130
|
+
```typescript
|
|
131
|
+
// v2
|
|
132
|
+
export const userPhotoCache = createCache(redisClient, {
|
|
133
|
+
name: "UserPhotoCache",
|
|
134
|
+
parse: (value) => JSON.parse(value),
|
|
135
|
+
serialize: (value) => JSON.stringify(value),
|
|
136
|
+
})
|
|
137
|
+
.withQueries({
|
|
138
|
+
findUserPhotos: defineQuery({
|
|
139
|
+
resolve: async (args: { userId: string }) =>
|
|
140
|
+
db.userPhoto.findMany({ where: { userId: args.userId } }),
|
|
141
|
+
indexArgsBy: { userId: true },
|
|
142
|
+
onInsert(items, helpers) {
|
|
143
|
+
return helpers.invalidateByArgs(
|
|
144
|
+
items.map((item) => ({ userId: item.userId }))
|
|
145
|
+
);
|
|
146
|
+
},
|
|
147
|
+
onDelete(pairs, helpers) {
|
|
148
|
+
return helpers.invalidateByArgs(
|
|
149
|
+
pairs.flatMap((p) =>
|
|
150
|
+
p.previous ? [{ userId: p.previous.userId }] : []
|
|
151
|
+
)
|
|
152
|
+
);
|
|
153
|
+
},
|
|
154
|
+
}),
|
|
155
|
+
})
|
|
156
|
+
.build();
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
#### Other changes
|
|
160
|
+
|
|
161
|
+
- TTL is now milliseconds (`ttlMs`) everywhere, replacing v1's seconds-based `ttl`.
|
|
162
|
+
- A cache must have a `name`; `revision`, `ttlMs` and `namespace` can be set on the cache or defaulted from the client.
|
|
163
|
+
- By default, re-resolving a cached query does not overwrite items already in the cache (preventing a stale query result from clobbering a concurrent mutation). Set `replaceExistingItems: true` on a query to opt back into overwriting.
|
|
164
|
+
- Custom hooks fire asynchronously by default; pass `{ waitForHooks: true }` to `insert`/`update`/`delete` to await them.
|
|
165
|
+
|
|
166
|
+
See the [caching guide](https://baeta.io/docs/advanced/caching) for an end-to-end setup.
|
|
167
|
+
|
|
168
|
+
- Drop support for Node.js v23 and v25. Baeta now targets the active LTS releases — Node.js `^22.20.0`, `^24.0.0`, or `>=26.0.0`. by [@andreisergiu98](https://github.com/andreisergiu98) in [#290](https://github.com/andreisergiu98/baeta/pull/290)
|
|
169
|
+
|
|
170
|
+
### Patch Changes
|
|
14
171
|
|
|
15
|
-
- [
|
|
172
|
+
- Updated dependencies [[`046dc5c`](https://github.com/andreisergiu98/baeta/commit/046dc5c29a8ec0f613b9430caa659c08d41a678c), [`046dc5c`](https://github.com/andreisergiu98/baeta/commit/046dc5c29a8ec0f613b9430caa659c08d41a678c), [`046dc5c`](https://github.com/andreisergiu98/baeta/commit/046dc5c29a8ec0f613b9430caa659c08d41a678c)]:
|
|
173
|
+
- @baeta/util-encoding@2.0.0-next.5
|
|
174
|
+
- @baeta/util-log@2.0.0-next.5
|
package/README.md
CHANGED
|
@@ -5,9 +5,10 @@
|
|
|
5
5
|
<div align="center">
|
|
6
6
|
<h1>Baeta</h1>
|
|
7
7
|
<a href="https://www.npmjs.com/package/@baeta/cli"><img src="https://img.shields.io/npm/v/@baeta/cli.svg?style=flat" /></a>
|
|
8
|
-
<a href="https://github.com/andreisergiu98/baeta/actions/workflows/
|
|
8
|
+
<a href="https://github.com/andreisergiu98/baeta/actions/workflows/build.yml"><img src="https://img.shields.io/github/actions/workflow/status/andreisergiu98/baeta/build.yml" /></a>
|
|
9
9
|
<a href="https://github.com/andreisergiu98/baeta/pulls"><img src="https://img.shields.io/badge/PRs-welcome-brightgreen.svg" /></a>
|
|
10
10
|
<a href="https://github.com/andreisergiu98/baeta/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-MIT-blue" /></a>
|
|
11
|
+
<img alt="nycrc config on GitHub" src="https://img.shields.io/nycrc/andreisergiu98/baeta?config=.nycrc.json&preferredThreshold=branches&color=green">
|
|
11
12
|
<br />
|
|
12
13
|
<br />
|
|
13
14
|
<a href="https://baeta.io/docs/getting-started/installation">Getting Started</a>
|
|
@@ -35,10 +36,11 @@ Building GraphQL APIs shouldn't be complicated. **Baeta** is a modern, modular,
|
|
|
35
36
|
- **Middleware & Directives**: Easy integration of custom behaviors
|
|
36
37
|
- **High Performance**: Built for scalability and efficiency
|
|
37
38
|
|
|
38
|
-
#### And optional
|
|
39
|
+
#### And optional app plugins and libraries
|
|
39
40
|
|
|
40
|
-
- **@baeta/
|
|
41
|
-
- **@baeta/
|
|
41
|
+
- **@baeta/auth**: Add powerful scope-based authorization
|
|
42
|
+
- **@baeta/complexity**: Reject resource-exhausting queries with depth, breadth and complexity limits
|
|
43
|
+
- **@baeta/cache**: Type-safe caching with declarative queries and automatic reconciliation
|
|
42
44
|
- ... and more!
|
|
43
45
|
|
|
44
46
|
## Why use Baeta?
|
|
@@ -89,7 +91,7 @@ const usersQuery = Query.users.resolve(() => {
|
|
|
89
91
|
return dataSource.user.findMany();
|
|
90
92
|
});
|
|
91
93
|
|
|
92
|
-
Query.$fields({
|
|
94
|
+
export default Query.$fields({
|
|
93
95
|
user: userQuery,
|
|
94
96
|
users: usersQuery,
|
|
95
97
|
});
|
|
@@ -98,17 +100,13 @@ Query.$fields({
|
|
|
98
100
|
#### 3. Add authorization
|
|
99
101
|
|
|
100
102
|
```typescript
|
|
103
|
+
import { auth, rule, scope } from "./lib/auth.ts";
|
|
101
104
|
import { UserModule } from "./typedef.ts";
|
|
102
105
|
|
|
103
106
|
const { Query } = UserModule;
|
|
104
107
|
|
|
105
108
|
const userQuery = Query.user
|
|
106
|
-
.$auth(
|
|
107
|
-
$or: {
|
|
108
|
-
isPublic: true,
|
|
109
|
-
isLoggedIn: true,
|
|
110
|
-
},
|
|
111
|
-
})
|
|
109
|
+
.$use(auth(rule.or(scope.isPublic, scope.isLoggedIn)))
|
|
112
110
|
.resolve(async ({ args }) => {
|
|
113
111
|
// ...
|
|
114
112
|
});
|
|
@@ -117,23 +115,33 @@ const userQuery = Query.user
|
|
|
117
115
|
#### 4. Add caching
|
|
118
116
|
|
|
119
117
|
```typescript
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
118
|
+
import { createCache, defineQuery } from "@baeta/cache";
|
|
119
|
+
import { redisClient } from "./lib/redis.ts";
|
|
120
|
+
|
|
121
|
+
const { Query, Mutation } = UserModule;
|
|
122
|
+
|
|
123
|
+
export const userCache = createCache(redisClient, {
|
|
124
|
+
name: "UserCache",
|
|
125
|
+
parse: JSON.parse,
|
|
126
|
+
serialize: JSON.stringify,
|
|
127
|
+
})
|
|
128
|
+
.withQueries({
|
|
129
|
+
findUser: defineQuery({
|
|
130
|
+
resolve: async (args: { id: string }) => {
|
|
131
|
+
return dataSource.user.findUnique({ where: args });
|
|
132
|
+
},
|
|
133
|
+
}),
|
|
127
134
|
})
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
})
|
|
135
|
+
.build();
|
|
136
|
+
|
|
137
|
+
const userQuery = Query.user.map(({ args }) =>
|
|
138
|
+
userCache.queries.findUser({ id: args.where.id }),
|
|
139
|
+
);
|
|
132
140
|
|
|
133
141
|
const updateUserMutation = Mutation.updateUser
|
|
134
142
|
.$use(async (next) => {
|
|
135
143
|
const user = await next();
|
|
136
|
-
await userCache.
|
|
144
|
+
if (user) await userCache.update(user);
|
|
137
145
|
return user;
|
|
138
146
|
})
|
|
139
147
|
.resolve(async ({ args }) => {
|
package/dist/index.d.ts
CHANGED
|
@@ -179,7 +179,7 @@ declare class CacheStore<Item> {
|
|
|
179
179
|
getQuery(query: QueryTagWithArgs): Promise<{
|
|
180
180
|
query: unknown;
|
|
181
181
|
} | null>;
|
|
182
|
-
saveQuery(query: QueryTagWithData<Item>, replaceExistingItems?: boolean): Promise<void>;
|
|
182
|
+
saveQuery(query: QueryTagWithData<Item>, replaceExistingItems?: boolean, ttlMs?: number): Promise<void>;
|
|
183
183
|
deleteQueries(query: QueryTagWithIndexes): Promise<void>;
|
|
184
184
|
getRefWithFallback(root: Item): ItemRef;
|
|
185
185
|
getItemKey(item: Item): ItemCacheKey;
|
|
@@ -286,5 +286,5 @@ type CreateCacheFactory<Item> = {
|
|
|
286
286
|
declare function createCache<Item extends RefCompatibleItem>(client: CacheClient, options: CacheOptions<Item> & OptionalGetRef<Item>): CreateCacheFactory<Item>;
|
|
287
287
|
declare function createCache<Item>(client: CacheClient, options: CacheOptions<Item> & RequiredGetRef<Item>): CreateCacheFactory<Item>;
|
|
288
288
|
//#endregion
|
|
289
|
-
export { type Cache, CacheClient, type CacheClientArgs, type CacheClientOptions, type CacheClientSaveOptions, type CacheHooksOptions, type CacheOptions, type CacheWithQueries, type CreateCacheFactory, type ItemCacheKey, type ItemRef, type OptionalGetRef, type QueryArgs, type QueryArgsIndexes, type QueryCacheIndexKey, type QueryCacheKey, type QueryIndexValue, type QueryOptions, type RequiredGetRef, createCache, defineQuery };
|
|
289
|
+
export { type Cache, CacheClient, type CacheClientArgs, type CacheClientOptions, type CacheClientSaveOptions, type CacheHooksOptions, type CacheOptions, type CacheWithQueries, type CreateCacheFactory, type ItemCacheKey, type ItemRef, type OptionalGetRef, type QueryArgs, type QueryArgsIndexes, type QueryCacheIndexKey, type QueryCacheKey, type QueryIndexValue, type QueryOptions, type RefCompatibleItem, type RequiredGetRef, createCache, defineQuery };
|
|
290
290
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.js
CHANGED
|
@@ -84,7 +84,7 @@ var CacheStore = class {
|
|
|
84
84
|
};
|
|
85
85
|
this.queryCacheArgs = {
|
|
86
86
|
ttlMs: ttlMs ?? 36e5,
|
|
87
|
-
parse: (value) =>
|
|
87
|
+
parse: (value) => parseQueryMetadataSafely(value),
|
|
88
88
|
serialize: (meta) => JSON.stringify(meta)
|
|
89
89
|
};
|
|
90
90
|
}
|
|
@@ -136,7 +136,7 @@ var CacheStore = class {
|
|
|
136
136
|
const aligned = alignItemsWithRefs(nullableRefs, items);
|
|
137
137
|
return { query: isList ? aligned : aligned.at(0) ?? null };
|
|
138
138
|
}
|
|
139
|
-
async saveQuery(query, replaceExistingItems = false) {
|
|
139
|
+
async saveQuery(query, replaceExistingItems = false, ttlMs) {
|
|
140
140
|
const data = query.data;
|
|
141
141
|
const queryKey = this.getQueryKey(query);
|
|
142
142
|
const queryIndexes = this.getQueryIndexes(query, true);
|
|
@@ -152,7 +152,10 @@ var CacheStore = class {
|
|
|
152
152
|
}),
|
|
153
153
|
isList
|
|
154
154
|
};
|
|
155
|
-
return await this.client.saveQuery(queryKey, queryIndexes, metadata,
|
|
155
|
+
return await this.client.saveQuery(queryKey, queryIndexes, metadata, {
|
|
156
|
+
...this.queryCacheArgs,
|
|
157
|
+
ttlMs: ttlMs ?? this.queryCacheArgs.ttlMs
|
|
158
|
+
});
|
|
156
159
|
}
|
|
157
160
|
deleteQueries(query) {
|
|
158
161
|
const queryIndexes = this.getQueryIndexes(query);
|
|
@@ -194,10 +197,31 @@ function parseItemSafely(value, parseItem) {
|
|
|
194
197
|
try {
|
|
195
198
|
return parseItem(value);
|
|
196
199
|
} catch (err) {
|
|
197
|
-
log.warn(err, "Failed to parse item, returning null"
|
|
200
|
+
log.warn(err, "Failed to parse item, returning null");
|
|
198
201
|
return null;
|
|
199
202
|
}
|
|
200
203
|
}
|
|
204
|
+
function parseQueryMetadataSafely(value) {
|
|
205
|
+
let parsed;
|
|
206
|
+
try {
|
|
207
|
+
parsed = JSON.parse(value);
|
|
208
|
+
} catch (err) {
|
|
209
|
+
log.warn(err, "Failed to parse query metadata, treating as cache miss");
|
|
210
|
+
return null;
|
|
211
|
+
}
|
|
212
|
+
if (!isValidQueryMetadata(parsed)) {
|
|
213
|
+
log.warn("Query metadata has invalid shape, treating as cache miss");
|
|
214
|
+
return null;
|
|
215
|
+
}
|
|
216
|
+
return parsed;
|
|
217
|
+
}
|
|
218
|
+
function isValidQueryMetadata(value) {
|
|
219
|
+
if (value == null || typeof value !== "object") return false;
|
|
220
|
+
const candidate = value;
|
|
221
|
+
if (!Array.isArray(candidate.refs)) return false;
|
|
222
|
+
if (typeof candidate.isList !== "boolean") return false;
|
|
223
|
+
return candidate.refs.every((ref) => ref === null || typeof ref === "string");
|
|
224
|
+
}
|
|
201
225
|
//#endregion
|
|
202
226
|
//#region lib/create-cache.ts
|
|
203
227
|
function createCache(client, options) {
|
|
@@ -346,7 +370,7 @@ function defineQuery(options) {
|
|
|
346
370
|
args,
|
|
347
371
|
data,
|
|
348
372
|
indexes: buildIndexes(args, options.indexArgsBy)
|
|
349
|
-
}, options.replaceExistingItems).catch((err) => {
|
|
373
|
+
}, options.replaceExistingItems, options.ttlMs).catch((err) => {
|
|
350
374
|
log.error(err, `Failed to save query result for ${name}. Proceeding without caching.`);
|
|
351
375
|
});
|
|
352
376
|
return data;
|
|
@@ -396,8 +420,7 @@ function buildIndexes(args, indexArgsBy) {
|
|
|
396
420
|
if (!Object.hasOwn(args, key)) continue;
|
|
397
421
|
const value = args[key];
|
|
398
422
|
if (value === void 0) continue;
|
|
399
|
-
if (Array.isArray(value))
|
|
400
|
-
if (typeof value === "object" && value !== null) continue;
|
|
423
|
+
if (typeof value !== "string" && typeof value !== "number" && typeof value !== "boolean" && value !== null) throw new TypeError(`Cache index '${key}' must be a primitive (string, number, boolean, or null) but received ${Array.isArray(value) ? "array" : typeof value}.`);
|
|
401
424
|
indexes.push([key, value]);
|
|
402
425
|
}
|
|
403
426
|
return indexes;
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../lib/client.ts","../lib/item.ts","../lib/key.ts","../lib/options.ts","../lib/utils.ts","../lib/store.ts","../lib/create-cache.ts","../lib/define-query.ts"],"sourcesContent":["import type { ItemCacheKey, QueryCacheIndexKey, QueryCacheKey } from './key.ts';\n\nexport interface CacheClientArgs<Item> {\n\tttlMs: number;\n\tparse: (value: string) => Item | null;\n\tserialize: (item: Item) => string;\n}\n\nexport interface CacheClientOptions {\n\t/**\n\t * Revision number for cache invalidation.\n\t * Incrementing this number will invalidate all existing cache entries for this store.\n\t * @defaultValue \"default\"\n\t */\n\trevision?: number;\n\t/**\n\t * Time-to-live in milliseconds\n\t * @defaultValue 3_600_000 (1 hour)\n\t */\n\tttlMs?: number;\n\t/**\n\t * Optional namespace to prefix all cache keys\n\t * @defaultValue \"baeta\"\n\t */\n\tnamespace?: string;\n}\n\nexport interface CacheClientSaveOptions {\n\t/**\n\t * If true, the save operation will not overwrite existing cache entries. Instead, it will only save entries that do not already exist in the cache.\n\t * @defaultValue false\n\t */\n\tdisableOverwrite?: boolean;\n}\n\nexport abstract class CacheClient {\n\toptions?: CacheClientOptions;\n\n\tconstructor(options?: CacheClientOptions) {\n\t\tthis.options = options;\n\t}\n\n\tabstract getPartialItems<Item>(\n\t\tkeys: ItemCacheKey[],\n\t\toptions: CacheClientArgs<Item>,\n\t): Promise<Array<Item | null>>;\n\n\tabstract saveItems<Item>(\n\t\titems: Array<[ItemCacheKey, Item]>,\n\t\toptions: CacheClientArgs<Item>,\n\t\tsaveOptions?: CacheClientSaveOptions,\n\t): Promise<void>;\n\n\tabstract saveItemsWithDiff<Item>(\n\t\titems: Array<[ItemCacheKey, Item]>,\n\t\toptions: CacheClientArgs<Item>,\n\t): Promise<Array<Item | null>>;\n\n\tabstract deleteItems<Item>(keys: ItemCacheKey[], options: CacheClientArgs<Item>): Promise<void>;\n\n\tabstract deleteItemsWithDiff<Item>(\n\t\tkeys: ItemCacheKey[],\n\t\toptions: CacheClientArgs<Item>,\n\t): Promise<Array<Item | null>>;\n\n\tabstract getQuery<QueryMetadata>(\n\t\tkey: QueryCacheKey,\n\t\toptions: CacheClientArgs<QueryMetadata>,\n\t): Promise<QueryMetadata | null>;\n\n\tabstract saveQuery<QueryMetadata>(\n\t\tkey: QueryCacheKey,\n\t\tindexes: QueryCacheIndexKey[],\n\t\tmetadata: QueryMetadata,\n\t\toptions: CacheClientArgs<QueryMetadata>,\n\t): Promise<void>;\n\n\tabstract deleteQueries<QueryMetadata>(\n\t\tindexes: QueryCacheIndexKey[],\n\t\toptions: CacheClientArgs<QueryMetadata>,\n\t): Promise<void>;\n}\n","/**\n * Reference type for cached items\n */\nexport type ItemRef = string | number | bigint;\n\n/**\n * Type constraint for objects that are compatible with default cache ref\n */\nexport type RefCompatibleItem = { id: string | number | bigint };\n\n/**\n * Asserts that a given reference is of a valid type (string, number, or bigint) and that it can be safely serialized.\n */\nexport function assertValidRefType(ref: unknown): asserts ref is string | number | bigint {\n\tif (typeof ref !== 'string' && typeof ref !== 'number' && typeof ref !== 'bigint') {\n\t\tthrow new TypeError(\n\t\t\t'Reference must be string, number or bigint. Define getRef function in cache options',\n\t\t);\n\t}\n}\n","import { encodeBase64 } from '@baeta/util-encoding';\nimport { hash } from 'ohash';\nimport type { QueryArgs, QueryIndex } from './query.ts';\n\nexport type QueryCacheKey = `${QueryCacheKeyPrefix}:${QueryCacheKeyId}`;\nexport type QueryCacheIndexKey = `${QueryCacheKeyPrefix}:${QueryCacheIndexKeyId}`;\nexport type QueryCacheKeyId = `id:${string}`;\nexport type QueryCacheIndexKeyId = `idx:${string}`;\nexport type QueryCacheKeyPrefix = `${string}:${string}:query:${string}:${CacheRevisionId}`; // $namespace:$storeName:query:$queryName:rev_$value\n\nexport type ItemCacheKey = `${ItemCacheKeyPrefix}:${ItemCacheKeyId}`;\nexport type ItemCacheKeyId = `id:${string}`;\nexport type ItemCacheKeyPrefix = `${string}:${string}:item:${CacheRevisionId}`; // $namespace:$storeName:item:rev_$value\n\nexport type CacheRevisionId = `rev_${string}`;\n\nexport function buildCacheRevisionId(revision: string): CacheRevisionId {\n\treturn `rev_${revision}`;\n}\n\nexport function buildItemCacheKeyId(id: string): ItemCacheKeyId {\n\treturn `id:${id}`;\n}\n\nexport function buildQueryCacheKeyId(args: QueryArgs): QueryCacheKeyId {\n\treturn `id:${hash(args)}`;\n}\n\nexport function buildQueryCacheIndexKeyId(index?: QueryIndex | undefined): QueryCacheIndexKeyId {\n\tif (index == null) {\n\t\treturn 'idx:';\n\t}\n\tconst key = index[0];\n\tconst value = index[1];\n\tconst safeValue = value === null ? 'null' : `_${encodeBase64(value.toString())}`;\n\treturn `idx:${hash(`${key}=${safeValue}`)}`;\n}\n\nexport function buildQueryCacheIndexKeysIds(indexes: QueryIndex[]): QueryCacheIndexKeyId[] {\n\tif (indexes.length === 0) {\n\t\treturn ['idx:'];\n\t}\n\treturn indexes.map((idx) => buildQueryCacheIndexKeyId(idx));\n}\n","import type { ItemRef } from './item.ts';\n\nexport const DEFAULT_REVISION = 'default';\nexport const DEFAULT_NAMESPACE = 'baeta';\nexport const DEFAULT_TTL_MS = 3_600_000; // 1 hour\n\n/**\n * Configuration options for cache stores\n */\nexport type CacheOptions<Item> = {\n\t/**\n\t * Unique name for the cache store. Used as a prefix for cache keys to avoid collisions.\n\t */\n\tname: string;\n\t/**\n\t * Revision number for cache invalidation.\n\t * Incrementing this number will invalidate all existing cache entries for this store.\n\t * @defaultValue CacheClient options or \"default\"\n\t */\n\trevision?: number;\n\t/**\n\t * Time-to-live in milliseconds\n\t * @defaultValue CacheClient options or 3_600_000 (1 hour)\n\t */\n\tttlMs?: number;\n\t/**\n\t * Optional namespace to prefix all cache keys\n\t * @defaultValue CacheClient options or \"baeta\"\n\t */\n\tnamespace?: string;\n\t/**\n\t * Function to parse stored strings back into source objects.\n\t * If it throws an error, the cache will be treated as a miss and the value will be deleted.\n\t */\n\tparse: (value: string) => Item;\n\t/**\n\t * Function to serialize source objects into strings for cache storage.\n\t */\n\tserialize: (value: Item) => string;\n\t/**\n\t * Hook that gets called with the updated items after an update operation.\n\t */\n\tonUpdate?: (item: Item[]) => void | Promise<void>;\n\t/**\n\t * Hook that gets called with the inserted items after an insert operation.\n\t */\n\tonInsert?: (item: Item[]) => void | Promise<void>;\n\t/**\n\t * Hook that gets called with the refs of deleted items after a delete operation.\n\t */\n\tonDelete?: (ref: ItemRef[]) => void | Promise<void>;\n};\n\nexport type OptionalGetRef<Item> = {\n\t/*\n\t * Optional function to extract a string reference from source objects.\n\t * Will use \"id\" property by default.\n\t */\n\tgetRef?: (source: Item) => ItemRef;\n};\n\nexport type RequiredGetRef<Item> = {\n\t/*\n\t * Function to extract a string reference from source objects.\n\t */\n\tgetRef: (source: Item) => ItemRef;\n};\n","import type { ItemRef } from './item.ts';\n\nexport function arrayIsComplete<T>(items: Array<T | null> | null): items is T[] {\n\tif (items == null) {\n\t\treturn false;\n\t}\n\treturn items.every((item) => item != null);\n}\n\nexport function alignItemsWithRefs<T>(partialRefs: Array<ItemRef | null>, items: T[]) {\n\tif (partialRefs.length === items.length) {\n\t\treturn items;\n\t}\n\tlet itemIndex = 0;\n\tconst aligned: Array<T | null> = [];\n\tfor (const ref of partialRefs) {\n\t\tif (ref == null) {\n\t\t\taligned.push(null);\n\t\t} else {\n\t\t\taligned.push(items[itemIndex++]);\n\t\t}\n\t}\n\treturn aligned;\n}\n\nexport function fillNullItemsWithFallback<T>(items: Array<T | null>, fallbacks: T[]) {\n\tlet fallbackIndex = 0;\n\tconst completeItems: T[] = [];\n\tfor (const item of items) {\n\t\tif (item != null) {\n\t\t\tcompleteItems.push(item);\n\t\t} else if (fallbackIndex < fallbacks.length) {\n\t\t\tcompleteItems.push(fallbacks[fallbackIndex++]);\n\t\t}\n\t}\n\treturn {\n\t\titems: completeItems,\n\t\tmissing: items.length - completeItems.length,\n\t\textra: fallbacks.length - fallbackIndex,\n\t};\n}\n\nexport function toArray<T>(item: T | T[]): T[] {\n\treturn Array.isArray(item) ? item : [item];\n}\n\nexport function zip<T, U, R>(array1: T[], array2: U[], fn: (a: T, b: U) => R): R[] {\n\tif (array1.length !== array2.length) {\n\t\tthrow new Error('Arrays must have the same length to be zipped');\n\t}\n\tconst result: R[] = [];\n\tfor (let i = 0; i < array1.length; i++) {\n\t\tresult.push(fn(array1[i], array2[i]));\n\t}\n\treturn result;\n}\n","import { log } from '@baeta/util-log';\nimport DataLoader from 'dataloader';\nimport type { CacheClient, CacheClientArgs } from './client.ts';\nimport { assertValidRefType, type ItemRef } from './item.ts';\nimport {\n\tbuildCacheRevisionId,\n\tbuildItemCacheKeyId,\n\tbuildQueryCacheIndexKeyId,\n\tbuildQueryCacheIndexKeysIds,\n\tbuildQueryCacheKeyId,\n\ttype CacheRevisionId,\n\ttype ItemCacheKey,\n\ttype ItemCacheKeyPrefix,\n\ttype QueryCacheIndexKey,\n\ttype QueryCacheKey,\n\ttype QueryCacheKeyPrefix,\n} from './key.ts';\nimport { DEFAULT_NAMESPACE, DEFAULT_REVISION, DEFAULT_TTL_MS } from './options.ts';\nimport type { QueryTag, QueryTagWithArgs, QueryTagWithData, QueryTagWithIndexes } from './query.ts';\nimport { alignItemsWithRefs, arrayIsComplete, toArray } from './utils.ts';\n\nexport interface CacheStoreOptions<Item> {\n\tname: string;\n\tclient: CacheClient;\n\tnamespace?: string;\n\trevision?: string | number;\n\tttlMs?: number;\n\tparse: (value: string) => Item;\n\tserialize: (item: Item) => string;\n\tgetRef?: (source: Item) => ItemRef;\n}\n\ntype QueryMetadata = { refs: Array<null | string>; isList: boolean };\n\nexport class CacheStore<Item> {\n\tprotected readonly name: string;\n\tprotected readonly namespace: string;\n\tprotected readonly revision: string;\n\n\tprotected readonly client: CacheClient;\n\tprotected readonly itemCacheArgs: CacheClientArgs<Item>;\n\tprotected readonly queryCacheArgs: CacheClientArgs<QueryMetadata>;\n\n\tprotected readonly getRef?: (source: Item) => ItemRef;\n\n\tconstructor({\n\t\tname,\n\t\tclient,\n\t\tnamespace,\n\t\trevision,\n\t\tttlMs,\n\t\tparse,\n\t\tserialize,\n\t\tgetRef,\n\t}: CacheStoreOptions<Item>) {\n\t\tthis.name = name;\n\t\tthis.namespace = namespace ?? DEFAULT_NAMESPACE;\n\t\tthis.revision = revision?.toString() ?? DEFAULT_REVISION;\n\t\tthis.client = client;\n\t\tthis.getRef = getRef;\n\t\tthis.itemCacheArgs = {\n\t\t\tttlMs: ttlMs ?? DEFAULT_TTL_MS,\n\t\t\tparse: (value: string) => parseItemSafely(value, parse),\n\t\t\tserialize: (item: Item) => serialize(item),\n\t\t};\n\t\tthis.queryCacheArgs = {\n\t\t\tttlMs: ttlMs ?? DEFAULT_TTL_MS,\n\t\t\tparse: (value: string) => JSON.parse(value) as QueryMetadata,\n\t\t\tserialize: (meta: QueryMetadata) => JSON.stringify(meta),\n\t\t};\n\t}\n\n\tprotected loadAndParse = async (refs: ReadonlyArray<ItemRef>): Promise<Array<Item | null>> => {\n\t\tconst keys = refs.map((ref) => this.getItemKeyByRef(ref));\n\t\treturn await this.client.getPartialItems(keys, this.itemCacheArgs);\n\t};\n\n\tprotected loader = new DataLoader<ItemRef, Item | null>(this.loadAndParse, {\n\t\tcache: false,\n\t});\n\n\tasync get(ref: ItemRef): Promise<Item | null> {\n\t\treturn await this.loader.load(ref);\n\t}\n\n\tasync getMany(refs: ItemRef[]): Promise<Item[] | null> {\n\t\tconst results = await Promise.all(refs.map((r) => this.get(r)));\n\t\tif (!arrayIsComplete(results)) {\n\t\t\treturn null;\n\t\t}\n\t\treturn results;\n\t}\n\n\tasync getPartial(refs: ItemRef[]): Promise<Array<Item | null>> {\n\t\treturn await Promise.all(refs.map((ref) => this.get(ref)));\n\t}\n\n\tasync save(item: Item | Item[]) {\n\t\tconst values = toArray(item);\n\t\tconst entries: Array<[ItemCacheKey, Item]> = values.map((item) => [\n\t\t\tthis.getItemKey(item),\n\t\t\titem,\n\t\t]);\n\t\treturn await this.client.saveItems(entries, this.itemCacheArgs);\n\t}\n\n\tasync saveIfNotExists(item: Item | Item[]) {\n\t\tconst values = toArray(item);\n\t\tconst entries: Array<[ItemCacheKey, Item]> = values.map((item) => [\n\t\t\tthis.getItemKey(item),\n\t\t\titem,\n\t\t]);\n\t\treturn await this.client.saveItems(entries, this.itemCacheArgs, {\n\t\t\tdisableOverwrite: true,\n\t\t});\n\t}\n\n\tasync saveWithDiff(item: Item | Item[]): Promise<Array<Item | null>> {\n\t\tconst values = toArray(item);\n\t\tconst entries: Array<[ItemCacheKey, Item]> = values.map((item) => [\n\t\t\tthis.getItemKey(item),\n\t\t\titem,\n\t\t]);\n\t\treturn await this.client.saveItemsWithDiff(entries, this.itemCacheArgs);\n\t}\n\n\tasync delete(ref: ItemRef | ItemRef[]) {\n\t\tconst refs = toArray(ref);\n\t\tconst keys = refs.map((r) => this.getItemKeyByRef(r));\n\t\tawait this.client.deleteItems(keys, this.itemCacheArgs);\n\t}\n\n\tasync deleteWithDiff(ref: ItemRef | ItemRef[]): Promise<Array<Item | null>> {\n\t\tconst refs = toArray(ref);\n\t\tconst keys = refs.map((r) => this.getItemKeyByRef(r));\n\t\treturn await this.client.deleteItemsWithDiff(keys, this.itemCacheArgs);\n\t}\n\n\tasync getQuery(query: QueryTagWithArgs): Promise<{ query: unknown } | null> {\n\t\tconst queryKey = this.getQueryKey(query);\n\t\tconst meta = await this.client.getQuery(queryKey, this.queryCacheArgs);\n\n\t\tif (meta == null) {\n\t\t\treturn null;\n\t\t}\n\n\t\tconst isList = meta.isList;\n\t\tconst nullableRefs = meta.refs;\n\t\tconst refs = nullableRefs.filter((ref) => ref != null);\n\t\tconst items = await this.getMany(refs);\n\n\t\tif (items == null) {\n\t\t\treturn null;\n\t\t}\n\n\t\tconst aligned = alignItemsWithRefs(nullableRefs, items);\n\t\tconst result = isList ? aligned : (aligned.at(0) ?? null);\n\n\t\treturn { query: result };\n\t}\n\n\tasync saveQuery(query: QueryTagWithData<Item>, replaceExistingItems = false): Promise<void> {\n\t\tconst data = query.data;\n\t\tconst queryKey = this.getQueryKey(query);\n\t\tconst queryIndexes = this.getQueryIndexes(query, true);\n\n\t\tconst isList = Array.isArray(data);\n\t\tconst nullableItems = isList ? data : [data];\n\t\tconst items = nullableItems.filter((item) => item != null);\n\n\t\tif (items.length > 0) {\n\t\t\tif (replaceExistingItems) {\n\t\t\t\tawait this.save(items);\n\t\t\t} else {\n\t\t\t\tawait this.saveIfNotExists(items);\n\t\t\t}\n\t\t}\n\n\t\tconst encodedRefs = nullableItems.map((item) => {\n\t\t\tif (item == null) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\treturn this.getRefWithFallback(item).toString();\n\t\t});\n\n\t\tconst metadata = {\n\t\t\trefs: encodedRefs,\n\t\t\tisList,\n\t\t};\n\n\t\treturn await this.client.saveQuery(queryKey, queryIndexes, metadata, this.queryCacheArgs);\n\t}\n\n\tdeleteQueries(query: QueryTagWithIndexes): Promise<void> {\n\t\tconst queryIndexes = this.getQueryIndexes(query);\n\t\treturn this.client.deleteQueries(queryIndexes, this.queryCacheArgs);\n\t}\n\n\tgetRefWithFallback(root: Item): ItemRef {\n\t\tif (this.getRef) {\n\t\t\treturn this.getRef(root);\n\t\t}\n\t\tif (root == null) {\n\t\t\tthrow new Error('Object is null or undefined, cannot get ref');\n\t\t}\n\t\tif (typeof root === 'object' && 'id' in root) {\n\t\t\tassertValidRefType(root.id);\n\t\t\treturn root.id.toString();\n\t\t}\n\t\tthrow new Error('Object does not have id. Define \"getRef\" function in cache options');\n\t}\n\n\tgetItemKey(item: Item): ItemCacheKey {\n\t\tconst ref = this.getRefWithFallback(item);\n\t\treturn this.getItemKeyByRef(ref);\n\t}\n\n\tgetItemKeyByRef(ref: ItemRef): ItemCacheKey {\n\t\tconst prefix: ItemCacheKeyPrefix = `${this.namespace}:{${this.name}:item:${buildCacheRevisionId(this.revision)}}`;\n\t\tconst keyId = buildItemCacheKeyId(ref.toString());\n\t\treturn `${prefix}:${keyId}`;\n\t}\n\n\tgetQueryKey(query: QueryTagWithArgs): QueryCacheKey {\n\t\tconst prefix = this.getQueryKeyPrefix(query);\n\t\treturn `${prefix}:${buildQueryCacheKeyId(query.args)}`;\n\t}\n\n\tgetQueryIndexes(query: QueryTagWithIndexes, ensureCatchAll = false): QueryCacheIndexKey[] {\n\t\tconst prefix = this.getQueryKeyPrefix(query);\n\t\tconst keyIndexes = buildQueryCacheIndexKeysIds(query.indexes);\n\t\tif (ensureCatchAll && query.indexes.length > 0) {\n\t\t\tkeyIndexes.push(buildQueryCacheIndexKeyId());\n\t\t}\n\t\treturn keyIndexes.map((keyIndex) => `${prefix}:${keyIndex}` as const);\n\t}\n\n\tgetQueryKeyPrefix(query: QueryTag): QueryCacheKeyPrefix {\n\t\treturn `${this.namespace}:{${this.name}:query:${query.name}:${this.getQueryKeyRevision(query)}}`;\n\t}\n\n\tgetQueryKeyRevision(query: QueryTag): CacheRevisionId {\n\t\tconst combinedRevision = `${this.revision}_${query.revision?.toString() ?? DEFAULT_REVISION}`;\n\t\treturn buildCacheRevisionId(combinedRevision);\n\t}\n}\n\nfunction parseItemSafely<T>(value: string, parseItem: (value: string) => T): T | null {\n\ttry {\n\t\treturn parseItem(value);\n\t} catch (err) {\n\t\tlog.warn(err, 'Failed to parse item, returning null', {\n\t\t\tvalue,\n\t\t});\n\t\treturn null;\n\t}\n}\n","import { log } from '@baeta/util-log';\nimport type { CacheClient } from './client.ts';\nimport type { QueryDefinitionMap, QueryMethod, QueryMethodMap } from './define-query.ts';\nimport type { ItemRef, RefCompatibleItem } from './item.ts';\nimport type { CacheOptions, OptionalGetRef, RequiredGetRef } from './options.ts';\nimport type { QueryOnDeleteHook, QueryOnInsertHook, QueryOnUpdateHook, QueryTag } from './query.ts';\nimport { CacheStore } from './store.ts';\nimport { toArray, zip } from './utils.ts';\n\nexport type CacheHooksOptions = {\n\t/**\n\t * If true, hooks will be awaited. If false, hooks will be fired asynchronously and will not block cache methods.\n\t * @defaultValue false\n\t */\n\twaitForHooks?: boolean;\n};\n\nexport type Cache<Item> = {\n\tget(ref: ItemRef): Promise<Item | null>;\n\tgetMany(refs: ItemRef[]): Promise<Item[] | null>;\n\tgetPartial(refs: ItemRef[]): Promise<Array<Item | null>>;\n\tupdate(item: Item | Item[]): Promise<void>;\n\tinsert(item: Item | Item[]): Promise<void>;\n\tdelete(ref: ItemRef | ItemRef[]): Promise<void>;\n};\n\nexport type CacheWithQueries<Item, QueryDefinitions extends QueryDefinitionMap<Item>> = {\n\tget(ref: ItemRef): Promise<Item | null>;\n\tgetMany(refs: ItemRef[]): Promise<Item[] | null>;\n\tgetPartial(refs: ItemRef[]): Promise<Array<Item | null>>;\n\tupdate(item: Item | Item[], options?: CacheHooksOptions): Promise<void>;\n\tinsert(item: Item | Item[], options?: CacheHooksOptions): Promise<void>;\n\tdelete(ref: ItemRef | ItemRef[], options?: CacheHooksOptions): Promise<void>;\n\tdeleteQueries(): Promise<void>;\n\tqueries: QueryMethodMap<QueryDefinitions>;\n};\n\nexport type CreateCacheFactory<Item> = {\n\tbuild: () => Cache<Item>;\n\twithQueries: <QueryDefinitions extends QueryDefinitionMap<Item>>(\n\t\tdefinitions: QueryDefinitions,\n\t) => {\n\t\tbuild: () => CacheWithQueries<Item, QueryDefinitions>;\n\t};\n};\n\nexport function createCache<Item extends RefCompatibleItem>(\n\tclient: CacheClient,\n\toptions: CacheOptions<Item> & OptionalGetRef<Item>,\n): CreateCacheFactory<Item>;\nexport function createCache<Item>(\n\tclient: CacheClient,\n\toptions: CacheOptions<Item> & RequiredGetRef<Item>,\n): CreateCacheFactory<Item>;\nexport function createCache<Item>(\n\tclient: CacheClient,\n\toptions: CacheOptions<Item> & OptionalGetRef<Item>,\n): CreateCacheFactory<Item> {\n\tconst storeClient = new CacheStore<Item>({\n\t\tclient,\n\t\tname: options.name,\n\t\tparse: options.parse,\n\t\tserialize: options.serialize,\n\t\tgetRef: options.getRef,\n\t\tttlMs: options.ttlMs ?? client.options?.ttlMs,\n\t\tnamespace: options.namespace ?? client.options?.namespace,\n\t\trevision: options.revision ?? client.options?.revision,\n\t});\n\treturn {\n\t\tbuild: () =>\n\t\t\tcreateCacheMethods(\n\t\t\t\tstoreClient,\n\t\t\t\t{\n\t\t\t\t\tonUpdateHook: options.onUpdate,\n\t\t\t\t\tonInsertHook: options.onInsert,\n\t\t\t\t\tonDeleteHook: options.onDelete,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tonUpdateHooks: [],\n\t\t\t\t\tonInsertHooks: [],\n\t\t\t\t\tonDeleteHooks: [],\n\t\t\t\t},\n\t\t\t),\n\t\twithQueries: (definitions) => {\n\t\t\treturn {\n\t\t\t\tbuild: () => createCacheMethodsWithQueries(storeClient, options, definitions),\n\t\t\t};\n\t\t},\n\t};\n}\n\nfunction createCacheMethods<Item>(\n\tstoreClient: CacheStore<Item>,\n\titemHooks: {\n\t\tonUpdateHook?: (item: Item[]) => void | Promise<void>;\n\t\tonInsertHook?: (item: Item[]) => void | Promise<void>;\n\t\tonDeleteHook?: (ref: ItemRef[]) => void | Promise<void>;\n\t},\n\tqueryHooks: {\n\t\tonUpdateHooks: Array<QueryOnUpdateHook<Item>>;\n\t\tonInsertHooks: Array<QueryOnInsertHook<Item>>;\n\t\tonDeleteHooks: Array<QueryOnDeleteHook<Item>>;\n\t},\n): Cache<Item> | Omit<CacheWithQueries<Item, any>, 'queries' | 'deleteQueries'> {\n\treturn {\n\t\tget: (ref) => storeClient.get(ref),\n\t\tgetMany: (refs) => storeClient.getMany(refs),\n\t\tgetPartial: (refs) => storeClient.getPartial(refs),\n\t\tupdate: async (item, options) => {\n\t\t\tif (queryHooks.onUpdateHooks.length === 0) {\n\t\t\t\tawait storeClient.save(item);\n\t\t\t\tawait fireHook(itemHooks.onUpdateHook, toArray(item), options);\n\t\t\t} else {\n\t\t\t\tconst items = toArray(item);\n\t\t\t\tconst previous = await storeClient.saveWithDiff(items);\n\t\t\t\tconst pairs = zip(items, previous, (next, previous) => ({ next, previous }));\n\t\t\t\tawait Promise.all([\n\t\t\t\t\tfireHook(itemHooks.onUpdateHook, items, options),\n\t\t\t\t\tfireHooks(queryHooks.onUpdateHooks, pairs, options),\n\t\t\t\t]);\n\t\t\t}\n\t\t},\n\t\tinsert: async (item, options) => {\n\t\t\tawait storeClient.save(item);\n\t\t\tif (queryHooks.onInsertHooks.length === 0) {\n\t\t\t\tawait fireHook(itemHooks.onInsertHook, toArray(item), options);\n\t\t\t} else {\n\t\t\t\tconst items = toArray(item);\n\t\t\t\tawait Promise.all([\n\t\t\t\t\tfireHook(itemHooks.onInsertHook, items, options),\n\t\t\t\t\tfireHooks(queryHooks.onInsertHooks, items, options),\n\t\t\t\t]);\n\t\t\t}\n\t\t},\n\t\tdelete: async (ref, options) => {\n\t\t\tif (queryHooks.onDeleteHooks.length === 0) {\n\t\t\t\tawait storeClient.delete(ref);\n\t\t\t\tawait fireHook(itemHooks.onDeleteHook, toArray(ref), options);\n\t\t\t} else {\n\t\t\t\tconst refs = toArray(ref);\n\t\t\t\tconst previous = await storeClient.deleteWithDiff(refs);\n\t\t\t\tawait storeClient.delete(refs);\n\t\t\t\tconst pairs = zip(refs, previous, (ref, previous) => ({ ref, previous }));\n\t\t\t\tawait Promise.all([\n\t\t\t\t\tfireHook(itemHooks.onDeleteHook, refs, options),\n\t\t\t\t\tfireHooks(queryHooks.onDeleteHooks, pairs, options),\n\t\t\t\t]);\n\t\t\t}\n\t\t},\n\t};\n}\n\nfunction createCacheMethodsWithQueries<Item, QueryDefinitions extends QueryDefinitionMap<Item>>(\n\tstoreClient: CacheStore<Item>,\n\toptions: CacheOptions<Item> & OptionalGetRef<Item>,\n\tdefinitions: QueryDefinitions,\n): CacheWithQueries<Item, QueryDefinitions> {\n\tconst { queries, queryTags, onUpdateHooks, onInsertHooks, onDeleteHooks } = createQueriesAndHooks<\n\t\tItem,\n\t\tQueryDefinitions\n\t>(definitions, storeClient);\n\treturn {\n\t\t...createCacheMethods(\n\t\t\tstoreClient,\n\t\t\t{\n\t\t\t\tonUpdateHook: options.onUpdate,\n\t\t\t\tonInsertHook: options.onInsert,\n\t\t\t\tonDeleteHook: options.onDelete,\n\t\t\t},\n\t\t\t{ onUpdateHooks, onInsertHooks, onDeleteHooks },\n\t\t),\n\t\tdeleteQueries: async () => {\n\t\t\tconst promises = queryTags.map((tag) =>\n\t\t\t\tstoreClient.deleteQueries({\n\t\t\t\t\t...tag,\n\t\t\t\t\tindexes: [],\n\t\t\t\t}),\n\t\t\t);\n\t\t\tawait Promise.all(promises);\n\t\t},\n\t\tqueries,\n\t};\n}\n\nfunction createQueriesAndHooks<Item, QueryDefinitions extends QueryDefinitionMap<Item>>(\n\tdefinitions: QueryDefinitions | undefined,\n\tstore: CacheStore<Item>,\n) {\n\tconst queries: Partial<QueryMethodMap<QueryDefinitions>> = {};\n\tconst queryTags: QueryTag[] = [];\n\tconst onUpdateHooks: Array<QueryOnUpdateHook<Item>> = [];\n\tconst onInsertHooks: Array<QueryOnInsertHook<Item>> = [];\n\tconst onDeleteHooks: Array<QueryOnDeleteHook<Item>> = [];\n\tfor (const [queryName, buildQuery] of Object.entries(definitions ?? {})) {\n\t\tconst queryHandler = buildQuery(store, queryName);\n\t\tqueries[queryName as keyof QueryDefinitions] = queryHandler.call as QueryMethod<\n\t\t\tQueryDefinitions[keyof QueryDefinitions]\n\t\t>;\n\t\tqueryTags.push(queryHandler.tag);\n\t\tif (queryHandler.hooks.onUpdate) {\n\t\t\tonUpdateHooks.push(queryHandler.hooks.onUpdate);\n\t\t}\n\t\tif (queryHandler.hooks.onDelete) {\n\t\t\tonDeleteHooks.push(queryHandler.hooks.onDelete);\n\t\t}\n\t\tif (queryHandler.hooks.onInsert) {\n\t\t\tonInsertHooks.push(queryHandler.hooks.onInsert);\n\t\t}\n\t}\n\treturn {\n\t\tqueries: queries as QueryMethodMap<QueryDefinitions>,\n\t\tqueryTags,\n\t\tonUpdateHooks,\n\t\tonInsertHooks,\n\t\tonDeleteHooks,\n\t};\n}\n\nasync function fireHook<T>(\n\thook: ((v: T) => void | Promise<void>) | undefined,\n\tvalue: T,\n\toptions?: CacheHooksOptions,\n) {\n\tif (hook == null) {\n\t\treturn;\n\t}\n\tif (options?.waitForHooks) {\n\t\tawait hook(value);\n\t} else {\n\t\tPromise.resolve()\n\t\t\t.then(() => hook(value))\n\t\t\t.catch((err) => {\n\t\t\t\tlog.error(err, 'Error in cache hook');\n\t\t\t});\n\t}\n}\n\nasync function fireHooks<T>(\n\thooks: Array<(v: T) => Promise<void>>,\n\tvalue: T,\n\toptions?: CacheHooksOptions,\n) {\n\tawait Promise.all(hooks.map((hook) => fireHook(hook, value, options)));\n}\n","import { log } from '@baeta/util-log';\nimport type {\n\tIndexedQueryArgs,\n\tItemFromQueryResult,\n\tQueryArgs,\n\tQueryArgsIndexes,\n\tQueryHandle,\n\tQueryHelpers,\n\tQueryHelpersWithIndexes,\n\tQueryIndex,\n\tQueryOptions,\n\tQueryResult,\n\tQueryTag,\n} from './query.ts';\nimport type { CacheStore } from './store.ts';\n\nexport type QueryFactory<\n\tResult extends QueryResult<Item>,\n\tArgs extends QueryArgs,\n\tIndexes extends QueryArgsIndexes<Args, Indexes>,\n\tItem = ItemFromQueryResult<Result>,\n> = (store: CacheStore<Item>, name: string) => QueryHandle<Result, Args, Indexes, Item>;\n\nexport type QueryMethod<T extends QueryFactory<any, any, any>> =\n\tT extends QueryFactory<infer Result, infer Args, any, any>\n\t\t? (args: Args) => Promise<Result>\n\t\t: never;\n\nexport type QueryDefinitionMap<Item> = Record<\n\tstring,\n\tQueryFactory<QueryResult<Item>, any, any, Item>\n>;\n\nexport type QueryMethodMap<Definitions extends QueryDefinitionMap<any>> = {\n\t[K in keyof Definitions]: QueryMethod<Definitions[K]>;\n};\n\nexport function defineQuery<\n\tResult extends QueryResult<Item>,\n\tArgs extends QueryArgs = Record<string, never>,\n\tIndexes extends QueryArgsIndexes<Args, Indexes> = Record<string, never>,\n\tItem = ItemFromQueryResult<Result>,\n>(options: QueryOptions<Result, Args, Indexes, Item>): QueryFactory<Result, Args, Indexes, Item> {\n\treturn (store: CacheStore<Item>, name: string) => {\n\t\tconst tag: QueryTag = {\n\t\t\tname,\n\t\t\trevision: options.revision,\n\t\t};\n\n\t\tconst resolve = async (args: Args): Promise<Result> => {\n\t\t\tconst fromCache = await store\n\t\t\t\t.getQuery({\n\t\t\t\t\t...tag,\n\t\t\t\t\targs,\n\t\t\t\t})\n\t\t\t\t.catch((err) => {\n\t\t\t\t\tlog.error(err, `Failed to get query result for ${name}. Proceeding without caching.`);\n\t\t\t\t\treturn null;\n\t\t\t\t});\n\n\t\t\tif (fromCache != null) {\n\t\t\t\treturn fromCache.query as Result;\n\t\t\t}\n\n\t\t\tconst data = await options.resolve(args);\n\n\t\t\tawait store\n\t\t\t\t.saveQuery(\n\t\t\t\t\t{\n\t\t\t\t\t\t...tag,\n\t\t\t\t\t\targs,\n\t\t\t\t\t\tdata,\n\t\t\t\t\t\tindexes: buildIndexes(args, options.indexArgsBy),\n\t\t\t\t\t},\n\t\t\t\t\toptions.replaceExistingItems,\n\t\t\t\t)\n\t\t\t\t.catch((err) => {\n\t\t\t\t\tlog.error(err, `Failed to save query result for ${name}. Proceeding without caching.`);\n\t\t\t\t});\n\n\t\t\treturn data;\n\t\t};\n\n\t\tconst invalidateAll = async () => {\n\t\t\tawait store.deleteQueries({\n\t\t\t\t...tag,\n\t\t\t\tindexes: [],\n\t\t\t});\n\t\t};\n\n\t\tconst invalidateByArgs = async (\n\t\t\targs: Partial<IndexedQueryArgs<Args, Indexes>> | Partial<IndexedQueryArgs<Args, Indexes>>[],\n\t\t) => {\n\t\t\tconst argsArray = Array.isArray(args) ? args : [args];\n\t\t\tconst deletePromises = argsArray.map((args) =>\n\t\t\t\tstore.deleteQueries({\n\t\t\t\t\t...tag,\n\t\t\t\t\tindexes: buildIndexes(args, options.indexArgsBy),\n\t\t\t\t}),\n\t\t\t);\n\t\t\tawait Promise.all(deletePromises);\n\t\t};\n\n\t\tconst helpers: QueryHelpersWithIndexes<Args, Indexes> = {\n\t\t\tinvalidateAll,\n\t\t\tinvalidateByArgs,\n\t\t};\n\t\tconst helpersCast: QueryHelpers<Args, Indexes> = helpers as QueryHelpers<Args, Indexes>;\n\n\t\tconst { onUpdate, onDelete, onInsert } = options;\n\n\t\tconst hooks = {\n\t\t\tonUpdate: hookWithHelpers(helpersCast, onUpdate),\n\t\t\tonInsert: hookWithHelpers(helpersCast, onInsert),\n\t\t\tonDelete: hookWithHelpers(helpersCast, onDelete),\n\t\t};\n\n\t\treturn {\n\t\t\tcall: resolve,\n\t\t\ttag,\n\t\t\thelpers,\n\t\t\thooks,\n\t\t};\n\t};\n}\n\nfunction hookWithHelpers<Helpers, Args>(\n\thelpers: Helpers,\n\thook?: (args: Args, helpers: Helpers) => void | Promise<void>,\n) {\n\tif (!hook) {\n\t\treturn undefined;\n\t}\n\tconst hookWithHelpers = async (args: Args) => {\n\t\tawait hook(args, helpers);\n\t};\n\treturn hookWithHelpers;\n}\n\nfunction buildIndexes<Args extends QueryArgs, Indexes extends QueryArgsIndexes<Args, Indexes>>(\n\targs: Partial<Args>,\n\tindexArgsBy?: Indexes,\n): QueryIndex[] {\n\tif (!indexArgsBy) {\n\t\treturn [];\n\t}\n\tconst indexes: QueryIndex[] = [];\n\tfor (const key in indexArgsBy) {\n\t\tif (!Object.hasOwn(args, key)) {\n\t\t\tcontinue;\n\t\t}\n\t\tconst value = args[key];\n\t\tif (value === undefined) {\n\t\t\tcontinue;\n\t\t}\n\t\tif (Array.isArray(value)) {\n\t\t\tcontinue;\n\t\t}\n\t\tif (typeof value === 'object' && value !== null) {\n\t\t\tcontinue;\n\t\t}\n\t\tindexes.push([key, value]);\n\t}\n\treturn indexes;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../lib/client.ts","../lib/item.ts","../lib/key.ts","../lib/options.ts","../lib/utils.ts","../lib/store.ts","../lib/create-cache.ts","../lib/define-query.ts"],"sourcesContent":["import type { ItemCacheKey, QueryCacheIndexKey, QueryCacheKey } from './key.ts';\n\nexport interface CacheClientArgs<Item> {\n\tttlMs: number;\n\tparse: (value: string) => Item | null;\n\tserialize: (item: Item) => string;\n}\n\nexport interface CacheClientOptions {\n\t/**\n\t * Revision number for cache invalidation.\n\t * Incrementing this number will invalidate all existing cache entries for this store.\n\t * @defaultValue \"default\"\n\t */\n\trevision?: number;\n\t/**\n\t * Time-to-live in milliseconds\n\t * @defaultValue 3_600_000 (1 hour)\n\t */\n\tttlMs?: number;\n\t/**\n\t * Optional namespace to prefix all cache keys\n\t * @defaultValue \"baeta\"\n\t */\n\tnamespace?: string;\n}\n\nexport interface CacheClientSaveOptions {\n\t/**\n\t * If true, the save operation will not overwrite existing cache entries. Instead, it will only save entries that do not already exist in the cache.\n\t * @defaultValue false\n\t */\n\tdisableOverwrite?: boolean;\n}\n\nexport abstract class CacheClient {\n\toptions?: CacheClientOptions;\n\n\tconstructor(options?: CacheClientOptions) {\n\t\tthis.options = options;\n\t}\n\n\tabstract getPartialItems<Item>(\n\t\tkeys: ItemCacheKey[],\n\t\toptions: CacheClientArgs<Item>,\n\t): Promise<Array<Item | null>>;\n\n\tabstract saveItems<Item>(\n\t\titems: Array<[ItemCacheKey, Item]>,\n\t\toptions: CacheClientArgs<Item>,\n\t\tsaveOptions?: CacheClientSaveOptions,\n\t): Promise<void>;\n\n\tabstract saveItemsWithDiff<Item>(\n\t\titems: Array<[ItemCacheKey, Item]>,\n\t\toptions: CacheClientArgs<Item>,\n\t): Promise<Array<Item | null>>;\n\n\tabstract deleteItems<Item>(keys: ItemCacheKey[], options: CacheClientArgs<Item>): Promise<void>;\n\n\tabstract deleteItemsWithDiff<Item>(\n\t\tkeys: ItemCacheKey[],\n\t\toptions: CacheClientArgs<Item>,\n\t): Promise<Array<Item | null>>;\n\n\tabstract getQuery<QueryMetadata>(\n\t\tkey: QueryCacheKey,\n\t\toptions: CacheClientArgs<QueryMetadata>,\n\t): Promise<QueryMetadata | null>;\n\n\tabstract saveQuery<QueryMetadata>(\n\t\tkey: QueryCacheKey,\n\t\tindexes: QueryCacheIndexKey[],\n\t\tmetadata: QueryMetadata,\n\t\toptions: CacheClientArgs<QueryMetadata>,\n\t): Promise<void>;\n\n\tabstract deleteQueries<QueryMetadata>(\n\t\tindexes: QueryCacheIndexKey[],\n\t\toptions: CacheClientArgs<QueryMetadata>,\n\t): Promise<void>;\n}\n","/**\n * Reference type for cached items\n */\nexport type ItemRef = string | number | bigint;\n\n/**\n * Type constraint for objects that are compatible with default cache ref\n */\nexport type RefCompatibleItem = { id: string | number | bigint };\n\n/**\n * Asserts that a given reference is of a valid type (string, number, or bigint) and that it can be safely serialized.\n */\nexport function assertValidRefType(ref: unknown): asserts ref is string | number | bigint {\n\tif (typeof ref !== 'string' && typeof ref !== 'number' && typeof ref !== 'bigint') {\n\t\tthrow new TypeError(\n\t\t\t'Reference must be string, number or bigint. Define getRef function in cache options',\n\t\t);\n\t}\n}\n","import { encodeBase64 } from '@baeta/util-encoding';\nimport { hash } from 'ohash';\nimport type { QueryArgs, QueryIndex } from './query.ts';\n\nexport type QueryCacheKey = `${QueryCacheKeyPrefix}:${QueryCacheKeyId}`;\nexport type QueryCacheIndexKey = `${QueryCacheKeyPrefix}:${QueryCacheIndexKeyId}`;\nexport type QueryCacheKeyId = `id:${string}`;\nexport type QueryCacheIndexKeyId = `idx:${string}`;\nexport type QueryCacheKeyPrefix = `${string}:${string}:query:${string}:${CacheRevisionId}`; // $namespace:$storeName:query:$queryName:rev_$value\n\nexport type ItemCacheKey = `${ItemCacheKeyPrefix}:${ItemCacheKeyId}`;\nexport type ItemCacheKeyId = `id:${string}`;\nexport type ItemCacheKeyPrefix = `${string}:${string}:item:${CacheRevisionId}`; // $namespace:$storeName:item:rev_$value\n\nexport type CacheRevisionId = `rev_${string}`;\n\nexport function buildCacheRevisionId(revision: string): CacheRevisionId {\n\treturn `rev_${revision}`;\n}\n\nexport function buildItemCacheKeyId(id: string): ItemCacheKeyId {\n\treturn `id:${id}`;\n}\n\nexport function buildQueryCacheKeyId(args: QueryArgs): QueryCacheKeyId {\n\treturn `id:${hash(args)}`;\n}\n\nexport function buildQueryCacheIndexKeyId(index?: QueryIndex | undefined): QueryCacheIndexKeyId {\n\tif (index == null) {\n\t\treturn 'idx:';\n\t}\n\tconst key = index[0];\n\tconst value = index[1];\n\tconst safeValue = value === null ? 'null' : `_${encodeBase64(value.toString())}`;\n\treturn `idx:${hash(`${key}=${safeValue}`)}`;\n}\n\nexport function buildQueryCacheIndexKeysIds(indexes: QueryIndex[]): QueryCacheIndexKeyId[] {\n\tif (indexes.length === 0) {\n\t\treturn ['idx:'];\n\t}\n\treturn indexes.map((idx) => buildQueryCacheIndexKeyId(idx));\n}\n","import type { ItemRef } from './item.ts';\n\nexport const DEFAULT_REVISION = 'default';\nexport const DEFAULT_NAMESPACE = 'baeta';\nexport const DEFAULT_TTL_MS = 3_600_000; // 1 hour\n\n/**\n * Configuration options for cache stores\n */\nexport type CacheOptions<Item> = {\n\t/**\n\t * Unique name for the cache store. Used as a prefix for cache keys to avoid collisions.\n\t */\n\tname: string;\n\t/**\n\t * Revision number for cache invalidation.\n\t * Incrementing this number will invalidate all existing cache entries for this store.\n\t * @defaultValue CacheClient options or \"default\"\n\t */\n\trevision?: number;\n\t/**\n\t * Time-to-live in milliseconds\n\t * @defaultValue CacheClient options or 3_600_000 (1 hour)\n\t */\n\tttlMs?: number;\n\t/**\n\t * Optional namespace to prefix all cache keys\n\t * @defaultValue CacheClient options or \"baeta\"\n\t */\n\tnamespace?: string;\n\t/**\n\t * Function to parse stored strings back into source objects.\n\t * If it throws an error, the cache will be treated as a miss and the value will be deleted.\n\t */\n\tparse: (value: string) => Item;\n\t/**\n\t * Function to serialize source objects into strings for cache storage.\n\t */\n\tserialize: (value: Item) => string;\n\t/**\n\t * Hook that gets called with the updated items after an update operation.\n\t */\n\tonUpdate?: (item: Item[]) => void | Promise<void>;\n\t/**\n\t * Hook that gets called with the inserted items after an insert operation.\n\t */\n\tonInsert?: (item: Item[]) => void | Promise<void>;\n\t/**\n\t * Hook that gets called with the refs of deleted items after a delete operation.\n\t */\n\tonDelete?: (ref: ItemRef[]) => void | Promise<void>;\n};\n\nexport type OptionalGetRef<Item> = {\n\t/*\n\t * Optional function to extract a string reference from source objects.\n\t * Will use \"id\" property by default.\n\t */\n\tgetRef?: (source: Item) => ItemRef;\n};\n\nexport type RequiredGetRef<Item> = {\n\t/*\n\t * Function to extract a string reference from source objects.\n\t */\n\tgetRef: (source: Item) => ItemRef;\n};\n","import type { ItemRef } from './item.ts';\n\nexport function arrayIsComplete<T>(items: Array<T | null> | null): items is T[] {\n\tif (items == null) {\n\t\treturn false;\n\t}\n\treturn items.every((item) => item != null);\n}\n\nexport function alignItemsWithRefs<T>(partialRefs: Array<ItemRef | null>, items: T[]) {\n\tif (partialRefs.length === items.length) {\n\t\treturn items;\n\t}\n\tlet itemIndex = 0;\n\tconst aligned: Array<T | null> = [];\n\tfor (const ref of partialRefs) {\n\t\tif (ref == null) {\n\t\t\taligned.push(null);\n\t\t} else {\n\t\t\taligned.push(items[itemIndex++]);\n\t\t}\n\t}\n\treturn aligned;\n}\n\nexport function toArray<T>(item: T | T[]): T[] {\n\treturn Array.isArray(item) ? item : [item];\n}\n\nexport function zip<T, U, R>(array1: T[], array2: U[], fn: (a: T, b: U) => R): R[] {\n\tif (array1.length !== array2.length) {\n\t\tthrow new Error('Arrays must have the same length to be zipped');\n\t}\n\tconst result: R[] = [];\n\tfor (let i = 0; i < array1.length; i++) {\n\t\tresult.push(fn(array1[i], array2[i]));\n\t}\n\treturn result;\n}\n","import { log } from '@baeta/util-log';\nimport DataLoader from 'dataloader';\nimport type { CacheClient, CacheClientArgs } from './client.ts';\nimport { assertValidRefType, type ItemRef } from './item.ts';\nimport {\n\tbuildCacheRevisionId,\n\tbuildItemCacheKeyId,\n\tbuildQueryCacheIndexKeyId,\n\tbuildQueryCacheIndexKeysIds,\n\tbuildQueryCacheKeyId,\n\ttype CacheRevisionId,\n\ttype ItemCacheKey,\n\ttype ItemCacheKeyPrefix,\n\ttype QueryCacheIndexKey,\n\ttype QueryCacheKey,\n\ttype QueryCacheKeyPrefix,\n} from './key.ts';\nimport { DEFAULT_NAMESPACE, DEFAULT_REVISION, DEFAULT_TTL_MS } from './options.ts';\nimport type { QueryTag, QueryTagWithArgs, QueryTagWithData, QueryTagWithIndexes } from './query.ts';\nimport { alignItemsWithRefs, arrayIsComplete, toArray } from './utils.ts';\n\nexport interface CacheStoreOptions<Item> {\n\tname: string;\n\tclient: CacheClient;\n\tnamespace?: string;\n\trevision?: string | number;\n\tttlMs?: number;\n\tparse: (value: string) => Item;\n\tserialize: (item: Item) => string;\n\tgetRef?: (source: Item) => ItemRef;\n}\n\ntype QueryMetadata = { refs: Array<null | string>; isList: boolean };\n\nexport class CacheStore<Item> {\n\tprotected readonly name: string;\n\tprotected readonly namespace: string;\n\tprotected readonly revision: string;\n\n\tprotected readonly client: CacheClient;\n\tprotected readonly itemCacheArgs: CacheClientArgs<Item>;\n\tprotected readonly queryCacheArgs: CacheClientArgs<QueryMetadata>;\n\n\tprotected readonly getRef?: (source: Item) => ItemRef;\n\n\tconstructor({\n\t\tname,\n\t\tclient,\n\t\tnamespace,\n\t\trevision,\n\t\tttlMs,\n\t\tparse,\n\t\tserialize,\n\t\tgetRef,\n\t}: CacheStoreOptions<Item>) {\n\t\tthis.name = name;\n\t\tthis.namespace = namespace ?? DEFAULT_NAMESPACE;\n\t\tthis.revision = revision?.toString() ?? DEFAULT_REVISION;\n\t\tthis.client = client;\n\t\tthis.getRef = getRef;\n\t\tthis.itemCacheArgs = {\n\t\t\tttlMs: ttlMs ?? DEFAULT_TTL_MS,\n\t\t\tparse: (value: string) => parseItemSafely(value, parse),\n\t\t\tserialize: (item: Item) => serialize(item),\n\t\t};\n\t\tthis.queryCacheArgs = {\n\t\t\tttlMs: ttlMs ?? DEFAULT_TTL_MS,\n\t\t\tparse: (value: string) => parseQueryMetadataSafely(value),\n\t\t\tserialize: (meta: QueryMetadata) => JSON.stringify(meta),\n\t\t};\n\t}\n\n\tprotected loadAndParse = async (refs: ReadonlyArray<ItemRef>): Promise<Array<Item | null>> => {\n\t\tconst keys = refs.map((ref) => this.getItemKeyByRef(ref));\n\t\treturn await this.client.getPartialItems(keys, this.itemCacheArgs);\n\t};\n\n\tprotected loader = new DataLoader<ItemRef, Item | null>(this.loadAndParse, {\n\t\tcache: false,\n\t});\n\n\tasync get(ref: ItemRef): Promise<Item | null> {\n\t\treturn await this.loader.load(ref);\n\t}\n\n\tasync getMany(refs: ItemRef[]): Promise<Item[] | null> {\n\t\tconst results = await Promise.all(refs.map((r) => this.get(r)));\n\t\tif (!arrayIsComplete(results)) {\n\t\t\treturn null;\n\t\t}\n\t\treturn results;\n\t}\n\n\tasync getPartial(refs: ItemRef[]): Promise<Array<Item | null>> {\n\t\treturn await Promise.all(refs.map((ref) => this.get(ref)));\n\t}\n\n\tasync save(item: Item | Item[]) {\n\t\tconst values = toArray(item);\n\t\tconst entries: Array<[ItemCacheKey, Item]> = values.map((item) => [\n\t\t\tthis.getItemKey(item),\n\t\t\titem,\n\t\t]);\n\t\treturn await this.client.saveItems(entries, this.itemCacheArgs);\n\t}\n\n\tasync saveIfNotExists(item: Item | Item[]) {\n\t\tconst values = toArray(item);\n\t\tconst entries: Array<[ItemCacheKey, Item]> = values.map((item) => [\n\t\t\tthis.getItemKey(item),\n\t\t\titem,\n\t\t]);\n\t\treturn await this.client.saveItems(entries, this.itemCacheArgs, {\n\t\t\tdisableOverwrite: true,\n\t\t});\n\t}\n\n\tasync saveWithDiff(item: Item | Item[]): Promise<Array<Item | null>> {\n\t\tconst values = toArray(item);\n\t\tconst entries: Array<[ItemCacheKey, Item]> = values.map((item) => [\n\t\t\tthis.getItemKey(item),\n\t\t\titem,\n\t\t]);\n\t\treturn await this.client.saveItemsWithDiff(entries, this.itemCacheArgs);\n\t}\n\n\tasync delete(ref: ItemRef | ItemRef[]) {\n\t\tconst refs = toArray(ref);\n\t\tconst keys = refs.map((r) => this.getItemKeyByRef(r));\n\t\tawait this.client.deleteItems(keys, this.itemCacheArgs);\n\t}\n\n\tasync deleteWithDiff(ref: ItemRef | ItemRef[]): Promise<Array<Item | null>> {\n\t\tconst refs = toArray(ref);\n\t\tconst keys = refs.map((r) => this.getItemKeyByRef(r));\n\t\treturn await this.client.deleteItemsWithDiff(keys, this.itemCacheArgs);\n\t}\n\n\tasync getQuery(query: QueryTagWithArgs): Promise<{ query: unknown } | null> {\n\t\tconst queryKey = this.getQueryKey(query);\n\t\tconst meta = await this.client.getQuery(queryKey, this.queryCacheArgs);\n\n\t\tif (meta == null) {\n\t\t\treturn null;\n\t\t}\n\n\t\tconst isList = meta.isList;\n\t\tconst nullableRefs = meta.refs;\n\t\tconst refs = nullableRefs.filter((ref) => ref != null);\n\t\tconst items = await this.getMany(refs);\n\n\t\tif (items == null) {\n\t\t\treturn null;\n\t\t}\n\n\t\tconst aligned = alignItemsWithRefs(nullableRefs, items);\n\t\tconst result = isList ? aligned : (aligned.at(0) ?? null);\n\n\t\treturn { query: result };\n\t}\n\n\tasync saveQuery(\n\t\tquery: QueryTagWithData<Item>,\n\t\treplaceExistingItems = false,\n\t\tttlMs?: number,\n\t): Promise<void> {\n\t\tconst data = query.data;\n\t\tconst queryKey = this.getQueryKey(query);\n\t\tconst queryIndexes = this.getQueryIndexes(query, true);\n\n\t\tconst isList = Array.isArray(data);\n\t\tconst nullableItems = isList ? data : [data];\n\t\tconst items = nullableItems.filter((item) => item != null);\n\n\t\tif (items.length > 0) {\n\t\t\tif (replaceExistingItems) {\n\t\t\t\tawait this.save(items);\n\t\t\t} else {\n\t\t\t\tawait this.saveIfNotExists(items);\n\t\t\t}\n\t\t}\n\n\t\tconst encodedRefs = nullableItems.map((item) => {\n\t\t\tif (item == null) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\treturn this.getRefWithFallback(item).toString();\n\t\t});\n\n\t\tconst metadata = {\n\t\t\trefs: encodedRefs,\n\t\t\tisList,\n\t\t};\n\n\t\treturn await this.client.saveQuery(queryKey, queryIndexes, metadata, {\n\t\t\t...this.queryCacheArgs,\n\t\t\tttlMs: ttlMs ?? this.queryCacheArgs.ttlMs,\n\t\t});\n\t}\n\n\tdeleteQueries(query: QueryTagWithIndexes): Promise<void> {\n\t\tconst queryIndexes = this.getQueryIndexes(query);\n\t\treturn this.client.deleteQueries(queryIndexes, this.queryCacheArgs);\n\t}\n\n\tgetRefWithFallback(root: Item): ItemRef {\n\t\tif (this.getRef) {\n\t\t\treturn this.getRef(root);\n\t\t}\n\t\tif (root == null) {\n\t\t\tthrow new Error('Object is null or undefined, cannot get ref');\n\t\t}\n\t\tif (typeof root === 'object' && 'id' in root) {\n\t\t\tassertValidRefType(root.id);\n\t\t\treturn root.id.toString();\n\t\t}\n\t\tthrow new Error('Object does not have id. Define \"getRef\" function in cache options');\n\t}\n\n\tgetItemKey(item: Item): ItemCacheKey {\n\t\tconst ref = this.getRefWithFallback(item);\n\t\treturn this.getItemKeyByRef(ref);\n\t}\n\n\tgetItemKeyByRef(ref: ItemRef): ItemCacheKey {\n\t\tconst prefix: ItemCacheKeyPrefix = `${this.namespace}:{${this.name}:item:${buildCacheRevisionId(this.revision)}}`;\n\t\tconst keyId = buildItemCacheKeyId(ref.toString());\n\t\treturn `${prefix}:${keyId}`;\n\t}\n\n\tgetQueryKey(query: QueryTagWithArgs): QueryCacheKey {\n\t\tconst prefix = this.getQueryKeyPrefix(query);\n\t\treturn `${prefix}:${buildQueryCacheKeyId(query.args)}`;\n\t}\n\n\tgetQueryIndexes(query: QueryTagWithIndexes, ensureCatchAll = false): QueryCacheIndexKey[] {\n\t\tconst prefix = this.getQueryKeyPrefix(query);\n\t\tconst keyIndexes = buildQueryCacheIndexKeysIds(query.indexes);\n\t\tif (ensureCatchAll && query.indexes.length > 0) {\n\t\t\tkeyIndexes.push(buildQueryCacheIndexKeyId());\n\t\t}\n\t\treturn keyIndexes.map((keyIndex) => `${prefix}:${keyIndex}` as const);\n\t}\n\n\tgetQueryKeyPrefix(query: QueryTag): QueryCacheKeyPrefix {\n\t\treturn `${this.namespace}:{${this.name}:query:${query.name}:${this.getQueryKeyRevision(query)}}`;\n\t}\n\n\tgetQueryKeyRevision(query: QueryTag): CacheRevisionId {\n\t\tconst combinedRevision = `${this.revision}_${query.revision?.toString() ?? DEFAULT_REVISION}`;\n\t\treturn buildCacheRevisionId(combinedRevision);\n\t}\n}\n\nfunction parseItemSafely<T>(value: string, parseItem: (value: string) => T): T | null {\n\ttry {\n\t\treturn parseItem(value);\n\t} catch (err) {\n\t\tlog.warn(err, 'Failed to parse item, returning null');\n\t\treturn null;\n\t}\n}\n\nfunction parseQueryMetadataSafely(value: string): QueryMetadata | null {\n\tlet parsed: unknown;\n\ttry {\n\t\tparsed = JSON.parse(value);\n\t} catch (err) {\n\t\tlog.warn(err, 'Failed to parse query metadata, treating as cache miss');\n\t\treturn null;\n\t}\n\tif (!isValidQueryMetadata(parsed)) {\n\t\tlog.warn('Query metadata has invalid shape, treating as cache miss');\n\t\treturn null;\n\t}\n\treturn parsed;\n}\n\nfunction isValidQueryMetadata(value: unknown): value is QueryMetadata {\n\tif (value == null || typeof value !== 'object') {\n\t\treturn false;\n\t}\n\tconst candidate = value as { refs?: unknown; isList?: unknown };\n\tif (!Array.isArray(candidate.refs)) {\n\t\treturn false;\n\t}\n\tif (typeof candidate.isList !== 'boolean') {\n\t\treturn false;\n\t}\n\treturn candidate.refs.every((ref) => ref === null || typeof ref === 'string');\n}\n","import { log } from '@baeta/util-log';\nimport type { CacheClient } from './client.ts';\nimport type { QueryDefinitionMap, QueryMethod, QueryMethodMap } from './define-query.ts';\nimport type { ItemRef, RefCompatibleItem } from './item.ts';\nimport type { CacheOptions, OptionalGetRef, RequiredGetRef } from './options.ts';\nimport type { QueryOnDeleteHook, QueryOnInsertHook, QueryOnUpdateHook, QueryTag } from './query.ts';\nimport { CacheStore } from './store.ts';\nimport { toArray, zip } from './utils.ts';\n\nexport type CacheHooksOptions = {\n\t/**\n\t * If true, hooks will be awaited. If false, hooks will be fired asynchronously and will not block cache methods.\n\t * @defaultValue false\n\t */\n\twaitForHooks?: boolean;\n};\n\nexport type Cache<Item> = {\n\tget(ref: ItemRef): Promise<Item | null>;\n\tgetMany(refs: ItemRef[]): Promise<Item[] | null>;\n\tgetPartial(refs: ItemRef[]): Promise<Array<Item | null>>;\n\tupdate(item: Item | Item[]): Promise<void>;\n\tinsert(item: Item | Item[]): Promise<void>;\n\tdelete(ref: ItemRef | ItemRef[]): Promise<void>;\n};\n\nexport type CacheWithQueries<Item, QueryDefinitions extends QueryDefinitionMap<Item>> = {\n\tget(ref: ItemRef): Promise<Item | null>;\n\tgetMany(refs: ItemRef[]): Promise<Item[] | null>;\n\tgetPartial(refs: ItemRef[]): Promise<Array<Item | null>>;\n\tupdate(item: Item | Item[], options?: CacheHooksOptions): Promise<void>;\n\tinsert(item: Item | Item[], options?: CacheHooksOptions): Promise<void>;\n\tdelete(ref: ItemRef | ItemRef[], options?: CacheHooksOptions): Promise<void>;\n\tdeleteQueries(): Promise<void>;\n\tqueries: QueryMethodMap<QueryDefinitions>;\n};\n\nexport type CreateCacheFactory<Item> = {\n\tbuild: () => Cache<Item>;\n\twithQueries: <QueryDefinitions extends QueryDefinitionMap<Item>>(\n\t\tdefinitions: QueryDefinitions,\n\t) => {\n\t\tbuild: () => CacheWithQueries<Item, QueryDefinitions>;\n\t};\n};\n\nexport function createCache<Item extends RefCompatibleItem>(\n\tclient: CacheClient,\n\toptions: CacheOptions<Item> & OptionalGetRef<Item>,\n): CreateCacheFactory<Item>;\nexport function createCache<Item>(\n\tclient: CacheClient,\n\toptions: CacheOptions<Item> & RequiredGetRef<Item>,\n): CreateCacheFactory<Item>;\nexport function createCache<Item>(\n\tclient: CacheClient,\n\toptions: CacheOptions<Item> & OptionalGetRef<Item>,\n): CreateCacheFactory<Item> {\n\tconst storeClient = new CacheStore<Item>({\n\t\tclient,\n\t\tname: options.name,\n\t\tparse: options.parse,\n\t\tserialize: options.serialize,\n\t\tgetRef: options.getRef,\n\t\tttlMs: options.ttlMs ?? client.options?.ttlMs,\n\t\tnamespace: options.namespace ?? client.options?.namespace,\n\t\trevision: options.revision ?? client.options?.revision,\n\t});\n\treturn {\n\t\tbuild: () =>\n\t\t\tcreateCacheMethods(\n\t\t\t\tstoreClient,\n\t\t\t\t{\n\t\t\t\t\tonUpdateHook: options.onUpdate,\n\t\t\t\t\tonInsertHook: options.onInsert,\n\t\t\t\t\tonDeleteHook: options.onDelete,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tonUpdateHooks: [],\n\t\t\t\t\tonInsertHooks: [],\n\t\t\t\t\tonDeleteHooks: [],\n\t\t\t\t},\n\t\t\t),\n\t\twithQueries: (definitions) => {\n\t\t\treturn {\n\t\t\t\tbuild: () => createCacheMethodsWithQueries(storeClient, options, definitions),\n\t\t\t};\n\t\t},\n\t};\n}\n\nfunction createCacheMethods<Item>(\n\tstoreClient: CacheStore<Item>,\n\titemHooks: {\n\t\tonUpdateHook?: (item: Item[]) => void | Promise<void>;\n\t\tonInsertHook?: (item: Item[]) => void | Promise<void>;\n\t\tonDeleteHook?: (ref: ItemRef[]) => void | Promise<void>;\n\t},\n\tqueryHooks: {\n\t\tonUpdateHooks: Array<QueryOnUpdateHook<Item>>;\n\t\tonInsertHooks: Array<QueryOnInsertHook<Item>>;\n\t\tonDeleteHooks: Array<QueryOnDeleteHook<Item>>;\n\t},\n): Cache<Item> | Omit<CacheWithQueries<Item, any>, 'queries' | 'deleteQueries'> {\n\treturn {\n\t\tget: (ref) => storeClient.get(ref),\n\t\tgetMany: (refs) => storeClient.getMany(refs),\n\t\tgetPartial: (refs) => storeClient.getPartial(refs),\n\t\tupdate: async (item, options) => {\n\t\t\tif (queryHooks.onUpdateHooks.length === 0) {\n\t\t\t\tawait storeClient.save(item);\n\t\t\t\tawait fireHook(itemHooks.onUpdateHook, toArray(item), options);\n\t\t\t} else {\n\t\t\t\tconst items = toArray(item);\n\t\t\t\tconst previous = await storeClient.saveWithDiff(items);\n\t\t\t\tconst pairs = zip(items, previous, (next, previous) => ({ next, previous }));\n\t\t\t\tawait Promise.all([\n\t\t\t\t\tfireHook(itemHooks.onUpdateHook, items, options),\n\t\t\t\t\tfireHooks(queryHooks.onUpdateHooks, pairs, options),\n\t\t\t\t]);\n\t\t\t}\n\t\t},\n\t\tinsert: async (item, options) => {\n\t\t\tawait storeClient.save(item);\n\t\t\tif (queryHooks.onInsertHooks.length === 0) {\n\t\t\t\tawait fireHook(itemHooks.onInsertHook, toArray(item), options);\n\t\t\t} else {\n\t\t\t\tconst items = toArray(item);\n\t\t\t\tawait Promise.all([\n\t\t\t\t\tfireHook(itemHooks.onInsertHook, items, options),\n\t\t\t\t\tfireHooks(queryHooks.onInsertHooks, items, options),\n\t\t\t\t]);\n\t\t\t}\n\t\t},\n\t\tdelete: async (ref, options) => {\n\t\t\tif (queryHooks.onDeleteHooks.length === 0) {\n\t\t\t\tawait storeClient.delete(ref);\n\t\t\t\tawait fireHook(itemHooks.onDeleteHook, toArray(ref), options);\n\t\t\t} else {\n\t\t\t\tconst refs = toArray(ref);\n\t\t\t\tconst previous = await storeClient.deleteWithDiff(refs);\n\t\t\t\tawait storeClient.delete(refs);\n\t\t\t\tconst pairs = zip(refs, previous, (ref, previous) => ({ ref, previous }));\n\t\t\t\tawait Promise.all([\n\t\t\t\t\tfireHook(itemHooks.onDeleteHook, refs, options),\n\t\t\t\t\tfireHooks(queryHooks.onDeleteHooks, pairs, options),\n\t\t\t\t]);\n\t\t\t}\n\t\t},\n\t};\n}\n\nfunction createCacheMethodsWithQueries<Item, QueryDefinitions extends QueryDefinitionMap<Item>>(\n\tstoreClient: CacheStore<Item>,\n\toptions: CacheOptions<Item> & OptionalGetRef<Item>,\n\tdefinitions: QueryDefinitions,\n): CacheWithQueries<Item, QueryDefinitions> {\n\tconst { queries, queryTags, onUpdateHooks, onInsertHooks, onDeleteHooks } = createQueriesAndHooks<\n\t\tItem,\n\t\tQueryDefinitions\n\t>(definitions, storeClient);\n\treturn {\n\t\t...createCacheMethods(\n\t\t\tstoreClient,\n\t\t\t{\n\t\t\t\tonUpdateHook: options.onUpdate,\n\t\t\t\tonInsertHook: options.onInsert,\n\t\t\t\tonDeleteHook: options.onDelete,\n\t\t\t},\n\t\t\t{ onUpdateHooks, onInsertHooks, onDeleteHooks },\n\t\t),\n\t\tdeleteQueries: async () => {\n\t\t\tconst promises = queryTags.map((tag) =>\n\t\t\t\tstoreClient.deleteQueries({\n\t\t\t\t\t...tag,\n\t\t\t\t\tindexes: [],\n\t\t\t\t}),\n\t\t\t);\n\t\t\tawait Promise.all(promises);\n\t\t},\n\t\tqueries,\n\t};\n}\n\nfunction createQueriesAndHooks<Item, QueryDefinitions extends QueryDefinitionMap<Item>>(\n\tdefinitions: QueryDefinitions | undefined,\n\tstore: CacheStore<Item>,\n) {\n\tconst queries: Partial<QueryMethodMap<QueryDefinitions>> = {};\n\tconst queryTags: QueryTag[] = [];\n\tconst onUpdateHooks: Array<QueryOnUpdateHook<Item>> = [];\n\tconst onInsertHooks: Array<QueryOnInsertHook<Item>> = [];\n\tconst onDeleteHooks: Array<QueryOnDeleteHook<Item>> = [];\n\tfor (const [queryName, buildQuery] of Object.entries(definitions ?? {})) {\n\t\tconst queryHandler = buildQuery(store, queryName);\n\t\tqueries[queryName as keyof QueryDefinitions] = queryHandler.call as QueryMethod<\n\t\t\tQueryDefinitions[keyof QueryDefinitions]\n\t\t>;\n\t\tqueryTags.push(queryHandler.tag);\n\t\tif (queryHandler.hooks.onUpdate) {\n\t\t\tonUpdateHooks.push(queryHandler.hooks.onUpdate);\n\t\t}\n\t\tif (queryHandler.hooks.onDelete) {\n\t\t\tonDeleteHooks.push(queryHandler.hooks.onDelete);\n\t\t}\n\t\tif (queryHandler.hooks.onInsert) {\n\t\t\tonInsertHooks.push(queryHandler.hooks.onInsert);\n\t\t}\n\t}\n\treturn {\n\t\tqueries: queries as QueryMethodMap<QueryDefinitions>,\n\t\tqueryTags,\n\t\tonUpdateHooks,\n\t\tonInsertHooks,\n\t\tonDeleteHooks,\n\t};\n}\n\nasync function fireHook<T>(\n\thook: ((v: T) => void | Promise<void>) | undefined,\n\tvalue: T,\n\toptions?: CacheHooksOptions,\n) {\n\tif (hook == null) {\n\t\treturn;\n\t}\n\tif (options?.waitForHooks) {\n\t\tawait hook(value);\n\t} else {\n\t\tPromise.resolve()\n\t\t\t.then(() => hook(value))\n\t\t\t.catch((err) => {\n\t\t\t\tlog.error(err, 'Error in cache hook');\n\t\t\t});\n\t}\n}\n\nasync function fireHooks<T>(\n\thooks: Array<(v: T) => Promise<void>>,\n\tvalue: T,\n\toptions?: CacheHooksOptions,\n) {\n\tawait Promise.all(hooks.map((hook) => fireHook(hook, value, options)));\n}\n","import { log } from '@baeta/util-log';\nimport type {\n\tIndexedQueryArgs,\n\tItemFromQueryResult,\n\tQueryArgs,\n\tQueryArgsIndexes,\n\tQueryHandle,\n\tQueryHelpers,\n\tQueryHelpersWithIndexes,\n\tQueryIndex,\n\tQueryOptions,\n\tQueryResult,\n\tQueryTag,\n} from './query.ts';\nimport type { CacheStore } from './store.ts';\n\nexport type QueryFactory<\n\tResult extends QueryResult<Item>,\n\tArgs extends QueryArgs,\n\tIndexes extends QueryArgsIndexes<Args, Indexes>,\n\tItem = ItemFromQueryResult<Result>,\n> = (store: CacheStore<Item>, name: string) => QueryHandle<Result, Args, Indexes, Item>;\n\nexport type QueryMethod<T extends QueryFactory<any, any, any>> =\n\tT extends QueryFactory<infer Result, infer Args, any, any>\n\t\t? (args: Args) => Promise<Result>\n\t\t: never;\n\nexport type QueryDefinitionMap<Item> = Record<\n\tstring,\n\tQueryFactory<QueryResult<Item>, any, any, Item>\n>;\n\nexport type QueryMethodMap<Definitions extends QueryDefinitionMap<any>> = {\n\t[K in keyof Definitions]: QueryMethod<Definitions[K]>;\n};\n\nexport function defineQuery<\n\tResult extends QueryResult<Item>,\n\tArgs extends QueryArgs = Record<string, never>,\n\tIndexes extends QueryArgsIndexes<Args, Indexes> = Record<string, never>,\n\tItem = ItemFromQueryResult<Result>,\n>(options: QueryOptions<Result, Args, Indexes, Item>): QueryFactory<Result, Args, Indexes, Item> {\n\treturn (store: CacheStore<Item>, name: string) => {\n\t\tconst tag: QueryTag = {\n\t\t\tname,\n\t\t\trevision: options.revision,\n\t\t};\n\n\t\tconst resolve = async (args: Args): Promise<Result> => {\n\t\t\tconst fromCache = await store\n\t\t\t\t.getQuery({\n\t\t\t\t\t...tag,\n\t\t\t\t\targs,\n\t\t\t\t})\n\t\t\t\t.catch((err) => {\n\t\t\t\t\tlog.error(err, `Failed to get query result for ${name}. Proceeding without caching.`);\n\t\t\t\t\treturn null;\n\t\t\t\t});\n\n\t\t\tif (fromCache != null) {\n\t\t\t\treturn fromCache.query as Result;\n\t\t\t}\n\n\t\t\tconst data = await options.resolve(args);\n\n\t\t\tawait store\n\t\t\t\t.saveQuery(\n\t\t\t\t\t{\n\t\t\t\t\t\t...tag,\n\t\t\t\t\t\targs,\n\t\t\t\t\t\tdata,\n\t\t\t\t\t\tindexes: buildIndexes(args, options.indexArgsBy),\n\t\t\t\t\t},\n\t\t\t\t\toptions.replaceExistingItems,\n\t\t\t\t\toptions.ttlMs,\n\t\t\t\t)\n\t\t\t\t.catch((err) => {\n\t\t\t\t\tlog.error(err, `Failed to save query result for ${name}. Proceeding without caching.`);\n\t\t\t\t});\n\n\t\t\treturn data;\n\t\t};\n\n\t\tconst invalidateAll = async () => {\n\t\t\tawait store.deleteQueries({\n\t\t\t\t...tag,\n\t\t\t\tindexes: [],\n\t\t\t});\n\t\t};\n\n\t\tconst invalidateByArgs = async (\n\t\t\targs: Partial<IndexedQueryArgs<Args, Indexes>> | Partial<IndexedQueryArgs<Args, Indexes>>[],\n\t\t) => {\n\t\t\tconst argsArray = Array.isArray(args) ? args : [args];\n\t\t\tconst deletePromises = argsArray.map((args) =>\n\t\t\t\tstore.deleteQueries({\n\t\t\t\t\t...tag,\n\t\t\t\t\tindexes: buildIndexes(args, options.indexArgsBy),\n\t\t\t\t}),\n\t\t\t);\n\t\t\tawait Promise.all(deletePromises);\n\t\t};\n\n\t\tconst helpers: QueryHelpersWithIndexes<Args, Indexes> = {\n\t\t\tinvalidateAll,\n\t\t\tinvalidateByArgs,\n\t\t};\n\t\tconst helpersCast: QueryHelpers<Args, Indexes> = helpers as QueryHelpers<Args, Indexes>;\n\n\t\tconst { onUpdate, onDelete, onInsert } = options;\n\n\t\tconst hooks = {\n\t\t\tonUpdate: hookWithHelpers(helpersCast, onUpdate),\n\t\t\tonInsert: hookWithHelpers(helpersCast, onInsert),\n\t\t\tonDelete: hookWithHelpers(helpersCast, onDelete),\n\t\t};\n\n\t\treturn {\n\t\t\tcall: resolve,\n\t\t\ttag,\n\t\t\thelpers,\n\t\t\thooks,\n\t\t};\n\t};\n}\n\nfunction hookWithHelpers<Helpers, Args>(\n\thelpers: Helpers,\n\thook?: (args: Args, helpers: Helpers) => void | Promise<void>,\n) {\n\tif (!hook) {\n\t\treturn undefined;\n\t}\n\tconst hookWithHelpers = async (args: Args) => {\n\t\tawait hook(args, helpers);\n\t};\n\treturn hookWithHelpers;\n}\n\nfunction buildIndexes<Args extends QueryArgs, Indexes extends QueryArgsIndexes<Args, Indexes>>(\n\targs: Partial<Args>,\n\tindexArgsBy?: Indexes,\n): QueryIndex[] {\n\tif (!indexArgsBy) {\n\t\treturn [];\n\t}\n\tconst indexes: QueryIndex[] = [];\n\tfor (const key in indexArgsBy) {\n\t\tif (!Object.hasOwn(args, key)) {\n\t\t\tcontinue;\n\t\t}\n\t\tconst value = args[key];\n\t\tif (value === undefined) {\n\t\t\tcontinue;\n\t\t}\n\t\tif (\n\t\t\ttypeof value !== 'string' &&\n\t\t\ttypeof value !== 'number' &&\n\t\t\ttypeof value !== 'boolean' &&\n\t\t\tvalue !== null\n\t\t) {\n\t\t\tthrow new TypeError(\n\t\t\t\t`Cache index '${key}' must be a primitive (string, number, boolean, or null) but received ${\n\t\t\t\t\tArray.isArray(value) ? 'array' : typeof value\n\t\t\t\t}.`,\n\t\t\t);\n\t\t}\n\t\tindexes.push([key, value]);\n\t}\n\treturn indexes;\n}\n"],"mappings":";;;;;AAmCA,IAAsB,cAAtB,MAAkC;CACjC;CAEA,YAAY,SAA8B;EACzC,KAAK,UAAU;CAChB;AAyCD;;;;;;ACpEA,SAAgB,mBAAmB,KAAuD;CACzF,IAAI,OAAO,QAAQ,YAAY,OAAO,QAAQ,YAAY,OAAO,QAAQ,UACxE,MAAM,IAAI,UACT,qFACD;AAEF;;;ACHA,SAAgB,qBAAqB,UAAmC;CACvE,OAAO,OAAO;AACf;AAEA,SAAgB,oBAAoB,IAA4B;CAC/D,OAAO,MAAM;AACd;AAEA,SAAgB,qBAAqB,MAAkC;CACtE,OAAO,MAAM,KAAK,IAAI;AACvB;AAEA,SAAgB,0BAA0B,OAAsD;CAC/F,IAAI,SAAS,MACZ,OAAO;CAER,MAAM,MAAM,MAAM;CAClB,MAAM,QAAQ,MAAM;CAEpB,OAAO,OAAO,KAAK,GAAG,IAAI,GADR,UAAU,OAAO,SAAS,IAAI,aAAa,MAAM,SAAS,CAAC,KACrC;AACzC;AAEA,SAAgB,4BAA4B,SAA+C;CAC1F,IAAI,QAAQ,WAAW,GACtB,OAAO,CAAC,MAAM;CAEf,OAAO,QAAQ,KAAK,QAAQ,0BAA0B,GAAG,CAAC;AAC3D;;;AEzCA,SAAgB,gBAAmB,OAA6C;CAC/E,IAAI,SAAS,MACZ,OAAO;CAER,OAAO,MAAM,OAAO,SAAS,QAAQ,IAAI;AAC1C;AAEA,SAAgB,mBAAsB,aAAoC,OAAY;CACrF,IAAI,YAAY,WAAW,MAAM,QAChC,OAAO;CAER,IAAI,YAAY;CAChB,MAAM,UAA2B,CAAC;CAClC,KAAK,MAAM,OAAO,aACjB,IAAI,OAAO,MACV,QAAQ,KAAK,IAAI;MAEjB,QAAQ,KAAK,MAAM,YAAY;CAGjC,OAAO;AACR;AAEA,SAAgB,QAAW,MAAoB;CAC9C,OAAO,MAAM,QAAQ,IAAI,IAAI,OAAO,CAAC,IAAI;AAC1C;AAEA,SAAgB,IAAa,QAAa,QAAa,IAA4B;CAClF,IAAI,OAAO,WAAW,OAAO,QAC5B,MAAM,IAAI,MAAM,+CAA+C;CAEhE,MAAM,SAAc,CAAC;CACrB,KAAK,IAAI,IAAI,GAAG,IAAI,OAAO,QAAQ,KAClC,OAAO,KAAK,GAAG,OAAO,IAAI,OAAO,EAAE,CAAC;CAErC,OAAO;AACR;;;ACJA,IAAa,aAAb,MAA8B;CAC7B;CACA;CACA;CAEA;CACA;CACA;CAEA;CAEA,YAAY,EACX,MACA,QACA,WACA,UACA,OACA,OACA,WACA,UAC2B;EAC3B,KAAK,OAAO;EACZ,KAAK,YAAY,aAAA;EACjB,KAAK,WAAW,UAAU,SAAS,KAAA;EACnC,KAAK,SAAS;EACd,KAAK,SAAS;EACd,KAAK,gBAAgB;GACpB,OAAO,SAAA;GACP,QAAQ,UAAkB,gBAAgB,OAAO,KAAK;GACtD,YAAY,SAAe,UAAU,IAAI;EAC1C;EACA,KAAK,iBAAiB;GACrB,OAAO,SAAA;GACP,QAAQ,UAAkB,yBAAyB,KAAK;GACxD,YAAY,SAAwB,KAAK,UAAU,IAAI;EACxD;CACD;CAEA,eAAyB,OAAO,SAA8D;EAC7F,MAAM,OAAO,KAAK,KAAK,QAAQ,KAAK,gBAAgB,GAAG,CAAC;EACxD,OAAO,MAAM,KAAK,OAAO,gBAAgB,MAAM,KAAK,aAAa;CAClE;CAEA,SAAmB,IAAI,WAAiC,KAAK,cAAc,EAC1E,OAAO,MACR,CAAC;CAED,MAAM,IAAI,KAAoC;EAC7C,OAAO,MAAM,KAAK,OAAO,KAAK,GAAG;CAClC;CAEA,MAAM,QAAQ,MAAyC;EACtD,MAAM,UAAU,MAAM,QAAQ,IAAI,KAAK,KAAK,MAAM,KAAK,IAAI,CAAC,CAAC,CAAC;EAC9D,IAAI,CAAC,gBAAgB,OAAO,GAC3B,OAAO;EAER,OAAO;CACR;CAEA,MAAM,WAAW,MAA8C;EAC9D,OAAO,MAAM,QAAQ,IAAI,KAAK,KAAK,QAAQ,KAAK,IAAI,GAAG,CAAC,CAAC;CAC1D;CAEA,MAAM,KAAK,MAAqB;EAE/B,MAAM,UADS,QAAQ,IAC2B,CAAC,CAAC,KAAK,SAAS,CACjE,KAAK,WAAW,IAAI,GACpB,IACD,CAAC;EACD,OAAO,MAAM,KAAK,OAAO,UAAU,SAAS,KAAK,aAAa;CAC/D;CAEA,MAAM,gBAAgB,MAAqB;EAE1C,MAAM,UADS,QAAQ,IAC2B,CAAC,CAAC,KAAK,SAAS,CACjE,KAAK,WAAW,IAAI,GACpB,IACD,CAAC;EACD,OAAO,MAAM,KAAK,OAAO,UAAU,SAAS,KAAK,eAAe,EAC/D,kBAAkB,KACnB,CAAC;CACF;CAEA,MAAM,aAAa,MAAkD;EAEpE,MAAM,UADS,QAAQ,IAC2B,CAAC,CAAC,KAAK,SAAS,CACjE,KAAK,WAAW,IAAI,GACpB,IACD,CAAC;EACD,OAAO,MAAM,KAAK,OAAO,kBAAkB,SAAS,KAAK,aAAa;CACvE;CAEA,MAAM,OAAO,KAA0B;EAEtC,MAAM,OADO,QAAQ,GACL,CAAC,CAAC,KAAK,MAAM,KAAK,gBAAgB,CAAC,CAAC;EACpD,MAAM,KAAK,OAAO,YAAY,MAAM,KAAK,aAAa;CACvD;CAEA,MAAM,eAAe,KAAuD;EAE3E,MAAM,OADO,QAAQ,GACL,CAAC,CAAC,KAAK,MAAM,KAAK,gBAAgB,CAAC,CAAC;EACpD,OAAO,MAAM,KAAK,OAAO,oBAAoB,MAAM,KAAK,aAAa;CACtE;CAEA,MAAM,SAAS,OAA6D;EAC3E,MAAM,WAAW,KAAK,YAAY,KAAK;EACvC,MAAM,OAAO,MAAM,KAAK,OAAO,SAAS,UAAU,KAAK,cAAc;EAErE,IAAI,QAAQ,MACX,OAAO;EAGR,MAAM,SAAS,KAAK;EACpB,MAAM,eAAe,KAAK;EAC1B,MAAM,OAAO,aAAa,QAAQ,QAAQ,OAAO,IAAI;EACrD,MAAM,QAAQ,MAAM,KAAK,QAAQ,IAAI;EAErC,IAAI,SAAS,MACZ,OAAO;EAGR,MAAM,UAAU,mBAAmB,cAAc,KAAK;EAGtD,OAAO,EAAE,OAFM,SAAS,UAAW,QAAQ,GAAG,CAAC,KAAK,KAE7B;CACxB;CAEA,MAAM,UACL,OACA,uBAAuB,OACvB,OACgB;EAChB,MAAM,OAAO,MAAM;EACnB,MAAM,WAAW,KAAK,YAAY,KAAK;EACvC,MAAM,eAAe,KAAK,gBAAgB,OAAO,IAAI;EAErD,MAAM,SAAS,MAAM,QAAQ,IAAI;EACjC,MAAM,gBAAgB,SAAS,OAAO,CAAC,IAAI;EAC3C,MAAM,QAAQ,cAAc,QAAQ,SAAS,QAAQ,IAAI;EAEzD,IAAI,MAAM,SAAS,GAClB,IAAI,sBACH,MAAM,KAAK,KAAK,KAAK;OAErB,MAAM,KAAK,gBAAgB,KAAK;EAWlC,MAAM,WAAW;GAChB,MARmB,cAAc,KAAK,SAAS;IAC/C,IAAI,QAAQ,MACX,OAAO;IAER,OAAO,KAAK,mBAAmB,IAAI,CAAC,CAAC,SAAS;GAC/C,CAGiB;GAChB;EACD;EAEA,OAAO,MAAM,KAAK,OAAO,UAAU,UAAU,cAAc,UAAU;GACpE,GAAG,KAAK;GACR,OAAO,SAAS,KAAK,eAAe;EACrC,CAAC;CACF;CAEA,cAAc,OAA2C;EACxD,MAAM,eAAe,KAAK,gBAAgB,KAAK;EAC/C,OAAO,KAAK,OAAO,cAAc,cAAc,KAAK,cAAc;CACnE;CAEA,mBAAmB,MAAqB;EACvC,IAAI,KAAK,QACR,OAAO,KAAK,OAAO,IAAI;EAExB,IAAI,QAAQ,MACX,MAAM,IAAI,MAAM,6CAA6C;EAE9D,IAAI,OAAO,SAAS,YAAY,QAAQ,MAAM;GAC7C,mBAAmB,KAAK,EAAE;GAC1B,OAAO,KAAK,GAAG,SAAS;EACzB;EACA,MAAM,IAAI,MAAM,sEAAoE;CACrF;CAEA,WAAW,MAA0B;EACpC,MAAM,MAAM,KAAK,mBAAmB,IAAI;EACxC,OAAO,KAAK,gBAAgB,GAAG;CAChC;CAEA,gBAAgB,KAA4B;EAG3C,OAAO,GAAG,GAF4B,KAAK,UAAU,IAAI,KAAK,KAAK,QAAQ,qBAAqB,KAAK,QAAQ,EAAE,GAE9F,GADH,oBAAoB,IAAI,SAAS,CACvB;CACzB;CAEA,YAAY,OAAwC;EAEnD,OAAO,GADQ,KAAK,kBAAkB,KACvB,EAAE,GAAG,qBAAqB,MAAM,IAAI;CACpD;CAEA,gBAAgB,OAA4B,iBAAiB,OAA6B;EACzF,MAAM,SAAS,KAAK,kBAAkB,KAAK;EAC3C,MAAM,aAAa,4BAA4B,MAAM,OAAO;EAC5D,IAAI,kBAAkB,MAAM,QAAQ,SAAS,GAC5C,WAAW,KAAK,0BAA0B,CAAC;EAE5C,OAAO,WAAW,KAAK,aAAa,GAAG,OAAO,GAAG,UAAmB;CACrE;CAEA,kBAAkB,OAAsC;EACvD,OAAO,GAAG,KAAK,UAAU,IAAI,KAAK,KAAK,SAAS,MAAM,KAAK,GAAG,KAAK,oBAAoB,KAAK,EAAE;CAC/F;CAEA,oBAAoB,OAAkC;EAErD,OAAO,qBAAqB,GADA,KAAK,SAAS,GAAG,MAAM,UAAU,SAAS,KAAA,WAC1B;CAC7C;AACD;AAEA,SAAS,gBAAmB,OAAe,WAA2C;CACrF,IAAI;EACH,OAAO,UAAU,KAAK;CACvB,SAAS,KAAK;EACb,IAAI,KAAK,KAAK,sCAAsC;EACpD,OAAO;CACR;AACD;AAEA,SAAS,yBAAyB,OAAqC;CACtE,IAAI;CACJ,IAAI;EACH,SAAS,KAAK,MAAM,KAAK;CAC1B,SAAS,KAAK;EACb,IAAI,KAAK,KAAK,wDAAwD;EACtE,OAAO;CACR;CACA,IAAI,CAAC,qBAAqB,MAAM,GAAG;EAClC,IAAI,KAAK,0DAA0D;EACnE,OAAO;CACR;CACA,OAAO;AACR;AAEA,SAAS,qBAAqB,OAAwC;CACrE,IAAI,SAAS,QAAQ,OAAO,UAAU,UACrC,OAAO;CAER,MAAM,YAAY;CAClB,IAAI,CAAC,MAAM,QAAQ,UAAU,IAAI,GAChC,OAAO;CAER,IAAI,OAAO,UAAU,WAAW,WAC/B,OAAO;CAER,OAAO,UAAU,KAAK,OAAO,QAAQ,QAAQ,QAAQ,OAAO,QAAQ,QAAQ;AAC7E;;;AC5OA,SAAgB,YACf,QACA,SAC2B;CAC3B,MAAM,cAAc,IAAI,WAAiB;EACxC;EACA,MAAM,QAAQ;EACd,OAAO,QAAQ;EACf,WAAW,QAAQ;EACnB,QAAQ,QAAQ;EAChB,OAAO,QAAQ,SAAS,OAAO,SAAS;EACxC,WAAW,QAAQ,aAAa,OAAO,SAAS;EAChD,UAAU,QAAQ,YAAY,OAAO,SAAS;CAC/C,CAAC;CACD,OAAO;EACN,aACC,mBACC,aACA;GACC,cAAc,QAAQ;GACtB,cAAc,QAAQ;GACtB,cAAc,QAAQ;EACvB,GACA;GACC,eAAe,CAAC;GAChB,eAAe,CAAC;GAChB,eAAe,CAAC;EACjB,CACD;EACD,cAAc,gBAAgB;GAC7B,OAAO,EACN,aAAa,8BAA8B,aAAa,SAAS,WAAW,EAC7E;EACD;CACD;AACD;AAEA,SAAS,mBACR,aACA,WAKA,YAK+E;CAC/E,OAAO;EACN,MAAM,QAAQ,YAAY,IAAI,GAAG;EACjC,UAAU,SAAS,YAAY,QAAQ,IAAI;EAC3C,aAAa,SAAS,YAAY,WAAW,IAAI;EACjD,QAAQ,OAAO,MAAM,YAAY;GAChC,IAAI,WAAW,cAAc,WAAW,GAAG;IAC1C,MAAM,YAAY,KAAK,IAAI;IAC3B,MAAM,SAAS,UAAU,cAAc,QAAQ,IAAI,GAAG,OAAO;GAC9D,OAAO;IACN,MAAM,QAAQ,QAAQ,IAAI;IAE1B,MAAM,QAAQ,IAAI,OAAO,MADF,YAAY,aAAa,KAAK,IACjB,MAAM,cAAc;KAAE;KAAM;IAAS,EAAE;IAC3E,MAAM,QAAQ,IAAI,CACjB,SAAS,UAAU,cAAc,OAAO,OAAO,GAC/C,UAAU,WAAW,eAAe,OAAO,OAAO,CACnD,CAAC;GACF;EACD;EACA,QAAQ,OAAO,MAAM,YAAY;GAChC,MAAM,YAAY,KAAK,IAAI;GAC3B,IAAI,WAAW,cAAc,WAAW,GACvC,MAAM,SAAS,UAAU,cAAc,QAAQ,IAAI,GAAG,OAAO;QACvD;IACN,MAAM,QAAQ,QAAQ,IAAI;IAC1B,MAAM,QAAQ,IAAI,CACjB,SAAS,UAAU,cAAc,OAAO,OAAO,GAC/C,UAAU,WAAW,eAAe,OAAO,OAAO,CACnD,CAAC;GACF;EACD;EACA,QAAQ,OAAO,KAAK,YAAY;GAC/B,IAAI,WAAW,cAAc,WAAW,GAAG;IAC1C,MAAM,YAAY,OAAO,GAAG;IAC5B,MAAM,SAAS,UAAU,cAAc,QAAQ,GAAG,GAAG,OAAO;GAC7D,OAAO;IACN,MAAM,OAAO,QAAQ,GAAG;IACxB,MAAM,WAAW,MAAM,YAAY,eAAe,IAAI;IACtD,MAAM,YAAY,OAAO,IAAI;IAC7B,MAAM,QAAQ,IAAI,MAAM,WAAW,KAAK,cAAc;KAAE;KAAK;IAAS,EAAE;IACxE,MAAM,QAAQ,IAAI,CACjB,SAAS,UAAU,cAAc,MAAM,OAAO,GAC9C,UAAU,WAAW,eAAe,OAAO,OAAO,CACnD,CAAC;GACF;EACD;CACD;AACD;AAEA,SAAS,8BACR,aACA,SACA,aAC2C;CAC3C,MAAM,EAAE,SAAS,WAAW,eAAe,eAAe,kBAAkB,sBAG1E,aAAa,WAAW;CAC1B,OAAO;EACN,GAAG,mBACF,aACA;GACC,cAAc,QAAQ;GACtB,cAAc,QAAQ;GACtB,cAAc,QAAQ;EACvB,GACA;GAAE;GAAe;GAAe;EAAc,CAC/C;EACA,eAAe,YAAY;GAC1B,MAAM,WAAW,UAAU,KAAK,QAC/B,YAAY,cAAc;IACzB,GAAG;IACH,SAAS,CAAC;GACX,CAAC,CACF;GACA,MAAM,QAAQ,IAAI,QAAQ;EAC3B;EACA;CACD;AACD;AAEA,SAAS,sBACR,aACA,OACC;CACD,MAAM,UAAqD,CAAC;CAC5D,MAAM,YAAwB,CAAC;CAC/B,MAAM,gBAAgD,CAAC;CACvD,MAAM,gBAAgD,CAAC;CACvD,MAAM,gBAAgD,CAAC;CACvD,KAAK,MAAM,CAAC,WAAW,eAAe,OAAO,QAAQ,eAAe,CAAC,CAAC,GAAG;EACxE,MAAM,eAAe,WAAW,OAAO,SAAS;EAChD,QAAQ,aAAuC,aAAa;EAG5D,UAAU,KAAK,aAAa,GAAG;EAC/B,IAAI,aAAa,MAAM,UACtB,cAAc,KAAK,aAAa,MAAM,QAAQ;EAE/C,IAAI,aAAa,MAAM,UACtB,cAAc,KAAK,aAAa,MAAM,QAAQ;EAE/C,IAAI,aAAa,MAAM,UACtB,cAAc,KAAK,aAAa,MAAM,QAAQ;CAEhD;CACA,OAAO;EACG;EACT;EACA;EACA;EACA;CACD;AACD;AAEA,eAAe,SACd,MACA,OACA,SACC;CACD,IAAI,QAAQ,MACX;CAED,IAAI,SAAS,cACZ,MAAM,KAAK,KAAK;MAEhB,QAAQ,QAAQ,CAAC,CACf,WAAW,KAAK,KAAK,CAAC,CAAC,CACvB,OAAO,QAAQ;EACf,IAAI,MAAM,KAAK,qBAAqB;CACrC,CAAC;AAEJ;AAEA,eAAe,UACd,OACA,OACA,SACC;CACD,MAAM,QAAQ,IAAI,MAAM,KAAK,SAAS,SAAS,MAAM,OAAO,OAAO,CAAC,CAAC;AACtE;;;AC9MA,SAAgB,YAKd,SAA+F;CAChG,QAAQ,OAAyB,SAAiB;EACjD,MAAM,MAAgB;GACrB;GACA,UAAU,QAAQ;EACnB;EAEA,MAAM,UAAU,OAAO,SAAgC;GACtD,MAAM,YAAY,MAAM,MACtB,SAAS;IACT,GAAG;IACH;GACD,CAAC,CAAC,CACD,OAAO,QAAQ;IACf,IAAI,MAAM,KAAK,kCAAkC,KAAK,8BAA8B;IACpF,OAAO;GACR,CAAC;GAEF,IAAI,aAAa,MAChB,OAAO,UAAU;GAGlB,MAAM,OAAO,MAAM,QAAQ,QAAQ,IAAI;GAEvC,MAAM,MACJ,UACA;IACC,GAAG;IACH;IACA;IACA,SAAS,aAAa,MAAM,QAAQ,WAAW;GAChD,GACA,QAAQ,sBACR,QAAQ,KACT,CAAC,CACA,OAAO,QAAQ;IACf,IAAI,MAAM,KAAK,mCAAmC,KAAK,8BAA8B;GACtF,CAAC;GAEF,OAAO;EACR;EAEA,MAAM,gBAAgB,YAAY;GACjC,MAAM,MAAM,cAAc;IACzB,GAAG;IACH,SAAS,CAAC;GACX,CAAC;EACF;EAEA,MAAM,mBAAmB,OACxB,SACI;GAEJ,MAAM,kBADY,MAAM,QAAQ,IAAI,IAAI,OAAO,CAAC,IAAI,EAAA,CACnB,KAAK,SACrC,MAAM,cAAc;IACnB,GAAG;IACH,SAAS,aAAa,MAAM,QAAQ,WAAW;GAChD,CAAC,CACF;GACA,MAAM,QAAQ,IAAI,cAAc;EACjC;EAEA,MAAM,UAAkD;GACvD;GACA;EACD;EACA,MAAM,cAA2C;EAEjD,MAAM,EAAE,UAAU,UAAU,aAAa;EAQzC,OAAO;GACN,MAAM;GACN;GACA;GACA,OAAA;IATA,UAAU,gBAAgB,aAAa,QAAQ;IAC/C,UAAU,gBAAgB,aAAa,QAAQ;IAC/C,UAAU,gBAAgB,aAAa,QAAQ;GAO3C;EACL;CACD;AACD;AAEA,SAAS,gBACR,SACA,MACC;CACD,IAAI,CAAC,MACJ;CAED,MAAM,kBAAkB,OAAO,SAAe;EAC7C,MAAM,KAAK,MAAM,OAAO;CACzB;CACA,OAAO;AACR;AAEA,SAAS,aACR,MACA,aACe;CACf,IAAI,CAAC,aACJ,OAAO,CAAC;CAET,MAAM,UAAwB,CAAC;CAC/B,KAAK,MAAM,OAAO,aAAa;EAC9B,IAAI,CAAC,OAAO,OAAO,MAAM,GAAG,GAC3B;EAED,MAAM,QAAQ,KAAK;EACnB,IAAI,UAAU,KAAA,GACb;EAED,IACC,OAAO,UAAU,YACjB,OAAO,UAAU,YACjB,OAAO,UAAU,aACjB,UAAU,MAEV,MAAM,IAAI,UACT,gBAAgB,IAAI,wEACnB,MAAM,QAAQ,KAAK,IAAI,UAAU,OAAO,MACxC,EACF;EAED,QAAQ,KAAK,CAAC,KAAK,KAAK,CAAC;CAC1B;CACA,OAAO;AACR"}
|
package/dist/sdk/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../sdk/batch.ts"],"sourcesContent":["export async function doBatched<T>(\n\titems: T[],\n\tbatchSize: number,\n\tfn: (batch: T[]) => Promise<void>,\n): Promise<void> {\n\tfor (let i = 0; i < items.length; i += batchSize) {\n\t\tconst batch = items.slice(i, i + batchSize);\n\t\tawait fn(batch);\n\t}\n}\n"],"mappings":";AAAA,eAAsB,UACrB,OACA,WACA,IACgB;
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../sdk/batch.ts"],"sourcesContent":["export async function doBatched<T>(\n\titems: T[],\n\tbatchSize: number,\n\tfn: (batch: T[]) => Promise<void>,\n): Promise<void> {\n\tfor (let i = 0; i < items.length; i += batchSize) {\n\t\tconst batch = items.slice(i, i + batchSize);\n\t\tawait fn(batch);\n\t}\n}\n"],"mappings":";AAAA,eAAsB,UACrB,OACA,WACA,IACgB;CAChB,KAAK,IAAI,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK,WAEtC,MAAM,GADQ,MAAM,MAAM,GAAG,IAAI,SACpB,CAAC;AAEhB"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@baeta/cache",
|
|
3
|
-
"version": "2.0.0-next.
|
|
3
|
+
"version": "2.0.0-next.16",
|
|
4
|
+
"description": "Type-safe caching for Baeta.",
|
|
4
5
|
"keywords": [
|
|
5
6
|
"baeta",
|
|
6
7
|
"builder",
|
|
@@ -21,14 +22,14 @@
|
|
|
21
22
|
},
|
|
22
23
|
"repository": {
|
|
23
24
|
"type": "git",
|
|
24
|
-
"url": "https://github.com/andreisergiu98/baeta.git",
|
|
25
|
+
"url": "git+https://github.com/andreisergiu98/baeta.git",
|
|
25
26
|
"directory": "packages/cache"
|
|
26
27
|
},
|
|
27
28
|
"files": [
|
|
28
|
-
"dist"
|
|
29
|
-
"package.json"
|
|
29
|
+
"dist"
|
|
30
30
|
],
|
|
31
31
|
"type": "module",
|
|
32
|
+
"sideEffects": false,
|
|
32
33
|
"types": "dist/index.d.ts",
|
|
33
34
|
"exports": {
|
|
34
35
|
".": {
|
|
@@ -41,7 +42,6 @@
|
|
|
41
42
|
}
|
|
42
43
|
},
|
|
43
44
|
"publishConfig": {
|
|
44
|
-
"access": "public",
|
|
45
45
|
"exports": {
|
|
46
46
|
".": {
|
|
47
47
|
"types": "./dist/index.d.ts",
|
|
@@ -51,19 +51,20 @@
|
|
|
51
51
|
"types": "./dist/sdk/index.d.ts",
|
|
52
52
|
"default": "./dist/sdk/index.js"
|
|
53
53
|
}
|
|
54
|
-
}
|
|
54
|
+
},
|
|
55
|
+
"access": "public"
|
|
55
56
|
},
|
|
56
57
|
"scripts": {
|
|
57
58
|
"build": "builder build",
|
|
58
59
|
"check:deps": "builder check-deps",
|
|
59
60
|
"postpack": "builder prepare --restore",
|
|
60
61
|
"prepack": "builder prepare",
|
|
61
|
-
"test": "builder test
|
|
62
|
+
"test": "builder test",
|
|
62
63
|
"types": "tsc --noEmit"
|
|
63
64
|
},
|
|
64
65
|
"dependencies": {
|
|
65
|
-
"@baeta/util-encoding": "^2.0.0-next.
|
|
66
|
-
"@baeta/util-log": "^2.0.0-next.
|
|
66
|
+
"@baeta/util-encoding": "^2.0.0-next.5",
|
|
67
|
+
"@baeta/util-log": "^2.0.0-next.5",
|
|
67
68
|
"dataloader": "^2.2.3",
|
|
68
69
|
"ohash": "^2.0.11"
|
|
69
70
|
},
|
|
@@ -79,7 +80,7 @@
|
|
|
79
80
|
]
|
|
80
81
|
},
|
|
81
82
|
"engines": {
|
|
82
|
-
"node": "
|
|
83
|
+
"node": "^22.20.0 || ^24.0.0 || >=26.0.0"
|
|
83
84
|
},
|
|
84
85
|
"typedocOptions": {
|
|
85
86
|
"entryPoints": [
|