🚔 ER:LC API Wrapper
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-apibun 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
- Global Token: Contact ER:LC developers through their Discord to request increased API limits
- 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
- Use Promise.all() for concurrent requests when fetching multiple endpoints
- Implement caching for frequently accessed data that doesn't change often
- Handle rate limits by implementing retry logic with exponential backoff
- 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 statusmessage: Human-readable error messagecategory: Error category (e.g., "AUTHENTICATION_ERROR")severity: Error severity ("LOW", "MEDIUM", "HIGH", "CRITICAL")suggestions: Array of suggested actions to resolve the errorretryable: Boolean indicating if the error might be resolved by retryingtimestamp: 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.
🔗 Links
- Discord Bot: Invite to your server
- API Documentation: PRC API Docs
- Discord Support: Join PRC Discord
- Custom Liveries: Browse Collection
👨💻 Credits
- Library Development: Egologics
- NPM Package: ERLC-API
- API Development: Police Roleplay Community
- Community Support: PRC Discord Community
Made with ❤️ for the ER:LC community
⭐ Star us on GitHub • 💬 Join our Discord • 🐦 Follow on Twitter