Important: This documentation covers Yarn 1 (Classic).
For Yarn 2+ docs and migration guide, see yarnpkg.com.

Package detail

erlc-api

Exodo0183MIT3.1.0TypeScript support: included

An ER:LC API wrapper for JS/TS

erlc, roblox, prc, erlc-api, liberty-county

readme

🚔 ER:LC API Wrapper

npm version License: MIT

A comprehensive, lightweight, and fully-typed API wrapper for Emergency Response: Liberty County (ER:LC) with 100% API coverage, robust error handling, and TypeScript support.

✨ Features

  • 🎯 100% API Coverage - All ER:LC API endpoints supported
  • 🛡️ Robust Error Handling - Comprehensive error catching and meaningful error messages
  • 📝 Full TypeScript Support - Complete type definitions for all methods and responses
  • Optimized Performance - Efficient request handling with timeout management
  • 🔒 Secure - Built-in validation and secure token handling
  • 📚 Well Documented - Extensive documentation and examples
  • 🚀 Easy to Use - Simple, intuitive API design

📦 Installation

npm install erlc-api
bun add erlc-api

🚀 Quick Start

Basic Setup

const erlc = require("erlc-api");

// Initialize the client with your global token
const client = new erlc.Client({
  globalToken: "your-global-token-here", // Get this from ER:LC developers
});

// Register your client
client.config();

TypeScript Setup

import erlc from "erlc-api";

const client = new erlc.Client({
  globalToken: "your-global-token-here",
});

client.config();

📖 API Methods

🖥️ Server Information

Get Server Details

const getServerInfo = async () => {
  try {
    const serverToken = "your-server-api-key"; // From Server Settings
    const server = await erlc.getServer(serverToken);

    console.log(server);
    /*
    Expected Response:
    {
      Name: "Your Server Name",
      OwnerUsername: "ServerOwner",
      CoOwnerUsernames: ["CoOwner1", "CoOwner2"],
      CurrentPlayers: 25,
      MaxPlayers: 40,
      JoinKey: "ABC123",
      AccVerifiedReq: "Disabled", // "Email" | "Phone/ID"
      TeamBalance: true,
      VanityURL: "https://policeroleplay.community/join?code=ABC123"
    }
    */
  } catch (error) {
    console.error("Error fetching server info:", error.message);
  }
};

Get Current Players

const getCurrentPlayers = async () => {
  try {
    const players = await erlc.getPlayers(serverToken);

    console.log(players);
    /*
    Expected Response:
    [
      {
        Player: "PlayerName:123456789",
        Permission: "Server Owner", // "Member" | "Moderator" | "Server Administrator"
        Team: "Police" // "Civilian" | "Fire" | "Sheriff"
      }
    ]
    */
  } catch (error) {
    console.error("Error fetching players:", error.message);
  }
};

Get Server Queue

const getServerQueue = async () => {
  try {
    const queue = await erlc.getQueue(serverToken);
    console.log(`Players in queue: ${queue.length}`);
  } catch (error) {
    console.error("Error fetching queue:", error.message);
  }
};

👥 Staff Management

Get Staff Information

const getStaffInfo = async () => {
  try {
    const staff = await erlc.getStaff(serverToken);

    console.log(staff);
    /*
    Expected Response:
    {
      CoOwners: [123456789, 987654321],
      Admins: { "123456789": "AdminName" },
      Mods: { "987654321": "ModName" }
    }
    */
  } catch (error) {
    console.error("Error fetching staff:", error.message);
  }
};

📊 Server Logs

Get Join/Leave Logs

const getJoinLogs = async () => {
  try {
    const logs = await erlc.getJoinLogs(serverToken);

    logs.forEach((log) => {
      const action = log.Join ? "joined" : "left";
      console.log(
        `${log.Player} ${action} at ${new Date(log.Timestamp * 1000)}`
      );
    });
  } catch (error) {
    console.error("Error fetching join logs:", error.message);
  }
};

Get Kill Logs

const getKillLogs = async () => {
  try {
    const kills = await erlc.getKillLogs(serverToken);

    kills.forEach((kill) => {
      console.log(
        `${kill.Killer} killed ${kill.Killed} at ${new Date(
          kill.Timestamp * 1000
        )}`
      );
    });
  } catch (error) {
    console.error("Error fetching kill logs:", error.message);
  }
};

Get Command Logs

const getCommandLogs = async () => {
  try {
    const commands = await erlc.getCommandLogs(serverToken);

    commands.forEach((cmd) => {
      console.log(`${cmd.Player} executed: ${cmd.Command}`);
    });
  } catch (error) {
    console.error("Error fetching command logs:", error.message);
  }
};

Get Moderator Call Logs

const getModCalls = async () => {
  try {
    const modcalls = await erlc.getModcallLogs(serverToken);

    modcalls.forEach((call) => {
      const status = call.Moderator
        ? `answered by ${call.Moderator}`
        : "unanswered";
      console.log(`${call.Caller} made a modcall - ${status}`);
    });
  } catch (error) {
    console.error("Error fetching modcall logs:", error.message);
  }
};

🚗 Vehicle Management

Get Server Vehicles

const getVehicles = async () => {
  try {
    const vehicles = await erlc.getVehicles(serverToken);

    vehicles.forEach((vehicle) => {
      console.log(
        `${vehicle.Name} owned by ${vehicle.Owner} - Texture: ${
          vehicle.Texture || "Default"
        }`
      );
    });
  } catch (error) {
    console.error("Error fetching vehicles:", error.message);
  }
};

🔨 Server Management

Execute Server Commands

