https://github.com/jonathanong/valkyries
Valkey Functions - Caching, Bloom Filters, Rate Limiters, and Dynamic Configurations
https://github.com/jonathanong/valkyries
Last synced: 2 months ago
JSON representation
Valkey Functions - Caching, Bloom Filters, Rate Limiters, and Dynamic Configurations
- Host: GitHub
- URL: https://github.com/jonathanong/valkyries
- Owner: jonathanong
- License: mit
- Created: 2026-05-17T05:43:54.000Z (2 months ago)
- Default Branch: main
- Last Pushed: 2026-05-19T01:44:19.000Z (2 months ago)
- Last Synced: 2026-05-19T03:43:19.988Z (2 months ago)
- Language: TypeScript
- Size: 176 KB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# valkyries
Valkey utilities for Node.js services: cache helpers, Bloom filters, dynamic configuration, and sliding-window rate limiting.
## Install
```sh
pnpm add valkyries @valkey/valkey-glide
```
`valkyries` is ESM-only and requires Node.js 24 or newer.
## Valkey
By default the package reads `VALKEY_URL`, falling back to `redis://localhost:6379`.
Specialized URLs can split traffic by data type:
```sh
VALKEY_CACHE_URL=redis://localhost:6379
VALKEY_RATE_LIMITER_URL=redis://localhost:6379
VALKEY_DYNAMIC_CONFIG_URL=redis://localhost:6379
```
Bloom filters require Valkey with the Bloom module. For local development and CI, use Valkey Bundle:
```sh
docker run --rm -p 6379:6379 valkey/valkey-bundle:latest
```
## Cache
```ts
import { ValkeyCache } from "valkyries";
const cache = new ValkeyCache({ prefix: "users", ttlSeconds: 300 });
const getUser = cache.cacheGetByAny(async (id) => {
return await loadUserFromDatabase(id);
});
const user = await getUser("user_123");
await cache.invalidateCacheGetByAny("user_123");
```
Cache keys are normalized with `trim().toLowerCase()`. Use `keySerializer` for composite keys.
## Bloom Filters
```ts
import { ValkeyBloomFilter } from "valkyries";
const filter = new ValkeyBloomFilter({
name: "users",
capacity: 1_000_000,
errorRate: 0.01,
});
await filter.ensureExists();
await filter.add(["user_123"]);
const maybeExists = await filter.existsIfReady("users:ready", "user_123");
```
`null` means the filter is missing or not ready and callers should fall back to the authoritative store.
## Dynamic Config
```ts
import { DynamicConfig } from "valkyries";
const flags = new DynamicConfig({
key: "feature-flags",
fieldTypes: { enabled: "boolean", sampleRate: "number" },
defaultFields: { enabled: false, sampleRate: 0 },
});
await flags.waitForInitialization();
await flags.setField("enabled", true);
```
Dynamic config stores fields in a Valkey hash and publishes changes over pub/sub.
## Rate Limiter
```ts
import { RateLimiter } from "valkyries";
const limiter = new RateLimiter({ prefix: "login", ttlSeconds: 60 });
const { limited, counts } = await limiter.addAndCheck(["ip:127.0.0.1"], 10);
```
`addAndCheck()` increments first and blocks when any post-add count is greater than or equal to the threshold.
## Client Injection
Every class accepts an optional `GlideClient` for tests or custom connection management:
```ts
import { GlideClient } from "@valkey/valkey-glide";
import { ValkeyCache, glideConfigFromUrl } from "valkyries";
const client = await GlideClient.createClient(glideConfigFromUrl("redis://localhost:6379"));
const cache = new ValkeyCache({ prefix: "custom", ttlSeconds: 60, client });
```
Call `closeValkeyClients()` to close package-managed clients.
## Documentation
- [Configuration](docs/configuration.md)
- [API reference](docs/api.md)
- [Clients](docs/clients.md)
- [Cache](docs/cache.md)
- [Bloom filters](docs/bloom-filters.md)
- [Dynamic config](docs/dynamic-config.md)
- [Rate limiter](docs/rate-limiter.md)
- [Events and metrics](docs/events-and-metrics.md)
- [Lua scripts](docs/lua-scripts.md)
- [Utilities](docs/utilities.md)
- [Testing and CI](docs/testing-and-ci.md)
- [Migration guide](docs/migration.md)