Adapters
Storage, rate limiting, and analytics backends that can be customized to your preferences.
What are adapters?
Adapters are how you plug UsefulKey into your infrastructure. They are responsible for persisting and retrieving data from your chosen storage backend or logging analytics to your chosen service.
Overview
UsefulKey by default uses the in-memory adapters and console analytics but these can be swapped out for any adapter you want. If no adapters are provided in the usefulkey
config (see Configuration), the in-memory adapters will be used.
There are currently 3 adapter types:
- Key store:
KeyStoreAdapter
- used to store and retrieve keys from a database or other storage location. - Rate limit store:
RateLimitStoreAdapter
- used to store and retrieve rate limits data. - Analytics:
AnalyticsAdapter
- used to log analytics.
Key store
The key store adapter is responsible for persisting, retrieving, and managing API keys in your chosen storage backend. By default, UsefulKey uses an in-memory key store, but you can provide your own implementation to use databases like Postgres, MongoDB, or even remote HTTP APIs.
This adapter is required for persistent storage.
Key store adapter interface
export interface KeyStoreAdapter {
createKey(record: KeyRecord): Promise<void>;
findKeyByHash(hash: string): Promise<KeyRecord | null>;
findKeyById(id: KeyId): Promise<KeyRecord | null>;
updateKey(record: KeyRecord): Promise<void>;
revokeKeyById(id: KeyId): Promise<void>;
}
See list of avaliable key store adapters here.
Memory key store
import { usefulkey, MemoryKeyStore } from "betterkey";
const keyStore = new MemoryKeyStore();
const uk = usefulkey({ adapters: { keyStore } });
Stored values
- Memory (in-process):
// Stored as in-memory map of records
{
id: "k_123",
userId: "u_789",
prefix: "uk",
keyHash: "a3b1f6...",
createdAt: 1733942000000,
expiresAt: null,
metadata: { plan: "pro" },
usesRemaining: 42,
revokedAt: null
}
Rate limit store
The rate limit store adapter persists request to a database or other storage location. It powers the rate limiting plugins and supports fixed-window and token bucket strategies. By default, UsefulKey uses an in-memory store, but you can provide Redis, SQLite, or Postgres implementations.
Rate limit store adapter interface
export interface RateLimitStoreAdapter {
incrementAndCheck(
namespace: string,
identifier: string,
limit: number,
durationMs: number
): Promise<{ success: boolean; remaining: number; reset: number }>;
check(
namespace: string,
identifier: string,
limit: number,
durationMs: number
): Promise<{ success: boolean; remaining: number; reset: number }>;
consumeTokenBucket(
namespace: string,
identifier: string,
capacity: number,
refillTokens: number,
refillIntervalMs: number,
cost?: number
): Promise<{ success: boolean; remaining: number; reset: number }>;
reset(namespace: string, identifier: string): Promise<void>;
}
See list of available rate limit store adapters here.
Memory rate limit store
import { usefulkey, MemoryRateLimitStore } from "betterkey";
const rateLimitStore = new MemoryRateLimitStore();
const uk = usefulkey({ adapters: { rateLimitStore } });
Stored values
- Memory (in-process):
// Fixed window (windows map)
"global:ip_1.1.1.1" => { count: 3, reset: 1733942399123 }
// Token bucket (buckets map)
"global:ip_1.1.1.1" => {
tokens: 6,
lastRefill: 1733942398000,
capacity: 10,
refillTokens: 1,
refillIntervalMs: 1000
}
Analytics
The analytics adapter lets UsefulKey emit audit and usage events to your observability stack.
Analytics adapter interface
export interface AnalyticsAdapter {
track(event: string, payload: Record<string, unknown>): Promise<void>;
}
Console analytics
import { usefulkey, ConsoleAnalytics } from "betterkey";
const analytics = new ConsoleAnalytics();
const uk = usefulkey({ adapters: { analytics } });
See list of available analytics adapters here.
Stored values / outputs
- Console analytics (stdout):
[usefulkey:analytics] key.verified { keyId: 'k_123', ip: '1.1.1.1', ok: true }
[usefulkey:analytics] rate.limit.hit { namespace: 'global', identifier: 'ip_1.1.1.1', limit: 100 }
Authoring your own adapters
See the Authoring your own adapters section for more information.