Remove redundant .js extensions from import paths.

- TypeScript 소스 파일 내 모든 import 구문에서 불필요한 `.js` 확장자를 제거하여 모듈 참조 방식을 표준화했습니다.
- 핸들러, 서비스, 리포지토리 및 테스트 코드를 포함한 프로젝트 전반의 import 경로를 일관성 있게 정리했습니다.
This commit is contained in:
윤정민 2026-05-06 16:17:51 +09:00
parent 7496cb7de7
commit c94ce69e4f
58 changed files with 221 additions and 221 deletions

View File

@ -1,4 +1,4 @@
import type { DailyJudgment } from "../types/panit.js"; import type { DailyJudgment } from "../types/panit";
export interface Thresholds { export interface Thresholds {
success: number; success: number;

View File

@ -1,4 +1,4 @@
import type { TierName } from "../types/panit.js"; import type { TierName } from "../types/panit";
interface TierStep { interface TierStep {
name: TierName; name: TierName;

View File

@ -1,7 +1,7 @@
import { onRequest } from "firebase-functions/https"; import { onRequest } from "firebase-functions/https";
import { requireAdmin } from "../middleware/admin.js"; import { requireAdmin } from "../middleware/admin";
import { sendError } from "../middleware/errors.js"; import { sendError } from "../middleware/errors";
import { markGameEnded } from "../services/gameResultService.js"; import { markGameEnded } from "../services/gameResultService";
export const admin = onRequest(async (req, res) => { export const admin = onRequest(async (req, res) => {
const segs = req.path.replace(/^\/+|\/+$/g, "").split("/"); const segs = req.path.replace(/^\/+|\/+$/g, "").split("/");

View File

@ -1,9 +1,9 @@
import { onRequest } from "firebase-functions/https"; import { onRequest } from "firebase-functions/https";
import { logger } from "firebase-functions"; import { logger } from "firebase-functions";
import { runDailyArchive } from "../scheduled/dailyArchive.js"; import { runDailyArchive } from "../scheduled/dailyArchive";
import { syncYesterdayFromLive } from "../services/gameSyncService.js"; import { syncYesterdayFromLive } from "../services/gameSyncService";
import { sendError } from "../middleware/errors.js"; import { sendError } from "../middleware/errors";
import { daysAgoKst, parseDateString } from "../types/dateString.js"; import { daysAgoKst, parseDateString } from "../types/dateString";
/** /**
* . . * . .

View File

@ -1,10 +1,10 @@
import { onRequest } from "firebase-functions/https"; import { onRequest } from "firebase-functions/https";
import { getRank } from "../services/rankService.js"; import { getRank } from "../services/rankService";
import { getSchedule } from "../services/scheduleService.js"; import { getSchedule } from "../services/scheduleService";
import { getPlayerStats, getValidPlayerTypes } from "../services/playerService.js"; import { getPlayerStats, getValidPlayerTypes } from "../services/playerService";
import { getGameList } from "../services/gameListService.js"; import { getGameList } from "../services/gameListService";
import { getGameDetail } from "../services/gameDetailService.js"; import { getGameDetail } from "../services/gameDetailService";
import { TeamCode } from "../types/panit.js"; import { TeamCode } from "../types/panit";
enum KboPath { enum KboPath {
Rank = "rank", Rank = "rank",

View File

@ -1,14 +1,14 @@
import { onRequest } from "firebase-functions/https"; import { onRequest } from "firebase-functions/https";
import { requireAuth } from "../middleware/auth.js"; import { requireAuth } from "../middleware/auth";
import { HttpError, sendError } from "../middleware/errors.js"; import { HttpError, sendError } from "../middleware/errors";
import { import {
createPrediction, createPrediction,
updatePrediction, updatePrediction,
getMyVotes, getMyVotes,
getSummary, getSummary,
listGamesByDate, listGamesByDate,
} from "../services/predictionService.js"; } from "../services/predictionService";
import { getScoreboard } from "../services/scoreboardService.js"; import { getScoreboard } from "../services/scoreboardService";
export const prediction = onRequest(async (req, res) => { export const prediction = onRequest(async (req, res) => {
const segs = req.path.replace(/^\/+|\/+$/g, "").split("/"); const segs = req.path.replace(/^\/+|\/+$/g, "").split("/");

View File

@ -1,7 +1,7 @@
import { onRequest } from "firebase-functions/https"; import { onRequest } from "firebase-functions/https";
import { requireAuth } from "../middleware/auth.js"; import { requireAuth } from "../middleware/auth";
import { sendError } from "../middleware/errors.js"; import { sendError } from "../middleware/errors";
import { getStats, getHistory } from "../services/statsService.js"; import { getStats, getHistory } from "../services/statsService";
export const stats = onRequest(async (req, res) => { export const stats = onRequest(async (req, res) => {
const segs = req.path.replace(/^\/+|\/+$/g, "").split("/"); const segs = req.path.replace(/^\/+|\/+$/g, "").split("/");

View File

@ -1,13 +1,13 @@
import { onRequest } from "firebase-functions/https"; import { onRequest } from "firebase-functions/https";
import { requireAuthToken } from "../middleware/auth.js"; import { requireAuthToken } from "../middleware/auth";
import { sendError } from "../middleware/errors.js"; import { sendError } from "../middleware/errors";
import { import {
checkNickname, checkNickname,
createMe, createMe,
deleteMe, deleteMe,
getMe, getMe,
updateMe, updateMe,
} from "../services/userService.js"; } from "../services/userService";
export const user = onRequest(async (req, res) => { export const user = onRequest(async (req, res) => {
try { try {

View File

@ -1,4 +1,4 @@
import { extractHiddenField } from "./html-utils.js"; import { extractHiddenField } from "./html-utils";
export const PREFIX = export const PREFIX =
"ctl00$ctl00$ctl00$cphContents$cphContents$cphContents$"; "ctl00$ctl00$ctl00$cphContents$cphContents$cphContents$";

View File

@ -14,7 +14,7 @@
* --series= (schedule: 정규//) * --series= (schedule: 정규//)
*/ */
import { padCell } from "./html-utils.js"; import { padCell } from "./html-utils";
import { import {
fetchTeamRankInitial, fetchTeamRankInitial,
fetchTeamRank, fetchTeamRank,
@ -22,7 +22,7 @@ import {
type TeamVsRecord, type TeamVsRecord,
type TeamRankResult, type TeamRankResult,
type WinLossDraw, type WinLossDraw,
} from "./team-rank.js"; } from "./team-rank";
import { import {
fetchPlayerStatsInitial, fetchPlayerStatsInitial,
fetchPlayerStats, fetchPlayerStats,
@ -31,25 +31,25 @@ import {
type PlayerPageConfig, type PlayerPageConfig,
type PlayerFilters, type PlayerFilters,
type PlayerStatsResult, type PlayerStatsResult,
} from "./player/common.js"; } from "./player/common";
import { HITTER_CONFIG } from "./player/hitter.js"; import { HITTER_CONFIG } from "./player/hitter";
import { PITCHER_CONFIG } from "./player/pitcher.js"; import { PITCHER_CONFIG } from "./player/pitcher";
import { DEFENSE_CONFIG } from "./player/defense.js"; import { DEFENSE_CONFIG } from "./player/defense";
import { RUNNER_CONFIG } from "./player/runner.js"; import { RUNNER_CONFIG } from "./player/runner";
import { import {
fetchSchedule, fetchSchedule,
SERIES_CODES, SERIES_CODES,
type ScheduleGame, type ScheduleGame,
type ScheduleResult, type ScheduleResult,
} from "./schedule.js"; } from "./schedule";
import { import {
fetchGameList, fetchGameList,
LEAGUE_CODES, LEAGUE_CODES,
LeagueCode, LeagueCode,
type GameListRecord, type GameListRecord,
type GameListResult, type GameListResult,
} from "./game-list.js"; } from "./game-list";
import { fetchGameDetail, type GameDetail } from "./game-detail.js"; import { fetchGameDetail, type GameDetail } from "./game-detail";
const PLAYER_CONFIGS: Record<string, PlayerPageConfig> = { const PLAYER_CONFIGS: Record<string, PlayerPageConfig> = {
hitter: HITTER_CONFIG, hitter: HITTER_CONFIG,

View File

@ -1,7 +1,7 @@
import { stripTags, decodeHtmlEntities } from "./html-utils.js"; import { stripTags, decodeHtmlEntities } from "./html-utils";
import { LeagueCode, LEAGUE_CODES } from "./game-list.js"; import { LeagueCode, LEAGUE_CODES } from "./game-list";
import { SERIES_ID } from "./schedule.js"; import { SERIES_ID } from "./schedule";
import { fetchScoringPlays, type GameScoringPlays } from "./play-by-play.js"; import { fetchScoringPlays, type GameScoringPlays } from "./play-by-play";
const BASE_URL = "https://www.koreabaseball.com/ws/Schedule.asmx"; const BASE_URL = "https://www.koreabaseball.com/ws/Schedule.asmx";

View File

@ -1,4 +1,4 @@
import { SERIES_CODES } from "./schedule.js"; import { SERIES_CODES } from "./schedule";
export { SERIES_CODES }; export { SERIES_CODES };

View File

@ -1,11 +1,11 @@
import { stripTags, decodeHtmlEntities } from "../html-utils.js"; import { stripTags, decodeHtmlEntities } from "../html-utils";
import { import {
PREFIX, PREFIX,
postback, postback,
getInitialPageState, getInitialPageState,
type PageState, type PageState,
type PostbackResponse, type PostbackResponse,
} from "../aspnet-client.js"; } from "../aspnet-client";
const SM_KEY = `${PREFIX}smData`; const SM_KEY = `${PREFIX}smData`;
const UPDATE_PANEL = `${PREFIX}udpContent`; const UPDATE_PANEL = `${PREFIX}udpContent`;
@ -39,7 +39,7 @@ export interface PlayerPageConfig {
* . * .
* *
* @example * @example
* import type { HitterStats } from "./hitter.js"; * import type { HitterStats } from "./hitter";
* const hitter = record as HitterStats; * const hitter = record as HitterStats;
* console.log(hitter.avg, hitter.hr); * console.log(hitter.avg, hitter.hr);
*/ */

View File

@ -1,4 +1,4 @@
import type { PlayerPageConfig, PlayerValue } from "./common.js"; import type { PlayerPageConfig, PlayerValue } from "./common";
export const DEFENSE_COLUMNS = [ export const DEFENSE_COLUMNS = [
"rank", "player", "team", "pos", "games", "gs", "ip", "rank", "player", "team", "pos", "games", "gs", "ip",

View File

@ -1,4 +1,4 @@
import type { PlayerPageConfig, PlayerValue } from "./common.js"; import type { PlayerPageConfig, PlayerValue } from "./common";
export const HITTER_COLUMNS = [ export const HITTER_COLUMNS = [
"rank", "player", "team", "avg", "games", "pa", "ab", "rank", "player", "team", "avg", "games", "pa", "ab",

View File

@ -1,4 +1,4 @@
import type { PlayerPageConfig, PlayerValue } from "./common.js"; import type { PlayerPageConfig, PlayerValue } from "./common";
export const PITCHER_COLUMNS = [ export const PITCHER_COLUMNS = [
"rank", "player", "team", "era", "games", "wins", "losses", "rank", "player", "team", "era", "games", "wins", "losses",

View File

@ -1,4 +1,4 @@
import type { PlayerPageConfig, PlayerValue } from "./common.js"; import type { PlayerPageConfig, PlayerValue } from "./common";
export const RUNNER_COLUMNS = [ export const RUNNER_COLUMNS = [
"rank", "player", "team", "games", "sba", "sb", "cs", "rank", "player", "team", "games", "sba", "sb", "cs",

View File

@ -1,6 +1,6 @@
import { stripTags, decodeHtmlEntities } from "./html-utils.js"; import { stripTags, decodeHtmlEntities } from "./html-utils";
import { TEAM_CODES } from "./player/common.js"; import { TEAM_CODES } from "./player/common";
import { fetchGameList, type PersonRef } from "./game-list.js"; import { fetchGameList, type PersonRef } from "./game-list";
function toTeamCode(name: string): string { function toTeamCode(name: string): string {
return TEAM_CODES[name] ?? name; return TEAM_CODES[name] ?? name;

View File

@ -1,11 +1,11 @@
import { stripTags, decodeHtmlEntities } from "./html-utils.js"; import { stripTags, decodeHtmlEntities } from "./html-utils";
import { import {
PREFIX, PREFIX,
postback, postback,
getInitialPageState, getInitialPageState,
type PageState, type PageState,
type PostbackResponse, type PostbackResponse,
} from "./aspnet-client.js"; } from "./aspnet-client";
const PAGE_URL = const PAGE_URL =
"https://www.koreabaseball.com/Record/TeamRank/TeamRank.aspx"; "https://www.koreabaseball.com/Record/TeamRank/TeamRank.aspx";

View File

@ -1,6 +1,6 @@
import type { Request } from "firebase-functions/https"; import type { Request } from "firebase-functions/https";
import { auth } from "../firebase.js"; import { auth } from "../firebase";
import { HttpError } from "./errors.js"; import { HttpError } from "./errors";
export async function requireAdmin(req: Request): Promise<string> { export async function requireAdmin(req: Request): Promise<string> {
const header = req.get("authorization") ?? req.get("Authorization"); const header = req.get("authorization") ?? req.get("Authorization");

View File

@ -1,7 +1,7 @@
import type { Request } from "firebase-functions/https"; import type { Request } from "firebase-functions/https";
import type { DecodedIdToken } from "firebase-admin/auth"; import type { DecodedIdToken } from "firebase-admin/auth";
import { auth } from "../firebase.js"; import { auth } from "../firebase";
import { HttpError } from "./errors.js"; import { HttpError } from "./errors";
export async function requireAuthToken(req: Request): Promise<DecodedIdToken> { export async function requireAuthToken(req: Request): Promise<DecodedIdToken> {
const header = req.get("authorization") ?? req.get("Authorization"); const header = req.get("authorization") ?? req.get("Authorization");

View File

@ -1,7 +1,7 @@
import { Timestamp } from "firebase-admin/firestore"; import { Timestamp } from "firebase-admin/firestore";
import { firestore } from "../firebase.js"; import { firestore } from "../firebase";
import type { Game } from "../types/panit.js"; import type { Game } from "../types/panit";
import { startOfDayKst, type DateString } from "../types/dateString.js"; import { startOfDayKst, type DateString } from "../types/dateString";
const COLLECTION = "games"; const COLLECTION = "games";

View File

@ -1,5 +1,5 @@
import { FieldValue } from "firebase-admin/firestore"; import { FieldValue } from "firebase-admin/firestore";
import { firestore } from "../firebase.js"; import { firestore } from "../firebase";
const CACHE_COLLECTION = "kboCache"; const CACHE_COLLECTION = "kboCache";
const LOCK_COLLECTION = "kboLocks"; const LOCK_COLLECTION = "kboLocks";

View File

@ -2,14 +2,14 @@ import {
fetchTeamRankInitial, fetchTeamRankInitial,
fetchTeamRank, fetchTeamRank,
type TeamRankResult, type TeamRankResult,
} from "../kbo/team-rank.js"; } from "../kbo/team-rank";
import { import {
fetchSchedule, fetchSchedule,
type ScheduleFilters, type ScheduleFilters,
type ScheduleResult, type ScheduleResult,
type ScheduleGame, type ScheduleGame,
type GameStatus, type GameStatus,
} from "../kbo/schedule.js"; } from "../kbo/schedule";
import { import {
fetchPlayerStatsInitial, fetchPlayerStatsInitial,
fetchPlayerStats, fetchPlayerStats,
@ -17,17 +17,17 @@ import {
type PlayerPageConfig, type PlayerPageConfig,
type PlayerFilters, type PlayerFilters,
type PlayerStatsResult, type PlayerStatsResult,
} from "../kbo/player/common.js"; } from "../kbo/player/common";
import { import {
encodeKey, encodeKey,
getOrFetch, getOrFetch,
setCached, setCached,
acquireLock, acquireLock,
releaseLock, releaseLock,
} from "./kboCacheRepository.js"; } from "./kboCacheRepository";
import { firestore } from "../firebase.js"; import { firestore } from "../firebase";
import { getGameList } from "../services/gameListService.js"; import { getGameList } from "../services/gameListService";
import type { GameListRecord } from "../kbo/game-list.js"; import type { GameListRecord } from "../kbo/game-list";
const TTL_MS = 60 * 60 * 1000; // 1 hour const TTL_MS = 60 * 60 * 1000; // 1 hour

View File

@ -1,5 +1,5 @@
import { rtdb } from "../firebase.js"; import { rtdb } from "../firebase";
import { HttpError } from "../middleware/errors.js"; import { HttpError } from "../middleware/errors";
export const RESERVATION_TTL_MS = 10 * 60 * 1000; export const RESERVATION_TTL_MS = 10 * 60 * 1000;

View File

@ -1,7 +1,7 @@
import { rtdb } from "../firebase.js"; import { rtdb } from "../firebase";
import type { DateString } from "../types/dateString.js"; import type { DateString } from "../types/dateString";
import type { TeamCode } from "../types/panit.js"; import type { TeamCode } from "../types/panit";
import type { ScoreboardScopeCache } from "../types/scoreboard.js"; import type { ScoreboardScopeCache } from "../types/scoreboard";
const BASE = "/scoreboardCache"; const BASE = "/scoreboardCache";

View File

@ -1,6 +1,6 @@
import { firestore } from "../firebase.js"; import { firestore } from "../firebase";
import type { VoteHistoryDoc } from "../types/panit.js"; import type { VoteHistoryDoc } from "../types/panit";
import type { DateString } from "../types/dateString.js"; import type { DateString } from "../types/dateString";
/** /**
* voteHistory . * voteHistory .

View File

@ -1,7 +1,7 @@
import { ServerValue } from "firebase-admin/database"; import { ServerValue } from "firebase-admin/database";
import { rtdb } from "../firebase.js"; import { rtdb } from "../firebase";
import type { VoteEntry } from "../types/panit.js"; import type { VoteEntry } from "../types/panit";
import type { DateString } from "../types/dateString.js"; import type { DateString } from "../types/dateString";
/** /**
* . * .

View File

@ -1,23 +1,23 @@
import { onSchedule } from "firebase-functions/scheduler"; import { onSchedule } from "firebase-functions/scheduler";
import { logger } from "firebase-functions"; import { logger } from "firebase-functions";
import { rtdb } from "../firebase.js"; import { rtdb } from "../firebase";
import { setDay } from "../repositories/voteHistoryRepository.js"; import { setDay } from "../repositories/voteHistoryRepository";
import { invalidateStats } from "../services/statsService.js"; import { invalidateStats } from "../services/statsService";
import { judgeDay, judgeWeekIfNeeded } from "../services/judgmentService.js"; import { judgeDay, judgeWeekIfNeeded } from "../services/judgmentService";
import { import {
precomputeScoreboardCache, precomputeScoreboardCache,
snapshotRankForUser, snapshotRankForUser,
} from "../services/rankSnapshotService.js"; } from "../services/rankSnapshotService";
import { todayKst } from "../types/dateString.js"; import { todayKst } from "../types/dateString";
import { getGame } from "../repositories/gameRepository.js"; import { getGame } from "../repositories/gameRepository";
import { deleteUserVoteGame } from "../repositories/voteRepository.js"; import { deleteUserVoteGame } from "../repositories/voteRepository";
import { processGameEndWithGame } from "../services/gameResultService.js"; import { processGameEndWithGame } from "../services/gameResultService";
import type { VoteHistoryDoc } from "../types/panit.js"; import type { VoteHistoryDoc } from "../types/panit";
import { import {
dayOfWeekKst, dayOfWeekKst,
daysAgoKst, daysAgoKst,
type DateString, type DateString,
} from "../types/dateString.js"; } from "../types/dateString";
interface RawVote { interface RawVote {
team: string; team: string;

View File

@ -1,15 +1,15 @@
import { onSchedule } from "firebase-functions/scheduler"; import { onSchedule } from "firebase-functions/scheduler";
import { logger } from "firebase-functions"; import { logger } from "firebase-functions";
import { firestore } from "../firebase.js"; import { firestore } from "../firebase";
import { import {
fetchRankFromKbo, fetchRankFromKbo,
fetchScheduleFromKbo, fetchScheduleFromKbo,
} from "../repositories/kboRepository.js"; } from "../repositories/kboRepository";
import { import {
syncGamesForMonth, syncGamesForMonth,
syncYesterdayFromLive, syncYesterdayFromLive,
} from "../services/gameSyncService.js"; } from "../services/gameSyncService";
import { daysAgoKst } from "../types/dateString.js"; import { daysAgoKst } from "../types/dateString";
const CACHE_COLLECTION = "kboCache"; const CACHE_COLLECTION = "kboCache";

View File

@ -3,14 +3,14 @@ import {
type GameDetail, type GameDetail,
type GameDetailFilters, type GameDetailFilters,
type ScoreBoardMeta, type ScoreBoardMeta,
} from "../kbo/game-detail.js"; } from "../kbo/game-detail";
import { import {
encodeKey, encodeKey,
getCached, getCached,
setCached, setCached,
acquireLock, acquireLock,
releaseLock, releaseLock,
} from "../repositories/kboCacheRepository.js"; } from "../repositories/kboCacheRepository";
const SEVEN_DAYS_MS = 7 * 24 * 60 * 60 * 1000; const SEVEN_DAYS_MS = 7 * 24 * 60 * 60 * 1000;
const ONE_HOUR_MS = 60 * 60 * 1000; const ONE_HOUR_MS = 60 * 60 * 1000;

View File

@ -4,8 +4,8 @@ import {
LeagueCode, LeagueCode,
SERIES_CODES, SERIES_CODES,
type GameListResult, type GameListResult,
} from "../kbo/game-list.js"; } from "../kbo/game-list";
import { MemCache } from "../lib/memCache.js"; import { MemCache } from "../lib/memCache";
// 게임센터(GetKboGameList)는 다른 KBO 데이터와 달리 Firestore 공유 캐시 // 게임센터(GetKboGameList)는 다른 KBO 데이터와 달리 Firestore 공유 캐시
// (kboCacheRepository) 대신 인스턴스 단위 인메모리 캐시를 쓴다. // (kboCacheRepository) 대신 인스턴스 단위 인메모리 캐시를 쓴다.

View File

@ -1,12 +1,12 @@
import { FieldValue } from "firebase-admin/firestore"; import { FieldValue } from "firebase-admin/firestore";
import { logger } from "firebase-functions"; import { logger } from "firebase-functions";
import { firestore, rtdb } from "../firebase.js"; import { firestore, rtdb } from "../firebase";
import { HttpError } from "../middleware/errors.js"; import { HttpError } from "../middleware/errors";
import { getGame } from "../repositories/gameRepository.js"; import { getGame } from "../repositories/gameRepository";
import { getAllUserVotes, deleteGameVotes } from "../repositories/voteRepository.js"; import { getAllUserVotes, deleteGameVotes } from "../repositories/voteRepository";
import { invalidateStats } from "./statsService.js"; import { invalidateStats } from "./statsService";
import { fromTimestamp } from "../types/dateString.js"; import { fromTimestamp } from "../types/dateString";
import type { Game } from "../types/panit.js"; import type { Game } from "../types/panit";
export async function processGameEnd(gameId: string): Promise<{ processed: number }> { export async function processGameEnd(gameId: string): Promise<{ processed: number }> {
const game = await getGame(gameId); const game = await getGame(gameId);

View File

@ -1,13 +1,13 @@
import { Timestamp } from "firebase-admin/firestore"; import { Timestamp } from "firebase-admin/firestore";
import { firestore } from "../firebase.js"; import { firestore } from "../firebase";
import { import {
fetchScheduleFromKbo, fetchScheduleFromKbo,
statusFromRecord, statusFromRecord,
} from "../repositories/kboRepository.js"; } from "../repositories/kboRepository";
import { getGameList } from "./gameListService.js"; import { getGameList } from "./gameListService";
import type { GameListRecord } from "../kbo/game-list.js"; import type { GameListRecord } from "../kbo/game-list";
import type { ScheduleGame, GameStatus } from "../kbo/schedule.js"; import type { ScheduleGame, GameStatus } from "../kbo/schedule";
import type { Game } from "../types/panit.js"; import type { Game } from "../types/panit";
const COLLECTION = "games"; const COLLECTION = "games";

View File

@ -1,18 +1,18 @@
import { logger } from "firebase-functions"; import { logger } from "firebase-functions";
import { listByDate } from "../repositories/gameRepository.js"; import { listByDate } from "../repositories/gameRepository";
import { getRange, setDay } from "../repositories/voteHistoryRepository.js"; import { getRange, setDay } from "../repositories/voteHistoryRepository";
import { import {
applyDailyJudgmentTx, applyDailyJudgmentTx,
applyWeeklyMasterTx, applyWeeklyMasterTx,
getUser, getUser,
} from "../repositories/userRepository.js"; } from "../repositories/userRepository";
import { import {
judgeByCounts, judgeByCounts,
streakBonus, streakBonus,
thresholdsFor, thresholdsFor,
} from "../constants/judgment.js"; } from "../constants/judgment";
import type { DailyJudgment, VoteHistoryDoc } from "../types/panit.js"; import type { DailyJudgment, VoteHistoryDoc } from "../types/panit";
import { addDaysKst, tuesdayOf, type DateString } from "../types/dateString.js"; import { addDaysKst, tuesdayOf, type DateString } from "../types/dateString";
/** /**
* `(lastJudged, upTo)` ( ) ** **(=`thresholdsFor` * `(lastJudged, upTo)` ( ) ** **(=`thresholdsFor`

View File

@ -1,10 +1,10 @@
import { fetchPlayerFromKbo } from "../repositories/kboRepository.js"; import { fetchPlayerFromKbo } from "../repositories/kboRepository";
import type { PlayerFilters, PlayerPageConfig, PlayerStatsResult } from "../types/kbo.js"; import type { PlayerFilters, PlayerPageConfig, PlayerStatsResult } from "../types/kbo";
import { TeamCode } from "../types/panit.js"; import { TeamCode } from "../types/panit";
import { HITTER_CONFIG } from "../kbo/player/hitter.js"; import { HITTER_CONFIG } from "../kbo/player/hitter";
import { PITCHER_CONFIG } from "../kbo/player/pitcher.js"; import { PITCHER_CONFIG } from "../kbo/player/pitcher";
import { DEFENSE_CONFIG } from "../kbo/player/defense.js"; import { DEFENSE_CONFIG } from "../kbo/player/defense";
import { RUNNER_CONFIG } from "../kbo/player/runner.js"; import { RUNNER_CONFIG } from "../kbo/player/runner";
const PLAYER_CONFIGS: Record<string, PlayerPageConfig> = { const PLAYER_CONFIGS: Record<string, PlayerPageConfig> = {
hitter: HITTER_CONFIG, hitter: HITTER_CONFIG,

View File

@ -1,15 +1,15 @@
import { HttpError } from "../middleware/errors.js"; import { HttpError } from "../middleware/errors";
import { getGame, listByDate, type GameWithId } from "../repositories/gameRepository.js"; import { getGame, listByDate, type GameWithId } from "../repositories/gameRepository";
import { import {
getUserVote, getUserVote,
submitVote, submitVote,
changeVote, changeVote,
getCounts, getCounts,
getUserDateVotes, getUserDateVotes,
} from "../repositories/voteRepository.js"; } from "../repositories/voteRepository";
import type { Game, VoteEntry } from "../types/panit.js"; import type { Game, VoteEntry } from "../types/panit";
import { fromTimestamp, parseDateString, type DateString } from "../types/dateString.js"; import { fromTimestamp, parseDateString, type DateString } from "../types/dateString";
import { MemCache } from "../lib/memCache.js"; import { MemCache } from "../lib/memCache";
type SummaryCounts = { homeCount: number; awayCount: number }; type SummaryCounts = { homeCount: number; awayCount: number };

View File

@ -1,5 +1,5 @@
import { fetchRankFromKbo } from "../repositories/kboRepository.js"; import { fetchRankFromKbo } from "../repositories/kboRepository";
import type { TeamRankResult } from "../types/kbo.js"; import type { TeamRankResult } from "../types/kbo";
export async function getRank(years: number[]): Promise<TeamRankResult[]> { export async function getRank(years: number[]): Promise<TeamRankResult[]> {
return fetchRankFromKbo(years); return fetchRankFromKbo(years);

View File

@ -1,20 +1,20 @@
import { logger } from "firebase-functions"; import { logger } from "firebase-functions";
import { firestore } from "../firebase.js"; import { firestore } from "../firebase";
import { import {
countRankedUsers, countRankedUsers,
countUsersAboveTierPoints, countUsersAboveTierPoints,
getUser, getUser,
listTopByTierPoints, listTopByTierPoints,
type ScoreboardUserEntry, type ScoreboardUserEntry,
} from "../repositories/userRepository.js"; } from "../repositories/userRepository";
import { writeScope, type Scope } from "../repositories/scoreboardCacheRepository.js"; import { writeScope, type Scope } from "../repositories/scoreboardCacheRepository";
import { computePercentile, deltaFor } from "./scoreboardHelpers.js"; import { computePercentile, deltaFor } from "./scoreboardHelpers";
import type { DateString } from "../types/dateString.js"; import type { DateString } from "../types/dateString";
import { TeamCode, type RankSnapshot } from "../types/panit.js"; import { TeamCode, type RankSnapshot } from "../types/panit";
import type { import type {
ScoreboardEntry, ScoreboardEntry,
ScoreboardScopeCache, ScoreboardScopeCache,
} from "../types/scoreboard.js"; } from "../types/scoreboard";
/** /**
* 1 `tierPoints` rank를 count aggregation으로 * 1 `tierPoints` rank를 count aggregation으로

View File

@ -1,7 +1,7 @@
import { fetchScheduleFromKbo } from "../repositories/kboRepository.js"; import { fetchScheduleFromKbo } from "../repositories/kboRepository";
import { SERIES_CODES } from "../types/kbo.js"; import { SERIES_CODES } from "../types/kbo";
import type { ScheduleResult } from "../types/kbo.js"; import type { ScheduleResult } from "../types/kbo";
import type { TeamCode } from "../types/panit.js"; import type { TeamCode } from "../types/panit";
export async function getSchedule( export async function getSchedule(
year: number, year: number,

View File

@ -1,5 +1,5 @@
import type { Scope } from "../repositories/scoreboardCacheRepository.js"; import type { Scope } from "../repositories/scoreboardCacheRepository";
import type { RankSnapshot } from "../types/panit.js"; import type { RankSnapshot } from "../types/panit";
export function computePercentile(rank: number, totalCount: number): number { export function computePercentile(rank: number, totalCount: number): number {
if (totalCount <= 0) return 0; if (totalCount <= 0) return 0;

View File

@ -1,22 +1,22 @@
import { MemCache } from "../lib/memCache.js"; import { MemCache } from "../lib/memCache";
import { import {
countUsersAboveTierPoints, countUsersAboveTierPoints,
getUser, getUser,
} from "../repositories/userRepository.js"; } from "../repositories/userRepository";
import { import {
readScope, readScope,
type Scope, type Scope,
} from "../repositories/scoreboardCacheRepository.js"; } from "../repositories/scoreboardCacheRepository";
import { HttpError } from "../middleware/errors.js"; import { HttpError } from "../middleware/errors";
import { computePercentile, deltaFor } from "./scoreboardHelpers.js"; import { computePercentile, deltaFor } from "./scoreboardHelpers";
import { todayKst } from "../types/dateString.js"; import { todayKst } from "../types/dateString";
import { type TeamCode } from "../types/panit.js"; import { type TeamCode } from "../types/panit";
import type { import type {
ScoreboardEntry, ScoreboardEntry,
ScoreboardResponse, ScoreboardResponse,
ScoreboardScopeCache, ScoreboardScopeCache,
ScoreboardType, ScoreboardType,
} from "../types/scoreboard.js"; } from "../types/scoreboard";
const BURST_TTL_MS = 30_000; const BURST_TTL_MS = 30_000;

View File

@ -1,11 +1,11 @@
import {rtdb} from "../firebase.js"; import {rtdb} from "../firebase";
import {HttpError} from "../middleware/errors.js"; import {HttpError} from "../middleware/errors";
import {computeLevel} from "../constants/levels.js"; import {computeLevel} from "../constants/levels";
import {tierOf} from "../constants/tiers.js"; import {tierOf} from "../constants/tiers";
import {getAll, getDay} from "../repositories/voteHistoryRepository.js"; import {getAll, getDay} from "../repositories/voteHistoryRepository";
import {getUser} from "../repositories/userRepository.js"; import {getUser} from "../repositories/userRepository";
import {hasMissedGameDayBetween} from "./judgmentService.js"; import {hasMissedGameDayBetween} from "./judgmentService";
import type {DailyJudgment, StatsResponse, VoteHistoryDoc} from "../types/panit.js"; import type {DailyJudgment, StatsResponse, VoteHistoryDoc} from "../types/panit";
import { import {
addDaysKst, addDaysKst,
parseDateString, parseDateString,
@ -14,7 +14,7 @@ import {
todayKst, todayKst,
tuesdayOf as tuesdayOfUtil, tuesdayOf as tuesdayOfUtil,
type DateString, type DateString,
} from "../types/dateString.js"; } from "../types/dateString";
type Period = type Period =
| "current" | "current"

View File

@ -1,27 +1,27 @@
import type { DecodedIdToken } from "firebase-admin/auth"; import type { DecodedIdToken } from "firebase-admin/auth";
import { FieldValue } from "firebase-admin/firestore"; import { FieldValue } from "firebase-admin/firestore";
import { HttpError } from "../middleware/errors.js"; import { HttpError } from "../middleware/errors";
import { auth } from "../firebase.js"; import { auth } from "../firebase";
import { import {
createUser, createUser,
deleteUser, deleteUser,
findUidByDisplayName, findUidByDisplayName,
getUser, getUser,
updateUser, updateUser,
} from "../repositories/userRepository.js"; } from "../repositories/userRepository";
import { import {
deleteReservation, deleteReservation,
releaseReservation, releaseReservation,
reserveNickname, reserveNickname,
verifyReservation, verifyReservation,
} from "../repositories/nicknameRepository.js"; } from "../repositories/nicknameRepository";
import { import {
KnowledgeLevel, KnowledgeLevel,
TeamCode, TeamCode,
type Provider, type Provider,
type User, type User,
type UserProfile, type UserProfile,
} from "../types/panit.js"; } from "../types/panit";
/** /**
* User . * User .

View File

@ -1,14 +1,14 @@
import {onDocumentUpdated} from "firebase-functions/firestore"; import {onDocumentUpdated} from "firebase-functions/firestore";
import {logger} from "firebase-functions"; import {logger} from "firebase-functions";
import {rtdb} from "../firebase.js"; import {rtdb} from "../firebase";
import {processGameEndWithGame} from "../services/gameResultService.js"; import {processGameEndWithGame} from "../services/gameResultService";
import { import {
getAllUserVotes, getAllUserVotes,
deleteGameVotes, deleteGameVotes,
} from "../repositories/voteRepository.js"; } from "../repositories/voteRepository";
import {invalidateStats} from "../services/statsService.js"; import {invalidateStats} from "../services/statsService";
import {fromTimestamp} from "../types/dateString.js"; import {fromTimestamp} from "../types/dateString";
import type {Game} from "../types/panit.js"; import type {Game} from "../types/panit";
/** /**
* `games/{gameId}` Firestore . * `games/{gameId}` Firestore .

View File

@ -6,32 +6,32 @@ export type {
WinLossDraw, WinLossDraw,
TeamVsRecord, TeamVsRecord,
TeamRankResult, TeamRankResult,
} from "../kbo/team-rank.js"; } from "../kbo/team-rank";
export type { export type {
GameStatus, GameStatus,
ScheduleGame, ScheduleGame,
ScheduleFilters, ScheduleFilters,
ScheduleResult, ScheduleResult,
} from "../kbo/schedule.js"; } from "../kbo/schedule";
export type { export type {
PlayerPageConfig, PlayerPageConfig,
PlayerRecord, PlayerRecord,
PlayerFilters, PlayerFilters,
PlayerStatsResult, PlayerStatsResult,
} from "../kbo/player/common.js"; } from "../kbo/player/common";
export { SERIES_CODES } from "../kbo/schedule.js"; export { SERIES_CODES } from "../kbo/schedule";
export type { export type {
GameListFilters, GameListFilters,
GameListRecord, GameListRecord,
GameListResult, GameListResult,
PersonRef, PersonRef,
} from "../kbo/game-list.js"; } from "../kbo/game-list";
export { LeagueCode, LEAGUE_CODES } from "../kbo/game-list.js"; export { LeagueCode, LEAGUE_CODES } from "../kbo/game-list";
export type { export type {
GameDetail, GameDetail,
@ -50,7 +50,7 @@ export type {
KeyPlayerRanking, KeyPlayerRanking,
KeyPlayerItem, KeyPlayerItem,
KeyPlayerGroup, KeyPlayerGroup,
} from "../kbo/game-detail.js"; } from "../kbo/game-detail";
export type { export type {
GameScoringPlays, GameScoringPlays,
@ -61,6 +61,6 @@ export type {
ScoringOutcome, ScoringOutcome,
BaseState, BaseState,
BaseRunner, BaseRunner,
} from "../kbo/play-by-play.js"; } from "../kbo/play-by-play";
export { SERIES_ID } from "../kbo/schedule.js"; export { SERIES_ID } from "../kbo/schedule";

View File

@ -1,5 +1,5 @@
import type { Timestamp } from "firebase-admin/firestore"; import type { Timestamp } from "firebase-admin/firestore";
import type { DateString } from "./dateString.js"; import type { DateString } from "./dateString";
export type Provider = "google" | "apple"; export type Provider = "google" | "apple";

View File

@ -1,4 +1,4 @@
import type { TeamCode } from "./panit.js"; import type { TeamCode } from "./panit";
export interface ScoreboardEntry { export interface ScoreboardEntry {
uid: string; uid: string;

View File

@ -1,8 +1,8 @@
import { beforeEach, describe, expect, it } from "vitest"; import { beforeEach, describe, expect, it } from "vitest";
import { Timestamp } from "firebase-admin/firestore"; import { Timestamp } from "firebase-admin/firestore";
import { firestore } from "../../src/firebase.js"; import { firestore } from "../../src/firebase";
import { getGame, listByDate } from "../../src/repositories/gameRepository.js"; import { getGame, listByDate } from "../../src/repositories/gameRepository";
import type { DateString } from "../../src/types/dateString.js"; import type { DateString } from "../../src/types/dateString";
describe("gameRepository", () => { describe("gameRepository", () => {
beforeEach(async () => { beforeEach(async () => {

View File

@ -1,9 +1,9 @@
import { beforeEach, describe, expect, it } from "vitest"; import { beforeEach, describe, expect, it } from "vitest";
import { firestore } from "../../src/firebase.js"; import { firestore } from "../../src/firebase";
import { import {
fetchRankFromKbo, fetchRankFromKbo,
fetchScheduleFromKbo, fetchScheduleFromKbo,
} from "../../src/repositories/kboRepository.js"; } from "../../src/repositories/kboRepository";
describe("kboRepository (실제 KBO 사이트 호출)", () => { describe("kboRepository (실제 KBO 사이트 호출)", () => {
beforeEach(async () => { beforeEach(async () => {

View File

@ -1,13 +1,13 @@
import { beforeEach, describe, expect, it } from "vitest"; import { beforeEach, describe, expect, it } from "vitest";
import { firestore } from "../../src/firebase.js"; import { firestore } from "../../src/firebase";
import { import {
getAll, getAll,
getDay, getDay,
getRange, getRange,
setDay, setDay,
} from "../../src/repositories/voteHistoryRepository.js"; } from "../../src/repositories/voteHistoryRepository";
import type { DateString } from "../../src/types/dateString.js"; import type { DateString } from "../../src/types/dateString";
import type { VoteHistoryDoc } from "../../src/types/panit.js"; import type { VoteHistoryDoc } from "../../src/types/panit";
const uid = "test-uid-1"; const uid = "test-uid-1";

View File

@ -1,5 +1,5 @@
import { beforeEach, describe, expect, it } from "vitest"; import { beforeEach, describe, expect, it } from "vitest";
import { rtdb } from "../../src/firebase.js"; import { rtdb } from "../../src/firebase";
import { import {
changeVote, changeVote,
deleteGameVotes, deleteGameVotes,
@ -8,8 +8,8 @@ import {
getUserDateVotes, getUserDateVotes,
getUserVote, getUserVote,
submitVote, submitVote,
} from "../../src/repositories/voteRepository.js"; } from "../../src/repositories/voteRepository";
import type { DateString } from "../../src/types/dateString.js"; import type { DateString } from "../../src/types/dateString";
const gameId = "20260412HTLG0"; const gameId = "20260412HTLG0";
const gameId2 = "20260412WOSK0"; const gameId2 = "20260412WOSK0";

View File

@ -1,6 +1,6 @@
import { beforeEach, describe, expect, it } from "vitest"; import { beforeEach, describe, expect, it } from "vitest";
import { firestore } from "../../src/firebase.js"; import { firestore } from "../../src/firebase";
import { getGameDetail } from "../../src/services/gameDetailService.js"; import { getGameDetail } from "../../src/services/gameDetailService";
// 실제 KBO 게임센터 + Firestore 에뮬레이터를 함께 사용한다. // 실제 KBO 게임센터 + Firestore 에뮬레이터를 함께 사용한다.
// nested-array Firestore 거부, parseGameStartTs NPE 등 회귀를 잡기 위함. // nested-array Firestore 거부, parseGameStartTs NPE 등 회귀를 잡기 위함.

View File

@ -1,13 +1,13 @@
import { beforeEach, describe, expect, it } from "vitest"; import { beforeEach, describe, expect, it } from "vitest";
import { firestore } from "../../src/firebase.js"; import { firestore } from "../../src/firebase";
import { import {
toGameDoc, toGameDoc,
toTime, toTime,
syncGamesForMonth, syncGamesForMonth,
gameUpdateFromRecord, gameUpdateFromRecord,
} from "../../src/services/gameSyncService.js"; } from "../../src/services/gameSyncService";
import type { ScheduleGame } from "../../src/kbo/schedule.js"; import type { ScheduleGame } from "../../src/kbo/schedule";
import type { GameListRecord } from "../../src/kbo/game-list.js"; import type { GameListRecord } from "../../src/kbo/game-list";
function baseGame(overrides: Partial<ScheduleGame> = {}): ScheduleGame { function baseGame(overrides: Partial<ScheduleGame> = {}): ScheduleGame {
return { return {

View File

@ -1,19 +1,19 @@
import { beforeEach, describe, expect, it } from "vitest"; import { beforeEach, describe, expect, it } from "vitest";
import { Timestamp } from "firebase-admin/firestore"; import { Timestamp } from "firebase-admin/firestore";
import { firestore } from "../../src/firebase.js"; import { firestore } from "../../src/firebase";
import { import {
judgeDay, judgeDay,
judgeWeekIfNeeded, judgeWeekIfNeeded,
} from "../../src/services/judgmentService.js"; } from "../../src/services/judgmentService";
import { setDay } from "../../src/repositories/voteHistoryRepository.js"; import { setDay } from "../../src/repositories/voteHistoryRepository";
import type { DateString } from "../../src/types/dateString.js"; import type { DateString } from "../../src/types/dateString";
import type { import type {
DailyJudgment, DailyJudgment,
Game, Game,
GameStatus, GameStatus,
User, User,
VoteHistoryDoc, VoteHistoryDoc,
} from "../../src/types/panit.js"; } from "../../src/types/panit";
const uid = "judge-uid"; const uid = "judge-uid";

View File

@ -1,15 +1,15 @@
import { beforeEach, describe, expect, it } from "vitest"; import { beforeEach, describe, expect, it } from "vitest";
import { firestore, rtdb } from "../../src/firebase.js"; import { firestore, rtdb } from "../../src/firebase";
import { import {
__resetScoreboardCaches, __resetScoreboardCaches,
getScoreboard, getScoreboard,
} from "../../src/services/scoreboardService.js"; } from "../../src/services/scoreboardService";
import { import {
precomputeScoreboardCache, precomputeScoreboardCache,
snapshotRankForUser, snapshotRankForUser,
} from "../../src/services/rankSnapshotService.js"; } from "../../src/services/rankSnapshotService";
import { todayKst } from "../../src/types/dateString.js"; import { todayKst } from "../../src/types/dateString";
import { TeamCode, type RankSnapshot } from "../../src/types/panit.js"; import { TeamCode, type RankSnapshot } from "../../src/types/panit";
interface SeedUser { interface SeedUser {
uid: string; uid: string;

View File

@ -1,18 +1,18 @@
import { beforeEach, describe, expect, it } from "vitest"; import { beforeEach, describe, expect, it } from "vitest";
import { Timestamp } from "firebase-admin/firestore"; import { Timestamp } from "firebase-admin/firestore";
import { firestore, rtdb } from "../../src/firebase.js"; import { firestore, rtdb } from "../../src/firebase";
import { getStats } from "../../src/services/statsService.js"; import { getStats } from "../../src/services/statsService";
import { import {
addDaysKst, addDaysKst,
todayKst, todayKst,
type DateString, type DateString,
} from "../../src/types/dateString.js"; } from "../../src/types/dateString";
import type { import type {
Game, Game,
GameStatus, GameStatus,
StatsResponse, StatsResponse,
User, User,
} from "../../src/types/panit.js"; } from "../../src/types/panit";
const uid = "stats-uid"; const uid = "stats-uid";

View File

@ -1,18 +1,18 @@
import { beforeEach, describe, expect, it } from "vitest"; import { beforeEach, describe, expect, it } from "vitest";
import type { DecodedIdToken } from "firebase-admin/auth"; import type { DecodedIdToken } from "firebase-admin/auth";
import { firestore, rtdb } from "../../src/firebase.js"; import { firestore, rtdb } from "../../src/firebase";
import { import {
checkNickname, checkNickname,
createMe, createMe,
deleteMe, deleteMe,
getMe, getMe,
updateMe, updateMe,
} from "../../src/services/userService.js"; } from "../../src/services/userService";
import { HttpError } from "../../src/middleware/errors.js"; import { HttpError } from "../../src/middleware/errors";
import { import {
RESERVATION_TTL_MS, RESERVATION_TTL_MS,
reserveNickname, reserveNickname,
} from "../../src/repositories/nicknameRepository.js"; } from "../../src/repositories/nicknameRepository";
const uid = "user-1"; const uid = "user-1";