npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

gofast-ts-client

v1.0.0

Published

High-performance TypeScript client for GoFast distributed cache server

Readme

GoFast TypeScript Client

A high-performance TypeScript/JavaScript client library for the GoFast distributed cache server. This client provides a complete interface to all GoFast operations with full TypeScript support, connection pooling, and pipeline capabilities.

🚀 Features

  • Complete API Coverage - Support for all GoFast data types (strings, lists, sets, hashes)
  • TypeScript First - Full type safety with comprehensive TypeScript definitions
  • High Performance - Binary protocol with connection pooling and pipelining
  • Pipeline Support - Batch multiple operations for maximum throughput
  • Redis-Compatible - Familiar API for Redis users with friendly aliases
  • Robust Error Handling - Detailed error types and automatic retry logic
  • Zero Dependencies - Lightweight with no external dependencies

📦 Installation

npm install gofast-ts-client
# or
yarn add gofast-ts-client
# or
pnpm add gofast-ts-client

🏃 Quick Start

import { GoFastClient } from 'gofast-ts-client';

async function quickStart() {
  const client = new GoFastClient({
    host: 'localhost',
    port: 6379,
    timeout: 5000
  });

  try {
    // Connect to the server
    await client.connect();

    // Basic operations
    await client.set('greeting', 'Hello, World!');
    const message = await client.get('greeting');
    console.log(message); // "Hello, World!"

    // Atomic operations
    await client.set('counter', '0');
    const newValue = await client.incr('counter');
    console.log(newValue); // 1

    // List operations
    await client.lpush('tasks', 'important-task');
    await client.rpush('tasks', 'normal-task');
    const task = await client.lpop('tasks');
    console.log(task); // "important-task"

  } finally {
    await client.disconnect();
  }
}

quickStart();

📋 API Reference

Connection Management

// Create client with options
const client = new GoFastClient({
  host: 'localhost',      // Server host (default: 'localhost')
  port: 6379,             // Server port (default: 6379)
  timeout: 5000,          // Operation timeout in ms (default: 5000)
  maxRetries: 3,          // Max retry attempts (default: 3)
  retryDelay: 1000        // Delay between retries in ms (default: 1000)
});

// Connect and disconnect
await client.connect();
await client.disconnect();

// Check connection status
console.log(client.isConnected()); // true/false

Basic String Operations

// SET with optional TTL
await client.set('key', 'value');
await client.set('session', 'user123', { ttl: 3600 }); // 1 hour expiration

// GET
const value = await client.get('key');
console.log(value); // "value" or null if not found

// DELETE
const deleted = await client.del('key');
console.log(deleted); // true if key existed

// Multiple operations
const values = await client.mget(['key1', 'key2', 'key3']);
console.log(values); // ['value1', 'value2', null] - null for missing keys

const count = await client.mset({
  'user:1': 'Alice',
  'user:2': 'Bob',
  'user:3': 'Charlie'
}, 300); // 5-minute TTL
console.log(count); // 3 - number of keys set

Atomic Operations

// Increment/Decrement
await client.set('counter', '10');
const inc1 = await client.incr('counter');  // 11
const inc2 = await client.incr('counter');  // 12
const dec1 = await client.decr('counter');  // 11

// Get and Set atomically
const oldValue = await client.getSet('status', 'active');
console.log(oldValue); // previous value

List Operations

// Push operations
const len1 = await client.lpush('queue', 'high-priority');     // Add to front
const len2 = await client.rpush('queue', 'low-priority');      // Add to back
console.log(len1, len2); // 1, 2 - list lengths after each operation

// Pop operations
const highPri = await client.lpop('queue');    // Remove from front
const lowPri = await client.rpop('queue');     // Remove from back

// List inspection
const length = await client.llen('queue');           // Get list length
const item = await client.lindex('queue', 0);        // Get item at index
const range = await client.lrange('queue', 0, -1);   // Get range (0 to end)

Set Operations

// Add members (sets only store unique values)
const added1 = await client.sadd('tags', 'javascript');  // true - new member
const added2 = await client.sadd('tags', 'typescript');  // true - new member  
const added3 = await client.sadd('tags', 'javascript');  // false - already exists

// Set inspection
const members = await client.smembers('tags');      // ['javascript', 'typescript']
const count = await client.scard('tags');           // 2
const exists = await client.sismember('tags', 'go'); // false

