Depot API & v4 (#298)

* feat: nginx + torrential basics & services system

* fix: lint + i18n

* fix: update torrential to remove openssl

* feat: add torrential to Docker build

* feat: move to self hosted runner

* fix: move off self-hosted runner

* fix: update nginx.conf

* feat: torrential cache invalidation

* fix: update torrential for cache invalidation

* feat: integrity check task

* fix: lint

* feat: move to version ids

* fix: client fixes and client-side checks

* feat: new depot apis and version id fixes

* feat: update torrential

* feat: droplet bump and remove unsafe update functions

* fix: lint

* feat: v4 featureset: emulators, multi-launch commands

* fix: lint

* fix: mobile ui for game editor

* feat: launch options

* fix: lint

* fix: remove axios, use $fetch

* feat: metadata and task api improvements

* feat: task actions

* fix: slight styling issue

* feat: fix style and lints

* feat: totp backend routes

* feat: oidc groups

* fix: update drop-base

* feat: creation of passkeys & totp

* feat: totp signin

* feat: webauthn mfa/signin

* feat: launch selecting ui

* fix: manually running tasks

* feat: update add company game modal to use new SelectorGame

* feat: executor selector

* fix(docker): update rust to rust nightly for torrential build (#305)

* feat: new version ui

* feat: move package lookup to build time to allow for deno dev

* fix: lint

* feat: localisation cleanup

* feat: apply localisation cleanup

* feat: potential i18n refactor logic

* feat: remove args from commands

* fix: lint

* fix: lockfile

---------

Co-authored-by: Aden Lindsay <140392385+AdenMGB@users.noreply.github.com>
This commit is contained in:
DecDuck
2026-01-13 15:32:39 +11:00
committed by GitHub
parent 8ef983304c
commit 63ac2b8ffc
190 changed files with 5848 additions and 2309 deletions

View File

@@ -0,0 +1,28 @@
/*
Warnings:
- The primary key for the `GameVersion` table will be changed. If it partially fails, the table could be left without primary key constraint.
- You are about to drop the column `versionName` on the `GameVersion` table. All the data in the column will be lost.
- Made the column `libraryId` on table `Game` required. This step will fail if there are existing NULL values in that column.
- The required column `versionId` was added to the `GameVersion` table with a prisma-level default value. This is not possible if the table is not empty. Please add this column as optional, then populate it before making it required.
- Added the required column `versionPath` to the `GameVersion` table without a default value. This is not possible if the table is not empty.
*/
-- DropIndex
DROP INDEX "GameTag_name_idx";
-- AlterTable
ALTER TABLE "Game" ALTER COLUMN "libraryId" SET NOT NULL;
DELETE FROM "GameVersion";
-- AlterTable
ALTER TABLE "GameVersion" DROP CONSTRAINT "GameVersion_pkey",
DROP COLUMN "versionName",
ADD COLUMN "displayName" TEXT,
ADD COLUMN "versionId" TEXT NOT NULL,
ADD COLUMN "versionPath" TEXT NOT NULL,
ADD CONSTRAINT "GameVersion_pkey" PRIMARY KEY ("gameId", "versionId");
-- CreateIndex
CREATE INDEX "GameTag_name_idx" ON "GameTag" USING GIST ("name" gist_trgm_ops(siglen=32));

View File

@@ -0,0 +1,14 @@
-- DropIndex
DROP INDEX "GameTag_name_idx";
-- CreateTable
CREATE TABLE "Depot" (
"id" TEXT NOT NULL,
"endpoint" TEXT NOT NULL,
"key" TEXT NOT NULL,
CONSTRAINT "Depot_pkey" PRIMARY KEY ("id")
);
-- CreateIndex
CREATE INDEX "GameTag_name_idx" ON "GameTag" USING GIST ("name" gist_trgm_ops(siglen=32));

View File

@@ -0,0 +1,60 @@
/*
Warnings:
- You are about to drop the column `launchArgs` on the `GameVersion` table. All the data in the column will be lost.
- You are about to drop the column `launchCommand` on the `GameVersion` table. All the data in the column will be lost.
- You are about to drop the column `platform` on the `GameVersion` table. All the data in the column will be lost.
- You are about to drop the column `setupArgs` on the `GameVersion` table. All the data in the column will be lost.
- You are about to drop the column `setupCommand` on the `GameVersion` table. All the data in the column will be lost.
- You are about to drop the column `umuIdOverride` on the `GameVersion` table. All the data in the column will be lost.
- Added the required column `setupId` to the `GameVersion` table without a default value. This is not possible if the table is not empty.
*/
-- DropIndex
DROP INDEX "GameTag_name_idx";
-- AlterTable
ALTER TABLE "GameVersion" DROP COLUMN "launchArgs",
DROP COLUMN "launchCommand",
DROP COLUMN "platform",
DROP COLUMN "setupArgs",
DROP COLUMN "setupCommand",
DROP COLUMN "umuIdOverride",
ADD COLUMN "setupId" TEXT NOT NULL;
-- CreateTable
CREATE TABLE "SetupConfiguration" (
"setupId" TEXT NOT NULL,
"command" TEXT NOT NULL,
"args" TEXT[],
"platform" "Platform" NOT NULL,
CONSTRAINT "SetupConfiguration_pkey" PRIMARY KEY ("setupId")
);
-- CreateTable
CREATE TABLE "LaunchConfiguration" (
"launchId" TEXT NOT NULL,
"name" TEXT NOT NULL,
"command" TEXT NOT NULL,
"args" TEXT[],
"platform" "Platform" NOT NULL,
"executorId" TEXT,
"umuIdOverride" TEXT,
"gameId" TEXT NOT NULL,
"versionId" TEXT NOT NULL,
CONSTRAINT "LaunchConfiguration_pkey" PRIMARY KEY ("launchId")
);
-- CreateIndex
CREATE INDEX "GameTag_name_idx" ON "GameTag" USING GIST ("name" gist_trgm_ops(siglen=32));
-- AddForeignKey
ALTER TABLE "GameVersion" ADD CONSTRAINT "GameVersion_setupId_fkey" FOREIGN KEY ("setupId") REFERENCES "SetupConfiguration"("setupId") ON DELETE RESTRICT ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "LaunchConfiguration" ADD CONSTRAINT "LaunchConfiguration_executorId_fkey" FOREIGN KEY ("executorId") REFERENCES "LaunchConfiguration"("launchId") ON DELETE SET NULL ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "LaunchConfiguration" ADD CONSTRAINT "LaunchConfiguration_gameId_versionId_fkey" FOREIGN KEY ("gameId", "versionId") REFERENCES "GameVersion"("gameId", "versionId") ON DELETE RESTRICT ON UPDATE CASCADE;

View File

@@ -0,0 +1,14 @@
-- DropForeignKey
ALTER TABLE "GameVersion" DROP CONSTRAINT "GameVersion_setupId_fkey";
-- DropIndex
DROP INDEX "GameTag_name_idx";
-- AlterTable
ALTER TABLE "GameVersion" ALTER COLUMN "setupId" DROP NOT NULL;
-- CreateIndex
CREATE INDEX "GameTag_name_idx" ON "GameTag" USING GIST ("name" gist_trgm_ops(siglen=32));
-- AddForeignKey
ALTER TABLE "GameVersion" ADD CONSTRAINT "GameVersion_setupId_fkey" FOREIGN KEY ("setupId") REFERENCES "SetupConfiguration"("setupId") ON DELETE SET NULL ON UPDATE CASCADE;

View File

@@ -0,0 +1,26 @@
/*
Warnings:
- You are about to drop the column `setupId` on the `GameVersion` table. All the data in the column will be lost.
- Added the required column `gameId` to the `SetupConfiguration` table without a default value. This is not possible if the table is not empty.
- Added the required column `versionId` to the `SetupConfiguration` table without a default value. This is not possible if the table is not empty.
*/
-- DropForeignKey
ALTER TABLE "GameVersion" DROP CONSTRAINT "GameVersion_setupId_fkey";
-- DropIndex
DROP INDEX "GameTag_name_idx";
-- AlterTable
ALTER TABLE "GameVersion" DROP COLUMN "setupId";
-- AlterTable
ALTER TABLE "SetupConfiguration" ADD COLUMN "gameId" TEXT NOT NULL,
ADD COLUMN "versionId" TEXT NOT NULL;
-- CreateIndex
CREATE INDEX "GameTag_name_idx" ON "GameTag" USING GIST ("name" gist_trgm_ops(siglen=32));
-- AddForeignKey
ALTER TABLE "SetupConfiguration" ADD CONSTRAINT "SetupConfiguration_gameId_versionId_fkey" FOREIGN KEY ("gameId", "versionId") REFERENCES "GameVersion"("gameId", "versionId") ON DELETE RESTRICT ON UPDATE CASCADE;

View File

@@ -0,0 +1,23 @@
-- DropForeignKey
ALTER TABLE "LaunchConfiguration" DROP CONSTRAINT "LaunchConfiguration_executorId_fkey";
-- DropForeignKey
ALTER TABLE "LaunchConfiguration" DROP CONSTRAINT "LaunchConfiguration_gameId_versionId_fkey";
-- DropForeignKey
ALTER TABLE "SetupConfiguration" DROP CONSTRAINT "SetupConfiguration_gameId_versionId_fkey";
-- DropIndex
DROP INDEX "GameTag_name_idx";
-- CreateIndex
CREATE INDEX "GameTag_name_idx" ON "GameTag" USING GIST ("name" gist_trgm_ops(siglen=32));
-- AddForeignKey
ALTER TABLE "SetupConfiguration" ADD CONSTRAINT "SetupConfiguration_gameId_versionId_fkey" FOREIGN KEY ("gameId", "versionId") REFERENCES "GameVersion"("gameId", "versionId") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "LaunchConfiguration" ADD CONSTRAINT "LaunchConfiguration_executorId_fkey" FOREIGN KEY ("executorId") REFERENCES "LaunchConfiguration"("launchId") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "LaunchConfiguration" ADD CONSTRAINT "LaunchConfiguration_gameId_versionId_fkey" FOREIGN KEY ("gameId", "versionId") REFERENCES "GameVersion"("gameId", "versionId") ON DELETE CASCADE ON UPDATE CASCADE;

View File

@@ -0,0 +1,8 @@
-- DropIndex
DROP INDEX "GameTag_name_idx";
-- AlterTable
ALTER TABLE "Task" ADD COLUMN "actions" TEXT[];
-- CreateIndex
CREATE INDEX "GameTag_name_idx" ON "GameTag" USING GIST ("name" gist_trgm_ops(siglen=32));

View File

@@ -0,0 +1,22 @@
-- CreateEnum
CREATE TYPE "MFAMec" AS ENUM ('WebAuthn', 'TOTP');
-- DropIndex
DROP INDEX "GameTag_name_idx";
-- CreateTable
CREATE TABLE "LinkedMFAMec" (
"userId" TEXT NOT NULL,
"mec" "MFAMec" NOT NULL,
"enabled" BOOLEAN NOT NULL DEFAULT true,
"version" INTEGER NOT NULL DEFAULT 1,
"credentials" JSONB NOT NULL,
CONSTRAINT "LinkedMFAMec_pkey" PRIMARY KEY ("userId","mec")
);
-- CreateIndex
CREATE INDEX "GameTag_name_idx" ON "GameTag" USING GIST ("name" gist_trgm_ops(siglen=32));
-- AddForeignKey
ALTER TABLE "LinkedMFAMec" ADD CONSTRAINT "LinkedMFAMec_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;

View File

@@ -0,0 +1,8 @@
-- DropIndex
DROP INDEX "GameTag_name_idx";
-- AlterTable
ALTER TABLE "Session" ALTER COLUMN "userId" DROP NOT NULL;
-- CreateIndex
CREATE INDEX "GameTag_name_idx" ON "GameTag" USING GIST ("name" gist_trgm_ops(siglen=32));

View File

@@ -0,0 +1,8 @@
-- DropIndex
DROP INDEX "GameTag_name_idx";
-- CreateIndex
CREATE INDEX "Game_mName_idx" ON "Game" USING GIST ("mName" gist_trgm_ops(siglen=32));
-- CreateIndex
CREATE INDEX "GameTag_name_idx" ON "GameTag" USING GIST ("name" gist_trgm_ops(siglen=32));

View File

@@ -0,0 +1,11 @@
-- DropIndex
DROP INDEX "Game_mName_idx";
-- DropIndex
DROP INDEX "GameTag_name_idx";
-- CreateIndex
CREATE INDEX "Game_mName_idx" ON "Game" USING GIST ("mName" gist_trgm_ops(siglen=32));
-- CreateIndex
CREATE INDEX "GameTag_name_idx" ON "GameTag" USING GIST ("name" gist_trgm_ops(siglen=32));

View File

@@ -0,0 +1,24 @@
/*
Warnings:
- You are about to drop the column `args` on the `LaunchConfiguration` table. All the data in the column will be lost.
- You are about to drop the column `args` on the `SetupConfiguration` table. All the data in the column will be lost.
*/
-- DropIndex
DROP INDEX "Game_mName_idx";
-- DropIndex
DROP INDEX "GameTag_name_idx";
-- AlterTable
ALTER TABLE "LaunchConfiguration" DROP COLUMN "args";
-- AlterTable
ALTER TABLE "SetupConfiguration" DROP COLUMN "args";
-- CreateIndex
CREATE INDEX "Game_mName_idx" ON "Game" USING GIST ("mName" gist_trgm_ops(siglen=32));
-- CreateIndex
CREATE INDEX "GameTag_name_idx" ON "GameTag" USING GIST ("name" gist_trgm_ops(siglen=32));

View File

@@ -30,3 +30,9 @@ model Library {
games Game[]
}
model Depot {
id String @id @default(uuid())
endpoint String
key String @default(uuid())
}

View File

@@ -11,7 +11,25 @@ model LinkedAuthMec {
version Int @default(1)
credentials Json
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
user User @relation(fields: [userId], references: [id], onDelete: Cascade, onUpdate: Cascade)
@@id([userId, mec])
}
enum MFAMec {
WebAuthn
TOTP
}
model LinkedMFAMec {
userId String
mec MFAMec
enabled Boolean @default(true)
version Int @default(1)
credentials Json
user User @relation(fields: [userId], references: [id], onDelete: Cascade, onUpdate: Cascade)
@@id([userId, mec])
}
@@ -63,7 +81,7 @@ model Session {
token String @id
expiresAt DateTime
userId String
userId String?
user User? @relation(fields: [userId], references: [id], onDelete: Cascade)
data Json // misc extra data

View File

@@ -17,7 +17,8 @@ model Game {
// Any field prefixed with m is filled in from metadata
// Acts as a cache so we can search and filter it
mName String // Name of game
mName String // Name of game
mShortDescription String // Short description
mDescription String // Supports markdown
mReleased DateTime // When the game was released
@@ -36,8 +37,8 @@ model Game {
// These fields will not be optional in the next version
// Any game without a library ID will be assigned one at startup, based on the defaults
libraryId String?
library Library? @relation(fields: [libraryId], references: [id], onDelete: Cascade, onUpdate: Cascade)
libraryId String
library Library @relation(fields: [libraryId], references: [id], onDelete: Cascade, onUpdate: Cascade)
libraryPath String
collections CollectionEntry[]
@@ -51,18 +52,18 @@ model Game {
@@unique([metadataSource, metadataId], name: "metadataKey")
@@unique([libraryId, libraryPath], name: "libraryKey")
@@index([mName(ops: raw("gist_trgm_ops(siglen=32)"))], type: Gist)
}
model GameTag {
id String @id @default(uuid())
name String @unique
games Game[]
games Game[]
@@index([name(ops: raw("gist_trgm_ops(siglen=32)"))], type: Gist)
}
model GameRating {
id String @id @default(uuid())
@@ -83,28 +84,60 @@ model GameRating {
// A particular set of files that relate to the version
model GameVersion {
gameId String
game Game @relation(fields: [gameId], references: [id], onDelete: Cascade)
versionName String // Sub directory for the game files
gameId String
game Game @relation(fields: [gameId], references: [id], onDelete: Cascade)
versionId String @default(uuid())
displayName String?
versionPath String
created DateTime @default(now())
platform Platform
launches LaunchConfiguration[]
setups SetupConfiguration[]
launchCommand String @default("") // Command to run to start. Platform-specific. Windows games on Linux will wrap this command in Proton/Wine
launchArgs String[]
setupCommand String @default("") // Command to setup game (dependencies and such)
setupArgs String[]
onlySetup Boolean @default(false)
umuIdOverride String?
onlySetup Boolean @default(false)
dropletManifest Json // Results from droplet
versionIndex Int
delta Boolean @default(false)
@@id([gameId, versionName])
@@id([gameId, versionId])
}
model SetupConfiguration {
setupId String @id @default(uuid())
command String
platform Platform
gameId String
versionId String
gameVersion GameVersion @relation(fields: [gameId, versionId], references: [gameId, versionId], onDelete: Cascade, onUpdate: Cascade)
}
model LaunchConfiguration {
launchId String @id @default(uuid())
name String
command String
platform Platform
// For emulation targets
executorId String?
executor LaunchConfiguration? @relation(fields: [executorId], references: [launchId], name: "executor", onDelete: Cascade, onUpdate: Cascade)
umuIdOverride String?
gameId String
versionId String
gameVersion GameVersion @relation(fields: [gameId, versionId], references: [gameId, versionId], onDelete: Cascade, onUpdate: Cascade)
executions LaunchConfiguration[] @relation("executor")
}
// A save slot for a game

View File

@@ -11,6 +11,8 @@ model Task {
progress Float
log String[]
actions String[]
acls String[]
@@id([id, started])

View File

@@ -8,7 +8,9 @@ model User {
displayName String
profilePictureObjectId String // Object
authMecs LinkedAuthMec[]
authMecs LinkedAuthMec[]
mfas LinkedMFAMec[]
clients Client[]
notifications Notification[]
collections Collection[]