공유 덱 카드 복원 기준을 imgSrc로 전환
동일 번호 카드가 많은 시리즈에서도 선택한 카드가 정확히 복원되도록 저장·검증·복원 흐름을 imgSrc 중심으로 정리하고, 이미지 누락 시 공통 뒷면 폴백을 적용한다. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "uadeck-api",
|
||||
"version": "4.0.16",
|
||||
"version": "4.0.17",
|
||||
"type": "module",
|
||||
"main": "src/index.js",
|
||||
"scripts": {
|
||||
|
||||
@@ -1,13 +1,19 @@
|
||||
import { pathToFileURL } from 'url';
|
||||
import path from 'path';
|
||||
|
||||
/** @type {Map<string, Map<string, object>>} */
|
||||
/**
|
||||
* @typedef {object} CardIndex
|
||||
* @property {Map<string, object>} byNumber
|
||||
* @property {Map<string, object>} byImgSrc
|
||||
*/
|
||||
|
||||
/** @type {Map<string, CardIndex>} */
|
||||
const cache = new Map();
|
||||
|
||||
/**
|
||||
* 시리즈 카드 맵 로드
|
||||
* 시리즈 카드 인덱스 로드
|
||||
* @param {string} seriesKey
|
||||
* @returns {Promise<Map<string, object>>}
|
||||
* @returns {Promise<CardIndex>}
|
||||
*/
|
||||
export async function getCardMap(seriesKey) {
|
||||
if (cache.has(seriesKey)) {
|
||||
@@ -25,27 +31,34 @@ export async function getCardMap(seriesKey) {
|
||||
}
|
||||
|
||||
const byNumber = new Map();
|
||||
const byImgSrc = new Map();
|
||||
for (const card of mod.cardList) {
|
||||
byNumber.set(card.Number, card);
|
||||
if (!byNumber.has(card.Number)) {
|
||||
byNumber.set(card.Number, card);
|
||||
}
|
||||
if (card.imgSrc && !byImgSrc.has(card.imgSrc)) {
|
||||
byImgSrc.set(card.imgSrc, card);
|
||||
}
|
||||
}
|
||||
|
||||
cache.set(seriesKey, byNumber);
|
||||
return byNumber;
|
||||
const index = { byNumber, byImgSrc };
|
||||
cache.set(seriesKey, index);
|
||||
return index;
|
||||
}
|
||||
|
||||
/**
|
||||
* 저장된 덱 카드를 풀 카드 객체로 합성
|
||||
* @param {string} seriesKey
|
||||
* @param {Array<{number: string, count: number, key: boolean}>} cards
|
||||
* @param {Array<{number?: string, imgSrc?: string, count: number, key: boolean}>} cards
|
||||
* @returns {Promise<{cards: object[], totalCards: number}>}
|
||||
*/
|
||||
export async function resolveDeckCards(seriesKey, cards) {
|
||||
const map = await getCardMap(seriesKey);
|
||||
const index = await getCardMap(seriesKey);
|
||||
const resolved = [];
|
||||
let totalCards = 0;
|
||||
|
||||
for (const item of cards) {
|
||||
const base = map.get(item.number);
|
||||
const base = (item.imgSrc && index.byImgSrc.get(item.imgSrc)) || index.byNumber.get(item.number);
|
||||
if (!base) continue;
|
||||
|
||||
totalCards += item.count;
|
||||
|
||||
@@ -18,23 +18,24 @@ export function generateShareCode(length = 8) {
|
||||
|
||||
/**
|
||||
* 덱 본문 정규화 (해시용)
|
||||
* @param {Array<{number: string, count: number, key: boolean}>} cards
|
||||
* @param {Array<{imgSrc: string, number?: string, count: number, key: boolean}>} cards
|
||||
* @returns {string}
|
||||
*/
|
||||
export function normalizeCards(cards) {
|
||||
const sorted = [...cards]
|
||||
.map((c) => ({
|
||||
imgSrc: String(c.imgSrc).trim(),
|
||||
number: String(c.number).trim(),
|
||||
count: Number(c.count),
|
||||
key: Boolean(c.key),
|
||||
}))
|
||||
.sort((a, b) => a.number.localeCompare(b.number));
|
||||
.sort((a, b) => a.imgSrc.localeCompare(b.imgSrc));
|
||||
return JSON.stringify(sorted);
|
||||
}
|
||||
|
||||
/**
|
||||
* 프리셋 덱용 내용 해시 (8자)
|
||||
* @param {Array<{number: string, count: number, key: boolean}>} cards
|
||||
* @param {Array<{imgSrc: string, number?: string, count: number, key: boolean}>} cards
|
||||
* @returns {string}
|
||||
*/
|
||||
export function contentHash(cards) {
|
||||
@@ -45,7 +46,7 @@ export function contentHash(cards) {
|
||||
/**
|
||||
* 덱 카드 배열 검증
|
||||
* @param {unknown} cards
|
||||
* @returns {Array<{number: string, count: number, key: boolean}>}
|
||||
* @returns {Array<{imgSrc: string, number: string, count: number, key: boolean}>}
|
||||
*/
|
||||
export function validateCards(cards) {
|
||||
if (!Array.isArray(cards) || cards.length === 0) {
|
||||
@@ -54,6 +55,9 @@ export function validateCards(cards) {
|
||||
|
||||
let total = 0;
|
||||
const normalized = cards.map((c) => {
|
||||
if (!c.imgSrc || typeof c.imgSrc !== 'string' || !c.imgSrc.trim()) {
|
||||
throw new Error('카드 형식이 올바르지 않습니다. (imgSrc 필요)');
|
||||
}
|
||||
if (!c.number || c.count == null) {
|
||||
throw new Error('카드 형식이 올바르지 않습니다.');
|
||||
}
|
||||
@@ -63,6 +67,7 @@ export function validateCards(cards) {
|
||||
}
|
||||
total += count;
|
||||
return {
|
||||
imgSrc: String(c.imgSrc).trim(),
|
||||
number: String(c.number).trim(),
|
||||
count,
|
||||
key: Boolean(c.key),
|
||||
|
||||
Reference in New Issue
Block a user