// Remove members
const removed = await client.srem('tags', 'javascript'); // true if existed

Hash Operations

// Set hash fields
const new1 = await client.hset('user:123', 'name', 'Alice');     // true - new field
const new2 = await client.hset('user:123', 'email', '[email protected]');
const upd1 = await client.hset('user:123', 'name', 'Alice Smith'); // false - updated

// Get hash fields
const name = await client.hget('user:123', 'name');        // "Alice Smith"
const email = await client.hget('user:123', 'email');      // "[email protected]"
const phone = await client.hget('user:123', 'phone');      // null - doesn't exist

// Hash inspection
const user = await client.hgetall('user:123');     // { name: 'Alice Smith', email: '...' }
const fieldCount = await client.hlen('user:123');  // 2
const hasPhone = await client.hexists('user:123', 'phone'); // false

// Delete hash fields
const deleted = await client.hdel('user:123', 'email'); // true if field existed

Pattern Operations

// Find keys by pattern
const userKeys = await client.keys('user:*');       // ['user:123', 'user:456']
const allKeys = await client.keys('*');             // All keys

// Cursor-based scanning (better for large datasets)
let cursor = 0;
const allMatches = [];
do {
  const result = await client.scan(cursor, 'session:*', 100);
  allMatches.push(...result.keys);
  cursor = result.cursor;
} while (cursor !== 0);

🚀 Pipeline Operations

Pipeline operations allow you to batch multiple commands together for significantly better performance:

// Create a pipeline
const pipeline = client.pipeline();

// Queue multiple operations
pipeline
  .set('user:1', 'Alice')
  .set('user:2', 'Bob')
  .set('counter', '0')
  .incr('counter')
  .incr('counter')
  .get('user:1')
  .get('user:2')
  .get('counter')
  .lpush('notifications', 'welcome')
  .sadd('active_users', 'user:1')
  .hset('stats', 'users_online', '1');

console.log(`Pipeline has ${pipeline.length()} commands queued`);

// Execute all commands at once
const results = await pipeline.exec();
console.log('Results:', results);
// ['OK', 'OK', 'OK', '1', '2', 'Alice', 'Bob', '2', '1', '1', '1']

Pipeline Performance Benefits

async function performanceComparison() {
  // Individual operations (slower)
  console.time('Individual Operations');
  await client.set('a', '1');
  await client.set('b', '2');
  await client.get('a');
  await client.get('b');
  await client.incr('counter');
  await client.incr('counter');
  console.timeEnd('Individual Operations');

  // Pipeline operations (faster)
  console.time('Pipeline Operations');
  const results = await client.pipeline()
    .set('a', '1')
    .set('b', '2')
    .get('a')
    .get('b')
    .incr('counter')
    .incr('counter')
    .exec();
  console.timeEnd('Pipeline Operations');
  
  // Pipeline is typically 5-10x faster for multiple operations!
}

🎨 Friendly Aliases

The client provides both Redis-style commands and more descriptive aliases:

// Redis-style (familiar to Redis users)
await client.hset('user:1', 'name', 'Alice');
await client.hget('user:1', 'name');
await client.lpush('queue', 'job1');
await client.scard('tags');

// Friendly style (self-documenting)
await client.hashSet('user:1', 'name', 'Alice');
await client.hashGet('user:1', 'name');
await client.listPushLeft('queue', 'job1');
await client.setCount('tags');

// Both styles work identically - choose what feels natural!

Complete Alias Reference

