maplestorysea-mcp-server
Version:
NEXON MapleStory SEA API MCP Server for Claude Desktop - Complete character info, union details, guild data, rankings optimized for SEA servers
272 lines • 9.38 kB
JavaScript
;
/**
* Ranking system utilities
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.RankingCacheKeys = exports.GuildRankingType = exports.RankingType = void 0;
exports.validatePage = validatePage;
exports.validateRankingType = validateRankingType;
exports.validateGuildRankingType = validateGuildRankingType;
exports.calculateRankingPosition = calculateRankingPosition;
exports.calculatePageFromPosition = calculatePageFromPosition;
exports.formatRankingEntry = formatRankingEntry;
exports.formatNumber = formatNumber;
exports.findCharacterPosition = findCharacterPosition;
exports.findGuildPosition = findGuildPosition;
exports.parseRankingResponse = parseRankingResponse;
exports.mergeRankingPages = mergeRankingPages;
exports.calculateRankingStats = calculateRankingStats;
/**
* Ranking types supported by the API
*/
var RankingType;
(function (RankingType) {
RankingType["OVERALL"] = "overall";
RankingType["UNION"] = "union";
RankingType["GUILD"] = "guild";
RankingType["DOJANG"] = "dojang";
RankingType["THESEED"] = "theseed";
RankingType["ACHIEVEMENT"] = "achievement";
})(RankingType || (exports.RankingType = RankingType = {}));
/**
* Guild ranking types
*/
var GuildRankingType;
(function (GuildRankingType) {
GuildRankingType[GuildRankingType["FLAG_RACE"] = 0] = "FLAG_RACE";
GuildRankingType[GuildRankingType["GUILD_POWER"] = 1] = "GUILD_POWER";
})(GuildRankingType || (exports.GuildRankingType = GuildRankingType = {}));
/**
* Validate page number for ranking queries
*/
function validatePage(page) {
if (!Number.isInteger(page) || page < 1) {
throw new Error('Page number must be a positive integer starting from 1');
}
if (page > 200) {
throw new Error('Page number cannot exceed 200');
}
}
/**
* Validate ranking type
*/
function validateRankingType(type) {
const validTypes = Object.values(RankingType);
if (!validTypes.includes(type)) {
throw new Error(`Invalid ranking type. Valid types: ${validTypes.join(', ')}`);
}
}
/**
* Validate guild ranking type
*/
function validateGuildRankingType(type) {
const validTypes = Object.values(GuildRankingType).filter((v) => typeof v === 'number');
if (!validTypes.includes(type)) {
throw new Error(`Invalid guild ranking type. Valid types: ${validTypes.join(', ')}`);
}
}
/**
* Calculate ranking position from page and index
*/
function calculateRankingPosition(page, index, pageSize = 200) {
return (page - 1) * pageSize + index + 1;
}
/**
* Calculate page from ranking position
*/
function calculatePageFromPosition(position, pageSize = 200) {
return Math.ceil(position / pageSize);
}
/**
* Format ranking data for display
*/
function formatRankingEntry(entry, position) {
if (!entry)
return entry;
return {
...entry,
displayRanking: position || entry.ranking || entry.guild_ranking || 0,
formattedLevel: entry.character_level ? `Lv.${entry.character_level}` : undefined,
formattedExp: entry.character_exp ? formatNumber(entry.character_exp) : undefined,
formattedGuildLevel: entry.guild_level ? `Lv.${entry.guild_level}` : undefined,
formattedMemberCount: entry.guild_member_count
? `${entry.guild_member_count} members`
: undefined,
};
}
/**
* Format large numbers with commas
*/
function formatNumber(num) {
const number = typeof num === 'string' ? parseInt(num, 10) : num;
if (isNaN(number))
return '0';
return number.toLocaleString('en-US');
}
/**
* Find character position in ranking data
*/
function findCharacterPosition(rankings, characterName, currentPage = 1, pageSize = 200) {
if (!rankings || !Array.isArray(rankings)) {
return { found: false };
}
const normalizedName = characterName.toLowerCase().trim();
for (let i = 0; i < rankings.length; i++) {
const entry = rankings[i];
const entryName = (entry.character_name || '').toLowerCase().trim();
if (entryName === normalizedName) {
const position = calculateRankingPosition(currentPage, i, pageSize);
return {
found: true,
position,
entry: formatRankingEntry(entry, position),
};
}
}
return { found: false };
}
/**
* Find guild position in ranking data
*/
function findGuildPosition(rankings, guildName, currentPage = 1, pageSize = 200) {
if (!rankings || !Array.isArray(rankings)) {
return { found: false };
}
const normalizedName = guildName.toLowerCase().trim();
for (let i = 0; i < rankings.length; i++) {
const entry = rankings[i];
const entryName = (entry.guild_name || '').toLowerCase().trim();
if (entryName === normalizedName) {
const position = calculateRankingPosition(currentPage, i, pageSize);
return {
found: true,
position,
entry: formatRankingEntry(entry, position),
};
}
}
return { found: false };
}
/**
* Generate ranking cache keys
*/
exports.RankingCacheKeys = {
overall: (worldName, worldType, className, page, date) => {
const parts = ['sea_ranking_overall'];
if (worldName)
parts.push(`world:${worldName}`);
if (worldType)
parts.push(`type:${worldType}`);
if (className)
parts.push(`class:${className}`);
if (page)
parts.push(`page:${page}`);
if (date)
parts.push(`date:${date}`);
return parts.join(':');
},
union: (worldName, page, date) => {
const parts = ['sea_ranking_union'];
if (worldName)
parts.push(`world:${worldName}`);
if (page)
parts.push(`page:${page}`);
if (date)
parts.push(`date:${date}`);
return parts.join(':');
},
guild: (worldName, rankingType, page, date) => {
const parts = ['sea_ranking_guild', `world:${worldName}`, `type:${rankingType}`];
if (page)
parts.push(`page:${page}`);
if (date)
parts.push(`date:${date}`);
return parts.join(':');
},
characterPosition: (characterName, worldName, className) => {
const normalizedName = characterName.trim().toLowerCase().replace(/\s+/g, '');
const parts = ['sea_char_position', `name:${normalizedName}`];
if (worldName)
parts.push(`world:${worldName}`);
if (className)
parts.push(`class:${className}`);
return parts.join(':');
},
guildPosition: (guildName, worldName, rankingType) => {
const normalizedName = guildName.trim().toLowerCase().replace(/\s+/g, '');
return `sea_guild_position:${worldName}:${rankingType}:${normalizedName}`;
},
};
/**
* Parse ranking response and add metadata
*/
function parseRankingResponse(response, page = 1) {
const rankings = response.ranking || [];
const currentPage = page;
return {
rankings: rankings.map((entry, index) => formatRankingEntry(entry, calculateRankingPosition(currentPage, index))),
pagination: {
currentPage,
hasNextPage: rankings.length >= 200, // Assume full page means more data
hasPreviousPage: currentPage > 1,
totalEntries: rankings.length,
},
metadata: {
lastUpdate: new Date().toISOString(),
rankingType: response.ranking_type || 'unknown',
worldName: response.world_name,
},
};
}
/**
* Merge ranking data from multiple pages for position search
*/
function mergeRankingPages(pages) {
const merged = [];
pages.forEach((page, pageIndex) => {
if (page.ranking && Array.isArray(page.ranking)) {
page.ranking.forEach((entry, entryIndex) => {
const position = calculateRankingPosition(pageIndex + 1, entryIndex);
merged.push(formatRankingEntry(entry, position));
});
}
});
return merged;
}
/**
* Calculate ranking statistics
*/
function calculateRankingStats(rankings) {
if (!rankings || rankings.length === 0) {
return {
totalEntries: 0,
levelRange: { min: 0, max: 0 },
averageLevel: 0,
};
}
const levels = rankings.map((entry) => entry.character_level || 0).filter((level) => level > 0);
const guildNames = rankings
.map((entry) => entry.character_guild_name || entry.guild_name)
.filter((name) => name && name.trim())
.reduce((acc, name) => {
acc[name] = (acc[name] || 0) + 1;
return acc;
}, {});
const topGuilds = Object.entries(guildNames)
.sort(([, a], [, b]) => b - a)
.slice(0, 5)
.map(([name]) => name);
const result = {
totalEntries: rankings.length,
levelRange: {
min: levels.length > 0 ? Math.min(...levels) : 0,
max: levels.length > 0 ? Math.max(...levels) : 0,
},
averageLevel: levels.length > 0 ? Math.round(levels.reduce((a, b) => a + b, 0) / levels.length) : 0,
};
if (topGuilds.length > 0) {
result.topGuilds = topGuilds;
}
return result;
}
//# sourceMappingURL=ranking-utils.js.map