UNPKG

@trifrost/core

Version:

Blazingly fast, runtime-agnostic server framework for modern edge and node environments

79 lines (78 loc) 2.13 kB
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)), }); } }