Socket
Book a DemoInstallSign in
Socket

@shipengine/connect-rate-limiter

Package Overview
Dependencies
Maintainers
43
Versions
3
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@shipengine/connect-rate-limiter

Connect rate limiter

latest
npmnpm
Version
1.0.2
Version published
Maintainers
43
Created
Source

Connect Rate Limiter

A Redis-based rate limiting library for ShipEngine Connect modules, providing distributed rate limiting and quota management capabilities.

Overview

The Connect Rate Limiter provides a simple, Redis-backed solution for implementing rate limiting in Connect carrier modules. It supports multiple rate limiting strategies including rolling and fixed windows, with optional quota management for longer-term limits.

Installation

For local testing and development:

# In the connect-rate-limiter directory
cd shared-libs/connect-rate-limiter
npm install
npm run build
npm link

# In your Connect module directory
cd modules/your-module
npm link @shipengine/connect-rate-limiter

Using File Path in package.json

Add to your Connect module's package.json:

{
  "dependencies": {
    "@shipengine/connect-rate-limiter": "file:../../shared-libs/connect-rate-limiter"
  }
}

Then run:

npm install

Prerequisites

  • Redis server running and accessible
  • Node.js 14+ with TypeScript support
  • ShipEngine Connect Runtime environment

Local Development Setup

The package includes a Docker Compose configuration for easy local Redis setup:

# docker-compose.yml (included in the package)
version: '3.8'

services:
  redis:
    image: redis:7-alpine
    container_name: connect-rate-limiter-redis
    ports:
      - "6379:6379"
    volumes:
      - redis_data:/data
    command: redis-server --appendonly yes
    restart: unless-stopped
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 10s
      timeout: 3s
      retries: 3

volumes:
  redis_data:

Start Redis for local development:

# In the connect-rate-limiter directory
docker compose up -d

# Check Redis is running
docker compose ps

# View Redis logs
docker compose logs redis

# Stop Redis when done
docker compose down

Configuration

The rate limiter automatically connects to Redis at localhost:6379 by default for local development. For custom Redis configurations, you can provide a Redis configuration object with the following structure:

{
  "host": "your-redis-host",
  "port": 6379,
  "connectTimeout": 3000,
  "commandTimeout": 3000,
  "retryDelayOnFailover": 100,
  "maxRetriesPerRequest": 3,
  "tls": {}
}

Configuration Options:

  • host: Redis server hostname
  • port: Redis server port (default: 6379)
  • connectTimeout: Connection timeout in milliseconds
  • commandTimeout: Command execution timeout in milliseconds
  • retryDelayOnFailover: Delay between retry attempts in milliseconds
  • maxRetriesPerRequest: Maximum number of retry attempts per request
  • tls: TLS configuration object (empty object enables TLS with default settings)

Production Deployment: For production environments, Redis configuration needs to be set up in the infra/helm directory, similar to the current setup for the dummy module. Add the Redis configuration to your module's values.yaml:

# infra/helm/your-module/values.yaml
secret:
  REDIS_CONFIGURATION: '#{YOUR_MODULE_REDIS_CONFIGURATION}'

This ensures proper Redis connectivity in deployed environments by using the appropriate Redis instance for your module.

Usage

Basic Setup

Create a rate limiter configuration file in your Connect module:

// src/rate-limit-config.ts
import {
    RateLimitMode,
    RateLimitConfiguration,
    RateLimiter,
    QuotaRateLimitConfig
} from '@shipengine/connect-rate-limiter';

// Create a singleton instance
export const rateLimiter = new RateLimiter();

// Default configuration with quota (10 requests per minute, 15 per day)
export const quotaRateLimitConfig: QuotaRateLimitConfig = {
    rateLimit: {
        maxRequests: 10,
        windowSize: 60
    },
    quota: {
        maxRequests: 15,
        windowSize: 86400 // 24 hours
    }
};

export const baseLimitConfig: RateLimitConfiguration = {
    strategy: {
        mode: RateLimitMode.ROLLING_QUOTA_ROLLING_RATE_LIMIT
    },
    config: quotaRateLimitConfig
};

Integration in Connect Methods

Method 1: Using checkRateLimitAndIncrementCounter with Base Configuration

This method checks rate limits and increments counters using the base configuration. This should be used for carriers with rate limits configured for our entire organization (one limit for the whole module)

// src/methods/track/track.ts
import { TrackingRequest, TrackingResponse } from '@shipengine/connect-carrier-api';
import { rateLimiter, baseLimitConfig } from '../../rate-limit-config';

export const Track = async (request: TrackingRequest): Promise<TrackingResponse> => {
    // Check rate limit and increment counter before executing API call
    // Rate limit errors are automatically handled by the package
    const sellerId = request.metadata?.seller_id;
    const limitId = `your_module_se-${sellerId}`;

    await rateLimiter.checkRateLimitAndIncrementCounter(limitId, baseLimitConfig);

    // Execute api call after rate limit check
    const apiResponse = await callCarrierAPI(request);
    return mapResponse(apiResponse);
};

Method 2: Using checkRateLimitAndIncrementCounter with Metadata Configuration

