Simple key-value storage with support for multiple backends
—
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
Direct access to internal data structures including TTL metadata, useful for debugging and advanced use cases where expiry information is needed.
Retrieves the raw stored data including internal metadata like expiry timestamps.
/**
* Get raw stored data for a key including TTL metadata
* @param key - Key to retrieve raw data for
* @returns Promise resolving to raw data object or undefined if key doesn't exist or is expired
*/
async getRaw<Value = GenericValue>(key: string): Promise<StoredDataRaw<Value> | undefined>;
type DeserializedData<Value> = {
/** The stored value */
value?: Value;
/** Unix timestamp when the key expires (undefined means no expiration) */
expires?: number | undefined;
};
type StoredDataRaw<Value> = DeserializedData<Value> | undefined;Usage Examples:
const keyv = new Keyv();
// Set data with TTL
await keyv.set('session', 'abc123', 60000); // expires in 1 minute
// Get raw data
const raw = await keyv.getRaw('session');
console.log(raw);
// {
// value: 'abc123',
// expires: 1625097660000 // Unix timestamp
// }
// Set data without TTL
await keyv.set('permanent', 'forever');
const rawPermanent = await keyv.getRaw('permanent');
console.log(rawPermanent);
// {
// value: 'forever',
// expires: undefined // No expiration
// }
// Check if key will expire soon
const userData = await keyv.getRaw('user:session');
if (userData && userData.expires) {
const timeLeft = userData.expires - Date.now();
if (timeLeft < 5000) { // Less than 5 seconds
console.log('Session expires soon!');
}
}
// Nonexistent key
const missing = await keyv.getRaw('nonexistent'); // undefined
// Expired key (returns undefined, key is also deleted)
await keyv.set('temp', 'data', 1000); // 1 second TTL
// ... wait 2 seconds
const expired = await keyv.getRaw('temp'); // undefinedRetrieves raw stored data for multiple keys simultaneously.
/**
* Get raw stored data for multiple keys including TTL metadata
* @param keys - Array of keys to retrieve raw data for
* @returns Promise resolving to array of raw data objects in same order as keys
*/
async getManyRaw<Value = GenericValue>(keys: string[]): Promise<Array<StoredDataRaw<Value>>>;Usage Examples:
const keyv = new Keyv();
// Setup test data with different TTL values
await keyv.set('user:1', { name: 'Alice' }, 60000); // 1 minute
await keyv.set('user:2', { name: 'Bob' }, 120000); // 2 minutes
await keyv.set('user:3', { name: 'Charlie' }); // permanent
// Get raw data for multiple keys
const rawUsers = await keyv.getManyRaw(['user:1', 'user:2', 'user:3', 'user:4']);
console.log(rawUsers);
// [
// { value: { name: 'Alice' }, expires: 1625097720000 },
// { value: { name: 'Bob' }, expires: 1625097780000 },
// { value: { name: 'Charlie' }, expires: undefined },
// undefined // user:4 doesn't exist
// ]
// Process results with expiry checking
const results = await keyv.getManyRaw(['session:1', 'session:2', 'session:3']);
const now = Date.now();
results.forEach((raw, index) => {
const key = `session:${index + 1}`;
if (!raw) {
console.log(`${key}: Not found`);
} else if (raw.expires && raw.expires < now) {
console.log(`${key}: Expired`);
} else if (raw.expires) {
const timeLeft = Math.round((raw.expires - now) / 1000);
console.log(`${key}: Expires in ${timeLeft} seconds`);
} else {
console.log(`${key}: Permanent`);
}
});
// Type safety with generics
interface Session { userId: string; token: string; }
const rawSessions = await keyv.getManyRaw<Session>(['session:1', 'session:2']);
// Array<DeserializedData<Session> | undefined>
// Empty array handling
const empty = await keyv.getManyRaw([]); // []Raw data access is particularly useful for:
const keyv = new Keyv();
// Function to check TTL status
async function checkTTL(key: string) {
const raw = await keyv.getRaw(key);
if (!raw) {
return 'Key does not exist';
}
if (!raw.expires) {
return 'Key never expires';
}
const timeLeft = raw.expires - Date.now();
if (timeLeft <= 0) {
return 'Key has expired';
}
return `Key expires in ${Math.round(timeLeft / 1000)} seconds`;
}
await keyv.set('temp-data', 'value', 30000); // 30 seconds
console.log(await checkTTL('temp-data')); // "Key expires in 30 seconds"const keyv = new Keyv();
// Pre-emptively refresh keys that are about to expire
async function refreshExpiringSoon(keys: string[], thresholdMs: number = 5000) {
const rawData = await keyv.getManyRaw(keys);
const now = Date.now();
const expiringSoon = rawData
.map((raw, index) => ({ key: keys[index], raw }))
.filter(({ raw }) =>
raw && raw.expires && (raw.expires - now) < thresholdMs
);
for (const { key, raw } of expiringSoon) {
console.log(`Refreshing ${key} (expires in ${raw!.expires! - now}ms)`);
// Refresh logic here
await refreshKey(key);
}
}
async function refreshKey(key: string) {
// Your refresh logic
const newValue = await fetchFreshData(key);
await keyv.set(key, newValue, 60000);
}const keyv = new Keyv();
// Debug function to inspect storage state
async function debugKeys(keys: string[]) {
const rawData = await keyv.getManyRaw(keys);
keys.forEach((key, index) => {
const raw = rawData[index];
if (!raw) {
console.log(`${key}: [MISSING]`);
} else {
const expires = raw.expires ? new Date(raw.expires).toISOString() : 'never';
console.log(`${key}: value=${JSON.stringify(raw.value)}, expires=${expires}`);
}
});
}
await keyv.set('debug:1', { test: true }, 30000);
await keyv.set('debug:2', 'permanent data');
await debugKeys(['debug:1', 'debug:2', 'debug:3']);
// debug:1: value={"test":true}, expires=2021-07-01T12:30:00.000Z
// debug:2: value="permanent data", expires=never
// debug:3: [MISSING]