Limitly
API Reference

Type Exports

All TypeScript types are exported for use in your own code. Get full type safety and IDE autocomplete.

Type Exports

Limitly exports all TypeScript types for use in your own code. This provides full type safety, better IDE autocomplete, and makes it easier to build type-safe wrappers around Limitly.

Available Types

All types can be imported from 'limitly-sdk':

import type {
  LimitlyConfig,
  LimitlyResponse,
  RateLimitOptions,
  LimitlyClient
} from 'limitly-sdk';

LimitlyConfig

Configuration for creating a Limitly client:

interface LimitlyConfig {
  serviceId?: string;      // Service identifier for isolation
  redisUrl?: string;       // Redis connection URL
  timeout?: number;        // Request timeout in milliseconds
}

Example Usage

import type { LimitlyConfig } from 'limitly-sdk';
import { createClient } from 'limitly-sdk';

function createLimitlyClient(config: LimitlyConfig) {
  return createClient(config);
}

const client = createLimitlyClient({
  serviceId: 'my-api',
  timeout: 5000
});

LimitlyResponse

Response object returned by rate limit checks:

interface LimitlyResponse {
  allowed: boolean;        // Is request allowed?
  limit?: number;          // Total request limit
  remaining?: number;      // Requests remaining
  reset?: number;          // Unix timestamp (ms) when limit resets
  message?: string;        // Optional error message
}

Example Usage

import type { LimitlyResponse } from 'limitly-sdk';
import { createClient } from 'limitly-sdk';

// Recommended: Use your own Redis
const client = createClient({
  redisUrl: process.env.REDIS_URL || 'redis://localhost:6379',
  serviceId: 'my-app'
});

async function handleRequest(userId: string): Promise<LimitlyResponse> {
  const result: LimitlyResponse = await client.checkRateLimit(userId);
  
  if (!result.allowed) {
    console.log(`Rate limited. Reset at: ${new Date(result.reset!)}`);
  }
  
  return result;
}

RateLimitOptions

Options for checking rate limits:

interface RateLimitOptions {
  identifier?: string;     // User ID, IP, or other identifier
  capacity?: number;       // Maximum number of requests
  refillRate?: number;     // Tokens refilled per second
  window?: number;         // Time window in milliseconds
  skip?: boolean;          // Skip rate limiting
}

Example Usage

import type { RateLimitOptions } from 'limitly-sdk';
import { createClient } from 'limitly-sdk';

const client = createClient();

function checkCustomLimit(
  userId: string,
  options?: Partial<RateLimitOptions>
): Promise<LimitlyResponse> {
  return client.checkRateLimit({
    identifier: userId,
    ...options
  });
}

// Usage
await checkCustomLimit('user-123', {
  capacity: 50,
  refillRate: 5
});

LimitlyClient

Type for the client instance:

interface LimitlyClient {
  checkRateLimit(options?: RateLimitOptions | string): Promise<LimitlyResponse>;
  // ... other methods
}

Example Usage

import type { LimitlyClient } from 'limitly-sdk';
import { createClient } from 'limitly-sdk';

let client: LimitlyClient | null = null;

export function getClient(): LimitlyClient {
  if (!client) {
    client = createClient({ serviceId: 'my-api' });
  }
  return client;
}

Type Guards

Create type guards for better type safety:

import type { LimitlyResponse } from 'limitly-sdk';

function isRateLimited(response: LimitlyResponse): response is LimitlyResponse & { allowed: false } {
  return !response.allowed;
}

function isAllowed(response: LimitlyResponse): response is LimitlyResponse & { allowed: true } {
  return response.allowed;
}

// Usage
const result = await checkLimit('user-123');

if (isRateLimited(result)) {
  // TypeScript knows result.allowed is false here
  console.log('Rate limited:', result.message);
  const retryAfter = result.reset 
    ? Math.ceil((result.reset - Date.now()) / 1000) 
    : 60;
} else if (isAllowed(result)) {
  // TypeScript knows result.allowed is true here
  console.log('Allowed. Remaining:', result.remaining);
}

Typed Wrappers

Create type-safe wrappers around Limitly:

import type { LimitlyResponse, RateLimitOptions } from 'limitly-sdk';
import { createClient } from 'limitly-sdk';

interface ProtectedRouteOptions extends RateLimitOptions {
  userId: string;
  endpoint?: string;
}

async function protectedRoute(
  options: ProtectedRouteOptions
): Promise<LimitlyResponse> {
  const client = createClient({ serviceId: 'api' });
  
  return client.checkRateLimit({
    identifier: options.endpoint 
      ? `${options.userId}:${options.endpoint}`
      : options.userId,
    capacity: options.capacity,
    refillRate: options.refillRate,
    skip: options.skip
  });
}

// Usage with full type safety
const result = await protectedRoute({
  userId: 'user-123',
  endpoint: '/api/data',
  capacity: 100,
  refillRate: 10
});

Generic Helpers

Create generic helper functions with proper typing:

import type { LimitlyResponse } from 'limitly-sdk';
import { createClient } from 'limitly-sdk';

type RateLimitHandler<T> = (result: LimitlyResponse) => T;

async function withRateLimit<T>(
  identifier: string,
  onAllowed: RateLimitHandler<T>,
  onRateLimited: RateLimitHandler<T>
): Promise<T> {
  const client = createClient({
    redisUrl: process.env.REDIS_URL || 'redis://localhost:6379',
    serviceId: 'my-app'
  });
  const result = await client.checkRateLimit(identifier);
  
  return result.allowed ? onAllowed(result) : onRateLimited(result);
}

Usage:

const response = await withRateLimit(
  'user-123',
  (result) => ({ success: true, remaining: result.remaining }),
  (result) => ({ 
    success: false, 
    error: 'Rate limited',
    retryAfter: result.reset ? Math.ceil((result.reset - Date.now()) / 1000) : 60
  })
);

Complete Example

Putting it all together:

import type {
  LimitlyConfig,
  LimitlyResponse,
  RateLimitOptions,
  LimitlyClient
} from 'limitly-sdk';
import { createClient } from 'limitly-sdk';

// Typed configuration
const config: LimitlyConfig = {
  serviceId: 'my-api',
  timeout: 5000
};

// Typed client
const client: LimitlyClient = createClient(config);

// Typed options
const options: RateLimitOptions = {
  identifier: 'user-123',
  capacity: 100,
  refillRate: 10
};

// Typed response
const result: LimitlyResponse = await client.checkRateLimit(options);

// Type-safe handling
if (result.allowed && result.remaining !== undefined) {
  console.log(`Allowed. ${result.remaining} remaining.`);
} else if (!result.allowed) {
  console.log('Rate limited:', result.message);
}