For cases where rate limit configuration comes from seller metadata (set during registration). This should be used for carriers with rate limits configured per each seller.

// src/methods/track/track.ts
import { TrackingRequest, TrackingResponse } from '@shipengine/connect-carrier-api';
import { rateLimiter, baseLimitConfig } from '../../rate-limit-config';

export const Track = async (request: TrackingRequest): Promise<TrackingResponse> => {
    const sellerId = request.metadata?.seller_id;
    const limitId = `your_module_${sellerId}`;

    // Use configuration from metadata if available, otherwise use base config
    const rateLimitConfig = request.metadata?.rate_limit_config || baseLimitConfig;

    // Rate limit check and increment counter with configuration from metadata or base config
    // Errors are automatically handled by the package
    await rateLimiter.checkRateLimitAndIncrementCounter(limitId, rateLimitConfig);

    // Execute api call
    const apiResponse = await callCarrierAPI(request);
    return mapResponse(apiResponse);
};

Per-Seller Rate Limiting

For carriers that have per-seller API limits:

export const Track = async (request: TrackingRequest): Promise<TrackingResponse> => {
    const sellerId = request.metadata?.seller_id;
    const limitId = `your_module_se-${sellerId}`;

    await rateLimiter.checkRateLimitAndIncrementCounter(limitId, baseLimitConfig);
    return performTracking(request);
};

Dynamic Configuration in Register Method

Set up rate limiting configuration during carrier registration:

// src/methods/register/register.ts
import { RegisterRequest, RegisterResponse } from '@shipengine/connect-carrier-api';
import { rateLimiter, RateLimitMode } from '../../rate-limit-config';

export const Register = async (request: RegisterRequest): Promise<RegisterResponse> => {
    const registrationInfo = request.registration_info;

    // Set up rate limiting based on registration information
    if (registrationInfo.api_rate_limit) {
        await rateLimiter.setConfiguration(`your_module_se-${request.metadata.seller_id}`, {
            strategy: { mode: RateLimitMode.ROLLING_RATE_LIMIT },
            config: {
                rateLimit: {
                    maxRequests: registrationInfo.api_rate_limit.max_requests,
                    windowSize: registrationInfo.api_rate_limit.window_size
                }
            }
        });
    }

    // Continue with registration logic
    return mapRegistrationResponse(registrationInfo);
};

Note: Configuration updates should also be handled in the UpdateSettings method. Use the same setConfiguration pattern when processing settings changes to ensure rate limiting configurations stay synchronized with carrier settings.

Rate Limiting Modes

The library supports six different rate limiting modes:

Simple Rate Limiting

  • ROLLING_RATE_LIMIT: Sliding window rate limiting (most common)
  • FIXED_RATE_LIMIT: Fixed window rate limiting

Rate Limiting with Quota

  • ROLLING_QUOTA_ROLLING_RATE_LIMIT: Rolling quota with rolling rate limit
  • ROLLING_QUOTA_FIXED_RATE_LIMIT: Rolling quota with fixed rate limit
  • FIXED_QUOTA_ROLLING_RATE_LIMIT: Fixed quota with rolling rate limit
  • FIXED_QUOTA_FIXED_RATE_LIMIT: Fixed quota with fixed rate limit

Configuration Examples

// Default configuration: 10 requests per minute, 1000 per day
const defaultConfig: RateLimitConfiguration = {
    strategy: { mode: RateLimitMode.ROLLING_QUOTA_ROLLING_RATE_LIMIT },
    config: {
        rateLimit: {
            maxRequests: 10,
            windowSize: 60
        },
        quota: {
            maxRequests: 1000,
            windowSize: 86400
        }
    }
};

Error Handling

When using checkRateLimitAndIncrementCounter(), error handling is automatically managed by the package. The library will throw appropriate Connect runtime errors that are handled by the Connect framework.

The library provides specific error types for different rate limiting scenarios:

  • RateLimitExceededError: Thrown when short-term rate limits are exceeded
  • QuotaExceededError: Thrown when long-term quota limits are exceeded
  • RateLimiterError: Thrown for other rate limiter errors

These errors are automatically converted to appropriate Connect runtime errors and handled by the framework. You typically don't need to catch these errors manually when using checkRateLimitAndIncrementCounter().

For advanced use cases where you need custom error handling, you can use the isAllowed() method instead:

import { rateLimiter, baseLimitConfig } from '../../rate-limit-config';

const limitId = `your_module_${sellerId}`;
const isAllowed = await rateLimiter.checkRateLimitAndIncrementCounter(limitId, baseLimitConfig);

if (!isAllowed) {
    // Handle rate limiting without exceptions
    return customRateLimitResponse();
}

Testing

Running Tests

# Run all tests
npm test

# Run with coverage
npm run test -- --coverage

# Run specific test file
npm test -- rate-limiter.test.ts

Deployment

The package is automatically published to npm after merging changes to the master branch.

To use the latest version in your Connect module:

npm install @shipengine/connect-rate-limiter@latest

Or update your package.json to use the latest version and run npm install.

FAQs

Package last updated on 08 Oct 2025

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts