Refactor platform publishing

Introduce a new `getMinecraftVersions` function to fetch Minecraft
versions from
CurseForge with caching, along with its Zod schema and exports. Refactor
the
publishing system to use a unified `PlatformAdaptor` interface, replace
the old
`PlatformContext` type, and update the publish flow to compute version
ranges
and pass files as structured objects. Improve `resolveVersionName` to
accept a
full config object and rework `buildJarPath` to use a Template instance.
Add
server functions to retrieve filtered MC version lists for both Modrinth
and
CurseForge.
This commit is contained in:
CPTProgrammer
2026-07-11 09:26:05 +08:00
parent e8bcd18c76
commit ffcfa9c4f5
13 changed files with 191 additions and 102 deletions
+46 -14
View File
@@ -7,10 +7,30 @@ import {
type ProgressEvent,
type PlatformResult,
type PublishResult,
platforms,
type PlatformContext,
type PlatformAdaptor,
} from "./publish.schemas";
import { publishModrinthVersion } from "./platforms/modrinth";
import { publishCurseForgeVersion } from "./platforms/curseforge";
import type { PlatformContext } from "./platforms/types";
import { computeVersionRanges } from "@/lib/utils/mcVersion";
import { getCurseForgeMcVersions, getModrinthMcVersions } from "./meta";
import { readAsFile } from "@/lib/utils/file";
import { Template } from "@/lib/utils/template";
import { buildJarPath } from "@/lib/utils/format";
export const platformAdaptors: {
[key in typeof platforms[number]]: PlatformAdaptor
} = {
modrinth: {
publish: publishModrinthVersion,
getGameVersions: getModrinthMcVersions,
},
curseforge: {
publish: publishCurseForgeVersion,
getGameVersions: getCurseForgeMcVersions,
},
};
// ── tRPC init ──────────────────────────────────────────
@@ -23,7 +43,7 @@ const ee = new EventEmitter();
// ── Platform orchestrator ──────────────────────────────
async function runPlatform(
platform: "modrinth" | "curseforge",
platform: typeof platforms[number],
mcVersions: { mc_version: string }[],
ctx: PlatformContext,
): Promise<PlatformResult> {
@@ -50,16 +70,29 @@ async function runPlatform(
errors: [],
} satisfies ProgressEvent);
const publishFn =
platform === "modrinth"
? publishModrinthVersion
: publishCurseForgeVersion;
const publishFn = platformAdaptors[platform].publish;
const getGameVersionsFn = platformAdaptors[platform].getGameVersions;
for (let i = 0; i < mcVersions.length; i++) {
const { mc_version } = mcVersions[i];
const mcVersionEntries = computeVersionRanges(
mcVersions.map(v => v.mc_version),
await getGameVersionsFn(),
ctx.input.cutoffMcVersion
);
const primaryFileTemplate = new Template(ctx.config.filename_format);
const sourceFileTemplate = new Template(ctx.config.source_filename_format);
for (let i = 0; i < mcVersionEntries.length; i++) {
const mcVersionEntry = mcVersionEntries[i];
try {
await publishFn(ctx, mc_version);
const primaryFile = await readAsFile(buildJarPath(ctx.config.project_dir, primaryFileTemplate, ctx.input.version, mcVersionEntry.version));
const sourceFile = await readAsFile(buildJarPath(ctx.config.project_dir, sourceFileTemplate, ctx.input.version, mcVersionEntry.version));
await publishFn(ctx, mcVersionEntry, {
primary: primaryFile,
source: sourceFile,
});
result.success++;
const isLast = i + 1 === total;
@@ -72,7 +105,7 @@ async function runPlatform(
} satisfies ProgressEvent);
} catch (err) {
result.fail++;
const msg = `${mc_version}: ${errorMessage(err)}`;
const msg = `${mcVersionEntry.version}: ${errorMessage(err)}`;
result.errors.push(msg);
ee.emit("progress", {
@@ -101,10 +134,9 @@ export const appRouter = t.router({
const ctx: PlatformContext = { input, config };
const [modrinthSettled, curseforgeSettled] = await Promise.allSettled([
runPlatform("modrinth", input.mcVersions.modrinth, ctx),
runPlatform("curseforge", input.mcVersions.curseforge, ctx),
]);
const [modrinthSettled, curseforgeSettled] = await Promise.allSettled(
platforms.map(platform => runPlatform(platform, input.mcVersions[platform], ctx))
);
const modrinth: PlatformResult = modrinthSettled.status === "fulfilled"
? modrinthSettled.value