| Redis Style | Friendly Style | Description | |-------------|----------------|-------------| | del(key) | delete(key) | Delete a key | | mget(keys) | multiGet(keys) | Get multiple values | | mset(pairs, ttl) | multiSet(pairs, ttl) | Set multiple key-value pairs | | incr(key) | increment(key) | Increment a number | | decr(key) | decrement(key) | Decrement a number | | getSet(key, value) | getAndSet(key, value) | Get old value and set new | | keys(pattern) | findKeys(pattern) | Find keys by pattern | | scan(...) | scanKeys(...) | Scan keys with cursor | | hset(key, field, value) | hashSet(key, field, value) | Set hash field | | hget(key, field) | hashGet(key, field) | Get hash field | | hdel(key, field) | hashDelete(key, field) | Delete hash field | | hgetall(key) | hashGetAll(key) | Get all hash fields | | hlen(key) | hashLength(key) | Get hash field count | | hexists(key, field) | hashExists(key, field) | Check if hash field exists | | lpush(key, value) | listPushLeft(key, value) | Add to list front | | rpush(key, value) | listPushRight(key, value) | Add to list back | | lpop(key) | listPopLeft(key) | Remove from list front | | rpop(key) | listPopRight(key) | Remove from list back | | llen(key) | listLength(key) | Get list length | | lindex(key, index) | listGetIndex(key, index) | Get list item by index | | lrange(key, start, end) | listGetRange(key, start, end) | Get list range | | sadd(key, member) | setAdd(key, member) | Add to set | | srem(key, member) | setRemove(key, member) | Remove from set | | smembers(key) | setGetMembers(key) | Get all set members | | scard(key) | setCount(key) | Get set member count | | sismember(key, member) | setIsMember(key, member) | Check set membership |

🔧 Error Handling

The client provides specific error types for different failure scenarios:

import { 
  GoFastClient, 
  ConnectionError, 
  ProtocolError, 
  TimeoutError 
} from 'gofast-ts-client';

async function handleErrors() {
  const client = new GoFastClient();
  
  try {
    await client.connect();
    await client.set('key', 'value');
  } catch (error) {
    if (error instanceof ConnectionError) {
      console.error('Connection failed:', error.message);
      // Maybe try to reconnect
    } else if (error instanceof TimeoutError) {
      console.error('Operation timed out:', error.message);
      // Maybe retry with longer timeout
    } else if (error instanceof ProtocolError) {
      console.error('Protocol error:', error.message);
      // Check server compatibility
    } else {
      console.error('Unknown error:', error);
    }
  }
}

⚙️ Configuration Options

const client = new GoFastClient({
  host: 'cache.example.com',    // Server hostname
  port: 6379,                   // Server port
  timeout: 10000,               // 10-second timeout
  maxRetries: 5,                // Retry failed operations 5 times
  retryDelay: 2000              // Wait 2 seconds between retries
});

📊 Real-World Examples

Session Management

class SessionManager {
  constructor(private client: GoFastClient) {}

  async createSession(userId: string, sessionData: any): Promise<string> {
    const sessionId = generateId();
    const sessionKey = `session:${sessionId}`;
    
    // Store session with 1-hour expiration
    await this.client.set(sessionKey, JSON.stringify(sessionData), { ttl: 3600 });
    
    // Add to user's active sessions
    await this.client.sadd(`user:${userId}:sessions`, sessionId);
    
    return sessionId;
  }

  async getSession(sessionId: string): Promise<any | null> {
    const sessionKey = `session:${sessionId}`;
    const data = await this.client.get(sessionKey);
    return data ? JSON.parse(data) : null;
  }

  async invalidateSession(sessionId: string, userId: string): Promise<void> {
    const pipeline = this.client.pipeline();
    pipeline
      .del(`session:${sessionId}`)
      .srem(`user:${userId}:sessions`, sessionId);
    
    await pipeline.exec();
  }
}

Real-time Analytics

class AnalyticsTracker {
  constructor(private client: GoFastClient) {}

  async trackPageView(page: string, userId?: string): Promise<void> {
    const today = new Date().toISOString().split('T')[0]; // YYYY-MM-DD
    const hour = new Date().getHours();
    
    const pipeline = this.client.pipeline();
    
    // Increment page view counters
    pipeline
      .incr(`pageviews:${page}:${today}`)
      .incr(`pageviews:${page}:${today}:${hour}`)
      .incr(`pageviews:total:${today}`);
    
    // Track unique users if provided
    if (userId) {
      pipeline
        .sadd(`unique_users:${page}:${today}`, userId)
        .sadd(`unique_users:total:${today}`, userId);
    }
    
    await pipeline.exec();
  }

  async getPageStats(page: string, date: string): Promise<any> {
    const pipeline = this.client.pipeline();
    
    // Get stats for the page
    pipeline
      .get(`pageviews:${page}:${date}`)
      .scard(`unique_users:${page}:${date}`);
    
    // Get hourly breakdown
    for (let hour = 0; hour < 24; hour++) {
      pipeline.get(`pageviews:${page}:${date}:${hour}`);
    }
    
    const results = await pipeline.exec();
    
    return {
      totalViews: parseInt(results[0] || '0'),
      uniqueUsers: parseInt(results[1] || '0'),
      hourlyViews: results.slice(2).map(v => parseInt(v || '0'))
    };
  }
}

