Utilities Documentation

July 19, 2026 · View on GitHub

Internal cache and performance helpers for the npm CLI codebase.

End-user commands: doctor-command.md · OPEN_SOURCE_USER_SCENARIOS.md · ../README.md

Cache System

Using Cache

import { Cache, getCachedOrFetch } from './utils/cache.js';

// Simple usage
const data = await getCachedOrFetch('my-key', async () => {
  // Heavy operation
  return await fetchDataFromAPI();
});

// Advanced usage
const cache = Cache.getInstance();

// Save
await cache.set('user-data', userData, '1.0');

// Read
const cached = await cache.get('user-data', '1.0');

// Invalidate
await cache.invalidate('user-data');

// Clear all
await cache.clear();

Cache Features

  • Memory cache for fast access
  • Disk cache for persistence
  • TTL: fixed at 24 hours
  • Versioning: Version support
  • Lazy cleanup: Expired disk entries are removed when read

Performance Monitoring

Using Performance Monitor

import { PerformanceMonitor, measure, measurePerformance } from './utils/performance.js';

// Method 1: Manual timing
const monitor = PerformanceMonitor.getInstance();
monitor.start('my-operation');
// ... operation
monitor.end('my-operation');

// Method 2: Helper function
await measure('my-async-operation', async () => {
  await doSomethingHeavy();
});

// Method 3: Decorator (for methods)
class MyService {
  @measurePerformance
  async heavyOperation() {
    // This method is automatically measured
  }
}

// Show summary
monitor.summary();

// Get metrics
const metrics = monitor.getMetrics();
console.log(metrics);

Use Cases

  • Measure operation timing
  • Identify bottlenecks
  • Optimize performance
  • Debug performance issues

Best Practices

Cache

// ✅ Good: Use version for invalidation
await cache.set('data', myData, '2.0');

// ✅ Good: Use getCachedOrFetch
const result = await getCachedOrFetch('expensive-op', fetchData);

// ❌ Bad: Forgetting version
await cache.set('data', myData); // default version '1.0'

Performance

// ✅ Good: Measure heavy operations
await measure('database-query', () => db.query());

// ✅ Good: Show summary in development
if (process.env.NODE_ENV === 'development') {
  monitor.summary();
}

// ❌ Bad: Measuring trivial operations
monitor.start('simple-addition');
const result = 1 + 1;
monitor.end('simple-addition'); // overhead exceeds benefit

Integration Example

import { getCachedOrFetch } from './utils/cache.js';
import { measure } from './utils/performance.js';
import { logger } from './logger.js';

async function fetchUserData(userId: string) {
  const apiBaseUrl = process.env.API_BASE_URL ?? 'https://api.example.com';
  return await getCachedOrFetch(
    `user-${userId}`,
    async () => {
      return await measure('fetch-user-from-api', async () => {
        logger.debug(`Fetching user ${userId} from API`);
        const response = await fetch(`${apiBaseUrl}/users/${userId}`);
        return await response.json();
      });
    },
    '1.0'
  );
}

// Usage
const user = await fetchUserData('123');
// First time: Fetches from API and caches
// Second time: Reads from cache (fast)

Debugging

These utilities do not implement DEBUG=rapidkit:* namespace handling. Use the CLI's supported --debug flag where available, or enable logger.setDebug(true) in a focused maintainer harness.

Testing

import { describe, it, expect, beforeEach } from 'vitest';
import { Cache } from './utils/cache.js';

describe('Cache', () => {
  beforeEach(async () => {
    await Cache.getInstance().clear();
  });

  it('should cache and retrieve data', async () => {
    const cache = Cache.getInstance();
    await cache.set('test', { value: 42 });
    const result = await cache.get('test');
    expect(result).toEqual({ value: 42 });
  });

  it('should invalidate expired cache', async () => {
    // Test with mock Date.now()
  });
});

Migration Guide

If you have existing code that you want to add caching to:

// Before
async function loadTemplates() {
  const files = await fs.readdir(templateDir);
  return files.map(parseTemplate);
}

// After
async function loadTemplates() {
  return await getCachedOrFetch('templates', async () => {
    const files = await fs.readdir(templateDir);
    return files.map(parseTemplate);
  }, '1.0');
}

Troubleshooting

Cache not working

# Check cache location
ls -la "$HOME/.workspai/cache/"

# Clear cache manually
rm -rf "$HOME/.workspai/cache/"

# Check safe permissions (least privilege)
chmod 700 "$HOME/.workspai"
chmod 700 "$HOME/.workspai/cache"

Incorrect performance metrics

Verify that each timer is started and ended exactly once. For focused memory diagnostics, run node --expose-gc --max-old-space-size=4096 dist/index.js.