diff --git a/apps/frontend/src/pages/hosting/manage/[id]/options/loader.vue b/apps/frontend/src/pages/hosting/manage/[id]/options/loader.vue index 247ddffd4..e0ddf660b 100644 --- a/apps/frontend/src/pages/hosting/manage/[id]/options/loader.vue +++ b/apps/frontend/src/pages/hosting/manage/[id]/options/loader.vue @@ -256,6 +256,26 @@ const purpurBuildsQuery = useQuery({ staleTime: 5 * 60 * 1000, }) +const paperSupportedVersionsQuery = useQuery({ + queryKey: ['paper-supported-versions'] as const, + queryFn: async () => { + const project = await client.paper.versions_v3.getProject() + return new Set(Object.values(project.versions).flat()) + }, + enabled: computed(() => editingPlatform.value === 'paper'), + staleTime: 5 * 60 * 1000, +}) + +const purpurSupportedVersionsQuery = useQuery({ + queryKey: ['purpur-supported-versions'] as const, + queryFn: async () => { + const project = await client.purpur.versions_v2.getProject() + return new Set(project.versions) + }, + enabled: computed(() => editingPlatform.value === 'purpur'), + staleTime: 5 * 60 * 1000, +}) + type LoaderVersionEntry = LauncherMeta.Manifest.v0.LoaderVersion function getLoaderVersionsForGameVersion( @@ -363,18 +383,34 @@ provideInstallationSettings({ ? tags.gameVersions.value : tags.gameVersions.value.filter((v) => v.version_type === 'release') - if (loader && loader !== 'vanilla' && !['paper', 'purpur'].includes(loader)) { - const manifest = manifestQuery.data.value?.gameVersions - if (manifest) { - const hasPlaceholder = manifest.some((x) => x.id === '${modrinth.gameVersion}') - if (!hasPlaceholder) { - const supportedVersions = new Set( - manifest.filter((x) => x.loaders.length > 0).map((x) => x.id), - ) + if (loader && loader !== 'vanilla') { + if (loader === 'paper') { + const supported = paperSupportedVersionsQuery.data.value + if (supported) { return versions - .filter((v) => supportedVersions.has(v.version)) + .filter((v) => supported.has(v.version)) .map((v) => ({ value: v.version, label: v.version })) } + } else if (loader === 'purpur') { + const supported = purpurSupportedVersionsQuery.data.value + if (supported) { + return versions + .filter((v) => supported.has(v.version)) + .map((v) => ({ value: v.version, label: v.version })) + } + } else { + const manifest = manifestQuery.data.value?.gameVersions + if (manifest) { + const hasPlaceholder = manifest.some((x) => x.id === '${modrinth.gameVersion}') + if (!hasPlaceholder) { + const supportedVersions = new Set( + manifest.filter((x) => x.loaders.length > 0).map((x) => x.id), + ) + return versions + .filter((v) => supportedVersions.has(v.version)) + .map((v) => ({ value: v.version, label: v.version })) + } + } } } @@ -387,9 +423,23 @@ provideInstallationSettings({ }, resolveHasSnapshots(loader) { - if (loader === 'vanilla' || ['paper', 'purpur'].includes(loader)) { + if (loader === 'vanilla') { return tags.gameVersions.value.some((v) => v.version_type !== 'release') } + if (loader === 'paper') { + const supported = paperSupportedVersionsQuery.data.value + if (!supported) return false + return tags.gameVersions.value.some( + (v) => v.version_type !== 'release' && supported.has(v.version), + ) + } + if (loader === 'purpur') { + const supported = purpurSupportedVersionsQuery.data.value + if (!supported) return false + return tags.gameVersions.value.some( + (v) => v.version_type !== 'release' && supported.has(v.version), + ) + } const manifest = manifestQuery.data.value?.gameVersions if (!manifest) return false const hasPlaceholder = manifest.some((x) => x.id === '${modrinth.gameVersion}') diff --git a/packages/api-client/src/modules/index.ts b/packages/api-client/src/modules/index.ts index e0b61dcdb..3312b7388 100644 --- a/packages/api-client/src/modules/index.ts +++ b/packages/api-client/src/modules/index.ts @@ -14,18 +14,18 @@ import { LabrinthAffiliateInternalModule } from './labrinth/affiliate/internal' import { LabrinthAuthInternalModule } from './labrinth/auth/internal' import { LabrinthAuthV2Module } from './labrinth/auth/v2' import { LabrinthBillingInternalModule } from './labrinth/billing/internal' +import { LabrinthCollectionsModule } from './labrinth/collections' import { LabrinthGlobalsInternalModule } from './labrinth/globals/internal' +import { LabrinthLimitsV3Module } from './labrinth/limits/v3' import { LabrinthNotificationsV2Module } from './labrinth/notifications/v2' import { LabrinthOAuthInternalModule } from './labrinth/oauth/internal' -import { LabrinthCollectionsModule } from './labrinth/collections' import { LabrinthOrganizationsV3Module } from './labrinth/organizations/v3' import { LabrinthPatsV2Module } from './labrinth/pats/v2' -import { LabrinthLimitsV3Module } from './labrinth/limits/v3' import { LabrinthPayoutV3Module } from './labrinth/payout/v3' import { LabrinthPayoutsV3Module } from './labrinth/payouts/v3' -import { LabrinthReportsV3Module } from './labrinth/reports/v3' import { LabrinthProjectsV2Module } from './labrinth/projects/v2' import { LabrinthProjectsV3Module } from './labrinth/projects/v3' +import { LabrinthReportsV3Module } from './labrinth/reports/v3' import { LabrinthServerPingInternalModule } from './labrinth/server-ping/internal' import { LabrinthSessionsV2Module } from './labrinth/sessions/v2' import { LabrinthStateModule } from './labrinth/state' diff --git a/packages/api-client/src/modules/labrinth/index.ts b/packages/api-client/src/modules/labrinth/index.ts index 3beed4d87..a1e25783a 100644 --- a/packages/api-client/src/modules/labrinth/index.ts +++ b/packages/api-client/src/modules/labrinth/index.ts @@ -3,11 +3,11 @@ export * from './auth/v2' export * from './billing/internal' export * from './collections' export * from './globals/internal' +export * from './limits/v3' export * from './notifications/v2' export * from './oauth/internal' export * from './organizations/v3' export * from './pats/v2' -export * from './limits/v3' export * from './payout/v3' export * from './payouts/v3' export * from './projects/v2' diff --git a/packages/api-client/src/modules/paper/types.ts b/packages/api-client/src/modules/paper/types.ts index f8febff0c..3e02778ca 100644 --- a/packages/api-client/src/modules/paper/types.ts +++ b/packages/api-client/src/modules/paper/types.ts @@ -1,6 +1,11 @@ export namespace Paper { export namespace Versions { export namespace v3 { + export type Project = { + project: { id: string; name: string } + versions: Record + } + export type VersionBuilds = { builds: number[] } diff --git a/packages/api-client/src/modules/paper/v3.ts b/packages/api-client/src/modules/paper/v3.ts index 83ea2fcad..85353be11 100644 --- a/packages/api-client/src/modules/paper/v3.ts +++ b/packages/api-client/src/modules/paper/v3.ts @@ -12,6 +12,13 @@ export class PaperVersionsV3Module extends AbstractModule { return 'paper_versions_v3' } + /** + * Get the Paper project info including all supported Minecraft versions. + */ + public async getProject(): Promise { + return $fetch(`${BASE_URL}/projects/paper`) + } + /** * Get available Paper builds for a Minecraft version. * diff --git a/packages/api-client/src/modules/purpur/types.ts b/packages/api-client/src/modules/purpur/types.ts index 998b81809..14e985ad8 100644 --- a/packages/api-client/src/modules/purpur/types.ts +++ b/packages/api-client/src/modules/purpur/types.ts @@ -1,6 +1,11 @@ export namespace Purpur { export namespace Versions { export namespace v2 { + export type Project = { + project: string + versions: string[] + } + export type VersionBuilds = { builds: { all: string[] diff --git a/packages/api-client/src/modules/purpur/v2.ts b/packages/api-client/src/modules/purpur/v2.ts index 441be34e0..6efd06443 100644 --- a/packages/api-client/src/modules/purpur/v2.ts +++ b/packages/api-client/src/modules/purpur/v2.ts @@ -12,6 +12,13 @@ export class PurpurVersionsV2Module extends AbstractModule { return 'purpur_versions_v2' } + /** + * Get the Purpur project info including all supported Minecraft versions. + */ + public async getProject(): Promise { + return $fetch(`${BASE_URL}/purpur`) + } + /** * Get available Purpur builds for a Minecraft version. * diff --git a/packages/ui/src/components/flows/creation-flow-modal/components/CustomSetupStage.vue b/packages/ui/src/components/flows/creation-flow-modal/components/CustomSetupStage.vue index 536b3057d..7e11a590a 100644 --- a/packages/ui/src/components/flows/creation-flow-modal/components/CustomSetupStage.vue +++ b/packages/ui/src/components/flows/creation-flow-modal/components/CustomSetupStage.vue @@ -104,7 +104,7 @@ import { computed, onMounted, ref, watch } from 'vue' import { useDebugLogger } from '#ui/composables/debug-logger' -import { injectFilePicker, injectTags } from '../../../../providers' +import { injectFilePicker, injectModrinthClient, injectTags } from '../../../../providers' import Avatar from '../../../base/Avatar.vue' import ButtonStyled from '../../../base/ButtonStyled.vue' import Chips from '../../../base/Chips.vue' @@ -116,6 +116,7 @@ import { injectCreationFlowContext } from '../creation-flow-context' import { capitalize, formatLoaderLabel } from '../shared' const debug = useDebugLogger('CustomSetupStage') +const client = injectModrinthClient() const ctx = injectCreationFlowContext() const { selectedLoader, @@ -280,9 +281,8 @@ async function fetchLoaderManifest(loader: string) { async function fetchPaperSupportedVersions() { if (paperSupportedVersions.value) return try { - const res = await fetch('https://api.papermc.io/v2/projects/paper') - const data = (await res.json()) as { versions: string[] } - paperSupportedVersions.value = new Set(data.versions) + const project = await client.paper.versions_v3.getProject() + paperSupportedVersions.value = new Set(Object.values(project.versions).flat()) } catch { paperSupportedVersions.value = new Set() } @@ -291,9 +291,8 @@ async function fetchPaperSupportedVersions() { async function fetchPurpurSupportedVersions() { if (purpurSupportedVersions.value) return try { - const res = await fetch('https://api.purpurmc.org/v2/purpur') - const data = (await res.json()) as { versions: string[] } - purpurSupportedVersions.value = new Set(data.versions) + const project = await client.purpur.versions_v2.getProject() + purpurSupportedVersions.value = new Set(project.versions) } catch { purpurSupportedVersions.value = new Set() } @@ -302,8 +301,7 @@ async function fetchPurpurSupportedVersions() { async function fetchPaperVersions(mcVersion: string) { if (paperVersions.value[mcVersion]) return try { - const res = await fetch(`https://fill.papermc.io/v3/projects/paper/versions/${mcVersion}`) - const data = (await res.json()) as { builds: number[] } + const data = await client.paper.versions_v3.getBuilds(mcVersion) paperVersions.value[mcVersion] = data.builds.sort((a, b) => b - a) } catch { paperVersions.value[mcVersion] = [] @@ -313,8 +311,7 @@ async function fetchPaperVersions(mcVersion: string) { async function fetchPurpurVersions(mcVersion: string) { if (purpurVersions.value[mcVersion]) return try { - const res = await fetch(`https://api.purpurmc.org/v2/purpur/${mcVersion}`) - const data = (await res.json()) as { builds: { all: string[] } } + const data = await client.purpur.versions_v2.getBuilds(mcVersion) purpurVersions.value[mcVersion] = data.builds.all.sort((a, b) => parseInt(b) - parseInt(a)) } catch { purpurVersions.value[mcVersion] = []