Caching Layer

class CacheLayer {
  constructor(private client: GoFastClient) {}

  async cached<T>(
    key: string, 
    fetchFn: () => Promise<T>, 
    ttl: number = 300
  ): Promise<T> {
    // Try to get from cache first
    const cached = await this.client.get(key);
    if (cached) {
      return JSON.parse(cached);
    }
    
    // Not in cache, fetch the data
    const data = await fetchFn();
    
    // Store in cache for future requests
    await this.client.set(key, JSON.stringify(data), { ttl });
    
    return data;
  }

  async invalidatePattern(pattern: string): Promise<number> {
    const keys = await this.client.keys(pattern);
    if (keys.length === 0) return 0;
    
    // Delete all matching keys in a pipeline
    const pipeline = this.client.pipeline();
    keys.forEach(key => pipeline.del(key));
    
    const results = await pipeline.exec();
    return results.filter(r => r === '1').length;
  }
}

// Usage
const cache = new CacheLayer(client);

const userData = await cache.cached(
  `user:${userId}`, 
  () => database.getUser(userId),
  600 // Cache for 10 minutes
);

🧪 Testing

import { GoFastClient } from 'gofast-ts-client';

describe('GoFast Client', () => {
  let client: GoFastClient;

  beforeEach(async () => {
    client = new GoFastClient({ 
      host: process.env.GOFAST_HOST || 'localhost',
      port: parseInt(process.env.GOFAST_PORT || '6379')
    });
    await client.connect();
  });

  afterEach(async () => {
    await client.disconnect();
  });

  test('basic set and get', async () => {
    await client.set('test:key', 'test value');
    const value = await client.get('test:key');
    expect(value).toBe('test value');
  });

  test('pipeline operations', async () => {
    const results = await client.pipeline()
      .set('a', '1')
      .set('b', '2')
      .get('a')
      .get('b')
      .exec();
    
    expect(results).toEqual(['OK', 'OK', '1', '2']);
  });
});

🔄 Migration from Redis

If you're migrating from a Redis client, the GoFast client provides a very similar API:

// Redis client code
await redis.set('key', 'value');
await redis.get('key');
await redis.hset('hash', 'field', 'value');
await redis.lpush('list', 'item');

// GoFast client code (nearly identical!)
await client.set('key', 'value');
await client.get('key');
await client.hset('hash', 'field', 'value');
await client.lpush('list', 'item');

📈 Performance Tips

  1. Use Pipelines - Batch operations whenever possible
  2. Connection Reuse - Keep connections open for the lifetime of your application
  3. Appropriate TTLs - Set expiration times to prevent memory bloat
  4. Batch Reads - Use mget() instead of multiple get() calls
  5. Pattern Operations - Use scan() instead of keys() for large datasets

🐛 Troubleshooting

Connection Issues

// Check if server is running
const client = new GoFastClient({ timeout: 1000 });
try {
  await client.connect();
  console.log('✅ Server is running');
} catch (error) {
  console.log('❌ Server is not accessible:', error.message);
}

Debug Mode

// Enable verbose logging (if implemented)
const client = new GoFastClient({ 
  host: 'localhost',
  port: 6379,
  debug: true  // Log all commands and responses
});

Performance Monitoring

// Measure operation timing
console.time('operation');
await client.get('key');
console.timeEnd('operation');

// Pipeline vs individual timing
console.time('individual');
await client.set('a', '1');
await client.set('b', '2');
await client.get('a');
console.timeEnd('individual');

console.time('pipeline');
await client.pipeline()
  .set('a', '1')
  .set('b', '2')
  .get('a')
  .exec();
console.timeEnd('pipeline');

📄 License

MIT License - see LICENSE file for details.

🤝 Contributing

  1. Fork the repository
  2. Create a feature branch: git checkout -b feature/amazing-feature
  3. Commit your changes: git commit -m 'Add amazing feature'
  4. Push to the branch: git push origin feature/amazing-feature
  5. Open a Pull Request

Built with ❤️ for high-performance caching. Star ⭐ the project if you find it useful!