const executeCommand = async () => {
  try {
    const success = await erlc.runCommand(
      serverToken,
      ":h Welcome to our server!"
    );

    if (success) {
      console.log("Command executed successfully!");
    }
  } catch (error) {
    console.error("Error executing command:", error.message);
  }
};

Get Server Bans

const getBannedPlayers = async () => {
  try {
    const bans = await erlc.getBans(serverToken);

    Object.entries(bans).forEach(([playerId, playerName]) => {
      console.log(`${playerName} (${playerId}) is banned`);
    });
  } catch (error) {
    console.error("Error fetching bans:", error.message);
  }
};

🛠️ Advanced Usage

Error Handling Best Practices

const handleApiCall = async () => {
  try {
    const result = await erlc.getServer(serverToken);
    return result;
  } catch (error) {
    // The error is now an ErlcError with detailed information
    console.error(`Error ${error.code}: ${error.message}`);
    console.error(`Category: ${error.category}, Severity: ${error.severity}`);

    // Handle specific ERLC error codes
    switch (error.code) {
      case 2002:
        console.error(
          "Invalid server key - get a new one from server settings"
        );
        break;
      case 4001:
        console.error("Rate limited - reduce request frequency");
        break;
      case 3002:
        console.error("Server offline - wait for players to join");
        break;
      case 9999:
        console.error("Server module outdated - restart server");
        break;
    }

    // Show suggested actions
    if (error.suggestions) {
      console.error("Suggested actions:");
      error.suggestions.forEach((action) => console.error(`- ${action}`));
    }

    // Check if error is retryable
    if (error.retryable) {
      console.error("This error might be resolved by retrying");
    }

    throw error; // Re-throw if needed
  }
};

Batch Operations

const getServerOverview = async (serverToken) => {
  try {
    // Execute multiple API calls concurrently
    const [serverInfo, players, staff, vehicles] = await Promise.all([
      erlc.getServer(serverToken),
      erlc.getPlayers(serverToken),
      erlc.getStaff(serverToken),
      erlc.getVehicles(serverToken),
    ]);

    return {
      server: serverInfo,
      playerCount: players.length,
      staffCount:
        Object.keys(staff.Admins).length + Object.keys(staff.Mods).length,
      vehicleCount: vehicles.length,
    };
  } catch (error) {
    console.error("Error getting server overview:", error.message);
    throw error;
  }
};

🔑 Authentication

Getting Your Tokens

  1. Global Token: Contact ER:LC developers through their Discord to request increased API limits
  2. Server Token: Found in your server settings within ER:LC

Token Security

// ❌ Don't hardcode tokens
const client = new erlc.Client({
  globalToken: "your-token-here",
});

// ✅ Use environment variables
const client = new erlc.Client({
  globalToken: process.env.ERLC_GLOBAL_TOKEN,
});

📝 TypeScript Support

The package includes comprehensive TypeScript definitions:

import erlc, { ServerStatus, ServerPlayer, JoinLog } from "erlc-api";

const client = new erlc.Client({
  globalToken: process.env.ERLC_GLOBAL_TOKEN!,
});

client.config();

// Fully typed responses
const server: ServerStatus = await erlc.getServer(serverToken);
const players: ServerPlayer[] = await erlc.getPlayers(serverToken);
const joinLogs: JoinLog[] = await erlc.getJoinLogs(serverToken);

⚡ Performance Tips

  1. Use Promise.all() for concurrent requests when fetching multiple endpoints
  2. Implement caching for frequently accessed data that doesn't change often
  3. Handle rate limits by implementing retry logic with exponential backoff
  4. Use timeouts - all methods have built-in 10-15 second timeouts

🐛 Error Types

The wrapper provides comprehensive error handling with specific ERLC error codes:

ERLC Error Codes

Code Category Description
0 System Error Unknown error occurred
1001 Communication Error Error communicating with Roblox server
1002 System Error Internal system error
2000 Authentication Error Missing server key
2001 Authentication Error Invalid server key format
2002 Authentication Error Invalid or expired server key
2003 Authentication Error Invalid global API key
2004 Authentication Error Server key banned
3001 Request Error Invalid command provided
3002 Request Error Server offline (no players)
4001 Rate Limit Error Rate limited
4002 Permission Error Restricted command
4003 Content Error Prohibited message
9998 Access Error Restricted resource
9999 Version Error Outdated server module

Error Properties

All errors are instances of ErlcError with these properties:

  • code: ERLC error code or HTTP status
  • message: Human-readable error message
  • category: Error category (e.g., "AUTHENTICATION_ERROR")
  • severity: Error severity ("LOW", "MEDIUM", "HIGH", "CRITICAL")
  • suggestions: Array of suggested actions to resolve the error
  • retryable: Boolean indicating if the error might be resolved by retrying
  • timestamp: ISO timestamp when the error occurred

Retry Logic Example

async function withRetry(apiCall, maxRetries = 3) {
  for (let attempt = 1; attempt <= maxRetries; attempt++) {
    try {
      return await apiCall();
    } catch (error) {
      if (!error.retryable || attempt === maxRetries) {
        throw error;
      }

      // Wait before retrying with exponential backoff
      const delay = 1000 * Math.pow(2, attempt - 1);
      await new Promise((resolve) => setTimeout(resolve, delay));
    }
  }
}

// Usage
const players = await withRetry(() => erlc.getPlayers(serverToken));

🤝 Contributing

We welcome contributions! Please see our Contributing Guide for details.

📄 License

This project is licensed under the MIT License - see the LICENSE file for details.

👨‍💻 Credits


Made with ❤️ for the ER:LC community

⭐ Star us on GitHub💬 Join our Discord🐦 Follow on Twitter