Files
minecraft_launcher/src/shared/paths.ts
claude-bot 996a7cc03e feat(installer): v0.4.0 — 파일제거기, 커스텀 폴더명, 포트포워딩 개편, 이름/개발자용 표기
- 음악퀴즈 파일제거 도구 신규 추가: 동의 → 휴지통/완전삭제 선택 → 커스텀 폴더
  (현재값 + 기본 .mc_custom) 전체, 데스크톱 바로가기, gameDir 가 해당 폴더인
  마인크래프트 런처 프로필 정리.
- MC_CUSTOM_DIR .env 로 커스텀 게임 폴더 이름 유동화(.mc_custom 기본). 렌더러
  사전에도 실제 폴더명 반영.
- 간편포트포워딩: 실행 중 UPnP 매핑 유지, 창 닫힘/종료 시 자동 제거(activePort 추적).
- 개발자용 빌드는 창/헤더 제목 앞에 (개발자용) 표기, exe 이름에도 반영.
- exe 이름 변경: 음악퀴즈 간편설치기 / 음악퀴즈 리소스팩설치기 / 간편포트포워딩.
- README 및 .env 템플릿 갱신, 버전 0.3.23 → 0.4.0.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-07-15 23:21:46 +09:00

90 lines
4.3 KiB
TypeScript

import path from 'node:path'
import os from 'node:os'
// 컴파일 후 dist/shared/paths.js → 2단계 상위가 프로젝트 루트.
export const projectRoot = path.resolve(__dirname, '..', '..')
export const manifestRootPath = path.join(projectRoot, 'manifest.json')
export const manifestDirPath = path.join(projectRoot, 'manifest')
export const manifestTermsDirPath = path.join(manifestDirPath, 'terms')
// 추적되는 account.json(과거 평문 노출)을 대체할, gitignore 된 운영 계정 파일.
// readAccounts 는 이 파일을 우선 사용하고, 없을 때만 account.json 을 시드로 읽는다.
//
// TODO(untrack-after-redeploy): account.json 은 아직 git 추적 상태다. 절대 지금
// 같은 커밋에서 `git rm --cached account.json` 하지 말 것 — 서버에 account.local.json
// 이 아직 없을 때 시드 소스가 사라져 로그인이 막힌다(chicken-and-egg).
// 안전한 순서: (1) 이 커밋 배포 → 서버가 account.local.json(0o600) 자동 생성 확인 →
// (2) 그 다음 후속 커밋에서 account.json 추적 해제.
// 주의: 추적 해제는 위생일 뿐, 히스토리의 평문 비밀번호는 지워지지 않는다 → 비밀번호 로테이션이 실질 조치.
export const accountFilePath = path.join(projectRoot, 'account.json')
export const accountLocalFilePath = path.join(projectRoot, 'account.local.json')
export const fileDirPath = path.join(projectRoot, 'file')
export const fileListDirPath = path.join(fileDirPath, 'list')
export const fileDatapacksDirPath = path.join(fileDirPath, 'datapacks')
export const viewsDirPath = path.join(projectRoot, 'views')
export const publicDirPath = path.join(projectRoot, 'public')
/**
* 사용자 환경의 "%appdata%" 디렉터리(OS별 표준 사용자 데이터 경로)를 반환.
* - Windows : %APPDATA% (보통 C:\Users\<user>\AppData\Roaming)
* - macOS : ~/Library/Application Support
* - Linux 등 : $XDG_CONFIG_HOME 또는 ~/.config
*/
export function getAppDataDir(): string {
if (process.platform === 'win32') {
return process.env.APPDATA || path.join(os.homedir(), 'AppData', 'Roaming')
}
if (process.platform === 'darwin') {
return path.join(os.homedir(), 'Library', 'Application Support')
}
return process.env.XDG_CONFIG_HOME || path.join(os.homedir(), '.config')
}
/**
* 커스텀 게임 디렉터리의 폴더 이름. 기본은 `.mc_custom` 이지만 환경변수
* `MC_CUSTOM_DIR` 로 다른 이름을 지정할 수 있다(.env / .env.build 로 주입).
* 경로 구분자·상위경로 이스케이프(`/`, `\`, `..`)는 제거해 항상 %appdata%
* 바로 아래 단일 폴더로 강제한다.
*/
export function getMcCustomDirName(): string {
const raw = (process.env.MC_CUSTOM_DIR ?? '').trim()
if (!raw) return '.mc_custom'
const sanitized = raw.replace(/[\\/]+/g, '').replace(/\.\.+/g, '.')
return sanitized || '.mc_custom'
}
/** %appdata%/<MC_CUSTOM_DIR|.mc_custom> — 음악퀴즈 관련 게임 폴더/외부 도구/캐시 보관 디렉터리. */
export function getMcCustomDir(): string {
return path.join(getAppDataDir(), getMcCustomDirName())
}
/**
* 사전/문자열 구조 안의 리터럴 `.mc_custom` 을 실제 폴더 이름으로 치환한 깊은
* 복사본을 돌려준다. 기본값(`.mc_custom`)이면 원본을 그대로 반환한다. 렌더러로
* 넘기는 i18n 사전에 적용해 UI 안내 문구가 실제 폴더 이름과 어긋나지 않게 한다.
*/
export function withCustomDirName<T>(value: T): T {
const name = getMcCustomDirName()
if (name === '.mc_custom') return value
const replace = (v: unknown): unknown => {
if (typeof v === 'string') return v.split('.mc_custom').join(name)
if (Array.isArray(v)) return v.map(replace)
if (v && typeof v === 'object') {
const out: Record<string, unknown> = {}
for (const [k, val] of Object.entries(v as Record<string, unknown>)) out[k] = replace(val)
return out
}
return v
}
return replace(value) as T
}
/**
* %appdata%/.mc_custom/installer — 설치기가 자체적으로 다운로드해 사용하는
* 외부 바이너리(yt-dlp.exe, ffmpeg.exe 등) 보관 위치. .mc_custom 루트가
* 마인크래프트 게임 폴더(`mods/`, `resourcepacks/`, `saves/` 등)와 섞이지
* 않도록 별도 하위 폴더에 둔다.
*/
export function getMcCustomInstallerDir(): string {
return path.join(getMcCustomDir(), 'installer')
}