Rearchitecture for v0.4.0 (#197)

* feat: database redist support

* feat: rearchitecture of database schemas, migration reset, and #180

* feat: import redists

* fix: giantbomb logging bug

* feat: partial user platform support + statusMessage -> message

* feat: add user platform filters to store view

* fix: sanitize svg uploads

... copilot suggested this

I feel dirty.

* feat: beginnings of platform & redist management

* feat: add server side redist patching

* fix: update drop-base commit

* feat: import of custom platforms & file extensions

* fix: redelete platform

* fix: remove platform

* feat: uninstall commands, new R UI

* checkpoint: before migrating to nuxt v4

* update to nuxt 4

* fix: fixes for Nuxt v4 update

* fix: remaining type issues

* feat: initial feedback to import other kinds of versions

* working commit

* fix: lint

* feat: redist import
This commit is contained in:
DecDuck
2025-11-10 10:36:13 +11:00
committed by GitHub
parent dfa30c8a65
commit 251ddb8ff8
465 changed files with 8029 additions and 7509 deletions

View File

@ -1,5 +1,5 @@
import clientHandler from "~/server/internal/clients/handler";
import sessionHandler from "~/server/internal/session";
import clientHandler from "~~/server/internal/clients/handler";
import sessionHandler from "~~/server/internal/session";
export default defineEventHandler(async (h3) => {
const user = await sessionHandler.getSession(h3);
@ -12,13 +12,13 @@ export default defineEventHandler(async (h3) => {
if (!client)
throw createError({
statusCode: 400,
statusMessage: "Invalid or expired client ID.",
message: "Invalid or expired client ID.",
});
if (client.userId != user.userId)
throw createError({
statusCode: 403,
statusMessage: "Not allowed to authorize this client.",
message: "Not allowed to authorize this client.",
});
const token = await clientHandler.generateAuthToken(clientId);

View File

@ -1,5 +1,5 @@
import clientHandler from "~/server/internal/clients/handler";
import sessionHandler from "~/server/internal/session";
import clientHandler from "~~/server/internal/clients/handler";
import sessionHandler from "~~/server/internal/session";
export default defineEventHandler(async (h3) => {
const user = await sessionHandler.getSession(h3);
@ -10,12 +10,12 @@ export default defineEventHandler(async (h3) => {
if (!code)
throw createError({
statusCode: 400,
statusMessage: "Code required in query params.",
message: "Code required in query params.",
});
const clientId = await clientHandler.fetchClientIdByCode(code);
if (!clientId)
throw createError({ statusCode: 400, statusMessage: "Invalid code." });
throw createError({ statusCode: 400, message: "Invalid code." });
return clientId;
});

View File

@ -1,5 +1,5 @@
import clientHandler from "~/server/internal/clients/handler";
import sessionHandler from "~/server/internal/session";
import clientHandler from "~~/server/internal/clients/handler";
import sessionHandler from "~~/server/internal/session";
export default defineEventHandler(async (h3) => {
const user = await sessionHandler.getSession(h3);
@ -12,19 +12,19 @@ export default defineEventHandler(async (h3) => {
if (!client)
throw createError({
statusCode: 400,
statusMessage: "Invalid or expired client ID.",
message: "Invalid or expired client ID.",
});
if (client.userId != user.userId)
throw createError({
statusCode: 403,
statusMessage: "Not allowed to authorize this client.",
message: "Not allowed to authorize this client.",
});
if (!client.peer)
throw createError({
statusCode: 500,
statusMessage: "No client listening for authorization.",
message: "No client listening for authorization.",
});
const token = await clientHandler.generateAuthToken(clientId);

View File

@ -1,5 +1,5 @@
import type { FetchError } from "ofetch";
import clientHandler from "~/server/internal/clients/handler";
import clientHandler from "~~/server/internal/clients/handler";
export default defineWebSocketHandler({
async open(peer) {
@ -9,14 +9,14 @@ export default defineWebSocketHandler({
if (!code)
throw createError({
statusCode: 400,
statusMessage: "Code required in Authorization header.",
message: "Code required in Authorization header.",
});
await clientHandler.connectCodeListener(code, peer);
} catch (e) {
peer.send(
JSON.stringify({
type: "error",
value: (e as FetchError)?.statusMessage,
value: (e as FetchError)?.message,
}),
);
peer.close();

View File

@ -1,5 +1,5 @@
import clientHandler from "~/server/internal/clients/handler";
import { useCertificateAuthority } from "~/server/plugins/ca";
import clientHandler from "~~/server/internal/clients/handler";
import { useCertificateAuthority } from "~~/server/plugins/ca";
export default defineEventHandler(async (h3) => {
const body = await readBody(h3);
@ -8,24 +8,24 @@ export default defineEventHandler(async (h3) => {
if (!clientId || !token)
throw createError({
statusCode: 400,
statusMessage: "Missing token or client ID from body",
message: "Missing token or client ID from body",
});
const metadata = await clientHandler.fetchClient(clientId);
if (!metadata)
throw createError({
statusCode: 403,
statusMessage: "Invalid client ID",
message: "Invalid client ID",
});
if (!metadata.authToken || !metadata.userId)
throw createError({
statusCode: 400,
statusMessage: "Un-authorized client ID",
message: "Un-authorized client ID",
});
if (metadata.authToken !== token)
throw createError({
statusCode: 403,
statusMessage: "Invalid token",
message: "Invalid token",
});
const certificateAuthority = useCertificateAuthority();

View File

@ -1,5 +1,5 @@
import clientHandler from "~/server/internal/clients/handler";
import sessionHandler from "~/server/internal/session";
import clientHandler from "~~/server/internal/clients/handler";
import sessionHandler from "~~/server/internal/session";
export default defineEventHandler(async (h3) => {
const user = await sessionHandler.getSession(h3);
@ -10,20 +10,20 @@ export default defineEventHandler(async (h3) => {
if (!providedClientId)
throw createError({
statusCode: 400,
statusMessage: "Provide client ID in request params as 'id'",
message: "Provide client ID in request params as 'id'",
});
const client = await clientHandler.fetchClient(providedClientId);
if (!client)
throw createError({
statusCode: 404,
statusMessage: "Request not found.",
message: "Request not found.",
});
if (client.userId && user.userId !== client.userId)
throw createError({
statusCode: 400,
statusMessage: "Client already claimed.",
message: "Client already claimed.",
});
await clientHandler.attachUserId(providedClientId, user.userId);

View File

@ -1,20 +1,20 @@
import { type } from "arktype";
import { readDropValidatedBody, throwingArktype } from "~/server/arktype";
import type { ClientCapabilities } from "~~/prisma/client/enums";
import { readDropValidatedBody, throwingArktype } from "~~/server/arktype";
import type {
CapabilityConfiguration,
InternalClientCapability,
} from "~/server/internal/clients/capabilities";
} from "~~/server/internal/clients/capabilities";
import capabilityManager, {
validCapabilities,
} from "~/server/internal/clients/capabilities";
import clientHandler, { AuthMode } from "~/server/internal/clients/handler";
import { parsePlatform } from "~/server/internal/utils/parseplatform";
} from "~~/server/internal/clients/capabilities";
import clientHandler, { AuthModes } from "~~/server/internal/clients/handler";
import { parsePlatform } from "~~/server/internal/utils/parseplatform";
const ClientAuthInitiate = type({
name: "string",
platform: "string",
capabilities: "object",
mode: type.valueOf(AuthMode).default(AuthMode.Callback),
mode: type.enumerated(...AuthModes).default("callback"),
}).configure(throwingArktype);
export default defineEventHandler(async (h3) => {
@ -28,11 +28,11 @@ export default defineEventHandler(async (h3) => {
if (!platform)
throw createError({
statusCode: 400,
statusMessage: "Invalid or unsupported platform",
message: "Invalid or unsupported platform",
});
const capabilityIterable = Object.entries(capabilities) as Array<
[InternalClientCapability, object]
[ClientCapabilities, object]
>;
if (
capabilityIterable.length > 0 &&
@ -42,7 +42,7 @@ export default defineEventHandler(async (h3) => {
)
throw createError({
statusCode: 400,
statusMessage: "Invalid capabilities.",
message: "Invalid capabilities.",
});
if (
@ -57,7 +57,7 @@ export default defineEventHandler(async (h3) => {
)
throw createError({
statusCode: 400,
statusMessage: "Invalid capability configuration.",
message: "Invalid capability configuration.",
});
const result = await clientHandler.initiate({

View File

@ -1,49 +1,32 @@
import type { InternalClientCapability } from "~/server/internal/clients/capabilities";
import capabilityManager, {
validCapabilities,
} from "~/server/internal/clients/capabilities";
import { defineClientEventHandler } from "~/server/internal/clients/event-handler";
import notificationSystem from "~/server/internal/notifications";
import { type } from "arktype";
import { ClientCapabilities } from "~~/prisma/client/enums";
import { readDropValidatedBody, throwingArktype } from "~~/server/arktype";
import capabilityManager from "~~/server/internal/clients/capabilities";
import { defineClientEventHandler } from "~~/server/internal/clients/event-handler";
import notificationSystem from "~~/server/internal/notifications";
const SetCapability = type({
capability: type.enumerated(...Object.values(ClientCapabilities)),
configuration: "object"
}).configure(throwingArktype);
export default defineClientEventHandler(
async (h3, { clientId, fetchClient, fetchUser }) => {
const body = await readBody(h3);
const rawCapability = body.capability;
const configuration = body.configuration;
if (!rawCapability || typeof rawCapability !== "string")
throw createError({
statusCode: 400,
statusMessage: "capability must be a string",
});
if (!configuration || typeof configuration !== "object")
throw createError({
statusCode: 400,
statusMessage: "configuration must be an object",
});
const capability = rawCapability as InternalClientCapability;
if (!validCapabilities.includes(capability))
throw createError({
statusCode: 400,
statusMessage: "Invalid capability.",
});
const body = await readDropValidatedBody(h3, SetCapability);
const isValid = await capabilityManager.validateCapabilityConfiguration(
capability,
configuration,
body.capability,
body.configuration,
);
if (!isValid)
throw createError({
statusCode: 400,
statusMessage: "Invalid capability configuration.",
message: "Invalid capability configuration.",
});
await capabilityManager.upsertClientCapability(
capability,
configuration,
body.capability,
body.configuration,
clientId,
);
@ -51,9 +34,9 @@ export default defineClientEventHandler(
const user = await fetchUser();
await notificationSystem.push(user.id, {
nonce: `capability-${clientId}-${capability}`,
title: `"${client.name}" can now access ${capability}`,
description: `A device called "${client.name}" now has access to your ${capability}.`,
nonce: `capability-${clientId}-${body.capability}`,
title: `"${client.name}" can now access ${body.capability}`,
description: `A device called "${client.name}" now has access to your ${body.capability}.`,
actions: ["Review|/account/devices"],
acls: ["user:clients:read"],
});

View File

@ -1,7 +1,7 @@
import cacheHandler from "~/server/internal/cache";
import { defineClientEventHandler } from "~/server/internal/clients/event-handler";
import prisma from "~/server/internal/db/database";
import libraryManager from "~/server/internal/library";
import cacheHandler from "~~/server/internal/cache";
import { defineClientEventHandler } from "~~/server/internal/clients/event-handler";
import prisma from "~~/server/internal/db/database";
import libraryManager from "~~/server/internal/library";
const chunkSize = 1024 * 1024 * 64;
@ -20,7 +20,7 @@ export default defineClientEventHandler(async (h3) => {
if (!gameId || !versionName || !filename || Number.isNaN(chunkIndex))
throw createError({
statusCode: 400,
statusMessage: "Invalid chunk arguments",
message: "Invalid chunk arguments",
});
let game = await gameLookupCache.getItem(gameId);
@ -35,7 +35,7 @@ export default defineClientEventHandler(async (h3) => {
},
});
if (!game || !game.libraryId)
throw createError({ statusCode: 400, statusMessage: "Invalid game ID" });
throw createError({ statusCode: 400, message: "Invalid game ID" });
await gameLookupCache.setItem(gameId, game);
}
@ -43,7 +43,7 @@ export default defineClientEventHandler(async (h3) => {
if (!game.libraryId)
throw createError({
statusCode: 500,
statusMessage: "Somehow, we got here.",
message: "Somehow, we got here.",
});
const peek = await libraryManager.peekFile(
@ -53,7 +53,7 @@ export default defineClientEventHandler(async (h3) => {
filename,
);
if (!peek)
throw createError({ status: 400, statusMessage: "Failed to peek file" });
throw createError({ status: 400, message: "Failed to peek file" });
const start = chunkIndex * chunkSize;
const end = Math.min((chunkIndex + 1) * chunkSize, peek.size);
@ -63,7 +63,7 @@ export default defineClientEventHandler(async (h3) => {
if (start >= end)
throw createError({
statusCode: 400,
statusMessage: "Invalid chunk index",
message: "Invalid chunk index",
});
const gameReadStream = await libraryManager.readFile(
@ -76,7 +76,7 @@ export default defineClientEventHandler(async (h3) => {
if (!gameReadStream)
throw createError({
statusCode: 400,
statusMessage: "Failed to create stream",
message: "Failed to create stream",
});
return sendStream(h3, gameReadStream);

View File

@ -1,5 +1,5 @@
import { defineClientEventHandler } from "~/server/internal/clients/event-handler";
import userLibraryManager from "~/server/internal/userlibrary";
import { defineClientEventHandler } from "~~/server/internal/clients/event-handler";
import userLibraryManager from "~~/server/internal/userlibrary";
export default defineClientEventHandler(async (h3, { fetchUser }) => {
const user = await fetchUser();
@ -8,13 +8,13 @@ export default defineClientEventHandler(async (h3, { fetchUser }) => {
if (!id)
throw createError({
statusCode: 400,
statusMessage: "ID required in route params",
message: "ID required in route params",
});
const body = await readBody(h3);
const gameId = body.id;
if (!gameId)
throw createError({ statusCode: 400, statusMessage: "Game ID required" });
throw createError({ statusCode: 400, message: "Game ID required" });
const successful = await userLibraryManager.collectionRemove(
gameId,
@ -24,7 +24,7 @@ export default defineClientEventHandler(async (h3, { fetchUser }) => {
if (!successful)
throw createError({
statusCode: 404,
statusMessage: "Collection not found",
message: "Collection not found",
});
return {};
});

View File

@ -1,5 +1,5 @@
import { defineClientEventHandler } from "~/server/internal/clients/event-handler";
import userLibraryManager from "~/server/internal/userlibrary";
import { defineClientEventHandler } from "~~/server/internal/clients/event-handler";
import userLibraryManager from "~~/server/internal/userlibrary";
export default defineClientEventHandler(async (h3, { fetchUser }) => {
const user = await fetchUser();
@ -8,13 +8,13 @@ export default defineClientEventHandler(async (h3, { fetchUser }) => {
if (!id)
throw createError({
statusCode: 400,
statusMessage: "ID required in route params",
message: "ID required in route params",
});
const body = await readBody(h3);
const gameId = body.id;
if (!gameId)
throw createError({ statusCode: 400, statusMessage: "Game ID required" });
throw createError({ statusCode: 400, message: "Game ID required" });
return await userLibraryManager.collectionAdd(gameId, id, user.id);
});

View File

@ -1,5 +1,5 @@
import { defineClientEventHandler } from "~/server/internal/clients/event-handler";
import userLibraryManager from "~/server/internal/userlibrary";
import { defineClientEventHandler } from "~~/server/internal/clients/event-handler";
import userLibraryManager from "~~/server/internal/userlibrary";
export default defineClientEventHandler(async (h3, { fetchUser }) => {
const user = await fetchUser();
@ -8,7 +8,7 @@ export default defineClientEventHandler(async (h3, { fetchUser }) => {
if (!id)
throw createError({
statusCode: 400,
statusMessage: "ID required in route params",
message: "ID required in route params",
});
// Verify collection exists and user owns it
@ -17,13 +17,13 @@ export default defineClientEventHandler(async (h3, { fetchUser }) => {
if (!collection)
throw createError({
statusCode: 404,
statusMessage: "Collection not found",
message: "Collection not found",
});
if (collection.userId !== user.id)
throw createError({
statusCode: 403,
statusMessage: "Not authorized to delete this collection",
message: "Not authorized to delete this collection",
});
await userLibraryManager.deleteCollection(id);

View File

@ -1,5 +1,5 @@
import { defineClientEventHandler } from "~/server/internal/clients/event-handler";
import userLibraryManager from "~/server/internal/userlibrary";
import { defineClientEventHandler } from "~~/server/internal/clients/event-handler";
import userLibraryManager from "~~/server/internal/userlibrary";
export default defineClientEventHandler(async (h3, { fetchUser }) => {
const user = await fetchUser();
@ -8,7 +8,7 @@ export default defineClientEventHandler(async (h3, { fetchUser }) => {
if (!id)
throw createError({
statusCode: 400,
statusMessage: "ID required in route params",
message: "ID required in route params",
});
// Fetch specific collection
@ -17,14 +17,14 @@ export default defineClientEventHandler(async (h3, { fetchUser }) => {
if (!collection)
throw createError({
statusCode: 404,
statusMessage: "Collection not found",
message: "Collection not found",
});
// Verify user owns this collection
if (collection.userId !== user.id)
throw createError({
statusCode: 403,
statusMessage: "Not authorized to access this collection",
message: "Not authorized to access this collection",
});
return collection;

View File

@ -1,5 +1,5 @@
import { defineClientEventHandler } from "~/server/internal/clients/event-handler";
import userLibraryManager from "~/server/internal/userlibrary";
import { defineClientEventHandler } from "~~/server/internal/clients/event-handler";
import userLibraryManager from "~~/server/internal/userlibrary";
export default defineClientEventHandler(async (h3, { fetchUser }) => {
const user = await fetchUser();
@ -8,7 +8,7 @@ export default defineClientEventHandler(async (h3, { fetchUser }) => {
const gameId = body.id;
if (!gameId)
throw createError({ statusCode: 400, statusMessage: "Game ID required" });
throw createError({ statusCode: 400, message: "Game ID required" });
await userLibraryManager.libraryRemove(gameId, user.id);
return {};

View File

@ -1,5 +1,5 @@
import { defineClientEventHandler } from "~/server/internal/clients/event-handler";
import userLibraryManager from "~/server/internal/userlibrary";
import { defineClientEventHandler } from "~~/server/internal/clients/event-handler";
import userLibraryManager from "~~/server/internal/userlibrary";
export default defineClientEventHandler(async (h3, { fetchUser }) => {
const user = await fetchUser();
@ -7,7 +7,7 @@ export default defineClientEventHandler(async (h3, { fetchUser }) => {
const body = await readBody(h3);
const gameId = body.id;
if (!gameId)
throw createError({ statusCode: 400, statusMessage: "Game ID required" });
throw createError({ statusCode: 400, message: "Game ID required" });
// Add the game to the default collection
await userLibraryManager.libraryAdd(gameId, user.id);

View File

@ -1,5 +1,5 @@
import { defineClientEventHandler } from "~/server/internal/clients/event-handler";
import userLibraryManager from "~/server/internal/userlibrary";
import { defineClientEventHandler } from "~~/server/internal/clients/event-handler";
import userLibraryManager from "~~/server/internal/userlibrary";
export default defineClientEventHandler(async (h3, { fetchUser }) => {
const user = await fetchUser();

View File

@ -1,5 +1,5 @@
import { defineClientEventHandler } from "~/server/internal/clients/event-handler";
import userLibraryManager from "~/server/internal/userlibrary";
import { defineClientEventHandler } from "~~/server/internal/clients/event-handler";
import userLibraryManager from "~~/server/internal/userlibrary";
export default defineClientEventHandler(async (h3, { fetchUser }) => {
const user = await fetchUser();

View File

@ -1,5 +1,5 @@
import { defineClientEventHandler } from "~/server/internal/clients/event-handler";
import userLibraryManager from "~/server/internal/userlibrary";
import { defineClientEventHandler } from "~~/server/internal/clients/event-handler";
import userLibraryManager from "~~/server/internal/userlibrary";
export default defineClientEventHandler(async (h3, { fetchUser }) => {
const user = await fetchUser();
@ -8,7 +8,7 @@ export default defineClientEventHandler(async (h3, { fetchUser }) => {
const name = body.name;
if (!name)
throw createError({ statusCode: 400, statusMessage: "Requires name" });
throw createError({ statusCode: 400, message: "Requires name" });
// Create the collection using the manager
const newCollection = await userLibraryManager.collectionCreate(

View File

@ -1,10 +1,10 @@
import { defineClientEventHandler } from "~/server/internal/clients/event-handler";
import prisma from "~/server/internal/db/database";
import { defineClientEventHandler } from "~~/server/internal/clients/event-handler";
import prisma from "~~/server/internal/db/database";
export default defineClientEventHandler(async (h3) => {
const id = getRouterParam(h3, "id");
if (!id)
throw createError({ statusCode: 400, statusMessage: "No ID in route" });
throw createError({ statusCode: 400, message: "No ID in route" });
const game = await prisma.game.findUnique({
where: {
@ -12,7 +12,7 @@ export default defineClientEventHandler(async (h3) => {
},
});
if (!game)
throw createError({ statusCode: 404, statusMessage: "Game not found" });
throw createError({ statusCode: 404, message: "Game not found" });
return game;
});

View File

@ -1,21 +1,20 @@
import { defineClientEventHandler } from "~/server/internal/clients/event-handler";
import manifestGenerator from "~/server/internal/downloads/manifest";
import { defineClientEventHandler } from "~~/server/internal/clients/event-handler";
import manifestGenerator from "~~/server/internal/downloads/manifest";
export default defineClientEventHandler(async (h3) => {
const query = getQuery(h3);
const id = query.id?.toString();
const version = query.version?.toString();
if (!id || !version)
if (!id)
throw createError({
statusCode: 400,
statusMessage: "Missing id or version in query",
message: "Missing version id in query",
});
const manifest = await manifestGenerator.generateManifest(id, version);
const manifest = await manifestGenerator.generateManifest(id);
if (!manifest)
throw createError({
statusCode: 400,
statusMessage: "Invalid game or version, or no versions added.",
message: "Invalid game or version, or no versions added.",
});
return manifest;
});

View File

@ -1,6 +1,6 @@
import { defineClientEventHandler } from "~/server/internal/clients/event-handler";
import prisma from "~/server/internal/db/database";
import libraryManager from "~/server/internal/library";
import { defineClientEventHandler } from "~~/server/internal/clients/event-handler";
import prisma from "~~/server/internal/db/database";
import libraryManager from "~~/server/internal/library";
export default defineClientEventHandler(async (h3) => {
const query = getQuery(h3);
@ -9,22 +9,19 @@ export default defineClientEventHandler(async (h3) => {
if (!id || !version)
throw createError({
statusCode: 400,
statusMessage: "Missing id or version in query",
message: "Missing id or version in query",
});
const gameVersion = await prisma.gameVersion.findUnique({
where: {
gameId_versionName: {
gameId: id,
versionName: version,
},
versionId: id,
},
});
if (!gameVersion)
throw createError({
statusCode: 404,
statusMessage: "Game version not found",
message: "Game version not found",
});
return {

View File

@ -1,5 +1,5 @@
import { defineClientEventHandler } from "~/server/internal/clients/event-handler";
import prisma from "~/server/internal/db/database";
import { defineClientEventHandler } from "~~/server/internal/clients/event-handler";
import prisma from "~~/server/internal/db/database";
export default defineClientEventHandler(async (h3) => {
const query = getQuery(h3);
@ -7,31 +7,21 @@ export default defineClientEventHandler(async (h3) => {
if (!id)
throw createError({
statusCode: 400,
statusMessage: "No ID in request query",
message: "No ID in request query",
});
const versions = await prisma.gameVersion.findMany({
const versions = await prisma.version.findMany({
where: {
gameId: id,
hidden: false,
},
orderBy: {
versionIndex: "desc", // Latest one first
},
include: {
gameVersions: true,
},
});
const mappedVersions = versions
.map((version) => {
if (!version.dropletManifest) return undefined;
const newVersion = { ...version, dropletManifest: undefined };
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore idk why we delete an undefined object
delete newVersion.dropletManifest;
return {
...newVersion,
};
})
.filter((e) => e);
return mappedVersions;
return versions;
});

View File

@ -1,5 +1,5 @@
import { defineClientEventHandler } from "~/server/internal/clients/event-handler";
import newsManager from "~/server/internal/news";
import { defineClientEventHandler } from "~~/server/internal/clients/event-handler";
import newsManager from "~~/server/internal/news";
export default defineClientEventHandler(async (h3) => {
const id = h3.context.params?.id;

View File

@ -1,5 +1,5 @@
import { defineClientEventHandler } from "~/server/internal/clients/event-handler";
import newsManager from "~/server/internal/news";
import { defineClientEventHandler } from "~~/server/internal/clients/event-handler";
import newsManager from "~~/server/internal/news";
export default defineClientEventHandler(async (h3) => {
const query = getQuery(h3);
@ -7,13 +7,13 @@ export default defineClientEventHandler(async (h3) => {
const orderBy = query.order as "asc" | "desc";
if (orderBy) {
if (typeof orderBy !== "string" || !["asc", "desc"].includes(orderBy))
throw createError({ statusCode: 400, statusMessage: "Invalid order" });
throw createError({ statusCode: 400, message: "Invalid order" });
}
const tags = query.tags as string[] | undefined;
if (tags) {
if (typeof tags !== "object" || !Array.isArray(tags))
throw createError({ statusCode: 400, statusMessage: "Invalid tags" });
throw createError({ statusCode: 400, message: "Invalid tags" });
}
const options = {

View File

@ -1,15 +1,15 @@
import { defineClientEventHandler } from "~/server/internal/clients/event-handler";
import objectHandler from "~/server/internal/objects";
import { defineClientEventHandler } from "~~/server/internal/clients/event-handler";
import objectHandler from "~~/server/internal/objects";
export default defineClientEventHandler(async (h3, utils) => {
const id = getRouterParam(h3, "id");
if (!id) throw createError({ statusCode: 400, statusMessage: "Invalid ID" });
if (!id) throw createError({ statusCode: 400, message: "Invalid ID" });
const user = await utils.fetchUser();
const object = await objectHandler.fetchWithPermissions(id, user.id);
if (!object)
throw createError({ statusCode: 404, statusMessage: "Object not found" });
throw createError({ statusCode: 404, message: "Object not found" });
setHeader(h3, "Content-Type", object.mime);
return object.data;

View File

@ -1,6 +1,6 @@
import { ClientCapabilities } from "~/prisma/client/enums";
import { defineClientEventHandler } from "~/server/internal/clients/event-handler";
import prisma from "~/server/internal/db/database";
import { ClientCapabilities } from "~~/prisma/client/enums";
import { defineClientEventHandler } from "~~/server/internal/clients/event-handler";
import prisma from "~~/server/internal/db/database";
export default defineClientEventHandler(
async (h3, { fetchClient, fetchUser }) => {
@ -8,27 +8,27 @@ export default defineClientEventHandler(
if (!client.capabilities.includes(ClientCapabilities.CloudSaves))
throw createError({
statusCode: 403,
statusMessage: "Capability not allowed.",
message: "Capability not allowed.",
});
const user = await fetchUser();
const gameId = getRouterParam(h3, "gameid");
if (!gameId)
throw createError({
statusCode: 400,
statusMessage: "No gameID in route params",
message: "No gameID in route params",
});
const slotIndexString = getRouterParam(h3, "slotindex");
if (!slotIndexString)
throw createError({
statusCode: 400,
statusMessage: "No slotIndex in route params",
message: "No slotIndex in route params",
});
const slotIndex = parseInt(slotIndexString);
if (Number.isNaN(slotIndex))
throw createError({
statusCode: 400,
statusMessage: "Invalid slotIndex",
message: "Invalid slotIndex",
});
const game = await prisma.game.findUnique({
@ -36,7 +36,7 @@ export default defineClientEventHandler(
select: { id: true },
});
if (!game)
throw createError({ statusCode: 400, statusMessage: "Invalid game ID" });
throw createError({ statusCode: 400, message: "Invalid game ID" });
const save = await prisma.saveSlot.delete({
where: {
@ -48,6 +48,6 @@ export default defineClientEventHandler(
},
});
if (!save)
throw createError({ statusCode: 404, statusMessage: "Save not found" });
throw createError({ statusCode: 404, message: "Save not found" });
},
);

View File

@ -1,6 +1,6 @@
import { ClientCapabilities } from "~/prisma/client/enums";
import { defineClientEventHandler } from "~/server/internal/clients/event-handler";
import prisma from "~/server/internal/db/database";
import { ClientCapabilities } from "~~/prisma/client/enums";
import { defineClientEventHandler } from "~~/server/internal/clients/event-handler";
import prisma from "~~/server/internal/db/database";
export default defineClientEventHandler(
async (h3, { fetchClient, fetchUser }) => {
@ -8,27 +8,27 @@ export default defineClientEventHandler(
if (!client.capabilities.includes(ClientCapabilities.CloudSaves))
throw createError({
statusCode: 403,
statusMessage: "Capability not allowed.",
message: "Capability not allowed.",
});
const user = await fetchUser();
const gameId = getRouterParam(h3, "gameid");
if (!gameId)
throw createError({
statusCode: 400,
statusMessage: "No gameID in route params",
message: "No gameID in route params",
});
const slotIndexString = getRouterParam(h3, "slotindex");
if (!slotIndexString)
throw createError({
statusCode: 400,
statusMessage: "No slotIndex in route params",
message: "No slotIndex in route params",
});
const slotIndex = parseInt(slotIndexString);
if (Number.isNaN(slotIndex))
throw createError({
statusCode: 400,
statusMessage: "Invalid slotIndex",
message: "Invalid slotIndex",
});
const game = await prisma.game.findUnique({
@ -36,7 +36,7 @@ export default defineClientEventHandler(
select: { id: true },
});
if (!game)
throw createError({ statusCode: 400, statusMessage: "Invalid game ID" });
throw createError({ statusCode: 400, message: "Invalid game ID" });
const save = await prisma.saveSlot.findUnique({
where: {
@ -48,7 +48,7 @@ export default defineClientEventHandler(
},
});
if (!save)
throw createError({ statusCode: 404, statusMessage: "Save not found" });
throw createError({ statusCode: 404, message: "Save not found" });
return save;
},

View File

@ -1,7 +1,7 @@
import { ClientCapabilities } from "~/prisma/client/enums";
import { defineClientEventHandler } from "~/server/internal/clients/event-handler";
import prisma from "~/server/internal/db/database";
import saveManager from "~/server/internal/saves";
import { ClientCapabilities } from "~~/prisma/client/enums";
import { defineClientEventHandler } from "~~/server/internal/clients/event-handler";
import prisma from "~~/server/internal/db/database";
import saveManager from "~~/server/internal/saves";
export default defineClientEventHandler(
async (h3, { fetchClient, fetchUser }) => {
@ -9,27 +9,27 @@ export default defineClientEventHandler(
if (!client.capabilities.includes(ClientCapabilities.CloudSaves))
throw createError({
statusCode: 403,
statusMessage: "Capability not allowed.",
message: "Capability not allowed.",
});
const user = await fetchUser();
const gameId = getRouterParam(h3, "gameid");
if (!gameId)
throw createError({
statusCode: 400,
statusMessage: "No gameID in route params",
message: "No gameID in route params",
});
const slotIndexString = getRouterParam(h3, "slotindex");
if (!slotIndexString)
throw createError({
statusCode: 400,
statusMessage: "No slotIndex in route params",
message: "No slotIndex in route params",
});
const slotIndex = parseInt(slotIndexString);
if (Number.isNaN(slotIndex))
throw createError({
statusCode: 400,
statusMessage: "Invalid slotIndex",
message: "Invalid slotIndex",
});
const game = await prisma.game.findUnique({
@ -37,7 +37,7 @@ export default defineClientEventHandler(
select: { id: true },
});
if (!game)
throw createError({ statusCode: 400, statusMessage: "Invalid game ID" });
throw createError({ statusCode: 400, message: "Invalid game ID" });
await saveManager.pushSave(
gameId,

View File

@ -1,6 +1,6 @@
import { ClientCapabilities } from "~/prisma/client/enums";
import { defineClientEventHandler } from "~/server/internal/clients/event-handler";
import prisma from "~/server/internal/db/database";
import { ClientCapabilities } from "~~/prisma/client/enums";
import { defineClientEventHandler } from "~~/server/internal/clients/event-handler";
import prisma from "~~/server/internal/db/database";
export default defineClientEventHandler(
async (h3, { fetchClient, fetchUser }) => {
@ -8,14 +8,14 @@ export default defineClientEventHandler(
if (!client.capabilities.includes(ClientCapabilities.CloudSaves))
throw createError({
statusCode: 403,
statusMessage: "Capability not allowed.",
message: "Capability not allowed.",
});
const user = await fetchUser();
const gameId = getRouterParam(h3, "gameid");
if (!gameId)
throw createError({
statusCode: 400,
statusMessage: "No gameID in route params",
message: "No gameID in route params",
});
const game = await prisma.game.findUnique({
@ -23,7 +23,7 @@ export default defineClientEventHandler(
select: { id: true },
});
if (!game)
throw createError({ statusCode: 400, statusMessage: "Invalid game ID" });
throw createError({ statusCode: 400, message: "Invalid game ID" });
const saves = await prisma.saveSlot.findMany({
where: {

View File

@ -1,7 +1,7 @@
import { ClientCapabilities } from "~/prisma/client/enums";
import { defineClientEventHandler } from "~/server/internal/clients/event-handler";
import { applicationSettings } from "~/server/internal/config/application-configuration";
import prisma from "~/server/internal/db/database";
import { ClientCapabilities } from "~~/prisma/client/enums";
import { defineClientEventHandler } from "~~/server/internal/clients/event-handler";
import { applicationSettings } from "~~/server/internal/config/application-configuration";
import prisma from "~~/server/internal/db/database";
export default defineClientEventHandler(
async (h3, { fetchClient, fetchUser }) => {
@ -9,14 +9,14 @@ export default defineClientEventHandler(
if (!client.capabilities.includes(ClientCapabilities.CloudSaves))
throw createError({
statusCode: 403,
statusMessage: "Capability not allowed.",
message: "Capability not allowed.",
});
const user = await fetchUser();
const gameId = getRouterParam(h3, "gameid");
if (!gameId)
throw createError({
statusCode: 400,
statusMessage: "No gameID in route params",
message: "No gameID in route params",
});
const game = await prisma.game.findUnique({
@ -24,7 +24,7 @@ export default defineClientEventHandler(
select: { id: true },
});
if (!game)
throw createError({ statusCode: 400, statusMessage: "Invalid game ID" });
throw createError({ statusCode: 400, message: "Invalid game ID" });
const saves = await prisma.saveSlot.findMany({
where: {
@ -40,7 +40,7 @@ export default defineClientEventHandler(
if (saves.length + 1 > limit)
throw createError({
statusCode: 400,
statusMessage: "Out of save slots",
message: "Out of save slots",
});
let firstIndex = 0;

View File

@ -1,6 +1,6 @@
import { ClientCapabilities } from "~/prisma/client/enums";
import { defineClientEventHandler } from "~/server/internal/clients/event-handler";
import prisma from "~/server/internal/db/database";
import { ClientCapabilities } from "~~/prisma/client/enums";
import { defineClientEventHandler } from "~~/server/internal/clients/event-handler";
import prisma from "~~/server/internal/db/database";
export default defineClientEventHandler(
async (h3, { fetchClient, fetchUser }) => {
@ -8,7 +8,7 @@ export default defineClientEventHandler(
if (!client.capabilities.includes(ClientCapabilities.CloudSaves))
throw createError({
statusCode: 403,
statusMessage: "Capability not allowed.",
message: "Capability not allowed.",
});
const user = await fetchUser();

View File

@ -1,13 +1,13 @@
import { ClientCapabilities } from "~/prisma/client/enums";
import { defineClientEventHandler } from "~/server/internal/clients/event-handler";
import { applicationSettings } from "~/server/internal/config/application-configuration";
import { ClientCapabilities } from "~~/prisma/client/enums";
import { defineClientEventHandler } from "~~/server/internal/clients/event-handler";
import { applicationSettings } from "~~/server/internal/config/application-configuration";
export default defineClientEventHandler(async (_h3, { fetchClient }) => {
const client = await fetchClient();
if (!client.capabilities.includes(ClientCapabilities.CloudSaves))
throw createError({
statusCode: 403,
statusMessage: "Capability not allowed.",
message: "Capability not allowed.",
});
const slotLimit = await applicationSettings.get("saveSlotCountLimit");

View File

@ -1,4 +1,4 @@
import { defineClientEventHandler } from "~/server/internal/clients/event-handler";
import { defineClientEventHandler } from "~~/server/internal/clients/event-handler";
export default defineClientEventHandler(async (h3, { fetchUser }) => {
const user = await fetchUser();

View File

@ -1,5 +1,5 @@
import { defineClientEventHandler } from "~/server/internal/clients/event-handler";
import userLibraryManager from "~/server/internal/userlibrary";
import { defineClientEventHandler } from "~~/server/internal/clients/event-handler";
import userLibraryManager from "~~/server/internal/userlibrary";
export default defineClientEventHandler(async (_h3, { fetchUser }) => {
const user = await fetchUser();

View File

@ -1,8 +1,8 @@
import { APITokenMode } from "~/prisma/client/enums";
import { APITokenMode } from "~~/prisma/client/enums";
import { DateTime } from "luxon";
import type { UserACL } from "~/server/internal/acls";
import { defineClientEventHandler } from "~/server/internal/clients/event-handler";
import prisma from "~/server/internal/db/database";
import type { UserACL } from "~~/server/internal/acls";
import { defineClientEventHandler } from "~~/server/internal/clients/event-handler";
import prisma from "~~/server/internal/db/database";
export default defineClientEventHandler(
async (h3, { fetchUser, fetchClient, clientId }) => {