Switch mods to per-folder auto-discovery and resourcepack to single zip
- PackDefinition: replace mods[]/resourcepacks[] with modsFolder (string) + resourcepackPath (string); drop PackAsset - Editor: replace dynamic add/remove lists with two single inputs; remove the now-dead JS for adding/removing rows - Server: expose GET /file/mods/<folder>/index.json that returns the list of .jar names; folder name restricted to [a-zA-Z0-9_-]+ - Installer: fetch the listing JSON and download each jar from /file/mods/<folder>/<file>.jar; download the single resourcepack from /file/resourcepacks/<file>.zip directly into resourcepacks/ Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -32,8 +32,8 @@ export function defaultPackDefinition(name: string): PackDefinition {
|
||||
name,
|
||||
mcVersion: '1.20.1',
|
||||
platform: { type: 'vanilla' },
|
||||
mods: [],
|
||||
resourcepacks: [],
|
||||
modsFolder: '',
|
||||
resourcepackPath: '',
|
||||
serverMinRam: 2048,
|
||||
serverMaxRam: 4096,
|
||||
clientMinRam: 2048,
|
||||
@@ -53,6 +53,15 @@ function sanitizeZipFileName(input: unknown): string {
|
||||
return trimmed
|
||||
}
|
||||
|
||||
// 모드 폴더명: 영문/숫자/언더스코어/하이픈만 허용. 빈 값 허용.
|
||||
function sanitizeFolderName(input: unknown): string {
|
||||
if (typeof input !== 'string') return ''
|
||||
const trimmed = input.trim().replace(/^\/+|\/+$/g, '')
|
||||
if (trimmed.length === 0) return ''
|
||||
if (!/^[a-zA-Z0-9_\-]+$/.test(trimmed)) return ''
|
||||
return trimmed
|
||||
}
|
||||
|
||||
const ALLOWED_LOADERS: LoaderType[] = ['vanilla', 'forge', 'fabric', 'neoforge']
|
||||
|
||||
export function normalizePackDefinition(input: Partial<PackDefinition> & Record<string, unknown>): PackDefinition {
|
||||
@@ -62,28 +71,6 @@ export function normalizePackDefinition(input: Partial<PackDefinition> & Record<
|
||||
? (platform.type as LoaderType)
|
||||
: 'vanilla'
|
||||
|
||||
const modsSource = Array.isArray(input.mods) ? input.mods : []
|
||||
const mods = modsSource
|
||||
.map((entry) => {
|
||||
const value = entry as Partial<PackDefinition['mods'][number]>
|
||||
return {
|
||||
name: typeof value?.name === 'string' ? value.name.trim() : '',
|
||||
downloadUrl: typeof value?.downloadUrl === 'string' ? value.downloadUrl.trim() : ''
|
||||
}
|
||||
})
|
||||
.filter((entry) => entry.name.length > 0 || entry.downloadUrl.length > 0)
|
||||
|
||||
const resourcePacksSource = Array.isArray(input.resourcepacks) ? input.resourcepacks : []
|
||||
const resourcepacks = resourcePacksSource
|
||||
.map((entry) => {
|
||||
const value = entry as Partial<PackDefinition['resourcepacks'][number]>
|
||||
return {
|
||||
name: typeof value?.name === 'string' ? value.name.trim() : '',
|
||||
downloadUrl: typeof value?.downloadUrl === 'string' ? value.downloadUrl.trim() : ''
|
||||
}
|
||||
})
|
||||
.filter((entry) => entry.name.length > 0 || entry.downloadUrl.length > 0)
|
||||
|
||||
return {
|
||||
name: typeof input.name === 'string' && input.name.trim().length > 0 ? input.name.trim() : fallback.name,
|
||||
mcVersion: typeof input.mcVersion === 'string' && input.mcVersion.trim().length > 0
|
||||
@@ -95,8 +82,8 @@ export function normalizePackDefinition(input: Partial<PackDefinition> & Record<
|
||||
? platform.downloadUrl.trim()
|
||||
: undefined
|
||||
},
|
||||
mods,
|
||||
resourcepacks,
|
||||
modsFolder: sanitizeFolderName(input.modsFolder),
|
||||
resourcepackPath: sanitizeZipFileName(input.resourcepackPath),
|
||||
serverMinRam: clampNumber(input.serverMinRam, fallback.serverMinRam),
|
||||
serverMaxRam: clampNumber(input.serverMaxRam, fallback.serverMaxRam),
|
||||
clientMinRam: clampNumber(input.clientMinRam, fallback.clientMinRam),
|
||||
|
||||
@@ -5,17 +5,14 @@ export interface PackPlatform {
|
||||
downloadUrl?: string
|
||||
}
|
||||
|
||||
export interface PackAsset {
|
||||
name: string
|
||||
downloadUrl: string
|
||||
}
|
||||
|
||||
export interface PackDefinition {
|
||||
name: string
|
||||
mcVersion: string
|
||||
platform: PackPlatform
|
||||
mods: PackAsset[]
|
||||
resourcepacks: PackAsset[]
|
||||
/** /file/mods/<modsFolder>/ 폴더 안의 모든 .jar을 자동 다운로드. */
|
||||
modsFolder: string
|
||||
/** /file/resourcepacks/<resourcepackPath> 의 단일 .zip을 그대로 다운로드. */
|
||||
resourcepackPath: string
|
||||
serverMinRam: number
|
||||
serverMaxRam: number
|
||||
clientMinRam: number
|
||||
|
||||
Reference in New Issue
Block a user