{"id":49989625,"url":"https://github.com/jonathanong/valkyries","last_synced_at":"2026-05-23T08:00:48.991Z","repository":{"id":358393706,"uuid":"1241229067","full_name":"jonathanong/valkyries","owner":"jonathanong","description":"Valkey Functions - Caching, Bloom Filters, Rate Limiters, and Dynamic Configurations","archived":false,"fork":false,"pushed_at":"2026-05-19T01:44:19.000Z","size":180,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-19T03:43:19.988Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jonathanong.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-05-17T05:43:54.000Z","updated_at":"2026-05-19T01:38:35.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/jonathanong/valkyries","commit_stats":null,"previous_names":["jonathanong/valkyries"],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/jonathanong/valkyries","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jonathanong%2Fvalkyries","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jonathanong%2Fvalkyries/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jonathanong%2Fvalkyries/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jonathanong%2Fvalkyries/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jonathanong","download_url":"https://codeload.github.com/jonathanong/valkyries/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jonathanong%2Fvalkyries/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33387656,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-23T04:15:53.637Z","status":"ssl_error","status_checked_at":"2026-05-23T04:15:53.242Z","response_time":53,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-05-19T03:24:06.767Z","updated_at":"2026-05-23T08:00:48.979Z","avatar_url":"https://github.com/jonathanong.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# valkyries\n\nValkey utilities for Node.js services: cache helpers, Bloom filters, dynamic configuration, and sliding-window rate limiting.\n\n## Install\n\n```sh\npnpm add valkyries @valkey/valkey-glide\n```\n\n`valkyries` is ESM-only and requires Node.js 24 or newer.\n\n## Valkey\n\nBy default the package reads `VALKEY_URL`, falling back to `redis://localhost:6379`.\n\nSpecialized URLs can split traffic by data type:\n\n```sh\nVALKEY_CACHE_URL=redis://localhost:6379\nVALKEY_RATE_LIMITER_URL=redis://localhost:6379\nVALKEY_DYNAMIC_CONFIG_URL=redis://localhost:6379\n```\n\nBloom filters require Valkey with the Bloom module. For local development and CI, use Valkey Bundle:\n\n```sh\ndocker run --rm -p 6379:6379 valkey/valkey-bundle:latest\n```\n\n## Cache\n\n```ts\nimport { ValkeyCache } from \"valkyries\";\n\nconst cache = new ValkeyCache({ prefix: \"users\", ttlSeconds: 300 });\n\nconst getUser = cache.cacheGetByAny(async (id) =\u003e {\n  return await loadUserFromDatabase(id);\n});\n\nconst user = await getUser(\"user_123\");\nawait cache.invalidateCacheGetByAny(\"user_123\");\n```\n\nCache keys are normalized with `trim().toLowerCase()`. Use `keySerializer` for composite keys.\n\n## Bloom Filters\n\n```ts\nimport { ValkeyBloomFilter } from \"valkyries\";\n\nconst filter = new ValkeyBloomFilter({\n  name: \"users\",\n  capacity: 1_000_000,\n  errorRate: 0.01,\n});\n\nawait filter.ensureExists();\nawait filter.add([\"user_123\"]);\n\nconst maybeExists = await filter.existsIfReady(\"users:ready\", \"user_123\");\n```\n\n`null` means the filter is missing or not ready and callers should fall back to the authoritative store.\n\n## Dynamic Config\n\n```ts\nimport { DynamicConfig } from \"valkyries\";\n\nconst flags = new DynamicConfig({\n  key: \"feature-flags\",\n  fieldTypes: { enabled: \"boolean\", sampleRate: \"number\" },\n  defaultFields: { enabled: false, sampleRate: 0 },\n});\n\nawait flags.waitForInitialization();\nawait flags.setField(\"enabled\", true);\n```\n\nDynamic config stores fields in a Valkey hash and publishes changes over pub/sub.\n\n## Rate Limiter\n\n```ts\nimport { RateLimiter } from \"valkyries\";\n\nconst limiter = new RateLimiter({ prefix: \"login\", ttlSeconds: 60 });\nconst { limited, counts } = await limiter.addAndCheck([\"ip:127.0.0.1\"], 10);\n```\n\n`addAndCheck()` increments first and blocks when any post-add count is greater than or equal to the threshold.\n\n## Client Injection\n\nEvery class accepts an optional `GlideClient` for tests or custom connection management:\n\n```ts\nimport { GlideClient } from \"@valkey/valkey-glide\";\nimport { ValkeyCache, glideConfigFromUrl } from \"valkyries\";\n\nconst client = await GlideClient.createClient(glideConfigFromUrl(\"redis://localhost:6379\"));\nconst cache = new ValkeyCache({ prefix: \"custom\", ttlSeconds: 60, client });\n```\n\nCall `closeValkeyClients()` to close package-managed clients.\n\n## Documentation\n\n- [Configuration](docs/configuration.md)\n- [API reference](docs/api.md)\n- [Clients](docs/clients.md)\n- [Cache](docs/cache.md)\n- [Bloom filters](docs/bloom-filters.md)\n- [Dynamic config](docs/dynamic-config.md)\n- [Rate limiter](docs/rate-limiter.md)\n- [Events and metrics](docs/events-and-metrics.md)\n- [Lua scripts](docs/lua-scripts.md)\n- [Utilities](docs/utilities.md)\n- [Testing and CI](docs/testing-and-ci.md)\n- [Migration guide](docs/migration.md)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjonathanong%2Fvalkyries","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjonathanong%2Fvalkyries","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjonathanong%2Fvalkyries/lists"}