From 56d4371a5d35a08ba9f2bdc1068513d566244d24 Mon Sep 17 00:00:00 2001 From: DecDuck Date: Mon, 3 Nov 2025 13:54:53 +1100 Subject: [PATCH] feat: redist import --- app/pages/admin/library/g/[id]/import.vue | 2 +- app/pages/admin/library/index.vue | 9 +- app/pages/admin/library/r/[id]/import.vue | 479 +++++++++++++++++- .../api/v1/admin/import/version/index.get.ts | 36 +- server/internal/library/index.ts | 77 ++- 5 files changed, 559 insertions(+), 44 deletions(-) diff --git a/app/pages/admin/library/g/[id]/import.vue b/app/pages/admin/library/g/[id]/import.vue index 19a3d6b..4729854 100644 --- a/app/pages/admin/library/g/[id]/import.vue +++ b/app/pages/admin/library/g/[id]/import.vue @@ -487,7 +487,7 @@ const { t } = useI18n(); const route = useRoute(); const gameId = route.params.id.toString(); const versions = await $dropFetch( - `/api/v1/admin/import/version?id=${encodeURIComponent(gameId)}`, + `/api/v1/admin/import/version?id=${encodeURIComponent(gameId)}&mode=game`, ); const userPlatforms = await useAdminPlatforms(); const allPlatforms = renderPlatforms(userPlatforms); diff --git a/app/pages/admin/library/index.vue b/app/pages/admin/library/index.vue index 7e9751e..18a6fbd 100644 --- a/app/pages/admin/library/index.vue +++ b/app/pages/admin/library/index.vue @@ -158,7 +158,7 @@

( toImport?: boolean; offline?: boolean; }; + urlPrefix: string, } > { return values.map((e) => { @@ -418,6 +419,7 @@ function clientSideTransformation( notifications: { offline: true, }, + urlPrefix: type[0], }; } @@ -433,6 +435,7 @@ function clientSideTransformation( }, hasNotifications: noVersions || toImport, status: "online" as const, + urlPrefix: type[0], }; }); } diff --git a/app/pages/admin/library/r/[id]/import.vue b/app/pages/admin/library/r/[id]/import.vue index 3553385..22b7d6b 100644 --- a/app/pages/admin/library/r/[id]/import.vue +++ b/app/pages/admin/library/r/[id]/import.vue @@ -1 +1,478 @@ - + + + diff --git a/server/api/v1/admin/import/version/index.get.ts b/server/api/v1/admin/import/version/index.get.ts index 1476bf8..c10427a 100644 --- a/server/api/v1/admin/import/version/index.get.ts +++ b/server/api/v1/admin/import/version/index.get.ts @@ -1,29 +1,33 @@ +import { ArkErrors, type } from "arktype"; import aclManager from "~~/server/internal/acls"; import prisma from "~~/server/internal/db/database"; -import libraryManager from "~~/server/internal/library"; +import libraryManager, { VersionImportModes } from "~~/server/internal/library"; + +export const PreloadQuery = type({ + id: "string", + mode: type.enumerated(...VersionImportModes), +}); export default defineEventHandler(async (h3) => { const allowed = await aclManager.allowSystemACL(h3, ["import:version:read"]); if (!allowed) throw createError({ statusCode: 403 }); - const query = await getQuery(h3); - const gameId = query.id?.toString(); - if (!gameId) - throw createError({ - statusCode: 400, - message: "Missing id in request params", - }); + const rawQuery = await getQuery(h3); + const query = PreloadQuery(rawQuery); + if (query instanceof ArkErrors) + throw createError({ statusCode: 400, message: query.summary }); - const game = await prisma.game.findUnique({ - where: { id: gameId }, - select: { libraryId: true, libraryPath: true }, - }); - if (!game || !game.libraryId) - throw createError({ statusCode: 404, message: "Game not found" }); + const value: { libraryId: string; libraryPath: string } | undefined = + await // eslint-disable-next-line @typescript-eslint/no-explicit-any + (prisma[query.mode] as any).findUnique({ + where: { id: query.id }, + select: { libraryId: true, libraryPath: true }, + }); + if (!value) throw createError({ statusCode: 404, message: "Not found" }); const unimportedVersions = await libraryManager.fetchUnimportedGameVersions( - game.libraryId, - game.libraryPath, + value.libraryId, + value.libraryPath, ); if (!unimportedVersions) throw createError({ statusCode: 400, message: "Invalid game ID" }); diff --git a/server/internal/library/index.ts b/server/internal/library/index.ts index dcb86b5..7e71c9c 100644 --- a/server/internal/library/index.ts +++ b/server/internal/library/index.ts @@ -256,30 +256,30 @@ class LibraryManager { currentIndex: number, metadata: typeof ImportVersion.infer, ): Partial { + const installCreator = { + install: { + create: { + name: "", + description: "", + command: metadata.install!, + args: metadata.installArgs || "", + }, + }, + } satisfies Partial; + + const uninstallCreator = { + uninstall: { + create: { + name: "", + description: "", + command: metadata.uninstall!, + args: metadata.uninstallArgs || "", + }, + }, + } satisfies Partial; + switch (metadata.mode) { case "game": { - const installCreator = { - install: { - create: { - name: "", - description: "", - command: metadata.install!, - args: metadata.installArgs || "", - }, - }, - } satisfies Partial; - - const uninstallCreator = { - uninstall: { - create: { - name: "", - description: "", - command: metadata.uninstall!, - args: metadata.uninstallArgs || "", - }, - }, - } satisfies Partial; - return { gameId: id, gameVersions: { @@ -317,7 +317,38 @@ class LibraryManager { }; } case "redist": - return {}; + return { + redistId: id, + redistVersions: { + create: { + versionIndex: currentIndex, + delta: metadata.delta, + + launches: { + createMany: { + data: metadata.launches.map( + (v) => + ({ + name: v.name, + description: v.description, + command: v.launchCommand, + args: v.launchArgs, + }) satisfies LaunchOptionCreateManyInput, + ), + }, + }, + + ...(metadata.install ? installCreator : undefined), + ...(metadata.uninstall ? uninstallCreator : undefined), + + platform: { + connect: { + id: metadata.platform, + }, + }, + }, + }, + }; } }