CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-keyv

Simple key-value storage with support for multiple backends

Pending
Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

raw-data-access.mddocs/

Raw Data Access

Direct access to internal data structures including TTL metadata, useful for debugging and advanced use cases where expiry information is needed.

Capabilities

Get Raw

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'); // undefined

Get Many Raw

Retrieves 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([]); // []

Use Cases

Raw data access is particularly useful for:

TTL Monitoring

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"

Cache Warming

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);
}

Debugging and Monitoring

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]

docs

batch-operations.md

configuration.md

core-storage.md

events-hooks.md

index.md

raw-data-access.md

storage-adapters.md

tile.json