Package Exports
- erlc-api
- erlc-api/index.js
This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (erlc-api) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.
Readme
🚔 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