A comprehensive and enhanced Node.js API for accessing MCPEDL.org content. This improved version provides better error handling, TypeScript support, rate limiting, retry mechanisms, and comprehensive documentation.
- 🚀 Enhanced Performance: Built-in rate limiting and retry mechanisms
- đź”’ Type Safety: Full TypeScript support with comprehensive type definitions
- 🛡️ Robust Error Handling: Detailed error messages with proper error codes
- ⚡ Input Validation: Validates all parameters before making requests
- 🔄 Retry Logic: Automatic retry for failed requests with exponential backoff
- 📝 Comprehensive Documentation: Detailed JSDoc comments and examples
- đź§Ş Tested: Unit tests with Jest for reliability
- 🎨 Code Quality: ESLint and Prettier for consistent code style
npm install github:terastudio-org/mcpedl
# or
yarn add github:terastudio-org/mcpedlimport { McpedlAPI } from 'mcpedl';
const mc = new McpedlAPI();
// Search for content
const searchResults = await mc.search('minecraft 1.21', 1);
console.log(searchResults);
// Get detailed information
const detail = await mc.detail('minecraft-pe-1-21-124-apk');
console.log(detail);
// Get download URL
const download = await mc.download(6517);
console.log(download);
// Get latest content
const latest = await mc.mclatest(1);
console.log(latest);You can customize the API behavior by passing a configuration object:
const mc = new McpedlAPI({
timeout: 15000, // Request timeout in milliseconds
maxRetries: 5, // Maximum retry attempts
retryDelay: 2000, // Initial retry delay in milliseconds
rateLimit: {
minTime: 2000, // Minimum time between requests (ms)
maxConcurrent: 1 // Maximum concurrent requests
},
baseURL: 'https://mcpedl.org', // Base URL for API requests
userAgent: 'Custom User Agent'
});The main class for interacting with the MCPEDL API.
new McpedlAPI(config?: McpedlConfig): McpedlAPISearches for content on MCPEDL.
Parameters:
query(string): Search query (required, non-empty)page(number): Page number (optional, default: 1, positive integer)
Returns: Promise<SearchResult>
Example:
try {
const results = await mc.search('texture pack', 2);
console.log(`Found ${results.list.length} results`);
console.log(`Has next page: ${results.hasNextPage}`);
if (results.nextPage) {
console.log(`Next page: ${results.nextPage}`);
}
} catch (error) {
console.error('Search failed:', error.message);
}Retrieves detailed information about a specific post.
Parameters:
id(string): Post ID (required, non-empty string)
Returns: Promise<DetailResult>
Example:
try {
const post = await mc.detail('minecraft-pe-1-21-124-apk');
console.log(`Title: ${post.title}`);
console.log(`Rating: ${post.rating.value}/5 (${post.rating.count} votes)`);
console.log(`Category: ${post.info.category}`);
console.log(`Downloads available: ${post.list.length}`);
// Display gallery
post.gallery.forEach(item => {
console.log(`${item.type}: ${item.img}`);
});
// Display FAQ
post.faq.forEach(item => {
console.log(`Q: ${item.question}`);
console.log(`A: ${item.answer}`);
});
} catch (error) {
console.error('Failed to get details:', error.message);
}Gets the download URL for a file.
Parameters:
id(number): Download ID (required, positive integer)
Returns: Promise<DownloadResult>
Example:
try {
const downloadInfo = await mc.download(6517);
console.log(`Download URL: ${downloadInfo.url}`);
// Use the URL to download the file
} catch (error) {
console.error('Failed to get download URL:', error.message);
}Gets the latest Minecraft content.
Parameters:
page(number): Page number (optional, default: 1, positive integer)
Returns: Promise<LatestResult>
Example:
try {
const latest = await mc.mclatest(1);
console.log(`Quick downloads: ${latest.quick.length}`);
console.log(`Regular listings: ${latest.list.length}`);
latest.quick.forEach(item => {
console.log(`${item.name} (File ID: ${item.file})`);
});
} catch (error) {
console.error('Failed to get latest content:', error.message);
}Returns the current configuration.
Returns: Required<McpedlConfig>
Updates the configuration at runtime.
Parameters:
newConfig(Partial): New configuration options
interface SearchResult {
list: SearchItem[];
hasNextPage: boolean;
nextPage?: number;
}
interface SearchItem {
name: string;
id: string;
img: string;
rating: string;
}interface DetailResult {
title: string;
img: string;
rating: {
count: string;
value: string;
};
comment: string;
content: string;
info: PostInfo;
gallery: GalleryItem[];
faq: FAQItem[];
list: DownloadItem[];
}
interface PostInfo {
category: string;
postDate: string;
author: string;
[key: string]: any;
}
interface GalleryItem {
type: 'image' | 'video';
img: string;
name?: string;
postTime?: string;
duration?: string | null;
video?: string | null;
}
interface FAQItem {
question: string;
answer: string;
}
interface DownloadItem {
index: number;
name: string;
version: string;
files: DownloadFile[];
}
interface DownloadFile {
index: number;
type: string;
id: number;
meta_title?: string | null;
}interface DownloadResult {
url: string;
}interface LatestResult {
quick: QuickDownload[];
list: SearchItem[];
}
interface QuickDownload {
name: string;
id: string;
file: number;
}The API provides detailed error information through the McpedlError class:
import { McpedlError } from 'improved-mcpedl-api';
try {
const results = await mc.search('');
} catch (error) {
if (error instanceof McpedlError) {
console.error(`Error Code: ${error.code}`);
console.error(`HTTP Status: ${error.status}`);
console.error(`Message: ${error.message}`);
if (error.originalError) {
console.error('Original Error:', error.originalError);
}
}
}INVALID_QUERY: Search query is empty or invalidINVALID_PAGE: Page number is invalidINVALID_ID: Post ID is empty or invalidINVALID_DOWNLOAD_ID: Download ID is invalidNOT_FOUND: Requested resource not found (404)RATE_LIMIT: Rate limit exceeded (429)SERVER_ERROR: Server error (5xx)TIMEOUT: Request timeoutREQUEST_FAILED: General request failureSEARCH_FAILED: Search operation failedDETAIL_FAILED: Detail operation failedDOWNLOAD_FAILED: Download operation failedDOWNLOAD_URL_NOT_FOUND: Download URL not foundCONFIG_ERROR: Configuration error
git clone https://github.com/terastudio-org/mcpedl.git
cd mcpedl
npm installnpm run build- Build the projectnpm run dev- Run in development modenpm start- Run the built versionnpm test- Run testsnpm test:watch- Run tests in watch modenpm run lint- Run ESLintnpm run lint:fix- Fix ESLint issuesnpm run format- Format code with Prettiernpm run example- Run the examplenpm run clean- Clean build directory
Check the examples/usage.ts file for a comprehensive example.
import { McpedlAPI } from 'improved-mcpedl-api';
const mc = new McpedlAPI({
rateLimit: { minTime: 3000, maxConcurrent: 1 }
});
async function getMultipleDetails(ids: string[]) {
const results = [];
for (const id of ids) {
try {
const detail = await mc.detail(id);
results.push({ id, success: true, data: detail });
} catch (error) {
results.push({
id,
success: false,
error: error instanceof McpedlError ? error.message : 'Unknown error'
});
}
}
return results;
}
// Usage
const ids = ['minecraft-pe-1-21-124-apk', 'texture-pack-example'];
const results = await getMultipleDetails(ids);const mc = new McpedlAPI({
timeout: 30000, // 30 second timeout
maxRetries: 5, // More retries
retryDelay: 3000, // 3 second initial delay
rateLimit: {
minTime: 5000, // 5 seconds between requests
maxConcurrent: 1 // Only one request at a time
},
userAgent: 'MyApp/1.0 (Contact: developer@example.com)'
});
// Update configuration later
mc.updateConfig({
maxRetries: 3,
timeout: 20000
});import { McpedlAPI, McpedlError } from 'improved-mcpedl-api';
const mc = new McpedlAPI();
async function robustSearch(query: string, maxAttempts = 3) {
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
try {
return await mc.search(query);
} catch (error) {
if (error instanceof McpedlError) {
if (error.code === 'RATE_LIMIT') {
console.log(`Rate limited. Waiting before attempt ${attempt + 1}...`);
await new Promise(resolve => setTimeout(resolve, 10000)); // Wait 10 seconds
continue;
}
if (error.code === 'SERVER_ERROR' && attempt < maxAttempts) {
console.log(`Server error on attempt ${attempt}. Retrying...`);
await new Promise(resolve => setTimeout(resolve, 2000 * attempt));
continue;
}
if (['INVALID_QUERY', 'NOT_FOUND'].includes(error.code!)) {
throw error; // Don't retry for these errors
}
}
if (attempt === maxAttempts) {
throw error;
}
}
}
}The improved API maintains backward compatibility with the original API, but with enhanced features:
const Mcpedl = require('./mcpedl');
const mc = new Mcpedl();
const results = await mc.search("1.21", 13);import { McpedlAPI } from 'improved-mcpedl-api';
// Option 1: Drop-in replacement
const mc = new McpedlAPI();
const results = await mc.search("1.21", 13);
// Option 2: With enhanced features
const mc = new McpedlAPI({
timeout: 15000,
maxRetries: 5,
rateLimit: { minTime: 2000, maxConcurrent: 1 }
});- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add some amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
This project is licensed under the MIT License - see the LICENSE file for details.
This is an unofficial API for educational purposes. Please respect the terms of service of the target website and use this API responsibly.
terastudio-org