@trifrost/core
Version:
Blazingly fast, runtime-agnostic server framework for modern edge and node environments
79 lines (78 loc) • 2.13 kB
JavaScript
import { split } from '@valkyriestudios/utils/array';
import { TriFrostCache } from '../modules/Cache/_Cache';
import { TriFrostRateLimit } from '../modules/RateLimit/_RateLimit';
import { Store } from './_Storage';
/**
* MARK: Adapter
*/
export class KVStoreAdapter {
#kv;
constructor(kv) {
this.#kv = kv;
}
async get(key) {
return this.#kv.get(key, 'json');
}
async set(key, value, ttl) {
await this.#kv.put(key, JSON.stringify(value), { expirationTtl: ttl });
}
async del(key) {
await this.#kv.delete(key);
}
async delPrefixed(prefix) {
let cursor;
const acc = new Set();
do {
const list = await this.#kv.list({ prefix, cursor });
cursor = list.cursor || undefined;
for (let i = 0; i < list.keys.length; i++) {
acc.add(list.keys[i].name);
}
} while (cursor);
if (!acc.size)
return;
for (const batch of split([...acc], 10)) {
const proms = [];
/* Sadly KV namespace currently does not support direct bulk deletion */
for (let i = 0; i < batch.length; i++)
proms.push(this.#kv.delete(batch[i]));
await Promise.all(proms);
}
}
async stop() {
/* Nothing to do here */
}
}
/**
* MARK: Store
*/
export class KVStore extends Store {
constructor(kv) {
super('KVStore', new KVStoreAdapter(kv));
}
}
/**
* MARK: Cache
*/
export class KVCache extends TriFrostCache {
constructor(cfg) {
if (!cfg?.store)
throw new Error('KVCache: Expected a store initializer');
super({
store: new Store('KVCache', new KVStoreAdapter(cfg.store)),
});
}
}
/**
* MARK: RateLimit
*/
export class KVRateLimit extends TriFrostRateLimit {
constructor(cfg) {
if (!cfg?.store)
throw new Error('KVRateLimit: Expected a store initializer');
super({
...cfg,
store: new Store('KVRateLimit', new KVStoreAdapter(cfg.store)),
});
}
}