@getstrata/core 0.5.15 → 0.5.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.
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { Policy } from "../../core/auth/policy";
|
|
2
|
+
import type { RouteRequest } from "../../core/http/route";
|
|
3
|
+
interface RouteModelAuthorization {
|
|
4
|
+
resource: string;
|
|
5
|
+
action: keyof Policy;
|
|
6
|
+
requireIfMatch?: boolean;
|
|
7
|
+
}
|
|
8
|
+
declare function securedBindRouteModel<TParams extends Record<string, string>, TModel, TParam extends keyof TParams & string>(param: TParam, resolver: (id: number, request: RouteRequest<TParams>) => Promise<TModel>, authorization: RouteModelAuthorization, handler: (request: RouteRequest<TParams>, model: TModel) => Response | Promise<Response>): (request: RouteRequest<TParams>) => Promise<Response>;
|
|
9
|
+
declare function securedBindRouteModelByKey<TParams extends Record<string, string>, TModel, TParam extends keyof TParams & string>(param: TParam, resolver: (key: string, request: RouteRequest<TParams>) => Promise<TModel>, authorization: RouteModelAuthorization, handler: (request: RouteRequest<TParams>, model: TModel) => Response | Promise<Response>): (request: RouteRequest<TParams>) => Promise<Response>;
|
|
10
|
+
export type { RouteModelAuthorization };
|
|
11
|
+
export { securedBindRouteModel, securedBindRouteModelByKey };
|
|
@@ -1,11 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
interface RouteModelAuthorization {
|
|
4
|
-
resource: string;
|
|
5
|
-
action: keyof Policy;
|
|
6
|
-
requireIfMatch?: boolean;
|
|
7
|
-
}
|
|
8
|
-
declare function securedBindRouteModel<TParams extends Record<string, string>, TModel, TParam extends keyof TParams & string>(param: TParam, resolver: (id: number, request: RouteRequest<TParams>) => Promise<TModel>, authorization: RouteModelAuthorization, handler: (request: RouteRequest<TParams>, model: TModel) => Response | Promise<Response>): (request: RouteRequest<TParams>) => Promise<Response>;
|
|
9
|
-
declare function securedBindRouteModelByKey<TParams extends Record<string, string>, TModel, TParam extends keyof TParams & string>(param: TParam, resolver: (key: string, request: RouteRequest<TParams>) => Promise<TModel>, authorization: RouteModelAuthorization, handler: (request: RouteRequest<TParams>, model: TModel) => Response | Promise<Response>): (request: RouteRequest<TParams>) => Promise<Response>;
|
|
10
|
-
export type { RouteModelAuthorization };
|
|
11
|
-
export { securedBindRouteModel, securedBindRouteModelByKey };
|
|
1
|
+
export type { RouteModelAuthorization } from "../../bootstrap/http/securedRouteModelBinding.ts";
|
|
2
|
+
export { securedBindRouteModel, securedBindRouteModelByKey, } from "../../bootstrap/http/securedRouteModelBinding.ts";
|
|
@@ -0,0 +1,376 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
// ../../src/core/cache/redisCacheStore.ts
|
|
3
|
+
var {RedisClient } = globalThis.Bun;
|
|
4
|
+
var KEY_PREFIX = "workhub:cache:";
|
|
5
|
+
var TAG_PREFIX = "workhub:cache:tag:";
|
|
6
|
+
|
|
7
|
+
class RedisCacheStore {
|
|
8
|
+
ttlMs;
|
|
9
|
+
maxEntries;
|
|
10
|
+
client;
|
|
11
|
+
inflight = new Map;
|
|
12
|
+
keyTags = new Map;
|
|
13
|
+
constructor(redisUrl, ttlMs, maxEntries) {
|
|
14
|
+
this.ttlMs = ttlMs;
|
|
15
|
+
this.maxEntries = maxEntries;
|
|
16
|
+
this.client = new RedisClient(redisUrl);
|
|
17
|
+
}
|
|
18
|
+
async get(key) {
|
|
19
|
+
const raw = await this.client.get(this.storageKey(key));
|
|
20
|
+
if (raw === null) {
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
return JSON.parse(raw);
|
|
24
|
+
}
|
|
25
|
+
async set(key, value, ttlMs) {
|
|
26
|
+
const resolvedTtlMs = ttlMs ?? this.ttlMs;
|
|
27
|
+
const payload = JSON.stringify(value);
|
|
28
|
+
if (resolvedTtlMs > 0) {
|
|
29
|
+
await this.client.psetex(this.storageKey(key), resolvedTtlMs, payload);
|
|
30
|
+
} else {
|
|
31
|
+
await this.client.set(this.storageKey(key), payload);
|
|
32
|
+
}
|
|
33
|
+
await this.enforceMaxEntries();
|
|
34
|
+
}
|
|
35
|
+
async getOrSet(key, loader, ttlMs) {
|
|
36
|
+
const cached = await this.get(key);
|
|
37
|
+
if (cached !== undefined) {
|
|
38
|
+
return cached;
|
|
39
|
+
}
|
|
40
|
+
const inflightRequest = this.inflight.get(key);
|
|
41
|
+
if (inflightRequest) {
|
|
42
|
+
return inflightRequest;
|
|
43
|
+
}
|
|
44
|
+
const pendingRequest = loader().then(async (value) => {
|
|
45
|
+
await this.set(key, value, ttlMs);
|
|
46
|
+
return value;
|
|
47
|
+
}).finally(() => {
|
|
48
|
+
this.inflight.delete(key);
|
|
49
|
+
});
|
|
50
|
+
this.inflight.set(key, pendingRequest);
|
|
51
|
+
return pendingRequest;
|
|
52
|
+
}
|
|
53
|
+
async attachTags(key, tags) {
|
|
54
|
+
if (tags.length === 0) {
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
let tagsForKey = this.keyTags.get(key);
|
|
58
|
+
if (!tagsForKey) {
|
|
59
|
+
tagsForKey = new Set;
|
|
60
|
+
this.keyTags.set(key, tagsForKey);
|
|
61
|
+
}
|
|
62
|
+
for (const tag of tags) {
|
|
63
|
+
tagsForKey.add(tag);
|
|
64
|
+
await this.client.sadd(this.tagKey(tag), key);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
async flushTags(tags) {
|
|
68
|
+
const keysToRemove = new Set;
|
|
69
|
+
for (const tag of tags) {
|
|
70
|
+
const members = await this.client.smembers(this.tagKey(tag));
|
|
71
|
+
for (const member of members) {
|
|
72
|
+
keysToRemove.add(member);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
let removed = 0;
|
|
76
|
+
for (const key of keysToRemove) {
|
|
77
|
+
if (await this.invalidate(key)) {
|
|
78
|
+
removed += 1;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
for (const tag of tags) {
|
|
82
|
+
await this.client.del(this.tagKey(tag));
|
|
83
|
+
}
|
|
84
|
+
return removed;
|
|
85
|
+
}
|
|
86
|
+
async invalidate(key) {
|
|
87
|
+
const deleted = await this.client.del(this.storageKey(key));
|
|
88
|
+
await this.detachKeyFromTags(key);
|
|
89
|
+
return deleted > 0;
|
|
90
|
+
}
|
|
91
|
+
async invalidateByPrefix(prefix) {
|
|
92
|
+
const keys = await this.client.keys(`${KEY_PREFIX}*`);
|
|
93
|
+
let removed = 0;
|
|
94
|
+
for (const storageKey of keys) {
|
|
95
|
+
const key = storageKey.slice(KEY_PREFIX.length);
|
|
96
|
+
if (key === prefix || key.startsWith(`${prefix}?`)) {
|
|
97
|
+
if (await this.invalidate(key)) {
|
|
98
|
+
removed += 1;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
return removed;
|
|
103
|
+
}
|
|
104
|
+
async clear() {
|
|
105
|
+
const keys = await this.client.keys(`${KEY_PREFIX}*`);
|
|
106
|
+
if (keys.length > 0) {
|
|
107
|
+
await this.client.del(...keys);
|
|
108
|
+
}
|
|
109
|
+
const tagKeys = await this.client.keys(`${TAG_PREFIX}*`);
|
|
110
|
+
if (tagKeys.length > 0) {
|
|
111
|
+
await this.client.del(...tagKeys);
|
|
112
|
+
}
|
|
113
|
+
this.inflight.clear();
|
|
114
|
+
this.keyTags.clear();
|
|
115
|
+
}
|
|
116
|
+
async size() {
|
|
117
|
+
const keys = await this.client.keys(`${KEY_PREFIX}*`);
|
|
118
|
+
return keys.length;
|
|
119
|
+
}
|
|
120
|
+
storageKey(key) {
|
|
121
|
+
return `${KEY_PREFIX}${key}`;
|
|
122
|
+
}
|
|
123
|
+
tagKey(tag) {
|
|
124
|
+
return `${TAG_PREFIX}${tag}`;
|
|
125
|
+
}
|
|
126
|
+
async detachKeyFromTags(key) {
|
|
127
|
+
const tags = this.keyTags.get(key);
|
|
128
|
+
if (!tags) {
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
for (const tag of tags) {
|
|
132
|
+
await this.client.srem(this.tagKey(tag), key);
|
|
133
|
+
}
|
|
134
|
+
this.keyTags.delete(key);
|
|
135
|
+
}
|
|
136
|
+
async enforceMaxEntries() {
|
|
137
|
+
const keys = await this.client.keys(`${KEY_PREFIX}*`);
|
|
138
|
+
if (keys.length <= this.maxEntries) {
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
const overflow = keys.length - this.maxEntries;
|
|
142
|
+
const keysToRemove = keys.slice(0, overflow);
|
|
143
|
+
if (keysToRemove.length > 0) {
|
|
144
|
+
await this.client.del(...keysToRemove);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
var redisCacheStore_default = RedisCacheStore;
|
|
149
|
+
|
|
150
|
+
// ../../src/core/cache/simpleCache.ts
|
|
151
|
+
class SimpleCache {
|
|
152
|
+
ttlMs;
|
|
153
|
+
maxEntries;
|
|
154
|
+
cache = new Map;
|
|
155
|
+
inflight = new Map;
|
|
156
|
+
tagIndex = new Map;
|
|
157
|
+
keyTags = new Map;
|
|
158
|
+
constructor(ttlMs = 3600000, maxEntries = 100) {
|
|
159
|
+
this.ttlMs = ttlMs;
|
|
160
|
+
this.maxEntries = maxEntries;
|
|
161
|
+
if (!Number.isFinite(ttlMs) || ttlMs < 0) {
|
|
162
|
+
throw new RangeError("ttlMs must be a non-negative number.");
|
|
163
|
+
}
|
|
164
|
+
if (!Number.isInteger(maxEntries) || maxEntries < 1) {
|
|
165
|
+
throw new RangeError("maxEntries must be a positive integer.");
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
get(key) {
|
|
169
|
+
return this.getFreshEntry(key)?.value;
|
|
170
|
+
}
|
|
171
|
+
set(key, value, ttlMs) {
|
|
172
|
+
const now = Date.now();
|
|
173
|
+
const resolvedTtlMs = ttlMs ?? this.ttlMs;
|
|
174
|
+
this.cache.set(key, {
|
|
175
|
+
value,
|
|
176
|
+
expiresAt: now + resolvedTtlMs,
|
|
177
|
+
lastAccessedAt: now
|
|
178
|
+
});
|
|
179
|
+
this.evictOverflow();
|
|
180
|
+
}
|
|
181
|
+
async getOrSet(key, loader, ttlMs) {
|
|
182
|
+
this.pruneExpired();
|
|
183
|
+
const cachedEntry = this.getFreshEntry(key);
|
|
184
|
+
if (cachedEntry) {
|
|
185
|
+
return cachedEntry.value;
|
|
186
|
+
}
|
|
187
|
+
const inflightRequest = this.inflight.get(key);
|
|
188
|
+
if (inflightRequest) {
|
|
189
|
+
return inflightRequest;
|
|
190
|
+
}
|
|
191
|
+
const pendingRequest = loader().then((value) => {
|
|
192
|
+
this.set(key, value, ttlMs);
|
|
193
|
+
return value;
|
|
194
|
+
}).finally(() => {
|
|
195
|
+
this.inflight.delete(key);
|
|
196
|
+
});
|
|
197
|
+
this.inflight.set(key, pendingRequest);
|
|
198
|
+
return pendingRequest;
|
|
199
|
+
}
|
|
200
|
+
attachTags(key, tags) {
|
|
201
|
+
if (tags.length === 0) {
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
let tagsForKey = this.keyTags.get(key);
|
|
205
|
+
if (!tagsForKey) {
|
|
206
|
+
tagsForKey = new Set;
|
|
207
|
+
this.keyTags.set(key, tagsForKey);
|
|
208
|
+
}
|
|
209
|
+
for (const tag of tags) {
|
|
210
|
+
tagsForKey.add(tag);
|
|
211
|
+
let keysForTag = this.tagIndex.get(tag);
|
|
212
|
+
if (!keysForTag) {
|
|
213
|
+
keysForTag = new Set;
|
|
214
|
+
this.tagIndex.set(tag, keysForTag);
|
|
215
|
+
}
|
|
216
|
+
keysForTag.add(key);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
flushTags(tags) {
|
|
220
|
+
const keysToRemove = new Set;
|
|
221
|
+
for (const tag of tags) {
|
|
222
|
+
const keys = this.tagIndex.get(tag);
|
|
223
|
+
if (!keys) {
|
|
224
|
+
continue;
|
|
225
|
+
}
|
|
226
|
+
for (const key of keys) {
|
|
227
|
+
keysToRemove.add(key);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
let removed = 0;
|
|
231
|
+
for (const key of keysToRemove) {
|
|
232
|
+
if (this.invalidate(key)) {
|
|
233
|
+
removed += 1;
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
for (const tag of tags) {
|
|
237
|
+
this.tagIndex.delete(tag);
|
|
238
|
+
}
|
|
239
|
+
return removed;
|
|
240
|
+
}
|
|
241
|
+
invalidate(key) {
|
|
242
|
+
const removed = this.cache.delete(key);
|
|
243
|
+
if (removed) {
|
|
244
|
+
this.detachKeyFromTags(key);
|
|
245
|
+
}
|
|
246
|
+
return removed;
|
|
247
|
+
}
|
|
248
|
+
invalidateByPrefix(prefix) {
|
|
249
|
+
let removed = 0;
|
|
250
|
+
for (const key of [...this.cache.keys()]) {
|
|
251
|
+
if (key === prefix || key.startsWith(`${prefix}?`)) {
|
|
252
|
+
if (this.invalidate(key)) {
|
|
253
|
+
removed += 1;
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
return removed;
|
|
258
|
+
}
|
|
259
|
+
clear() {
|
|
260
|
+
this.cache.clear();
|
|
261
|
+
this.inflight.clear();
|
|
262
|
+
this.tagIndex.clear();
|
|
263
|
+
this.keyTags.clear();
|
|
264
|
+
}
|
|
265
|
+
size() {
|
|
266
|
+
this.pruneExpired();
|
|
267
|
+
return this.cache.size;
|
|
268
|
+
}
|
|
269
|
+
detachKeyFromTags(key) {
|
|
270
|
+
const tags = this.keyTags.get(key);
|
|
271
|
+
if (!tags) {
|
|
272
|
+
return;
|
|
273
|
+
}
|
|
274
|
+
for (const tag of tags) {
|
|
275
|
+
const keys = this.tagIndex.get(tag);
|
|
276
|
+
if (!keys) {
|
|
277
|
+
continue;
|
|
278
|
+
}
|
|
279
|
+
keys.delete(key);
|
|
280
|
+
if (keys.size === 0) {
|
|
281
|
+
this.tagIndex.delete(tag);
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
this.keyTags.delete(key);
|
|
285
|
+
}
|
|
286
|
+
getFreshEntry(key) {
|
|
287
|
+
const entry = this.cache.get(key);
|
|
288
|
+
if (!entry) {
|
|
289
|
+
return;
|
|
290
|
+
}
|
|
291
|
+
if (entry.expiresAt <= Date.now()) {
|
|
292
|
+
this.invalidate(key);
|
|
293
|
+
return;
|
|
294
|
+
}
|
|
295
|
+
entry.lastAccessedAt = Date.now();
|
|
296
|
+
return entry;
|
|
297
|
+
}
|
|
298
|
+
pruneExpired() {
|
|
299
|
+
const now = Date.now();
|
|
300
|
+
for (const [key, entry] of this.cache.entries()) {
|
|
301
|
+
if (entry.expiresAt <= now) {
|
|
302
|
+
this.invalidate(key);
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
evictOverflow() {
|
|
307
|
+
while (this.cache.size > this.maxEntries) {
|
|
308
|
+
let oldestKey;
|
|
309
|
+
let oldestAccessTime = Number.POSITIVE_INFINITY;
|
|
310
|
+
for (const [key, entry] of this.cache.entries()) {
|
|
311
|
+
if (entry.lastAccessedAt < oldestAccessTime) {
|
|
312
|
+
oldestAccessTime = entry.lastAccessedAt;
|
|
313
|
+
oldestKey = key;
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
if (!oldestKey) {
|
|
317
|
+
return;
|
|
318
|
+
}
|
|
319
|
+
this.invalidate(oldestKey);
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
var simpleCache_default = SimpleCache;
|
|
324
|
+
|
|
325
|
+
// ../../src/core/cache/simpleCacheStore.ts
|
|
326
|
+
class SimpleCacheStore {
|
|
327
|
+
cache;
|
|
328
|
+
constructor(cache) {
|
|
329
|
+
this.cache = cache;
|
|
330
|
+
}
|
|
331
|
+
get(key) {
|
|
332
|
+
return Promise.resolve(this.cache.get(key));
|
|
333
|
+
}
|
|
334
|
+
set(key, value, ttlMs) {
|
|
335
|
+
this.cache.set(key, value, ttlMs);
|
|
336
|
+
return Promise.resolve();
|
|
337
|
+
}
|
|
338
|
+
getOrSet(key, loader, ttlMs) {
|
|
339
|
+
return this.cache.getOrSet(key, loader, ttlMs);
|
|
340
|
+
}
|
|
341
|
+
attachTags(key, tags) {
|
|
342
|
+
this.cache.attachTags(key, tags);
|
|
343
|
+
return Promise.resolve();
|
|
344
|
+
}
|
|
345
|
+
flushTags(tags) {
|
|
346
|
+
return Promise.resolve(this.cache.flushTags(tags));
|
|
347
|
+
}
|
|
348
|
+
invalidate(key) {
|
|
349
|
+
return Promise.resolve(this.cache.invalidate(key));
|
|
350
|
+
}
|
|
351
|
+
invalidateByPrefix(prefix) {
|
|
352
|
+
return Promise.resolve(this.cache.invalidateByPrefix(prefix));
|
|
353
|
+
}
|
|
354
|
+
clear() {
|
|
355
|
+
this.cache.clear();
|
|
356
|
+
return Promise.resolve();
|
|
357
|
+
}
|
|
358
|
+
size() {
|
|
359
|
+
return Promise.resolve(this.cache.size());
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
var simpleCacheStore_default = SimpleCacheStore;
|
|
363
|
+
|
|
364
|
+
// ../../src/core/cache/createCacheStore.ts
|
|
365
|
+
function createCacheStore(options) {
|
|
366
|
+
if (options.driver === "redis") {
|
|
367
|
+
if (!options.redisUrl) {
|
|
368
|
+
throw new Error('CACHE_DRIVER="redis" requires REDIS_URL to be set.');
|
|
369
|
+
}
|
|
370
|
+
return new redisCacheStore_default(options.redisUrl, options.ttlMs, options.maxEntries);
|
|
371
|
+
}
|
|
372
|
+
return new simpleCacheStore_default(new simpleCache_default(options.ttlMs, options.maxEntries));
|
|
373
|
+
}
|
|
374
|
+
export {
|
|
375
|
+
createCacheStore
|
|
376
|
+
};
|
|
@@ -19,6 +19,7 @@ export { appendOrganizationScope, appendProjectScope, assertOrganizationReadable
|
|
|
19
19
|
export { default as MembershipService, resolveMembershipService, } from "../core/auth/membershipService.ts";
|
|
20
20
|
export { Policy, PolicyGate } from "../core/auth/policy.ts";
|
|
21
21
|
export { createScimAuthMiddleware } from "../core/auth/scimAuthMiddleware.ts";
|
|
22
|
+
export { type CacheDriver, type CreateCacheStoreOptions, createCacheStore, } from "../core/cache/createCacheStore.ts";
|
|
22
23
|
export { default as CacheRepository } from "../core/cache/repository.ts";
|
|
23
24
|
export { CACHE_TAGS } from "../core/cache/tags.ts";
|
|
24
25
|
export type { DatabaseConnection } from "../core/database/baseRepository.ts";
|
package/dist/index.js
CHANGED
|
@@ -3526,6 +3526,378 @@ function jsonScimError(detail, status) {
|
|
|
3526
3526
|
headers: { "content-type": "application/scim+json" }
|
|
3527
3527
|
});
|
|
3528
3528
|
}
|
|
3529
|
+
// ../../src/core/cache/redisCacheStore.ts
|
|
3530
|
+
var {RedisClient } = globalThis.Bun;
|
|
3531
|
+
var KEY_PREFIX = "workhub:cache:";
|
|
3532
|
+
var TAG_PREFIX = "workhub:cache:tag:";
|
|
3533
|
+
|
|
3534
|
+
class RedisCacheStore {
|
|
3535
|
+
ttlMs;
|
|
3536
|
+
maxEntries;
|
|
3537
|
+
client;
|
|
3538
|
+
inflight = new Map;
|
|
3539
|
+
keyTags = new Map;
|
|
3540
|
+
constructor(redisUrl, ttlMs, maxEntries) {
|
|
3541
|
+
this.ttlMs = ttlMs;
|
|
3542
|
+
this.maxEntries = maxEntries;
|
|
3543
|
+
this.client = new RedisClient(redisUrl);
|
|
3544
|
+
}
|
|
3545
|
+
async get(key) {
|
|
3546
|
+
const raw = await this.client.get(this.storageKey(key));
|
|
3547
|
+
if (raw === null) {
|
|
3548
|
+
return;
|
|
3549
|
+
}
|
|
3550
|
+
return JSON.parse(raw);
|
|
3551
|
+
}
|
|
3552
|
+
async set(key, value, ttlMs) {
|
|
3553
|
+
const resolvedTtlMs = ttlMs ?? this.ttlMs;
|
|
3554
|
+
const payload = JSON.stringify(value);
|
|
3555
|
+
if (resolvedTtlMs > 0) {
|
|
3556
|
+
await this.client.psetex(this.storageKey(key), resolvedTtlMs, payload);
|
|
3557
|
+
} else {
|
|
3558
|
+
await this.client.set(this.storageKey(key), payload);
|
|
3559
|
+
}
|
|
3560
|
+
await this.enforceMaxEntries();
|
|
3561
|
+
}
|
|
3562
|
+
async getOrSet(key, loader, ttlMs) {
|
|
3563
|
+
const cached = await this.get(key);
|
|
3564
|
+
if (cached !== undefined) {
|
|
3565
|
+
return cached;
|
|
3566
|
+
}
|
|
3567
|
+
const inflightRequest = this.inflight.get(key);
|
|
3568
|
+
if (inflightRequest) {
|
|
3569
|
+
return inflightRequest;
|
|
3570
|
+
}
|
|
3571
|
+
const pendingRequest = loader().then(async (value) => {
|
|
3572
|
+
await this.set(key, value, ttlMs);
|
|
3573
|
+
return value;
|
|
3574
|
+
}).finally(() => {
|
|
3575
|
+
this.inflight.delete(key);
|
|
3576
|
+
});
|
|
3577
|
+
this.inflight.set(key, pendingRequest);
|
|
3578
|
+
return pendingRequest;
|
|
3579
|
+
}
|
|
3580
|
+
async attachTags(key, tags) {
|
|
3581
|
+
if (tags.length === 0) {
|
|
3582
|
+
return;
|
|
3583
|
+
}
|
|
3584
|
+
let tagsForKey = this.keyTags.get(key);
|
|
3585
|
+
if (!tagsForKey) {
|
|
3586
|
+
tagsForKey = new Set;
|
|
3587
|
+
this.keyTags.set(key, tagsForKey);
|
|
3588
|
+
}
|
|
3589
|
+
for (const tag of tags) {
|
|
3590
|
+
tagsForKey.add(tag);
|
|
3591
|
+
await this.client.sadd(this.tagKey(tag), key);
|
|
3592
|
+
}
|
|
3593
|
+
}
|
|
3594
|
+
async flushTags(tags) {
|
|
3595
|
+
const keysToRemove = new Set;
|
|
3596
|
+
for (const tag of tags) {
|
|
3597
|
+
const members = await this.client.smembers(this.tagKey(tag));
|
|
3598
|
+
for (const member of members) {
|
|
3599
|
+
keysToRemove.add(member);
|
|
3600
|
+
}
|
|
3601
|
+
}
|
|
3602
|
+
let removed = 0;
|
|
3603
|
+
for (const key of keysToRemove) {
|
|
3604
|
+
if (await this.invalidate(key)) {
|
|
3605
|
+
removed += 1;
|
|
3606
|
+
}
|
|
3607
|
+
}
|
|
3608
|
+
for (const tag of tags) {
|
|
3609
|
+
await this.client.del(this.tagKey(tag));
|
|
3610
|
+
}
|
|
3611
|
+
return removed;
|
|
3612
|
+
}
|
|
3613
|
+
async invalidate(key) {
|
|
3614
|
+
const deleted = await this.client.del(this.storageKey(key));
|
|
3615
|
+
await this.detachKeyFromTags(key);
|
|
3616
|
+
return deleted > 0;
|
|
3617
|
+
}
|
|
3618
|
+
async invalidateByPrefix(prefix) {
|
|
3619
|
+
const keys = await this.client.keys(`${KEY_PREFIX}*`);
|
|
3620
|
+
let removed = 0;
|
|
3621
|
+
for (const storageKey of keys) {
|
|
3622
|
+
const key = storageKey.slice(KEY_PREFIX.length);
|
|
3623
|
+
if (key === prefix || key.startsWith(`${prefix}?`)) {
|
|
3624
|
+
if (await this.invalidate(key)) {
|
|
3625
|
+
removed += 1;
|
|
3626
|
+
}
|
|
3627
|
+
}
|
|
3628
|
+
}
|
|
3629
|
+
return removed;
|
|
3630
|
+
}
|
|
3631
|
+
async clear() {
|
|
3632
|
+
const keys = await this.client.keys(`${KEY_PREFIX}*`);
|
|
3633
|
+
if (keys.length > 0) {
|
|
3634
|
+
await this.client.del(...keys);
|
|
3635
|
+
}
|
|
3636
|
+
const tagKeys = await this.client.keys(`${TAG_PREFIX}*`);
|
|
3637
|
+
if (tagKeys.length > 0) {
|
|
3638
|
+
await this.client.del(...tagKeys);
|
|
3639
|
+
}
|
|
3640
|
+
this.inflight.clear();
|
|
3641
|
+
this.keyTags.clear();
|
|
3642
|
+
}
|
|
3643
|
+
async size() {
|
|
3644
|
+
const keys = await this.client.keys(`${KEY_PREFIX}*`);
|
|
3645
|
+
return keys.length;
|
|
3646
|
+
}
|
|
3647
|
+
storageKey(key) {
|
|
3648
|
+
return `${KEY_PREFIX}${key}`;
|
|
3649
|
+
}
|
|
3650
|
+
tagKey(tag) {
|
|
3651
|
+
return `${TAG_PREFIX}${tag}`;
|
|
3652
|
+
}
|
|
3653
|
+
async detachKeyFromTags(key) {
|
|
3654
|
+
const tags = this.keyTags.get(key);
|
|
3655
|
+
if (!tags) {
|
|
3656
|
+
return;
|
|
3657
|
+
}
|
|
3658
|
+
for (const tag of tags) {
|
|
3659
|
+
await this.client.srem(this.tagKey(tag), key);
|
|
3660
|
+
}
|
|
3661
|
+
this.keyTags.delete(key);
|
|
3662
|
+
}
|
|
3663
|
+
async enforceMaxEntries() {
|
|
3664
|
+
const keys = await this.client.keys(`${KEY_PREFIX}*`);
|
|
3665
|
+
if (keys.length <= this.maxEntries) {
|
|
3666
|
+
return;
|
|
3667
|
+
}
|
|
3668
|
+
const overflow = keys.length - this.maxEntries;
|
|
3669
|
+
const keysToRemove = keys.slice(0, overflow);
|
|
3670
|
+
if (keysToRemove.length > 0) {
|
|
3671
|
+
await this.client.del(...keysToRemove);
|
|
3672
|
+
}
|
|
3673
|
+
}
|
|
3674
|
+
}
|
|
3675
|
+
var redisCacheStore_default = RedisCacheStore;
|
|
3676
|
+
|
|
3677
|
+
// ../../src/core/cache/simpleCache.ts
|
|
3678
|
+
class SimpleCache {
|
|
3679
|
+
ttlMs;
|
|
3680
|
+
maxEntries;
|
|
3681
|
+
cache = new Map;
|
|
3682
|
+
inflight = new Map;
|
|
3683
|
+
tagIndex = new Map;
|
|
3684
|
+
keyTags = new Map;
|
|
3685
|
+
constructor(ttlMs = 3600000, maxEntries = 100) {
|
|
3686
|
+
this.ttlMs = ttlMs;
|
|
3687
|
+
this.maxEntries = maxEntries;
|
|
3688
|
+
if (!Number.isFinite(ttlMs) || ttlMs < 0) {
|
|
3689
|
+
throw new RangeError("ttlMs must be a non-negative number.");
|
|
3690
|
+
}
|
|
3691
|
+
if (!Number.isInteger(maxEntries) || maxEntries < 1) {
|
|
3692
|
+
throw new RangeError("maxEntries must be a positive integer.");
|
|
3693
|
+
}
|
|
3694
|
+
}
|
|
3695
|
+
get(key) {
|
|
3696
|
+
return this.getFreshEntry(key)?.value;
|
|
3697
|
+
}
|
|
3698
|
+
set(key, value, ttlMs) {
|
|
3699
|
+
const now = Date.now();
|
|
3700
|
+
const resolvedTtlMs = ttlMs ?? this.ttlMs;
|
|
3701
|
+
this.cache.set(key, {
|
|
3702
|
+
value,
|
|
3703
|
+
expiresAt: now + resolvedTtlMs,
|
|
3704
|
+
lastAccessedAt: now
|
|
3705
|
+
});
|
|
3706
|
+
this.evictOverflow();
|
|
3707
|
+
}
|
|
3708
|
+
async getOrSet(key, loader, ttlMs) {
|
|
3709
|
+
this.pruneExpired();
|
|
3710
|
+
const cachedEntry = this.getFreshEntry(key);
|
|
3711
|
+
if (cachedEntry) {
|
|
3712
|
+
return cachedEntry.value;
|
|
3713
|
+
}
|
|
3714
|
+
const inflightRequest = this.inflight.get(key);
|
|
3715
|
+
if (inflightRequest) {
|
|
3716
|
+
return inflightRequest;
|
|
3717
|
+
}
|
|
3718
|
+
const pendingRequest = loader().then((value) => {
|
|
3719
|
+
this.set(key, value, ttlMs);
|
|
3720
|
+
return value;
|
|
3721
|
+
}).finally(() => {
|
|
3722
|
+
this.inflight.delete(key);
|
|
3723
|
+
});
|
|
3724
|
+
this.inflight.set(key, pendingRequest);
|
|
3725
|
+
return pendingRequest;
|
|
3726
|
+
}
|
|
3727
|
+
attachTags(key, tags) {
|
|
3728
|
+
if (tags.length === 0) {
|
|
3729
|
+
return;
|
|
3730
|
+
}
|
|
3731
|
+
let tagsForKey = this.keyTags.get(key);
|
|
3732
|
+
if (!tagsForKey) {
|
|
3733
|
+
tagsForKey = new Set;
|
|
3734
|
+
this.keyTags.set(key, tagsForKey);
|
|
3735
|
+
}
|
|
3736
|
+
for (const tag of tags) {
|
|
3737
|
+
tagsForKey.add(tag);
|
|
3738
|
+
let keysForTag = this.tagIndex.get(tag);
|
|
3739
|
+
if (!keysForTag) {
|
|
3740
|
+
keysForTag = new Set;
|
|
3741
|
+
this.tagIndex.set(tag, keysForTag);
|
|
3742
|
+
}
|
|
3743
|
+
keysForTag.add(key);
|
|
3744
|
+
}
|
|
3745
|
+
}
|
|
3746
|
+
flushTags(tags) {
|
|
3747
|
+
const keysToRemove = new Set;
|
|
3748
|
+
for (const tag of tags) {
|
|
3749
|
+
const keys = this.tagIndex.get(tag);
|
|
3750
|
+
if (!keys) {
|
|
3751
|
+
continue;
|
|
3752
|
+
}
|
|
3753
|
+
for (const key of keys) {
|
|
3754
|
+
keysToRemove.add(key);
|
|
3755
|
+
}
|
|
3756
|
+
}
|
|
3757
|
+
let removed = 0;
|
|
3758
|
+
for (const key of keysToRemove) {
|
|
3759
|
+
if (this.invalidate(key)) {
|
|
3760
|
+
removed += 1;
|
|
3761
|
+
}
|
|
3762
|
+
}
|
|
3763
|
+
for (const tag of tags) {
|
|
3764
|
+
this.tagIndex.delete(tag);
|
|
3765
|
+
}
|
|
3766
|
+
return removed;
|
|
3767
|
+
}
|
|
3768
|
+
invalidate(key) {
|
|
3769
|
+
const removed = this.cache.delete(key);
|
|
3770
|
+
if (removed) {
|
|
3771
|
+
this.detachKeyFromTags(key);
|
|
3772
|
+
}
|
|
3773
|
+
return removed;
|
|
3774
|
+
}
|
|
3775
|
+
invalidateByPrefix(prefix) {
|
|
3776
|
+
let removed = 0;
|
|
3777
|
+
for (const key of [...this.cache.keys()]) {
|
|
3778
|
+
if (key === prefix || key.startsWith(`${prefix}?`)) {
|
|
3779
|
+
if (this.invalidate(key)) {
|
|
3780
|
+
removed += 1;
|
|
3781
|
+
}
|
|
3782
|
+
}
|
|
3783
|
+
}
|
|
3784
|
+
return removed;
|
|
3785
|
+
}
|
|
3786
|
+
clear() {
|
|
3787
|
+
this.cache.clear();
|
|
3788
|
+
this.inflight.clear();
|
|
3789
|
+
this.tagIndex.clear();
|
|
3790
|
+
this.keyTags.clear();
|
|
3791
|
+
}
|
|
3792
|
+
size() {
|
|
3793
|
+
this.pruneExpired();
|
|
3794
|
+
return this.cache.size;
|
|
3795
|
+
}
|
|
3796
|
+
detachKeyFromTags(key) {
|
|
3797
|
+
const tags = this.keyTags.get(key);
|
|
3798
|
+
if (!tags) {
|
|
3799
|
+
return;
|
|
3800
|
+
}
|
|
3801
|
+
for (const tag of tags) {
|
|
3802
|
+
const keys = this.tagIndex.get(tag);
|
|
3803
|
+
if (!keys) {
|
|
3804
|
+
continue;
|
|
3805
|
+
}
|
|
3806
|
+
keys.delete(key);
|
|
3807
|
+
if (keys.size === 0) {
|
|
3808
|
+
this.tagIndex.delete(tag);
|
|
3809
|
+
}
|
|
3810
|
+
}
|
|
3811
|
+
this.keyTags.delete(key);
|
|
3812
|
+
}
|
|
3813
|
+
getFreshEntry(key) {
|
|
3814
|
+
const entry = this.cache.get(key);
|
|
3815
|
+
if (!entry) {
|
|
3816
|
+
return;
|
|
3817
|
+
}
|
|
3818
|
+
if (entry.expiresAt <= Date.now()) {
|
|
3819
|
+
this.invalidate(key);
|
|
3820
|
+
return;
|
|
3821
|
+
}
|
|
3822
|
+
entry.lastAccessedAt = Date.now();
|
|
3823
|
+
return entry;
|
|
3824
|
+
}
|
|
3825
|
+
pruneExpired() {
|
|
3826
|
+
const now = Date.now();
|
|
3827
|
+
for (const [key, entry] of this.cache.entries()) {
|
|
3828
|
+
if (entry.expiresAt <= now) {
|
|
3829
|
+
this.invalidate(key);
|
|
3830
|
+
}
|
|
3831
|
+
}
|
|
3832
|
+
}
|
|
3833
|
+
evictOverflow() {
|
|
3834
|
+
while (this.cache.size > this.maxEntries) {
|
|
3835
|
+
let oldestKey;
|
|
3836
|
+
let oldestAccessTime = Number.POSITIVE_INFINITY;
|
|
3837
|
+
for (const [key, entry] of this.cache.entries()) {
|
|
3838
|
+
if (entry.lastAccessedAt < oldestAccessTime) {
|
|
3839
|
+
oldestAccessTime = entry.lastAccessedAt;
|
|
3840
|
+
oldestKey = key;
|
|
3841
|
+
}
|
|
3842
|
+
}
|
|
3843
|
+
if (!oldestKey) {
|
|
3844
|
+
return;
|
|
3845
|
+
}
|
|
3846
|
+
this.invalidate(oldestKey);
|
|
3847
|
+
}
|
|
3848
|
+
}
|
|
3849
|
+
}
|
|
3850
|
+
var simpleCache_default = SimpleCache;
|
|
3851
|
+
|
|
3852
|
+
// ../../src/core/cache/simpleCacheStore.ts
|
|
3853
|
+
class SimpleCacheStore {
|
|
3854
|
+
cache;
|
|
3855
|
+
constructor(cache) {
|
|
3856
|
+
this.cache = cache;
|
|
3857
|
+
}
|
|
3858
|
+
get(key) {
|
|
3859
|
+
return Promise.resolve(this.cache.get(key));
|
|
3860
|
+
}
|
|
3861
|
+
set(key, value, ttlMs) {
|
|
3862
|
+
this.cache.set(key, value, ttlMs);
|
|
3863
|
+
return Promise.resolve();
|
|
3864
|
+
}
|
|
3865
|
+
getOrSet(key, loader, ttlMs) {
|
|
3866
|
+
return this.cache.getOrSet(key, loader, ttlMs);
|
|
3867
|
+
}
|
|
3868
|
+
attachTags(key, tags) {
|
|
3869
|
+
this.cache.attachTags(key, tags);
|
|
3870
|
+
return Promise.resolve();
|
|
3871
|
+
}
|
|
3872
|
+
flushTags(tags) {
|
|
3873
|
+
return Promise.resolve(this.cache.flushTags(tags));
|
|
3874
|
+
}
|
|
3875
|
+
invalidate(key) {
|
|
3876
|
+
return Promise.resolve(this.cache.invalidate(key));
|
|
3877
|
+
}
|
|
3878
|
+
invalidateByPrefix(prefix) {
|
|
3879
|
+
return Promise.resolve(this.cache.invalidateByPrefix(prefix));
|
|
3880
|
+
}
|
|
3881
|
+
clear() {
|
|
3882
|
+
this.cache.clear();
|
|
3883
|
+
return Promise.resolve();
|
|
3884
|
+
}
|
|
3885
|
+
size() {
|
|
3886
|
+
return Promise.resolve(this.cache.size());
|
|
3887
|
+
}
|
|
3888
|
+
}
|
|
3889
|
+
var simpleCacheStore_default = SimpleCacheStore;
|
|
3890
|
+
|
|
3891
|
+
// ../../src/core/cache/createCacheStore.ts
|
|
3892
|
+
function createCacheStore(options) {
|
|
3893
|
+
if (options.driver === "redis") {
|
|
3894
|
+
if (!options.redisUrl) {
|
|
3895
|
+
throw new Error('CACHE_DRIVER="redis" requires REDIS_URL to be set.');
|
|
3896
|
+
}
|
|
3897
|
+
return new redisCacheStore_default(options.redisUrl, options.ttlMs, options.maxEntries);
|
|
3898
|
+
}
|
|
3899
|
+
return new simpleCacheStore_default(new simpleCache_default(options.ttlMs, options.maxEntries));
|
|
3900
|
+
}
|
|
3529
3901
|
// ../../src/core/cache/taggedCache.ts
|
|
3530
3902
|
class TaggedCache {
|
|
3531
3903
|
store;
|
|
@@ -4894,7 +5266,7 @@ function bindRouteModel(param, resolver, handler) {
|
|
|
4894
5266
|
return await handler(request, model);
|
|
4895
5267
|
};
|
|
4896
5268
|
}
|
|
4897
|
-
// ../../src/
|
|
5269
|
+
// ../../src/bootstrap/http/securedRouteModelBinding.ts
|
|
4898
5270
|
function isMutatingPolicyAction(action) {
|
|
4899
5271
|
return action === "update" || action === "delete";
|
|
4900
5272
|
}
|
|
@@ -5050,7 +5422,7 @@ function withErrorHandling(handler) {
|
|
|
5050
5422
|
};
|
|
5051
5423
|
}
|
|
5052
5424
|
// ../../src/core/http/loginThrottleMiddleware.ts
|
|
5053
|
-
var {RedisClient } = globalThis.Bun;
|
|
5425
|
+
var {RedisClient: RedisClient2 } = globalThis.Bun;
|
|
5054
5426
|
function resolveLoginIdentity(request) {
|
|
5055
5427
|
return request.headers.get("x-forwarded-for")?.split(",")[0]?.trim() ?? "unknown";
|
|
5056
5428
|
}
|
|
@@ -5069,7 +5441,7 @@ async function resolveLoginEmail(request) {
|
|
|
5069
5441
|
}
|
|
5070
5442
|
}
|
|
5071
5443
|
function createLoginThrottleMiddleware(options) {
|
|
5072
|
-
const client = new
|
|
5444
|
+
const client = new RedisClient2(options.redisUrl);
|
|
5073
5445
|
const prefix = options.keyPrefix ?? "workhub:login-throttle:";
|
|
5074
5446
|
return async (request, next) => {
|
|
5075
5447
|
const identity = resolveLoginIdentity(request);
|
|
@@ -5249,9 +5621,9 @@ function createRequireWebAuthMiddleware(auth2) {
|
|
|
5249
5621
|
};
|
|
5250
5622
|
}
|
|
5251
5623
|
// ../../src/core/http/scimThrottleMiddleware.ts
|
|
5252
|
-
var {RedisClient:
|
|
5624
|
+
var {RedisClient: RedisClient3 } = globalThis.Bun;
|
|
5253
5625
|
function createScimThrottleMiddleware(options) {
|
|
5254
|
-
const client = options.redisUrl ? new
|
|
5626
|
+
const client = options.redisUrl ? new RedisClient3(options.redisUrl) : null;
|
|
5255
5627
|
return async (request, next) => {
|
|
5256
5628
|
const identity = request.headers.get("authorization")?.slice("Bearer ".length, "Bearer ".length + 16) ?? request.headers.get("x-forwarded-for")?.split(",")[0]?.trim() ?? "unknown";
|
|
5257
5629
|
const key = `workhub:scim-throttle:${identity}`;
|
|
@@ -5341,7 +5713,7 @@ function createSecurityHeadersMiddleware() {
|
|
|
5341
5713
|
};
|
|
5342
5714
|
}
|
|
5343
5715
|
// ../../src/core/http/throttleMiddleware.ts
|
|
5344
|
-
var {RedisClient:
|
|
5716
|
+
var {RedisClient: RedisClient4 } = globalThis.Bun;
|
|
5345
5717
|
function resolveThrottleIdentity(request) {
|
|
5346
5718
|
const user = currentAuthUser();
|
|
5347
5719
|
if (user?.tokenId !== undefined) {
|
|
@@ -5353,7 +5725,7 @@ function resolveThrottleIdentity(request) {
|
|
|
5353
5725
|
return request.headers.get("x-forwarded-for")?.split(",")[0]?.trim() ?? "unknown";
|
|
5354
5726
|
}
|
|
5355
5727
|
function createThrottleMiddleware(options) {
|
|
5356
|
-
const client = new
|
|
5728
|
+
const client = new RedisClient4(options.redisUrl);
|
|
5357
5729
|
const prefix = options.keyPrefix ?? "workhub:throttle:";
|
|
5358
5730
|
return async (request, next) => {
|
|
5359
5731
|
const identity = resolveThrottleIdentity(request);
|
|
@@ -5772,7 +6144,7 @@ async function runQueueJob(envelope, failedJobs) {
|
|
|
5772
6144
|
}
|
|
5773
6145
|
|
|
5774
6146
|
// ../../src/core/queue/redisQueue.ts
|
|
5775
|
-
var {RedisClient:
|
|
6147
|
+
var {RedisClient: RedisClient5 } = globalThis.Bun;
|
|
5776
6148
|
var QUEUE_LIST_KEY = "workhub:queue:default";
|
|
5777
6149
|
var QUEUE_HIGH_KEY = "workhub:queue:high";
|
|
5778
6150
|
var QUEUE_LOW_KEY = "workhub:queue:low";
|
|
@@ -5822,7 +6194,7 @@ function parseQueueJobEnvelope(rawPayload) {
|
|
|
5822
6194
|
class RedisQueue {
|
|
5823
6195
|
client;
|
|
5824
6196
|
constructor(redisUrl) {
|
|
5825
|
-
this.client = new
|
|
6197
|
+
this.client = new RedisClient5(redisUrl);
|
|
5826
6198
|
}
|
|
5827
6199
|
async dispatch(job, payload) {
|
|
5828
6200
|
const name = jobRegistry.resolveName(job);
|
|
@@ -5848,7 +6220,7 @@ class QueueWorker {
|
|
|
5848
6220
|
constructor(redisUrl, failedJobs, timeoutSeconds = 5) {
|
|
5849
6221
|
this.failedJobs = failedJobs;
|
|
5850
6222
|
this.timeoutSeconds = timeoutSeconds;
|
|
5851
|
-
this.client = new
|
|
6223
|
+
this.client = new RedisClient5(redisUrl);
|
|
5852
6224
|
}
|
|
5853
6225
|
requestStop() {
|
|
5854
6226
|
this.stopping = true;
|
|
@@ -5946,7 +6318,7 @@ function createQueueWorker(redisUrl, failedJobs = createFailedJobService()) {
|
|
|
5946
6318
|
return new QueueWorker(redisUrl, failedJobs);
|
|
5947
6319
|
}
|
|
5948
6320
|
// ../../src/core/queue/queueMetrics.ts
|
|
5949
|
-
var {RedisClient:
|
|
6321
|
+
var {RedisClient: RedisClient6 } = globalThis.Bun;
|
|
5950
6322
|
|
|
5951
6323
|
// ../../src/core/security/safeUrl.ts
|
|
5952
6324
|
var BLOCKED_HOSTNAMES = new Set([
|
|
@@ -5959,7 +6331,7 @@ var BLOCKED_HOSTNAMES = new Set([
|
|
|
5959
6331
|
|
|
5960
6332
|
// ../../src/core/queue/queueMetrics.ts
|
|
5961
6333
|
async function readRedisQueueDepth(redisUrl) {
|
|
5962
|
-
const client = new
|
|
6334
|
+
const client = new RedisClient6(redisUrl);
|
|
5963
6335
|
const [high, defaultQueue, low] = await Promise.all([
|
|
5964
6336
|
client.llen(QUEUE_HIGH_KEY),
|
|
5965
6337
|
client.llen(QUEUE_LIST_KEY),
|
|
@@ -6452,6 +6824,7 @@ export {
|
|
|
6452
6824
|
createCsrfProtection,
|
|
6453
6825
|
createCsrfMiddleware,
|
|
6454
6826
|
createCorsMiddleware,
|
|
6827
|
+
createCacheStore,
|
|
6455
6828
|
createBodySizeLimitMiddleware,
|
|
6456
6829
|
createAuthorizeMiddleware,
|
|
6457
6830
|
createAuthMiddleware,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@getstrata/core",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.16",
|
|
4
4
|
"description": "Strata — Laravel-inspired Bun framework public API",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -90,6 +90,11 @@
|
|
|
90
90
|
"import": "./dist/entries/cache/tags.js",
|
|
91
91
|
"default": "./dist/entries/cache/tags.js"
|
|
92
92
|
},
|
|
93
|
+
"./cache/createCacheStore": {
|
|
94
|
+
"types": "./dist/core/cache/createCacheStore.d.ts",
|
|
95
|
+
"import": "./dist/entries/cache/createCacheStore.js",
|
|
96
|
+
"default": "./dist/entries/cache/createCacheStore.js"
|
|
97
|
+
},
|
|
93
98
|
"./crypto/fieldEncryption": {
|
|
94
99
|
"types": "./dist/core/crypto/fieldEncryption.d.ts",
|
|
95
100
|
"import": "./dist/entries/crypto/fieldEncryption.js",
|
|
@@ -312,7 +317,7 @@
|
|
|
312
317
|
"build:bundle": "bun build index.ts --outdir dist --target bun --external bun --external eta",
|
|
313
318
|
"build:types": "tsc -p tsconfig.types.json",
|
|
314
319
|
"prepublishOnly": "bun run build && bun ../../scripts/prepare-core-package-publish.ts",
|
|
315
|
-
"build:subpaths": "bun build entries/auth/oauth/oidcProvider.ts entries/auth/oauth/providers.ts entries/auth/oauth/samlProvider.ts entries/auth/oauth/types.ts entries/auth/password.ts entries/auth/sessionCookie.ts entries/auth/tokenHash.ts entries/cache/tags.ts entries/crypto/fieldEncryption.ts entries/crypto/mfaSecret.ts entries/database/factory.ts entries/database/seeders.ts entries/database/types.ts entries/errors/http.ts entries/http/contentNegotiation.ts entries/http/csrfToken.ts entries/http/etag.ts entries/http/flashSession.ts entries/http/parseFormBody.ts entries/http/resources.ts entries/http/webErrorResponse.ts entries/http/webFormRequest.ts entries/jobs/dispatchWebhookJob.ts entries/lifecycle/gracefulShutdown.ts entries/metrics/prometheus.ts entries/pagination.ts entries/queue/createAppQueue.ts entries/queue/failedJobService.ts entries/queue/jobRegistry.ts entries/queue/jobRunner.ts entries/queue/queueMetrics.ts entries/queue/publicQueue.ts entries/queue/types.ts entries/security/oauthState.ts entries/security/publicReads.ts entries/security/safeUrl.ts entries/security/stripeWebhook.ts entries/security/tokenExpiry.ts entries/security/totp.ts entries/storage/storage.ts entries/validation/rules.ts entries/view.ts --outdir dist --root . --target bun --external bun --external eta",
|
|
320
|
+
"build:subpaths": "bun build entries/auth/oauth/oidcProvider.ts entries/auth/oauth/providers.ts entries/auth/oauth/samlProvider.ts entries/auth/oauth/types.ts entries/auth/password.ts entries/auth/sessionCookie.ts entries/auth/tokenHash.ts entries/cache/tags.ts entries/cache/createCacheStore.ts entries/crypto/fieldEncryption.ts entries/crypto/mfaSecret.ts entries/database/factory.ts entries/database/seeders.ts entries/database/types.ts entries/errors/http.ts entries/http/contentNegotiation.ts entries/http/csrfToken.ts entries/http/etag.ts entries/http/flashSession.ts entries/http/parseFormBody.ts entries/http/resources.ts entries/http/webErrorResponse.ts entries/http/webFormRequest.ts entries/jobs/dispatchWebhookJob.ts entries/lifecycle/gracefulShutdown.ts entries/metrics/prometheus.ts entries/pagination.ts entries/queue/createAppQueue.ts entries/queue/failedJobService.ts entries/queue/jobRegistry.ts entries/queue/jobRunner.ts entries/queue/queueMetrics.ts entries/queue/publicQueue.ts entries/queue/types.ts entries/security/oauthState.ts entries/security/publicReads.ts entries/security/safeUrl.ts entries/security/stripeWebhook.ts entries/security/tokenExpiry.ts entries/security/totp.ts entries/storage/storage.ts entries/validation/rules.ts entries/view.ts --outdir dist --root . --target bun --external bun --external eta",
|
|
316
321
|
"build:shims": "bun ../../scripts/write-core-shared-shims.ts"
|
|
317
322
|
},
|
|
318
323
|
"publishConfig": {
|