diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..0a0c0bd --- /dev/null +++ b/.gitattributes @@ -0,0 +1,6 @@ +*.ico filter=lfs diff=lfs merge=lfs -text +*.png filter=lfs diff=lfs merge=lfs -text +*.jpg filter=lfs diff=lfs merge=lfs -text +*.gif filter=lfs diff=lfs merge=lfs -text +*.webp filter=lfs diff=lfs merge=lfs -text +*.svg filter=lfs diff=lfs merge=lfs -text diff --git a/.github/screenshots/7s0842oAC9.png b/.github/screenshots/7s0842oAC9.png new file mode 100644 index 0000000..4c55f38 --- /dev/null +++ b/.github/screenshots/7s0842oAC9.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:df932e6c24b3d70cb7ad7d7ec3ea240341e4be80cee328eee41d35c36e1937c6 +size 1556410 diff --git a/.github/screenshots/8jipsHiLST.png b/.github/screenshots/8jipsHiLST.png new file mode 100644 index 0000000..7abc387 --- /dev/null +++ b/.github/screenshots/8jipsHiLST.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1e2db97ea3b385ac01fb6ec4ac89197dfd4fc6c727639c9493336ddd23be60c7 +size 1003321 diff --git a/.github/screenshots/EWPHmIBEE5.png b/.github/screenshots/EWPHmIBEE5.png new file mode 100644 index 0000000..6fd9f40 --- /dev/null +++ b/.github/screenshots/EWPHmIBEE5.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a03b0cd56b78f51f8bc4c304b8b14fa611748b9efa192ef26283e732beff90c1 +size 643600 diff --git a/.github/screenshots/FHMzJjGOs6.png b/.github/screenshots/FHMzJjGOs6.png new file mode 100644 index 0000000..d9dbbf8 --- /dev/null +++ b/.github/screenshots/FHMzJjGOs6.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:96eef8c330ed6739ed2a595fa2170c8f5b5cb7a9cec9b4ad58af51a63eb22b4f +size 1325789 diff --git a/.github/screenshots/J5BHVZBh7k.png b/.github/screenshots/J5BHVZBh7k.png new file mode 100644 index 0000000..dc1bf97 --- /dev/null +++ b/.github/screenshots/J5BHVZBh7k.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c92749fe4122c719f09a9397345f1a06df4aedee8f50855601be3ec25e85ad3c +size 50175 diff --git a/.forgejo/workflows/build.yml b/.github/workflows/build.yml similarity index 86% rename from .forgejo/workflows/build.yml rename to .github/workflows/build.yml index 5e3da10..0a064c8 100644 --- a/.forgejo/workflows/build.yml +++ b/.github/workflows/build.yml @@ -22,14 +22,14 @@ jobs: run: | # Download and install via official script curl -fsSL https://bun.sh/install | bash - + # Manually add Bun to the PATH for subsequent steps echo "BUN_INSTALL=$HOME/.bun" >> $GITHUB_ENV echo "$HOME/.bun/bin" >> $GITHUB_PATH - + # Force execution permissions just in case chmod +x $HOME/.bun/bin/bun - + # Verify it works immediately $HOME/.bun/bin/bun --version @@ -37,12 +37,11 @@ jobs: run: bun install --frozen-lockfile - name: Build Canary - run: bun run build:canary + run: bun run package:auto-prod - name: Upload Artifact uses: actions/upload-artifact@v3 with: name: canary-build - # Replace 'dist' with your actual output folder (e.g., 'out' or 'build') - path: artifacts/ - retention-days: 7 \ No newline at end of file + path: build/ + retention-days: 7 diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..fea718a --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,38 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + + { + "type": "bun", + "internalConsoleOptions": "neverOpen", + "request": "launch", + "name": "Debug File", + "program": "./src/bun/index.ts", + "cwd": "${workspaceFolder}", + "stopOnEntry": false, + "watchMode": true + }, + { + "type": "bun", + "internalConsoleOptions": "neverOpen", + "request": "launch", + "name": "Run File", + "program": "./src/bun/index.ts", + "cwd": "${workspaceFolder}", + "noDebug": true, + "watchMode": false + }, + { + "type": "bun", + "internalConsoleOptions": "neverOpen", + "request": "attach", + "name": "Attach Bun", + "url": "ws://127.0.0.1:9229/nvnfnsqez8s", + "localRoot": "${workspaceFolder}", + "stopOnEntry": false + } + ] +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json index 8e45f31..411cba2 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,9 +1,27 @@ +{ "files.readonlyInclude": { - "**/routeTree.gen.ts": true + "**/*.gen.ts": true, + "src/mainview/gen/*": true, }, "files.watcherExclude": { - "**/routeTree.gen.ts": true + "**/*.gen.ts": true, + "src/mainview/gen/*": true, }, "search.exclude": { - "**/routeTree.gen.ts": true - } \ No newline at end of file + "**/*.gen.ts": true, + "src/mainview/gen/*": true, + + }, + "editor.formatOnSave": true, + "[typescriptreact]": { + "editor.defaultFormatter": "vscode.typescript-language-features", + "editor.formatOnSave": true + }, + "[typescript]": { + "editor.defaultFormatter": "vscode.typescript-language-features", + "editor.formatOnSave": true + }, + "cSpell.words": [ + "elysia" + ] +} \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000..c6d29c6 --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,18 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "label": "Run Act", + "type": "shell", + "command": "act", + "args": ["--artifact-server-path", "artifacts", "-W", ".github/workflows/build.yml"], + "options": { + "env": { + "PATH": "${env:PATH}", + "ACTIONS_RUNTIME_TOKEN": "foo" + }, + }, + "problemMatcher": [] + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md index 2ddd3b3..101f462 100644 --- a/README.md +++ b/README.md @@ -1,18 +1,58 @@ # Gameflow Deck -## Getting Started +A Cross-Platform Retro gaming frontend designed for handheld and controllers. +Focused on building a simple user experience and intuitive UI. + +> [!WARNING] +> This app is actively in development, it doesn't have most of its critical features implemented yet. + +## Features + +- **Cross Platform**: Can run on multiple platforms. Built with web technologies and bun backend. +- **[Romm](https://github.com/rommapp/romm) Support**: Has integration with romm. +- **Lightweight**: It uses the existing system browser to launch the front end, so no need to include a whole web browser. + - On Windows it first uses webview2 then your browser + - On linux it uses WebKitGTK or a browser even from flatpak + - Not tested on Mac yet +- **Steam Deck Support**: Extensively tested with the steam deck. It can use flatpak installed browsers. +- **Great for Controllers**: The UI is inspired by the switch and works great with joysticks and dpads. + +## Screenshots + + + + + + + +## Development 1. Install dependencies: + ```bash bun install ``` 2. Run in development mode: + ```bash + # Use 'bun run dev:hmr' for hot reload bun run dev ``` 3. Build for production: ```bash - bun run build - ``` \ No newline at end of file + bun run package:auto-prod + ``` + Builds will go in `/builds/`. + +### Tech Stack + +- [Bun](https://bun.com/) for the backend +- [React](https://react.dev/) for the frontend +- [tailwindcss](https://tailwindcss.com/) for styling +- [daisyUI](https://daisyui.com/) for base theme +- [Vite](https://vite.dev/) for building the frontend +- [Tanstack](https://tanstack.com/) router and query for navigation and data +- [elysia](https://elysiajs.com/) for the APIs +- [webview](https://github.com/webview/webview) for launching existing system webviews instead of full browser if possible. diff --git a/bun.lock b/bun.lock index dc9cb5f..1f8eac5 100644 --- a/bun.lock +++ b/bun.lock @@ -5,30 +5,56 @@ "": { "name": "electrobun-hello-world", "dependencies": { - "@tanstack/react-router": "^1.154.10", - "@tanstack/router-plugin": "^1.154.10", - "classnames": "^2.5.1", - "electrobun": "latest", - "gamepad.css": "^0.0.4", - "lucide-react": "^0.562.0", - "react": "^19.2.3", - "react-dom": "^19.2.3", + "@auth/core": "^0.34.3", + "@elysiajs/cors": "^1.4.1", + "@elysiajs/eden": "^1.4.6", + "@elysiajs/static": "^1.4.7", + "@rcompat/webview": "^0.18.0", + "conf": "^15.0.2", + "elysia": "^1.4.22", + "pathe": "^2.0.3", + "zod": "^4.3.6", }, "devDependencies": { + "@hey-api/openapi-ts": "^0.91.0", + "@noriginmedia/norigin-spatial-navigation": "^2.3.0", "@tailwindcss/vite": "^4.1.18", - "@tanstack/react-router-devtools": "^1.154.10", + "@tanstack/react-query": "^5.90.20", + "@tanstack/react-query-devtools": "^5.91.3", + "@tanstack/react-router": "^1.157.16", + "@tanstack/react-router-devtools": "^1.154.12", + "@tanstack/react-router-ssr-query": "^1.157.17", + "@tanstack/router-plugin": "^1.157.16", "@types/bun": "latest", "@types/react": "^19.2.9", "@types/react-dom": "^19.2.3", "@vitejs/plugin-react": "^5.1.2", + "animate.css": "^4.1.1", + "babel-plugin-react-compiler": "^1.0.0", + "classnames": "^2.5.1", "concurrently": "^9.2.1", + "cross-env": "^10.1.0", + "daisyui": "^5.5.14", + "lucide-react": "^0.563.0", + "pretty-bytes": "^7.1.0", + "react": "^19.2.4", + "react-dom": "^19.2.4", + "react-error-boundary": "^6.1.0", + "react-hot-toast": "^2.6.0", + "tailwind-merge": "^3.4.0", "tailwindcss": "^4.1.18", + "tailwindcss-animate": "^1.0.7", "typescript": "^5.9.3", + "usehooks-ts": "^3.1.1", "vite": "^7.3.1", + "vite-plugin-svg-icons-ng": "^1.5.2", + "vite-static-assets-plugin": "^1.2.2", }, }, }, "packages": { + "@auth/core": ["@auth/core@0.34.3", "", { "dependencies": { "@panva/hkdf": "^1.1.1", "@types/cookie": "0.6.0", "cookie": "0.6.0", "jose": "^5.1.3", "oauth4webapi": "^2.10.4", "preact": "10.11.3", "preact-render-to-string": "5.2.3" }, "peerDependencies": { "@simplewebauthn/browser": "^9.0.1", "@simplewebauthn/server": "^9.0.2", "nodemailer": "^7" }, "optionalPeers": ["@simplewebauthn/browser", "@simplewebauthn/server", "nodemailer"] }, "sha512-jMjY/S0doZnWYNV90x0jmU3B+UcrsfGYnukxYrRbj0CVvGI/MX3JbHsxSrx2d4mbnXaUsqJmAcDfoQWA6r0lOw=="], + "@babel/code-frame": ["@babel/code-frame@7.28.6", "", { "dependencies": { "@babel/helper-validator-identifier": "^7.28.5", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" } }, "sha512-JYgintcMjRiCvS8mMECzaEn+m3PfoQiyqukOMCCVQtoJGYJw8j/8LBJEiqkHLkfwCcs74E3pbAUFNg7d9VNJ+Q=="], "@babel/compat-data": ["@babel/compat-data@7.28.6", "", {}, "sha512-2lfu57JtzctfIrcGMz992hyLlByuzgIk58+hhGCxjKZ3rWI82NnVLjXcaTqkI2NvlcvOskZaiZ5kjUALo3Lpxg=="], @@ -71,6 +97,16 @@ "@babel/types": ["@babel/types@7.28.6", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.28.5" } }, "sha512-0ZrskXVEHSWIqZM/sQZ4EV3jZJXRkio/WCxaqKZP1g//CEWEPSfeZFcms4XeKBCHU0ZKnIkdJeU/kF+eRp5lBg=="], + "@borewit/text-codec": ["@borewit/text-codec@0.2.1", "", {}, "sha512-k7vvKPbf7J2fZ5klGRD9AeKfUvojuZIQ3BT5u7Jfv+puwXkUBUT5PVyMDfJZpy30CBDXGMgw7fguK/lpOMBvgw=="], + + "@elysiajs/cors": ["@elysiajs/cors@1.4.1", "", { "peerDependencies": { "elysia": ">= 1.4.0" } }, "sha512-lQfad+F3r4mNwsxRKbXyJB8Jg43oAOXjRwn7sKUL6bcOW3KjUqUimTS+woNpO97efpzjtDE0tEjGk9DTw8lqTQ=="], + + "@elysiajs/eden": ["@elysiajs/eden@1.4.6", "", { "peerDependencies": { "elysia": ">=1.4.19" } }, "sha512-Tsa4NwXEWg/u73vWiYZQ3L5/ecgZSxqiEjYwpS+4qBKXeTZqZKl2hcgHJSVBL+InEDMi35Xugct7qyAXE5oM4Q=="], + + "@elysiajs/static": ["@elysiajs/static@1.4.7", "", { "peerDependencies": { "elysia": ">= 1.4.0" } }, "sha512-Go4kIXZ0G3iWfkAld07HmLglqIDMVXdyRKBQK/sVEjtpDdjHNb+rUIje73aDTWpZYg4PEVHUpi9v4AlNEwrQug=="], + + "@epic-web/invariant": ["@epic-web/invariant@1.0.0", "", {}, "sha512-lrTPqgvfFQtR/eY/qkIzp98OGdNJu0m5ji3q/nJI8v3SXkRKEnWiOxMmbvcSoAIzv/cGiuvRy57k4suKQSAdwA=="], + "@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.27.2", "", { "os": "aix", "cpu": "ppc64" }, "sha512-GZMB+a0mOMZs4MpDbj8RJp4cw+w1WV5NYD6xzgvzUJ5Ek2jerwfO2eADyI6ExDSUED+1X8aMbegahsJi+8mgpw=="], "@esbuild/android-arm": ["@esbuild/android-arm@0.27.2", "", { "os": "android", "cpu": "arm" }, "sha512-DVNI8jlPa7Ujbr1yjU2PfUSRtAUZPG9I1RwW4F4xFB1Imiu2on0ADiI/c3td+KmDtVKNbi+nffGDQMfcIMkwIA=="], @@ -123,7 +159,19 @@ "@esbuild/win32-x64": ["@esbuild/win32-x64@0.27.2", "", { "os": "win32", "cpu": "x64" }, "sha512-sRdU18mcKf7F+YgheI/zGf5alZatMUTKj/jNS6l744f9u3WFu4v7twcUI9vu4mknF4Y9aDlblIie0IM+5xxaqQ=="], - "@isaacs/cliui": ["@isaacs/cliui@8.0.2", "", { "dependencies": { "string-width": "^5.1.2", "string-width-cjs": "npm:string-width@^4.2.0", "strip-ansi": "^7.0.1", "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", "wrap-ansi": "^8.1.0", "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" } }, "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA=="], + "@hey-api/codegen-core": ["@hey-api/codegen-core@0.6.0", "", { "dependencies": { "@hey-api/types": "0.1.3", "ansi-colors": "4.1.3", "c12": "3.3.3", "color-support": "1.1.3" }, "peerDependencies": { "typescript": ">=5.5.3" } }, "sha512-O6TRP3g1188gdpZC9yio64KkvWD97QpLjaCFnwTgykTZtzQXZbkyw+lYPVfZ7Ee+m7eLau1/jEJmQcUY9G0sLw=="], + + "@hey-api/json-schema-ref-parser": ["@hey-api/json-schema-ref-parser@1.2.3", "", { "dependencies": { "@jsdevtools/ono": "^7.1.3", "@types/json-schema": "^7.0.15", "js-yaml": "^4.1.1", "lodash": "^4.17.21" } }, "sha512-gRbyyTjzpFVNmbD+Upn3w4dWV+bCXGJbff3A7leDO/tfNxSz1xIb6Ad/5UKtvEW9kDt/2Uyc3XkFZ6rpafvbfQ=="], + + "@hey-api/openapi-ts": ["@hey-api/openapi-ts@0.91.0", "", { "dependencies": { "@hey-api/codegen-core": "0.6.0", "@hey-api/json-schema-ref-parser": "1.2.3", "@hey-api/shared": "0.1.0", "@hey-api/types": "0.1.3", "ansi-colors": "4.1.3", "color-support": "1.1.3", "commander": "14.0.2" }, "peerDependencies": { "typescript": ">=5.5.3" }, "bin": { "openapi-ts": "bin/run.js" } }, "sha512-AHkd982HsPz1XpqRm59URwJyJqTzyzzC30EAp07b/0M9KojjneCPxm8FnvFnXLRTMyKgcOymMsYXuLzJ9mpMHA=="], + + "@hey-api/shared": ["@hey-api/shared@0.1.0", "", { "dependencies": { "@hey-api/codegen-core": "0.6.0", "@hey-api/json-schema-ref-parser": "1.2.3", "@hey-api/types": "0.1.3", "ansi-colors": "4.1.3", "cross-spawn": "7.0.6", "open": "11.0.0", "semver": "7.7.3" }, "peerDependencies": { "typescript": ">=5.5.3" } }, "sha512-qEDMSBWEEWxcBU5XHacjCCnFOVq1YWPPR3owURVep60I7ejfSG5OINxM4eF+p3KJGMcZduzzfq9pd1grStHZBg=="], + + "@hey-api/types": ["@hey-api/types@0.1.3", "", { "peerDependencies": { "typescript": ">=5.5.3" } }, "sha512-mZaiPOWH761yD4GjDQvtjS2ZYLu5o5pI1TVSvV/u7cmbybv51/FVtinFBeaE1kFQCKZ8OQpn2ezjLBJrKsGATw=="], + + "@isaacs/balanced-match": ["@isaacs/balanced-match@4.0.1", "", {}, "sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ=="], + + "@isaacs/brace-expansion": ["@isaacs/brace-expansion@5.0.0", "", { "dependencies": { "@isaacs/balanced-match": "^4.0.1" } }, "sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA=="], "@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.13", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA=="], @@ -135,9 +183,27 @@ "@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.31", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw=="], - "@oneidentity/zstd-js": ["@oneidentity/zstd-js@1.0.3", "", { "dependencies": { "@types/emscripten": "^1.39.4" } }, "sha512-Jm6sawqxLzBrjC4sg2BeXToa33yPzUmq20CKsehKY2++D/gHb/oSwVjNgT+RH4vys+r8FynrgcNzGwhZWMLzfQ=="], + "@jsdevtools/ono": ["@jsdevtools/ono@7.1.3", "", {}, "sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg=="], - "@pkgjs/parseargs": ["@pkgjs/parseargs@0.11.0", "", {}, "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg=="], + "@nodelib/fs.scandir": ["@nodelib/fs.scandir@2.1.5", "", { "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" } }, "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g=="], + + "@nodelib/fs.stat": ["@nodelib/fs.stat@2.0.5", "", {}, "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A=="], + + "@nodelib/fs.walk": ["@nodelib/fs.walk@1.2.8", "", { "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" } }, "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg=="], + + "@noriginmedia/norigin-spatial-navigation": ["@noriginmedia/norigin-spatial-navigation@2.3.0", "", { "dependencies": { "lodash": "^4.17.21" }, "peerDependencies": { "react": ">=16.8.0" } }, "sha512-gR//N45NnKz1h0/AVknkfg7QnNATETdgXUUD3EKPxuQPyhk7NhsphODzRamyvjYaxsU6VbY/szcUlzBWWBkNMw=="], + + "@panva/hkdf": ["@panva/hkdf@1.2.1", "", {}, "sha512-6oclG6Y3PiDFcoyk8srjLfVKyMfVCKJ27JwNPViuXziFpmdz+MZnZN/aKY0JGXgYuO/VghU0jcOAZgWXZ1Dmrw=="], + + "@rcompat/assert": ["@rcompat/assert@0.6.0", "", { "dependencies": { "@rcompat/is": "^0.4.0", "@rcompat/type": "^0.9.0" } }, "sha512-V8YrttJqBNsLo9DQkXGpPt09LqfUGvwA30q8Tf+uukEhE6Nraw4jM4Nq0c5yKQF0IWv1eSoPUJyCO4W4neS5IA=="], + + "@rcompat/dict": ["@rcompat/dict@0.3.1", "", { "dependencies": { "@rcompat/assert": "^0.6.0", "@rcompat/is": "^0.4.2" } }, "sha512-eWZ4ACk0DpT8PS+umVlp/TmFfWAD0yqkGxfvvtfL/9fqPEh1bcCFtGMySCwmTGx/FU8sPnxwnSiZGZmN36gTBQ=="], + + "@rcompat/is": ["@rcompat/is@0.4.3", "", {}, "sha512-IRTVOUhgmRjnlEyZ76wmxPNS46TnUTp7m54mbNgMFDdTTNpjnmpuWw0DcBSUuh4p66fqP/7t9M5tmMUiYAFVzQ=="], + + "@rcompat/type": ["@rcompat/type@0.9.0", "", {}, "sha512-oMGchVrm9K98rXigdfHY98P223iHKfmCxH2GfD+vcwHdWqC3YyuJxlfhd6AeLFNkuBz+0G27GD5qm9g03IPIrA=="], + + "@rcompat/webview": ["@rcompat/webview@0.18.0", "", { "dependencies": { "@rcompat/dict": "^0.3.0" } }, "sha512-bJaDPFPSgXg4dhKVbohDgUZZcP+wsO49RRDaWj01L4klxyiMa6EUCv7RIoOgYnwNt+WRDZ0dJbH8AuSmhHdcPA=="], "@rolldown/pluginutils": ["@rolldown/pluginutils@1.0.0-beta.53", "", {}, "sha512-vENRlFU4YbrwVqNDZ7fLvy+JR1CRkyr01jhSiDpE1u6py3OMzQfztQU2jxykW3ALNxO4kSlqIDeYyD0Y9RcQeQ=="], @@ -191,6 +257,8 @@ "@rollup/rollup-win32-x64-msvc": ["@rollup/rollup-win32-x64-msvc@4.56.0", "", { "os": "win32", "cpu": "x64" }, "sha512-H8AE9Ur/t0+1VXujj90w0HrSOuv0Nq9r1vSZF2t5km20NTfosQsGGUXDaKdQZzwuLts7IyL1fYT4hM95TI9c4g=="], + "@sinclair/typebox": ["@sinclair/typebox@0.34.48", "", {}, "sha512-kKJTNuK3AQOrgjjotVxMrCn1sUJwM76wMszfq1kdU4uYVJjvEWuFQ6HgvLt4Xz3fSmZlTOxJ/Ie13KnIcWQXFA=="], + "@tailwindcss/node": ["@tailwindcss/node@4.1.18", "", { "dependencies": { "@jridgewell/remapping": "^2.3.4", "enhanced-resolve": "^5.18.3", "jiti": "^2.6.1", "lightningcss": "1.30.2", "magic-string": "^0.30.21", "source-map-js": "^1.2.1", "tailwindcss": "4.1.18" } }, "sha512-DoR7U1P7iYhw16qJ49fgXUlry1t4CpXeErJHnQ44JgTSKMaZUdf17cfn5mHchfJ4KRBZRFA/Coo+MUF5+gOaCQ=="], "@tailwindcss/oxide": ["@tailwindcss/oxide@4.1.18", "", { "optionalDependencies": { "@tailwindcss/oxide-android-arm64": "4.1.18", "@tailwindcss/oxide-darwin-arm64": "4.1.18", "@tailwindcss/oxide-darwin-x64": "4.1.18", "@tailwindcss/oxide-freebsd-x64": "4.1.18", "@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.18", "@tailwindcss/oxide-linux-arm64-gnu": "4.1.18", "@tailwindcss/oxide-linux-arm64-musl": "4.1.18", "@tailwindcss/oxide-linux-x64-gnu": "4.1.18", "@tailwindcss/oxide-linux-x64-musl": "4.1.18", "@tailwindcss/oxide-wasm32-wasi": "4.1.18", "@tailwindcss/oxide-win32-arm64-msvc": "4.1.18", "@tailwindcss/oxide-win32-x64-msvc": "4.1.18" } }, "sha512-EgCR5tTS5bUSKQgzeMClT6iCY3ToqE1y+ZB0AKldj809QXk1Y+3jB0upOYZrn9aGIzPtUsP7sX4QQ4XtjBB95A=="], @@ -221,21 +289,33 @@ "@tailwindcss/vite": ["@tailwindcss/vite@4.1.18", "", { "dependencies": { "@tailwindcss/node": "4.1.18", "@tailwindcss/oxide": "4.1.18", "tailwindcss": "4.1.18" }, "peerDependencies": { "vite": "^5.2.0 || ^6 || ^7" } }, "sha512-jVA+/UpKL1vRLg6Hkao5jldawNmRo7mQYrZtNHMIVpLfLhDml5nMRUo/8MwoX2vNXvnaXNNMedrMfMugAVX1nA=="], - "@tanstack/history": ["@tanstack/history@1.154.7", "", {}, "sha512-YBgwS9qG4rs1ZY/ZrhQtjOH8BG9Qa2wf2AsxT/SnZ4HZJ1DcCEqkoiHH0yH6CYvdDit31X5HokOqQrRSsZEwGA=="], + "@tanstack/history": ["@tanstack/history@1.154.14", "", {}, "sha512-xyIfof8eHBuub1CkBnbKNKQXeRZC4dClhmzePHVOEel4G7lk/dW+TQ16da7CFdeNLv6u6Owf5VoBQxoo6DFTSA=="], - "@tanstack/react-router": ["@tanstack/react-router@1.154.12", "", { "dependencies": { "@tanstack/history": "1.154.7", "@tanstack/react-store": "^0.8.0", "@tanstack/router-core": "1.154.12", "isbot": "^5.1.22", "tiny-invariant": "^1.3.3", "tiny-warning": "^1.0.3" }, "peerDependencies": { "react": ">=18.0.0 || >=19.0.0", "react-dom": ">=18.0.0 || >=19.0.0" } }, "sha512-WiYfC6IYC2HwjkATouJCQlAM5RJ8MViefslfUcZpsbCb+WGQpdpvUY7GPJLEeessSpqgiC2EabRYC2kYVNyMPg=="], + "@tanstack/query-core": ["@tanstack/query-core@5.90.20", "", {}, "sha512-OMD2HLpNouXEfZJWcKeVKUgQ5n+n3A2JFmBaScpNDUqSrQSjiveC7dKMe53uJUg1nDG16ttFPz2xfilz6i2uVg=="], + + "@tanstack/query-devtools": ["@tanstack/query-devtools@5.93.0", "", {}, "sha512-+kpsx1NQnOFTZsw6HAFCW3HkKg0+2cepGtAWXjiiSOJJ1CtQpt72EE2nyZb+AjAbLRPoeRmPJ8MtQd8r8gsPdg=="], + + "@tanstack/react-query": ["@tanstack/react-query@5.90.20", "", { "dependencies": { "@tanstack/query-core": "5.90.20" }, "peerDependencies": { "react": "^18 || ^19" } }, "sha512-vXBxa+qeyveVO7OA0jX1z+DeyCA4JKnThKv411jd5SORpBKgkcVnYKCiBgECvADvniBX7tobwBmg01qq9JmMJw=="], + + "@tanstack/react-query-devtools": ["@tanstack/react-query-devtools@5.91.3", "", { "dependencies": { "@tanstack/query-devtools": "5.93.0" }, "peerDependencies": { "@tanstack/react-query": "^5.90.20", "react": "^18 || ^19" } }, "sha512-nlahjMtd/J1h7IzOOfqeyDh5LNfG0eULwlltPEonYy0QL+nqrBB+nyzJfULV+moL7sZyxc2sHdNJki+vLA9BSA=="], + + "@tanstack/react-router": ["@tanstack/react-router@1.157.16", "", { "dependencies": { "@tanstack/history": "1.154.14", "@tanstack/react-store": "^0.8.0", "@tanstack/router-core": "1.157.16", "isbot": "^5.1.22", "tiny-invariant": "^1.3.3", "tiny-warning": "^1.0.3" }, "peerDependencies": { "react": ">=18.0.0 || >=19.0.0", "react-dom": ">=18.0.0 || >=19.0.0" } }, "sha512-xwFQa7S7dhBhm3aJYwU79cITEYgAKSrcL6wokaROIvl2JyIeazn8jueWqUPJzFjv+QF6Q8euKRlKUEyb5q2ymg=="], "@tanstack/react-router-devtools": ["@tanstack/react-router-devtools@1.154.12", "", { "dependencies": { "@tanstack/router-devtools-core": "1.154.12" }, "peerDependencies": { "@tanstack/react-router": "^1.154.12", "@tanstack/router-core": "^1.154.12", "react": ">=18.0.0 || >=19.0.0", "react-dom": ">=18.0.0 || >=19.0.0" }, "optionalPeers": ["@tanstack/router-core"] }, "sha512-TcGe7pmeVjk1zD58eMR87GG9OXMx6LDGz5QopmJS4LafvK2hvuaht+eKBnZlCvKLPlXu5juwHT4u+2bYdn6sqQ=="], + "@tanstack/react-router-ssr-query": ["@tanstack/react-router-ssr-query@1.157.17", "", { "dependencies": { "@tanstack/router-ssr-query-core": "1.157.16" }, "peerDependencies": { "@tanstack/query-core": ">=5.90.0", "@tanstack/react-query": ">=5.90.0", "@tanstack/react-router": ">=1.127.0", "react": ">=18.0.0 || >=19.0.0", "react-dom": ">=18.0.0 || >=19.0.0" } }, "sha512-IrLi+cNLOAiTShuwGUi9WCNWXMG4993fnyXnWMC53M64rhUngPRFCAQiA05BavE/d7bifC6WKDTt1ZhC1Pewaw=="], + "@tanstack/react-store": ["@tanstack/react-store@0.8.0", "", { "dependencies": { "@tanstack/store": "0.8.0", "use-sync-external-store": "^1.6.0" }, "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-1vG9beLIuB7q69skxK9r5xiLN3ztzIPfSQSs0GfeqWGO2tGIyInZx0x1COhpx97RKaONSoAb8C3dxacWksm1ow=="], - "@tanstack/router-core": ["@tanstack/router-core@1.154.12", "", { "dependencies": { "@tanstack/history": "1.154.7", "@tanstack/store": "^0.8.0", "cookie-es": "^2.0.0", "seroval": "^1.4.2", "seroval-plugins": "^1.4.2", "tiny-invariant": "^1.3.3", "tiny-warning": "^1.0.3" } }, "sha512-p+TKxkXcLGtCwwW237D8pV4f6ea2K1pzc/e65ljugoTawsA/YR2/gmTSBDTUsSYy6Tmu4mMJmZ0Q4zNkcfCS3g=="], + "@tanstack/router-core": ["@tanstack/router-core@1.157.16", "", { "dependencies": { "@tanstack/history": "1.154.14", "@tanstack/store": "^0.8.0", "cookie-es": "^2.0.0", "seroval": "^1.4.2", "seroval-plugins": "^1.4.2", "tiny-invariant": "^1.3.3", "tiny-warning": "^1.0.3" } }, "sha512-eJuVgM7KZYTTr4uPorbUzUflmljMVcaX2g6VvhITLnHmg9SBx9RAgtQ1HmT+72mzyIbRSlQ1q0fY/m+of/fosA=="], "@tanstack/router-devtools-core": ["@tanstack/router-devtools-core@1.154.12", "", { "dependencies": { "clsx": "^2.1.1", "goober": "^2.1.16", "tiny-invariant": "^1.3.3" }, "peerDependencies": { "@tanstack/router-core": "^1.154.12", "csstype": "^3.0.10" }, "optionalPeers": ["csstype"] }, "sha512-lvnP9cqknvSSkUjqQRVn61TcBhq72hCFFOzMwdFdFPTO8nMEXvYE6ZZJiXtivwcvsKmO6XVFLMXuJr/928gNkw=="], - "@tanstack/router-generator": ["@tanstack/router-generator@1.154.12", "", { "dependencies": { "@tanstack/router-core": "1.154.12", "@tanstack/router-utils": "1.154.7", "@tanstack/virtual-file-routes": "1.154.7", "prettier": "^3.5.0", "recast": "^0.23.11", "source-map": "^0.7.4", "tsx": "^4.19.2", "zod": "^3.24.2" } }, "sha512-cjr3KS3Esnyh05CWl78KgK2Z9kTjeFasZXcSUrh//TzzU72eXQ+dzKppD3kMsjuyRfUxAfdufsR9GDNMMuLk9w=="], + "@tanstack/router-generator": ["@tanstack/router-generator@1.157.16", "", { "dependencies": { "@tanstack/router-core": "1.157.16", "@tanstack/router-utils": "1.154.7", "@tanstack/virtual-file-routes": "1.154.7", "prettier": "^3.5.0", "recast": "^0.23.11", "source-map": "^0.7.4", "tsx": "^4.19.2", "zod": "^3.24.2" } }, "sha512-Ae2M00VTFjjED7glSCi/mMLENRzhEym6NgjoOx7UVNbCC/rLU/5ASDe5VIlDa8QLEqP5Pj088Gi51gjmRuICvQ=="], - "@tanstack/router-plugin": ["@tanstack/router-plugin@1.154.12", "", { "dependencies": { "@babel/core": "^7.28.5", "@babel/plugin-syntax-jsx": "^7.27.1", "@babel/plugin-syntax-typescript": "^7.27.1", "@babel/template": "^7.27.2", "@babel/traverse": "^7.28.5", "@babel/types": "^7.28.5", "@tanstack/router-core": "1.154.12", "@tanstack/router-generator": "1.154.12", "@tanstack/router-utils": "1.154.7", "@tanstack/virtual-file-routes": "1.154.7", "babel-dead-code-elimination": "^1.0.11", "chokidar": "^3.6.0", "unplugin": "^2.1.2", "zod": "^3.24.2" }, "peerDependencies": { "@rsbuild/core": ">=1.0.2", "@tanstack/react-router": "^1.154.12", "vite": ">=5.0.0 || >=6.0.0 || >=7.0.0", "vite-plugin-solid": "^2.11.10", "webpack": ">=5.92.0" }, "optionalPeers": ["@rsbuild/core", "@tanstack/react-router", "vite", "vite-plugin-solid", "webpack"] }, "sha512-YlFjrL5j7RbYT/B3RZZedbXOHXfqRV7b/qIGyojBaHsrIgKFGo4AHg/FyS50HJaHGQ27vvgWNSy/4Orrozbm0Q=="], + "@tanstack/router-plugin": ["@tanstack/router-plugin@1.157.16", "", { "dependencies": { "@babel/core": "^7.28.5", "@babel/plugin-syntax-jsx": "^7.27.1", "@babel/plugin-syntax-typescript": "^7.27.1", "@babel/template": "^7.27.2", "@babel/traverse": "^7.28.5", "@babel/types": "^7.28.5", "@tanstack/router-core": "1.157.16", "@tanstack/router-generator": "1.157.16", "@tanstack/router-utils": "1.154.7", "@tanstack/virtual-file-routes": "1.154.7", "babel-dead-code-elimination": "^1.0.11", "chokidar": "^3.6.0", "unplugin": "^2.1.2", "zod": "^3.24.2" }, "peerDependencies": { "@rsbuild/core": ">=1.0.2", "@tanstack/react-router": "^1.157.16", "vite": ">=5.0.0 || >=6.0.0 || >=7.0.0", "vite-plugin-solid": "^2.11.10", "webpack": ">=5.92.0" }, "optionalPeers": ["@rsbuild/core", "@tanstack/react-router", "vite", "vite-plugin-solid", "webpack"] }, "sha512-YQg7L06xyCJAYyrEJNZGAnDL8oChILU+G/eSDIwEfcWn5iLk+47x1Gcdxr82++47PWmOPhzuTo8edDQXWs7kAA=="], + + "@tanstack/router-ssr-query-core": ["@tanstack/router-ssr-query-core@1.157.16", "", { "peerDependencies": { "@tanstack/query-core": ">=5.90.0", "@tanstack/router-core": ">=1.127.0" } }, "sha512-YuwNG4jdtn+r90yyti8yP27IKaVoflWmRezqnj0gyJxpRauBkK7MVLvWSNbJadnk88b9H+rdtNOF2k3owGaong=="], "@tanstack/router-utils": ["@tanstack/router-utils@1.154.7", "", { "dependencies": { "@babel/core": "^7.28.5", "@babel/generator": "^7.28.5", "@babel/parser": "^7.28.5", "ansis": "^4.1.0", "diff": "^8.0.2", "pathe": "^2.0.3", "tinyglobby": "^0.2.15" } }, "sha512-61bGx32tMKuEpVRseu2sh1KQe8CfB7793Mch/kyQt0EP3tD7X0sXmimCl3truRiDGUtI0CaSoQV1NPjAII1RBA=="], @@ -243,6 +323,12 @@ "@tanstack/virtual-file-routes": ["@tanstack/virtual-file-routes@1.154.7", "", {}, "sha512-cHHDnewHozgjpI+MIVp9tcib6lYEQK5MyUr0ChHpHFGBl8Xei55rohFK0I0ve/GKoHeioaK42Smd8OixPp6CTg=="], + "@tokenizer/inflate": ["@tokenizer/inflate@0.4.1", "", { "dependencies": { "debug": "^4.4.3", "token-types": "^6.1.1" } }, "sha512-2mAv+8pkG6GIZiF1kNg1jAjh27IDxEPKwdGul3snfztFerfPGI1LjDezZp3i7BElXompqEtPmoPx6c2wgtWsOA=="], + + "@tokenizer/token": ["@tokenizer/token@0.3.0", "", {}, "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A=="], + + "@trysound/sax": ["@trysound/sax@0.2.0", "", {}, "sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA=="], + "@types/babel__core": ["@types/babel__core@7.20.5", "", { "dependencies": { "@babel/parser": "^7.20.7", "@babel/types": "^7.20.7", "@types/babel__generator": "*", "@types/babel__template": "*", "@types/babel__traverse": "*" } }, "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA=="], "@types/babel__generator": ["@types/babel__generator@7.27.0", "", { "dependencies": { "@babel/types": "^7.0.0" } }, "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg=="], @@ -253,15 +339,11 @@ "@types/bun": ["@types/bun@1.3.6", "", { "dependencies": { "bun-types": "1.3.6" } }, "sha512-uWCv6FO/8LcpREhenN1d1b6fcspAB+cefwD7uti8C8VffIv0Um08TKMn98FynpTiU38+y2dUO55T11NgDt8VAA=="], - "@types/emscripten": ["@types/emscripten@1.40.1", "", {}, "sha512-sr53lnYkQNhjHNN0oJDdUm5564biioI5DuOpycufDVK7D3y+GR3oUswe2rlwY1nPNyusHbrJ9WoTyIHl4/Bpwg=="], + "@types/cookie": ["@types/cookie@0.6.0", "", {}, "sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA=="], "@types/estree": ["@types/estree@1.0.8", "", {}, "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w=="], - "@types/filesystem": ["@types/filesystem@0.0.36", "", { "dependencies": { "@types/filewriter": "*" } }, "sha512-vPDXOZuannb9FZdxgHnqSwAG/jvdGM8Wq+6N4D/d80z+D4HWH+bItqsZaVRQykAn6WEVeEkLm2oQigyHtgb0RA=="], - - "@types/filewriter": ["@types/filewriter@0.0.33", "", {}, "sha512-xFU8ZXTw4gd358lb2jw25nxY9QAgqn2+bKKjKOYfNCzN4DKCFetK7sPtrlpg66Ywe3vWY9FNxprZawAh9wfJ3g=="], - - "@types/har-format": ["@types/har-format@1.2.16", "", {}, "sha512-fluxdy7ryD3MV6h8pTfTYpy/xQzCFC7m89nOH9y94cNqJ1mDIDPut7MnRHI3F6qRmh/cT2fUjG1MLdCNb4hE9A=="], + "@types/json-schema": ["@types/json-schema@7.0.15", "", {}, "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA=="], "@types/node": ["@types/node@24.1.0", "", { "dependencies": { "undici-types": "~7.8.0" } }, "sha512-ut5FthK5moxFKH2T1CUOC6ctR67rQRvvHdFLCD2Ql6KXmMuCrjsSsRI9UsLCm9M18BMwClv4pn327UvB7eeO1w=="], @@ -269,14 +351,18 @@ "@types/react-dom": ["@types/react-dom@19.2.3", "", { "peerDependencies": { "@types/react": "^19.2.0" } }, "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ=="], - "@types/webextension-polyfill": ["@types/webextension-polyfill@0.12.3", "", {}, "sha512-F58aDVSeN/MjUGazXo/cPsmR76EvqQhQ1v4x23hFjUX0cfAJYE+JBWwiOGW36/VJGGxoH74sVlRIF3z7SJCKyg=="], - "@vitejs/plugin-react": ["@vitejs/plugin-react@5.1.2", "", { "dependencies": { "@babel/core": "^7.28.5", "@babel/plugin-transform-react-jsx-self": "^7.27.1", "@babel/plugin-transform-react-jsx-source": "^7.27.1", "@rolldown/pluginutils": "1.0.0-beta.53", "@types/babel__core": "^7.20.5", "react-refresh": "^0.18.0" }, "peerDependencies": { "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" } }, "sha512-EcA07pHJouywpzsoTUqNh5NwGayl2PPVEJKUSinGGSxFGYn+shYbqMGBg6FXDqgXum9Ou/ecb+411ssw8HImJQ=="], - "abort-controller": ["abort-controller@3.0.0", "", { "dependencies": { "event-target-shim": "^5.0.0" } }, "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg=="], - "acorn": ["acorn@8.15.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg=="], + "ajv": ["ajv@8.17.1", "", { "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2" } }, "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g=="], + + "ajv-formats": ["ajv-formats@3.0.1", "", { "dependencies": { "ajv": "^8.0.0" } }, "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ=="], + + "animate.css": ["animate.css@4.1.1", "", {}, "sha512-+mRmCTv6SbCmtYJCN4faJMNFVNN5EuCTTprDTAo7YzIGji2KADmakjVA3+8mVDkZ2Bf09vayB35lSQIex2+QaQ=="], + + "ansi-colors": ["ansi-colors@4.1.3", "", {}, "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw=="], + "ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], "ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], @@ -285,49 +371,39 @@ "anymatch": ["anymatch@3.1.3", "", { "dependencies": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" } }, "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw=="], - "archiver": ["archiver@7.0.1", "", { "dependencies": { "archiver-utils": "^5.0.2", "async": "^3.2.4", "buffer-crc32": "^1.0.0", "readable-stream": "^4.0.0", "readdir-glob": "^1.1.2", "tar-stream": "^3.0.0", "zip-stream": "^6.0.1" } }, "sha512-ZcbTaIqJOfCc03QwD468Unz/5Ir8ATtvAHsK+FdXbDIbGfihqh9mrvdcYunQzqn4HrvWWaFyaxJhGZagaJJpPQ=="], - - "archiver-utils": ["archiver-utils@5.0.2", "", { "dependencies": { "glob": "^10.0.0", "graceful-fs": "^4.2.0", "is-stream": "^2.0.1", "lazystream": "^1.0.0", "lodash": "^4.17.15", "normalize-path": "^3.0.0", "readable-stream": "^4.0.0" } }, "sha512-wuLJMmIBQYCsGZgYLTy5FIB2pF6Lfb6cXMSF8Qywwk3t20zWnAi7zLcQFdKQmIB8wyZpY5ER38x08GbwtR2cLA=="], + "argparse": ["argparse@2.0.1", "", {}, "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="], "ast-types": ["ast-types@0.16.1", "", { "dependencies": { "tslib": "^2.0.1" } }, "sha512-6t10qk83GOG8p0vKmaCr8eiilZwO171AvbROMtvvNiwrTly62t+7XkA8RdIIVbpMhCASAsxgAzdRSwh6nw/5Dg=="], - "async": ["async@3.2.6", "", {}, "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA=="], - - "b4a": ["b4a@1.6.7", "", {}, "sha512-OnAYlL5b7LEkALw87fUVafQw5rVR9RjwGd4KUwNQ6DrrNmaVaUCgLipfVlzrPQ4tWOR9P0IXGNOx50jYCCdSJg=="], + "atomically": ["atomically@2.1.0", "", { "dependencies": { "stubborn-fs": "^2.0.0", "when-exit": "^2.1.4" } }, "sha512-+gDffFXRW6sl/HCwbta7zK4uNqbPjv4YJEAdz7Vu+FLQHe77eZ4bvbJGi4hE0QPeJlMYMA3piXEr1UL3dAwx7Q=="], "babel-dead-code-elimination": ["babel-dead-code-elimination@1.0.12", "", { "dependencies": { "@babel/core": "^7.23.7", "@babel/parser": "^7.23.6", "@babel/traverse": "^7.23.7", "@babel/types": "^7.23.6" } }, "sha512-GERT7L2TiYcYDtYk1IpD+ASAYXjKbLTDPhBtYj7X1NuRMDTMtAx9kyBenub1Ev41lo91OHCKdmP+egTDmfQ7Ig=="], - "balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], - - "bare-events": ["bare-events@2.6.1", "", {}, "sha512-AuTJkq9XmE6Vk0FJVNq5QxETrSA/vKHarWVBG5l/JbdCL1prJemiyJqUS0jrlXO0MftuPq4m3YVYhoNc5+aE/g=="], - - "base64-js": ["base64-js@1.5.1", "", {}, "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="], + "babel-plugin-react-compiler": ["babel-plugin-react-compiler@1.0.0", "", { "dependencies": { "@babel/types": "^7.26.0" } }, "sha512-Ixm8tFfoKKIPYdCCKYTsqv+Fd4IJ0DQqMyEimo+pxUOMUR9cVPlwTrFt9Avu+3cb6Zp3mAzl+t1MrG2fxxKsxw=="], "baseline-browser-mapping": ["baseline-browser-mapping@2.9.17", "", { "bin": { "baseline-browser-mapping": "dist/cli.js" } }, "sha512-agD0MgJFUP/4nvjqzIB29zRPUuCF7Ge6mEv9s8dHrtYD7QWXRcx75rOADE/d5ah1NI+0vkDl0yorDd5U852IQQ=="], "binary-extensions": ["binary-extensions@2.3.0", "", {}, "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw=="], - "brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="], + "boolbase": ["boolbase@1.0.0", "", {}, "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww=="], "braces": ["braces@3.0.3", "", { "dependencies": { "fill-range": "^7.1.1" } }, "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA=="], - "browser-namespace": ["browser-namespace@1.4.0", "", { "dependencies": { "@types/filesystem": "*", "@types/har-format": "*", "@types/webextension-polyfill": "*" } }, "sha512-9b4yNTNs+8HVPssSq8RSZMRunf+G4cVQ2PMtOTn+uEVFOW5C0Uo+eGXuJ5LfxS1UDph5oAdWj92thPyxVhpqXg=="], - "browserslist": ["browserslist@4.28.1", "", { "dependencies": { "baseline-browser-mapping": "^2.9.0", "caniuse-lite": "^1.0.30001759", "electron-to-chromium": "^1.5.263", "node-releases": "^2.0.27", "update-browserslist-db": "^1.2.0" }, "bin": { "browserslist": "cli.js" } }, "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA=="], - "buffer": ["buffer@6.0.3", "", { "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.2.1" } }, "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA=="], - - "buffer-crc32": ["buffer-crc32@1.0.0", "", {}, "sha512-Db1SbgBS/fg/392AblrMJk97KggmvYhr4pB5ZIMTWtaivCPMWLkmb7m21cJvpvgK+J3nsU2CmmixNBZx4vFj/w=="], - "bun-types": ["bun-types@1.3.6", "", { "dependencies": { "@types/node": "*" } }, "sha512-OlFwHcnNV99r//9v5IIOgQ9Uk37gZqrNMCcqEaExdkVq3Avwqok1bJFmvGMCkCE0FqzdY8VMOZpfpR3lwI+CsQ=="], + "bundle-name": ["bundle-name@4.1.0", "", { "dependencies": { "run-applescript": "^7.0.0" } }, "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q=="], + + "c12": ["c12@3.3.3", "", { "dependencies": { "chokidar": "^5.0.0", "confbox": "^0.2.2", "defu": "^6.1.4", "dotenv": "^17.2.3", "exsolve": "^1.0.8", "giget": "^2.0.0", "jiti": "^2.6.1", "ohash": "^2.0.11", "pathe": "^2.0.3", "perfect-debounce": "^2.0.0", "pkg-types": "^2.3.0", "rc9": "^2.1.2" }, "peerDependencies": { "magicast": "*" }, "optionalPeers": ["magicast"] }, "sha512-750hTRvgBy5kcMNPdh95Qo+XUBeGo8C7nsKSmedDmaQI+E0r82DwHeM6vBewDe4rGFbnxoa4V9pw+sPh5+Iz8Q=="], + "caniuse-lite": ["caniuse-lite@1.0.30001765", "", {}, "sha512-LWcNtSyZrakjECqmpP4qdg0MMGdN368D7X8XvvAqOcqMv0RxnlqVKZl2V6/mBR68oYMxOZPLw/gO7DuisMHUvQ=="], "chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="], "chokidar": ["chokidar@3.6.0", "", { "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", "glob-parent": "~5.1.2", "is-binary-path": "~2.1.0", "is-glob": "~4.0.1", "normalize-path": "~3.0.0", "readdirp": "~3.6.0" }, "optionalDependencies": { "fsevents": "~2.3.2" } }, "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw=="], - "chownr": ["chownr@2.0.0", "", {}, "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ=="], + "citty": ["citty@0.1.6", "", { "dependencies": { "consola": "^3.2.3" } }, "sha512-tskPPKEs8D2KPafUypv2gxwJP8h/OaJmC82QQGGDQcHvXX43xF2VDACcJVmZ0EuSxkpO9Kc4MlrA3q0+FG58AQ=="], "classnames": ["classnames@2.5.1", "", {}, "sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow=="], @@ -339,71 +415,119 @@ "color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="], - "compress-commons": ["compress-commons@6.0.2", "", { "dependencies": { "crc-32": "^1.2.0", "crc32-stream": "^6.0.0", "is-stream": "^2.0.1", "normalize-path": "^3.0.0", "readable-stream": "^4.0.0" } }, "sha512-6FqVXeETqWPoGcfzrXb37E50NP0LXT8kAMu5ooZayhWWdgEY4lBEEcbQNXtkuKQsGduxiIcI4gOTsxTmuq/bSg=="], + "color-support": ["color-support@1.1.3", "", { "bin": { "color-support": "bin.js" } }, "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg=="], + + "commander": ["commander@14.0.2", "", {}, "sha512-TywoWNNRbhoD0BXs1P3ZEScW8W5iKrnbithIl0YH+uCmBd0QpPOA8yc82DS3BIE5Ma6FnBVUsJ7wVUDz4dvOWQ=="], "concurrently": ["concurrently@9.2.1", "", { "dependencies": { "chalk": "4.1.2", "rxjs": "7.8.2", "shell-quote": "1.8.3", "supports-color": "8.1.1", "tree-kill": "1.2.2", "yargs": "17.7.2" }, "bin": { "conc": "dist/bin/concurrently.js", "concurrently": "dist/bin/concurrently.js" } }, "sha512-fsfrO0MxV64Znoy8/l1vVIjjHa29SZyyqPgQBwhiDcaW8wJc2W3XWVOGx4M3oJBnv/zdUZIIp1gDeS98GzP8Ng=="], + "conf": ["conf@15.0.2", "", { "dependencies": { "ajv": "^8.17.1", "ajv-formats": "^3.0.1", "atomically": "^2.0.3", "debounce-fn": "^6.0.0", "dot-prop": "^10.0.0", "env-paths": "^3.0.0", "json-schema-typed": "^8.0.1", "semver": "^7.7.2", "uint8array-extras": "^1.5.0" } }, "sha512-JBSrutapCafTrddF9dH3lc7+T2tBycGF4uPkI4Js+g4vLLEhG6RZcFi3aJd5zntdf5tQxAejJt8dihkoQ/eSJw=="], + + "confbox": ["confbox@0.2.2", "", {}, "sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ=="], + + "consola": ["consola@3.4.2", "", {}, "sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA=="], + "convert-source-map": ["convert-source-map@2.0.0", "", {}, "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg=="], + "cookie": ["cookie@0.6.0", "", {}, "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw=="], + "cookie-es": ["cookie-es@2.0.0", "", {}, "sha512-RAj4E421UYRgqokKUmotqAwuplYw15qtdXfY+hGzgCJ/MBjCVZcSoHK/kH9kocfjRjcDME7IiDWR/1WX1TM2Pg=="], - "core-util-is": ["core-util-is@1.0.3", "", {}, "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ=="], - - "crc-32": ["crc-32@1.2.2", "", { "bin": { "crc32": "bin/crc32.njs" } }, "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ=="], - - "crc32-stream": ["crc32-stream@6.0.0", "", { "dependencies": { "crc-32": "^1.2.0", "readable-stream": "^4.0.0" } }, "sha512-piICUB6ei4IlTv1+653yq5+KoqfBYmj9bw6LqXoOneTMDXk5nM1qt12mFW1caG3LlJXEKW1Bp0WggEmIfQB34g=="], + "cross-env": ["cross-env@10.1.0", "", { "dependencies": { "@epic-web/invariant": "^1.0.0", "cross-spawn": "^7.0.6" }, "bin": { "cross-env": "dist/bin/cross-env.js", "cross-env-shell": "dist/bin/cross-env-shell.js" } }, "sha512-GsYosgnACZTADcmEyJctkJIoqAhHjttw7RsFrVoJNXbsWWqaq6Ym+7kZjq6mS45O0jij6vtiReppKQEtqWy6Dw=="], "cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="], + "css-select": ["css-select@5.2.2", "", { "dependencies": { "boolbase": "^1.0.0", "css-what": "^6.1.0", "domhandler": "^5.0.2", "domutils": "^3.0.1", "nth-check": "^2.0.1" } }, "sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw=="], + + "css-tree": ["css-tree@2.3.1", "", { "dependencies": { "mdn-data": "2.0.30", "source-map-js": "^1.0.1" } }, "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw=="], + + "css-what": ["css-what@6.2.2", "", {}, "sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA=="], + + "csso": ["csso@5.0.5", "", { "dependencies": { "css-tree": "~2.2.0" } }, "sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ=="], + "csstype": ["csstype@3.2.3", "", {}, "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ=="], + "daisyui": ["daisyui@5.5.14", "", {}, "sha512-L47rvw7I7hK68TA97VB8Ee0woHew+/ohR6Lx6Ah/krfISOqcG4My7poNpX5Mo5/ytMxiR40fEaz6njzDi7cuSg=="], + + "debounce-fn": ["debounce-fn@6.0.0", "", { "dependencies": { "mimic-function": "^5.0.0" } }, "sha512-rBMW+F2TXryBwB54Q0d8drNEI+TfoS9JpNTAoVpukbWEhjXQq4rySFYLaqXMFXwdv61Zb2OHtj5bviSoimqxRQ=="], + "debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="], + "default-browser": ["default-browser@5.4.0", "", { "dependencies": { "bundle-name": "^4.1.0", "default-browser-id": "^5.0.0" } }, "sha512-XDuvSq38Hr1MdN47EDvYtx3U0MTqpCEn+F6ft8z2vYDzMrvQhVp0ui9oQdqW3MvK3vqUETglt1tVGgjLuJ5izg=="], + + "default-browser-id": ["default-browser-id@5.0.1", "", {}, "sha512-x1VCxdX4t+8wVfd1so/9w+vQ4vx7lKd2Qp5tDRutErwmR85OgmfX7RlLRMWafRMY7hbEiXIbudNrjOAPa/hL8Q=="], + + "define-lazy-prop": ["define-lazy-prop@3.0.0", "", {}, "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg=="], + + "defu": ["defu@6.1.4", "", {}, "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg=="], + + "destr": ["destr@2.0.5", "", {}, "sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA=="], + "detect-libc": ["detect-libc@2.1.2", "", {}, "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ=="], "diff": ["diff@8.0.3", "", {}, "sha512-qejHi7bcSD4hQAZE0tNAawRK1ZtafHDmMTMkrrIGgSLl7hTnQHmKCeB45xAcbfTqK2zowkM3j3bHt/4b/ARbYQ=="], - "eastasianwidth": ["eastasianwidth@0.2.0", "", {}, "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA=="], + "dom-serializer": ["dom-serializer@2.0.0", "", { "dependencies": { "domelementtype": "^2.3.0", "domhandler": "^5.0.2", "entities": "^4.2.0" } }, "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg=="], - "electrobun": ["electrobun@0.8.0", "", { "dependencies": { "@oneidentity/zstd-js": "^1.0.3", "archiver": "^7.0.1", "rpc-anywhere": "1.5.0", "tar": "^6.2.1" }, "bin": { "electrobun": "bin/electrobun.cjs" } }, "sha512-tjYmWyp9NIR80ejVUrqeMHu/H0QR2nb7zC79MJxSOfQYk6uKE5XCgr9UBURiIdnX71LfTd4Mb+R9A/Oo7vxxUg=="], + "domelementtype": ["domelementtype@2.3.0", "", {}, "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw=="], + + "domhandler": ["domhandler@5.0.3", "", { "dependencies": { "domelementtype": "^2.3.0" } }, "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w=="], + + "domutils": ["domutils@3.2.2", "", { "dependencies": { "dom-serializer": "^2.0.0", "domelementtype": "^2.3.0", "domhandler": "^5.0.3" } }, "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw=="], + + "dot-prop": ["dot-prop@10.1.0", "", { "dependencies": { "type-fest": "^5.0.0" } }, "sha512-MVUtAugQMOff5RnBy2d9N31iG0lNwg1qAoAOn7pOK5wf94WIaE3My2p3uwTQuvS2AcqchkcR3bHByjaM0mmi7Q=="], + + "dotenv": ["dotenv@17.2.3", "", {}, "sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w=="], "electron-to-chromium": ["electron-to-chromium@1.5.277", "", {}, "sha512-wKXFZw4erWmmOz5N/grBoJ2XrNJGDFMu2+W5ACHza5rHtvsqrK4gb6rnLC7XxKB9WlJ+RmyQatuEXmtm86xbnw=="], + "elysia": ["elysia@1.4.22", "", { "dependencies": { "cookie": "^1.1.1", "exact-mirror": "^0.2.6", "fast-decode-uri-component": "^1.0.1", "memoirist": "^0.4.0" }, "peerDependencies": { "@sinclair/typebox": ">= 0.34.0 < 1", "@types/bun": ">= 1.2.0", "file-type": ">= 20.0.0", "openapi-types": ">= 12.0.0", "typescript": ">= 5.0.0" }, "optionalPeers": ["@types/bun", "typescript"] }, "sha512-Q90VCb1RVFxnFaRV0FDoSylESQQLWgLHFmWciQJdX9h3b2cSasji9KWEUvaJuy/L9ciAGg4RAhUVfsXHg5K2RQ=="], + "emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="], "enhanced-resolve": ["enhanced-resolve@5.18.4", "", { "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.2.0" } }, "sha512-LgQMM4WXU3QI+SYgEc2liRgznaD5ojbmY3sb8LxyguVkIg5FxdpTkvk72te2R38/TGKxH634oLxXRGY6d7AP+Q=="], + "entities": ["entities@4.5.0", "", {}, "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw=="], + + "env-paths": ["env-paths@3.0.0", "", {}, "sha512-dtJUTepzMW3Lm/NPxRf3wP4642UWhjL2sQxc+ym2YMj1m/H2zDNQOlezafzkHwn6sMstjHTwG6iQQsctDW/b1A=="], + "esbuild": ["esbuild@0.27.2", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.27.2", "@esbuild/android-arm": "0.27.2", "@esbuild/android-arm64": "0.27.2", "@esbuild/android-x64": "0.27.2", "@esbuild/darwin-arm64": "0.27.2", "@esbuild/darwin-x64": "0.27.2", "@esbuild/freebsd-arm64": "0.27.2", "@esbuild/freebsd-x64": "0.27.2", "@esbuild/linux-arm": "0.27.2", "@esbuild/linux-arm64": "0.27.2", "@esbuild/linux-ia32": "0.27.2", "@esbuild/linux-loong64": "0.27.2", "@esbuild/linux-mips64el": "0.27.2", "@esbuild/linux-ppc64": "0.27.2", "@esbuild/linux-riscv64": "0.27.2", "@esbuild/linux-s390x": "0.27.2", "@esbuild/linux-x64": "0.27.2", "@esbuild/netbsd-arm64": "0.27.2", "@esbuild/netbsd-x64": "0.27.2", "@esbuild/openbsd-arm64": "0.27.2", "@esbuild/openbsd-x64": "0.27.2", "@esbuild/openharmony-arm64": "0.27.2", "@esbuild/sunos-x64": "0.27.2", "@esbuild/win32-arm64": "0.27.2", "@esbuild/win32-ia32": "0.27.2", "@esbuild/win32-x64": "0.27.2" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-HyNQImnsOC7X9PMNaCIeAm4ISCQXs5a5YasTXVliKv4uuBo1dKrG0A+uQS8M5eXjVMnLg3WgXaKvprHlFJQffw=="], "escalade": ["escalade@3.2.0", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="], "esprima": ["esprima@4.0.1", "", { "bin": { "esparse": "./bin/esparse.js", "esvalidate": "./bin/esvalidate.js" } }, "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A=="], - "event-target-shim": ["event-target-shim@5.0.1", "", {}, "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ=="], + "exact-mirror": ["exact-mirror@0.2.6", "", { "peerDependencies": { "@sinclair/typebox": "^0.34.15" }, "optionalPeers": ["@sinclair/typebox"] }, "sha512-7s059UIx9/tnOKSySzUk5cPGkoILhTE4p6ncf6uIPaQ+9aRBQzQjc9+q85l51+oZ+P6aBxh084pD0CzBQPcFUA=="], - "events": ["events@3.3.0", "", {}, "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q=="], + "exsolve": ["exsolve@1.0.8", "", {}, "sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA=="], - "fast-fifo": ["fast-fifo@1.3.2", "", {}, "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ=="], + "fast-decode-uri-component": ["fast-decode-uri-component@1.0.1", "", {}, "sha512-WKgKWg5eUxvRZGwW8FvfbaH7AXSh2cL+3j5fMGzUMCxWBJ3dV3a7Wz8y2f/uQ0e3B6WmodD3oS54jTQ9HVTIIg=="], + + "fast-deep-equal": ["fast-deep-equal@3.1.3", "", {}, "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="], + + "fast-glob": ["fast-glob@3.3.3", "", { "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", "glob-parent": "^5.1.2", "merge2": "^1.3.0", "micromatch": "^4.0.8" } }, "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg=="], + + "fast-uri": ["fast-uri@3.1.0", "", {}, "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA=="], + + "fastq": ["fastq@1.20.1", "", { "dependencies": { "reusify": "^1.0.4" } }, "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw=="], "fdir": ["fdir@6.5.0", "", { "peerDependencies": { "picomatch": "^3 || ^4" }, "optionalPeers": ["picomatch"] }, "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg=="], + "file-type": ["file-type@21.3.0", "", { "dependencies": { "@tokenizer/inflate": "^0.4.1", "strtok3": "^10.3.4", "token-types": "^6.1.1", "uint8array-extras": "^1.4.0" } }, "sha512-8kPJMIGz1Yt/aPEwOsrR97ZyZaD1Iqm8PClb1nYFclUCkBi0Ma5IsYNQzvSFS9ib51lWyIw5mIT9rWzI/xjpzA=="], + "fill-range": ["fill-range@7.1.1", "", { "dependencies": { "to-regex-range": "^5.0.1" } }, "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg=="], - "foreground-child": ["foreground-child@3.3.1", "", { "dependencies": { "cross-spawn": "^7.0.6", "signal-exit": "^4.0.1" } }, "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw=="], - - "fs-minipass": ["fs-minipass@2.1.0", "", { "dependencies": { "minipass": "^3.0.0" } }, "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg=="], + "fs-extra": ["fs-extra@11.3.3", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-VWSRii4t0AFm6ixFFmLLx1t7wS1gh+ckoa84aOeapGum0h+EZd1EhEumSB+ZdDLnEPuucsVB9oB7cxJHap6Afg=="], "fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="], - "gamepad.css": ["gamepad.css@0.0.4", "", {}, "sha512-cgE1dbJT+HXbivqSIuendOrO920BlSBVzSWI695tturtPqd41bBmhljIuRu/wOSkq40n/yA2oTs45pj6vR06Jw=="], - "gensync": ["gensync@1.0.0-beta.2", "", {}, "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg=="], "get-caller-file": ["get-caller-file@2.0.5", "", {}, "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="], "get-tsconfig": ["get-tsconfig@4.13.0", "", { "dependencies": { "resolve-pkg-maps": "^1.0.0" } }, "sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ=="], - "glob": ["glob@10.4.5", "", { "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", "minimatch": "^9.0.4", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^1.11.1" }, "bin": { "glob": "dist/esm/bin.mjs" } }, "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg=="], + "giget": ["giget@2.0.0", "", { "dependencies": { "citty": "^0.1.6", "consola": "^3.4.0", "defu": "^6.1.4", "node-fetch-native": "^1.6.6", "nypm": "^0.6.0", "pathe": "^2.0.3" }, "bin": { "giget": "dist/cli.mjs" } }, "sha512-L5bGsVkxJbJgdnwyuheIunkGatUF/zssUoxxjACCseZYAVbaqdh9Tsmmlkl8vYan09H7sbvKt4pS8GqKLBrEzA=="], "glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="], @@ -413,39 +537,49 @@ "has-flag": ["has-flag@4.0.0", "", {}, "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="], + "he": ["he@1.2.0", "", { "bin": { "he": "bin/he" } }, "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw=="], + "ieee754": ["ieee754@1.2.1", "", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="], - "inherits": ["inherits@2.0.4", "", {}, "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="], - "is-binary-path": ["is-binary-path@2.1.0", "", { "dependencies": { "binary-extensions": "^2.0.0" } }, "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw=="], + "is-docker": ["is-docker@3.0.0", "", { "bin": { "is-docker": "cli.js" } }, "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ=="], + "is-extglob": ["is-extglob@2.1.1", "", {}, "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ=="], "is-fullwidth-code-point": ["is-fullwidth-code-point@3.0.0", "", {}, "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="], "is-glob": ["is-glob@4.0.3", "", { "dependencies": { "is-extglob": "^2.1.1" } }, "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg=="], + "is-in-ssh": ["is-in-ssh@1.0.0", "", {}, "sha512-jYa6Q9rH90kR1vKB6NM7qqd1mge3Fx4Dhw5TVlK1MUBqhEOuCagrEHMevNuCcbECmXZ0ThXkRm+Ymr51HwEPAw=="], + + "is-inside-container": ["is-inside-container@1.0.0", "", { "dependencies": { "is-docker": "^3.0.0" }, "bin": { "is-inside-container": "cli.js" } }, "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA=="], + "is-number": ["is-number@7.0.0", "", {}, "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="], - "is-stream": ["is-stream@2.0.1", "", {}, "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg=="], - - "isarray": ["isarray@1.0.0", "", {}, "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ=="], + "is-wsl": ["is-wsl@3.1.0", "", { "dependencies": { "is-inside-container": "^1.0.0" } }, "sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw=="], "isbot": ["isbot@5.1.33", "", {}, "sha512-P4Hgb5NqswjkI0J1CM6XKXon/sxKY1SuowE7Qx2hrBhIwICFyXy54mfgB5eMHXsbe/eStzzpbIGNOvGmz+dlKg=="], "isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="], - "jackspeak": ["jackspeak@3.4.3", "", { "dependencies": { "@isaacs/cliui": "^8.0.2" }, "optionalDependencies": { "@pkgjs/parseargs": "^0.11.0" } }, "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw=="], - "jiti": ["jiti@2.6.1", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ=="], + "jose": ["jose@5.10.0", "", {}, "sha512-s+3Al/p9g32Iq+oqXxkW//7jk2Vig6FF1CFqzVXoTUXt2qz89YWbL+OwS17NFYEvxC35n0FKeGO2LGYSxeM2Gg=="], + "js-tokens": ["js-tokens@4.0.0", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="], + "js-yaml": ["js-yaml@4.1.1", "", { "dependencies": { "argparse": "^2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA=="], + "jsesc": ["jsesc@3.1.0", "", { "bin": { "jsesc": "bin/jsesc" } }, "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA=="], + "json-schema-traverse": ["json-schema-traverse@1.0.0", "", {}, "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="], + + "json-schema-typed": ["json-schema-typed@8.0.2", "", {}, "sha512-fQhoXdcvc3V28x7C7BMs4P5+kNlgUURe2jmUT1T//oBRMDrqy1QPelJimwZGo7Hg9VPV3EQV5Bnq4hbFy2vetA=="], + "json5": ["json5@2.2.3", "", { "bin": { "json5": "lib/cli.js" } }, "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg=="], - "lazystream": ["lazystream@1.0.1", "", { "dependencies": { "readable-stream": "^2.0.5" } }, "sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw=="], + "jsonfile": ["jsonfile@6.2.0", "", { "dependencies": { "universalify": "^2.0.0" }, "optionalDependencies": { "graceful-fs": "^4.1.6" } }, "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg=="], "lightningcss": ["lightningcss@1.30.2", "", { "dependencies": { "detect-libc": "^2.0.3" }, "optionalDependencies": { "lightningcss-android-arm64": "1.30.2", "lightningcss-darwin-arm64": "1.30.2", "lightningcss-darwin-x64": "1.30.2", "lightningcss-freebsd-x64": "1.30.2", "lightningcss-linux-arm-gnueabihf": "1.30.2", "lightningcss-linux-arm64-gnu": "1.30.2", "lightningcss-linux-arm64-musl": "1.30.2", "lightningcss-linux-x64-gnu": "1.30.2", "lightningcss-linux-x64-musl": "1.30.2", "lightningcss-win32-arm64-msvc": "1.30.2", "lightningcss-win32-x64-msvc": "1.30.2" } }, "sha512-utfs7Pr5uJyyvDETitgsaqSyjCb2qNRAtuqUeWIAKztsOYdcACf2KtARYXg2pSvhkt+9NfoaNY7fxjl6nuMjIQ=="], @@ -471,79 +605,115 @@ "lightningcss-win32-x64-msvc": ["lightningcss-win32-x64-msvc@1.30.2", "", { "os": "win32", "cpu": "x64" }, "sha512-5g1yc73p+iAkid5phb4oVFMB45417DkRevRbt/El/gKXJk4jid+vPFF/AXbxn05Aky8PapwzZrdJShv5C0avjw=="], - "lodash": ["lodash@4.17.21", "", {}, "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="], + "lodash": ["lodash@4.17.23", "", {}, "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w=="], + + "lodash.debounce": ["lodash.debounce@4.0.8", "", {}, "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow=="], "lru-cache": ["lru-cache@5.1.1", "", { "dependencies": { "yallist": "^3.0.2" } }, "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w=="], - "lucide-react": ["lucide-react@0.562.0", "", { "peerDependencies": { "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-82hOAu7y0dbVuFfmO4bYF1XEwYk/mEbM5E+b1jgci/udUBEE/R7LF5Ip0CCEmXe8AybRM8L+04eP+LGZeDvkiw=="], + "lucide-react": ["lucide-react@0.563.0", "", { "peerDependencies": { "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-8dXPB2GI4dI8jV4MgUDGBeLdGk8ekfqVZ0BdLcrRzocGgG75ltNEmWS+gE7uokKF/0oSUuczNDT+g9hFJ23FkA=="], "magic-string": ["magic-string@0.30.21", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.5" } }, "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ=="], - "minimatch": ["minimatch@5.1.6", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g=="], + "mdn-data": ["mdn-data@2.0.30", "", {}, "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA=="], - "minipass": ["minipass@5.0.0", "", {}, "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ=="], + "memoirist": ["memoirist@0.4.0", "", {}, "sha512-zxTgA0mSYELa66DimuNQDvyLq36AwDlTuVRbnQtB+VuTcKWm5Qc4z3WkSpgsFWHNhexqkIooqpv4hdcqrX5Nmg=="], - "minizlib": ["minizlib@2.1.2", "", { "dependencies": { "minipass": "^3.0.0", "yallist": "^4.0.0" } }, "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg=="], + "merge2": ["merge2@1.4.1", "", {}, "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg=="], - "mkdirp": ["mkdirp@1.0.4", "", { "bin": { "mkdirp": "bin/cmd.js" } }, "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw=="], + "micromatch": ["micromatch@4.0.8", "", { "dependencies": { "braces": "^3.0.3", "picomatch": "^2.3.1" } }, "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA=="], + + "mimic-function": ["mimic-function@5.0.1", "", {}, "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA=="], + + "minimatch": ["minimatch@10.1.1", "", { "dependencies": { "@isaacs/brace-expansion": "^5.0.0" } }, "sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ=="], "ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], "nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="], + "node-fetch-native": ["node-fetch-native@1.6.7", "", {}, "sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q=="], + + "node-html-parser": ["node-html-parser@7.0.2", "", { "dependencies": { "css-select": "^5.1.0", "he": "1.2.0" } }, "sha512-DxodLVh7a6JMkYzWyc8nBX9MaF4M0lLFYkJHlWOiu7+9/I6mwNK9u5TbAMC7qfqDJEPX9OIoWA2A9t4C2l1mUQ=="], + "node-releases": ["node-releases@2.0.27", "", {}, "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA=="], "normalize-path": ["normalize-path@3.0.0", "", {}, "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA=="], - "package-json-from-dist": ["package-json-from-dist@1.0.1", "", {}, "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw=="], + "nth-check": ["nth-check@2.1.1", "", { "dependencies": { "boolbase": "^1.0.0" } }, "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w=="], + + "nypm": ["nypm@0.6.4", "", { "dependencies": { "citty": "^0.2.0", "pathe": "^2.0.3", "tinyexec": "^1.0.2" }, "bin": { "nypm": "dist/cli.mjs" } }, "sha512-1TvCKjZyyklN+JJj2TS3P4uSQEInrM/HkkuSXsEzm1ApPgBffOn8gFguNnZf07r/1X6vlryfIqMUkJKQMzlZiw=="], + + "oauth4webapi": ["oauth4webapi@2.17.0", "", {}, "sha512-lbC0Z7uzAFNFyzEYRIC+pkSVvDHJTbEW+dYlSBAlCYDe6RxUkJ26bClhk8ocBZip1wfI9uKTe0fm4Ib4RHn6uQ=="], + + "ohash": ["ohash@2.0.11", "", {}, "sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ=="], + + "open": ["open@11.0.0", "", { "dependencies": { "default-browser": "^5.4.0", "define-lazy-prop": "^3.0.0", "is-in-ssh": "^1.0.0", "is-inside-container": "^1.0.0", "powershell-utils": "^0.1.0", "wsl-utils": "^0.3.0" } }, "sha512-smsWv2LzFjP03xmvFoJ331ss6h+jixfA4UUV/Bsiyuu4YJPfN+FIQGOIiv4w9/+MoHkfkJ22UIaQWRVFRfH6Vw=="], + + "openapi-types": ["openapi-types@12.1.3", "", {}, "sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw=="], "path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="], - "path-scurry": ["path-scurry@1.11.1", "", { "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" } }, "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA=="], - "pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="], + "perfect-debounce": ["perfect-debounce@2.1.0", "", {}, "sha512-LjgdTytVFXeUgtHZr9WYViYSM/g8MkcTPYDlPa3cDqMirHjKiSZPYd6DoL7pK8AJQr+uWkQvCjHNdiMqsrJs+g=="], + "picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="], "picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="], + "pkg-types": ["pkg-types@2.3.0", "", { "dependencies": { "confbox": "^0.2.2", "exsolve": "^1.0.7", "pathe": "^2.0.3" } }, "sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig=="], + "postcss": ["postcss@8.5.6", "", { "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg=="], + "powershell-utils": ["powershell-utils@0.1.0", "", {}, "sha512-dM0jVuXJPsDN6DvRpea484tCUaMiXWjuCn++HGTqUWzGDjv5tZkEZldAJ/UMlqRYGFrD/etByo4/xOuC/snX2A=="], + + "preact": ["preact@10.11.3", "", {}, "sha512-eY93IVpod/zG3uMF22Unl8h9KkrcKIRs2EGar8hwLZZDU1lkjph303V9HZBwufh2s736U6VXuhD109LYqPoffg=="], + + "preact-render-to-string": ["preact-render-to-string@5.2.3", "", { "dependencies": { "pretty-format": "^3.8.0" }, "peerDependencies": { "preact": ">=10" } }, "sha512-aPDxUn5o3GhWdtJtW0svRC2SS/l8D9MAgo2+AWml+BhDImb27ALf04Q2d+AHqUUOc6RdSXFIBVa2gxzgMKgtZA=="], + "prettier": ["prettier@3.8.1", "", { "bin": { "prettier": "bin/prettier.cjs" } }, "sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg=="], - "process": ["process@0.11.10", "", {}, "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A=="], + "pretty-bytes": ["pretty-bytes@7.1.0", "", {}, "sha512-nODzvTiYVRGRqAOvE84Vk5JDPyyxsVk0/fbA/bq7RqlnhksGpset09XTxbpvLTIjoaF7K8Z8DG8yHtKGTPSYRw=="], - "process-nextick-args": ["process-nextick-args@2.0.1", "", {}, "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="], + "pretty-format": ["pretty-format@3.8.0", "", {}, "sha512-WuxUnVtlWL1OfZFQFuqvnvs6MiAGk9UNsBostyBOB0Is9wb5uRESevA6rnl/rkksXaGX3GzZhPup5d6Vp1nFew=="], - "react": ["react@19.2.3", "", {}, "sha512-Ku/hhYbVjOQnXDZFv2+RibmLFGwFdeeKHFcOTlrt7xplBnya5OGn/hIRDsqDiSUcfORsDC7MPxwork8jBwsIWA=="], + "queue-microtask": ["queue-microtask@1.2.3", "", {}, "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A=="], - "react-dom": ["react-dom@19.2.3", "", { "dependencies": { "scheduler": "^0.27.0" }, "peerDependencies": { "react": "^19.2.3" } }, "sha512-yELu4WmLPw5Mr/lmeEpox5rw3RETacE++JgHqQzd2dg+YbJuat3jH4ingc+WPZhxaoFzdv9y33G+F7Nl5O0GBg=="], + "rc9": ["rc9@2.1.2", "", { "dependencies": { "defu": "^6.1.4", "destr": "^2.0.3" } }, "sha512-btXCnMmRIBINM2LDZoEmOogIZU7Qe7zn4BpomSKZ/ykbLObuBdvG+mFq11DL6fjH1DRwHhrlgtYWG96bJiC7Cg=="], + + "react": ["react@19.2.4", "", {}, "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ=="], + + "react-dom": ["react-dom@19.2.4", "", { "dependencies": { "scheduler": "^0.27.0" }, "peerDependencies": { "react": "^19.2.4" } }, "sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ=="], + + "react-error-boundary": ["react-error-boundary@6.1.0", "", { "peerDependencies": { "react": "^18.0.0 || ^19.0.0" } }, "sha512-02k9WQ/mUhdbXir0tC1NiMesGzRPaCsJEWU/4bcFrbY1YMZOtHShtZP6zw0SJrBWA/31H0KT9/FgdL8+sPKgHA=="], + + "react-hot-toast": ["react-hot-toast@2.6.0", "", { "dependencies": { "csstype": "^3.1.3", "goober": "^2.1.16" }, "peerDependencies": { "react": ">=16", "react-dom": ">=16" } }, "sha512-bH+2EBMZ4sdyou/DPrfgIouFpcRLCJ+HoCA32UoAYHn6T3Ur5yfcDCeSr5mwldl6pFOsiocmrXMuoCJ1vV8bWg=="], "react-refresh": ["react-refresh@0.18.0", "", {}, "sha512-QgT5//D3jfjJb6Gsjxv0Slpj23ip+HtOpnNgnb2S5zU3CB26G/IDPGoy4RJB42wzFE46DRsstbW6tKHoKbhAxw=="], - "readable-stream": ["readable-stream@4.7.0", "", { "dependencies": { "abort-controller": "^3.0.0", "buffer": "^6.0.3", "events": "^3.3.0", "process": "^0.11.10", "string_decoder": "^1.3.0" } }, "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg=="], - - "readdir-glob": ["readdir-glob@1.1.3", "", { "dependencies": { "minimatch": "^5.1.0" } }, "sha512-v05I2k7xN8zXvPD9N+z/uhXPaj0sUFCe2rcWZIpBsqxfP7xXFQ0tipAd/wjj1YxWyWtUS5IDJpOG82JKt2EAVA=="], - "readdirp": ["readdirp@3.6.0", "", { "dependencies": { "picomatch": "^2.2.1" } }, "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA=="], "recast": ["recast@0.23.11", "", { "dependencies": { "ast-types": "^0.16.1", "esprima": "~4.0.0", "source-map": "~0.6.1", "tiny-invariant": "^1.3.3", "tslib": "^2.0.1" } }, "sha512-YTUo+Flmw4ZXiWfQKGcwwc11KnoRAYgzAE2E7mXKCjSviTKShtxBsN6YUUBB2gtaBzKzeKunxhUwNHQuRryhWA=="], "require-directory": ["require-directory@2.1.1", "", {}, "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q=="], + "require-from-string": ["require-from-string@2.0.2", "", {}, "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw=="], + "resolve-pkg-maps": ["resolve-pkg-maps@1.0.0", "", {}, "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw=="], + "reusify": ["reusify@1.1.0", "", {}, "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw=="], + "rollup": ["rollup@4.56.0", "", { "dependencies": { "@types/estree": "1.0.8" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.56.0", "@rollup/rollup-android-arm64": "4.56.0", "@rollup/rollup-darwin-arm64": "4.56.0", "@rollup/rollup-darwin-x64": "4.56.0", "@rollup/rollup-freebsd-arm64": "4.56.0", "@rollup/rollup-freebsd-x64": "4.56.0", "@rollup/rollup-linux-arm-gnueabihf": "4.56.0", "@rollup/rollup-linux-arm-musleabihf": "4.56.0", "@rollup/rollup-linux-arm64-gnu": "4.56.0", "@rollup/rollup-linux-arm64-musl": "4.56.0", "@rollup/rollup-linux-loong64-gnu": "4.56.0", "@rollup/rollup-linux-loong64-musl": "4.56.0", "@rollup/rollup-linux-ppc64-gnu": "4.56.0", "@rollup/rollup-linux-ppc64-musl": "4.56.0", "@rollup/rollup-linux-riscv64-gnu": "4.56.0", "@rollup/rollup-linux-riscv64-musl": "4.56.0", "@rollup/rollup-linux-s390x-gnu": "4.56.0", "@rollup/rollup-linux-x64-gnu": "4.56.0", "@rollup/rollup-linux-x64-musl": "4.56.0", "@rollup/rollup-openbsd-x64": "4.56.0", "@rollup/rollup-openharmony-arm64": "4.56.0", "@rollup/rollup-win32-arm64-msvc": "4.56.0", "@rollup/rollup-win32-ia32-msvc": "4.56.0", "@rollup/rollup-win32-x64-gnu": "4.56.0", "@rollup/rollup-win32-x64-msvc": "4.56.0", "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-9FwVqlgUHzbXtDg9RCMgodF3Ua4Na6Gau+Sdt9vyCN4RhHfVKX2DCHy3BjMLTDd47ITDhYAnTwGulWTblJSDLg=="], - "rpc-anywhere": ["rpc-anywhere@1.5.0", "", { "dependencies": { "browser-namespace": "^1.4.0" } }, "sha512-ZYrB0foAM4oE7oBnUH3BL7LwtW9d6+RkzL/rFnjj8GCaFt5c81Rbw6oVl6u9AMsGONsKeJX0mL62TpbPXSO6og=="], + "run-applescript": ["run-applescript@7.1.0", "", {}, "sha512-DPe5pVFaAsinSaV6QjQ6gdiedWDcRCbUuiQfQa2wmWV7+xC9bGulGI8+TdRmoFkAPaBXk8CrAbnlY2ISniJ47Q=="], + + "run-parallel": ["run-parallel@1.2.0", "", { "dependencies": { "queue-microtask": "^1.2.2" } }, "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA=="], "rxjs": ["rxjs@7.8.2", "", { "dependencies": { "tslib": "^2.1.0" } }, "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA=="], - "safe-buffer": ["safe-buffer@5.2.1", "", {}, "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="], - "scheduler": ["scheduler@0.27.0", "", {}, "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q=="], - "semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], + "semver": ["semver@7.7.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="], "seroval": ["seroval@1.4.2", "", {}, "sha512-N3HEHRCZYn3cQbsC4B5ldj9j+tHdf4JZoYPlcI4rRYu0Xy4qN8MQf1Z08EibzB0WpgRG5BGK08FTrmM66eSzKQ=="], @@ -555,89 +725,99 @@ "shell-quote": ["shell-quote@1.8.3", "", {}, "sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw=="], - "signal-exit": ["signal-exit@4.1.0", "", {}, "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw=="], - "source-map": ["source-map@0.7.6", "", {}, "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ=="], "source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="], - "streamx": ["streamx@2.22.1", "", { "dependencies": { "fast-fifo": "^1.3.2", "text-decoder": "^1.1.0" }, "optionalDependencies": { "bare-events": "^2.2.0" } }, "sha512-znKXEBxfatz2GBNK02kRnCXjV+AA4kjZIUxeWSr3UGirZMJfTE9uiwKHobnbgxWyL/JWro8tTq+vOqAK1/qbSA=="], - "string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], - "string-width-cjs": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], - - "string_decoder": ["string_decoder@1.3.0", "", { "dependencies": { "safe-buffer": "~5.2.0" } }, "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA=="], - "strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], - "strip-ansi-cjs": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], + "strtok3": ["strtok3@10.3.4", "", { "dependencies": { "@tokenizer/token": "^0.3.0" } }, "sha512-KIy5nylvC5le1OdaaoCJ07L+8iQzJHGH6pWDuzS+d07Cu7n1MZ2x26P8ZKIWfbK02+XIL8Mp4RkWeqdUCrDMfg=="], + + "stubborn-fs": ["stubborn-fs@2.0.0", "", { "dependencies": { "stubborn-utils": "^1.0.1" } }, "sha512-Y0AvSwDw8y+nlSNFXMm2g6L51rBGdAQT20J3YSOqxC53Lo3bjWRtr2BKcfYoAf352WYpsZSTURrA0tqhfgudPA=="], + + "stubborn-utils": ["stubborn-utils@1.0.2", "", {}, "sha512-zOh9jPYI+xrNOyisSelgym4tolKTJCQd5GBhK0+0xJvcYDcwlOoxF/rnFKQ2KRZknXSG9jWAp66fwP6AxN9STg=="], "supports-color": ["supports-color@8.1.1", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q=="], + "svgo": ["svgo@3.3.2", "", { "dependencies": { "@trysound/sax": "0.2.0", "commander": "^7.2.0", "css-select": "^5.1.0", "css-tree": "^2.3.1", "css-what": "^6.1.0", "csso": "^5.0.5", "picocolors": "^1.0.0" }, "bin": "./bin/svgo" }, "sha512-OoohrmuUlBs8B8o6MB2Aevn+pRIH9zDALSR+6hhqVfa6fRwG/Qw9VUMSMW9VNg2CFc/MTIfabtdOVl9ODIJjpw=="], + + "tagged-tag": ["tagged-tag@1.0.0", "", {}, "sha512-yEFYrVhod+hdNyx7g5Bnkkb0G6si8HJurOoOEgC8B/O0uXLHlaey/65KRv6cuWBNhBgHKAROVpc7QyYqE5gFng=="], + + "tailwind-merge": ["tailwind-merge@3.4.0", "", {}, "sha512-uSaO4gnW+b3Y2aWoWfFpX62vn2sR3skfhbjsEnaBI81WD1wBLlHZe5sWf0AqjksNdYTbGBEd0UasQMT3SNV15g=="], + "tailwindcss": ["tailwindcss@4.1.18", "", {}, "sha512-4+Z+0yiYyEtUVCScyfHCxOYP06L5Ne+JiHhY2IjR2KWMIWhJOYZKLSGZaP5HkZ8+bY0cxfzwDE5uOmzFXyIwxw=="], + "tailwindcss-animate": ["tailwindcss-animate@1.0.7", "", { "peerDependencies": { "tailwindcss": ">=3.0.0 || insiders" } }, "sha512-bl6mpH3T7I3UFxuvDEXLxy/VuFxBk5bbzplh7tXI68mwMokNYd1t9qPBHlnyTwfa4JGC4zP516I1hYYtQ/vspA=="], + "tapable": ["tapable@2.3.0", "", {}, "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg=="], - "tar": ["tar@6.2.1", "", { "dependencies": { "chownr": "^2.0.0", "fs-minipass": "^2.0.0", "minipass": "^5.0.0", "minizlib": "^2.1.1", "mkdirp": "^1.0.3", "yallist": "^4.0.0" } }, "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A=="], - - "tar-stream": ["tar-stream@3.1.7", "", { "dependencies": { "b4a": "^1.6.4", "fast-fifo": "^1.2.0", "streamx": "^2.15.0" } }, "sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ=="], - - "text-decoder": ["text-decoder@1.2.3", "", { "dependencies": { "b4a": "^1.6.4" } }, "sha512-3/o9z3X0X0fTupwsYvR03pJ/DjWuqqrfwBgTQzdWDiQSm9KitAyz/9WqsT2JQW7KV2m+bC2ol/zqpW37NHxLaA=="], - "tiny-invariant": ["tiny-invariant@1.3.3", "", {}, "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg=="], "tiny-warning": ["tiny-warning@1.0.3", "", {}, "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA=="], + "tinyexec": ["tinyexec@1.0.2", "", {}, "sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg=="], + "tinyglobby": ["tinyglobby@0.2.15", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.3" } }, "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ=="], "to-regex-range": ["to-regex-range@5.0.1", "", { "dependencies": { "is-number": "^7.0.0" } }, "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ=="], + "token-types": ["token-types@6.1.2", "", { "dependencies": { "@borewit/text-codec": "^0.2.1", "@tokenizer/token": "^0.3.0", "ieee754": "^1.2.1" } }, "sha512-dRXchy+C0IgK8WPC6xvCHFRIWYUbqqdEIKPaKo/AcTUNzwLTK6AH7RjdLWsEZcAN/TBdtfUw3PYEgPr5VPr6ww=="], + "tree-kill": ["tree-kill@1.2.2", "", { "bin": { "tree-kill": "cli.js" } }, "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A=="], "tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], "tsx": ["tsx@4.21.0", "", { "dependencies": { "esbuild": "~0.27.0", "get-tsconfig": "^4.7.5" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "bin": { "tsx": "dist/cli.mjs" } }, "sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw=="], + "type-fest": ["type-fest@5.4.1", "", { "dependencies": { "tagged-tag": "^1.0.0" } }, "sha512-xygQcmneDyzsEuKZrFbRMne5HDqMs++aFzefrJTgEIKjQ3rekM+RPfFCVq2Gp1VIDqddoYeppCj4Pcb+RZW0GQ=="], + "typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="], + "uint8array-extras": ["uint8array-extras@1.5.0", "", {}, "sha512-rvKSBiC5zqCCiDZ9kAOszZcDvdAHwwIKJG33Ykj43OKcWsnmcBRL09YTU4nOeHZ8Y2a7l1MgTd08SBe9A8Qj6A=="], + "undici-types": ["undici-types@7.8.0", "", {}, "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw=="], + "universalify": ["universalify@2.0.1", "", {}, "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw=="], + "unplugin": ["unplugin@2.3.11", "", { "dependencies": { "@jridgewell/remapping": "^2.3.5", "acorn": "^8.15.0", "picomatch": "^4.0.3", "webpack-virtual-modules": "^0.6.2" } }, "sha512-5uKD0nqiYVzlmCRs01Fhs2BdkEgBS3SAVP6ndrBsuK42iC2+JHyxM05Rm9G8+5mkmRtzMZGY8Ct5+mliZxU/Ww=="], "update-browserslist-db": ["update-browserslist-db@1.2.3", "", { "dependencies": { "escalade": "^3.2.0", "picocolors": "^1.1.1" }, "peerDependencies": { "browserslist": ">= 4.21.0" }, "bin": { "update-browserslist-db": "cli.js" } }, "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w=="], "use-sync-external-store": ["use-sync-external-store@1.6.0", "", { "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w=="], - "util-deprecate": ["util-deprecate@1.0.2", "", {}, "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="], + "usehooks-ts": ["usehooks-ts@3.1.1", "", { "dependencies": { "lodash.debounce": "^4.0.8" }, "peerDependencies": { "react": "^16.8.0 || ^17 || ^18 || ^19 || ^19.0.0-rc" } }, "sha512-I4diPp9Cq6ieSUH2wu+fDAVQO43xwtulo+fKEidHUwZPnYImbtkTjzIJYcDcJqxgmX31GVqNFURodvcgHcW0pA=="], "vite": ["vite@7.3.1", "", { "dependencies": { "esbuild": "^0.27.0", "fdir": "^6.5.0", "picomatch": "^4.0.3", "postcss": "^8.5.6", "rollup": "^4.43.0", "tinyglobby": "^0.2.15" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", "jiti": ">=1.21.0", "less": "^4.0.0", "lightningcss": "^1.21.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA=="], + "vite-plugin-svg-icons-ng": ["vite-plugin-svg-icons-ng@1.5.2", "", { "dependencies": { "fast-glob": "^3.3.3", "fs-extra": "^11.3.2", "node-html-parser": "^7.0.1", "svgo": "^3.3.2" }, "peerDependencies": { "vite": ">=5.0.0" } }, "sha512-A68obs8XDT+q8q8dKyjrT/v0qw8h5pEBKXJ27aUXjARYeJ6MNvhIhRLLiUwnSrbn/B4TBF4UVaWRXKftAqP7+A=="], + + "vite-static-assets-plugin": ["vite-static-assets-plugin@1.2.2", "", { "dependencies": { "chalk": "^5.4.1", "chokidar": "^3.5.3", "minimatch": "^10.0.1" }, "peerDependencies": { "typescript": "^5.0.0", "vite": "^6.2.0" } }, "sha512-0mzHsxFa46Np5AixQcdWYLVH6eJxeok7qL7tXmxYavg/Uo0e5z+J6gavJ0TJ6dmJSe2Z+gwmDb64bCCZfg+gqA=="], + "webpack-virtual-modules": ["webpack-virtual-modules@0.6.2", "", {}, "sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ=="], + "when-exit": ["when-exit@2.1.5", "", {}, "sha512-VGkKJ564kzt6Ms1dbgPP/yuIoQCrsFAnRbptpC5wOEsDaNsbCB2bnfnaA8i/vRs5tjUSEOtIuvl9/MyVsvQZCg=="], + "which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="], "wrap-ansi": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="], - "wrap-ansi-cjs": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="], + "wsl-utils": ["wsl-utils@0.3.1", "", { "dependencies": { "is-wsl": "^3.1.0", "powershell-utils": "^0.1.0" } }, "sha512-g/eziiSUNBSsdDJtCLB8bdYEUMj4jR7AGeUo96p/3dTafgjHhpF4RiCFPiRILwjQoDXx5MqkBr4fwWtR3Ky4Wg=="], "y18n": ["y18n@5.0.8", "", {}, "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA=="], - "yallist": ["yallist@4.0.0", "", {}, "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="], + "yallist": ["yallist@3.1.1", "", {}, "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="], "yargs": ["yargs@17.7.2", "", { "dependencies": { "cliui": "^8.0.1", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", "string-width": "^4.2.3", "y18n": "^5.0.5", "yargs-parser": "^21.1.1" } }, "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w=="], "yargs-parser": ["yargs-parser@21.1.1", "", {}, "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw=="], - "zip-stream": ["zip-stream@6.0.1", "", { "dependencies": { "archiver-utils": "^5.0.0", "compress-commons": "^6.0.2", "readable-stream": "^4.0.0" } }, "sha512-zK7YHHz4ZXpW89AHXUPbQVGKI7uvkd3hzusTdotCg1UxyaVtg0zFJSTfW/Dq5f7OBBVnq6cZIaC8Ti4hb6dtCA=="], + "zod": ["zod@4.3.6", "", {}, "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg=="], - "zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], + "@babel/core/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], - "@isaacs/cliui/string-width": ["string-width@5.1.2", "", { "dependencies": { "eastasianwidth": "^0.2.0", "emoji-regex": "^9.2.2", "strip-ansi": "^7.0.1" } }, "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA=="], - - "@isaacs/cliui/strip-ansi": ["strip-ansi@7.1.0", "", { "dependencies": { "ansi-regex": "^6.0.1" } }, "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ=="], - - "@isaacs/cliui/wrap-ansi": ["wrap-ansi@8.1.0", "", { "dependencies": { "ansi-styles": "^6.1.0", "string-width": "^5.0.1", "strip-ansi": "^7.0.1" } }, "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ=="], + "@babel/helper-compilation-targets/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], "@tailwindcss/oxide-wasm32-wasi/@emnapi/core": ["@emnapi/core@1.8.1", "", { "dependencies": { "@emnapi/wasi-threads": "1.1.0", "tslib": "^2.4.0" }, "bundled": true }, "sha512-AvT9QFpxK0Zd8J0jopedNm+w/2fIzvtPKPjqyw9jwvBaReTTqPBk9Hixaz7KbjimP+QNz605/XnjFcDAL2pqBg=="], @@ -651,38 +831,34 @@ "@tailwindcss/oxide-wasm32-wasi/tslib": ["tslib@2.8.1", "", { "bundled": true }, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], + "@tanstack/router-generator/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], + + "@tanstack/router-plugin/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], + "anymatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], + "c12/chokidar": ["chokidar@5.0.0", "", { "dependencies": { "readdirp": "^5.0.0" } }, "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw=="], + "chalk/supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="], - "fs-minipass/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="], + "csso/css-tree": ["css-tree@2.2.1", "", { "dependencies": { "mdn-data": "2.0.28", "source-map-js": "^1.0.1" } }, "sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA=="], - "glob/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="], + "elysia/cookie": ["cookie@1.1.1", "", {}, "sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ=="], - "glob/minipass": ["minipass@7.1.2", "", {}, "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw=="], + "micromatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], - "lazystream/readable-stream": ["readable-stream@2.3.8", "", { "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", "isarray": "~1.0.0", "process-nextick-args": "~2.0.0", "safe-buffer": "~5.1.1", "string_decoder": "~1.1.1", "util-deprecate": "~1.0.1" } }, "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA=="], - - "lru-cache/yallist": ["yallist@3.1.1", "", {}, "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="], - - "minizlib/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="], - - "path-scurry/lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="], - - "path-scurry/minipass": ["minipass@7.1.2", "", {}, "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw=="], + "nypm/citty": ["citty@0.2.0", "", {}, "sha512-8csy5IBFI2ex2hTVpaHN2j+LNE199AgiI7y4dMintrr8i0lQiFn+0AWMZrWdHKIgMOer65f8IThysYhoReqjWA=="], "readdirp/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], "recast/source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="], - "@isaacs/cliui/string-width/emoji-regex": ["emoji-regex@9.2.2", "", {}, "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="], + "svgo/commander": ["commander@7.2.0", "", {}, "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw=="], - "@isaacs/cliui/strip-ansi/ansi-regex": ["ansi-regex@6.1.0", "", {}, "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA=="], + "vite-static-assets-plugin/chalk": ["chalk@5.6.2", "", {}, "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA=="], - "@isaacs/cliui/wrap-ansi/ansi-styles": ["ansi-styles@6.2.1", "", {}, "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug=="], + "c12/chokidar/readdirp": ["readdirp@5.0.0", "", {}, "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ=="], - "lazystream/readable-stream/safe-buffer": ["safe-buffer@5.1.2", "", {}, "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="], - - "lazystream/readable-stream/string_decoder": ["string_decoder@1.1.1", "", { "dependencies": { "safe-buffer": "~5.1.0" } }, "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg=="], + "csso/css-tree/mdn-data": ["mdn-data@2.0.28", "", {}, "sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g=="], } } diff --git a/package.json b/package.json index 2e20b23..9d29ca5 100644 --- a/package.json +++ b/package.json @@ -1,36 +1,66 @@ { - "name": "gameflow-deck", + "name": "com.simeonradivoev.gameflow-deck", + "displayName": "Gameflow", "version": "1.0.0", "description": "Game Launcher", + "type": "module", "scripts": { - "dev": "bun run build && electrobun dev", - "dev:hmr": "concurrently \"bun run hmr\" \"bun run dev\"", - "build": "vite build && electrobun build", - "build:canary": "vite build && electrobun build --env=canary", - "build:stable": "vite build && electrobun build --env=stable", - "hmr": "vite --port 5173", - "start": "bun run dev" + "dev": "bun run build:dev && NODE_ENV=development bun run --inspect=127.0.0.1:9229 --watch ./src/bun/index.ts", + "dev:hmr": "PUBLIC_ACCESS=true conc -k 'bun run hmr' 'bun run dev'", + "build": "vite build", + "build:pro": "NODE_ENV=production bun run build", + "build:dev": "NODE_ENV=development bun run build", + "package": "bun run build && bun run ./scripts/package-bun.ts", + "package:auto-prod": "bun run build:pro && NODE_ENV=production bun run ./scripts/package-bun.ts", + "package:linux": "bun run build && TARGET=bun-linux-x64 bun run ./scripts/package-bun.ts", + "openapi-ts": "bun run ./scripts/romm/openapi-ts.ts", + "run:build-action": "act --artifact-server-path artifacts --env ACTIONS_RUNTIME_TOKEN=foo -W .github/workflows/build.yml", + "hmr": "vite --port 5173" }, "dependencies": { - "@tanstack/react-router": "^1.154.12", - "@tanstack/router-plugin": "^1.154.12", - "classnames": "^2.5.1", - "electrobun": "latest", - "gamepad.css": "^0.0.4", - "lucide-react": "^0.562.0", - "react": "^19.2.3", - "react-dom": "^19.2.3" + "@auth/core": "^0.34.3", + "@elysiajs/cors": "^1.4.1", + "@elysiajs/eden": "^1.4.6", + "@elysiajs/static": "^1.4.7", + "@rcompat/webview": "^0.18.0", + "conf": "^15.0.2", + "elysia": "^1.4.22", + "pathe": "^2.0.3", + "zod": "^4.3.6" }, "devDependencies": { + "@hey-api/openapi-ts": "^0.91.0", + "@noriginmedia/norigin-spatial-navigation": "^2.3.0", "@tailwindcss/vite": "^4.1.18", + "@tanstack/react-query": "^5.90.20", + "@tanstack/react-query-devtools": "^5.91.3", + "@tanstack/react-router": "^1.157.16", "@tanstack/react-router-devtools": "^1.154.12", + "@tanstack/react-router-ssr-query": "^1.157.17", + "@tanstack/router-plugin": "^1.157.16", "@types/bun": "latest", "@types/react": "^19.2.9", "@types/react-dom": "^19.2.3", "@vitejs/plugin-react": "^5.1.2", + "animate.css": "^4.1.1", + "babel-plugin-react-compiler": "^1.0.0", + "classnames": "^2.5.1", "concurrently": "^9.2.1", + "cross-env": "^10.1.0", + "daisyui": "^5.5.14", + "lucide-react": "^0.563.0", + "pretty-bytes": "^7.1.0", + "react": "^19.2.4", + "react-dom": "^19.2.4", + "react-error-boundary": "^6.1.0", + "react-hot-toast": "^2.6.0", + "tailwind-merge": "^3.4.0", "tailwindcss": "^4.1.18", + "tailwindcss-animate": "^1.0.7", "typescript": "^5.9.3", - "vite": "^7.3.1" + "usehooks-ts": "^3.1.1", + "vite": "^7.3.1", + "vite-plugin-svg-icons-ng": "^1.5.2", + "vite-static-assets-plugin": "^1.2.2" } } \ No newline at end of file diff --git a/scripts/package-bun.ts b/scripts/package-bun.ts new file mode 100644 index 0000000..fba4a8f --- /dev/null +++ b/scripts/package-bun.ts @@ -0,0 +1,85 @@ +import { PluginBuilder } from "bun"; +import fs from "node:fs/promises"; +import path, { resolve, sep } from "node:path"; +import os from "node:os"; +import appPackage from '../package.json'; + +const plugin = { + name: "dist-absolute-filter", + setup (build: PluginBuilder) + { + build.onStart(async () => + { + if (await fs.exists('./build')) + { + await fs.rm('./build', { recursive: true }); + } + }); + // 1. Intercept all resolutions to check their REAL path + build.onResolve({ filter: /.*/, namespace: 'file' }, (args) => + { + if (args.path.startsWith(`.${sep}dist`)) + { + return { path: resolve(args.resolveDir, args.path), namespace: "dist_assets" }; + } + }); + build.onLoad({ filter: /.*/, namespace: 'dist_assets' }, async (args) => + { + console.log(args.path); + return { contents: await Bun.file(args.path).bytes(), loader: 'file' }; + }); + }, +}; + +const compileOption: Bun.CompileBuildOptions = { + outfile: "gameflow", + execArgv: ['--windows-hide-console'], + autoloadTsconfig: true, + autoloadPackageJson: true, + autoloadDotenv: true, + autoloadBunfig: true +}; + +if (process.env.TARGET) +{ + compileOption.target = process.env.TARGET as any; +} + +await Bun.build({ + entrypoints: ["./src/bun/index.ts", "./src/bun/webview-worker.ts"], + metafile: true, + compile: compileOption, + outdir: `./build/${os.platform()}`, + root: './src/bun', + define: { + "process.env.IS_BINARY": "true" + }, + minify: true, + sourcemap: "linked", + target: 'bun', + format: 'esm', + loader: { + ".ico": "file" + }, + plugins: [{ + name: "clean build folder", + setup (build) + { + build.onStart(async () => + { + if (await fs.exists(`./build/${os.platform()}`)) + { + const files = await fs.readdir(`./build/${os.platform()}`, { withFileTypes: true }); + for (const file of files) + { + await fs.rm(path.join(file.parentPath, file.name), { recursive: true }); + } + } + }); + build.onEnd(async () => + { + await fs.cp('./dist', `./build/${os.platform()}/dist`, { recursive: true }); + }); + }, + }] +}); \ No newline at end of file diff --git a/scripts/romm/openapi-ts.ts b/scripts/romm/openapi-ts.ts new file mode 100644 index 0000000..54df5ba --- /dev/null +++ b/scripts/romm/openapi-ts.ts @@ -0,0 +1,8 @@ + +import { createClient } from '@hey-api/openapi-ts'; + +createClient({ + input: './scripts/romm/openapi.json', // sign up at app.heyapi.dev + output: './src/clients/romm', + plugins: ['@tanstack/react-query', '@hey-api/client-fetch', '@hey-api/typescript'], +}); \ No newline at end of file diff --git a/scripts/romm/openapi.json b/scripts/romm/openapi.json new file mode 100644 index 0000000..86d3921 --- /dev/null +++ b/scripts/romm/openapi.json @@ -0,0 +1 @@ +{"openapi":"3.1.0","info":{"title":"RomM API","version":"4.6.1"},"paths":{"/api/heartbeat":{"get":{"tags":["system"],"summary":"Heartbeat","description":"Endpoint to set the CSRF token in cache and return all the basic RomM config\n\nReturns:\n HeartbeatReturn: TypedDict structure with all the defined values in the HeartbeatReturn class.","operationId":"heartbeat_api_heartbeat_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HeartbeatResponse"}}}}}}},"/api/heartbeat/metadata/{source}":{"get":{"tags":["system"],"summary":"Metadata Heartbeat","description":"Endpoint to return the heartbeat of the metadata sources","operationId":"metadata_heartbeat_api_heartbeat_metadata__source__get","parameters":[{"name":"source","in":"path","required":true,"schema":{"type":"string","title":"Source"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"boolean","title":"Response Metadata Heartbeat Api Heartbeat Metadata Source Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/setup/library":{"get":{"tags":["system"],"summary":"Get Setup Library Info","description":"Get library structure information for setup wizard.\n\nOnly accessible during initial setup (no admin users) or with authentication.\n\nReturns:\n - detected_structure: \"struct_a\" (roms/{platform}), \"struct_b\" ({platform}/roms), or None\n - existing_platforms: list of objects with fs_slug and rom_count\n - supported_platforms: list of all supported platforms with metadata","operationId":"get_setup_library_info_api_setup_library_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"OAuth2PasswordBearer":[]},{"HTTPBasic":[]}]}},"/api/setup/platforms":{"post":{"tags":["system"],"summary":"Create Setup Platforms","description":"Create platform folders during setup wizard.\n\nOnly accessible during initial setup (no admin users) or with authentication.\n\nArgs:\n platform_slugs: List of platform fs_slugs to create\n\nReturns:\n - success: bool\n - created_count: number of platforms created\n - message: success or error message","operationId":"create_setup_platforms_api_setup_platforms_post","requestBody":{"content":{"application/json":{"schema":{"items":{"type":"string"},"type":"array","title":"Platform Slugs"}}},"required":true},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"OAuth2PasswordBearer":[]},{"HTTPBasic":[]}]}},"/api/login":{"post":{"tags":["auth"],"summary":"Login","description":"Session login endpoint\n\nArgs:\n request (Request): Fastapi Request object\n credentials: Defaults to Depends(HTTPBasic()).\n\nRaises:\n CredentialsException: Invalid credentials\n UserDisabledException: Auth is disabled","operationId":"login_api_login_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"HTTPBasic":[]}]}},"/api/logout":{"post":{"tags":["auth"],"summary":"Logout","description":"Session logout endpoint\n\nArgs:\n request (Request): Fastapi Request object","operationId":"logout_api_logout_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/token":{"post":{"tags":["auth"],"summary":"Token","description":"OAuth2 token endpoint\n\nArgs:\n form_data (Annotated[OAuth2RequestForm, Depends): Form Data with OAuth2 info\n\nRaises:\n HTTPException: Missing refresh token\n HTTPException: Invalid refresh token\n HTTPException: Missing username or password\n HTTPException: Invalid username or password\n HTTPException: Client credentials are not yet supported\n HTTPException: Invalid or unsupported grant type\n HTTPException: Insufficient scope\n\nReturns:\n TokenResponse: TypedDict with the new generated token info","operationId":"token_api_token_post","requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_token_api_token_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TokenResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/login/openid":{"get":{"tags":["auth"],"summary":"Login Via Openid","description":"OIDC login endpoint\n\nArgs:\n request (Request): Fastapi Request object\n\nRaises:\n OIDCDisabledException: OAuth is disabled\n OIDCNotConfiguredException: OAuth not configured\n\nReturns:\n RedirectResponse: Redirect to OIDC provider","operationId":"login_via_openid_api_login_openid_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/oauth/openid":{"get":{"tags":["auth"],"summary":"Auth Openid","description":"OIDC callback endpoint\n\nArgs:\n request (Request): Fastapi Request object\n\nRaises:\n OIDCDisabledException: OAuth is disabled\n OIDCNotConfiguredException: OAuth not configured\n AuthCredentialsException: Invalid credentials\n UserDisabledException: Auth is disabled\n\nReturns:\n RedirectResponse: Redirect to home page","operationId":"auth_openid_api_oauth_openid_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/forgot-password":{"post":{"tags":["auth"],"summary":"Request Password Reset","description":"Request a password reset link for the user.\n\nArgs:\n username (str): Username of the user requesting the reset\nReturns:\n None: Returns 200 OK status","operationId":"request_password_reset_api_forgot_password_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Body_request_password_reset_api_forgot_password_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/reset-password":{"post":{"tags":["auth"],"summary":"Reset Password","description":"Reset password using the token.\n\nArgs:\n token (str): Reset token from the URL\n new_password (str): New user password\n\nReturns:\n None: Returns 200 OK status","operationId":"reset_password_api_reset_password_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Body_reset_password_api_reset_password_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/users":{"get":{"tags":["users"],"summary":"Get Users","description":"Get all users endpoint\n\nArgs:\n request (Request): Fastapi Request object\n\nReturns:\n list[UserSchema]: All users stored in the RomM's database","operationId":"get_users_api_users_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/UserSchema"},"type":"array","title":"Response Get Users Api Users Get"}}}}},"security":[{"OAuth2PasswordBearer":["users.read"]},{"HTTPBasic":[]}]},"post":{"tags":["users"],"summary":"Add User","description":"Create user endpoint\n\nArgs:\n request (Request): Fastapi Requests object\n username (str): User username\n password (str): User password\n email (str): User email\n role (str): RomM Role object represented as string\n\nReturns:\n UserSchema: Newly created user","operationId":"add_user_api_users_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Body_add_user_api_users_post"}}},"required":true},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserSchema"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"OAuth2PasswordBearer":[]},{"HTTPBasic":[]}]}},"/api/users/invite-link":{"post":{"tags":["users"],"summary":"Create Invite Link","description":"Create an invite link for a user.\n\nArgs:\n request (Request): FastAPI Request object\n role (str): The role of the user\n\nReturns:\n InviteLinkSchema: Invite link","operationId":"create_invite_link_api_users_invite_link_post","security":[{"OAuth2PasswordBearer":[]},{"HTTPBasic":[]}],"parameters":[{"name":"role","in":"query","required":true,"schema":{"type":"string","title":"Role"}}],"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InviteLinkSchema"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/users/register":{"post":{"tags":["users"],"summary":"Create User From Invite","description":"Create user endpoint with invite link\n\nArgs:\n username (str): User username\n email (str): User email\n password (str): User password\n token (str): Invite link token\n\nReturns:\n UserSchema: Newly created user","operationId":"create_user_from_invite_api_users_register_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Body_create_user_from_invite_api_users_register_post"}}},"required":true},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserSchema"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/users/me":{"get":{"tags":["users"],"summary":"Get Current User","description":"Get current user endpoint\n\nArgs:\n request (Request): Fastapi Request object\n\nReturns:\n UserSchema | None: Current user","operationId":"get_current_user_api_users_me_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/UserSchema"},{"type":"null"}],"title":"Response Get Current User Api Users Me Get"}}}}},"security":[{"OAuth2PasswordBearer":["me.read"]},{"HTTPBasic":[]}]}},"/api/users/{id}":{"get":{"tags":["users"],"summary":"Get User","description":"Get user endpoint\n\nArgs:\n request (Request): Fastapi Request object\n\nReturns:\n UserSchem: User stored in the RomM's database","operationId":"get_user_api_users__id__get","security":[{"OAuth2PasswordBearer":["users.read"]},{"HTTPBasic":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","title":"Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserSchema"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"put":{"tags":["users"],"summary":"Update User","description":"Update user endpoint\n\nArgs:\n request (Request): Fastapi Requests object\n user_id (int): User internal id\n form_data (Annotated[UserUpdateForm, Depends): Form Data with user updated info\n\nRaises:\n HTTPException: User is not found in database\n HTTPException: Username already in use by another user\n\nReturns:\n UserSchema: Updated user info","operationId":"update_user_api_users__id__put","security":[{"OAuth2PasswordBearer":["me.write"]},{"HTTPBasic":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","title":"Id"}}],"requestBody":{"required":true,"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/UserForm"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserSchema"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["users"],"summary":"Delete User","description":"Delete a user by ID.\n\nRaises:\n HTTPException: User is not found in database\n HTTPException: User deleting itself\n HTTPException: User is the last admin user","operationId":"delete_user_api_users__id__delete","security":[{"OAuth2PasswordBearer":["users.write"]},{"HTTPBasic":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","minimum":1,"description":"User internal id.","title":"Id"},"description":"User internal id."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"400":{"description":"Bad Request"},"404":{"description":"Not Found"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/users/{id}/ra/refresh":{"post":{"tags":["users"],"summary":"Refresh RetroAchievements","description":"Refresh RetroAchievements progression data for a user.","operationId":"refresh_retro_achievements_api_users__id__ra_refresh_post","security":[{"OAuth2PasswordBearer":["me.write"]},{"HTTPBasic":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","minimum":1,"description":"User internal id.","title":"Id"},"description":"User internal id."}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Body_refresh_retro_achievements_api_users__id__ra_refresh_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"404":{"description":"Not Found"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/platforms":{"post":{"tags":["platforms"],"summary":"Add Platform","description":"Create a platform.","operationId":"add_platform_api_platforms_post","security":[{"OAuth2PasswordBearer":["platforms.write"]},{"HTTPBasic":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Body_add_platform_api_platforms_post"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PlatformSchema"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["platforms"],"summary":"Get Platforms","description":"Retrieve platforms.","operationId":"get_platforms_api_platforms_get","security":[{"OAuth2PasswordBearer":["platforms.read"]},{"HTTPBasic":[]}],"parameters":[{"name":"updated_after","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"Filter platforms updated after this datetime (ISO 8601 format with timezone information).","title":"Updated After"},"description":"Filter platforms updated after this datetime (ISO 8601 format with timezone information)."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PlatformSchema"},"title":"Response Get Platforms Api Platforms Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/platforms/supported":{"get":{"tags":["platforms"],"summary":"Get Supported Platforms Endpoint","description":"Retrieve the list of supported platforms.","operationId":"get_supported_platforms_endpoint_api_platforms_supported_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/PlatformSchema"},"type":"array","title":"Response Get Supported Platforms Endpoint Api Platforms Supported Get"}}}}},"security":[{"OAuth2PasswordBearer":["platforms.read"]},{"HTTPBasic":[]}]}},"/api/platforms/{id}":{"get":{"tags":["platforms"],"summary":"Get Platform","description":"Retrieve a platform by ID.","operationId":"get_platform_api_platforms__id__get","security":[{"OAuth2PasswordBearer":["platforms.read"]},{"HTTPBasic":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","minimum":1,"description":"Platform id.","title":"Id"},"description":"Platform id."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PlatformSchema"}}}},"404":{"description":"Not Found"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"put":{"tags":["platforms"],"summary":"Update Platform","description":"Update a platform.","operationId":"update_platform_api_platforms__id__put","security":[{"OAuth2PasswordBearer":["platforms.write"]},{"HTTPBasic":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","minimum":1,"description":"Platform id.","title":"Id"},"description":"Platform id."}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Body_update_platform_api_platforms__id__put"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PlatformSchema"}}}},"404":{"description":"Not Found"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["platforms"],"summary":"Delete Platform","description":"Delete a platform by ID.","operationId":"delete_platform_api_platforms__id__delete","security":[{"OAuth2PasswordBearer":["platforms.write"]},{"HTTPBasic":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","minimum":1,"description":"Platform id.","title":"Id"},"description":"Platform id."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"404":{"description":"Not Found"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/roms":{"post":{"tags":["roms"],"summary":"Add Rom","description":"Upload a single rom.","operationId":"add_rom_api_roms_post","security":[{"OAuth2PasswordBearer":["roms.write"]},{"HTTPBasic":[]}],"parameters":[{"name":"x-upload-platform","in":"header","required":true,"schema":{"type":"integer","minimum":1,"description":"Platform internal id.","title":"X-Upload-Platform"},"description":"Platform internal id."},{"name":"x-upload-filename","in":"header","required":true,"schema":{"type":"string","description":"The name of the file being uploaded.","title":"X-Upload-Filename"},"description":"The name of the file being uploaded."}],"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"400":{"description":"Bad Request"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["roms"],"summary":"Get Roms","description":"Retrieve roms.","operationId":"get_roms_api_roms_get","security":[{"OAuth2PasswordBearer":["roms.read"]},{"HTTPBasic":[]}],"parameters":[{"name":"with_char_index","in":"query","required":false,"schema":{"type":"boolean","description":"Whether to get the char index.","default":true,"title":"With Char Index"},"description":"Whether to get the char index."},{"name":"with_filter_values","in":"query","required":false,"schema":{"type":"boolean","description":"Whether to return filter values.","default":true,"title":"With Filter Values"},"description":"Whether to return filter values."},{"name":"search_term","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Search term to filter roms.","title":"Search Term"},"description":"Search term to filter roms."},{"name":"platform_ids","in":"query","required":false,"schema":{"anyOf":[{"type":"array","items":{"type":"integer"}},{"type":"null"}],"description":"Platform internal ids. Multiple values are allowed by repeating the parameter, and results that match any of the values will be returned.","title":"Platform Ids"},"description":"Platform internal ids. Multiple values are allowed by repeating the parameter, and results that match any of the values will be returned."},{"name":"collection_id","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","minimum":1},{"type":"null"}],"description":"Collection internal id.","title":"Collection Id"},"description":"Collection internal id."},{"name":"virtual_collection_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Virtual collection internal id.","title":"Virtual Collection Id"},"description":"Virtual collection internal id."},{"name":"smart_collection_id","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","minimum":1},{"type":"null"}],"description":"Smart collection internal id.","title":"Smart Collection Id"},"description":"Smart collection internal id."},{"name":"matched","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"description":"Whether the rom matched at least one metadata source.","title":"Matched"},"description":"Whether the rom matched at least one metadata source."},{"name":"favorite","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"description":"Whether the rom is marked as favorite.","title":"Favorite"},"description":"Whether the rom is marked as favorite."},{"name":"duplicate","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"description":"Whether the rom is marked as duplicate.","title":"Duplicate"},"description":"Whether the rom is marked as duplicate."},{"name":"last_played","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"description":"Whether the rom has a last played value for the current user.","title":"Last Played"},"description":"Whether the rom has a last played value for the current user."},{"name":"playable","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"description":"Whether the rom is playable from the browser.","title":"Playable"},"description":"Whether the rom is playable from the browser."},{"name":"missing","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"description":"Whether the rom is missing from the filesystem.","title":"Missing"},"description":"Whether the rom is missing from the filesystem."},{"name":"has_ra","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"description":"Whether the rom has RetroAchievements data.","title":"Has Ra"},"description":"Whether the rom has RetroAchievements data."},{"name":"verified","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"description":"Whether the rom is verified by Hasheous.","title":"Verified"},"description":"Whether the rom is verified by Hasheous."},{"name":"group_by_meta_id","in":"query","required":false,"schema":{"type":"boolean","description":"Whether to group roms by metadata ID (IGDB / Moby / ScreenScraper / RetroAchievements / LaunchBox).","default":false,"title":"Group By Meta Id"},"description":"Whether to group roms by metadata ID (IGDB / Moby / ScreenScraper / RetroAchievements / LaunchBox)."},{"name":"genres","in":"query","required":false,"schema":{"anyOf":[{"type":"array","items":{"type":"string"}},{"type":"null"}],"description":"Associated genre. Multiple values are allowed by repeating the parameter, and results that match any of the values will be returned.","title":"Genres"},"description":"Associated genre. Multiple values are allowed by repeating the parameter, and results that match any of the values will be returned."},{"name":"franchises","in":"query","required":false,"schema":{"anyOf":[{"type":"array","items":{"type":"string"}},{"type":"null"}],"description":"Associated franchise. Multiple values are allowed by repeating the parameter, and results that match any of the values will be returned.","title":"Franchises"},"description":"Associated franchise. Multiple values are allowed by repeating the parameter, and results that match any of the values will be returned."},{"name":"collections","in":"query","required":false,"schema":{"anyOf":[{"type":"array","items":{"type":"string"}},{"type":"null"}],"description":"Associated collection. Multiple values are allowed by repeating the parameter, and results that match any of the values will be returned.","title":"Collections"},"description":"Associated collection. Multiple values are allowed by repeating the parameter, and results that match any of the values will be returned."},{"name":"companies","in":"query","required":false,"schema":{"anyOf":[{"type":"array","items":{"type":"string"}},{"type":"null"}],"description":"Associated company. Multiple values are allowed by repeating the parameter, and results that match any of the values will be returned.","title":"Companies"},"description":"Associated company. Multiple values are allowed by repeating the parameter, and results that match any of the values will be returned."},{"name":"age_ratings","in":"query","required":false,"schema":{"anyOf":[{"type":"array","items":{"type":"string"}},{"type":"null"}],"description":"Associated age rating. Multiple values are allowed by repeating the parameter, and results that match any of the values will be returned.","title":"Age Ratings"},"description":"Associated age rating. Multiple values are allowed by repeating the parameter, and results that match any of the values will be returned."},{"name":"statuses","in":"query","required":false,"schema":{"anyOf":[{"type":"array","items":{"type":"string"}},{"type":"null"}],"description":"Game status, set by the current user. Multiple values are allowed by repeating the parameter, and results that match any of the values will be returned.","title":"Statuses"},"description":"Game status, set by the current user. Multiple values are allowed by repeating the parameter, and results that match any of the values will be returned."},{"name":"regions","in":"query","required":false,"schema":{"anyOf":[{"type":"array","items":{"type":"string"}},{"type":"null"}],"description":"Associated region tag. Multiple values are allowed by repeating the parameter, and results that match any of the values will be returned.","title":"Regions"},"description":"Associated region tag. Multiple values are allowed by repeating the parameter, and results that match any of the values will be returned."},{"name":"languages","in":"query","required":false,"schema":{"anyOf":[{"type":"array","items":{"type":"string"}},{"type":"null"}],"description":"Associated language tag. Multiple values are allowed by repeating the parameter, and results that match any of the values will be returned.","title":"Languages"},"description":"Associated language tag. Multiple values are allowed by repeating the parameter, and results that match any of the values will be returned."},{"name":"player_counts","in":"query","required":false,"schema":{"anyOf":[{"type":"array","items":{"type":"string"}},{"type":"null"}],"description":"Associated player count. Multiple values are allowed by repeating the parameter, and results that match any of the values will be returned.","title":"Player Counts"},"description":"Associated player count. Multiple values are allowed by repeating the parameter, and results that match any of the values will be returned."},{"name":"genres_logic","in":"query","required":false,"schema":{"type":"string","description":"Logic operator for genres filter: 'any' (OR), 'all' (AND) or 'none' (NOT).","default":"any","title":"Genres Logic"},"description":"Logic operator for genres filter: 'any' (OR), 'all' (AND) or 'none' (NOT)."},{"name":"franchises_logic","in":"query","required":false,"schema":{"type":"string","description":"Logic operator for franchises filter: 'any' (OR), 'all' (AND) or 'none' (NOT).","default":"any","title":"Franchises Logic"},"description":"Logic operator for franchises filter: 'any' (OR), 'all' (AND) or 'none' (NOT)."},{"name":"collections_logic","in":"query","required":false,"schema":{"type":"string","description":"Logic operator for collections filter: 'any' (OR), 'all' (AND) or 'none' (NOT).","default":"any","title":"Collections Logic"},"description":"Logic operator for collections filter: 'any' (OR), 'all' (AND) or 'none' (NOT)."},{"name":"companies_logic","in":"query","required":false,"schema":{"type":"string","description":"Logic operator for companies filter: 'any' (OR), 'all' (AND) or 'none' (NOT).","default":"any","title":"Companies Logic"},"description":"Logic operator for companies filter: 'any' (OR), 'all' (AND) or 'none' (NOT)."},{"name":"age_ratings_logic","in":"query","required":false,"schema":{"type":"string","description":"Logic operator for age ratings filter: 'any' (OR), 'all' (AND) or 'none' (NOT).","default":"any","title":"Age Ratings Logic"},"description":"Logic operator for age ratings filter: 'any' (OR), 'all' (AND) or 'none' (NOT)."},{"name":"regions_logic","in":"query","required":false,"schema":{"type":"string","description":"Logic operator for regions filter: 'any' (OR), 'all' (AND) or 'none' (NOT).","default":"any","title":"Regions Logic"},"description":"Logic operator for regions filter: 'any' (OR), 'all' (AND) or 'none' (NOT)."},{"name":"languages_logic","in":"query","required":false,"schema":{"type":"string","description":"Logic operator for languages filter: 'any' (OR), 'all' (AND) or 'none' (NOT).","default":"any","title":"Languages Logic"},"description":"Logic operator for languages filter: 'any' (OR), 'all' (AND) or 'none' (NOT)."},{"name":"statuses_logic","in":"query","required":false,"schema":{"type":"string","description":"Logic operator for statuses filter: 'any' (OR), 'all' (AND) or 'none' (NOT).","default":"any","title":"Statuses Logic"},"description":"Logic operator for statuses filter: 'any' (OR), 'all' (AND) or 'none' (NOT)."},{"name":"player_counts_logic","in":"query","required":false,"schema":{"type":"string","description":"Logic operator for player counts filter: 'any' (OR), 'all' (AND) or 'none' (NOT).","default":"any","title":"Player Counts Logic"},"description":"Logic operator for player counts filter: 'any' (OR), 'all' (AND) or 'none' (NOT)."},{"name":"order_by","in":"query","required":false,"schema":{"type":"string","description":"Field to order results by.","default":"name","title":"Order By"},"description":"Field to order results by."},{"name":"order_dir","in":"query","required":false,"schema":{"type":"string","description":"Order direction, either 'asc' or 'desc'.","default":"asc","title":"Order Dir"},"description":"Order direction, either 'asc' or 'desc'."},{"name":"updated_after","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"Filter roms updated after this datetime (ISO 8601 format with timezone information).","title":"Updated After"},"description":"Filter roms updated after this datetime (ISO 8601 format with timezone information)."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":10000,"minimum":1,"description":"Page size limit","default":50,"title":"Limit"},"description":"Page size limit"},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"description":"Page offset","default":0,"title":"Offset"},"description":"Page offset"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomLimitOffsetPage_SimpleRomSchema_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/roms/download":{"get":{"tags":["roms"],"summary":"Download Roms","description":"Download a list of roms as a zip file.","operationId":"download_roms_api_roms_download_get","security":[{"OAuth2PasswordBearer":["roms.read"]},{"HTTPBasic":[]}],"parameters":[{"name":"rom_ids","in":"query","required":true,"schema":{"type":"string","description":"Comma-separated list of ROM IDs to download as a zip file.","title":"Rom Ids"},"description":"Comma-separated list of ROM IDs to download as a zip file."},{"name":"filename","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Name for the zip file (optional).","title":"Filename"},"description":"Name for the zip file (optional)."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/roms/by-metadata-provider":{"get":{"tags":["roms"],"summary":"Get Rom By Metadata Provider","description":"Retrieve a rom by metadata ID.","operationId":"get_rom_by_metadata_provider_api_roms_by_metadata_provider_get","security":[{"OAuth2PasswordBearer":["roms.read"]},{"HTTPBasic":[]}],"parameters":[{"name":"igdb_id","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"description":"IGDB ID to search by","title":"Igdb Id"},"description":"IGDB ID to search by"},{"name":"moby_id","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"description":"MobyGames ID to search by","title":"Moby Id"},"description":"MobyGames ID to search by"},{"name":"ss_id","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"description":"ScreenScraper ID to search by","title":"Ss Id"},"description":"ScreenScraper ID to search by"},{"name":"ra_id","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"description":"RetroAchievements ID to search by","title":"Ra Id"},"description":"RetroAchievements ID to search by"},{"name":"launchbox_id","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"description":"LaunchBox ID to search by","title":"Launchbox Id"},"description":"LaunchBox ID to search by"},{"name":"hasheous_id","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"description":"Hasheous ID to search by","title":"Hasheous Id"},"description":"Hasheous ID to search by"},{"name":"tgdb_id","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"description":"TGDB ID to search by","title":"Tgdb Id"},"description":"TGDB ID to search by"},{"name":"flashpoint_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Flashpoint ID to search by","title":"Flashpoint Id"},"description":"Flashpoint ID to search by"},{"name":"hltb_id","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"description":"HLTB ID to search by","title":"Hltb Id"},"description":"HLTB ID to search by"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DetailedRomSchema"}}}},"404":{"description":"Not Found"},"400":{"description":"Bad Request"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/roms/by-hash":{"get":{"tags":["roms"],"summary":"Get Rom By Hash","operationId":"get_rom_by_hash_api_roms_by_hash_get","security":[{"OAuth2PasswordBearer":["roms.read"]},{"HTTPBasic":[]}],"parameters":[{"name":"crc_hash","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"CRC hash value","title":"Crc Hash"},"description":"CRC hash value"},{"name":"md5_hash","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"MD5 hash value","title":"Md5 Hash"},"description":"MD5 hash value"},{"name":"sha1_hash","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"SHA1 hash value","title":"Sha1 Hash"},"description":"SHA1 hash value"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DetailedRomSchema"}}}},"404":{"description":"Not Found"},"400":{"description":"Bad Request"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/roms/filters":{"get":{"tags":["roms"],"summary":"Get Rom Filters","operationId":"get_rom_filters_api_roms_filters_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RomFiltersDict"}}}}},"security":[{"OAuth2PasswordBearer":["roms.read"]},{"HTTPBasic":[]}]}},"/api/roms/{id}":{"get":{"tags":["roms"],"summary":"Get Rom","description":"Retrieve a rom by ID.","operationId":"get_rom_api_roms__id__get","security":[{"OAuth2PasswordBearer":["roms.read"]},{"HTTPBasic":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","minimum":1,"description":"Rom internal id.","title":"Id"},"description":"Rom internal id."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DetailedRomSchema"}}}},"404":{"description":"Not Found"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"put":{"tags":["roms"],"summary":"Update Rom","description":"Update a rom.","operationId":"update_rom_api_roms__id__put","security":[{"OAuth2PasswordBearer":["roms.write"]},{"HTTPBasic":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","minimum":1,"description":"Rom internal id.","title":"Id"},"description":"Rom internal id."},{"name":"remove_cover","in":"query","required":false,"schema":{"type":"boolean","description":"Whether to remove the cover image for this rom.","default":false,"title":"Remove Cover"},"description":"Whether to remove the cover image for this rom."},{"name":"unmatch_metadata","in":"query","required":false,"schema":{"type":"boolean","description":"Whether to remove the metadata matches for this game.","default":false,"title":"Unmatch Metadata"},"description":"Whether to remove the metadata matches for this game."}],"requestBody":{"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_update_rom_api_roms__id__put"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DetailedRomSchema"}}}},"404":{"description":"Not Found"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/roms/{id}/content/{file_name}":{"head":{"tags":["roms"],"summary":"Head Rom Content","description":"Retrieve head information for a rom file download.","operationId":"head_rom_content_api_roms__id__content__file_name__head","security":[{"OAuth2PasswordBearer":["roms.read"]},{"HTTPBasic":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","minimum":1,"description":"Rom internal id.","title":"Id"},"description":"Rom internal id."},{"name":"file_name","in":"path","required":true,"schema":{"type":"string","description":"File name to download","title":"File Name"},"description":"File name to download"},{"name":"file_ids","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Comma-separated list of file ids to download for multi-part roms.","title":"File Ids"},"description":"Comma-separated list of file ids to download for multi-part roms."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"404":{"description":"Not Found"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["roms"],"summary":"Get Rom Content","description":"Download a rom.\n\nThis endpoint serves the content of the requested rom, as:\n- A single file for single file roms.\n- A zipped file for multi-part roms, including a .m3u file if applicable.","operationId":"get_rom_content_api_roms__id__content__file_name__get","security":[{"OAuth2PasswordBearer":["roms.read"]},{"HTTPBasic":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","minimum":1,"description":"Rom internal id.","title":"Id"},"description":"Rom internal id."},{"name":"file_name","in":"path","required":true,"schema":{"type":"string","description":"Zip file output name","title":"File Name"},"description":"Zip file output name"},{"name":"file_ids","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Comma-separated list of file ids to download for multi-part roms.","title":"File Ids"},"description":"Comma-separated list of file ids to download for multi-part roms."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"404":{"description":"Not Found"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/roms/{id}/manuals":{"post":{"tags":["roms"],"summary":"Add Rom Manuals","description":"Upload manuals for a rom.","operationId":"add_rom_manuals_api_roms__id__manuals_post","security":[{"OAuth2PasswordBearer":["roms.write"]},{"HTTPBasic":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","minimum":1,"description":"Rom internal id.","title":"Id"},"description":"Rom internal id."},{"name":"x-upload-filename","in":"header","required":true,"schema":{"type":"string","description":"The name of the file being uploaded.","title":"X-Upload-Filename"},"description":"The name of the file being uploaded."}],"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"404":{"description":"Not Found"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["roms"],"summary":"Delete Rom Manuals","description":"Delete manuals for a rom.","operationId":"delete_rom_manuals_api_roms__id__manuals_delete","security":[{"OAuth2PasswordBearer":["roms.write"]},{"HTTPBasic":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","minimum":1,"description":"Rom internal id.","title":"Id"},"description":"Rom internal id."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"404":{"description":"Not Found"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/roms/delete":{"post":{"tags":["roms"],"summary":"Delete Roms","description":"Delete roms.","operationId":"delete_roms_api_roms_delete_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Body_delete_roms_api_roms_delete_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkOperationResponse"}}}},"404":{"description":"Not Found"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"OAuth2PasswordBearer":["roms.write"]},{"HTTPBasic":[]}]}},"/api/roms/{id}/props":{"put":{"tags":["roms"],"summary":"Update Rom User","description":"Update rom data associated to the current user.","operationId":"update_rom_user_api_roms__id__props_put","security":[{"OAuth2PasswordBearer":["roms.user.write"]},{"HTTPBasic":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","minimum":1,"description":"Rom internal id.","title":"Id"},"description":"Rom internal id."}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Body_update_rom_user_api_roms__id__props_put"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RomUserSchema"}}}},"404":{"description":"Not Found"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/roms/files/{id}":{"get":{"tags":["roms"],"summary":"Get Romfile","description":"Retrieve a rom file by ID.","operationId":"get_romfile_api_roms_files__id__get","security":[{"OAuth2PasswordBearer":["roms.read"]},{"HTTPBasic":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","minimum":1,"description":"Rom file internal id.","title":"Id"},"description":"Rom file internal id."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RomFileSchema"}}}},"404":{"description":"Not Found"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/romsfiles/{id}/content/{file_name}":{"get":{"tags":["roms"],"summary":"Get Romfile Content","description":"Download a rom file.","operationId":"get_romfile_content_api_romsfiles__id__content__file_name__get","security":[{"OAuth2PasswordBearer":["roms.read"]},{"HTTPBasic":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","minimum":1,"description":"Rom file internal id.","title":"Id"},"description":"Rom file internal id."},{"name":"file_name","in":"path","required":true,"schema":{"type":"string","description":"File name to download","title":"File Name"},"description":"File name to download"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"404":{"description":"Not Found"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/roms/{id}/notes":{"get":{"tags":["roms"],"summary":"Get Rom Notes","description":"Get all notes for a ROM.","operationId":"get_rom_notes_api_roms__id__notes_get","security":[{"OAuth2PasswordBearer":["roms.read"]},{"HTTPBasic":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","minimum":1,"description":"Rom internal id.","title":"Id"},"description":"Rom internal id."},{"name":"public_only","in":"query","required":false,"schema":{"type":"boolean","description":"Only return public notes","default":false,"title":"Public Only"},"description":"Only return public notes"},{"name":"search","in":"query","required":false,"schema":{"type":"string","description":"Search notes by title or content","title":"Search"},"description":"Search notes by title or content"},{"name":"tags","in":"query","required":false,"schema":{"type":"array","items":{"type":"string"},"description":"Filter by tags","title":"Tags"},"description":"Filter by tags"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/UserNoteSchema"},"title":"Response Get Rom Notes Api Roms Id Notes Get"}}}},"404":{"description":"Not Found"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["roms"],"summary":"Create Rom Note","description":"Create a new note for a ROM.","operationId":"create_rom_note_api_roms__id__notes_post","security":[{"OAuth2PasswordBearer":["roms.user.write"]},{"HTTPBasic":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","minimum":1,"description":"Rom internal id.","title":"Id"},"description":"Rom internal id."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Note Data"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserNoteSchema"}}}},"404":{"description":"Not Found"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/roms/{id}/notes/{note_id}":{"put":{"tags":["roms"],"summary":"Update Rom Note","description":"Update a ROM note.","operationId":"update_rom_note_api_roms__id__notes__note_id__put","security":[{"OAuth2PasswordBearer":["roms.user.write"]},{"HTTPBasic":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","minimum":1,"description":"Rom internal id.","title":"Id"},"description":"Rom internal id."},{"name":"note_id","in":"path","required":true,"schema":{"type":"integer","minimum":1,"description":"Note id.","title":"Note Id"},"description":"Note id."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Note Data"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserNoteSchema"}}}},"404":{"description":"Not Found"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["roms"],"summary":"Delete Rom Note","description":"Delete a ROM note.","operationId":"delete_rom_note_api_roms__id__notes__note_id__delete","security":[{"OAuth2PasswordBearer":["roms.user.write"]},{"HTTPBasic":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","minimum":1,"description":"Rom internal id.","title":"Id"},"description":"Rom internal id."},{"name":"note_id","in":"path","required":true,"schema":{"type":"integer","minimum":1,"description":"Note id.","title":"Note Id"},"description":"Note id."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Delete Rom Note Api Roms Id Notes Note Id Delete"}}}},"404":{"description":"Not Found"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/search/roms":{"get":{"tags":["search"],"summary":"Search Rom","description":"Search for rom in metadata providers\n\nArgs:\n request (Request): FastAPI request\n rom_id (int): Rom ID\n source (str): Source of the rom\n search_term (str, optional): Search term. Defaults to None.\n search_by (str, optional): Search by name or ID. Defaults to \"name\".\n search_extended (bool, optional): Search extended info. Defaults to False.\n\nReturns:\n list[SearchRomSchema]: List of matched roms","operationId":"search_rom_api_search_roms_get","security":[{"OAuth2PasswordBearer":["roms.read"]},{"HTTPBasic":[]}],"parameters":[{"name":"rom_id","in":"query","required":true,"schema":{"type":"integer","title":"Rom Id"}},{"name":"search_term","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Search Term"}},{"name":"search_by","in":"query","required":false,"schema":{"type":"string","default":"name","title":"Search By"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/SearchRomSchema"},"title":"Response Search Rom Api Search Roms Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/search/cover":{"get":{"tags":["search"],"summary":"Search Cover","operationId":"search_cover_api_search_cover_get","security":[{"OAuth2PasswordBearer":["roms.read"]},{"HTTPBasic":[]}],"parameters":[{"name":"search_term","in":"query","required":false,"schema":{"type":"string","default":"","title":"Search Term"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/SearchCoverSchema"},"title":"Response Search Cover Api Search Cover Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/saves":{"post":{"tags":["saves"],"summary":"Add Save","operationId":"add_save_api_saves_post","security":[{"OAuth2PasswordBearer":["assets.write"]},{"HTTPBasic":[]}],"parameters":[{"name":"rom_id","in":"query","required":true,"schema":{"type":"integer","title":"Rom Id"}},{"name":"emulator","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Emulator"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SaveSchema"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["saves"],"summary":"Get Saves","operationId":"get_saves_api_saves_get","security":[{"OAuth2PasswordBearer":["assets.read"]},{"HTTPBasic":[]}],"parameters":[{"name":"rom_id","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Rom Id"}},{"name":"platform_id","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Platform Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/SaveSchema"},"title":"Response Get Saves Api Saves Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/saves/{id}":{"get":{"tags":["saves"],"summary":"Get Save","operationId":"get_save_api_saves__id__get","security":[{"OAuth2PasswordBearer":["assets.read"]},{"HTTPBasic":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","title":"Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SaveSchema"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"put":{"tags":["saves"],"summary":"Update Save","operationId":"update_save_api_saves__id__put","security":[{"OAuth2PasswordBearer":["assets.write"]},{"HTTPBasic":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","title":"Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SaveSchema"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/saves/delete":{"post":{"tags":["saves"],"summary":"Delete Saves","description":"Delete saves.","operationId":"delete_saves_api_saves_delete_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Body_delete_saves_api_saves_delete_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"items":{"type":"integer"},"type":"array","title":"Response Delete Saves Api Saves Delete Post"}}}},"400":{"description":"Bad Request"},"404":{"description":"Not Found"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"OAuth2PasswordBearer":["assets.write"]},{"HTTPBasic":[]}]}},"/api/states":{"post":{"tags":["states"],"summary":"Add State","operationId":"add_state_api_states_post","security":[{"OAuth2PasswordBearer":["assets.write"]},{"HTTPBasic":[]}],"parameters":[{"name":"rom_id","in":"query","required":true,"schema":{"type":"integer","title":"Rom Id"}},{"name":"emulator","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Emulator"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StateSchema"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["states"],"summary":"Get States","operationId":"get_states_api_states_get","security":[{"OAuth2PasswordBearer":["assets.read"]},{"HTTPBasic":[]}],"parameters":[{"name":"rom_id","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Rom Id"}},{"name":"platform_id","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Platform Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/StateSchema"},"title":"Response Get States Api States Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/states/{id}":{"get":{"tags":["states"],"summary":"Get State","operationId":"get_state_api_states__id__get","security":[{"OAuth2PasswordBearer":["assets.read"]},{"HTTPBasic":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","title":"Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StateSchema"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"put":{"tags":["states"],"summary":"Update State","operationId":"update_state_api_states__id__put","security":[{"OAuth2PasswordBearer":["assets.write"]},{"HTTPBasic":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","title":"Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StateSchema"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/states/delete":{"post":{"tags":["states"],"summary":"Delete States","description":"Delete states.","operationId":"delete_states_api_states_delete_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Body_delete_states_api_states_delete_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"items":{"type":"integer"},"type":"array","title":"Response Delete States Api States Delete Post"}}}},"400":{"description":"Bad Request"},"404":{"description":"Not Found"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"OAuth2PasswordBearer":["assets.write"]},{"HTTPBasic":[]}]}},"/api/tasks":{"get":{"tags":["tasks"],"summary":"List Tasks","description":"List all available tasks grouped by task type.\n\nArgs:\n request (Request): FastAPI Request object\nReturns:\n GroupedTasksDict: Dictionary with tasks grouped by their type (scheduled, manual, watcher)","operationId":"list_tasks_api_tasks_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":{"items":{"$ref":"#/components/schemas/TaskInfo"},"type":"array"},"type":"object","title":"Response List Tasks Api Tasks Get"}}}}},"security":[{"OAuth2PasswordBearer":["tasks.run"]},{"HTTPBasic":[]}]}},"/api/tasks/status":{"get":{"tags":["tasks"],"summary":"Get Tasks Status","description":"Get all active, queued, completed, and failed tasks.\n\nArgs:\n request (Request): FastAPI Request object\nReturns:\n list[TaskStatusResponse]: List of all tasks with their current status","operationId":"get_tasks_status_api_tasks_status_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"items":{"anyOf":[{"$ref":"#/components/schemas/ScanTaskStatusResponse"},{"$ref":"#/components/schemas/ConversionTaskStatusResponse"},{"$ref":"#/components/schemas/UpdateTaskStatusResponse"},{"$ref":"#/components/schemas/CleanupTaskStatusResponse"},{"$ref":"#/components/schemas/WatcherTaskStatusResponse"},{"$ref":"#/components/schemas/GenericTaskStatusResponse"}]},"type":"array","title":"Response Get Tasks Status Api Tasks Status Get"}}}}},"security":[{"OAuth2PasswordBearer":["tasks.run"]},{"HTTPBasic":[]}]}},"/api/tasks/{task_id}":{"get":{"tags":["tasks"],"summary":"Get Task By Id","description":"Get the status of a task by its job ID.\n\nArgs:\n request (Request): FastAPI Request object\n task_id (str): Job ID of the task to retrieve status for\nReturns:\n TaskStatusResponse: Task status information","operationId":"get_task_by_id_api_tasks__task_id__get","security":[{"OAuth2PasswordBearer":["tasks.run"]},{"HTTPBasic":[]}],"parameters":[{"name":"task_id","in":"path","required":true,"schema":{"type":"string","title":"Task Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/ScanTaskStatusResponse"},{"$ref":"#/components/schemas/ConversionTaskStatusResponse"},{"$ref":"#/components/schemas/UpdateTaskStatusResponse"},{"$ref":"#/components/schemas/CleanupTaskStatusResponse"},{"$ref":"#/components/schemas/WatcherTaskStatusResponse"},{"$ref":"#/components/schemas/GenericTaskStatusResponse"}],"title":"Response Get Task By Id Api Tasks Task Id Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/tasks/run":{"post":{"tags":["tasks"],"summary":"Run All Tasks","description":"Run all runnable tasks endpoint\n\nArgs:\n request (Request): FastAPI Request object\nReturns:\n TaskExecutionResponse: Task execution response with details","operationId":"run_all_tasks_api_tasks_run_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/TaskExecutionResponse"},"type":"array","title":"Response Run All Tasks Api Tasks Run Post"}}}}},"security":[{"OAuth2PasswordBearer":["tasks.run"]},{"HTTPBasic":[]}]}},"/api/tasks/run/{task_name}":{"post":{"tags":["tasks"],"summary":"Run Single Task","description":"Run a single task endpoint.\n\nArgs:\n request (Request): FastAPI Request object\n task_name (str): Name of the task to run\nReturns:\n TaskExecutionResponse: Task execution response with details","operationId":"run_single_task_api_tasks_run__task_name__post","security":[{"OAuth2PasswordBearer":["tasks.run"]},{"HTTPBasic":[]}],"parameters":[{"name":"task_name","in":"path","required":true,"schema":{"type":"string","title":"Task Name"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TaskExecutionResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/feeds/webrcade":{"get":{"tags":["feeds"],"summary":"Platforms Webrcade Feed","description":"Get webrcade feed endpoint\nhttps://docs.webrcade.com/feeds/format/\n\nArgs:\n request (Request): Fastapi Request object\n\nReturns:\n WebrcadeFeedSchema: Webrcade feed object schema","operationId":"platforms_webrcade_feed_api_feeds_webrcade_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebrcadeFeedSchema"}}}}},"security":[{"OAuth2PasswordBearer":["roms.read"]},{"HTTPBasic":[]}]}},"/api/feeds/tinfoil":{"get":{"tags":["feeds"],"summary":"Tinfoil Index Feed","description":"Get tinfoil custom index feed endpoint\nhttps://blawar.github.io/tinfoil/custom_index/\n\nArgs:\n request (Request): Fastapi Request object\n slug (str, optional): Platform slug. Defaults to \"switch\".\n\nReturns:\n TinfoilFeedSchema: Tinfoil feed object schema","operationId":"tinfoil_index_feed_api_feeds_tinfoil_get","security":[{"OAuth2PasswordBearer":[]},{"HTTPBasic":[]}],"parameters":[{"name":"slug","in":"query","required":false,"schema":{"type":"string","default":"switch","title":"Slug"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TinfoilFeedSchema"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/feeds/pkgi/ps3/{content_type}":{"get":{"tags":["feeds"],"summary":"Pkgi Ps3 Feed","description":"Get PKGi PS3 feed endpoint\nhttps://github.com/bucanero/pkgi-ps3\n\nArgs:\n request (Request): Fastapi Request object\n content_type (str): Content type (game, dlc, demo, update, patch, mod, translation, prototype)\n\nReturns:\n Response: txt file with PKGi PS3 database format","operationId":"pkgi_ps3_feed_api_feeds_pkgi_ps3__content_type__get","security":[{"OAuth2PasswordBearer":["roms.read"]},{"HTTPBasic":[]}],"parameters":[{"name":"content_type","in":"path","required":true,"schema":{"type":"string","description":"Content type","title":"Content Type"},"description":"Content type"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/feeds/pkgi/psvita/{content_type}":{"get":{"tags":["feeds"],"summary":"Pkgi Psvita Feed","description":"Get PKGi PS Vita feed endpoint\nhttps://github.com/mmozeiko/pkgi\n\nArgs:\n request (Request): Fastapi Request object\n content_type (str): Content type (game, dlc, demo, update, patch, mod, translation, prototype)\n\nReturns:\n Response: txt file with PKGi PS Vita database format","operationId":"pkgi_psvita_feed_api_feeds_pkgi_psvita__content_type__get","security":[{"OAuth2PasswordBearer":["roms.read"]},{"HTTPBasic":[]}],"parameters":[{"name":"content_type","in":"path","required":true,"schema":{"type":"string","description":"Content type","title":"Content Type"},"description":"Content type"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/feeds/pkgi/psp/{content_type}":{"get":{"tags":["feeds"],"summary":"Pkgi Psp Feed","description":"Get PKGi PSP feed endpoint\nhttps://github.com/bucanero/pkgi-psp\n\nArgs:\n request (Request): Fastapi Request object\n content_type (str): Content type (game, dlc, demo, update, patch, mod, translation, prototype)\n\nReturns:\n Response: txt file with PKGi PSP database format","operationId":"pkgi_psp_feed_api_feeds_pkgi_psp__content_type__get","security":[{"OAuth2PasswordBearer":["roms.read"]},{"HTTPBasic":[]}],"parameters":[{"name":"content_type","in":"path","required":true,"schema":{"type":"string","description":"Content type","title":"Content Type"},"description":"Content type"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/feeds/fpkgi/{platform_slug}":{"get":{"tags":["feeds"],"summary":"Fpkgi Feed","description":"https://github.com/ItsJokerZz/FPKGi\n\nArgs:\n request (Request): Fastapi Request object\n platform_slug (str): Platform slug (ps4, ps5)\n\nReturns:\n Response: JSON file in FPKGi format","operationId":"fpkgi_feed_api_feeds_fpkgi__platform_slug__get","security":[{"OAuth2PasswordBearer":["roms.read"]},{"HTTPBasic":[]}],"parameters":[{"name":"platform_slug","in":"path","required":true,"schema":{"type":"string","title":"Platform Slug"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/feeds/kekatsu/{platform_slug}":{"get":{"tags":["feeds"],"summary":"Kekatsu Ds Feed","description":"Get Kekatsu DS feed endpoint\nhttps://github.com/cavv-dev/Kekatsu-DS\n\nArgs:\n request (Request): Fastapi Request object\n platform_slug (str): Platform slug (nds, nintendo-ds, ds, gba, etc.)\n\nReturns:\n Response: Text file with Kekatsu DS database format","operationId":"kekatsu_ds_feed_api_feeds_kekatsu__platform_slug__get","security":[{"OAuth2PasswordBearer":["roms.read"]},{"HTTPBasic":[]}],"parameters":[{"name":"platform_slug","in":"path","required":true,"schema":{"type":"string","title":"Platform Slug"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/config":{"get":{"tags":["config"],"summary":"Get Config","description":"Get config endpoint\n\nReturns:\n ConfigResponse: RomM's configuration","operationId":"get_config_api_config_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConfigResponse"}}}}}}},"/api/config/system/platforms":{"post":{"tags":["config"],"summary":"Add Platform Binding","description":"Add platform binding to the configuration","operationId":"add_platform_binding_api_config_system_platforms_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"OAuth2PasswordBearer":["platforms.write"]},{"HTTPBasic":[]}]}},"/api/config/system/platforms/{fs_slug}":{"delete":{"tags":["config"],"summary":"Delete Platform Binding","description":"Delete platform binding from the configuration","operationId":"delete_platform_binding_api_config_system_platforms__fs_slug__delete","security":[{"OAuth2PasswordBearer":["platforms.write"]},{"HTTPBasic":[]}],"parameters":[{"name":"fs_slug","in":"path","required":true,"schema":{"type":"string","title":"Fs Slug"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/config/system/versions":{"post":{"tags":["config"],"summary":"Add Platform Version","description":"Add platform version to the configuration","operationId":"add_platform_version_api_config_system_versions_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"OAuth2PasswordBearer":["platforms.write"]},{"HTTPBasic":[]}]}},"/api/config/system/versions/{fs_slug}":{"delete":{"tags":["config"],"summary":"Delete Platform Version","description":"Delete platform version from the configuration","operationId":"delete_platform_version_api_config_system_versions__fs_slug__delete","security":[{"OAuth2PasswordBearer":["platforms.write"]},{"HTTPBasic":[]}],"parameters":[{"name":"fs_slug","in":"path","required":true,"schema":{"type":"string","title":"Fs Slug"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/config/exclude":{"post":{"tags":["config"],"summary":"Add Exclusion","description":"Add platform exclusion to the configuration","operationId":"add_exclusion_api_config_exclude_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"OAuth2PasswordBearer":["platforms.write"]},{"HTTPBasic":[]}]}},"/api/config/exclude/{exclusion_type}/{exclusion_value}":{"delete":{"tags":["config"],"summary":"Delete Exclusion","description":"Delete platform binding from the configuration","operationId":"delete_exclusion_api_config_exclude__exclusion_type___exclusion_value__delete","security":[{"OAuth2PasswordBearer":["platforms.write"]},{"HTTPBasic":[]}],"parameters":[{"name":"exclusion_type","in":"path","required":true,"schema":{"type":"string","title":"Exclusion Type"}},{"name":"exclusion_value","in":"path","required":true,"schema":{"type":"string","title":"Exclusion Value"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/stats":{"get":{"tags":["stats"],"summary":"Stats","description":"Endpoint to return the current RomM stats\n\nReturns:\n dict: Dictionary with all the stats","operationId":"stats_api_stats_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StatsReturn"}}}}}}},"/api/raw/assets/{path}":{"head":{"tags":["raw"],"summary":"Head Raw Asset","operationId":"head_raw_asset_api_raw_assets__path__head","security":[{"OAuth2PasswordBearer":["assets.read"]},{"HTTPBasic":[]}],"parameters":[{"name":"path","in":"path","required":true,"schema":{"type":"string","title":"Path"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["raw"],"summary":"Get Raw Asset","description":"Download a single asset file\n\nArgs:\n request (Request): Fastapi Request object\n path (str): Relative path to the asset file\n\nReturns:\n FileResponse: Returns a single asset file\n\nRaises:\n HTTPException: 404 if asset not found or access denied","operationId":"get_raw_asset_api_raw_assets__path__get","security":[{"OAuth2PasswordBearer":["assets.read"]},{"HTTPBasic":[]}],"parameters":[{"name":"path","in":"path","required":true,"schema":{"type":"string","title":"Path"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/screenshots":{"post":{"tags":["screenshots"],"summary":"Add Screenshot","operationId":"add_screenshot_api_screenshots_post","security":[{"OAuth2PasswordBearer":["assets.write"]},{"HTTPBasic":[]}],"parameters":[{"name":"rom_id","in":"query","required":true,"schema":{"type":"integer","title":"Rom Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScreenshotSchema"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/firmware":{"post":{"tags":["firmware"],"summary":"Add Firmware","description":"Upload firmware files endpoint\n\nArgs:\n request (Request): Fastapi Request object\n platform_slug (str): Slug of the platform where to upload the files\n files (list[UploadFile], optional): List of files to upload\n\nRaises:\n HTTPException\n\nReturns:\n AddFirmwareResponse: Standard message response","operationId":"add_firmware_api_firmware_post","security":[{"OAuth2PasswordBearer":["firmware.write"]},{"HTTPBasic":[]}],"parameters":[{"name":"platform_id","in":"query","required":true,"schema":{"type":"integer","title":"Platform Id"}}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_add_firmware_api_firmware_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddFirmwareResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["firmware"],"summary":"Get Platform Firmware","description":"Get firmware endpoint\n\nArgs:\n request (Request): Fastapi Request object\n\nReturns:\n list[FirmwareSchema]: Firmware stored in the database","operationId":"get_platform_firmware_api_firmware_get","security":[{"OAuth2PasswordBearer":["firmware.read"]},{"HTTPBasic":[]}],"parameters":[{"name":"platform_id","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Platform Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/FirmwareSchema"},"title":"Response Get Platform Firmware Api Firmware Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/firmware/{id}":{"get":{"tags":["firmware"],"summary":"Get Firmware","description":"Get firmware endpoint\n\nArgs:\n request (Request): Fastapi Request object\n id (int): Firmware internal id\n\nReturns:\n FirmwareSchema: Firmware stored in the database","operationId":"get_firmware_api_firmware__id__get","security":[{"OAuth2PasswordBearer":["firmware.read"]},{"HTTPBasic":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","title":"Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FirmwareSchema"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/firmware/{id}/content/{file_name}":{"head":{"tags":["firmware"],"summary":"Head Firmware Content","description":"Head firmware content endpoint\n\nArgs:\n request (Request): Fastapi Request object\n id (int): Rom internal id\n file_name (str): Required due to a bug in emulatorjs\n\nReturns:\n FileResponse: Returns the response with headers","operationId":"head_firmware_content_api_firmware__id__content__file_name__head","security":[{"OAuth2PasswordBearer":["firmware.read"]},{"HTTPBasic":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","title":"Id"}},{"name":"file_name","in":"path","required":true,"schema":{"type":"string","title":"File Name"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["firmware"],"summary":"Get Firmware Content","description":"Download firmware endpoint\n\nArgs:\n request (Request): Fastapi Request object\n id (int): Rom internal id\n file_name (str): Required due to a bug in emulatorjs\n\nReturns:\n FileResponse: Returns the firmware file","operationId":"get_firmware_content_api_firmware__id__content__file_name__get","security":[{"OAuth2PasswordBearer":["firmware.read"]},{"HTTPBasic":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","title":"Id"}},{"name":"file_name","in":"path","required":true,"schema":{"type":"string","title":"File Name"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/firmware/delete":{"post":{"tags":["firmware"],"summary":"Delete Firmware","description":"Delete firmware.","operationId":"delete_firmware_api_firmware_delete_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Body_delete_firmware_api_firmware_delete_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkOperationResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"OAuth2PasswordBearer":["firmware.write"]},{"HTTPBasic":[]}]}},"/api/collections":{"post":{"tags":["collections"],"summary":"Add Collection","description":"Create collection endpoint\n\nArgs:\n request (Request): Fastapi Request object\n\nReturns:\n CollectionSchema: Just created collection","operationId":"add_collection_api_collections_post","security":[{"OAuth2PasswordBearer":["collections.write"]},{"HTTPBasic":[]}],"parameters":[{"name":"is_public","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Is Public"}},{"name":"is_favorite","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Is Favorite"}}],"requestBody":{"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_add_collection_api_collections_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CollectionSchema"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["collections"],"summary":"Get Collections","description":"Get collections endpoint\n\nArgs:\n request (Request): Fastapi Request object\n updated_after: Filter collections updated after this datetime\n\nReturns:\n list[CollectionSchema]: List of collections","operationId":"get_collections_api_collections_get","security":[{"OAuth2PasswordBearer":["collections.read"]},{"HTTPBasic":[]}],"parameters":[{"name":"updated_after","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"Filter collections updated after this datetime (ISO 8601 format with timezone information).","title":"Updated After"},"description":"Filter collections updated after this datetime (ISO 8601 format with timezone information)."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/CollectionSchema"},"title":"Response Get Collections Api Collections Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/collections/smart":{"post":{"tags":["collections"],"summary":"Add Smart Collection","description":"Create smart collection endpoint\n\nArgs:\n request (Request): Fastapi Request object\n\nReturns:\n SmartCollectionSchema: Just created smart collection","operationId":"add_smart_collection_api_collections_smart_post","security":[{"OAuth2PasswordBearer":["collections.write"]},{"HTTPBasic":[]}],"parameters":[{"name":"is_public","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Is Public"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SmartCollectionSchema"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["collections"],"summary":"Get Smart Collections","description":"Get smart collections endpoint\n\nArgs:\n request (Request): Fastapi Request object\n updated_after: Filter smart collections updated after this datetime\n\nReturns:\n list[SmartCollectionSchema]: List of smart collections","operationId":"get_smart_collections_api_collections_smart_get","security":[{"OAuth2PasswordBearer":["collections.read"]},{"HTTPBasic":[]}],"parameters":[{"name":"updated_after","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"Filter smart collections updated after this datetime (ISO 8601 format with timezone information).","title":"Updated After"},"description":"Filter smart collections updated after this datetime (ISO 8601 format with timezone information)."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/SmartCollectionSchema"},"title":"Response Get Smart Collections Api Collections Smart Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/collections/virtual":{"get":{"tags":["collections"],"summary":"Get Virtual Collections","description":"Get virtual collections endpoint\n\nArgs:\n request (Request): Fastapi Request object\n\nReturns:\n list[VirtualCollectionSchema]: List of virtual collections","operationId":"get_virtual_collections_api_collections_virtual_get","security":[{"OAuth2PasswordBearer":["collections.read"]},{"HTTPBasic":[]}],"parameters":[{"name":"type","in":"query","required":true,"schema":{"type":"string","title":"Type"}},{"name":"limit","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/VirtualCollectionSchema"},"title":"Response Get Virtual Collections Api Collections Virtual Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/collections/{id}":{"get":{"tags":["collections"],"summary":"Get Collection","description":"Get collections endpoint\n\nArgs:\n request (Request): Fastapi Request object\n id (int, optional): Collection id. Defaults to None.\n\nReturns:\n CollectionSchema: Collection","operationId":"get_collection_api_collections__id__get","security":[{"OAuth2PasswordBearer":["collections.read"]},{"HTTPBasic":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","title":"Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CollectionSchema"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"put":{"tags":["collections"],"summary":"Update Collection","description":"Update collection endpoint\n\nArgs:\n request (Request): Fastapi Request object\n\nReturns:\n CollectionSchema: Updated collection","operationId":"update_collection_api_collections__id__put","security":[{"OAuth2PasswordBearer":["collections.write"]},{"HTTPBasic":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","title":"Id"}},{"name":"remove_cover","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Remove Cover"}},{"name":"is_public","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Is Public"}}],"requestBody":{"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_update_collection_api_collections__id__put"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CollectionSchema"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["collections"],"summary":"Delete Collection","description":"Delete a collection by ID.","operationId":"delete_collection_api_collections__id__delete","security":[{"OAuth2PasswordBearer":["collections.write"]},{"HTTPBasic":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","minimum":1,"description":"Collection internal id.","title":"Id"},"description":"Collection internal id."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"404":{"description":"Not Found"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/collections/virtual/{id}":{"get":{"tags":["collections"],"summary":"Get Virtual Collection","description":"Get virtual collections endpoint\n\nArgs:\n request (Request): Fastapi Request object\n id (str): Virtual collection id\n\nReturns:\n VirtualCollectionSchema: Virtual collection","operationId":"get_virtual_collection_api_collections_virtual__id__get","security":[{"OAuth2PasswordBearer":["collections.read"]},{"HTTPBasic":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","title":"Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VirtualCollectionSchema"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/collections/smart/{id}":{"get":{"tags":["collections"],"summary":"Get Smart Collection","description":"Get smart collection endpoint\n\nArgs:\n request (Request): Fastapi Request object\n id (int): Smart collection id\n\nReturns:\n SmartCollectionSchema: Smart collection","operationId":"get_smart_collection_api_collections_smart__id__get","security":[{"OAuth2PasswordBearer":["collections.read"]},{"HTTPBasic":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","title":"Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SmartCollectionSchema"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"put":{"tags":["collections"],"summary":"Update Smart Collection","description":"Update smart collection endpoint\n\nArgs:\n request (Request): Fastapi Request object\n id (int): Smart collection id\n\nReturns:\n SmartCollectionSchema: Updated smart collection","operationId":"update_smart_collection_api_collections_smart__id__put","security":[{"OAuth2PasswordBearer":["collections.write"]},{"HTTPBasic":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","title":"Id"}},{"name":"is_public","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Is Public"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SmartCollectionSchema"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["collections"],"summary":"Delete Smart Collection","description":"Delete a smart collection by ID.","operationId":"delete_smart_collection_api_collections_smart__id__delete","security":[{"OAuth2PasswordBearer":["collections.write"]},{"HTTPBasic":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","minimum":1,"description":"Smart collection internal id.","title":"Id"},"description":"Smart collection internal id."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"404":{"description":"Not Found"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/gamelist/export":{"post":{"tags":["gamelist"],"summary":"Export Gamelist","description":"Export platforms/ROMs to gamelist.xml format and write to platform directories","operationId":"export_gamelist_api_gamelist_export_post","security":[{"OAuth2PasswordBearer":["roms.read"]},{"HTTPBasic":[]}],"parameters":[{"name":"platform_ids","in":"query","required":true,"schema":{"type":"array","items":{"type":"integer"},"description":"List of platform IDs to export","title":"Platform Ids"},"description":"List of platform IDs to export"},{"name":"local_export","in":"query","required":false,"schema":{"type":"boolean","description":"Use local paths instead of URLs","default":false,"title":"Local Export"},"description":"Use local paths instead of URLs"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/netplay/list":{"get":{"tags":["netplay"],"summary":"Get Rooms","operationId":"get_rooms_api_netplay_list_get","security":[{"OAuth2PasswordBearer":["assets.read"]},{"HTTPBasic":[]}],"parameters":[{"name":"game_id","in":"query","required":true,"schema":{"type":"string","title":"Game Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":{"$ref":"#/components/schemas/RoomsResponse"},"title":"Response Get Rooms Api Netplay List Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}},"components":{"schemas":{"AddFirmwareResponse":{"properties":{"uploaded":{"type":"integer","title":"Uploaded"},"firmware":{"items":{"$ref":"#/components/schemas/FirmwareSchema"},"type":"array","title":"Firmware"}},"type":"object","required":["uploaded","firmware"],"title":"AddFirmwareResponse"},"Body_add_collection_api_collections_post":{"properties":{"artwork":{"anyOf":[{"type":"string","format":"binary"},{"type":"null"}],"title":"Artwork"}},"type":"object","title":"Body_add_collection_api_collections_post"},"Body_add_firmware_api_firmware_post":{"properties":{"files":{"items":{"type":"string","format":"binary"},"type":"array","title":"Files"}},"type":"object","required":["files"],"title":"Body_add_firmware_api_firmware_post"},"Body_add_platform_api_platforms_post":{"properties":{"fs_slug":{"type":"string","title":"Fs Slug","description":"Platform slug."}},"type":"object","required":["fs_slug"],"title":"Body_add_platform_api_platforms_post"},"Body_add_user_api_users_post":{"properties":{"username":{"type":"string","title":"Username"},"email":{"type":"string","title":"Email"},"password":{"type":"string","title":"Password"},"role":{"type":"string","title":"Role"}},"type":"object","required":["username","email","password","role"],"title":"Body_add_user_api_users_post"},"Body_create_user_from_invite_api_users_register_post":{"properties":{"username":{"type":"string","title":"Username"},"email":{"type":"string","title":"Email"},"password":{"type":"string","title":"Password"},"token":{"type":"string","title":"Token"}},"type":"object","required":["username","email","password","token"],"title":"Body_create_user_from_invite_api_users_register_post"},"Body_delete_firmware_api_firmware_delete_post":{"properties":{"firmware":{"items":{"type":"integer"},"type":"array","title":"Firmware","description":"List of firmware ids to delete from database."},"delete_from_fs":{"items":{"type":"integer"},"type":"array","title":"Delete From Fs","description":"List of firmware ids to delete from filesystem."}},"type":"object","required":["firmware"],"title":"Body_delete_firmware_api_firmware_delete_post"},"Body_delete_roms_api_roms_delete_post":{"properties":{"roms":{"items":{"type":"integer"},"type":"array","title":"Roms","description":"List of rom ids to delete from database."},"delete_from_fs":{"items":{"type":"integer"},"type":"array","title":"Delete From Fs","description":"List of rom ids to delete from filesystem."}},"type":"object","required":["roms"],"title":"Body_delete_roms_api_roms_delete_post"},"Body_delete_saves_api_saves_delete_post":{"properties":{"saves":{"items":{"type":"integer"},"type":"array","title":"Saves","description":"List of save ids to delete from database."}},"type":"object","required":["saves"],"title":"Body_delete_saves_api_saves_delete_post"},"Body_delete_states_api_states_delete_post":{"properties":{"states":{"items":{"type":"integer"},"type":"array","title":"States","description":"List of states ids to delete from database."}},"type":"object","required":["states"],"title":"Body_delete_states_api_states_delete_post"},"Body_refresh_retro_achievements_api_users__id__ra_refresh_post":{"properties":{"incremental":{"type":"boolean","title":"Incremental","description":"Whether to only retrieve RetroAchievements progression incrementally.","default":false}},"type":"object","title":"Body_refresh_retro_achievements_api_users__id__ra_refresh_post"},"Body_request_password_reset_api_forgot_password_post":{"properties":{"username":{"type":"string","title":"Username"}},"type":"object","required":["username"],"title":"Body_request_password_reset_api_forgot_password_post"},"Body_reset_password_api_reset_password_post":{"properties":{"token":{"type":"string","title":"Token"},"new_password":{"type":"string","title":"New Password"}},"type":"object","required":["token","new_password"],"title":"Body_reset_password_api_reset_password_post"},"Body_token_api_token_post":{"properties":{"grant_type":{"type":"string","title":"Grant Type","default":"password"},"scope":{"type":"string","title":"Scope","default":""},"username":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Username"},"password":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Password"},"client_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Client Id"},"client_secret":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Client Secret"},"refresh_token":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Refresh Token"}},"type":"object","title":"Body_token_api_token_post"},"Body_update_collection_api_collections__id__put":{"properties":{"artwork":{"anyOf":[{"type":"string","format":"binary"},{"type":"null"}],"title":"Artwork"}},"type":"object","title":"Body_update_collection_api_collections__id__put"},"Body_update_platform_api_platforms__id__put":{"properties":{"aspect_ratio":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Aspect Ratio","description":"Cover aspect ratio."},"custom_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Custom Name","description":"Custom platform name."}},"type":"object","title":"Body_update_platform_api_platforms__id__put"},"Body_update_rom_api_roms__id__put":{"properties":{"artwork":{"anyOf":[{"type":"string","format":"binary"},{"type":"null"}],"title":"Artwork","description":"Custom artwork to set as cover."}},"type":"object","title":"Body_update_rom_api_roms__id__put"},"Body_update_rom_user_api_roms__id__props_put":{"properties":{"update_last_played":{"type":"boolean","title":"Update Last Played","description":"Whether to update the last played date.","default":false},"remove_last_played":{"type":"boolean","title":"Remove Last Played","description":"Whether to remove the last played date.","default":false}},"type":"object","title":"Body_update_rom_user_api_roms__id__props_put"},"BulkOperationResponse":{"properties":{"successful_items":{"type":"integer","title":"Successful Items"},"failed_items":{"type":"integer","title":"Failed Items"},"errors":{"items":{"type":"string"},"type":"array","title":"Errors"}},"type":"object","required":["successful_items","failed_items","errors"],"title":"BulkOperationResponse"},"CleanupStats":{"properties":{"platforms_in_db":{"type":"integer","title":"Platforms In Db"},"roms_in_db":{"type":"integer","title":"Roms In Db"},"platforms_in_fs":{"type":"integer","title":"Platforms In Fs"},"roms_in_fs":{"type":"integer","title":"Roms In Fs"},"removed_fs_platforms":{"type":"integer","title":"Removed Fs Platforms"},"removed_fs_roms":{"type":"integer","title":"Removed Fs Roms"}},"type":"object","required":["platforms_in_db","roms_in_db","platforms_in_fs","roms_in_fs","removed_fs_platforms","removed_fs_roms"],"title":"CleanupStats"},"CleanupTaskMeta":{"properties":{"cleanup_stats":{"anyOf":[{"$ref":"#/components/schemas/CleanupStats"},{"type":"null"}]}},"type":"object","required":["cleanup_stats"],"title":"CleanupTaskMeta"},"CleanupTaskStatusResponse":{"properties":{"task_name":{"type":"string","title":"Task Name"},"task_id":{"type":"string","title":"Task Id"},"status":{"$ref":"#/components/schemas/JobStatus"},"created_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created At"},"enqueued_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Enqueued At"},"started_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Started At"},"ended_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Ended At"},"task_type":{"type":"string","const":"cleanup","title":"Task Type"},"meta":{"$ref":"#/components/schemas/CleanupTaskMeta"}},"type":"object","required":["task_name","task_id","status","created_at","enqueued_at","started_at","ended_at","task_type","meta"],"title":"CleanupTaskStatusResponse"},"CollectionSchema":{"properties":{"name":{"type":"string","title":"Name"},"description":{"type":"string","title":"Description"},"rom_ids":{"items":{"type":"integer"},"type":"array","uniqueItems":true,"title":"Rom Ids"},"rom_count":{"type":"integer","title":"Rom Count"},"path_cover_small":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Path Cover Small"},"path_cover_large":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Path Cover Large"},"path_covers_small":{"items":{"type":"string"},"type":"array","title":"Path Covers Small"},"path_covers_large":{"items":{"type":"string"},"type":"array","title":"Path Covers Large"},"is_public":{"type":"boolean","title":"Is Public","default":false},"is_favorite":{"type":"boolean","title":"Is Favorite","default":false},"is_virtual":{"type":"boolean","title":"Is Virtual","default":false},"is_smart":{"type":"boolean","title":"Is Smart","default":false},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"},"id":{"type":"integer","title":"Id"},"url_cover":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Url Cover"},"user_id":{"type":"integer","title":"User Id"},"user__username":{"type":"string","title":"User Username"}},"type":"object","required":["name","description","rom_ids","rom_count","path_cover_small","path_cover_large","path_covers_small","path_covers_large","created_at","updated_at","id","url_cover","user_id","user__username"],"title":"CollectionSchema"},"ConfigResponse":{"properties":{"CONFIG_FILE_MOUNTED":{"type":"boolean","title":"Config File Mounted"},"CONFIG_FILE_WRITABLE":{"type":"boolean","title":"Config File Writable"},"EXCLUDED_PLATFORMS":{"items":{"type":"string"},"type":"array","title":"Excluded Platforms"},"EXCLUDED_SINGLE_EXT":{"items":{"type":"string"},"type":"array","title":"Excluded Single Ext"},"EXCLUDED_SINGLE_FILES":{"items":{"type":"string"},"type":"array","title":"Excluded Single Files"},"EXCLUDED_MULTI_FILES":{"items":{"type":"string"},"type":"array","title":"Excluded Multi Files"},"EXCLUDED_MULTI_PARTS_EXT":{"items":{"type":"string"},"type":"array","title":"Excluded Multi Parts Ext"},"EXCLUDED_MULTI_PARTS_FILES":{"items":{"type":"string"},"type":"array","title":"Excluded Multi Parts Files"},"PLATFORMS_BINDING":{"additionalProperties":{"type":"string"},"type":"object","title":"Platforms Binding"},"PLATFORMS_VERSIONS":{"additionalProperties":{"type":"string"},"type":"object","title":"Platforms Versions"},"SKIP_HASH_CALCULATION":{"type":"boolean","title":"Skip Hash Calculation"},"EJS_DEBUG":{"type":"boolean","title":"Ejs Debug"},"EJS_CACHE_LIMIT":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Ejs Cache Limit"},"EJS_DISABLE_AUTO_UNLOAD":{"type":"boolean","title":"Ejs Disable Auto Unload"},"EJS_DISABLE_BATCH_BOOTUP":{"type":"boolean","title":"Ejs Disable Batch Bootup"},"EJS_NETPLAY_ENABLED":{"type":"boolean","title":"Ejs Netplay Enabled"},"EJS_NETPLAY_ICE_SERVERS":{"items":{"$ref":"#/components/schemas/NetplayICEServer"},"type":"array","title":"Ejs Netplay Ice Servers"},"EJS_SETTINGS":{"additionalProperties":{"additionalProperties":{"type":"string"},"type":"object"},"type":"object","title":"Ejs Settings"},"EJS_CONTROLS":{"additionalProperties":{"$ref":"#/components/schemas/EjsControls"},"type":"object","title":"Ejs Controls"},"SCAN_METADATA_PRIORITY":{"items":{"type":"string"},"type":"array","title":"Scan Metadata Priority"},"SCAN_ARTWORK_PRIORITY":{"items":{"type":"string"},"type":"array","title":"Scan Artwork Priority"},"SCAN_REGION_PRIORITY":{"items":{"type":"string"},"type":"array","title":"Scan Region Priority"},"SCAN_LANGUAGE_PRIORITY":{"items":{"type":"string"},"type":"array","title":"Scan Language Priority"},"SCAN_MEDIA":{"items":{"type":"string"},"type":"array","title":"Scan Media"}},"type":"object","required":["CONFIG_FILE_MOUNTED","CONFIG_FILE_WRITABLE","EXCLUDED_PLATFORMS","EXCLUDED_SINGLE_EXT","EXCLUDED_SINGLE_FILES","EXCLUDED_MULTI_FILES","EXCLUDED_MULTI_PARTS_EXT","EXCLUDED_MULTI_PARTS_FILES","PLATFORMS_BINDING","PLATFORMS_VERSIONS","SKIP_HASH_CALCULATION","EJS_DEBUG","EJS_CACHE_LIMIT","EJS_DISABLE_AUTO_UNLOAD","EJS_DISABLE_BATCH_BOOTUP","EJS_NETPLAY_ENABLED","EJS_NETPLAY_ICE_SERVERS","EJS_SETTINGS","EJS_CONTROLS","SCAN_METADATA_PRIORITY","SCAN_ARTWORK_PRIORITY","SCAN_REGION_PRIORITY","SCAN_LANGUAGE_PRIORITY","SCAN_MEDIA"],"title":"ConfigResponse"},"ConversionStats":{"properties":{"processed":{"type":"integer","title":"Processed"},"errors":{"type":"integer","title":"Errors"},"total":{"type":"integer","title":"Total"}},"type":"object","required":["processed","errors","total"],"title":"ConversionStats"},"ConversionTaskMeta":{"properties":{"conversion_stats":{"anyOf":[{"$ref":"#/components/schemas/ConversionStats"},{"type":"null"}]}},"type":"object","required":["conversion_stats"],"title":"ConversionTaskMeta"},"ConversionTaskStatusResponse":{"properties":{"task_name":{"type":"string","title":"Task Name"},"task_id":{"type":"string","title":"Task Id"},"status":{"$ref":"#/components/schemas/JobStatus"},"created_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created At"},"enqueued_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Enqueued At"},"started_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Started At"},"ended_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Ended At"},"task_type":{"type":"string","const":"conversion","title":"Task Type"},"meta":{"$ref":"#/components/schemas/ConversionTaskMeta"}},"type":"object","required":["task_name","task_id","status","created_at","enqueued_at","started_at","ended_at","task_type","meta"],"title":"ConversionTaskStatusResponse"},"CustomLimitOffsetPage_SimpleRomSchema_":{"properties":{"items":{"items":{"$ref":"#/components/schemas/SimpleRomSchema"},"type":"array","title":"Items"},"total":{"type":"integer","minimum":0.0,"title":"Total"},"limit":{"type":"integer","minimum":1.0,"title":"Limit"},"offset":{"type":"integer","minimum":0.0,"title":"Offset"},"char_index":{"additionalProperties":{"type":"integer"},"type":"object","title":"Char Index"},"rom_id_index":{"items":{"type":"integer"},"type":"array","title":"Rom Id Index"},"filter_values":{"$ref":"#/components/schemas/RomFiltersDict"}},"type":"object","required":["items","total","limit","offset","char_index","rom_id_index","filter_values"],"title":"CustomLimitOffsetPage[SimpleRomSchema]"},"DetailedRomSchema":{"properties":{"id":{"type":"integer","title":"Id"},"igdb_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Igdb Id"},"sgdb_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Sgdb Id"},"moby_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Moby Id"},"ss_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Ss Id"},"ra_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Ra Id"},"launchbox_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Launchbox Id"},"hasheous_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Hasheous Id"},"tgdb_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Tgdb Id"},"flashpoint_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Flashpoint Id"},"hltb_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Hltb Id"},"gamelist_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Gamelist Id"},"platform_id":{"type":"integer","title":"Platform Id"},"platform_slug":{"type":"string","title":"Platform Slug"},"platform_fs_slug":{"type":"string","title":"Platform Fs Slug"},"platform_custom_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Platform Custom Name"},"platform_display_name":{"type":"string","title":"Platform Display Name"},"fs_name":{"type":"string","title":"Fs Name"},"fs_name_no_tags":{"type":"string","title":"Fs Name No Tags"},"fs_name_no_ext":{"type":"string","title":"Fs Name No Ext"},"fs_extension":{"type":"string","title":"Fs Extension"},"fs_path":{"type":"string","title":"Fs Path"},"fs_size_bytes":{"type":"integer","title":"Fs Size Bytes"},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"slug":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Slug"},"summary":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Summary"},"alternative_names":{"items":{"type":"string"},"type":"array","title":"Alternative Names"},"youtube_video_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Youtube Video Id"},"metadatum":{"$ref":"#/components/schemas/RomMetadataSchema"},"igdb_metadata":{"anyOf":[{"$ref":"#/components/schemas/RomIGDBMetadata"},{"type":"null"}]},"moby_metadata":{"anyOf":[{"$ref":"#/components/schemas/RomMobyMetadata"},{"type":"null"}]},"ss_metadata":{"anyOf":[{"$ref":"#/components/schemas/RomSSMetadata"},{"type":"null"}]},"launchbox_metadata":{"anyOf":[{"$ref":"#/components/schemas/RomLaunchboxMetadata"},{"type":"null"}]},"hasheous_metadata":{"anyOf":[{"$ref":"#/components/schemas/RomHasheousMetadata"},{"type":"null"}]},"flashpoint_metadata":{"anyOf":[{"$ref":"#/components/schemas/RomFlashpointMetadata"},{"type":"null"}]},"hltb_metadata":{"anyOf":[{"$ref":"#/components/schemas/RomHLTBMetadata"},{"type":"null"}]},"gamelist_metadata":{"anyOf":[{"$ref":"#/components/schemas/RomGamelistMetadata"},{"type":"null"}]},"manual_metadata":{"anyOf":[{"$ref":"#/components/schemas/ManualMetadata"},{"type":"null"}]},"path_cover_small":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Path Cover Small"},"path_cover_large":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Path Cover Large"},"url_cover":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Url Cover"},"has_manual":{"type":"boolean","title":"Has Manual"},"path_manual":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Path Manual"},"url_manual":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Url Manual"},"is_identifying":{"type":"boolean","title":"Is Identifying","default":false},"is_unidentified":{"type":"boolean","title":"Is Unidentified"},"is_identified":{"type":"boolean","title":"Is Identified"},"revision":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Revision"},"regions":{"items":{"type":"string"},"type":"array","title":"Regions"},"languages":{"items":{"type":"string"},"type":"array","title":"Languages"},"tags":{"items":{"type":"string"},"type":"array","title":"Tags"},"crc_hash":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Crc Hash"},"md5_hash":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Md5 Hash"},"sha1_hash":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Sha1 Hash"},"has_simple_single_file":{"type":"boolean","title":"Has Simple Single File"},"has_nested_single_file":{"type":"boolean","title":"Has Nested Single File"},"has_multiple_files":{"type":"boolean","title":"Has Multiple Files"},"files":{"items":{"$ref":"#/components/schemas/RomFileSchema"},"type":"array","title":"Files"},"full_path":{"type":"string","title":"Full Path"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"},"missing_from_fs":{"type":"boolean","title":"Missing From Fs"},"has_notes":{"type":"boolean","title":"Has Notes"},"siblings":{"items":{"$ref":"#/components/schemas/SiblingRomSchema"},"type":"array","title":"Siblings"},"rom_user":{"$ref":"#/components/schemas/RomUserSchema"},"merged_screenshots":{"items":{"type":"string"},"type":"array","title":"Merged Screenshots"},"merged_ra_metadata":{"anyOf":[{"$ref":"#/components/schemas/RomRAMetadata"},{"type":"null"}]},"user_saves":{"items":{"$ref":"#/components/schemas/SaveSchema"},"type":"array","title":"User Saves"},"user_states":{"items":{"$ref":"#/components/schemas/StateSchema"},"type":"array","title":"User States"},"user_screenshots":{"items":{"$ref":"#/components/schemas/ScreenshotSchema"},"type":"array","title":"User Screenshots"},"user_collections":{"items":{"$ref":"#/components/schemas/UserCollectionSchema"},"type":"array","title":"User Collections"},"all_user_notes":{"items":{"$ref":"#/components/schemas/UserNoteSchema"},"type":"array","title":"All User Notes"}},"type":"object","required":["id","igdb_id","sgdb_id","moby_id","ss_id","ra_id","launchbox_id","hasheous_id","tgdb_id","flashpoint_id","hltb_id","gamelist_id","platform_id","platform_slug","platform_fs_slug","platform_custom_name","platform_display_name","fs_name","fs_name_no_tags","fs_name_no_ext","fs_extension","fs_path","fs_size_bytes","name","slug","summary","alternative_names","youtube_video_id","metadatum","igdb_metadata","moby_metadata","ss_metadata","launchbox_metadata","hasheous_metadata","flashpoint_metadata","hltb_metadata","gamelist_metadata","manual_metadata","path_cover_small","path_cover_large","url_cover","has_manual","path_manual","url_manual","is_unidentified","is_identified","revision","regions","languages","tags","crc_hash","md5_hash","sha1_hash","has_simple_single_file","has_nested_single_file","has_multiple_files","files","full_path","created_at","updated_at","missing_from_fs","has_notes","siblings","rom_user","merged_screenshots","merged_ra_metadata","user_saves","user_states","user_screenshots","user_collections","all_user_notes"],"title":"DetailedRomSchema"},"EarnedAchievement":{"properties":{"id":{"type":"string","title":"Id"},"date":{"type":"string","title":"Date"},"date_hardcore":{"type":"string","title":"Date Hardcore"}},"type":"object","required":["id","date"],"title":"EarnedAchievement"},"EjsControls":{"properties":{"_0":{"additionalProperties":{"$ref":"#/components/schemas/EjsControlsButton"},"type":"object","title":"0"},"_1":{"additionalProperties":{"$ref":"#/components/schemas/EjsControlsButton"},"type":"object","title":"1"},"_2":{"additionalProperties":{"$ref":"#/components/schemas/EjsControlsButton"},"type":"object","title":"2"},"_3":{"additionalProperties":{"$ref":"#/components/schemas/EjsControlsButton"},"type":"object","title":"3"}},"type":"object","required":["_0","_1","_2","_3"],"title":"EjsControls"},"EjsControlsButton":{"properties":{"value":{"type":"string","title":"Value"},"value2":{"type":"string","title":"Value2"}},"type":"object","title":"EjsControlsButton"},"EmulationDict":{"properties":{"DISABLE_EMULATOR_JS":{"type":"boolean","title":"Disable Emulator Js"},"DISABLE_RUFFLE_RS":{"type":"boolean","title":"Disable Ruffle Rs"}},"type":"object","required":["DISABLE_EMULATOR_JS","DISABLE_RUFFLE_RS"],"title":"EmulationDict"},"FilesystemDict":{"properties":{"FS_PLATFORMS":{"items":{"type":"string"},"type":"array","title":"Fs Platforms"}},"type":"object","required":["FS_PLATFORMS"],"title":"FilesystemDict"},"FirmwareSchema":{"properties":{"id":{"type":"integer","title":"Id"},"file_name":{"type":"string","title":"File Name"},"file_name_no_tags":{"type":"string","title":"File Name No Tags"},"file_name_no_ext":{"type":"string","title":"File Name No Ext"},"file_extension":{"type":"string","title":"File Extension"},"file_path":{"type":"string","title":"File Path"},"file_size_bytes":{"type":"integer","title":"File Size Bytes"},"full_path":{"type":"string","title":"Full Path"},"is_verified":{"type":"boolean","title":"Is Verified"},"crc_hash":{"type":"string","title":"Crc Hash"},"md5_hash":{"type":"string","title":"Md5 Hash"},"sha1_hash":{"type":"string","title":"Sha1 Hash"},"missing_from_fs":{"type":"boolean","title":"Missing From Fs"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"}},"type":"object","required":["id","file_name","file_name_no_tags","file_name_no_ext","file_extension","file_path","file_size_bytes","full_path","is_verified","crc_hash","md5_hash","sha1_hash","missing_from_fs","created_at","updated_at"],"title":"FirmwareSchema"},"FrontendDict":{"properties":{"UPLOAD_TIMEOUT":{"type":"integer","title":"Upload Timeout"},"DISABLE_USERPASS_LOGIN":{"type":"boolean","title":"Disable Userpass Login"},"YOUTUBE_BASE_URL":{"type":"string","title":"Youtube Base Url"}},"type":"object","required":["UPLOAD_TIMEOUT","DISABLE_USERPASS_LOGIN","YOUTUBE_BASE_URL"],"title":"FrontendDict"},"GenericTaskMeta":{"properties":{},"type":"object","title":"GenericTaskMeta"},"GenericTaskStatusResponse":{"properties":{"task_name":{"type":"string","title":"Task Name"},"task_id":{"type":"string","title":"Task Id"},"status":{"$ref":"#/components/schemas/JobStatus"},"created_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created At"},"enqueued_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Enqueued At"},"started_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Started At"},"ended_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Ended At"},"task_type":{"type":"string","const":"generic","title":"Task Type"},"meta":{"$ref":"#/components/schemas/GenericTaskMeta"}},"type":"object","required":["task_name","task_id","status","created_at","enqueued_at","started_at","ended_at","task_type","meta"],"title":"GenericTaskStatusResponse"},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"HeartbeatResponse":{"properties":{"SYSTEM":{"$ref":"#/components/schemas/SystemDict"},"METADATA_SOURCES":{"$ref":"#/components/schemas/MetadataSourcesDict"},"FILESYSTEM":{"$ref":"#/components/schemas/FilesystemDict"},"EMULATION":{"$ref":"#/components/schemas/EmulationDict"},"FRONTEND":{"$ref":"#/components/schemas/FrontendDict"},"OIDC":{"$ref":"#/components/schemas/OIDCDict"},"TASKS":{"$ref":"#/components/schemas/TasksDict"}},"type":"object","required":["SYSTEM","METADATA_SOURCES","FILESYSTEM","EMULATION","FRONTEND","OIDC","TASKS"],"title":"HeartbeatResponse"},"IGDBAgeRating":{"properties":{"rating":{"type":"string","title":"Rating"},"category":{"type":"string","title":"Category"},"rating_cover_url":{"type":"string","title":"Rating Cover Url"}},"type":"object","required":["rating","category","rating_cover_url"],"title":"IGDBAgeRating"},"IGDBMetadataMultiplayerMode":{"properties":{"campaigncoop":{"type":"boolean","title":"Campaigncoop"},"dropin":{"type":"boolean","title":"Dropin"},"lancoop":{"type":"boolean","title":"Lancoop"},"offlinecoop":{"type":"boolean","title":"Offlinecoop"},"offlinecoopmax":{"type":"integer","title":"Offlinecoopmax"},"offlinemax":{"type":"integer","title":"Offlinemax"},"onlinecoop":{"type":"integer","title":"Onlinecoop"},"onlinecoopmax":{"type":"integer","title":"Onlinecoopmax"},"onlinemax":{"type":"integer","title":"Onlinemax"},"splitscreen":{"type":"boolean","title":"Splitscreen"},"splitscreenonline":{"type":"boolean","title":"Splitscreenonline"},"platform":{"$ref":"#/components/schemas/IGDBMetadataPlatform"}},"type":"object","required":["campaigncoop","dropin","lancoop","offlinecoop","offlinecoopmax","offlinemax","onlinecoop","onlinecoopmax","onlinemax","splitscreen","splitscreenonline","platform"],"title":"IGDBMetadataMultiplayerMode"},"IGDBMetadataPlatform":{"properties":{"igdb_id":{"type":"integer","title":"Igdb Id"},"name":{"type":"string","title":"Name"}},"type":"object","required":["igdb_id","name"],"title":"IGDBMetadataPlatform"},"IGDBRelatedGame":{"properties":{"id":{"type":"integer","title":"Id"},"name":{"type":"string","title":"Name"},"slug":{"type":"string","title":"Slug"},"type":{"type":"string","title":"Type"},"cover_url":{"type":"string","title":"Cover Url"}},"type":"object","required":["id","name","slug","type","cover_url"],"title":"IGDBRelatedGame"},"InviteLinkSchema":{"properties":{"token":{"type":"string","title":"Token"}},"type":"object","required":["token"],"title":"InviteLinkSchema"},"JobStatus":{"type":"string","enum":["queued","finished","failed","started","deferred","scheduled","stopped","canceled"],"title":"JobStatus","description":"The Status of Job within its lifecycle at any given time."},"LaunchboxImage":{"properties":{"url":{"type":"string","title":"Url"},"type":{"type":"string","title":"Type"},"region":{"type":"string","title":"Region"}},"type":"object","required":["url"],"title":"LaunchboxImage"},"ManualMetadata":{"properties":{"genres":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Genres"},"franchises":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Franchises"},"companies":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Companies"},"game_modes":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Game Modes"},"age_ratings":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Age Ratings"},"first_release_date":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"First Release Date"},"youtube_video_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Youtube Video Id"}},"type":"object","title":"ManualMetadata"},"MetadataSourcesDict":{"properties":{"ANY_SOURCE_ENABLED":{"type":"boolean","title":"Any Source Enabled"},"IGDB_API_ENABLED":{"type":"boolean","title":"Igdb Api Enabled"},"SS_API_ENABLED":{"type":"boolean","title":"Ss Api Enabled"},"MOBY_API_ENABLED":{"type":"boolean","title":"Moby Api Enabled"},"STEAMGRIDDB_API_ENABLED":{"type":"boolean","title":"Steamgriddb Api Enabled"},"RA_API_ENABLED":{"type":"boolean","title":"Ra Api Enabled"},"LAUNCHBOX_API_ENABLED":{"type":"boolean","title":"Launchbox Api Enabled"},"HASHEOUS_API_ENABLED":{"type":"boolean","title":"Hasheous Api Enabled"},"PLAYMATCH_API_ENABLED":{"type":"boolean","title":"Playmatch Api Enabled"},"TGDB_API_ENABLED":{"type":"boolean","title":"Tgdb Api Enabled"},"FLASHPOINT_API_ENABLED":{"type":"boolean","title":"Flashpoint Api Enabled"},"HLTB_API_ENABLED":{"type":"boolean","title":"Hltb Api Enabled"}},"type":"object","required":["ANY_SOURCE_ENABLED","IGDB_API_ENABLED","SS_API_ENABLED","MOBY_API_ENABLED","STEAMGRIDDB_API_ENABLED","RA_API_ENABLED","LAUNCHBOX_API_ENABLED","HASHEOUS_API_ENABLED","PLAYMATCH_API_ENABLED","TGDB_API_ENABLED","FLASHPOINT_API_ENABLED","HLTB_API_ENABLED"],"title":"MetadataSourcesDict"},"MobyMetadataPlatform":{"properties":{"moby_id":{"type":"integer","title":"Moby Id"},"name":{"type":"string","title":"Name"}},"type":"object","required":["moby_id","name"],"title":"MobyMetadataPlatform"},"NetplayICEServer":{"properties":{"urls":{"type":"string","title":"Urls"},"username":{"type":"string","title":"Username"},"credential":{"type":"string","title":"Credential"}},"type":"object","required":["urls"],"title":"NetplayICEServer"},"OIDCDict":{"properties":{"ENABLED":{"type":"boolean","title":"Enabled"},"PROVIDER":{"type":"string","title":"Provider"}},"type":"object","required":["ENABLED","PROVIDER"],"title":"OIDCDict"},"PlatformSchema":{"properties":{"id":{"type":"integer","title":"Id"},"slug":{"type":"string","title":"Slug"},"fs_slug":{"type":"string","title":"Fs Slug"},"rom_count":{"type":"integer","title":"Rom Count"},"name":{"type":"string","title":"Name"},"igdb_slug":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Igdb Slug"},"moby_slug":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Moby Slug"},"hltb_slug":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Hltb Slug"},"custom_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Custom Name"},"igdb_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Igdb Id"},"sgdb_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Sgdb Id"},"moby_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Moby Id"},"launchbox_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Launchbox Id"},"ss_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Ss Id"},"ra_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Ra Id"},"hasheous_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Hasheous Id"},"tgdb_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Tgdb Id"},"flashpoint_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Flashpoint Id"},"category":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Category"},"generation":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Generation"},"family_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Family Name"},"family_slug":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Family Slug"},"url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Url"},"url_logo":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Url Logo"},"firmware":{"items":{"$ref":"#/components/schemas/FirmwareSchema"},"type":"array","title":"Firmware"},"aspect_ratio":{"type":"string","title":"Aspect Ratio","default":"2 / 3"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"},"fs_size_bytes":{"type":"integer","title":"Fs Size Bytes"},"is_unidentified":{"type":"boolean","title":"Is Unidentified"},"is_identified":{"type":"boolean","title":"Is Identified"},"missing_from_fs":{"type":"boolean","title":"Missing From Fs"},"display_name":{"type":"string","title":"Display Name","readOnly":true}},"type":"object","required":["id","slug","fs_slug","rom_count","name","igdb_slug","moby_slug","hltb_slug","created_at","updated_at","fs_size_bytes","is_unidentified","is_identified","missing_from_fs","display_name"],"title":"PlatformSchema"},"RAGameRomAchievement":{"properties":{"ra_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Ra Id"},"title":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Title"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"points":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Points"},"num_awarded":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Num Awarded"},"num_awarded_hardcore":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Num Awarded Hardcore"},"badge_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Badge Id"},"badge_url_lock":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Badge Url Lock"},"badge_path_lock":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Badge Path Lock"},"badge_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Badge Url"},"badge_path":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Badge Path"},"display_order":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Display Order"},"type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Type"}},"type":"object","required":["ra_id","title","description","points","num_awarded","num_awarded_hardcore","badge_id","badge_url_lock","badge_path_lock","badge_url","badge_path","display_order","type"],"title":"RAGameRomAchievement"},"RAProgression":{"properties":{"total":{"type":"integer","title":"Total"},"results":{"items":{"$ref":"#/components/schemas/RAUserGameProgression"},"type":"array","title":"Results"}},"type":"object","title":"RAProgression"},"RAUserGameProgression":{"properties":{"rom_ra_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Rom Ra Id"},"max_possible":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Max Possible"},"num_awarded":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Num Awarded"},"num_awarded_hardcore":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Num Awarded Hardcore"},"most_recent_awarded_date":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Most Recent Awarded Date"},"earned_achievements":{"items":{"$ref":"#/components/schemas/EarnedAchievement"},"type":"array","title":"Earned Achievements"}},"type":"object","required":["rom_ra_id","max_possible","num_awarded","num_awarded_hardcore","earned_achievements"],"title":"RAUserGameProgression"},"Role":{"type":"string","enum":["viewer","editor","admin"],"title":"Role"},"RomFileCategory":{"type":"string","enum":["game","dlc","hack","manual","patch","update","mod","demo","translation","prototype","cheat"],"title":"RomFileCategory"},"RomFileSchema":{"properties":{"id":{"type":"integer","title":"Id"},"rom_id":{"type":"integer","title":"Rom Id"},"file_name":{"type":"string","title":"File Name"},"file_path":{"type":"string","title":"File Path"},"file_size_bytes":{"type":"integer","title":"File Size Bytes"},"full_path":{"type":"string","title":"Full Path"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"},"last_modified":{"type":"string","format":"date-time","title":"Last Modified"},"crc_hash":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Crc Hash"},"md5_hash":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Md5 Hash"},"sha1_hash":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Sha1 Hash"},"category":{"anyOf":[{"$ref":"#/components/schemas/RomFileCategory"},{"type":"null"}]}},"type":"object","required":["id","rom_id","file_name","file_path","file_size_bytes","full_path","created_at","updated_at","last_modified","crc_hash","md5_hash","sha1_hash","category"],"title":"RomFileSchema"},"RomFiltersDict":{"properties":{"genres":{"items":{"type":"string"},"type":"array","title":"Genres"},"franchises":{"items":{"type":"string"},"type":"array","title":"Franchises"},"collections":{"items":{"type":"string"},"type":"array","title":"Collections"},"companies":{"items":{"type":"string"},"type":"array","title":"Companies"},"game_modes":{"items":{"type":"string"},"type":"array","title":"Game Modes"},"age_ratings":{"items":{"type":"string"},"type":"array","title":"Age Ratings"},"player_counts":{"items":{"type":"string"},"type":"array","title":"Player Counts"},"regions":{"items":{"type":"string"},"type":"array","title":"Regions"},"languages":{"items":{"type":"string"},"type":"array","title":"Languages"},"platforms":{"items":{"type":"integer"},"type":"array","title":"Platforms"}},"type":"object","required":["genres","franchises","collections","companies","game_modes","age_ratings","player_counts","regions","languages","platforms"],"title":"RomFiltersDict"},"RomFlashpointMetadata":{"properties":{"franchises":{"items":{"type":"string"},"type":"array","title":"Franchises"},"companies":{"items":{"type":"string"},"type":"array","title":"Companies"},"source":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Source"},"genres":{"items":{"type":"string"},"type":"array","title":"Genres"},"first_release_date":{"type":"string","title":"First Release Date"},"game_modes":{"items":{"type":"string"},"type":"array","title":"Game Modes"},"status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Status"},"version":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Version"},"language":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Language"},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes"}},"type":"object","title":"RomFlashpointMetadata"},"RomGamelistMetadata":{"properties":{"box2d_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Box2D Url"},"box2d_back_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Box2D Back Url"},"box3d_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Box3D Url"},"fanart_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Fanart Url"},"image_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Image Url"},"manual_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Manual Url"},"marquee_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Marquee Url"},"miximage_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Miximage Url"},"physical_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Physical Url"},"screenshot_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Screenshot Url"},"thumbnail_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Thumbnail Url"},"title_screen_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Title Screen Url"},"video_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Video Url"},"rating":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Rating"},"first_release_date":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"First Release Date"},"companies":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Companies"},"franchises":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Franchises"},"genres":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Genres"},"player_count":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Player Count"},"md5_hash":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Md5 Hash"},"box3d_path":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Box3D Path"},"miximage_path":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Miximage Path"},"physical_path":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Physical Path"},"marquee_path":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Marquee Path"},"video_path":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Video Path"}},"type":"object","title":"RomGamelistMetadata"},"RomHLTBMetadata":{"properties":{"main_story":{"type":"integer","title":"Main Story"},"main_story_count":{"type":"integer","title":"Main Story Count"},"main_plus_extra":{"type":"integer","title":"Main Plus Extra"},"main_plus_extra_count":{"type":"integer","title":"Main Plus Extra Count"},"completionist":{"type":"integer","title":"Completionist"},"completionist_count":{"type":"integer","title":"Completionist Count"},"all_styles":{"type":"integer","title":"All Styles"},"all_styles_count":{"type":"integer","title":"All Styles Count"},"release_year":{"type":"integer","title":"Release Year"},"review_score":{"type":"integer","title":"Review Score"},"review_count":{"type":"integer","title":"Review Count"},"popularity":{"type":"integer","title":"Popularity"},"completions":{"type":"integer","title":"Completions"}},"type":"object","title":"RomHLTBMetadata"},"RomHasheousMetadata":{"properties":{"tosec_match":{"type":"boolean","title":"Tosec Match"},"mame_arcade_match":{"type":"boolean","title":"Mame Arcade Match"},"mame_mess_match":{"type":"boolean","title":"Mame Mess Match"},"nointro_match":{"type":"boolean","title":"Nointro Match"},"redump_match":{"type":"boolean","title":"Redump Match"},"whdload_match":{"type":"boolean","title":"Whdload Match"},"ra_match":{"type":"boolean","title":"Ra Match"},"fbneo_match":{"type":"boolean","title":"Fbneo Match"},"puredos_match":{"type":"boolean","title":"Puredos Match"}},"type":"object","title":"RomHasheousMetadata"},"RomIGDBMetadata":{"properties":{"total_rating":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Total Rating"},"aggregated_rating":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Aggregated Rating"},"first_release_date":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"First Release Date"},"youtube_video_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Youtube Video Id"},"genres":{"items":{"type":"string"},"type":"array","title":"Genres"},"franchises":{"items":{"type":"string"},"type":"array","title":"Franchises"},"alternative_names":{"items":{"type":"string"},"type":"array","title":"Alternative Names"},"collections":{"items":{"type":"string"},"type":"array","title":"Collections"},"companies":{"items":{"type":"string"},"type":"array","title":"Companies"},"game_modes":{"items":{"type":"string"},"type":"array","title":"Game Modes"},"age_ratings":{"items":{"$ref":"#/components/schemas/IGDBAgeRating"},"type":"array","title":"Age Ratings"},"platforms":{"items":{"$ref":"#/components/schemas/IGDBMetadataPlatform"},"type":"array","title":"Platforms"},"multiplayer_modes":{"items":{"$ref":"#/components/schemas/IGDBMetadataMultiplayerMode"},"type":"array","title":"Multiplayer Modes"},"player_count":{"type":"string","title":"Player Count"},"expansions":{"items":{"$ref":"#/components/schemas/IGDBRelatedGame"},"type":"array","title":"Expansions"},"dlcs":{"items":{"$ref":"#/components/schemas/IGDBRelatedGame"},"type":"array","title":"Dlcs"},"remasters":{"items":{"$ref":"#/components/schemas/IGDBRelatedGame"},"type":"array","title":"Remasters"},"remakes":{"items":{"$ref":"#/components/schemas/IGDBRelatedGame"},"type":"array","title":"Remakes"},"expanded_games":{"items":{"$ref":"#/components/schemas/IGDBRelatedGame"},"type":"array","title":"Expanded Games"},"ports":{"items":{"$ref":"#/components/schemas/IGDBRelatedGame"},"type":"array","title":"Ports"},"similar_games":{"items":{"$ref":"#/components/schemas/IGDBRelatedGame"},"type":"array","title":"Similar Games"}},"type":"object","title":"RomIGDBMetadata"},"RomLaunchboxMetadata":{"properties":{"first_release_date":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"First Release Date"},"max_players":{"type":"integer","title":"Max Players"},"release_type":{"type":"string","title":"Release Type"},"cooperative":{"type":"boolean","title":"Cooperative"},"youtube_video_id":{"type":"string","title":"Youtube Video Id"},"community_rating":{"type":"number","title":"Community Rating"},"community_rating_count":{"type":"integer","title":"Community Rating Count"},"wikipedia_url":{"type":"string","title":"Wikipedia Url"},"esrb":{"type":"string","title":"Esrb"},"genres":{"items":{"type":"string"},"type":"array","title":"Genres"},"companies":{"items":{"type":"string"},"type":"array","title":"Companies"},"images":{"items":{"$ref":"#/components/schemas/LaunchboxImage"},"type":"array","title":"Images"}},"type":"object","title":"RomLaunchboxMetadata"},"RomMetadataSchema":{"properties":{"rom_id":{"type":"integer","title":"Rom Id"},"genres":{"items":{"type":"string"},"type":"array","title":"Genres"},"franchises":{"items":{"type":"string"},"type":"array","title":"Franchises"},"collections":{"items":{"type":"string"},"type":"array","title":"Collections"},"companies":{"items":{"type":"string"},"type":"array","title":"Companies"},"game_modes":{"items":{"type":"string"},"type":"array","title":"Game Modes"},"age_ratings":{"items":{"type":"string"},"type":"array","title":"Age Ratings"},"player_count":{"type":"string","title":"Player Count"},"first_release_date":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"First Release Date"},"average_rating":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Average Rating"}},"type":"object","required":["rom_id","genres","franchises","collections","companies","game_modes","age_ratings","player_count","first_release_date","average_rating"],"title":"RomMetadataSchema"},"RomMobyMetadata":{"properties":{"moby_score":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Moby Score"},"genres":{"items":{"type":"string"},"type":"array","title":"Genres"},"alternate_titles":{"items":{"type":"string"},"type":"array","title":"Alternate Titles"},"platforms":{"items":{"$ref":"#/components/schemas/MobyMetadataPlatform"},"type":"array","title":"Platforms"}},"type":"object","title":"RomMobyMetadata"},"RomRAMetadata":{"properties":{"first_release_date":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"First Release Date"},"genres":{"items":{"type":"string"},"type":"array","title":"Genres"},"companies":{"items":{"type":"string"},"type":"array","title":"Companies"},"achievements":{"items":{"$ref":"#/components/schemas/RAGameRomAchievement"},"type":"array","title":"Achievements"}},"type":"object","title":"RomRAMetadata"},"RomSSMetadata":{"properties":{"bezel_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Bezel Url"},"box2d_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Box2D Url"},"box2d_side_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Box2D Side Url"},"box2d_back_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Box2D Back Url"},"box3d_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Box3D Url"},"fanart_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Fanart Url"},"fullbox_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Fullbox Url"},"logo_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Logo Url"},"manual_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Manual Url"},"marquee_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Marquee Url"},"miximage_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Miximage Url"},"physical_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Physical Url"},"screenshot_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Screenshot Url"},"steamgrid_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Steamgrid Url"},"title_screen_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Title Screen Url"},"video_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Video Url"},"video_normalized_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Video Normalized Url"},"bezel_path":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Bezel Path"},"box2d_back_path":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Box2D Back Path"},"box3d_path":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Box3D Path"},"fanart_path":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Fanart Path"},"miximage_path":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Miximage Path"},"physical_path":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Physical Path"},"marquee_path":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Marquee Path"},"logo_path":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Logo Path"},"video_path":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Video Path"},"ss_score":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Ss Score"},"first_release_date":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"First Release Date"},"alternative_names":{"items":{"type":"string"},"type":"array","title":"Alternative Names"},"companies":{"items":{"type":"string"},"type":"array","title":"Companies"},"franchises":{"items":{"type":"string"},"type":"array","title":"Franchises"},"game_modes":{"items":{"type":"string"},"type":"array","title":"Game Modes"},"genres":{"items":{"type":"string"},"type":"array","title":"Genres"},"player_count":{"type":"string","title":"Player Count"}},"type":"object","title":"RomSSMetadata"},"RomUserSchema":{"properties":{"id":{"type":"integer","title":"Id"},"user_id":{"type":"integer","title":"User Id"},"rom_id":{"type":"integer","title":"Rom Id"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"},"last_played":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Last Played"},"is_main_sibling":{"type":"boolean","title":"Is Main Sibling"},"backlogged":{"type":"boolean","title":"Backlogged"},"now_playing":{"type":"boolean","title":"Now Playing"},"hidden":{"type":"boolean","title":"Hidden"},"rating":{"type":"integer","title":"Rating"},"difficulty":{"type":"integer","title":"Difficulty"},"completion":{"type":"integer","title":"Completion"},"status":{"anyOf":[{"$ref":"#/components/schemas/RomUserStatus"},{"type":"null"}]},"user__username":{"type":"string","title":"User Username"}},"type":"object","required":["id","user_id","rom_id","created_at","updated_at","last_played","is_main_sibling","backlogged","now_playing","hidden","rating","difficulty","completion","status","user__username"],"title":"RomUserSchema"},"RomUserStatus":{"type":"string","enum":["incomplete","finished","completed_100","retired","never_playing"],"title":"RomUserStatus"},"RoomsResponse":{"properties":{"room_name":{"type":"string","title":"Room Name"},"current":{"type":"integer","title":"Current"},"max":{"type":"integer","title":"Max"},"player_name":{"type":"string","title":"Player Name"},"hasPassword":{"type":"boolean","title":"Haspassword"}},"type":"object","required":["room_name","current","max","player_name","hasPassword"],"title":"RoomsResponse"},"SGDBResource":{"properties":{"thumb":{"type":"string","title":"Thumb"},"url":{"type":"string","title":"Url"},"type":{"type":"string","title":"Type"}},"type":"object","required":["thumb","url","type"],"title":"SGDBResource"},"SaveSchema":{"properties":{"id":{"type":"integer","title":"Id"},"rom_id":{"type":"integer","title":"Rom Id"},"user_id":{"type":"integer","title":"User Id"},"file_name":{"type":"string","title":"File Name"},"file_name_no_tags":{"type":"string","title":"File Name No Tags"},"file_name_no_ext":{"type":"string","title":"File Name No Ext"},"file_extension":{"type":"string","title":"File Extension"},"file_path":{"type":"string","title":"File Path"},"file_size_bytes":{"type":"integer","title":"File Size Bytes"},"full_path":{"type":"string","title":"Full Path"},"download_path":{"type":"string","title":"Download Path"},"missing_from_fs":{"type":"boolean","title":"Missing From Fs"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"},"emulator":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Emulator"},"screenshot":{"anyOf":[{"$ref":"#/components/schemas/ScreenshotSchema"},{"type":"null"}]}},"type":"object","required":["id","rom_id","user_id","file_name","file_name_no_tags","file_name_no_ext","file_extension","file_path","file_size_bytes","full_path","download_path","missing_from_fs","created_at","updated_at","emulator","screenshot"],"title":"SaveSchema"},"ScanStats":{"properties":{"total_platforms":{"type":"integer","title":"Total Platforms"},"total_roms":{"type":"integer","title":"Total Roms"},"scanned_platforms":{"type":"integer","title":"Scanned Platforms"},"new_platforms":{"type":"integer","title":"New Platforms"},"identified_platforms":{"type":"integer","title":"Identified Platforms"},"scanned_roms":{"type":"integer","title":"Scanned Roms"},"new_roms":{"type":"integer","title":"New Roms"},"identified_roms":{"type":"integer","title":"Identified Roms"},"scanned_firmware":{"type":"integer","title":"Scanned Firmware"},"new_firmware":{"type":"integer","title":"New Firmware"}},"type":"object","required":["total_platforms","total_roms","scanned_platforms","new_platforms","identified_platforms","scanned_roms","new_roms","identified_roms","scanned_firmware","new_firmware"],"title":"ScanStats"},"ScanTaskMeta":{"properties":{"scan_stats":{"anyOf":[{"$ref":"#/components/schemas/ScanStats"},{"type":"null"}]}},"type":"object","required":["scan_stats"],"title":"ScanTaskMeta"},"ScanTaskStatusResponse":{"properties":{"task_name":{"type":"string","title":"Task Name"},"task_id":{"type":"string","title":"Task Id"},"status":{"$ref":"#/components/schemas/JobStatus"},"created_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created At"},"enqueued_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Enqueued At"},"started_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Started At"},"ended_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Ended At"},"task_type":{"type":"string","const":"scan","title":"Task Type"},"meta":{"$ref":"#/components/schemas/ScanTaskMeta"}},"type":"object","required":["task_name","task_id","status","created_at","enqueued_at","started_at","ended_at","task_type","meta"],"title":"ScanTaskStatusResponse"},"ScreenshotSchema":{"properties":{"id":{"type":"integer","title":"Id"},"rom_id":{"type":"integer","title":"Rom Id"},"user_id":{"type":"integer","title":"User Id"},"file_name":{"type":"string","title":"File Name"},"file_name_no_tags":{"type":"string","title":"File Name No Tags"},"file_name_no_ext":{"type":"string","title":"File Name No Ext"},"file_extension":{"type":"string","title":"File Extension"},"file_path":{"type":"string","title":"File Path"},"file_size_bytes":{"type":"integer","title":"File Size Bytes"},"full_path":{"type":"string","title":"Full Path"},"download_path":{"type":"string","title":"Download Path"},"missing_from_fs":{"type":"boolean","title":"Missing From Fs"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"}},"type":"object","required":["id","rom_id","user_id","file_name","file_name_no_tags","file_name_no_ext","file_extension","file_path","file_size_bytes","full_path","download_path","missing_from_fs","created_at","updated_at"],"title":"ScreenshotSchema"},"SearchCoverSchema":{"properties":{"name":{"type":"string","title":"Name"},"resources":{"items":{"$ref":"#/components/schemas/SGDBResource"},"type":"array","title":"Resources"}},"type":"object","required":["name","resources"],"title":"SearchCoverSchema"},"SearchRomSchema":{"properties":{"id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Id"},"igdb_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Igdb Id"},"moby_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Moby Id"},"ss_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Ss Id"},"sgdb_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Sgdb Id"},"flashpoint_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Flashpoint Id"},"launchbox_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Launchbox Id"},"platform_id":{"type":"integer","title":"Platform Id"},"name":{"type":"string","title":"Name"},"slug":{"type":"string","title":"Slug","default":""},"summary":{"type":"string","title":"Summary","default":""},"igdb_url_cover":{"type":"string","title":"Igdb Url Cover","default":""},"moby_url_cover":{"type":"string","title":"Moby Url Cover","default":""},"ss_url_cover":{"type":"string","title":"Ss Url Cover","default":""},"sgdb_url_cover":{"type":"string","title":"Sgdb Url Cover","default":""},"flashpoint_url_cover":{"type":"string","title":"Flashpoint Url Cover","default":""},"launchbox_url_cover":{"type":"string","title":"Launchbox Url Cover","default":""},"is_unidentified":{"type":"boolean","title":"Is Unidentified"},"is_identified":{"type":"boolean","title":"Is Identified"}},"type":"object","required":["platform_id","name","is_unidentified","is_identified"],"title":"SearchRomSchema"},"SiblingRomSchema":{"properties":{"id":{"type":"integer","title":"Id"},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"fs_name_no_tags":{"type":"string","title":"Fs Name No Tags"},"fs_name_no_ext":{"type":"string","title":"Fs Name No Ext"},"sort_comparator":{"type":"string","title":"Sort Comparator","readOnly":true}},"type":"object","required":["id","name","fs_name_no_tags","fs_name_no_ext","sort_comparator"],"title":"SiblingRomSchema"},"SimpleRomSchema":{"properties":{"id":{"type":"integer","title":"Id"},"igdb_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Igdb Id"},"sgdb_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Sgdb Id"},"moby_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Moby Id"},"ss_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Ss Id"},"ra_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Ra Id"},"launchbox_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Launchbox Id"},"hasheous_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Hasheous Id"},"tgdb_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Tgdb Id"},"flashpoint_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Flashpoint Id"},"hltb_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Hltb Id"},"gamelist_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Gamelist Id"},"platform_id":{"type":"integer","title":"Platform Id"},"platform_slug":{"type":"string","title":"Platform Slug"},"platform_fs_slug":{"type":"string","title":"Platform Fs Slug"},"platform_custom_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Platform Custom Name"},"platform_display_name":{"type":"string","title":"Platform Display Name"},"fs_name":{"type":"string","title":"Fs Name"},"fs_name_no_tags":{"type":"string","title":"Fs Name No Tags"},"fs_name_no_ext":{"type":"string","title":"Fs Name No Ext"},"fs_extension":{"type":"string","title":"Fs Extension"},"fs_path":{"type":"string","title":"Fs Path"},"fs_size_bytes":{"type":"integer","title":"Fs Size Bytes"},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"slug":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Slug"},"summary":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Summary"},"alternative_names":{"items":{"type":"string"},"type":"array","title":"Alternative Names"},"youtube_video_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Youtube Video Id"},"metadatum":{"$ref":"#/components/schemas/RomMetadataSchema"},"igdb_metadata":{"anyOf":[{"$ref":"#/components/schemas/RomIGDBMetadata"},{"type":"null"}]},"moby_metadata":{"anyOf":[{"$ref":"#/components/schemas/RomMobyMetadata"},{"type":"null"}]},"ss_metadata":{"anyOf":[{"$ref":"#/components/schemas/RomSSMetadata"},{"type":"null"}]},"launchbox_metadata":{"anyOf":[{"$ref":"#/components/schemas/RomLaunchboxMetadata"},{"type":"null"}]},"hasheous_metadata":{"anyOf":[{"$ref":"#/components/schemas/RomHasheousMetadata"},{"type":"null"}]},"flashpoint_metadata":{"anyOf":[{"$ref":"#/components/schemas/RomFlashpointMetadata"},{"type":"null"}]},"hltb_metadata":{"anyOf":[{"$ref":"#/components/schemas/RomHLTBMetadata"},{"type":"null"}]},"gamelist_metadata":{"anyOf":[{"$ref":"#/components/schemas/RomGamelistMetadata"},{"type":"null"}]},"manual_metadata":{"anyOf":[{"$ref":"#/components/schemas/ManualMetadata"},{"type":"null"}]},"path_cover_small":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Path Cover Small"},"path_cover_large":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Path Cover Large"},"url_cover":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Url Cover"},"has_manual":{"type":"boolean","title":"Has Manual"},"path_manual":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Path Manual"},"url_manual":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Url Manual"},"is_identifying":{"type":"boolean","title":"Is Identifying","default":false},"is_unidentified":{"type":"boolean","title":"Is Unidentified"},"is_identified":{"type":"boolean","title":"Is Identified"},"revision":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Revision"},"regions":{"items":{"type":"string"},"type":"array","title":"Regions"},"languages":{"items":{"type":"string"},"type":"array","title":"Languages"},"tags":{"items":{"type":"string"},"type":"array","title":"Tags"},"crc_hash":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Crc Hash"},"md5_hash":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Md5 Hash"},"sha1_hash":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Sha1 Hash"},"has_simple_single_file":{"type":"boolean","title":"Has Simple Single File"},"has_nested_single_file":{"type":"boolean","title":"Has Nested Single File"},"has_multiple_files":{"type":"boolean","title":"Has Multiple Files"},"files":{"items":{"$ref":"#/components/schemas/RomFileSchema"},"type":"array","title":"Files"},"full_path":{"type":"string","title":"Full Path"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"},"missing_from_fs":{"type":"boolean","title":"Missing From Fs"},"has_notes":{"type":"boolean","title":"Has Notes"},"siblings":{"items":{"$ref":"#/components/schemas/SiblingRomSchema"},"type":"array","title":"Siblings"},"rom_user":{"$ref":"#/components/schemas/RomUserSchema"},"merged_screenshots":{"items":{"type":"string"},"type":"array","title":"Merged Screenshots"},"merged_ra_metadata":{"anyOf":[{"$ref":"#/components/schemas/RomRAMetadata"},{"type":"null"}]}},"type":"object","required":["id","igdb_id","sgdb_id","moby_id","ss_id","ra_id","launchbox_id","hasheous_id","tgdb_id","flashpoint_id","hltb_id","gamelist_id","platform_id","platform_slug","platform_fs_slug","platform_custom_name","platform_display_name","fs_name","fs_name_no_tags","fs_name_no_ext","fs_extension","fs_path","fs_size_bytes","name","slug","summary","alternative_names","youtube_video_id","metadatum","igdb_metadata","moby_metadata","ss_metadata","launchbox_metadata","hasheous_metadata","flashpoint_metadata","hltb_metadata","gamelist_metadata","manual_metadata","path_cover_small","path_cover_large","url_cover","has_manual","path_manual","url_manual","is_unidentified","is_identified","revision","regions","languages","tags","crc_hash","md5_hash","sha1_hash","has_simple_single_file","has_nested_single_file","has_multiple_files","files","full_path","created_at","updated_at","missing_from_fs","has_notes","siblings","rom_user","merged_screenshots","merged_ra_metadata"],"title":"SimpleRomSchema"},"SmartCollectionSchema":{"properties":{"name":{"type":"string","title":"Name"},"description":{"type":"string","title":"Description","default":""},"rom_ids":{"items":{"type":"integer"},"type":"array","uniqueItems":true,"title":"Rom Ids"},"rom_count":{"type":"integer","title":"Rom Count"},"path_cover_small":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Path Cover Small"},"path_cover_large":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Path Cover Large"},"path_covers_small":{"items":{"type":"string"},"type":"array","title":"Path Covers Small"},"path_covers_large":{"items":{"type":"string"},"type":"array","title":"Path Covers Large"},"is_public":{"type":"boolean","title":"Is Public","default":false},"is_favorite":{"type":"boolean","title":"Is Favorite","default":false},"is_virtual":{"type":"boolean","title":"Is Virtual","default":false},"is_smart":{"type":"boolean","title":"Is Smart","default":true},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"},"id":{"type":"integer","title":"Id"},"filter_criteria":{"additionalProperties":true,"type":"object","title":"Filter Criteria"},"filter_summary":{"type":"string","title":"Filter Summary"},"user_id":{"type":"integer","title":"User Id"},"user__username":{"type":"string","title":"User Username"}},"type":"object","required":["name","rom_ids","rom_count","path_cover_small","path_cover_large","path_covers_small","path_covers_large","created_at","updated_at","id","filter_criteria","filter_summary","user_id","user__username"],"title":"SmartCollectionSchema"},"StateSchema":{"properties":{"id":{"type":"integer","title":"Id"},"rom_id":{"type":"integer","title":"Rom Id"},"user_id":{"type":"integer","title":"User Id"},"file_name":{"type":"string","title":"File Name"},"file_name_no_tags":{"type":"string","title":"File Name No Tags"},"file_name_no_ext":{"type":"string","title":"File Name No Ext"},"file_extension":{"type":"string","title":"File Extension"},"file_path":{"type":"string","title":"File Path"},"file_size_bytes":{"type":"integer","title":"File Size Bytes"},"full_path":{"type":"string","title":"Full Path"},"download_path":{"type":"string","title":"Download Path"},"missing_from_fs":{"type":"boolean","title":"Missing From Fs"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"},"emulator":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Emulator"},"screenshot":{"anyOf":[{"$ref":"#/components/schemas/ScreenshotSchema"},{"type":"null"}]}},"type":"object","required":["id","rom_id","user_id","file_name","file_name_no_tags","file_name_no_ext","file_extension","file_path","file_size_bytes","full_path","download_path","missing_from_fs","created_at","updated_at","emulator","screenshot"],"title":"StateSchema"},"StatsReturn":{"properties":{"PLATFORMS":{"type":"integer","title":"Platforms"},"ROMS":{"type":"integer","title":"Roms"},"SAVES":{"type":"integer","title":"Saves"},"STATES":{"type":"integer","title":"States"},"SCREENSHOTS":{"type":"integer","title":"Screenshots"},"TOTAL_FILESIZE_BYTES":{"type":"integer","title":"Total Filesize Bytes"}},"type":"object","required":["PLATFORMS","ROMS","SAVES","STATES","SCREENSHOTS","TOTAL_FILESIZE_BYTES"],"title":"StatsReturn"},"SystemDict":{"properties":{"VERSION":{"type":"string","title":"Version"},"SHOW_SETUP_WIZARD":{"type":"boolean","title":"Show Setup Wizard"}},"type":"object","required":["VERSION","SHOW_SETUP_WIZARD"],"title":"SystemDict"},"TaskExecutionResponse":{"properties":{"task_name":{"type":"string","title":"Task Name"},"task_id":{"type":"string","title":"Task Id"},"status":{"$ref":"#/components/schemas/JobStatus"},"created_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created At"},"enqueued_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Enqueued At"}},"type":"object","required":["task_name","task_id","status","created_at","enqueued_at"],"title":"TaskExecutionResponse"},"TaskInfo":{"properties":{"name":{"type":"string","title":"Name"},"type":{"$ref":"#/components/schemas/TaskType"},"manual_run":{"type":"boolean","title":"Manual Run"},"title":{"type":"string","title":"Title"},"description":{"type":"string","title":"Description"},"enabled":{"type":"boolean","title":"Enabled"},"cron_string":{"type":"string","title":"Cron String"}},"type":"object","required":["name","type","manual_run","title","description","enabled","cron_string"],"title":"TaskInfo"},"TaskType":{"type":"string","enum":["scan","conversion","cleanup","update","watcher","generic"],"title":"TaskType","description":"Enumeration of task types for categorization and UI display."},"TasksDict":{"properties":{"ENABLE_SCHEDULED_RESCAN":{"type":"boolean","title":"Enable Scheduled Rescan"},"SCHEDULED_RESCAN_CRON":{"type":"string","title":"Scheduled Rescan Cron"},"ENABLE_SCHEDULED_UPDATE_SWITCH_TITLEDB":{"type":"boolean","title":"Enable Scheduled Update Switch Titledb"},"SCHEDULED_UPDATE_SWITCH_TITLEDB_CRON":{"type":"string","title":"Scheduled Update Switch Titledb Cron"},"ENABLE_SCHEDULED_UPDATE_LAUNCHBOX_METADATA":{"type":"boolean","title":"Enable Scheduled Update Launchbox Metadata"},"SCHEDULED_UPDATE_LAUNCHBOX_METADATA_CRON":{"type":"string","title":"Scheduled Update Launchbox Metadata Cron"},"ENABLE_SCHEDULED_CONVERT_IMAGES_TO_WEBP":{"type":"boolean","title":"Enable Scheduled Convert Images To Webp"},"SCHEDULED_CONVERT_IMAGES_TO_WEBP_CRON":{"type":"string","title":"Scheduled Convert Images To Webp Cron"}},"type":"object","required":["ENABLE_SCHEDULED_RESCAN","SCHEDULED_RESCAN_CRON","ENABLE_SCHEDULED_UPDATE_SWITCH_TITLEDB","SCHEDULED_UPDATE_SWITCH_TITLEDB_CRON","ENABLE_SCHEDULED_UPDATE_LAUNCHBOX_METADATA","SCHEDULED_UPDATE_LAUNCHBOX_METADATA_CRON","ENABLE_SCHEDULED_CONVERT_IMAGES_TO_WEBP","SCHEDULED_CONVERT_IMAGES_TO_WEBP_CRON"],"title":"TasksDict"},"TinfoilFeedFileSchema":{"properties":{"url":{"type":"string","title":"Url"},"size":{"type":"integer","title":"Size"}},"type":"object","required":["url","size"],"title":"TinfoilFeedFileSchema"},"TinfoilFeedSchema":{"properties":{"files":{"items":{"$ref":"#/components/schemas/TinfoilFeedFileSchema"},"type":"array","title":"Files"},"directories":{"items":{"type":"string"},"type":"array","title":"Directories"},"titledb":{"additionalProperties":{"additionalProperties":true,"type":"object"},"type":"object","title":"Titledb"},"success":{"type":"string","title":"Success"},"error":{"type":"string","title":"Error"}},"type":"object","required":["files","directories"],"title":"TinfoilFeedSchema"},"TokenResponse":{"properties":{"access_token":{"type":"string","title":"Access Token"},"refresh_token":{"type":"string","title":"Refresh Token"},"token_type":{"type":"string","title":"Token Type"},"expires":{"type":"integer","title":"Expires"}},"type":"object","required":["access_token","token_type","expires"],"title":"TokenResponse"},"UpdateStats":{"properties":{"processed":{"type":"integer","title":"Processed"},"total":{"type":"integer","title":"Total"}},"type":"object","required":["processed","total"],"title":"UpdateStats"},"UpdateTaskMeta":{"properties":{"update_stats":{"anyOf":[{"$ref":"#/components/schemas/UpdateStats"},{"type":"null"}]}},"type":"object","required":["update_stats"],"title":"UpdateTaskMeta"},"UpdateTaskStatusResponse":{"properties":{"task_name":{"type":"string","title":"Task Name"},"task_id":{"type":"string","title":"Task Id"},"status":{"$ref":"#/components/schemas/JobStatus"},"created_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created At"},"enqueued_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Enqueued At"},"started_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Started At"},"ended_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Ended At"},"task_type":{"type":"string","const":"update","title":"Task Type"},"meta":{"$ref":"#/components/schemas/UpdateTaskMeta"}},"type":"object","required":["task_name","task_id","status","created_at","enqueued_at","started_at","ended_at","task_type","meta"],"title":"UpdateTaskStatusResponse"},"UserCollectionSchema":{"properties":{"id":{"type":"integer","title":"Id"},"name":{"type":"string","title":"Name"}},"type":"object","required":["id","name"],"title":"UserCollectionSchema"},"UserForm":{"properties":{"username":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Username"},"password":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Password"},"email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Email"},"role":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Role"},"enabled":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Enabled"},"ra_username":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Ra Username"},"avatar":{"anyOf":[{"type":"string","format":"binary"},{"type":"null"}],"title":"Avatar"},"ui_settings":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Ui Settings"}},"type":"object","title":"UserForm"},"UserNoteSchema":{"properties":{"id":{"type":"integer","title":"Id"},"title":{"type":"string","title":"Title"},"content":{"type":"string","title":"Content"},"is_public":{"type":"boolean","title":"Is Public"},"tags":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Tags"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"},"user_id":{"type":"integer","title":"User Id"},"username":{"type":"string","title":"Username"}},"type":"object","required":["id","title","content","is_public","created_at","updated_at","user_id","username"],"title":"UserNoteSchema"},"UserSchema":{"properties":{"id":{"type":"integer","title":"Id"},"username":{"type":"string","title":"Username"},"email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Email"},"enabled":{"type":"boolean","title":"Enabled"},"role":{"$ref":"#/components/schemas/Role"},"oauth_scopes":{"items":{"type":"string"},"type":"array","title":"Oauth Scopes"},"avatar_path":{"type":"string","title":"Avatar Path"},"last_login":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Last Login"},"last_active":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Last Active"},"ra_username":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Ra Username"},"ra_progression":{"anyOf":[{"$ref":"#/components/schemas/RAProgression"},{"type":"null"}]},"ui_settings":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Ui Settings"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"}},"type":"object","required":["id","username","email","enabled","role","oauth_scopes","avatar_path","last_login","last_active","created_at","updated_at"],"title":"UserSchema"},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"},"VirtualCollectionSchema":{"properties":{"name":{"type":"string","title":"Name"},"description":{"type":"string","title":"Description"},"rom_ids":{"items":{"type":"integer"},"type":"array","uniqueItems":true,"title":"Rom Ids"},"rom_count":{"type":"integer","title":"Rom Count"},"path_cover_small":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Path Cover Small"},"path_cover_large":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Path Cover Large"},"path_covers_small":{"items":{"type":"string"},"type":"array","title":"Path Covers Small"},"path_covers_large":{"items":{"type":"string"},"type":"array","title":"Path Covers Large"},"is_public":{"type":"boolean","title":"Is Public","default":false},"is_favorite":{"type":"boolean","title":"Is Favorite","default":false},"is_virtual":{"type":"boolean","title":"Is Virtual","default":true},"is_smart":{"type":"boolean","title":"Is Smart","default":false},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"},"id":{"type":"string","title":"Id"},"type":{"type":"string","title":"Type"}},"type":"object","required":["name","description","rom_ids","rom_count","path_cover_small","path_cover_large","path_covers_small","path_covers_large","created_at","updated_at","id","type"],"title":"VirtualCollectionSchema"},"WatcherTaskMeta":{"properties":{},"type":"object","title":"WatcherTaskMeta"},"WatcherTaskStatusResponse":{"properties":{"task_name":{"type":"string","title":"Task Name"},"task_id":{"type":"string","title":"Task Id"},"status":{"$ref":"#/components/schemas/JobStatus"},"created_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created At"},"enqueued_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Enqueued At"},"started_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Started At"},"ended_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Ended At"},"task_type":{"type":"string","const":"watcher","title":"Task Type"},"meta":{"$ref":"#/components/schemas/WatcherTaskMeta"}},"type":"object","required":["task_name","task_id","status","created_at","enqueued_at","started_at","ended_at","task_type","meta"],"title":"WatcherTaskStatusResponse"},"WebrcadeFeedCategorySchema":{"properties":{"title":{"type":"string","title":"Title"},"longTitle":{"type":"string","title":"Longtitle"},"background":{"type":"string","title":"Background"},"thumbnail":{"type":"string","title":"Thumbnail"},"description":{"type":"string","title":"Description"},"items":{"items":{"$ref":"#/components/schemas/WebrcadeFeedItemSchema"},"type":"array","title":"Items"}},"type":"object","required":["title","items"],"title":"WebrcadeFeedCategorySchema"},"WebrcadeFeedItemPropsSchema":{"properties":{"rom":{"type":"string","title":"Rom"}},"type":"object","required":["rom"],"title":"WebrcadeFeedItemPropsSchema"},"WebrcadeFeedItemSchema":{"properties":{"title":{"type":"string","title":"Title"},"longTitle":{"type":"string","title":"Longtitle"},"description":{"type":"string","title":"Description"},"type":{"type":"string","title":"Type"},"thumbnail":{"type":"string","title":"Thumbnail"},"background":{"type":"string","title":"Background"},"props":{"$ref":"#/components/schemas/WebrcadeFeedItemPropsSchema"}},"type":"object","required":["title","type","props"],"title":"WebrcadeFeedItemSchema"},"WebrcadeFeedSchema":{"properties":{"title":{"type":"string","title":"Title"},"longTitle":{"type":"string","title":"Longtitle"},"description":{"type":"string","title":"Description"},"thumbnail":{"type":"string","title":"Thumbnail"},"background":{"type":"string","title":"Background"},"categories":{"items":{"$ref":"#/components/schemas/WebrcadeFeedCategorySchema"},"type":"array","title":"Categories"}},"type":"object","required":["title","categories"],"title":"WebrcadeFeedSchema"}},"securitySchemes":{"OAuth2PasswordBearer":{"type":"oauth2","flows":{"password":{"scopes":{"me.read":"View your profile","roms.read":"View ROMs","platforms.read":"View platforms","assets.read":"View assets","firmware.read":"View firmware","roms.user.read":"View user-rom properties","collections.read":"View collections","me.write":"Modify your profile","assets.write":"Modify assets","roms.user.write":"Modify user-rom properties","collections.write":"Modify collections","roms.write":"Modify ROMs","platforms.write":"Modify platforms","firmware.write":"Modify firmware","users.read":"View users","users.write":"Modify users","tasks.run":"Run tasks"},"tokenUrl":"/token"}}},"HTTPBasic":{"type":"http","scheme":"basic"}}}} \ No newline at end of file diff --git a/src/bun/api/clients.ts b/src/bun/api/clients.ts new file mode 100644 index 0000000..fcaf899 --- /dev/null +++ b/src/bun/api/clients.ts @@ -0,0 +1,38 @@ +import { config } from "./settings"; +import Elysia from "elysia"; + +export const romm = new Elysia({ prefix: "/romm" }) + .all("/*", async ({ request, params, set }) => + { + if (!config.has('rommAddress') && !config.get('rommAddress')) + { + return new Response("Romm Address Not Found", { status: 404 }); + } + + const rommUrl = new URL(config.get('rommAddress')!); + const url = new URL(request.url); + url.pathname = url.pathname.replace(/^\/api\/romm/, ''); + url.host = rommUrl.host; + url.port = rommUrl.port; + url.protocol = rommUrl.protocol; + + // Forward headers (optional: remove host if needed) + const headers = new Headers(request.headers); + headers.delete('host'); + headers.set("accept-encoding", "identity"); + + const rommResponse = await fetch(url, { + method: request.method, + headers, + body: await request.arrayBuffer(), + redirect: 'manual', // avoid ROMM redirects + }); + + set.status = rommResponse.status; + rommResponse.headers.forEach((value, key) => + { + set.headers[key] = value; + }); + + return new Response(rommResponse.body, { status: rommResponse.status }); + }); \ No newline at end of file diff --git a/src/bun/api/rpc.ts b/src/bun/api/rpc.ts new file mode 100644 index 0000000..eb2e933 --- /dev/null +++ b/src/bun/api/rpc.ts @@ -0,0 +1,42 @@ +import { RPC_PORT } from "../../shared/constants"; +import { settings } from "./settings"; +import { romm } from "./clients"; +import Elysia from "elysia"; +import { cors } from "@elysiajs/cors"; +import { host } from "../utils"; + +const api = new Elysia({ prefix: "/api", serve: {} }) + .use(cors()) + .use(romm) + .use(settings); + +export type AppType = typeof api; + +export function RunAPIServer () +{ + console.log("Launching API Server on port ", RPC_PORT); + return { + apiServer: api.listen({ + port: RPC_PORT, + hostname: host, + development: process.env.NODE_ENV === 'development', + fetch (req, server) + { + if (server.upgrade(req, { + data: undefined + })) + { + return; + } + return api.fetch(req); + }, + websocket: { + message (ws, message) + { + + + }, + } + }) + }; +} \ No newline at end of file diff --git a/src/bun/api/settings.ts b/src/bun/api/settings.ts new file mode 100644 index 0000000..118d41c --- /dev/null +++ b/src/bun/api/settings.ts @@ -0,0 +1,29 @@ +import z from "zod"; +import { SettingsSchema, SettingsType } from "../../shared/constants"; +import Conf from "conf"; +import projectPackage from '../../../package.json'; +import Elysia from "elysia"; + +export const config = new Conf({ + projectName: projectPackage.name, + projectSuffix: 'bun', + schema: Object.fromEntries(Object.entries(SettingsSchema.shape).map(([key, schema]) => [key, schema.toJSONSchema() as any])) as any, + defaults: SettingsSchema.parse({}), +}); +console.log("Config Path Located At: ", config.path); + +export const settings = new Elysia({ prefix: '/settings' }) + .get("/:id", async ({ params: { id } }) => + { + const value = config.get(id); + return { value: value }; + }, { + params: z.object({ id: z.keyof(SettingsSchema) }), + }).post('/:id', + async ({ params: { id }, body: { value }, }) => + { + config.set(id, value); + }, { + params: z.object({ id: z.keyof(SettingsSchema) }), + body: z.object({ value: z.any() }) + }); diff --git a/src/bun/index.ts b/src/bun/index.ts index 35266d7..4356ed2 100644 --- a/src/bun/index.ts +++ b/src/bun/index.ts @@ -1,39 +1,55 @@ -import { BrowserWindow, Updater } from "electrobun/bun"; +import { RunBunServer } from './server'; +import { RunAPIServer } from './api/rpc'; +import { spawnBrowser } from './utils/browser-spawner'; +import { BuildParams } from './utils/browser-params'; -const DEV_SERVER_PORT = 5173; -const DEV_SERVER_URL = `http://localhost:${DEV_SERVER_PORT}/Dashboard`; +const api = RunAPIServer(); +let bunServer: { stop: () => void; url: URL; } | undefined; -// Check if Vite dev server is running for HMR -async function getMainViewUrl(): Promise { - const channel = await Updater.localInfo.channel(); - if (channel === "dev") { - try { - await fetch(DEV_SERVER_URL, { method: "HEAD" }); - console.log(`HMR enabled: Using Vite dev server at ${DEV_SERVER_URL}`); - return DEV_SERVER_URL; - } catch { - console.log("Vite dev server not running. Run 'bun run dev:hmr' for HMR support."); - } - } - return "views://mainview/index.html"; +if (!Bun.env.PUBLIC_ACCESS) +{ + bunServer = RunBunServer(); } -// Create the main application window -const url = await getMainViewUrl(); +function cleanup () +{ + bunServer?.stop(); + api.apiServer.stop(); + process.exit(0); +} -const mainWindow = new BrowserWindow({ - title: "GameFlow", - url, - renderer: 'cef', - styleMask: { - Borderless: true, - }, - frame: { - width: 1280, - height: 800, - x: 200, - y: 200, - }, -}); +try +{ + const webviewWorker = new Worker(process.env.IS_BINARY ? "./webview-worker.ts" : new URL("./webview-worker", import.meta.url).href, { + smol: true, + }); + webviewWorker.addEventListener('error', console.error); + await new Promise(resolve => webviewWorker.addEventListener('close', resolve)); + cleanup(); +} +catch (error) +{ + console.error(error); -console.log("React Tailwind Vite app started!"); \ No newline at end of file + const browserParams = await BuildParams(); + + if (!browserParams) + { + console.error("Could not find valid browser"); + process.exit(); + } + + const browser = spawnBrowser({ + browser: browserParams.browser.type, + args: browserParams.args, + env: browserParams.env, + detached: true, + execPath: browserParams.browser.path, + source: browserParams.browser.source, + ipc (message) + { + console.log(message); + }, + onExit: cleanup + }); +} \ No newline at end of file diff --git a/src/bun/server.ts b/src/bun/server.ts new file mode 100644 index 0000000..2003f3b --- /dev/null +++ b/src/bun/server.ts @@ -0,0 +1,22 @@ +import { SERVER_PORT } from "../shared/constants"; +import path from 'node:path'; +import { host } from "./utils"; + +export function RunBunServer () +{ + console.log("Launching Server on port ", SERVER_PORT); + return Bun.serve({ + port: SERVER_PORT, + hostname: host, + routes: { + "/": Bun.file("./dist/index.html"), + // Serve a file by lazily loading it into memory + "/favicon.ico": Bun.file("./dist/favicon.ico"), + }, + fetch: async (req) => + { + const url = new URL(req.url); + return new Response(Bun.file(`./${path.join('dist', url.pathname)}`)); + }, + }); +} \ No newline at end of file diff --git a/src/bun/types.d.ts b/src/bun/types.d.ts new file mode 100644 index 0000000..fa77aaa --- /dev/null +++ b/src/bun/types.d.ts @@ -0,0 +1,19 @@ +declare const IS_BINARY: string; + +declare module 'download-chromium' { + export default function download ({ + platform, + revision = '499413', + log = false, + onProgress = undefined, + installPath = '{__dirname}/.local-chromium' }: { + platform?: 'linux' | 'mac' | 'win32' | 'win64', + revision?: string, + log?: boolean, + installPath?: string, + onProgress?: (percent: number, transferred: number, total: number) => void; + }): Promise + { + + }; +} \ No newline at end of file diff --git a/src/bun/utils.ts b/src/bun/utils.ts new file mode 100644 index 0000000..acd0053 --- /dev/null +++ b/src/bun/utils.ts @@ -0,0 +1,19 @@ + +import { networkInterfaces } from 'node:os'; + +const localIp = Object.values(networkInterfaces()) + .flat() + .find((iface) => iface?.family === 'IPv4' && !iface.internal)?.address || 'localhost'; + +export const host = process.env.PUBLIC_ACCESS ? localIp : 'localhost'; + +export function checkRunning (pid: number) +{ + try + { + return process.kill(pid, 0); + } catch (error: any) + { + return error.code === 'EPERM'; + } +} \ No newline at end of file diff --git a/src/bun/utils/browser-params.ts b/src/bun/utils/browser-params.ts new file mode 100644 index 0000000..4afa59f --- /dev/null +++ b/src/bun/utils/browser-params.ts @@ -0,0 +1,91 @@ +import { SERVER_URL } from "../../shared/constants"; +import os from 'node:os'; +import path, { dirname } from 'node:path'; +import { getBrowserPath } from "./get-browser"; +import { config } from "../api/settings"; +import { host } from "../utils"; + +export async function BuildParams () +{ + const validBrowser = await getBrowserPath({ + browserOrder: ['chrome', 'chromium'] + }); + + if (!validBrowser) + { + return undefined; + } + + const args: string[] = []; + const browserEnv = { + GOOGLE_API_KEY: 'no', + GOOGLE_DEFAULT_CLIENT_ID: 'no', + GOOGLE_DEFAULT_CLIENT_SECRET: 'no', + }; + + if (validBrowser.type === 'chrome' || validBrowser.type === 'chromium') + { + const isEdge = validBrowser.path.toLowerCase().includes('edge') || validBrowser.path.toLowerCase().includes('msedge'); + console.log(`[Browser] Detected: ${validBrowser.type} from ${validBrowser.source} - ${isEdge ? 'Edge' : 'Chrome/Chromium'}`); + + args.push(`--app=${SERVER_URL(host)}`); + args.push(`--app-id=gameflow`); + args.push(`--force-app-mode`); + args.push('--no-default-browser-check'); + args.push('--no-first-run'); + args.push('--disable-infobars'); + args.push("--disable-extensions"); + args.push("--disable-plugins"); + args.push(`--user-data-dir=${path.join(dirname(config.path), 'browser-data')}`); + args.push('--disable-sync'); //Disable syncing to a Google account + args.push('--disable-sync-preferences'); + args.push('--disable-component-update'); + args.push('--allow-insecure-localhost'); + args.push('--auto-accept-camera-and-microphone-capture'); + args.push(`--window-size=${config.get('windowSize.width')},${config.get('windowSize.height')}`); + args.push('--password-store=basic'); + args.push('--block-new-web-contents'); + args.push('--bwsi'); + args.push('--ash-no-nudges'); + args.push('--autoplay-policy=no-user-gesture-required'); // allow autoplay of videos + args.push('--disabled-features=WindowControlsOverlay,navigationControls,Translate,msUndersideButton'); + args.push(`--profile-directory=Default`); + + if (config.has('windowPosition')) + { + args.push(`--window-position=${config.get('windowPosition.x')},${config.get('windowPosition.y')}`); + } + + if (isEdge) + { + // Disable Edge sync and cloud features + args.push('--disable-sync'); + args.push('--disable-background-networking'); + args.push('--disable-client-side-phishing-detection'); + args.push('--disable-component-extensions-with-background-pages'); + args.push('--disable-default-apps'); + args.push('--disable-extensions-except='); + args.push('--disable-feature=TranslateUI'); + args.push('--disable-background-timer-throttling'); + args.push('--disable-backgrounding-occluded-windows'); + args.push('--disable-breakpad'); + args.push('--disable-client-side-phishing-detection'); + args.push('--disable-component-update'); + args.push('--disable-hang-monitor'); + args.push('--disable-ipc-flooding-protection'); + args.push('--disable-popup-blocking'); + args.push('--disable-prompt-on-repost'); + args.push('--disable-renderer-backgrounding'); + args.push('--metrics-recording-only'); + args.push('--no-service-autorun'); + } + + if (os.platform() === 'linux') + { + args.push("--disable-web-security"); + args.push("--no-sandbox"); + } + } + + return { env: browserEnv, args, browser: validBrowser }; +} \ No newline at end of file diff --git a/src/bun/utils/browser-spawner.ts b/src/bun/utils/browser-spawner.ts new file mode 100644 index 0000000..5f59d12 --- /dev/null +++ b/src/bun/utils/browser-spawner.ts @@ -0,0 +1,166 @@ +import { type Subprocess } from "bun"; + +export type RunBrowserType = "chrome" | "chromium" | "firefox" | "edge"; +export type RunBrowserSource = "running" | "system" | "flatpak"; + +/** + * Options for spawning a browser process. + * + * @property browser - The browser type to spawn + * @property args - Optional command-line arguments to pass to the browser + * @property env - Optional environment variables to set for the browser process + * @property detached - If true, the browser process runs independently of the parent + * @property execPath - Full path to the browser executable (required) + * @property source - How the browser was discovered (running, system, or flatpak) + */ +interface SpawnBrowserOptions +{ + browser: RunBrowserType; + args?: string[]; + env?: Record; + detached?: boolean; + execPath: string; // Required: browser executable path from get-browser.ts + source: RunBrowserSource; // How the browser was discovered (running, system, or flatpak) + onExit?: () => void; // Called when the browser exists duh + ipc?: (message: string) => void; +} + +/** + * Spawns a browser process with proper handling for different installation types. + * + * Behavior depends on the browser source: + * - "running": Browser is already running, spawns additional instance + * - "system": Native system installation, spawned directly with execPath + * - "flatpak": Flatpak containerized browser, spawned via `flatpak run` with proper arguments + * + * For Flatpak browsers, uses Steam-style argument ordering: + * `flatpak run [OPTIONS] [APP_ID] @@u @@ [USER_ARGS]` + * + * @param options - Spawn options including browser type, path, source, and arguments + * @returns A Bun Subprocess instance + * @throws Error if execPath is not provided or if browser configuration is invalid + * + * @example + * const browser = await getBrowserPath(); + * if (browser) { + * const proc = spawnBrowser({ + * browser: browser.type, + * args: ["--no-sandbox", "https://example.com"], + * source: browser.source, + * execPath: browser.path, + * detached: true + * }); + * } + */ +export function spawnBrowser ({ + browser, + args = [], + env = {}, + detached = false, + execPath, + source, + onExit, + ipc +}: SpawnBrowserOptions): Subprocess +{ + + // Configuration for both Flatpak and Native + // Contains Flatpak app IDs, internal container paths, and fallback binary names + const config: Record = { + chrome: { + id: "com.google.Chrome", + internalCmd: "/app/bin/chrome", // Explicit command inside container + bin: ["google-chrome", "google-chrome-stable", "chrome"] + }, + chromium: { + id: "org.chromium.Chromium", + internalCmd: "/app/bin/chromium", + bin: ["chromium", "chromium-browser"] + }, + firefox: { + id: "org.mozilla.firefox", + internalCmd: "/app/bin/firefox", + bin: ["firefox"] + }, + edge: { + id: "com.microsoft.Edge", + internalCmd: "/app/bin/edge", // Varies, but usually standard for Edge + bin: ["microsoft-edge", "microsoft-edge-stable"] + } + }; + + const target = config[browser]; + const useFlatpak = source === "flatpak"; + + let cmd: string[]; + let finalEnv: Record | undefined; + + if (useFlatpak) + { + // --- Flatpak Mode (Steam Style) --- + // Structure: flatpak run [ENV] [FLATPAK_OPTS] [APP_ID] @@u @@ [USER_ARGS] + // The @@u @@ syntax enables file forwarding for URL arguments + + const envFlags = Object.entries(env).map(([k, v]) => `--env=${k}=${v}`); + + // We explicitly set the command to ensure we don't rely on the default entrypoint failing + const flatpakOpts = [ + "run", + "--branch=stable", + `--arch=${process.arch === "x64" ? "x86_64" : process.arch}`, // map node arch to flatpak arch + `--command=${target.internalCmd}`, + "--file-forwarding", + ...envFlags // Inject env vars here + ]; + + // Combine: flatpak run ... com.google.Chrome @@u @@ [USER_ARGS] + cmd = [ + "flatpak", + ...flatpakOpts, + target.id, + "@@u", + "@@", + ...args + ]; + + // Clear env for the spawner so it doesn't pollute the flatpak command wrapper + finalEnv = undefined; + console.log(`[Browser] Launching Flatpak: ${cmd.join(" ")}`); + + } else + { + // --- Native Mode --- + // Use the provided execPath directly + cmd = [execPath, ...args]; + finalEnv = { ...process.env, ...env } as Record; + console.log(`[Browser] Launching Native: ${execPath}`); + } + + const processSub = Bun.spawn(cmd, { + env: finalEnv, + stdin: "ignore", + stdout: "inherit", + stderr: "inherit", + ipc, + onExit (_proc, exitCode) + { + if (exitCode !== 0 && exitCode !== null) + { + console.error(`[Browser] Exited with code: ${exitCode}`); + } + onExit?.(); + }, + }); + + if (detached) processSub.unref(); + + return processSub; +} + + +// --- Test Run --- +// spawnBrowser({ +// browser: "chrome", +// args: ["--window-size=1024,640", "--force-device-scale-factor=1.25"], +// detached: true +// }); \ No newline at end of file diff --git a/src/bun/utils/get-browser.ts b/src/bun/utils/get-browser.ts new file mode 100644 index 0000000..73370a2 --- /dev/null +++ b/src/bun/utils/get-browser.ts @@ -0,0 +1,611 @@ +import { spawnSync } from "bun"; +import { platform } from "node:os"; +import { RunBrowserType } from "./browser-spawner"; + +export type GetBrowserType = "chrome" | "chromium" | "firefox"; +export type GetBrowserSource = "running" | "system" | "flatpak"; + +/** + * Browser discovery priority configuration + */ +interface BrowserPriorityConfig +{ + /** Include currently running browser processes in search */ + includeRunning?: boolean; + /** Browser types to search for, in priority order */ + browserOrder?: GetBrowserType[]; + /** Include system default browser on Windows */ + includeSystemDefault?: boolean; + /** Include Flatpak browsers on Linux */ + includeFlatpak?: boolean; +} + +/** + * Browser discovery result containing the executable path, browser type, and discovery source. + */ +interface BrowserResult +{ + /** Full path to the browser executable */ + path: string; + /** Type of browser (chrome, chromium, or firefox) */ + type: GetBrowserType; + /** Source of discovery (running process, system installation, or flatpak) */ + source: GetBrowserSource; +} + +/** + * Main function to find a valid browser executable. + * + * Searches for an available browser based on customizable priority configuration. + * Default priority order: + * 1. Currently running Chrome process (fastest return) + * 2. Windows: Default system browser (if on Windows) + * 3. Standard System Paths (Firefox > Chrome > Chromium by default) + * 4. Flatpak (Linux only) + * + * @param config - Optional priority configuration to customize search behavior + * @returns A promise that resolves to a BrowserResult containing the path, type, and source + * of the discovered browser, or null if no suitable browser is found. + * + * @example + * // Use default priority + * const browser = await getBrowserPath(); + * + * @example + * // Prefer Chrome over Firefox, skip running processes + * const browser = await getBrowserPath({ + * includeRunning: false, + * browserOrder: ['chrome', 'firefox', 'chromium'] + * }); + */ +export async function getBrowserPath (config?: BrowserPriorityConfig): Promise +{ + // Default configuration + const { + includeRunning = true, + browserOrder = ["firefox", "chrome", "chromium"], + includeSystemDefault = true, + includeFlatpak = true + } = config || {}; + + const currentPlatform = platform(); + + // 1. Check for currently running browser process + if (includeRunning) + { + const runningBrowser = await getRunningBrowserPath(browserOrder, currentPlatform); + if (runningBrowser) + { + console.log(`[Found] Running ${runningBrowser.type} process: ${runningBrowser.path}`); + return { ...runningBrowser, source: "running" }; + } + } + + // 2. Windows: Check default system browser + if (includeSystemDefault && currentPlatform === "win32") + { + const defaultBrowser = await getWindowsDefaultBrowser(browserOrder); + if (defaultBrowser && browserOrder.includes(defaultBrowser.type)) + { + console.log(`[Found] Windows default browser: ${defaultBrowser.path} (${defaultBrowser.type})`); + return { ...defaultBrowser, source: "system" }; + } + } + + // 3. Check standard install paths with custom priority + for (const browser of browserOrder) + { + const path = await findSystemBrowser(browser, currentPlatform); + if (path) + { + console.log(`[Found] Installed ${browser}: ${path}`); + return { path, type: browser, source: "system" }; + } + } + + // 4. Check Flatpaks (Linux only) + if (includeFlatpak && currentPlatform === "linux") + { + for (const browser of browserOrder) + { + const path = await findFlatpakBrowser(browser); + if (path) + { + console.log(`[Found] Flatpak ${browser}: ${path}`); + return { path, type: browser, source: "flatpak" }; + } + } + } + + console.error("No suitable browser found."); + return null; +} + +// --- Helper: Find Running Process --- + +/** + * Attempts to find the path of a currently running browser (Chrome, Chromium, or Firefox). + * + * Platform-specific implementations: + * - Windows: Uses PowerShell to query running processes + * - Linux: Uses pgrep to find the process and resolves /proc/[pid]/exe + * - macOS: Uses ps command to find Chrome or Firefox in process list + * + * @param os - The operating system ("win32", "linux", or "darwin") + * @returns An object with path and type of the running browser, or null if not found + */ +async function getRunningBrowserPath (browserOrder: GetBrowserType[], os: string): Promise<{ path: string, type: GetBrowserType; } | null> +{ + try + { + if (os === "win32") + { + // PowerShell is most reliable for getting full paths on Windows + // Check for Firefox first, then Chrome + for (const processName of browserOrder) + { + const cmd = spawnSync([ + "powershell", + "-NoProfile", + "-Command", + `(Get-Process ${processName} -ErrorAction SilentlyContinue | Select-Object -First 1 -ExpandProperty Path)` + ]); + const path = cmd.stdout.toString().trim(); + if (path && await Bun.file(path).exists()) + { + const browserType: GetBrowserType = processName === 'firefox' ? 'firefox' : 'chrome'; + console.log(`[Browser] Found running ${browserType}: ${path}`); + return { path, type: browserType }; + } + } + return null; + } + + if (os === "linux") + { + const names: Record = { + chrome: ['chrome', 'google-chrome', 'google-chrome-stable'], + chromium: ['chromium'], + firefox: ['firefox'], + edge: ['edge'] + }; + + // Find PID of firefox or chrome, then resolve the symlink in /proc + for (const processName of browserOrder.flatMap(b => names[b])) + { + const pgrep = spawnSync(["pgrep", "-o", processName]); // -o = oldest (parent) + const pid = pgrep.stdout.toString().trim(); + + if (!pid) continue; + + // Read the symlink for the executable path using readlink + const linkPath = `/proc/${pid}/exe`; + + // Use shell readlink to resolve the symlink + const readLink = spawnSync(["readlink", "-f", linkPath]); + const finalPath = readLink.stdout.toString().trim(); + + if (finalPath && await Bun.file(finalPath).exists()) + { + const browserType: GetBrowserType = processName === 'firefox' ? 'firefox' : 'chrome'; + console.log(`[Browser] Found running ${browserType}: ${finalPath}`); + return { path: finalPath, type: browserType }; + } + } + return null; + } + + if (os === "darwin") + { + // macOS: ps command to list process paths + const cmd = spawnSync(["ps", "-A", "-o", "comm"]); + const output = cmd.stdout.toString(); + + // Check for Firefox first + const firefoxMatch = output.split('\n').find(line => line.includes("Firefox.app/Contents/MacOS/firefox")); + if (firefoxMatch) + { + console.log(`[Browser] Found running firefox: ${firefoxMatch.trim()}`); + return { path: firefoxMatch.trim(), type: 'firefox' }; + } + + // Check for Chrome + const chromeMatch = output.split('\n').find(line => line.includes("Google Chrome.app/Contents/MacOS/Google Chrome")); + if (chromeMatch) + { + console.log(`[Browser] Found running chrome: ${chromeMatch.trim()}`); + return { path: chromeMatch.trim(), type: 'chrome' }; + } + + return null; + } + } catch (e) + { + // Ignore errors checking running processes + return null; + } + return null; +} + +// --- Helper: Get Windows Default Browser --- + +/** + * Detects the default browser set in Windows via registry queries. + * + * Queries multiple registry locations for Windows 11+ and Windows 10 compatibility: + * - URL associations (Windows 11+) + * - File extension associations (Windows 10) + * - Classic ProgID associations + * + * Falls back through multiple methods if the primary registry keys are unavailable. + * + * @returns An object with the default browser's path and type, or null if detection fails + */ +async function getWindowsDefaultBrowser (allowed: GetBrowserType[]): Promise<{ path: string, type: GetBrowserType; } | null> +{ + try + { + // Query the registry for the default browser + // Windows 10/11 store default browser association in multiple places + const registryKeys = [ + // Windows 11+ (Preferred) + 'HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\Shell\\Associations\\UrlAssociations\\http\\UserChoice', + // Windows 10 fallback + 'HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\FileExts\\.html\\UserChoice', + // Classic method - looks at .html file association + 'HKEY_CLASSES_ROOT\\.html' + ]; + + for (const regKey of registryKeys) + { + try + { + const cmd = spawnSync(["reg", "query", regKey]); + + if (cmd.success) + { + const output = cmd.stdout.toString().toLowerCase(); + + // Check which browser is the default + if ((output.includes('chrome') || output.includes('google')) && allowed.includes('chrome')) + { + const chromePath = await findSystemBrowser("chrome", "win32"); + if (chromePath) return { path: chromePath, type: "chrome" }; + } + + if ((output.includes('msedge') || output.includes('edge')) && allowed.includes('chromium')) + { + const edgePath = await findSystemBrowser("chromium", "win32"); + if (edgePath && edgePath.includes('msedge')) return { path: edgePath, type: "chromium" }; + } + + if (output.includes('firefox') && allowed.includes('firefox')) + { + const firefoxPath = await findSystemBrowser("firefox", "win32"); + if (firefoxPath) return { path: firefoxPath, type: "firefox" }; + } + } + } catch (e) + { + // Try next registry key + } + } + + // Fallback: Try to get progId for .html files + try + { + const progIdCmd = spawnSync(["reg", "query", "HKEY_CLASSES_ROOT\\.html", "/ve"]); + if (progIdCmd.success) + { + const progId = progIdCmd.stdout.toString().match(/REG_SZ\s+(.+?)(?:\r?\n|$)/)?.[1]?.trim(); + + if (progId) + { + // Query the ProgID's shell\\open\\command to get the browser path + const cmdKey = `HKEY_CLASSES_ROOT\\${progId}\\shell\\open\\command`; + const openCmd = spawnSync(["reg", "query", cmdKey, "/ve"]); + + if (openCmd.success) + { + const execPath = openCmd.stdout.toString().match(/REG_SZ\s+"?([^"\r\n]+\.exe)/i)?.[1]; + + if (execPath && await Bun.file(execPath).exists()) + { + // Determine browser type + if (execPath.toLowerCase().includes('chrome') && allowed.includes('chrome')) + { + return { path: execPath, type: "chrome" }; + } else if ((execPath.toLowerCase().includes('edge') || execPath.toLowerCase().includes('msedge')) && allowed.includes('chromium')) + { + return { path: execPath, type: "chromium" }; + } else if (execPath.toLowerCase().includes('firefox') && allowed.includes('firefox')) + { + return { path: execPath, type: "firefox" }; + } + } + } + } + } + } catch (e) + { + // Fallback failed + } + } catch (e) + { + // Default browser detection failed + } + + return null; +} + +// --- Helper: Find System Installed Browser --- + +/** + * Searches for a browser installation in standard system locations. + * + * Platform-specific behavior: + * - Windows: Checks registry and common installation directories (Program Files, AppData, etc.) + * - macOS: Checks Applications folder + * - Linux: Uses `which` command to find binary in $PATH + * + * @param browser - The browser type to search for + * @param os - The operating system ("win32", "linux", or "darwin") + * @returns The full path to the browser executable, or null if not found + */ +async function findSystemBrowser (browser: GetBrowserType, os: string): Promise +{ + if (os === "win32") + { + // First, try registry lookup (most reliable on Windows) + const registryPath = await findBrowserViaRegistry(browser); + if (registryPath) return registryPath; + + // Fallback to standard install paths + const standardPaths = getStandardWindowsPaths(browser); + + for (const fullPath of standardPaths) + { + if (await Bun.file(fullPath).exists()) return fullPath; + } + return null; + } + + if (os === "linux" || os === "darwin") + { + // Common binary names + const binMap: Record = { + chrome: ["google-chrome", "google-chrome-stable", "chrome"], + chromium: ["chromium", "chromium-browser"], + firefox: ["firefox"] + }; + + if (os === "darwin") + { + // macOS standard paths + const macPaths = { + chrome: "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome", + chromium: "/Applications/Chromium.app/Contents/MacOS/Chromium", + firefox: "/Applications/Firefox.app/Contents/MacOS/firefox" + }; + if (await Bun.file(macPaths[browser]).exists()) return macPaths[browser]; + return null; + } + + // Linux: use `which` to find in $PATH + for (const bin of binMap[browser]) + { + const cmd = spawnSync(["which", bin]); + if (cmd.success) + { + const path = cmd.stdout.toString().trim(); + if (path && await Bun.file(path).exists()) return path; + } + } + } + return null; +} + +// --- Helper: Windows Registry Lookup --- + +/** + * Queries Windows registry for browser installation paths. + * + * Checks App Paths registry hives which are populated by browser installers: + * - HKEY_LOCAL_MACHINE (system-wide installations) + * - HKEY_LOCAL_MACHINE\WOW6432Node (32-bit applications on 64-bit systems) + * - HKEY_CURRENT_USER (user-specific installations) + * + * This is more reliable than hardcoded paths as it dynamically finds where + * the browser installer registered itself. + * + * @param browser - The browser type to search for + * @returns The full path to the browser executable from registry, or null if not found + */ +async function findBrowserViaRegistry (browser: GetBrowserType): Promise +{ + try + { + // Registry paths for browser installations + const registryPaths: Record = { + chrome: [ + // Standard Chrome registry paths + 'HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App Paths\\chrome.exe', + 'HKEY_LOCAL_MACHINE\\SOFTWARE\\WOW6432Node\\Microsoft\\Windows\\CurrentVersion\\App Paths\\chrome.exe', + // User-specific Chrome registry + 'HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\App Paths\\chrome.exe' + ], + chromium: [ + 'HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App Paths\\chromium.exe', + 'HKEY_LOCAL_MACHINE\\SOFTWARE\\WOW6432Node\\Microsoft\\Windows\\CurrentVersion\\App Paths\\chromium.exe' + ], + firefox: [ + 'HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App Paths\\firefox.exe', + 'HKEY_LOCAL_MACHINE\\SOFTWARE\\WOW6432Node\\Microsoft\\Windows\\CurrentVersion\\App Paths\\firefox.exe', + // Check Mozilla Firefox registry for install location + 'HKEY_LOCAL_MACHINE\\SOFTWARE\\Mozilla\\Mozilla Firefox' + ] + }; + + for (const regPath of registryPaths[browser]) + { + try + { + const cmd = spawnSync([ + "reg", + "query", + regPath, + "/ve" + ]); + + if (cmd.success) + { + const output = cmd.stdout.toString(); + // Extract path from registry output (format: " (Default) REG_SZ C:\path\to\exe") + const match = output.match(/REG_SZ\s+(.+?)(?:\r?\n|$)/); + if (match && match[1]) + { + const path = match[1].trim(); + if (path && await Bun.file(path).exists()) + { + return path; + } + } + } + } catch (e) + { + // Continue to next registry path + } + } + } catch (e) + { + // Registry lookup failed, will fallback to standard paths + } + return null; +} + +// --- Helper: Standard Windows Browser Paths --- + +/** + * Generates a list of common Windows browser installation paths to check. + * + * Includes: + * - Program Files locations (64-bit and 32-bit) + * - LocalAppData (user-specific installations) + * - Microsoft Edge paths (treated as chromium) + * - Portable installations and custom locations + * + * @param browser - The browser type to generate paths for + * @returns An array of potential browser executable paths + */ +function getStandardWindowsPaths (browser: GetBrowserType): string[] +{ + const paths: string[] = []; + const prefixes = [ + process.env.LOCALAPPDATA, + process.env.PROGRAMFILES, + process.env["PROGRAMFILES(X86)"] + ].filter(Boolean) as string[]; + + // Standard installation patterns + const browserPatterns: Record = { + chrome: [ + "\\Google\\Chrome\\Application\\chrome.exe", + "\\Google\\Chrome\\chrome.exe" + ], + chromium: [ + "\\Chromium\\Application\\chrome.exe", + "\\Chromium\\chromium.exe" + ], + firefox: [ + "\\Mozilla Firefox\\firefox.exe", + "\\Mozilla\\Firefox\\firefox.exe", + "\\Firefox\\firefox.exe" + ] + }; + + // Add standard paths + for (const prefix of prefixes) + { + for (const pattern of browserPatterns[browser]) + { + paths.push(`${prefix}${pattern}`); + } + } + + // Add common user-specific paths (especially for Chrome Portable or custom installations) + const userProfile = process.env.USERPROFILE; + if (userProfile) + { + if (browser === "chrome") + { + paths.push(`${userProfile}\\AppData\\Local\\Google\\Chrome\\Application\\chrome.exe`); + paths.push(`${userProfile}\\AppData\\Roaming\\Google\\Chrome\\Application\\chrome.exe`); + } else if (browser === "firefox") + { + paths.push(`${userProfile}\\AppData\\Local\\Mozilla Firefox\\firefox.exe`); + paths.push(`${userProfile}\\AppData\\Roaming\\Mozilla Firefox\\firefox.exe`); + // Also check for Program Files under user profile (some custom installs) + paths.push(`${userProfile}\\AppData\\Local\\Programs\\Firefox\\firefox.exe`); + } + } + + // Add alternative common locations for Edge (treated as chromium) + if (browser === "chromium") + { + const edgePaths = [ + `${process.env.PROGRAMFILES}\\Microsoft\\Edge\\Application\\msedge.exe`, + `${process.env["PROGRAMFILES(X86)"]}\\Microsoft\\Edge\\Application\\msedge.exe`, + `${userProfile}\\AppData\\Local\\Microsoft\\Edge\\Application\\msedge.exe` + ].filter(p => p); + paths.push(...edgePaths); + } + + return paths; +} + +// --- Helper: Find Flatpak (Linux Only) --- + +/** + * Searches for a Flatpak browser installation on Linux. + * + * Checks if a Flatpak is installed by querying the flatpak command, + * then looks for the exported binary in standard Flatpak export directories. + * + * Flatpak paths checked: + * - /var/lib/flatpak/exports/bin/ (system-wide) + * - ~/.local/share/flatpak/exports/bin/ (user-specific) + * + * @param browser - The browser type to search for + * @returns The path to the Flatpak browser binary, or null if not found + */ +async function findFlatpakBrowser (browser: GetBrowserType): Promise +{ + // Check if flatpak is installed first + if (spawnSync(["which", "flatpak"]).exitCode !== 0) return null; + + const flatpakIds = { + chrome: "com.google.Chrome", + chromium: "org.chromium.Chromium", + firefox: "org.mozilla.firefox" + }; + + const appId = flatpakIds[browser]; + + // Check if specific flatpak is installed + const checkCmd = spawnSync(["flatpak", "info", appId]); + if (checkCmd.success) + { + // We return the flatpak run command wrapper or the path? + // Usually tools expect an executable. For flatpak, we might need a wrapper script + // or just return "flatpak" with arguments. + // However, usually tools want a single path. + // We will return the internal path if accessible, or the flatpak binary path usually isn't enough. + // OPTION A: Return the standard export path if it exists + const exportPath = `/var/lib/flatpak/exports/bin/${appId}`; + if (await Bun.file(exportPath).exists()) return exportPath; + + const userExportPath = `${process.env.HOME}/.local/share/flatpak/exports/bin/${appId}`; + if (await Bun.file(userExportPath).exists()) return userExportPath; + } + return null; +} \ No newline at end of file diff --git a/src/bun/webview-worker.ts b/src/bun/webview-worker.ts new file mode 100644 index 0000000..4eafaac --- /dev/null +++ b/src/bun/webview-worker.ts @@ -0,0 +1,9 @@ +import Webview from "@rcompat/webview"; +import platform from "@rcompat/webview/windows-x64"; +import { SERVER_URL } from "../shared/constants"; +import { host } from "./utils"; + +console.log("Launching Webview"); +const webview = new Webview({ debug: import.meta.env.NODE_ENV === 'development', platform }); +webview.navigate(SERVER_URL(host)); +webview.run(); \ No newline at end of file diff --git a/src/clients/romm/@tanstack/react-query.gen.ts b/src/clients/romm/@tanstack/react-query.gen.ts new file mode 100644 index 0000000..ae5aaab --- /dev/null +++ b/src/clients/romm/@tanstack/react-query.gen.ts @@ -0,0 +1,2335 @@ +// This file is auto-generated by @hey-api/openapi-ts + +import { type DefaultError, type InfiniteData, infiniteQueryOptions, queryOptions, type UseMutationOptions } from '@tanstack/react-query'; + +import { client } from '../client.gen'; +import { addCollectionApiCollectionsPost, addExclusionApiConfigExcludePost, addFirmwareApiFirmwarePost, addPlatformApiPlatformsPost, addPlatformBindingApiConfigSystemPlatformsPost, addPlatformVersionApiConfigSystemVersionsPost, addRomApiRomsPost, addRomManualsApiRomsIdManualsPost, addSaveApiSavesPost, addScreenshotApiScreenshotsPost, addSmartCollectionApiCollectionsSmartPost, addStateApiStatesPost, addUserApiUsersPost, authOpenidApiOauthOpenidGet, createInviteLinkApiUsersInviteLinkPost, createRomNoteApiRomsIdNotesPost, createSetupPlatformsApiSetupPlatformsPost, createUserFromInviteApiUsersRegisterPost, deleteCollectionApiCollectionsIdDelete, deleteExclusionApiConfigExcludeExclusionTypeExclusionValueDelete, deleteFirmwareApiFirmwareDeletePost, deletePlatformApiPlatformsIdDelete, deletePlatformBindingApiConfigSystemPlatformsFsSlugDelete, deletePlatformVersionApiConfigSystemVersionsFsSlugDelete, deleteRomManualsApiRomsIdManualsDelete, deleteRomNoteApiRomsIdNotesNoteIdDelete, deleteRomsApiRomsDeletePost, deleteSavesApiSavesDeletePost, deleteSmartCollectionApiCollectionsSmartIdDelete, deleteStatesApiStatesDeletePost, deleteUserApiUsersIdDelete, downloadRomsApiRomsDownloadGet, exportGamelistApiGamelistExportPost, fpkgiFeedApiFeedsFpkgiPlatformSlugGet, getCollectionApiCollectionsIdGet, getCollectionsApiCollectionsGet, getConfigApiConfigGet, getCurrentUserApiUsersMeGet, getFirmwareApiFirmwareIdGet, getFirmwareContentApiFirmwareIdContentFileNameGet, getPlatformApiPlatformsIdGet, getPlatformFirmwareApiFirmwareGet, getPlatformsApiPlatformsGet, getRawAssetApiRawAssetsPathGet, getRomApiRomsIdGet, getRomByHashApiRomsByHashGet, getRomByMetadataProviderApiRomsByMetadataProviderGet, getRomContentApiRomsIdContentFileNameGet, getRomfileApiRomsFilesIdGet, getRomfileContentApiRomsfilesIdContentFileNameGet, getRomFiltersApiRomsFiltersGet, getRomNotesApiRomsIdNotesGet, getRomsApiRomsGet, getRoomsApiNetplayListGet, getSaveApiSavesIdGet, getSavesApiSavesGet, getSetupLibraryInfoApiSetupLibraryGet, getSmartCollectionApiCollectionsSmartIdGet, getSmartCollectionsApiCollectionsSmartGet, getStateApiStatesIdGet, getStatesApiStatesGet, getSupportedPlatformsEndpointApiPlatformsSupportedGet, getTaskByIdApiTasksTaskIdGet, getTasksStatusApiTasksStatusGet, getUserApiUsersIdGet, getUsersApiUsersGet, getVirtualCollectionApiCollectionsVirtualIdGet, getVirtualCollectionsApiCollectionsVirtualGet, heartbeatApiHeartbeatGet, kekatsuDsFeedApiFeedsKekatsuPlatformSlugGet, listTasksApiTasksGet, loginApiLoginPost, loginViaOpenidApiLoginOpenidGet, logoutApiLogoutPost, metadataHeartbeatApiHeartbeatMetadataSourceGet, type Options, pkgiPs3FeedApiFeedsPkgiPs3ContentTypeGet, pkgiPspFeedApiFeedsPkgiPspContentTypeGet, pkgiPsvitaFeedApiFeedsPkgiPsvitaContentTypeGet, platformsWebrcadeFeedApiFeedsWebrcadeGet, refreshRetroAchievementsApiUsersIdRaRefreshPost, requestPasswordResetApiForgotPasswordPost, resetPasswordApiResetPasswordPost, runAllTasksApiTasksRunPost, runSingleTaskApiTasksRunTaskNamePost, searchCoverApiSearchCoverGet, searchRomApiSearchRomsGet, statsApiStatsGet, tinfoilIndexFeedApiFeedsTinfoilGet, tokenApiTokenPost, updateCollectionApiCollectionsIdPut, updatePlatformApiPlatformsIdPut, updateRomApiRomsIdPut, updateRomNoteApiRomsIdNotesNoteIdPut, updateRomUserApiRomsIdPropsPut, updateSaveApiSavesIdPut, updateSmartCollectionApiCollectionsSmartIdPut, updateStateApiStatesIdPut, updateUserApiUsersIdPut } from '../sdk.gen'; +import type { AddCollectionApiCollectionsPostData, AddCollectionApiCollectionsPostError, AddCollectionApiCollectionsPostResponse, AddExclusionApiConfigExcludePostData, AddFirmwareApiFirmwarePostData, AddFirmwareApiFirmwarePostError, AddFirmwareApiFirmwarePostResponse, AddPlatformApiPlatformsPostData, AddPlatformApiPlatformsPostError, AddPlatformApiPlatformsPostResponse, AddPlatformBindingApiConfigSystemPlatformsPostData, AddPlatformVersionApiConfigSystemVersionsPostData, AddRomApiRomsPostData, AddRomApiRomsPostError, AddRomManualsApiRomsIdManualsPostData, AddRomManualsApiRomsIdManualsPostError, AddSaveApiSavesPostData, AddSaveApiSavesPostError, AddSaveApiSavesPostResponse, AddScreenshotApiScreenshotsPostData, AddScreenshotApiScreenshotsPostError, AddScreenshotApiScreenshotsPostResponse, AddSmartCollectionApiCollectionsSmartPostData, AddSmartCollectionApiCollectionsSmartPostError, AddSmartCollectionApiCollectionsSmartPostResponse, AddStateApiStatesPostData, AddStateApiStatesPostError, AddStateApiStatesPostResponse, AddUserApiUsersPostData, AddUserApiUsersPostError, AddUserApiUsersPostResponse, AuthOpenidApiOauthOpenidGetData, CreateInviteLinkApiUsersInviteLinkPostData, CreateInviteLinkApiUsersInviteLinkPostError, CreateInviteLinkApiUsersInviteLinkPostResponse, CreateRomNoteApiRomsIdNotesPostData, CreateRomNoteApiRomsIdNotesPostError, CreateRomNoteApiRomsIdNotesPostResponse, CreateSetupPlatformsApiSetupPlatformsPostData, CreateSetupPlatformsApiSetupPlatformsPostError, CreateUserFromInviteApiUsersRegisterPostData, CreateUserFromInviteApiUsersRegisterPostError, CreateUserFromInviteApiUsersRegisterPostResponse, DeleteCollectionApiCollectionsIdDeleteData, DeleteCollectionApiCollectionsIdDeleteError, DeleteExclusionApiConfigExcludeExclusionTypeExclusionValueDeleteData, DeleteExclusionApiConfigExcludeExclusionTypeExclusionValueDeleteError, DeleteFirmwareApiFirmwareDeletePostData, DeleteFirmwareApiFirmwareDeletePostError, DeleteFirmwareApiFirmwareDeletePostResponse, DeletePlatformApiPlatformsIdDeleteData, DeletePlatformApiPlatformsIdDeleteError, DeletePlatformBindingApiConfigSystemPlatformsFsSlugDeleteData, DeletePlatformBindingApiConfigSystemPlatformsFsSlugDeleteError, DeletePlatformVersionApiConfigSystemVersionsFsSlugDeleteData, DeletePlatformVersionApiConfigSystemVersionsFsSlugDeleteError, DeleteRomManualsApiRomsIdManualsDeleteData, DeleteRomManualsApiRomsIdManualsDeleteError, DeleteRomNoteApiRomsIdNotesNoteIdDeleteData, DeleteRomNoteApiRomsIdNotesNoteIdDeleteError, DeleteRomNoteApiRomsIdNotesNoteIdDeleteResponse, DeleteRomsApiRomsDeletePostData, DeleteRomsApiRomsDeletePostError, DeleteRomsApiRomsDeletePostResponse, DeleteSavesApiSavesDeletePostData, DeleteSavesApiSavesDeletePostError, DeleteSavesApiSavesDeletePostResponse, DeleteSmartCollectionApiCollectionsSmartIdDeleteData, DeleteSmartCollectionApiCollectionsSmartIdDeleteError, DeleteStatesApiStatesDeletePostData, DeleteStatesApiStatesDeletePostError, DeleteStatesApiStatesDeletePostResponse, DeleteUserApiUsersIdDeleteData, DeleteUserApiUsersIdDeleteError, DownloadRomsApiRomsDownloadGetData, DownloadRomsApiRomsDownloadGetError, ExportGamelistApiGamelistExportPostData, ExportGamelistApiGamelistExportPostError, FpkgiFeedApiFeedsFpkgiPlatformSlugGetData, FpkgiFeedApiFeedsFpkgiPlatformSlugGetError, GetCollectionApiCollectionsIdGetData, GetCollectionApiCollectionsIdGetError, GetCollectionApiCollectionsIdGetResponse, GetCollectionsApiCollectionsGetData, GetCollectionsApiCollectionsGetError, GetCollectionsApiCollectionsGetResponse, GetConfigApiConfigGetData, GetConfigApiConfigGetResponse, GetCurrentUserApiUsersMeGetData, GetCurrentUserApiUsersMeGetResponse, GetFirmwareApiFirmwareIdGetData, GetFirmwareApiFirmwareIdGetError, GetFirmwareApiFirmwareIdGetResponse, GetFirmwareContentApiFirmwareIdContentFileNameGetData, GetFirmwareContentApiFirmwareIdContentFileNameGetError, GetPlatformApiPlatformsIdGetData, GetPlatformApiPlatformsIdGetError, GetPlatformApiPlatformsIdGetResponse, GetPlatformFirmwareApiFirmwareGetData, GetPlatformFirmwareApiFirmwareGetError, GetPlatformFirmwareApiFirmwareGetResponse, GetPlatformsApiPlatformsGetData, GetPlatformsApiPlatformsGetError, GetPlatformsApiPlatformsGetResponse, GetRawAssetApiRawAssetsPathGetData, GetRawAssetApiRawAssetsPathGetError, GetRomApiRomsIdGetData, GetRomApiRomsIdGetError, GetRomApiRomsIdGetResponse, GetRomByHashApiRomsByHashGetData, GetRomByHashApiRomsByHashGetError, GetRomByHashApiRomsByHashGetResponse, GetRomByMetadataProviderApiRomsByMetadataProviderGetData, GetRomByMetadataProviderApiRomsByMetadataProviderGetError, GetRomByMetadataProviderApiRomsByMetadataProviderGetResponse, GetRomContentApiRomsIdContentFileNameGetData, GetRomContentApiRomsIdContentFileNameGetError, GetRomfileApiRomsFilesIdGetData, GetRomfileApiRomsFilesIdGetError, GetRomfileApiRomsFilesIdGetResponse, GetRomfileContentApiRomsfilesIdContentFileNameGetData, GetRomfileContentApiRomsfilesIdContentFileNameGetError, GetRomFiltersApiRomsFiltersGetData, GetRomFiltersApiRomsFiltersGetResponse, GetRomNotesApiRomsIdNotesGetData, GetRomNotesApiRomsIdNotesGetError, GetRomNotesApiRomsIdNotesGetResponse, GetRomsApiRomsGetData, GetRomsApiRomsGetError, GetRomsApiRomsGetResponse, GetRoomsApiNetplayListGetData, GetRoomsApiNetplayListGetError, GetRoomsApiNetplayListGetResponse, GetSaveApiSavesIdGetData, GetSaveApiSavesIdGetError, GetSaveApiSavesIdGetResponse, GetSavesApiSavesGetData, GetSavesApiSavesGetError, GetSavesApiSavesGetResponse, GetSetupLibraryInfoApiSetupLibraryGetData, GetSmartCollectionApiCollectionsSmartIdGetData, GetSmartCollectionApiCollectionsSmartIdGetError, GetSmartCollectionApiCollectionsSmartIdGetResponse, GetSmartCollectionsApiCollectionsSmartGetData, GetSmartCollectionsApiCollectionsSmartGetError, GetSmartCollectionsApiCollectionsSmartGetResponse, GetStateApiStatesIdGetData, GetStateApiStatesIdGetError, GetStateApiStatesIdGetResponse, GetStatesApiStatesGetData, GetStatesApiStatesGetError, GetStatesApiStatesGetResponse, GetSupportedPlatformsEndpointApiPlatformsSupportedGetData, GetSupportedPlatformsEndpointApiPlatformsSupportedGetResponse, GetTaskByIdApiTasksTaskIdGetData, GetTaskByIdApiTasksTaskIdGetError, GetTaskByIdApiTasksTaskIdGetResponse, GetTasksStatusApiTasksStatusGetData, GetTasksStatusApiTasksStatusGetResponse, GetUserApiUsersIdGetData, GetUserApiUsersIdGetError, GetUserApiUsersIdGetResponse, GetUsersApiUsersGetData, GetUsersApiUsersGetResponse, GetVirtualCollectionApiCollectionsVirtualIdGetData, GetVirtualCollectionApiCollectionsVirtualIdGetError, GetVirtualCollectionApiCollectionsVirtualIdGetResponse, GetVirtualCollectionsApiCollectionsVirtualGetData, GetVirtualCollectionsApiCollectionsVirtualGetError, GetVirtualCollectionsApiCollectionsVirtualGetResponse, HeartbeatApiHeartbeatGetData, HeartbeatApiHeartbeatGetResponse, KekatsuDsFeedApiFeedsKekatsuPlatformSlugGetData, KekatsuDsFeedApiFeedsKekatsuPlatformSlugGetError, ListTasksApiTasksGetData, ListTasksApiTasksGetResponse, LoginApiLoginPostData, LoginViaOpenidApiLoginOpenidGetData, LogoutApiLogoutPostData, MetadataHeartbeatApiHeartbeatMetadataSourceGetData, MetadataHeartbeatApiHeartbeatMetadataSourceGetError, MetadataHeartbeatApiHeartbeatMetadataSourceGetResponse, PkgiPs3FeedApiFeedsPkgiPs3ContentTypeGetData, PkgiPs3FeedApiFeedsPkgiPs3ContentTypeGetError, PkgiPspFeedApiFeedsPkgiPspContentTypeGetData, PkgiPspFeedApiFeedsPkgiPspContentTypeGetError, PkgiPsvitaFeedApiFeedsPkgiPsvitaContentTypeGetData, PkgiPsvitaFeedApiFeedsPkgiPsvitaContentTypeGetError, PlatformsWebrcadeFeedApiFeedsWebrcadeGetData, PlatformsWebrcadeFeedApiFeedsWebrcadeGetResponse, RefreshRetroAchievementsApiUsersIdRaRefreshPostData, RefreshRetroAchievementsApiUsersIdRaRefreshPostError, RequestPasswordResetApiForgotPasswordPostData, RequestPasswordResetApiForgotPasswordPostError, ResetPasswordApiResetPasswordPostData, ResetPasswordApiResetPasswordPostError, RunAllTasksApiTasksRunPostData, RunAllTasksApiTasksRunPostResponse, RunSingleTaskApiTasksRunTaskNamePostData, RunSingleTaskApiTasksRunTaskNamePostError, RunSingleTaskApiTasksRunTaskNamePostResponse, SearchCoverApiSearchCoverGetData, SearchCoverApiSearchCoverGetError, SearchCoverApiSearchCoverGetResponse, SearchRomApiSearchRomsGetData, SearchRomApiSearchRomsGetError, SearchRomApiSearchRomsGetResponse, StatsApiStatsGetData, StatsApiStatsGetResponse, TinfoilIndexFeedApiFeedsTinfoilGetData, TinfoilIndexFeedApiFeedsTinfoilGetError, TinfoilIndexFeedApiFeedsTinfoilGetResponse, TokenApiTokenPostData, TokenApiTokenPostError, TokenApiTokenPostResponse, UpdateCollectionApiCollectionsIdPutData, UpdateCollectionApiCollectionsIdPutError, UpdateCollectionApiCollectionsIdPutResponse, UpdatePlatformApiPlatformsIdPutData, UpdatePlatformApiPlatformsIdPutError, UpdatePlatformApiPlatformsIdPutResponse, UpdateRomApiRomsIdPutData, UpdateRomApiRomsIdPutError, UpdateRomApiRomsIdPutResponse, UpdateRomNoteApiRomsIdNotesNoteIdPutData, UpdateRomNoteApiRomsIdNotesNoteIdPutError, UpdateRomNoteApiRomsIdNotesNoteIdPutResponse, UpdateRomUserApiRomsIdPropsPutData, UpdateRomUserApiRomsIdPropsPutError, UpdateRomUserApiRomsIdPropsPutResponse, UpdateSaveApiSavesIdPutData, UpdateSaveApiSavesIdPutError, UpdateSaveApiSavesIdPutResponse, UpdateSmartCollectionApiCollectionsSmartIdPutData, UpdateSmartCollectionApiCollectionsSmartIdPutError, UpdateSmartCollectionApiCollectionsSmartIdPutResponse, UpdateStateApiStatesIdPutData, UpdateStateApiStatesIdPutError, UpdateStateApiStatesIdPutResponse, UpdateUserApiUsersIdPutData, UpdateUserApiUsersIdPutError, UpdateUserApiUsersIdPutResponse } from '../types.gen'; + +export type QueryKey = [ + Pick & { + _id: string; + _infinite?: boolean; + tags?: ReadonlyArray; + } +]; + +const createQueryKey = (id: string, options?: TOptions, infinite?: boolean, tags?: ReadonlyArray): [ + QueryKey[0] +] => { + const params: QueryKey[0] = { _id: id, baseUrl: options?.baseUrl || (options?.client ?? client).getConfig().baseUrl } as QueryKey[0]; + if (infinite) { + params._infinite = infinite; + } + if (tags) { + params.tags = tags; + } + if (options?.body) { + params.body = options.body; + } + if (options?.headers) { + params.headers = options.headers; + } + if (options?.path) { + params.path = options.path; + } + if (options?.query) { + params.query = options.query; + } + return [params]; +}; + +export const heartbeatApiHeartbeatGetQueryKey = (options?: Options) => createQueryKey('heartbeatApiHeartbeatGet', options); + +/** + * Heartbeat + * + * Endpoint to set the CSRF token in cache and return all the basic RomM config + * + * Returns: + * HeartbeatReturn: TypedDict structure with all the defined values in the HeartbeatReturn class. + */ +export const heartbeatApiHeartbeatGetOptions = (options?: Options) => queryOptions>({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await heartbeatApiHeartbeatGet({ + ...options, + ...queryKey[0], + signal, + throwOnError: true + }); + return data; + }, + queryKey: heartbeatApiHeartbeatGetQueryKey(options) +}); + +export const metadataHeartbeatApiHeartbeatMetadataSourceGetQueryKey = (options: Options) => createQueryKey('metadataHeartbeatApiHeartbeatMetadataSourceGet', options); + +/** + * Metadata Heartbeat + * + * Endpoint to return the heartbeat of the metadata sources + */ +export const metadataHeartbeatApiHeartbeatMetadataSourceGetOptions = (options: Options) => queryOptions>({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await metadataHeartbeatApiHeartbeatMetadataSourceGet({ + ...options, + ...queryKey[0], + signal, + throwOnError: true + }); + return data; + }, + queryKey: metadataHeartbeatApiHeartbeatMetadataSourceGetQueryKey(options) +}); + +export const getSetupLibraryInfoApiSetupLibraryGetQueryKey = (options?: Options) => createQueryKey('getSetupLibraryInfoApiSetupLibraryGet', options); + +/** + * Get Setup Library Info + * + * Get library structure information for setup wizard. + * + * Only accessible during initial setup (no admin users) or with authentication. + * + * Returns: + * - detected_structure: "struct_a" (roms/{platform}), "struct_b" ({platform}/roms), or None + * - existing_platforms: list of objects with fs_slug and rom_count + * - supported_platforms: list of all supported platforms with metadata + */ +export const getSetupLibraryInfoApiSetupLibraryGetOptions = (options?: Options) => queryOptions>({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await getSetupLibraryInfoApiSetupLibraryGet({ + ...options, + ...queryKey[0], + signal, + throwOnError: true + }); + return data; + }, + queryKey: getSetupLibraryInfoApiSetupLibraryGetQueryKey(options) +}); + +/** + * Create Setup Platforms + * + * Create platform folders during setup wizard. + * + * Only accessible during initial setup (no admin users) or with authentication. + * + * Args: + * platform_slugs: List of platform fs_slugs to create + * + * Returns: + * - success: bool + * - created_count: number of platforms created + * - message: success or error message + */ +export const createSetupPlatformsApiSetupPlatformsPostMutation = (options?: Partial>): UseMutationOptions> => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (fnOptions) => { + const { data } = await createSetupPlatformsApiSetupPlatformsPost({ + ...options, + ...fnOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; +}; + +/** + * Login + * + * Session login endpoint + * + * Args: + * request (Request): Fastapi Request object + * credentials: Defaults to Depends(HTTPBasic()). + * + * Raises: + * CredentialsException: Invalid credentials + * UserDisabledException: Auth is disabled + */ +export const loginApiLoginPostMutation = (options?: Partial>): UseMutationOptions> => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (fnOptions) => { + const { data } = await loginApiLoginPost({ + ...options, + ...fnOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; +}; + +/** + * Logout + * + * Session logout endpoint + * + * Args: + * request (Request): Fastapi Request object + */ +export const logoutApiLogoutPostMutation = (options?: Partial>): UseMutationOptions> => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (fnOptions) => { + const { data } = await logoutApiLogoutPost({ + ...options, + ...fnOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; +}; + +/** + * Token + * + * OAuth2 token endpoint + * + * Args: + * form_data (Annotated[OAuth2RequestForm, Depends): Form Data with OAuth2 info + * + * Raises: + * HTTPException: Missing refresh token + * HTTPException: Invalid refresh token + * HTTPException: Missing username or password + * HTTPException: Invalid username or password + * HTTPException: Client credentials are not yet supported + * HTTPException: Invalid or unsupported grant type + * HTTPException: Insufficient scope + * + * Returns: + * TokenResponse: TypedDict with the new generated token info + */ +export const tokenApiTokenPostMutation = (options?: Partial>): UseMutationOptions> => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (fnOptions) => { + const { data } = await tokenApiTokenPost({ + ...options, + ...fnOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; +}; + +export const loginViaOpenidApiLoginOpenidGetQueryKey = (options?: Options) => createQueryKey('loginViaOpenidApiLoginOpenidGet', options); + +/** + * Login Via Openid + * + * OIDC login endpoint + * + * Args: + * request (Request): Fastapi Request object + * + * Raises: + * OIDCDisabledException: OAuth is disabled + * OIDCNotConfiguredException: OAuth not configured + * + * Returns: + * RedirectResponse: Redirect to OIDC provider + */ +export const loginViaOpenidApiLoginOpenidGetOptions = (options?: Options) => queryOptions>({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await loginViaOpenidApiLoginOpenidGet({ + ...options, + ...queryKey[0], + signal, + throwOnError: true + }); + return data; + }, + queryKey: loginViaOpenidApiLoginOpenidGetQueryKey(options) +}); + +export const authOpenidApiOauthOpenidGetQueryKey = (options?: Options) => createQueryKey('authOpenidApiOauthOpenidGet', options); + +/** + * Auth Openid + * + * OIDC callback endpoint + * + * Args: + * request (Request): Fastapi Request object + * + * Raises: + * OIDCDisabledException: OAuth is disabled + * OIDCNotConfiguredException: OAuth not configured + * AuthCredentialsException: Invalid credentials + * UserDisabledException: Auth is disabled + * + * Returns: + * RedirectResponse: Redirect to home page + */ +export const authOpenidApiOauthOpenidGetOptions = (options?: Options) => queryOptions>({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await authOpenidApiOauthOpenidGet({ + ...options, + ...queryKey[0], + signal, + throwOnError: true + }); + return data; + }, + queryKey: authOpenidApiOauthOpenidGetQueryKey(options) +}); + +/** + * Request Password Reset + * + * Request a password reset link for the user. + * + * Args: + * username (str): Username of the user requesting the reset + * Returns: + * None: Returns 200 OK status + */ +export const requestPasswordResetApiForgotPasswordPostMutation = (options?: Partial>): UseMutationOptions> => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (fnOptions) => { + const { data } = await requestPasswordResetApiForgotPasswordPost({ + ...options, + ...fnOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; +}; + +/** + * Reset Password + * + * Reset password using the token. + * + * Args: + * token (str): Reset token from the URL + * new_password (str): New user password + * + * Returns: + * None: Returns 200 OK status + */ +export const resetPasswordApiResetPasswordPostMutation = (options?: Partial>): UseMutationOptions> => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (fnOptions) => { + const { data } = await resetPasswordApiResetPasswordPost({ + ...options, + ...fnOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; +}; + +export const getUsersApiUsersGetQueryKey = (options?: Options) => createQueryKey('getUsersApiUsersGet', options); + +/** + * Get Users + * + * Get all users endpoint + * + * Args: + * request (Request): Fastapi Request object + * + * Returns: + * list[UserSchema]: All users stored in the RomM's database + */ +export const getUsersApiUsersGetOptions = (options?: Options) => queryOptions>({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await getUsersApiUsersGet({ + ...options, + ...queryKey[0], + signal, + throwOnError: true + }); + return data; + }, + queryKey: getUsersApiUsersGetQueryKey(options) +}); + +/** + * Add User + * + * Create user endpoint + * + * Args: + * request (Request): Fastapi Requests object + * username (str): User username + * password (str): User password + * email (str): User email + * role (str): RomM Role object represented as string + * + * Returns: + * UserSchema: Newly created user + */ +export const addUserApiUsersPostMutation = (options?: Partial>): UseMutationOptions> => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (fnOptions) => { + const { data } = await addUserApiUsersPost({ + ...options, + ...fnOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; +}; + +/** + * Create Invite Link + * + * Create an invite link for a user. + * + * Args: + * request (Request): FastAPI Request object + * role (str): The role of the user + * + * Returns: + * InviteLinkSchema: Invite link + */ +export const createInviteLinkApiUsersInviteLinkPostMutation = (options?: Partial>): UseMutationOptions> => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (fnOptions) => { + const { data } = await createInviteLinkApiUsersInviteLinkPost({ + ...options, + ...fnOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; +}; + +/** + * Create User From Invite + * + * Create user endpoint with invite link + * + * Args: + * username (str): User username + * email (str): User email + * password (str): User password + * token (str): Invite link token + * + * Returns: + * UserSchema: Newly created user + */ +export const createUserFromInviteApiUsersRegisterPostMutation = (options?: Partial>): UseMutationOptions> => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (fnOptions) => { + const { data } = await createUserFromInviteApiUsersRegisterPost({ + ...options, + ...fnOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; +}; + +export const getCurrentUserApiUsersMeGetQueryKey = (options?: Options) => createQueryKey('getCurrentUserApiUsersMeGet', options); + +/** + * Get Current User + * + * Get current user endpoint + * + * Args: + * request (Request): Fastapi Request object + * + * Returns: + * UserSchema | None: Current user + */ +export const getCurrentUserApiUsersMeGetOptions = (options?: Options) => queryOptions>({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await getCurrentUserApiUsersMeGet({ + ...options, + ...queryKey[0], + signal, + throwOnError: true + }); + return data; + }, + queryKey: getCurrentUserApiUsersMeGetQueryKey(options) +}); + +/** + * Delete User + * + * Delete a user by ID. + * + * Raises: + * HTTPException: User is not found in database + * HTTPException: User deleting itself + * HTTPException: User is the last admin user + */ +export const deleteUserApiUsersIdDeleteMutation = (options?: Partial>): UseMutationOptions> => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (fnOptions) => { + const { data } = await deleteUserApiUsersIdDelete({ + ...options, + ...fnOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; +}; + +export const getUserApiUsersIdGetQueryKey = (options: Options) => createQueryKey('getUserApiUsersIdGet', options); + +/** + * Get User + * + * Get user endpoint + * + * Args: + * request (Request): Fastapi Request object + * + * Returns: + * UserSchem: User stored in the RomM's database + */ +export const getUserApiUsersIdGetOptions = (options: Options) => queryOptions>({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await getUserApiUsersIdGet({ + ...options, + ...queryKey[0], + signal, + throwOnError: true + }); + return data; + }, + queryKey: getUserApiUsersIdGetQueryKey(options) +}); + +/** + * Update User + * + * Update user endpoint + * + * Args: + * request (Request): Fastapi Requests object + * user_id (int): User internal id + * form_data (Annotated[UserUpdateForm, Depends): Form Data with user updated info + * + * Raises: + * HTTPException: User is not found in database + * HTTPException: Username already in use by another user + * + * Returns: + * UserSchema: Updated user info + */ +export const updateUserApiUsersIdPutMutation = (options?: Partial>): UseMutationOptions> => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (fnOptions) => { + const { data } = await updateUserApiUsersIdPut({ + ...options, + ...fnOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; +}; + +/** + * Refresh RetroAchievements + * + * Refresh RetroAchievements progression data for a user. + */ +export const refreshRetroAchievementsApiUsersIdRaRefreshPostMutation = (options?: Partial>): UseMutationOptions> => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (fnOptions) => { + const { data } = await refreshRetroAchievementsApiUsersIdRaRefreshPost({ + ...options, + ...fnOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; +}; + +export const getPlatformsApiPlatformsGetQueryKey = (options?: Options) => createQueryKey('getPlatformsApiPlatformsGet', options); + +/** + * Get Platforms + * + * Retrieve platforms. + */ +export const getPlatformsApiPlatformsGetOptions = (options?: Options) => queryOptions>({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await getPlatformsApiPlatformsGet({ + ...options, + ...queryKey[0], + signal, + throwOnError: true + }); + return data; + }, + queryKey: getPlatformsApiPlatformsGetQueryKey(options) +}); + +/** + * Add Platform + * + * Create a platform. + */ +export const addPlatformApiPlatformsPostMutation = (options?: Partial>): UseMutationOptions> => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (fnOptions) => { + const { data } = await addPlatformApiPlatformsPost({ + ...options, + ...fnOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; +}; + +export const getSupportedPlatformsEndpointApiPlatformsSupportedGetQueryKey = (options?: Options) => createQueryKey('getSupportedPlatformsEndpointApiPlatformsSupportedGet', options); + +/** + * Get Supported Platforms Endpoint + * + * Retrieve the list of supported platforms. + */ +export const getSupportedPlatformsEndpointApiPlatformsSupportedGetOptions = (options?: Options) => queryOptions>({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await getSupportedPlatformsEndpointApiPlatformsSupportedGet({ + ...options, + ...queryKey[0], + signal, + throwOnError: true + }); + return data; + }, + queryKey: getSupportedPlatformsEndpointApiPlatformsSupportedGetQueryKey(options) +}); + +/** + * Delete Platform + * + * Delete a platform by ID. + */ +export const deletePlatformApiPlatformsIdDeleteMutation = (options?: Partial>): UseMutationOptions> => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (fnOptions) => { + const { data } = await deletePlatformApiPlatformsIdDelete({ + ...options, + ...fnOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; +}; + +export const getPlatformApiPlatformsIdGetQueryKey = (options: Options) => createQueryKey('getPlatformApiPlatformsIdGet', options); + +/** + * Get Platform + * + * Retrieve a platform by ID. + */ +export const getPlatformApiPlatformsIdGetOptions = (options: Options) => queryOptions>({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await getPlatformApiPlatformsIdGet({ + ...options, + ...queryKey[0], + signal, + throwOnError: true + }); + return data; + }, + queryKey: getPlatformApiPlatformsIdGetQueryKey(options) +}); + +/** + * Update Platform + * + * Update a platform. + */ +export const updatePlatformApiPlatformsIdPutMutation = (options?: Partial>): UseMutationOptions> => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (fnOptions) => { + const { data } = await updatePlatformApiPlatformsIdPut({ + ...options, + ...fnOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; +}; + +export const getRomsApiRomsGetQueryKey = (options?: Options) => createQueryKey('getRomsApiRomsGet', options); + +/** + * Get Roms + * + * Retrieve roms. + */ +export const getRomsApiRomsGetOptions = (options?: Options) => queryOptions>({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await getRomsApiRomsGet({ + ...options, + ...queryKey[0], + signal, + throwOnError: true + }); + return data; + }, + queryKey: getRomsApiRomsGetQueryKey(options) +}); + +const createInfiniteParams = [0], 'body' | 'headers' | 'path' | 'query'>>(queryKey: QueryKey, page: K) => { + const params = { ...queryKey[0] }; + if (page.body) { + params.body = { + ...queryKey[0].body as any, + ...page.body as any + }; + } + if (page.headers) { + params.headers = { + ...queryKey[0].headers, + ...page.headers + }; + } + if (page.path) { + params.path = { + ...queryKey[0].path as any, + ...page.path as any + }; + } + if (page.query) { + params.query = { + ...queryKey[0].query as any, + ...page.query as any + }; + } + return params as unknown as typeof page; +}; + +export const getRomsApiRomsGetInfiniteQueryKey = (options?: Options): QueryKey> => createQueryKey('getRomsApiRomsGet', options, true); + +/** + * Get Roms + * + * Retrieve roms. + */ +export const getRomsApiRomsGetInfiniteOptions = (options?: Options) => infiniteQueryOptions, QueryKey>, number | Pick>[0], 'body' | 'headers' | 'path' | 'query'>>( +// @ts-ignore +{ + queryFn: async ({ pageParam, queryKey, signal }) => { + // @ts-ignore + const page: Pick>[0], 'body' | 'headers' | 'path' | 'query'> = typeof pageParam === 'object' ? pageParam : { + query: { + offset: pageParam + } + }; + const params = createInfiniteParams(queryKey, page); + const { data } = await getRomsApiRomsGet({ + ...options, + ...params, + signal, + throwOnError: true + }); + return data; + }, + queryKey: getRomsApiRomsGetInfiniteQueryKey(options) +}); + +/** + * Add Rom + * + * Upload a single rom. + */ +export const addRomApiRomsPostMutation = (options?: Partial>): UseMutationOptions> => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (fnOptions) => { + const { data } = await addRomApiRomsPost({ + ...options, + ...fnOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; +}; + +export const downloadRomsApiRomsDownloadGetQueryKey = (options: Options) => createQueryKey('downloadRomsApiRomsDownloadGet', options); + +/** + * Download Roms + * + * Download a list of roms as a zip file. + */ +export const downloadRomsApiRomsDownloadGetOptions = (options: Options) => queryOptions>({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await downloadRomsApiRomsDownloadGet({ + ...options, + ...queryKey[0], + signal, + throwOnError: true + }); + return data; + }, + queryKey: downloadRomsApiRomsDownloadGetQueryKey(options) +}); + +export const getRomByMetadataProviderApiRomsByMetadataProviderGetQueryKey = (options?: Options) => createQueryKey('getRomByMetadataProviderApiRomsByMetadataProviderGet', options); + +/** + * Get Rom By Metadata Provider + * + * Retrieve a rom by metadata ID. + */ +export const getRomByMetadataProviderApiRomsByMetadataProviderGetOptions = (options?: Options) => queryOptions>({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await getRomByMetadataProviderApiRomsByMetadataProviderGet({ + ...options, + ...queryKey[0], + signal, + throwOnError: true + }); + return data; + }, + queryKey: getRomByMetadataProviderApiRomsByMetadataProviderGetQueryKey(options) +}); + +export const getRomByHashApiRomsByHashGetQueryKey = (options?: Options) => createQueryKey('getRomByHashApiRomsByHashGet', options); + +/** + * Get Rom By Hash + */ +export const getRomByHashApiRomsByHashGetOptions = (options?: Options) => queryOptions>({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await getRomByHashApiRomsByHashGet({ + ...options, + ...queryKey[0], + signal, + throwOnError: true + }); + return data; + }, + queryKey: getRomByHashApiRomsByHashGetQueryKey(options) +}); + +export const getRomFiltersApiRomsFiltersGetQueryKey = (options?: Options) => createQueryKey('getRomFiltersApiRomsFiltersGet', options); + +/** + * Get Rom Filters + */ +export const getRomFiltersApiRomsFiltersGetOptions = (options?: Options) => queryOptions>({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await getRomFiltersApiRomsFiltersGet({ + ...options, + ...queryKey[0], + signal, + throwOnError: true + }); + return data; + }, + queryKey: getRomFiltersApiRomsFiltersGetQueryKey(options) +}); + +export const getRomApiRomsIdGetQueryKey = (options: Options) => createQueryKey('getRomApiRomsIdGet', options); + +/** + * Get Rom + * + * Retrieve a rom by ID. + */ +export const getRomApiRomsIdGetOptions = (options: Options) => queryOptions>({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await getRomApiRomsIdGet({ + ...options, + ...queryKey[0], + signal, + throwOnError: true + }); + return data; + }, + queryKey: getRomApiRomsIdGetQueryKey(options) +}); + +/** + * Update Rom + * + * Update a rom. + */ +export const updateRomApiRomsIdPutMutation = (options?: Partial>): UseMutationOptions> => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (fnOptions) => { + const { data } = await updateRomApiRomsIdPut({ + ...options, + ...fnOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; +}; + +export const getRomContentApiRomsIdContentFileNameGetQueryKey = (options: Options) => createQueryKey('getRomContentApiRomsIdContentFileNameGet', options); + +/** + * Get Rom Content + * + * Download a rom. + * + * This endpoint serves the content of the requested rom, as: + * - A single file for single file roms. + * - A zipped file for multi-part roms, including a .m3u file if applicable. + */ +export const getRomContentApiRomsIdContentFileNameGetOptions = (options: Options) => queryOptions>({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await getRomContentApiRomsIdContentFileNameGet({ + ...options, + ...queryKey[0], + signal, + throwOnError: true + }); + return data; + }, + queryKey: getRomContentApiRomsIdContentFileNameGetQueryKey(options) +}); + +/** + * Delete Rom Manuals + * + * Delete manuals for a rom. + */ +export const deleteRomManualsApiRomsIdManualsDeleteMutation = (options?: Partial>): UseMutationOptions> => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (fnOptions) => { + const { data } = await deleteRomManualsApiRomsIdManualsDelete({ + ...options, + ...fnOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; +}; + +/** + * Add Rom Manuals + * + * Upload manuals for a rom. + */ +export const addRomManualsApiRomsIdManualsPostMutation = (options?: Partial>): UseMutationOptions> => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (fnOptions) => { + const { data } = await addRomManualsApiRomsIdManualsPost({ + ...options, + ...fnOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; +}; + +/** + * Delete Roms + * + * Delete roms. + */ +export const deleteRomsApiRomsDeletePostMutation = (options?: Partial>): UseMutationOptions> => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (fnOptions) => { + const { data } = await deleteRomsApiRomsDeletePost({ + ...options, + ...fnOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; +}; + +/** + * Update Rom User + * + * Update rom data associated to the current user. + */ +export const updateRomUserApiRomsIdPropsPutMutation = (options?: Partial>): UseMutationOptions> => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (fnOptions) => { + const { data } = await updateRomUserApiRomsIdPropsPut({ + ...options, + ...fnOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; +}; + +export const getRomfileApiRomsFilesIdGetQueryKey = (options: Options) => createQueryKey('getRomfileApiRomsFilesIdGet', options); + +/** + * Get Romfile + * + * Retrieve a rom file by ID. + */ +export const getRomfileApiRomsFilesIdGetOptions = (options: Options) => queryOptions>({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await getRomfileApiRomsFilesIdGet({ + ...options, + ...queryKey[0], + signal, + throwOnError: true + }); + return data; + }, + queryKey: getRomfileApiRomsFilesIdGetQueryKey(options) +}); + +export const getRomfileContentApiRomsfilesIdContentFileNameGetQueryKey = (options: Options) => createQueryKey('getRomfileContentApiRomsfilesIdContentFileNameGet', options); + +/** + * Get Romfile Content + * + * Download a rom file. + */ +export const getRomfileContentApiRomsfilesIdContentFileNameGetOptions = (options: Options) => queryOptions>({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await getRomfileContentApiRomsfilesIdContentFileNameGet({ + ...options, + ...queryKey[0], + signal, + throwOnError: true + }); + return data; + }, + queryKey: getRomfileContentApiRomsfilesIdContentFileNameGetQueryKey(options) +}); + +export const getRomNotesApiRomsIdNotesGetQueryKey = (options: Options) => createQueryKey('getRomNotesApiRomsIdNotesGet', options); + +/** + * Get Rom Notes + * + * Get all notes for a ROM. + */ +export const getRomNotesApiRomsIdNotesGetOptions = (options: Options) => queryOptions>({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await getRomNotesApiRomsIdNotesGet({ + ...options, + ...queryKey[0], + signal, + throwOnError: true + }); + return data; + }, + queryKey: getRomNotesApiRomsIdNotesGetQueryKey(options) +}); + +/** + * Create Rom Note + * + * Create a new note for a ROM. + */ +export const createRomNoteApiRomsIdNotesPostMutation = (options?: Partial>): UseMutationOptions> => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (fnOptions) => { + const { data } = await createRomNoteApiRomsIdNotesPost({ + ...options, + ...fnOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; +}; + +/** + * Delete Rom Note + * + * Delete a ROM note. + */ +export const deleteRomNoteApiRomsIdNotesNoteIdDeleteMutation = (options?: Partial>): UseMutationOptions> => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (fnOptions) => { + const { data } = await deleteRomNoteApiRomsIdNotesNoteIdDelete({ + ...options, + ...fnOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; +}; + +/** + * Update Rom Note + * + * Update a ROM note. + */ +export const updateRomNoteApiRomsIdNotesNoteIdPutMutation = (options?: Partial>): UseMutationOptions> => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (fnOptions) => { + const { data } = await updateRomNoteApiRomsIdNotesNoteIdPut({ + ...options, + ...fnOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; +}; + +export const searchRomApiSearchRomsGetQueryKey = (options: Options) => createQueryKey('searchRomApiSearchRomsGet', options); + +/** + * Search Rom + * + * Search for rom in metadata providers + * + * Args: + * request (Request): FastAPI request + * rom_id (int): Rom ID + * source (str): Source of the rom + * search_term (str, optional): Search term. Defaults to None. + * search_by (str, optional): Search by name or ID. Defaults to "name". + * search_extended (bool, optional): Search extended info. Defaults to False. + * + * Returns: + * list[SearchRomSchema]: List of matched roms + */ +export const searchRomApiSearchRomsGetOptions = (options: Options) => queryOptions>({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await searchRomApiSearchRomsGet({ + ...options, + ...queryKey[0], + signal, + throwOnError: true + }); + return data; + }, + queryKey: searchRomApiSearchRomsGetQueryKey(options) +}); + +export const searchCoverApiSearchCoverGetQueryKey = (options?: Options) => createQueryKey('searchCoverApiSearchCoverGet', options); + +/** + * Search Cover + */ +export const searchCoverApiSearchCoverGetOptions = (options?: Options) => queryOptions>({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await searchCoverApiSearchCoverGet({ + ...options, + ...queryKey[0], + signal, + throwOnError: true + }); + return data; + }, + queryKey: searchCoverApiSearchCoverGetQueryKey(options) +}); + +export const getSavesApiSavesGetQueryKey = (options?: Options) => createQueryKey('getSavesApiSavesGet', options); + +/** + * Get Saves + */ +export const getSavesApiSavesGetOptions = (options?: Options) => queryOptions>({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await getSavesApiSavesGet({ + ...options, + ...queryKey[0], + signal, + throwOnError: true + }); + return data; + }, + queryKey: getSavesApiSavesGetQueryKey(options) +}); + +/** + * Add Save + */ +export const addSaveApiSavesPostMutation = (options?: Partial>): UseMutationOptions> => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (fnOptions) => { + const { data } = await addSaveApiSavesPost({ + ...options, + ...fnOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; +}; + +export const getSaveApiSavesIdGetQueryKey = (options: Options) => createQueryKey('getSaveApiSavesIdGet', options); + +/** + * Get Save + */ +export const getSaveApiSavesIdGetOptions = (options: Options) => queryOptions>({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await getSaveApiSavesIdGet({ + ...options, + ...queryKey[0], + signal, + throwOnError: true + }); + return data; + }, + queryKey: getSaveApiSavesIdGetQueryKey(options) +}); + +/** + * Update Save + */ +export const updateSaveApiSavesIdPutMutation = (options?: Partial>): UseMutationOptions> => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (fnOptions) => { + const { data } = await updateSaveApiSavesIdPut({ + ...options, + ...fnOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; +}; + +/** + * Delete Saves + * + * Delete saves. + */ +export const deleteSavesApiSavesDeletePostMutation = (options?: Partial>): UseMutationOptions> => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (fnOptions) => { + const { data } = await deleteSavesApiSavesDeletePost({ + ...options, + ...fnOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; +}; + +export const getStatesApiStatesGetQueryKey = (options?: Options) => createQueryKey('getStatesApiStatesGet', options); + +/** + * Get States + */ +export const getStatesApiStatesGetOptions = (options?: Options) => queryOptions>({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await getStatesApiStatesGet({ + ...options, + ...queryKey[0], + signal, + throwOnError: true + }); + return data; + }, + queryKey: getStatesApiStatesGetQueryKey(options) +}); + +/** + * Add State + */ +export const addStateApiStatesPostMutation = (options?: Partial>): UseMutationOptions> => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (fnOptions) => { + const { data } = await addStateApiStatesPost({ + ...options, + ...fnOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; +}; + +export const getStateApiStatesIdGetQueryKey = (options: Options) => createQueryKey('getStateApiStatesIdGet', options); + +/** + * Get State + */ +export const getStateApiStatesIdGetOptions = (options: Options) => queryOptions>({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await getStateApiStatesIdGet({ + ...options, + ...queryKey[0], + signal, + throwOnError: true + }); + return data; + }, + queryKey: getStateApiStatesIdGetQueryKey(options) +}); + +/** + * Update State + */ +export const updateStateApiStatesIdPutMutation = (options?: Partial>): UseMutationOptions> => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (fnOptions) => { + const { data } = await updateStateApiStatesIdPut({ + ...options, + ...fnOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; +}; + +/** + * Delete States + * + * Delete states. + */ +export const deleteStatesApiStatesDeletePostMutation = (options?: Partial>): UseMutationOptions> => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (fnOptions) => { + const { data } = await deleteStatesApiStatesDeletePost({ + ...options, + ...fnOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; +}; + +export const listTasksApiTasksGetQueryKey = (options?: Options) => createQueryKey('listTasksApiTasksGet', options); + +/** + * List Tasks + * + * List all available tasks grouped by task type. + * + * Args: + * request (Request): FastAPI Request object + * Returns: + * GroupedTasksDict: Dictionary with tasks grouped by their type (scheduled, manual, watcher) + */ +export const listTasksApiTasksGetOptions = (options?: Options) => queryOptions>({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await listTasksApiTasksGet({ + ...options, + ...queryKey[0], + signal, + throwOnError: true + }); + return data; + }, + queryKey: listTasksApiTasksGetQueryKey(options) +}); + +export const getTasksStatusApiTasksStatusGetQueryKey = (options?: Options) => createQueryKey('getTasksStatusApiTasksStatusGet', options); + +/** + * Get Tasks Status + * + * Get all active, queued, completed, and failed tasks. + * + * Args: + * request (Request): FastAPI Request object + * Returns: + * list[TaskStatusResponse]: List of all tasks with their current status + */ +export const getTasksStatusApiTasksStatusGetOptions = (options?: Options) => queryOptions>({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await getTasksStatusApiTasksStatusGet({ + ...options, + ...queryKey[0], + signal, + throwOnError: true + }); + return data; + }, + queryKey: getTasksStatusApiTasksStatusGetQueryKey(options) +}); + +export const getTaskByIdApiTasksTaskIdGetQueryKey = (options: Options) => createQueryKey('getTaskByIdApiTasksTaskIdGet', options); + +/** + * Get Task By Id + * + * Get the status of a task by its job ID. + * + * Args: + * request (Request): FastAPI Request object + * task_id (str): Job ID of the task to retrieve status for + * Returns: + * TaskStatusResponse: Task status information + */ +export const getTaskByIdApiTasksTaskIdGetOptions = (options: Options) => queryOptions>({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await getTaskByIdApiTasksTaskIdGet({ + ...options, + ...queryKey[0], + signal, + throwOnError: true + }); + return data; + }, + queryKey: getTaskByIdApiTasksTaskIdGetQueryKey(options) +}); + +/** + * Run All Tasks + * + * Run all runnable tasks endpoint + * + * Args: + * request (Request): FastAPI Request object + * Returns: + * TaskExecutionResponse: Task execution response with details + */ +export const runAllTasksApiTasksRunPostMutation = (options?: Partial>): UseMutationOptions> => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (fnOptions) => { + const { data } = await runAllTasksApiTasksRunPost({ + ...options, + ...fnOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; +}; + +/** + * Run Single Task + * + * Run a single task endpoint. + * + * Args: + * request (Request): FastAPI Request object + * task_name (str): Name of the task to run + * Returns: + * TaskExecutionResponse: Task execution response with details + */ +export const runSingleTaskApiTasksRunTaskNamePostMutation = (options?: Partial>): UseMutationOptions> => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (fnOptions) => { + const { data } = await runSingleTaskApiTasksRunTaskNamePost({ + ...options, + ...fnOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; +}; + +export const platformsWebrcadeFeedApiFeedsWebrcadeGetQueryKey = (options?: Options) => createQueryKey('platformsWebrcadeFeedApiFeedsWebrcadeGet', options); + +/** + * Platforms Webrcade Feed + * + * Get webrcade feed endpoint + * https://docs.webrcade.com/feeds/format/ + * + * Args: + * request (Request): Fastapi Request object + * + * Returns: + * WebrcadeFeedSchema: Webrcade feed object schema + */ +export const platformsWebrcadeFeedApiFeedsWebrcadeGetOptions = (options?: Options) => queryOptions>({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await platformsWebrcadeFeedApiFeedsWebrcadeGet({ + ...options, + ...queryKey[0], + signal, + throwOnError: true + }); + return data; + }, + queryKey: platformsWebrcadeFeedApiFeedsWebrcadeGetQueryKey(options) +}); + +export const tinfoilIndexFeedApiFeedsTinfoilGetQueryKey = (options?: Options) => createQueryKey('tinfoilIndexFeedApiFeedsTinfoilGet', options); + +/** + * Tinfoil Index Feed + * + * Get tinfoil custom index feed endpoint + * https://blawar.github.io/tinfoil/custom_index/ + * + * Args: + * request (Request): Fastapi Request object + * slug (str, optional): Platform slug. Defaults to "switch". + * + * Returns: + * TinfoilFeedSchema: Tinfoil feed object schema + */ +export const tinfoilIndexFeedApiFeedsTinfoilGetOptions = (options?: Options) => queryOptions>({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await tinfoilIndexFeedApiFeedsTinfoilGet({ + ...options, + ...queryKey[0], + signal, + throwOnError: true + }); + return data; + }, + queryKey: tinfoilIndexFeedApiFeedsTinfoilGetQueryKey(options) +}); + +export const pkgiPs3FeedApiFeedsPkgiPs3ContentTypeGetQueryKey = (options: Options) => createQueryKey('pkgiPs3FeedApiFeedsPkgiPs3ContentTypeGet', options); + +/** + * Pkgi Ps3 Feed + * + * Get PKGi PS3 feed endpoint + * https://github.com/bucanero/pkgi-ps3 + * + * Args: + * request (Request): Fastapi Request object + * content_type (str): Content type (game, dlc, demo, update, patch, mod, translation, prototype) + * + * Returns: + * Response: txt file with PKGi PS3 database format + */ +export const pkgiPs3FeedApiFeedsPkgiPs3ContentTypeGetOptions = (options: Options) => queryOptions>({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await pkgiPs3FeedApiFeedsPkgiPs3ContentTypeGet({ + ...options, + ...queryKey[0], + signal, + throwOnError: true + }); + return data; + }, + queryKey: pkgiPs3FeedApiFeedsPkgiPs3ContentTypeGetQueryKey(options) +}); + +export const pkgiPsvitaFeedApiFeedsPkgiPsvitaContentTypeGetQueryKey = (options: Options) => createQueryKey('pkgiPsvitaFeedApiFeedsPkgiPsvitaContentTypeGet', options); + +/** + * Pkgi Psvita Feed + * + * Get PKGi PS Vita feed endpoint + * https://github.com/mmozeiko/pkgi + * + * Args: + * request (Request): Fastapi Request object + * content_type (str): Content type (game, dlc, demo, update, patch, mod, translation, prototype) + * + * Returns: + * Response: txt file with PKGi PS Vita database format + */ +export const pkgiPsvitaFeedApiFeedsPkgiPsvitaContentTypeGetOptions = (options: Options) => queryOptions>({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await pkgiPsvitaFeedApiFeedsPkgiPsvitaContentTypeGet({ + ...options, + ...queryKey[0], + signal, + throwOnError: true + }); + return data; + }, + queryKey: pkgiPsvitaFeedApiFeedsPkgiPsvitaContentTypeGetQueryKey(options) +}); + +export const pkgiPspFeedApiFeedsPkgiPspContentTypeGetQueryKey = (options: Options) => createQueryKey('pkgiPspFeedApiFeedsPkgiPspContentTypeGet', options); + +/** + * Pkgi Psp Feed + * + * Get PKGi PSP feed endpoint + * https://github.com/bucanero/pkgi-psp + * + * Args: + * request (Request): Fastapi Request object + * content_type (str): Content type (game, dlc, demo, update, patch, mod, translation, prototype) + * + * Returns: + * Response: txt file with PKGi PSP database format + */ +export const pkgiPspFeedApiFeedsPkgiPspContentTypeGetOptions = (options: Options) => queryOptions>({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await pkgiPspFeedApiFeedsPkgiPspContentTypeGet({ + ...options, + ...queryKey[0], + signal, + throwOnError: true + }); + return data; + }, + queryKey: pkgiPspFeedApiFeedsPkgiPspContentTypeGetQueryKey(options) +}); + +export const fpkgiFeedApiFeedsFpkgiPlatformSlugGetQueryKey = (options: Options) => createQueryKey('fpkgiFeedApiFeedsFpkgiPlatformSlugGet', options); + +/** + * Fpkgi Feed + * + * https://github.com/ItsJokerZz/FPKGi + * + * Args: + * request (Request): Fastapi Request object + * platform_slug (str): Platform slug (ps4, ps5) + * + * Returns: + * Response: JSON file in FPKGi format + */ +export const fpkgiFeedApiFeedsFpkgiPlatformSlugGetOptions = (options: Options) => queryOptions>({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await fpkgiFeedApiFeedsFpkgiPlatformSlugGet({ + ...options, + ...queryKey[0], + signal, + throwOnError: true + }); + return data; + }, + queryKey: fpkgiFeedApiFeedsFpkgiPlatformSlugGetQueryKey(options) +}); + +export const kekatsuDsFeedApiFeedsKekatsuPlatformSlugGetQueryKey = (options: Options) => createQueryKey('kekatsuDsFeedApiFeedsKekatsuPlatformSlugGet', options); + +/** + * Kekatsu Ds Feed + * + * Get Kekatsu DS feed endpoint + * https://github.com/cavv-dev/Kekatsu-DS + * + * Args: + * request (Request): Fastapi Request object + * platform_slug (str): Platform slug (nds, nintendo-ds, ds, gba, etc.) + * + * Returns: + * Response: Text file with Kekatsu DS database format + */ +export const kekatsuDsFeedApiFeedsKekatsuPlatformSlugGetOptions = (options: Options) => queryOptions>({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await kekatsuDsFeedApiFeedsKekatsuPlatformSlugGet({ + ...options, + ...queryKey[0], + signal, + throwOnError: true + }); + return data; + }, + queryKey: kekatsuDsFeedApiFeedsKekatsuPlatformSlugGetQueryKey(options) +}); + +export const getConfigApiConfigGetQueryKey = (options?: Options) => createQueryKey('getConfigApiConfigGet', options); + +/** + * Get Config + * + * Get config endpoint + * + * Returns: + * ConfigResponse: RomM's configuration + */ +export const getConfigApiConfigGetOptions = (options?: Options) => queryOptions>({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await getConfigApiConfigGet({ + ...options, + ...queryKey[0], + signal, + throwOnError: true + }); + return data; + }, + queryKey: getConfigApiConfigGetQueryKey(options) +}); + +/** + * Add Platform Binding + * + * Add platform binding to the configuration + */ +export const addPlatformBindingApiConfigSystemPlatformsPostMutation = (options?: Partial>): UseMutationOptions> => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (fnOptions) => { + const { data } = await addPlatformBindingApiConfigSystemPlatformsPost({ + ...options, + ...fnOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; +}; + +/** + * Delete Platform Binding + * + * Delete platform binding from the configuration + */ +export const deletePlatformBindingApiConfigSystemPlatformsFsSlugDeleteMutation = (options?: Partial>): UseMutationOptions> => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (fnOptions) => { + const { data } = await deletePlatformBindingApiConfigSystemPlatformsFsSlugDelete({ + ...options, + ...fnOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; +}; + +/** + * Add Platform Version + * + * Add platform version to the configuration + */ +export const addPlatformVersionApiConfigSystemVersionsPostMutation = (options?: Partial>): UseMutationOptions> => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (fnOptions) => { + const { data } = await addPlatformVersionApiConfigSystemVersionsPost({ + ...options, + ...fnOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; +}; + +/** + * Delete Platform Version + * + * Delete platform version from the configuration + */ +export const deletePlatformVersionApiConfigSystemVersionsFsSlugDeleteMutation = (options?: Partial>): UseMutationOptions> => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (fnOptions) => { + const { data } = await deletePlatformVersionApiConfigSystemVersionsFsSlugDelete({ + ...options, + ...fnOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; +}; + +/** + * Add Exclusion + * + * Add platform exclusion to the configuration + */ +export const addExclusionApiConfigExcludePostMutation = (options?: Partial>): UseMutationOptions> => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (fnOptions) => { + const { data } = await addExclusionApiConfigExcludePost({ + ...options, + ...fnOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; +}; + +/** + * Delete Exclusion + * + * Delete platform binding from the configuration + */ +export const deleteExclusionApiConfigExcludeExclusionTypeExclusionValueDeleteMutation = (options?: Partial>): UseMutationOptions> => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (fnOptions) => { + const { data } = await deleteExclusionApiConfigExcludeExclusionTypeExclusionValueDelete({ + ...options, + ...fnOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; +}; + +export const statsApiStatsGetQueryKey = (options?: Options) => createQueryKey('statsApiStatsGet', options); + +/** + * Stats + * + * Endpoint to return the current RomM stats + * + * Returns: + * dict: Dictionary with all the stats + */ +export const statsApiStatsGetOptions = (options?: Options) => queryOptions>({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await statsApiStatsGet({ + ...options, + ...queryKey[0], + signal, + throwOnError: true + }); + return data; + }, + queryKey: statsApiStatsGetQueryKey(options) +}); + +export const getRawAssetApiRawAssetsPathGetQueryKey = (options: Options) => createQueryKey('getRawAssetApiRawAssetsPathGet', options); + +/** + * Get Raw Asset + * + * Download a single asset file + * + * Args: + * request (Request): Fastapi Request object + * path (str): Relative path to the asset file + * + * Returns: + * FileResponse: Returns a single asset file + * + * Raises: + * HTTPException: 404 if asset not found or access denied + */ +export const getRawAssetApiRawAssetsPathGetOptions = (options: Options) => queryOptions>({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await getRawAssetApiRawAssetsPathGet({ + ...options, + ...queryKey[0], + signal, + throwOnError: true + }); + return data; + }, + queryKey: getRawAssetApiRawAssetsPathGetQueryKey(options) +}); + +/** + * Add Screenshot + */ +export const addScreenshotApiScreenshotsPostMutation = (options?: Partial>): UseMutationOptions> => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (fnOptions) => { + const { data } = await addScreenshotApiScreenshotsPost({ + ...options, + ...fnOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; +}; + +export const getPlatformFirmwareApiFirmwareGetQueryKey = (options?: Options) => createQueryKey('getPlatformFirmwareApiFirmwareGet', options); + +/** + * Get Platform Firmware + * + * Get firmware endpoint + * + * Args: + * request (Request): Fastapi Request object + * + * Returns: + * list[FirmwareSchema]: Firmware stored in the database + */ +export const getPlatformFirmwareApiFirmwareGetOptions = (options?: Options) => queryOptions>({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await getPlatformFirmwareApiFirmwareGet({ + ...options, + ...queryKey[0], + signal, + throwOnError: true + }); + return data; + }, + queryKey: getPlatformFirmwareApiFirmwareGetQueryKey(options) +}); + +/** + * Add Firmware + * + * Upload firmware files endpoint + * + * Args: + * request (Request): Fastapi Request object + * platform_slug (str): Slug of the platform where to upload the files + * files (list[UploadFile], optional): List of files to upload + * + * Raises: + * HTTPException + * + * Returns: + * AddFirmwareResponse: Standard message response + */ +export const addFirmwareApiFirmwarePostMutation = (options?: Partial>): UseMutationOptions> => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (fnOptions) => { + const { data } = await addFirmwareApiFirmwarePost({ + ...options, + ...fnOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; +}; + +export const getFirmwareApiFirmwareIdGetQueryKey = (options: Options) => createQueryKey('getFirmwareApiFirmwareIdGet', options); + +/** + * Get Firmware + * + * Get firmware endpoint + * + * Args: + * request (Request): Fastapi Request object + * id (int): Firmware internal id + * + * Returns: + * FirmwareSchema: Firmware stored in the database + */ +export const getFirmwareApiFirmwareIdGetOptions = (options: Options) => queryOptions>({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await getFirmwareApiFirmwareIdGet({ + ...options, + ...queryKey[0], + signal, + throwOnError: true + }); + return data; + }, + queryKey: getFirmwareApiFirmwareIdGetQueryKey(options) +}); + +export const getFirmwareContentApiFirmwareIdContentFileNameGetQueryKey = (options: Options) => createQueryKey('getFirmwareContentApiFirmwareIdContentFileNameGet', options); + +/** + * Get Firmware Content + * + * Download firmware endpoint + * + * Args: + * request (Request): Fastapi Request object + * id (int): Rom internal id + * file_name (str): Required due to a bug in emulatorjs + * + * Returns: + * FileResponse: Returns the firmware file + */ +export const getFirmwareContentApiFirmwareIdContentFileNameGetOptions = (options: Options) => queryOptions>({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await getFirmwareContentApiFirmwareIdContentFileNameGet({ + ...options, + ...queryKey[0], + signal, + throwOnError: true + }); + return data; + }, + queryKey: getFirmwareContentApiFirmwareIdContentFileNameGetQueryKey(options) +}); + +/** + * Delete Firmware + * + * Delete firmware. + */ +export const deleteFirmwareApiFirmwareDeletePostMutation = (options?: Partial>): UseMutationOptions> => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (fnOptions) => { + const { data } = await deleteFirmwareApiFirmwareDeletePost({ + ...options, + ...fnOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; +}; + +export const getCollectionsApiCollectionsGetQueryKey = (options?: Options) => createQueryKey('getCollectionsApiCollectionsGet', options); + +/** + * Get Collections + * + * Get collections endpoint + * + * Args: + * request (Request): Fastapi Request object + * updated_after: Filter collections updated after this datetime + * + * Returns: + * list[CollectionSchema]: List of collections + */ +export const getCollectionsApiCollectionsGetOptions = (options?: Options) => queryOptions>({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await getCollectionsApiCollectionsGet({ + ...options, + ...queryKey[0], + signal, + throwOnError: true + }); + return data; + }, + queryKey: getCollectionsApiCollectionsGetQueryKey(options) +}); + +/** + * Add Collection + * + * Create collection endpoint + * + * Args: + * request (Request): Fastapi Request object + * + * Returns: + * CollectionSchema: Just created collection + */ +export const addCollectionApiCollectionsPostMutation = (options?: Partial>): UseMutationOptions> => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (fnOptions) => { + const { data } = await addCollectionApiCollectionsPost({ + ...options, + ...fnOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; +}; + +export const getSmartCollectionsApiCollectionsSmartGetQueryKey = (options?: Options) => createQueryKey('getSmartCollectionsApiCollectionsSmartGet', options); + +/** + * Get Smart Collections + * + * Get smart collections endpoint + * + * Args: + * request (Request): Fastapi Request object + * updated_after: Filter smart collections updated after this datetime + * + * Returns: + * list[SmartCollectionSchema]: List of smart collections + */ +export const getSmartCollectionsApiCollectionsSmartGetOptions = (options?: Options) => queryOptions>({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await getSmartCollectionsApiCollectionsSmartGet({ + ...options, + ...queryKey[0], + signal, + throwOnError: true + }); + return data; + }, + queryKey: getSmartCollectionsApiCollectionsSmartGetQueryKey(options) +}); + +/** + * Add Smart Collection + * + * Create smart collection endpoint + * + * Args: + * request (Request): Fastapi Request object + * + * Returns: + * SmartCollectionSchema: Just created smart collection + */ +export const addSmartCollectionApiCollectionsSmartPostMutation = (options?: Partial>): UseMutationOptions> => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (fnOptions) => { + const { data } = await addSmartCollectionApiCollectionsSmartPost({ + ...options, + ...fnOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; +}; + +export const getVirtualCollectionsApiCollectionsVirtualGetQueryKey = (options: Options) => createQueryKey('getVirtualCollectionsApiCollectionsVirtualGet', options); + +/** + * Get Virtual Collections + * + * Get virtual collections endpoint + * + * Args: + * request (Request): Fastapi Request object + * + * Returns: + * list[VirtualCollectionSchema]: List of virtual collections + */ +export const getVirtualCollectionsApiCollectionsVirtualGetOptions = (options: Options) => queryOptions>({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await getVirtualCollectionsApiCollectionsVirtualGet({ + ...options, + ...queryKey[0], + signal, + throwOnError: true + }); + return data; + }, + queryKey: getVirtualCollectionsApiCollectionsVirtualGetQueryKey(options) +}); + +/** + * Delete Collection + * + * Delete a collection by ID. + */ +export const deleteCollectionApiCollectionsIdDeleteMutation = (options?: Partial>): UseMutationOptions> => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (fnOptions) => { + const { data } = await deleteCollectionApiCollectionsIdDelete({ + ...options, + ...fnOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; +}; + +export const getCollectionApiCollectionsIdGetQueryKey = (options: Options) => createQueryKey('getCollectionApiCollectionsIdGet', options); + +/** + * Get Collection + * + * Get collections endpoint + * + * Args: + * request (Request): Fastapi Request object + * id (int, optional): Collection id. Defaults to None. + * + * Returns: + * CollectionSchema: Collection + */ +export const getCollectionApiCollectionsIdGetOptions = (options: Options) => queryOptions>({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await getCollectionApiCollectionsIdGet({ + ...options, + ...queryKey[0], + signal, + throwOnError: true + }); + return data; + }, + queryKey: getCollectionApiCollectionsIdGetQueryKey(options) +}); + +/** + * Update Collection + * + * Update collection endpoint + * + * Args: + * request (Request): Fastapi Request object + * + * Returns: + * CollectionSchema: Updated collection + */ +export const updateCollectionApiCollectionsIdPutMutation = (options?: Partial>): UseMutationOptions> => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (fnOptions) => { + const { data } = await updateCollectionApiCollectionsIdPut({ + ...options, + ...fnOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; +}; + +export const getVirtualCollectionApiCollectionsVirtualIdGetQueryKey = (options: Options) => createQueryKey('getVirtualCollectionApiCollectionsVirtualIdGet', options); + +/** + * Get Virtual Collection + * + * Get virtual collections endpoint + * + * Args: + * request (Request): Fastapi Request object + * id (str): Virtual collection id + * + * Returns: + * VirtualCollectionSchema: Virtual collection + */ +export const getVirtualCollectionApiCollectionsVirtualIdGetOptions = (options: Options) => queryOptions>({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await getVirtualCollectionApiCollectionsVirtualIdGet({ + ...options, + ...queryKey[0], + signal, + throwOnError: true + }); + return data; + }, + queryKey: getVirtualCollectionApiCollectionsVirtualIdGetQueryKey(options) +}); + +/** + * Delete Smart Collection + * + * Delete a smart collection by ID. + */ +export const deleteSmartCollectionApiCollectionsSmartIdDeleteMutation = (options?: Partial>): UseMutationOptions> => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (fnOptions) => { + const { data } = await deleteSmartCollectionApiCollectionsSmartIdDelete({ + ...options, + ...fnOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; +}; + +export const getSmartCollectionApiCollectionsSmartIdGetQueryKey = (options: Options) => createQueryKey('getSmartCollectionApiCollectionsSmartIdGet', options); + +/** + * Get Smart Collection + * + * Get smart collection endpoint + * + * Args: + * request (Request): Fastapi Request object + * id (int): Smart collection id + * + * Returns: + * SmartCollectionSchema: Smart collection + */ +export const getSmartCollectionApiCollectionsSmartIdGetOptions = (options: Options) => queryOptions>({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await getSmartCollectionApiCollectionsSmartIdGet({ + ...options, + ...queryKey[0], + signal, + throwOnError: true + }); + return data; + }, + queryKey: getSmartCollectionApiCollectionsSmartIdGetQueryKey(options) +}); + +/** + * Update Smart Collection + * + * Update smart collection endpoint + * + * Args: + * request (Request): Fastapi Request object + * id (int): Smart collection id + * + * Returns: + * SmartCollectionSchema: Updated smart collection + */ +export const updateSmartCollectionApiCollectionsSmartIdPutMutation = (options?: Partial>): UseMutationOptions> => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (fnOptions) => { + const { data } = await updateSmartCollectionApiCollectionsSmartIdPut({ + ...options, + ...fnOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; +}; + +/** + * Export Gamelist + * + * Export platforms/ROMs to gamelist.xml format and write to platform directories + */ +export const exportGamelistApiGamelistExportPostMutation = (options?: Partial>): UseMutationOptions> => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (fnOptions) => { + const { data } = await exportGamelistApiGamelistExportPost({ + ...options, + ...fnOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; +}; + +export const getRoomsApiNetplayListGetQueryKey = (options: Options) => createQueryKey('getRoomsApiNetplayListGet', options); + +/** + * Get Rooms + */ +export const getRoomsApiNetplayListGetOptions = (options: Options) => queryOptions>({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await getRoomsApiNetplayListGet({ + ...options, + ...queryKey[0], + signal, + throwOnError: true + }); + return data; + }, + queryKey: getRoomsApiNetplayListGetQueryKey(options) +}); diff --git a/src/clients/romm/client.gen.ts b/src/clients/romm/client.gen.ts new file mode 100644 index 0000000..cab3c70 --- /dev/null +++ b/src/clients/romm/client.gen.ts @@ -0,0 +1,16 @@ +// This file is auto-generated by @hey-api/openapi-ts + +import { type ClientOptions, type Config, createClient, createConfig } from './client'; +import type { ClientOptions as ClientOptions2 } from './types.gen'; + +/** + * The `createClientConfig()` function will be called on client initialization + * and the returned object will become the client's initial configuration. + * + * You may want to initialize your client this way instead of calling + * `setConfig()`. This is useful for example if you're using Next.js + * to ensure your client always has the correct values. + */ +export type CreateClientConfig = (override?: Config) => Config & T>; + +export const client = createClient(createConfig()); diff --git a/src/clients/romm/client/client.gen.ts b/src/clients/romm/client/client.gen.ts new file mode 100644 index 0000000..d4cbcce --- /dev/null +++ b/src/clients/romm/client/client.gen.ts @@ -0,0 +1,311 @@ +// This file is auto-generated by @hey-api/openapi-ts + +import { createSseClient } from '../core/serverSentEvents.gen'; +import type { HttpMethod } from '../core/types.gen'; +import { getValidRequestBody } from '../core/utils.gen'; +import type { + Client, + Config, + RequestOptions, + ResolvedRequestOptions, +} from './types.gen'; +import { + buildUrl, + createConfig, + createInterceptors, + getParseAs, + mergeConfigs, + mergeHeaders, + setAuthParams, +} from './utils.gen'; + +type ReqInit = Omit & { + body?: any; + headers: ReturnType; +}; + +export const createClient = (config: Config = {}): Client => { + let _config = mergeConfigs(createConfig(), config); + + const getConfig = (): Config => ({ ..._config }); + + const setConfig = (config: Config): Config => { + _config = mergeConfigs(_config, config); + return getConfig(); + }; + + const interceptors = createInterceptors< + Request, + Response, + unknown, + ResolvedRequestOptions + >(); + + const beforeRequest = async (options: RequestOptions) => { + const opts = { + ..._config, + ...options, + fetch: options.fetch ?? _config.fetch ?? globalThis.fetch, + headers: mergeHeaders(_config.headers, options.headers), + serializedBody: undefined, + }; + + if (opts.security) { + await setAuthParams({ + ...opts, + security: opts.security, + }); + } + + if (opts.requestValidator) { + await opts.requestValidator(opts); + } + + if (opts.body !== undefined && opts.bodySerializer) { + opts.serializedBody = opts.bodySerializer(opts.body); + } + + // remove Content-Type header if body is empty to avoid sending invalid requests + if (opts.body === undefined || opts.serializedBody === '') { + opts.headers.delete('Content-Type'); + } + + const url = buildUrl(opts); + + return { opts, url }; + }; + + const request: Client['request'] = async (options) => { + // @ts-expect-error + const { opts, url } = await beforeRequest(options); + const requestInit: ReqInit = { + redirect: 'follow', + ...opts, + body: getValidRequestBody(opts), + }; + + let request = new Request(url, requestInit); + + for (const fn of interceptors.request.fns) { + if (fn) { + request = await fn(request, opts); + } + } + + // fetch must be assigned here, otherwise it would throw the error: + // TypeError: Failed to execute 'fetch' on 'Window': Illegal invocation + const _fetch = opts.fetch!; + let response: Response; + + try { + response = await _fetch(request); + } catch (error) { + // Handle fetch exceptions (AbortError, network errors, etc.) + let finalError = error; + + for (const fn of interceptors.error.fns) { + if (fn) { + finalError = (await fn( + error, + undefined as any, + request, + opts, + )) as unknown; + } + } + + finalError = finalError || ({} as unknown); + + if (opts.throwOnError) { + throw finalError; + } + + // Return error response + return opts.responseStyle === 'data' + ? undefined + : { + error: finalError, + request, + response: undefined as any, + }; + } + + for (const fn of interceptors.response.fns) { + if (fn) { + response = await fn(response, request, opts); + } + } + + const result = { + request, + response, + }; + + if (response.ok) { + const parseAs = + (opts.parseAs === 'auto' + ? getParseAs(response.headers.get('Content-Type')) + : opts.parseAs) ?? 'json'; + + if ( + response.status === 204 || + response.headers.get('Content-Length') === '0' + ) { + let emptyData: any; + switch (parseAs) { + case 'arrayBuffer': + case 'blob': + case 'text': + emptyData = await response[parseAs](); + break; + case 'formData': + emptyData = new FormData(); + break; + case 'stream': + emptyData = response.body; + break; + case 'json': + default: + emptyData = {}; + break; + } + return opts.responseStyle === 'data' + ? emptyData + : { + data: emptyData, + ...result, + }; + } + + let data: any; + switch (parseAs) { + case 'arrayBuffer': + case 'blob': + case 'formData': + case 'text': + data = await response[parseAs](); + break; + case 'json': { + // Some servers return 200 with no Content-Length and empty body. + // response.json() would throw; read as text and parse if non-empty. + const text = await response.text(); + data = text ? JSON.parse(text) : {}; + break; + } + case 'stream': + return opts.responseStyle === 'data' + ? response.body + : { + data: response.body, + ...result, + }; + } + + if (parseAs === 'json') { + if (opts.responseValidator) { + await opts.responseValidator(data); + } + + if (opts.responseTransformer) { + data = await opts.responseTransformer(data); + } + } + + return opts.responseStyle === 'data' + ? data + : { + data, + ...result, + }; + } + + const textError = await response.text(); + let jsonError: unknown; + + try { + jsonError = JSON.parse(textError); + } catch { + // noop + } + + const error = jsonError ?? textError; + let finalError = error; + + for (const fn of interceptors.error.fns) { + if (fn) { + finalError = (await fn(error, response, request, opts)) as string; + } + } + + finalError = finalError || ({} as string); + + if (opts.throwOnError) { + throw finalError; + } + + // TODO: we probably want to return error and improve types + return opts.responseStyle === 'data' + ? undefined + : { + error: finalError, + ...result, + }; + }; + + const makeMethodFn = + (method: Uppercase) => (options: RequestOptions) => + request({ ...options, method }); + + const makeSseFn = + (method: Uppercase) => async (options: RequestOptions) => { + const { opts, url } = await beforeRequest(options); + return createSseClient({ + ...opts, + body: opts.body as BodyInit | null | undefined, + headers: opts.headers as unknown as Record, + method, + onRequest: async (url, init) => { + let request = new Request(url, init); + for (const fn of interceptors.request.fns) { + if (fn) { + request = await fn(request, opts); + } + } + return request; + }, + serializedBody: getValidRequestBody(opts) as + | BodyInit + | null + | undefined, + url, + }); + }; + + return { + buildUrl, + connect: makeMethodFn('CONNECT'), + delete: makeMethodFn('DELETE'), + get: makeMethodFn('GET'), + getConfig, + head: makeMethodFn('HEAD'), + interceptors, + options: makeMethodFn('OPTIONS'), + patch: makeMethodFn('PATCH'), + post: makeMethodFn('POST'), + put: makeMethodFn('PUT'), + request, + setConfig, + sse: { + connect: makeSseFn('CONNECT'), + delete: makeSseFn('DELETE'), + get: makeSseFn('GET'), + head: makeSseFn('HEAD'), + options: makeSseFn('OPTIONS'), + patch: makeSseFn('PATCH'), + post: makeSseFn('POST'), + put: makeSseFn('PUT'), + trace: makeSseFn('TRACE'), + }, + trace: makeMethodFn('TRACE'), + } as Client; +}; diff --git a/src/clients/romm/client/index.ts b/src/clients/romm/client/index.ts new file mode 100644 index 0000000..b295ede --- /dev/null +++ b/src/clients/romm/client/index.ts @@ -0,0 +1,25 @@ +// This file is auto-generated by @hey-api/openapi-ts + +export type { Auth } from '../core/auth.gen'; +export type { QuerySerializerOptions } from '../core/bodySerializer.gen'; +export { + formDataBodySerializer, + jsonBodySerializer, + urlSearchParamsBodySerializer, +} from '../core/bodySerializer.gen'; +export { buildClientParams } from '../core/params.gen'; +export { serializeQueryKeyValue } from '../core/queryKeySerializer.gen'; +export { createClient } from './client.gen'; +export type { + Client, + ClientOptions, + Config, + CreateClientConfig, + Options, + RequestOptions, + RequestResult, + ResolvedRequestOptions, + ResponseStyle, + TDataShape, +} from './types.gen'; +export { createConfig, mergeHeaders } from './utils.gen'; diff --git a/src/clients/romm/client/types.gen.ts b/src/clients/romm/client/types.gen.ts new file mode 100644 index 0000000..b4a499c --- /dev/null +++ b/src/clients/romm/client/types.gen.ts @@ -0,0 +1,241 @@ +// This file is auto-generated by @hey-api/openapi-ts + +import type { Auth } from '../core/auth.gen'; +import type { + ServerSentEventsOptions, + ServerSentEventsResult, +} from '../core/serverSentEvents.gen'; +import type { + Client as CoreClient, + Config as CoreConfig, +} from '../core/types.gen'; +import type { Middleware } from './utils.gen'; + +export type ResponseStyle = 'data' | 'fields'; + +export interface Config + extends Omit, + CoreConfig { + /** + * Base URL for all requests made by this client. + */ + baseUrl?: T['baseUrl']; + /** + * Fetch API implementation. You can use this option to provide a custom + * fetch instance. + * + * @default globalThis.fetch + */ + fetch?: typeof fetch; + /** + * Please don't use the Fetch client for Next.js applications. The `next` + * options won't have any effect. + * + * Install {@link https://www.npmjs.com/package/@hey-api/client-next `@hey-api/client-next`} instead. + */ + next?: never; + /** + * Return the response data parsed in a specified format. By default, `auto` + * will infer the appropriate method from the `Content-Type` response header. + * You can override this behavior with any of the {@link Body} methods. + * Select `stream` if you don't want to parse response data at all. + * + * @default 'auto' + */ + parseAs?: + | 'arrayBuffer' + | 'auto' + | 'blob' + | 'formData' + | 'json' + | 'stream' + | 'text'; + /** + * Should we return only data or multiple fields (data, error, response, etc.)? + * + * @default 'fields' + */ + responseStyle?: ResponseStyle; + /** + * Throw an error instead of returning it in the response? + * + * @default false + */ + throwOnError?: T['throwOnError']; +} + +export interface RequestOptions< + TData = unknown, + TResponseStyle extends ResponseStyle = 'fields', + ThrowOnError extends boolean = boolean, + Url extends string = string, +> extends Config<{ + responseStyle: TResponseStyle; + throwOnError: ThrowOnError; + }>, + Pick< + ServerSentEventsOptions, + | 'onSseError' + | 'onSseEvent' + | 'sseDefaultRetryDelay' + | 'sseMaxRetryAttempts' + | 'sseMaxRetryDelay' + > { + /** + * Any body that you want to add to your request. + * + * {@link https://developer.mozilla.org/docs/Web/API/fetch#body} + */ + body?: unknown; + path?: Record; + query?: Record; + /** + * Security mechanism(s) to use for the request. + */ + security?: ReadonlyArray; + url: Url; +} + +export interface ResolvedRequestOptions< + TResponseStyle extends ResponseStyle = 'fields', + ThrowOnError extends boolean = boolean, + Url extends string = string, +> extends RequestOptions { + serializedBody?: string; +} + +export type RequestResult< + TData = unknown, + TError = unknown, + ThrowOnError extends boolean = boolean, + TResponseStyle extends ResponseStyle = 'fields', +> = ThrowOnError extends true + ? Promise< + TResponseStyle extends 'data' + ? TData extends Record + ? TData[keyof TData] + : TData + : { + data: TData extends Record + ? TData[keyof TData] + : TData; + request: Request; + response: Response; + } + > + : Promise< + TResponseStyle extends 'data' + ? + | (TData extends Record + ? TData[keyof TData] + : TData) + | undefined + : ( + | { + data: TData extends Record + ? TData[keyof TData] + : TData; + error: undefined; + } + | { + data: undefined; + error: TError extends Record + ? TError[keyof TError] + : TError; + } + ) & { + request: Request; + response: Response; + } + >; + +export interface ClientOptions { + baseUrl?: string; + responseStyle?: ResponseStyle; + throwOnError?: boolean; +} + +type MethodFn = < + TData = unknown, + TError = unknown, + ThrowOnError extends boolean = false, + TResponseStyle extends ResponseStyle = 'fields', +>( + options: Omit, 'method'>, +) => RequestResult; + +type SseFn = < + TData = unknown, + TError = unknown, + ThrowOnError extends boolean = false, + TResponseStyle extends ResponseStyle = 'fields', +>( + options: Omit, 'method'>, +) => Promise>; + +type RequestFn = < + TData = unknown, + TError = unknown, + ThrowOnError extends boolean = false, + TResponseStyle extends ResponseStyle = 'fields', +>( + options: Omit, 'method'> & + Pick< + Required>, + 'method' + >, +) => RequestResult; + +type BuildUrlFn = < + TData extends { + body?: unknown; + path?: Record; + query?: Record; + url: string; + }, +>( + options: TData & Options, +) => string; + +export type Client = CoreClient< + RequestFn, + Config, + MethodFn, + BuildUrlFn, + SseFn +> & { + interceptors: Middleware; +}; + +/** + * The `createClientConfig()` function will be called on client initialization + * and the returned object will become the client's initial configuration. + * + * You may want to initialize your client this way instead of calling + * `setConfig()`. This is useful for example if you're using Next.js + * to ensure your client always has the correct values. + */ +export type CreateClientConfig = ( + override?: Config, +) => Config & T>; + +export interface TDataShape { + body?: unknown; + headers?: unknown; + path?: unknown; + query?: unknown; + url: string; +} + +type OmitKeys = Pick>; + +export type Options< + TData extends TDataShape = TDataShape, + ThrowOnError extends boolean = boolean, + TResponse = unknown, + TResponseStyle extends ResponseStyle = 'fields', +> = OmitKeys< + RequestOptions, + 'body' | 'path' | 'query' | 'url' +> & + ([TData] extends [never] ? unknown : Omit); diff --git a/src/clients/romm/client/utils.gen.ts b/src/clients/romm/client/utils.gen.ts new file mode 100644 index 0000000..4c48a9e --- /dev/null +++ b/src/clients/romm/client/utils.gen.ts @@ -0,0 +1,332 @@ +// This file is auto-generated by @hey-api/openapi-ts + +import { getAuthToken } from '../core/auth.gen'; +import type { QuerySerializerOptions } from '../core/bodySerializer.gen'; +import { jsonBodySerializer } from '../core/bodySerializer.gen'; +import { + serializeArrayParam, + serializeObjectParam, + serializePrimitiveParam, +} from '../core/pathSerializer.gen'; +import { getUrl } from '../core/utils.gen'; +import type { Client, ClientOptions, Config, RequestOptions } from './types.gen'; + +export const createQuerySerializer = ({ + parameters = {}, + ...args +}: QuerySerializerOptions = {}) => { + const querySerializer = (queryParams: T) => { + const search: string[] = []; + if (queryParams && typeof queryParams === 'object') { + for (const name in queryParams) { + const value = queryParams[name]; + + if (value === undefined || value === null) { + continue; + } + + const options = parameters[name] || args; + + if (Array.isArray(value)) { + const serializedArray = serializeArrayParam({ + allowReserved: options.allowReserved, + explode: true, + name, + style: 'form', + value, + ...options.array, + }); + if (serializedArray) search.push(serializedArray); + } else if (typeof value === 'object') { + const serializedObject = serializeObjectParam({ + allowReserved: options.allowReserved, + explode: true, + name, + style: 'deepObject', + value: value as Record, + ...options.object, + }); + if (serializedObject) search.push(serializedObject); + } else { + const serializedPrimitive = serializePrimitiveParam({ + allowReserved: options.allowReserved, + name, + value: value as string, + }); + if (serializedPrimitive) search.push(serializedPrimitive); + } + } + } + return search.join('&'); + }; + return querySerializer; +}; + +/** + * Infers parseAs value from provided Content-Type header. + */ +export const getParseAs = ( + contentType: string | null, +): Exclude => { + if (!contentType) { + // If no Content-Type header is provided, the best we can do is return the raw response body, + // which is effectively the same as the 'stream' option. + return 'stream'; + } + + const cleanContent = contentType.split(';')[0]?.trim(); + + if (!cleanContent) { + return; + } + + if ( + cleanContent.startsWith('application/json') || + cleanContent.endsWith('+json') + ) { + return 'json'; + } + + if (cleanContent === 'multipart/form-data') { + return 'formData'; + } + + if ( + ['application/', 'audio/', 'image/', 'video/'].some((type) => + cleanContent.startsWith(type), + ) + ) { + return 'blob'; + } + + if (cleanContent.startsWith('text/')) { + return 'text'; + } + + return; +}; + +const checkForExistence = ( + options: Pick & { + headers: Headers; + }, + name?: string, +): boolean => { + if (!name) { + return false; + } + if ( + options.headers.has(name) || + options.query?.[name] || + options.headers.get('Cookie')?.includes(`${name}=`) + ) { + return true; + } + return false; +}; + +export const setAuthParams = async ({ + security, + ...options +}: Pick, 'security'> & + Pick & { + headers: Headers; + }) => { + for (const auth of security) { + if (checkForExistence(options, auth.name)) { + continue; + } + + const token = await getAuthToken(auth, options.auth); + + if (!token) { + continue; + } + + const name = auth.name ?? 'Authorization'; + + switch (auth.in) { + case 'query': + if (!options.query) { + options.query = {}; + } + options.query[name] = token; + break; + case 'cookie': + options.headers.append('Cookie', `${name}=${token}`); + break; + case 'header': + default: + options.headers.set(name, token); + break; + } + } +}; + +export const buildUrl: Client['buildUrl'] = (options) => + getUrl({ + baseUrl: options.baseUrl as string, + path: options.path, + query: options.query, + querySerializer: + typeof options.querySerializer === 'function' + ? options.querySerializer + : createQuerySerializer(options.querySerializer), + url: options.url, + }); + +export const mergeConfigs = (a: Config, b: Config): Config => { + const config = { ...a, ...b }; + if (config.baseUrl?.endsWith('/')) { + config.baseUrl = config.baseUrl.substring(0, config.baseUrl.length - 1); + } + config.headers = mergeHeaders(a.headers, b.headers); + return config; +}; + +const headersEntries = (headers: Headers): Array<[string, string]> => { + const entries: Array<[string, string]> = []; + headers.forEach((value, key) => { + entries.push([key, value]); + }); + return entries; +}; + +export const mergeHeaders = ( + ...headers: Array['headers'] | undefined> +): Headers => { + const mergedHeaders = new Headers(); + for (const header of headers) { + if (!header) { + continue; + } + + const iterator = + header instanceof Headers + ? headersEntries(header) + : Object.entries(header); + + for (const [key, value] of iterator) { + if (value === null) { + mergedHeaders.delete(key); + } else if (Array.isArray(value)) { + for (const v of value) { + mergedHeaders.append(key, v as string); + } + } else if (value !== undefined) { + // assume object headers are meant to be JSON stringified, i.e. their + // content value in OpenAPI specification is 'application/json' + mergedHeaders.set( + key, + typeof value === 'object' ? JSON.stringify(value) : (value as string), + ); + } + } + } + return mergedHeaders; +}; + +type ErrInterceptor = ( + error: Err, + response: Res, + request: Req, + options: Options, +) => Err | Promise; + +type ReqInterceptor = ( + request: Req, + options: Options, +) => Req | Promise; + +type ResInterceptor = ( + response: Res, + request: Req, + options: Options, +) => Res | Promise; + +class Interceptors { + fns: Array = []; + + clear(): void { + this.fns = []; + } + + eject(id: number | Interceptor): void { + const index = this.getInterceptorIndex(id); + if (this.fns[index]) { + this.fns[index] = null; + } + } + + exists(id: number | Interceptor): boolean { + const index = this.getInterceptorIndex(id); + return Boolean(this.fns[index]); + } + + getInterceptorIndex(id: number | Interceptor): number { + if (typeof id === 'number') { + return this.fns[id] ? id : -1; + } + return this.fns.indexOf(id); + } + + update( + id: number | Interceptor, + fn: Interceptor, + ): number | Interceptor | false { + const index = this.getInterceptorIndex(id); + if (this.fns[index]) { + this.fns[index] = fn; + return id; + } + return false; + } + + use(fn: Interceptor): number { + this.fns.push(fn); + return this.fns.length - 1; + } +} + +export interface Middleware { + error: Interceptors>; + request: Interceptors>; + response: Interceptors>; +} + +export const createInterceptors = (): Middleware< + Req, + Res, + Err, + Options +> => ({ + error: new Interceptors>(), + request: new Interceptors>(), + response: new Interceptors>(), +}); + +const defaultQuerySerializer = createQuerySerializer({ + allowReserved: false, + array: { + explode: true, + style: 'form', + }, + object: { + explode: true, + style: 'deepObject', + }, +}); + +const defaultHeaders = { + 'Content-Type': 'application/json', +}; + +export const createConfig = ( + override: Config & T> = {}, +): Config & T> => ({ + ...jsonBodySerializer, + headers: defaultHeaders, + parseAs: 'auto', + querySerializer: defaultQuerySerializer, + ...override, +}); diff --git a/src/clients/romm/core/auth.gen.ts b/src/clients/romm/core/auth.gen.ts new file mode 100644 index 0000000..f8a7326 --- /dev/null +++ b/src/clients/romm/core/auth.gen.ts @@ -0,0 +1,42 @@ +// This file is auto-generated by @hey-api/openapi-ts + +export type AuthToken = string | undefined; + +export interface Auth { + /** + * Which part of the request do we use to send the auth? + * + * @default 'header' + */ + in?: 'header' | 'query' | 'cookie'; + /** + * Header or query parameter name. + * + * @default 'Authorization' + */ + name?: string; + scheme?: 'basic' | 'bearer'; + type: 'apiKey' | 'http'; +} + +export const getAuthToken = async ( + auth: Auth, + callback: ((auth: Auth) => Promise | AuthToken) | AuthToken, +): Promise => { + const token = + typeof callback === 'function' ? await callback(auth) : callback; + + if (!token) { + return; + } + + if (auth.scheme === 'bearer') { + return `Bearer ${token}`; + } + + if (auth.scheme === 'basic') { + return `Basic ${btoa(token)}`; + } + + return token; +}; diff --git a/src/clients/romm/core/bodySerializer.gen.ts b/src/clients/romm/core/bodySerializer.gen.ts new file mode 100644 index 0000000..552b50f --- /dev/null +++ b/src/clients/romm/core/bodySerializer.gen.ts @@ -0,0 +1,100 @@ +// This file is auto-generated by @hey-api/openapi-ts + +import type { + ArrayStyle, + ObjectStyle, + SerializerOptions, +} from './pathSerializer.gen'; + +export type QuerySerializer = (query: Record) => string; + +export type BodySerializer = (body: any) => any; + +type QuerySerializerOptionsObject = { + allowReserved?: boolean; + array?: Partial>; + object?: Partial>; +}; + +export type QuerySerializerOptions = QuerySerializerOptionsObject & { + /** + * Per-parameter serialization overrides. When provided, these settings + * override the global array/object settings for specific parameter names. + */ + parameters?: Record; +}; + +const serializeFormDataPair = ( + data: FormData, + key: string, + value: unknown, +): void => { + if (typeof value === 'string' || value instanceof Blob) { + data.append(key, value); + } else if (value instanceof Date) { + data.append(key, value.toISOString()); + } else { + data.append(key, JSON.stringify(value)); + } +}; + +const serializeUrlSearchParamsPair = ( + data: URLSearchParams, + key: string, + value: unknown, +): void => { + if (typeof value === 'string') { + data.append(key, value); + } else { + data.append(key, JSON.stringify(value)); + } +}; + +export const formDataBodySerializer = { + bodySerializer: | Array>>( + body: T, + ): FormData => { + const data = new FormData(); + + Object.entries(body).forEach(([key, value]) => { + if (value === undefined || value === null) { + return; + } + if (Array.isArray(value)) { + value.forEach((v) => serializeFormDataPair(data, key, v)); + } else { + serializeFormDataPair(data, key, value); + } + }); + + return data; + }, +}; + +export const jsonBodySerializer = { + bodySerializer: (body: T): string => + JSON.stringify(body, (_key, value) => + typeof value === 'bigint' ? value.toString() : value, + ), +}; + +export const urlSearchParamsBodySerializer = { + bodySerializer: | Array>>( + body: T, + ): string => { + const data = new URLSearchParams(); + + Object.entries(body).forEach(([key, value]) => { + if (value === undefined || value === null) { + return; + } + if (Array.isArray(value)) { + value.forEach((v) => serializeUrlSearchParamsPair(data, key, v)); + } else { + serializeUrlSearchParamsPair(data, key, value); + } + }); + + return data.toString(); + }, +}; diff --git a/src/clients/romm/core/params.gen.ts b/src/clients/romm/core/params.gen.ts new file mode 100644 index 0000000..602715c --- /dev/null +++ b/src/clients/romm/core/params.gen.ts @@ -0,0 +1,176 @@ +// This file is auto-generated by @hey-api/openapi-ts + +type Slot = 'body' | 'headers' | 'path' | 'query'; + +export type Field = + | { + in: Exclude; + /** + * Field name. This is the name we want the user to see and use. + */ + key: string; + /** + * Field mapped name. This is the name we want to use in the request. + * If omitted, we use the same value as `key`. + */ + map?: string; + } + | { + in: Extract; + /** + * Key isn't required for bodies. + */ + key?: string; + map?: string; + } + | { + /** + * Field name. This is the name we want the user to see and use. + */ + key: string; + /** + * Field mapped name. This is the name we want to use in the request. + * If `in` is omitted, `map` aliases `key` to the transport layer. + */ + map: Slot; + }; + +export interface Fields { + allowExtra?: Partial>; + args?: ReadonlyArray; +} + +export type FieldsConfig = ReadonlyArray; + +const extraPrefixesMap: Record = { + $body_: 'body', + $headers_: 'headers', + $path_: 'path', + $query_: 'query', +}; +const extraPrefixes = Object.entries(extraPrefixesMap); + +type KeyMap = Map< + string, + | { + in: Slot; + map?: string; + } + | { + in?: never; + map: Slot; + } +>; + +const buildKeyMap = (fields: FieldsConfig, map?: KeyMap): KeyMap => { + if (!map) { + map = new Map(); + } + + for (const config of fields) { + if ('in' in config) { + if (config.key) { + map.set(config.key, { + in: config.in, + map: config.map, + }); + } + } else if ('key' in config) { + map.set(config.key, { + map: config.map, + }); + } else if (config.args) { + buildKeyMap(config.args, map); + } + } + + return map; +}; + +interface Params { + body: unknown; + headers: Record; + path: Record; + query: Record; +} + +const stripEmptySlots = (params: Params) => { + for (const [slot, value] of Object.entries(params)) { + if (value && typeof value === 'object' && !Object.keys(value).length) { + delete params[slot as Slot]; + } + } +}; + +export const buildClientParams = ( + args: ReadonlyArray, + fields: FieldsConfig, +) => { + const params: Params = { + body: {}, + headers: {}, + path: {}, + query: {}, + }; + + const map = buildKeyMap(fields); + + let config: FieldsConfig[number] | undefined; + + for (const [index, arg] of args.entries()) { + if (fields[index]) { + config = fields[index]; + } + + if (!config) { + continue; + } + + if ('in' in config) { + if (config.key) { + const field = map.get(config.key)!; + const name = field.map || config.key; + if (field.in) { + (params[field.in] as Record)[name] = arg; + } + } else { + params.body = arg; + } + } else { + for (const [key, value] of Object.entries(arg ?? {})) { + const field = map.get(key); + + if (field) { + if (field.in) { + const name = field.map || key; + (params[field.in] as Record)[name] = value; + } else { + params[field.map] = value; + } + } else { + const extra = extraPrefixes.find(([prefix]) => + key.startsWith(prefix), + ); + + if (extra) { + const [prefix, slot] = extra; + (params[slot] as Record)[ + key.slice(prefix.length) + ] = value; + } else if ('allowExtra' in config && config.allowExtra) { + for (const [slot, allowed] of Object.entries(config.allowExtra)) { + if (allowed) { + (params[slot as Slot] as Record)[key] = value; + break; + } + } + } + } + } + } + } + + stripEmptySlots(params); + + return params; +}; diff --git a/src/clients/romm/core/pathSerializer.gen.ts b/src/clients/romm/core/pathSerializer.gen.ts new file mode 100644 index 0000000..8d99931 --- /dev/null +++ b/src/clients/romm/core/pathSerializer.gen.ts @@ -0,0 +1,181 @@ +// This file is auto-generated by @hey-api/openapi-ts + +interface SerializeOptions + extends SerializePrimitiveOptions, + SerializerOptions {} + +interface SerializePrimitiveOptions { + allowReserved?: boolean; + name: string; +} + +export interface SerializerOptions { + /** + * @default true + */ + explode: boolean; + style: T; +} + +export type ArrayStyle = 'form' | 'spaceDelimited' | 'pipeDelimited'; +export type ArraySeparatorStyle = ArrayStyle | MatrixStyle; +type MatrixStyle = 'label' | 'matrix' | 'simple'; +export type ObjectStyle = 'form' | 'deepObject'; +type ObjectSeparatorStyle = ObjectStyle | MatrixStyle; + +interface SerializePrimitiveParam extends SerializePrimitiveOptions { + value: string; +} + +export const separatorArrayExplode = (style: ArraySeparatorStyle) => { + switch (style) { + case 'label': + return '.'; + case 'matrix': + return ';'; + case 'simple': + return ','; + default: + return '&'; + } +}; + +export const separatorArrayNoExplode = (style: ArraySeparatorStyle) => { + switch (style) { + case 'form': + return ','; + case 'pipeDelimited': + return '|'; + case 'spaceDelimited': + return '%20'; + default: + return ','; + } +}; + +export const separatorObjectExplode = (style: ObjectSeparatorStyle) => { + switch (style) { + case 'label': + return '.'; + case 'matrix': + return ';'; + case 'simple': + return ','; + default: + return '&'; + } +}; + +export const serializeArrayParam = ({ + allowReserved, + explode, + name, + style, + value, +}: SerializeOptions & { + value: unknown[]; +}) => { + if (!explode) { + const joinedValues = ( + allowReserved ? value : value.map((v) => encodeURIComponent(v as string)) + ).join(separatorArrayNoExplode(style)); + switch (style) { + case 'label': + return `.${joinedValues}`; + case 'matrix': + return `;${name}=${joinedValues}`; + case 'simple': + return joinedValues; + default: + return `${name}=${joinedValues}`; + } + } + + const separator = separatorArrayExplode(style); + const joinedValues = value + .map((v) => { + if (style === 'label' || style === 'simple') { + return allowReserved ? v : encodeURIComponent(v as string); + } + + return serializePrimitiveParam({ + allowReserved, + name, + value: v as string, + }); + }) + .join(separator); + return style === 'label' || style === 'matrix' + ? separator + joinedValues + : joinedValues; +}; + +export const serializePrimitiveParam = ({ + allowReserved, + name, + value, +}: SerializePrimitiveParam) => { + if (value === undefined || value === null) { + return ''; + } + + if (typeof value === 'object') { + throw new Error( + 'Deeply-nested arrays/objects aren’t supported. Provide your own `querySerializer()` to handle these.', + ); + } + + return `${name}=${allowReserved ? value : encodeURIComponent(value)}`; +}; + +export const serializeObjectParam = ({ + allowReserved, + explode, + name, + style, + value, + valueOnly, +}: SerializeOptions & { + value: Record | Date; + valueOnly?: boolean; +}) => { + if (value instanceof Date) { + return valueOnly ? value.toISOString() : `${name}=${value.toISOString()}`; + } + + if (style !== 'deepObject' && !explode) { + let values: string[] = []; + Object.entries(value).forEach(([key, v]) => { + values = [ + ...values, + key, + allowReserved ? (v as string) : encodeURIComponent(v as string), + ]; + }); + const joinedValues = values.join(','); + switch (style) { + case 'form': + return `${name}=${joinedValues}`; + case 'label': + return `.${joinedValues}`; + case 'matrix': + return `;${name}=${joinedValues}`; + default: + return joinedValues; + } + } + + const separator = separatorObjectExplode(style); + const joinedValues = Object.entries(value) + .map(([key, v]) => + serializePrimitiveParam({ + allowReserved, + name: style === 'deepObject' ? `${name}[${key}]` : key, + value: v as string, + }), + ) + .join(separator); + return style === 'label' || style === 'matrix' + ? separator + joinedValues + : joinedValues; +}; diff --git a/src/clients/romm/core/queryKeySerializer.gen.ts b/src/clients/romm/core/queryKeySerializer.gen.ts new file mode 100644 index 0000000..d3bb683 --- /dev/null +++ b/src/clients/romm/core/queryKeySerializer.gen.ts @@ -0,0 +1,136 @@ +// This file is auto-generated by @hey-api/openapi-ts + +/** + * JSON-friendly union that mirrors what Pinia Colada can hash. + */ +export type JsonValue = + | null + | string + | number + | boolean + | JsonValue[] + | { [key: string]: JsonValue }; + +/** + * Replacer that converts non-JSON values (bigint, Date, etc.) to safe substitutes. + */ +export const queryKeyJsonReplacer = (_key: string, value: unknown) => { + if ( + value === undefined || + typeof value === 'function' || + typeof value === 'symbol' + ) { + return undefined; + } + if (typeof value === 'bigint') { + return value.toString(); + } + if (value instanceof Date) { + return value.toISOString(); + } + return value; +}; + +/** + * Safely stringifies a value and parses it back into a JsonValue. + */ +export const stringifyToJsonValue = (input: unknown): JsonValue | undefined => { + try { + const json = JSON.stringify(input, queryKeyJsonReplacer); + if (json === undefined) { + return undefined; + } + return JSON.parse(json) as JsonValue; + } catch { + return undefined; + } +}; + +/** + * Detects plain objects (including objects with a null prototype). + */ +const isPlainObject = (value: unknown): value is Record => { + if (value === null || typeof value !== 'object') { + return false; + } + const prototype = Object.getPrototypeOf(value as object); + return prototype === Object.prototype || prototype === null; +}; + +/** + * Turns URLSearchParams into a sorted JSON object for deterministic keys. + */ +const serializeSearchParams = (params: URLSearchParams): JsonValue => { + const entries = Array.from(params.entries()).sort(([a], [b]) => + a.localeCompare(b), + ); + const result: Record = {}; + + for (const [key, value] of entries) { + const existing = result[key]; + if (existing === undefined) { + result[key] = value; + continue; + } + + if (Array.isArray(existing)) { + (existing as string[]).push(value); + } else { + result[key] = [existing, value]; + } + } + + return result; +}; + +/** + * Normalizes any accepted value into a JSON-friendly shape for query keys. + */ +export const serializeQueryKeyValue = ( + value: unknown, +): JsonValue | undefined => { + if (value === null) { + return null; + } + + if ( + typeof value === 'string' || + typeof value === 'number' || + typeof value === 'boolean' + ) { + return value; + } + + if ( + value === undefined || + typeof value === 'function' || + typeof value === 'symbol' + ) { + return undefined; + } + + if (typeof value === 'bigint') { + return value.toString(); + } + + if (value instanceof Date) { + return value.toISOString(); + } + + if (Array.isArray(value)) { + return stringifyToJsonValue(value); + } + + if ( + typeof URLSearchParams !== 'undefined' && + value instanceof URLSearchParams + ) { + return serializeSearchParams(value); + } + + if (isPlainObject(value)) { + return stringifyToJsonValue(value); + } + + return undefined; +}; diff --git a/src/clients/romm/core/serverSentEvents.gen.ts b/src/clients/romm/core/serverSentEvents.gen.ts new file mode 100644 index 0000000..343d25a --- /dev/null +++ b/src/clients/romm/core/serverSentEvents.gen.ts @@ -0,0 +1,266 @@ +// This file is auto-generated by @hey-api/openapi-ts + +import type { Config } from './types.gen'; + +export type ServerSentEventsOptions = Omit< + RequestInit, + 'method' +> & + Pick & { + /** + * Fetch API implementation. You can use this option to provide a custom + * fetch instance. + * + * @default globalThis.fetch + */ + fetch?: typeof fetch; + /** + * Implementing clients can call request interceptors inside this hook. + */ + onRequest?: (url: string, init: RequestInit) => Promise; + /** + * Callback invoked when a network or parsing error occurs during streaming. + * + * This option applies only if the endpoint returns a stream of events. + * + * @param error The error that occurred. + */ + onSseError?: (error: unknown) => void; + /** + * Callback invoked when an event is streamed from the server. + * + * This option applies only if the endpoint returns a stream of events. + * + * @param event Event streamed from the server. + * @returns Nothing (void). + */ + onSseEvent?: (event: StreamEvent) => void; + serializedBody?: RequestInit['body']; + /** + * Default retry delay in milliseconds. + * + * This option applies only if the endpoint returns a stream of events. + * + * @default 3000 + */ + sseDefaultRetryDelay?: number; + /** + * Maximum number of retry attempts before giving up. + */ + sseMaxRetryAttempts?: number; + /** + * Maximum retry delay in milliseconds. + * + * Applies only when exponential backoff is used. + * + * This option applies only if the endpoint returns a stream of events. + * + * @default 30000 + */ + sseMaxRetryDelay?: number; + /** + * Optional sleep function for retry backoff. + * + * Defaults to using `setTimeout`. + */ + sseSleepFn?: (ms: number) => Promise; + url: string; + }; + +export interface StreamEvent { + data: TData; + event?: string; + id?: string; + retry?: number; +} + +export type ServerSentEventsResult< + TData = unknown, + TReturn = void, + TNext = unknown, +> = { + stream: AsyncGenerator< + TData extends Record ? TData[keyof TData] : TData, + TReturn, + TNext + >; +}; + +export const createSseClient = ({ + onRequest, + onSseError, + onSseEvent, + responseTransformer, + responseValidator, + sseDefaultRetryDelay, + sseMaxRetryAttempts, + sseMaxRetryDelay, + sseSleepFn, + url, + ...options +}: ServerSentEventsOptions): ServerSentEventsResult => { + let lastEventId: string | undefined; + + const sleep = + sseSleepFn ?? + ((ms: number) => new Promise((resolve) => setTimeout(resolve, ms))); + + const createStream = async function* () { + let retryDelay: number = sseDefaultRetryDelay ?? 3000; + let attempt = 0; + const signal = options.signal ?? new AbortController().signal; + + while (true) { + if (signal.aborted) break; + + attempt++; + + const headers = + options.headers instanceof Headers + ? options.headers + : new Headers(options.headers as Record | undefined); + + if (lastEventId !== undefined) { + headers.set('Last-Event-ID', lastEventId); + } + + try { + const requestInit: RequestInit = { + redirect: 'follow', + ...options, + body: options.serializedBody, + headers, + signal, + }; + let request = new Request(url, requestInit); + if (onRequest) { + request = await onRequest(url, requestInit); + } + // fetch must be assigned here, otherwise it would throw the error: + // TypeError: Failed to execute 'fetch' on 'Window': Illegal invocation + const _fetch = options.fetch ?? globalThis.fetch; + const response = await _fetch(request); + + if (!response.ok) + throw new Error( + `SSE failed: ${response.status} ${response.statusText}`, + ); + + if (!response.body) throw new Error('No body in SSE response'); + + const reader = response.body + .pipeThrough(new TextDecoderStream()) + .getReader(); + + let buffer = ''; + + const abortHandler = () => { + try { + reader.cancel(); + } catch { + // noop + } + }; + + signal.addEventListener('abort', abortHandler); + + try { + while (true) { + const { done, value } = await reader.read(); + if (done) break; + buffer += value; + // Normalize line endings: CRLF -> LF, then CR -> LF + buffer = buffer.replace(/\r\n/g, '\n').replace(/\r/g, '\n'); + + const chunks = buffer.split('\n\n'); + buffer = chunks.pop() ?? ''; + + for (const chunk of chunks) { + const lines = chunk.split('\n'); + const dataLines: Array = []; + let eventName: string | undefined; + + for (const line of lines) { + if (line.startsWith('data:')) { + dataLines.push(line.replace(/^data:\s*/, '')); + } else if (line.startsWith('event:')) { + eventName = line.replace(/^event:\s*/, ''); + } else if (line.startsWith('id:')) { + lastEventId = line.replace(/^id:\s*/, ''); + } else if (line.startsWith('retry:')) { + const parsed = Number.parseInt( + line.replace(/^retry:\s*/, ''), + 10, + ); + if (!Number.isNaN(parsed)) { + retryDelay = parsed; + } + } + } + + let data: unknown; + let parsedJson = false; + + if (dataLines.length) { + const rawData = dataLines.join('\n'); + try { + data = JSON.parse(rawData); + parsedJson = true; + } catch { + data = rawData; + } + } + + if (parsedJson) { + if (responseValidator) { + await responseValidator(data); + } + + if (responseTransformer) { + data = await responseTransformer(data); + } + } + + onSseEvent?.({ + data, + event: eventName, + id: lastEventId, + retry: retryDelay, + }); + + if (dataLines.length) { + yield data as any; + } + } + } + } finally { + signal.removeEventListener('abort', abortHandler); + reader.releaseLock(); + } + + break; // exit loop on normal completion + } catch (error) { + // connection failed or aborted; retry after delay + onSseError?.(error); + + if ( + sseMaxRetryAttempts !== undefined && + attempt >= sseMaxRetryAttempts + ) { + break; // stop after firing error + } + + // exponential backoff: double retry each attempt, cap at 30s + const backoff = Math.min( + retryDelay * 2 ** (attempt - 1), + sseMaxRetryDelay ?? 30000, + ); + await sleep(backoff); + } + } + }; + + const stream = createStream(); + + return { stream }; +}; diff --git a/src/clients/romm/core/types.gen.ts b/src/clients/romm/core/types.gen.ts new file mode 100644 index 0000000..643c070 --- /dev/null +++ b/src/clients/romm/core/types.gen.ts @@ -0,0 +1,118 @@ +// This file is auto-generated by @hey-api/openapi-ts + +import type { Auth, AuthToken } from './auth.gen'; +import type { + BodySerializer, + QuerySerializer, + QuerySerializerOptions, +} from './bodySerializer.gen'; + +export type HttpMethod = + | 'connect' + | 'delete' + | 'get' + | 'head' + | 'options' + | 'patch' + | 'post' + | 'put' + | 'trace'; + +export type Client< + RequestFn = never, + Config = unknown, + MethodFn = never, + BuildUrlFn = never, + SseFn = never, +> = { + /** + * Returns the final request URL. + */ + buildUrl: BuildUrlFn; + getConfig: () => Config; + request: RequestFn; + setConfig: (config: Config) => Config; +} & { + [K in HttpMethod]: MethodFn; +} & ([SseFn] extends [never] + ? { sse?: never } + : { sse: { [K in HttpMethod]: SseFn } }); + +export interface Config { + /** + * Auth token or a function returning auth token. The resolved value will be + * added to the request payload as defined by its `security` array. + */ + auth?: ((auth: Auth) => Promise | AuthToken) | AuthToken; + /** + * A function for serializing request body parameter. By default, + * {@link JSON.stringify()} will be used. + */ + bodySerializer?: BodySerializer | null; + /** + * An object containing any HTTP headers that you want to pre-populate your + * `Headers` object with. + * + * {@link https://developer.mozilla.org/docs/Web/API/Headers/Headers#init See more} + */ + headers?: + | RequestInit['headers'] + | Record< + string, + | string + | number + | boolean + | (string | number | boolean)[] + | null + | undefined + | unknown + >; + /** + * The request method. + * + * {@link https://developer.mozilla.org/docs/Web/API/fetch#method See more} + */ + method?: Uppercase; + /** + * A function for serializing request query parameters. By default, arrays + * will be exploded in form style, objects will be exploded in deepObject + * style, and reserved characters are percent-encoded. + * + * This method will have no effect if the native `paramsSerializer()` Axios + * API function is used. + * + * {@link https://swagger.io/docs/specification/serialization/#query View examples} + */ + querySerializer?: QuerySerializer | QuerySerializerOptions; + /** + * A function validating request data. This is useful if you want to ensure + * the request conforms to the desired shape, so it can be safely sent to + * the server. + */ + requestValidator?: (data: unknown) => Promise; + /** + * A function transforming response data before it's returned. This is useful + * for post-processing data, e.g. converting ISO strings into Date objects. + */ + responseTransformer?: (data: unknown) => Promise; + /** + * A function validating response data. This is useful if you want to ensure + * the response conforms to the desired shape, so it can be safely passed to + * the transformers and returned to the user. + */ + responseValidator?: (data: unknown) => Promise; +} + +type IsExactlyNeverOrNeverUndefined = [T] extends [never] + ? true + : [T] extends [never | undefined] + ? [undefined] extends [T] + ? false + : true + : false; + +export type OmitNever> = { + [K in keyof T as IsExactlyNeverOrNeverUndefined extends true + ? never + : K]: T[K]; +}; diff --git a/src/clients/romm/core/utils.gen.ts b/src/clients/romm/core/utils.gen.ts new file mode 100644 index 0000000..0b5389d --- /dev/null +++ b/src/clients/romm/core/utils.gen.ts @@ -0,0 +1,143 @@ +// This file is auto-generated by @hey-api/openapi-ts + +import type { BodySerializer, QuerySerializer } from './bodySerializer.gen'; +import { + type ArraySeparatorStyle, + serializeArrayParam, + serializeObjectParam, + serializePrimitiveParam, +} from './pathSerializer.gen'; + +export interface PathSerializer { + path: Record; + url: string; +} + +export const PATH_PARAM_RE = /\{[^{}]+\}/g; + +export const defaultPathSerializer = ({ path, url: _url }: PathSerializer) => { + let url = _url; + const matches = _url.match(PATH_PARAM_RE); + if (matches) { + for (const match of matches) { + let explode = false; + let name = match.substring(1, match.length - 1); + let style: ArraySeparatorStyle = 'simple'; + + if (name.endsWith('*')) { + explode = true; + name = name.substring(0, name.length - 1); + } + + if (name.startsWith('.')) { + name = name.substring(1); + style = 'label'; + } else if (name.startsWith(';')) { + name = name.substring(1); + style = 'matrix'; + } + + const value = path[name]; + + if (value === undefined || value === null) { + continue; + } + + if (Array.isArray(value)) { + url = url.replace( + match, + serializeArrayParam({ explode, name, style, value }), + ); + continue; + } + + if (typeof value === 'object') { + url = url.replace( + match, + serializeObjectParam({ + explode, + name, + style, + value: value as Record, + valueOnly: true, + }), + ); + continue; + } + + if (style === 'matrix') { + url = url.replace( + match, + `;${serializePrimitiveParam({ + name, + value: value as string, + })}`, + ); + continue; + } + + const replaceValue = encodeURIComponent( + style === 'label' ? `.${value as string}` : (value as string), + ); + url = url.replace(match, replaceValue); + } + } + return url; +}; + +export const getUrl = ({ + baseUrl, + path, + query, + querySerializer, + url: _url, +}: { + baseUrl?: string; + path?: Record; + query?: Record; + querySerializer: QuerySerializer; + url: string; +}) => { + const pathUrl = _url.startsWith('/') ? _url : `/${_url}`; + let url = (baseUrl ?? '') + pathUrl; + if (path) { + url = defaultPathSerializer({ path, url }); + } + let search = query ? querySerializer(query) : ''; + if (search.startsWith('?')) { + search = search.substring(1); + } + if (search) { + url += `?${search}`; + } + return url; +}; + +export function getValidRequestBody(options: { + body?: unknown; + bodySerializer?: BodySerializer | null; + serializedBody?: unknown; +}) { + const hasBody = options.body !== undefined; + const isSerializedBody = hasBody && options.bodySerializer; + + if (isSerializedBody) { + if ('serializedBody' in options) { + const hasSerializedBody = + options.serializedBody !== undefined && options.serializedBody !== ''; + + return hasSerializedBody ? options.serializedBody : null; + } + + // not all clients implement a serializedBody property (i.e. client-axios) + return options.body !== '' ? options.body : null; + } + + // plain/text body + if (hasBody) { + return options.body; + } + + // no body was provided + return undefined; +} diff --git a/src/clients/romm/index.ts b/src/clients/romm/index.ts new file mode 100644 index 0000000..2f21002 --- /dev/null +++ b/src/clients/romm/index.ts @@ -0,0 +1,4 @@ +// This file is auto-generated by @hey-api/openapi-ts + +export { addCollectionApiCollectionsPost, addExclusionApiConfigExcludePost, addFirmwareApiFirmwarePost, addPlatformApiPlatformsPost, addPlatformBindingApiConfigSystemPlatformsPost, addPlatformVersionApiConfigSystemVersionsPost, addRomApiRomsPost, addRomManualsApiRomsIdManualsPost, addSaveApiSavesPost, addScreenshotApiScreenshotsPost, addSmartCollectionApiCollectionsSmartPost, addStateApiStatesPost, addUserApiUsersPost, authOpenidApiOauthOpenidGet, createInviteLinkApiUsersInviteLinkPost, createRomNoteApiRomsIdNotesPost, createSetupPlatformsApiSetupPlatformsPost, createUserFromInviteApiUsersRegisterPost, deleteCollectionApiCollectionsIdDelete, deleteExclusionApiConfigExcludeExclusionTypeExclusionValueDelete, deleteFirmwareApiFirmwareDeletePost, deletePlatformApiPlatformsIdDelete, deletePlatformBindingApiConfigSystemPlatformsFsSlugDelete, deletePlatformVersionApiConfigSystemVersionsFsSlugDelete, deleteRomManualsApiRomsIdManualsDelete, deleteRomNoteApiRomsIdNotesNoteIdDelete, deleteRomsApiRomsDeletePost, deleteSavesApiSavesDeletePost, deleteSmartCollectionApiCollectionsSmartIdDelete, deleteStatesApiStatesDeletePost, deleteUserApiUsersIdDelete, downloadRomsApiRomsDownloadGet, exportGamelistApiGamelistExportPost, fpkgiFeedApiFeedsFpkgiPlatformSlugGet, getCollectionApiCollectionsIdGet, getCollectionsApiCollectionsGet, getConfigApiConfigGet, getCurrentUserApiUsersMeGet, getFirmwareApiFirmwareIdGet, getFirmwareContentApiFirmwareIdContentFileNameGet, getPlatformApiPlatformsIdGet, getPlatformFirmwareApiFirmwareGet, getPlatformsApiPlatformsGet, getRawAssetApiRawAssetsPathGet, getRomApiRomsIdGet, getRomByHashApiRomsByHashGet, getRomByMetadataProviderApiRomsByMetadataProviderGet, getRomContentApiRomsIdContentFileNameGet, getRomfileApiRomsFilesIdGet, getRomfileContentApiRomsfilesIdContentFileNameGet, getRomFiltersApiRomsFiltersGet, getRomNotesApiRomsIdNotesGet, getRomsApiRomsGet, getRoomsApiNetplayListGet, getSaveApiSavesIdGet, getSavesApiSavesGet, getSetupLibraryInfoApiSetupLibraryGet, getSmartCollectionApiCollectionsSmartIdGet, getSmartCollectionsApiCollectionsSmartGet, getStateApiStatesIdGet, getStatesApiStatesGet, getSupportedPlatformsEndpointApiPlatformsSupportedGet, getTaskByIdApiTasksTaskIdGet, getTasksStatusApiTasksStatusGet, getUserApiUsersIdGet, getUsersApiUsersGet, getVirtualCollectionApiCollectionsVirtualIdGet, getVirtualCollectionsApiCollectionsVirtualGet, headFirmwareContentApiFirmwareIdContentFileNameHead, headRawAssetApiRawAssetsPathHead, headRomContentApiRomsIdContentFileNameHead, heartbeatApiHeartbeatGet, kekatsuDsFeedApiFeedsKekatsuPlatformSlugGet, listTasksApiTasksGet, loginApiLoginPost, loginViaOpenidApiLoginOpenidGet, logoutApiLogoutPost, metadataHeartbeatApiHeartbeatMetadataSourceGet, type Options, pkgiPs3FeedApiFeedsPkgiPs3ContentTypeGet, pkgiPspFeedApiFeedsPkgiPspContentTypeGet, pkgiPsvitaFeedApiFeedsPkgiPsvitaContentTypeGet, platformsWebrcadeFeedApiFeedsWebrcadeGet, refreshRetroAchievementsApiUsersIdRaRefreshPost, requestPasswordResetApiForgotPasswordPost, resetPasswordApiResetPasswordPost, runAllTasksApiTasksRunPost, runSingleTaskApiTasksRunTaskNamePost, searchCoverApiSearchCoverGet, searchRomApiSearchRomsGet, statsApiStatsGet, tinfoilIndexFeedApiFeedsTinfoilGet, tokenApiTokenPost, updateCollectionApiCollectionsIdPut, updatePlatformApiPlatformsIdPut, updateRomApiRomsIdPut, updateRomNoteApiRomsIdNotesNoteIdPut, updateRomUserApiRomsIdPropsPut, updateSaveApiSavesIdPut, updateSmartCollectionApiCollectionsSmartIdPut, updateStateApiStatesIdPut, updateUserApiUsersIdPut } from './sdk.gen'; +export type { AddCollectionApiCollectionsPostData, AddCollectionApiCollectionsPostError, AddCollectionApiCollectionsPostErrors, AddCollectionApiCollectionsPostResponse, AddCollectionApiCollectionsPostResponses, AddExclusionApiConfigExcludePostData, AddExclusionApiConfigExcludePostResponses, AddFirmwareApiFirmwarePostData, AddFirmwareApiFirmwarePostError, AddFirmwareApiFirmwarePostErrors, AddFirmwareApiFirmwarePostResponse, AddFirmwareApiFirmwarePostResponses, AddFirmwareResponse, AddPlatformApiPlatformsPostData, AddPlatformApiPlatformsPostError, AddPlatformApiPlatformsPostErrors, AddPlatformApiPlatformsPostResponse, AddPlatformApiPlatformsPostResponses, AddPlatformBindingApiConfigSystemPlatformsPostData, AddPlatformBindingApiConfigSystemPlatformsPostResponses, AddPlatformVersionApiConfigSystemVersionsPostData, AddPlatformVersionApiConfigSystemVersionsPostResponses, AddRomApiRomsPostData, AddRomApiRomsPostError, AddRomApiRomsPostErrors, AddRomApiRomsPostResponses, AddRomManualsApiRomsIdManualsPostData, AddRomManualsApiRomsIdManualsPostError, AddRomManualsApiRomsIdManualsPostErrors, AddRomManualsApiRomsIdManualsPostResponses, AddSaveApiSavesPostData, AddSaveApiSavesPostError, AddSaveApiSavesPostErrors, AddSaveApiSavesPostResponse, AddSaveApiSavesPostResponses, AddScreenshotApiScreenshotsPostData, AddScreenshotApiScreenshotsPostError, AddScreenshotApiScreenshotsPostErrors, AddScreenshotApiScreenshotsPostResponse, AddScreenshotApiScreenshotsPostResponses, AddSmartCollectionApiCollectionsSmartPostData, AddSmartCollectionApiCollectionsSmartPostError, AddSmartCollectionApiCollectionsSmartPostErrors, AddSmartCollectionApiCollectionsSmartPostResponse, AddSmartCollectionApiCollectionsSmartPostResponses, AddStateApiStatesPostData, AddStateApiStatesPostError, AddStateApiStatesPostErrors, AddStateApiStatesPostResponse, AddStateApiStatesPostResponses, AddUserApiUsersPostData, AddUserApiUsersPostError, AddUserApiUsersPostErrors, AddUserApiUsersPostResponse, AddUserApiUsersPostResponses, AuthOpenidApiOauthOpenidGetData, AuthOpenidApiOauthOpenidGetResponses, BodyAddCollectionApiCollectionsPost, BodyAddFirmwareApiFirmwarePost, BodyAddPlatformApiPlatformsPost, BodyAddUserApiUsersPost, BodyCreateUserFromInviteApiUsersRegisterPost, BodyDeleteFirmwareApiFirmwareDeletePost, BodyDeleteRomsApiRomsDeletePost, BodyDeleteSavesApiSavesDeletePost, BodyDeleteStatesApiStatesDeletePost, BodyRefreshRetroAchievementsApiUsersIdRaRefreshPost, BodyRequestPasswordResetApiForgotPasswordPost, BodyResetPasswordApiResetPasswordPost, BodyTokenApiTokenPost, BodyUpdateCollectionApiCollectionsIdPut, BodyUpdatePlatformApiPlatformsIdPut, BodyUpdateRomApiRomsIdPut, BodyUpdateRomUserApiRomsIdPropsPut, BulkOperationResponse, CleanupStats, CleanupTaskMeta, CleanupTaskStatusResponse, ClientOptions, CollectionSchema, ConfigResponse, ConversionStats, ConversionTaskMeta, ConversionTaskStatusResponse, CreateInviteLinkApiUsersInviteLinkPostData, CreateInviteLinkApiUsersInviteLinkPostError, CreateInviteLinkApiUsersInviteLinkPostErrors, CreateInviteLinkApiUsersInviteLinkPostResponse, CreateInviteLinkApiUsersInviteLinkPostResponses, CreateRomNoteApiRomsIdNotesPostData, CreateRomNoteApiRomsIdNotesPostError, CreateRomNoteApiRomsIdNotesPostErrors, CreateRomNoteApiRomsIdNotesPostResponse, CreateRomNoteApiRomsIdNotesPostResponses, CreateSetupPlatformsApiSetupPlatformsPostData, CreateSetupPlatformsApiSetupPlatformsPostError, CreateSetupPlatformsApiSetupPlatformsPostErrors, CreateSetupPlatformsApiSetupPlatformsPostResponses, CreateUserFromInviteApiUsersRegisterPostData, CreateUserFromInviteApiUsersRegisterPostError, CreateUserFromInviteApiUsersRegisterPostErrors, CreateUserFromInviteApiUsersRegisterPostResponse, CreateUserFromInviteApiUsersRegisterPostResponses, CustomLimitOffsetPageSimpleRomSchema, CustomLimitOffsetPageSimpleRomSchemaWritable, DeleteCollectionApiCollectionsIdDeleteData, DeleteCollectionApiCollectionsIdDeleteError, DeleteCollectionApiCollectionsIdDeleteErrors, DeleteCollectionApiCollectionsIdDeleteResponses, DeleteExclusionApiConfigExcludeExclusionTypeExclusionValueDeleteData, DeleteExclusionApiConfigExcludeExclusionTypeExclusionValueDeleteError, DeleteExclusionApiConfigExcludeExclusionTypeExclusionValueDeleteErrors, DeleteExclusionApiConfigExcludeExclusionTypeExclusionValueDeleteResponses, DeleteFirmwareApiFirmwareDeletePostData, DeleteFirmwareApiFirmwareDeletePostError, DeleteFirmwareApiFirmwareDeletePostErrors, DeleteFirmwareApiFirmwareDeletePostResponse, DeleteFirmwareApiFirmwareDeletePostResponses, DeletePlatformApiPlatformsIdDeleteData, DeletePlatformApiPlatformsIdDeleteError, DeletePlatformApiPlatformsIdDeleteErrors, DeletePlatformApiPlatformsIdDeleteResponses, DeletePlatformBindingApiConfigSystemPlatformsFsSlugDeleteData, DeletePlatformBindingApiConfigSystemPlatformsFsSlugDeleteError, DeletePlatformBindingApiConfigSystemPlatformsFsSlugDeleteErrors, DeletePlatformBindingApiConfigSystemPlatformsFsSlugDeleteResponses, DeletePlatformVersionApiConfigSystemVersionsFsSlugDeleteData, DeletePlatformVersionApiConfigSystemVersionsFsSlugDeleteError, DeletePlatformVersionApiConfigSystemVersionsFsSlugDeleteErrors, DeletePlatformVersionApiConfigSystemVersionsFsSlugDeleteResponses, DeleteRomManualsApiRomsIdManualsDeleteData, DeleteRomManualsApiRomsIdManualsDeleteError, DeleteRomManualsApiRomsIdManualsDeleteErrors, DeleteRomManualsApiRomsIdManualsDeleteResponses, DeleteRomNoteApiRomsIdNotesNoteIdDeleteData, DeleteRomNoteApiRomsIdNotesNoteIdDeleteError, DeleteRomNoteApiRomsIdNotesNoteIdDeleteErrors, DeleteRomNoteApiRomsIdNotesNoteIdDeleteResponse, DeleteRomNoteApiRomsIdNotesNoteIdDeleteResponses, DeleteRomsApiRomsDeletePostData, DeleteRomsApiRomsDeletePostError, DeleteRomsApiRomsDeletePostErrors, DeleteRomsApiRomsDeletePostResponse, DeleteRomsApiRomsDeletePostResponses, DeleteSavesApiSavesDeletePostData, DeleteSavesApiSavesDeletePostError, DeleteSavesApiSavesDeletePostErrors, DeleteSavesApiSavesDeletePostResponse, DeleteSavesApiSavesDeletePostResponses, DeleteSmartCollectionApiCollectionsSmartIdDeleteData, DeleteSmartCollectionApiCollectionsSmartIdDeleteError, DeleteSmartCollectionApiCollectionsSmartIdDeleteErrors, DeleteSmartCollectionApiCollectionsSmartIdDeleteResponses, DeleteStatesApiStatesDeletePostData, DeleteStatesApiStatesDeletePostError, DeleteStatesApiStatesDeletePostErrors, DeleteStatesApiStatesDeletePostResponse, DeleteStatesApiStatesDeletePostResponses, DeleteUserApiUsersIdDeleteData, DeleteUserApiUsersIdDeleteError, DeleteUserApiUsersIdDeleteErrors, DeleteUserApiUsersIdDeleteResponses, DetailedRomSchema, DetailedRomSchemaWritable, DownloadRomsApiRomsDownloadGetData, DownloadRomsApiRomsDownloadGetError, DownloadRomsApiRomsDownloadGetErrors, DownloadRomsApiRomsDownloadGetResponses, EarnedAchievement, EjsControls, EjsControlsButton, EmulationDict, ExportGamelistApiGamelistExportPostData, ExportGamelistApiGamelistExportPostError, ExportGamelistApiGamelistExportPostErrors, ExportGamelistApiGamelistExportPostResponses, FilesystemDict, FirmwareSchema, FpkgiFeedApiFeedsFpkgiPlatformSlugGetData, FpkgiFeedApiFeedsFpkgiPlatformSlugGetError, FpkgiFeedApiFeedsFpkgiPlatformSlugGetErrors, FpkgiFeedApiFeedsFpkgiPlatformSlugGetResponses, FrontendDict, GenericTaskMeta, GenericTaskMetaWritable, GenericTaskStatusResponse, GetCollectionApiCollectionsIdGetData, GetCollectionApiCollectionsIdGetError, GetCollectionApiCollectionsIdGetErrors, GetCollectionApiCollectionsIdGetResponse, GetCollectionApiCollectionsIdGetResponses, GetCollectionsApiCollectionsGetData, GetCollectionsApiCollectionsGetError, GetCollectionsApiCollectionsGetErrors, GetCollectionsApiCollectionsGetResponse, GetCollectionsApiCollectionsGetResponses, GetConfigApiConfigGetData, GetConfigApiConfigGetResponse, GetConfigApiConfigGetResponses, GetCurrentUserApiUsersMeGetData, GetCurrentUserApiUsersMeGetResponse, GetCurrentUserApiUsersMeGetResponses, GetFirmwareApiFirmwareIdGetData, GetFirmwareApiFirmwareIdGetError, GetFirmwareApiFirmwareIdGetErrors, GetFirmwareApiFirmwareIdGetResponse, GetFirmwareApiFirmwareIdGetResponses, GetFirmwareContentApiFirmwareIdContentFileNameGetData, GetFirmwareContentApiFirmwareIdContentFileNameGetError, GetFirmwareContentApiFirmwareIdContentFileNameGetErrors, GetFirmwareContentApiFirmwareIdContentFileNameGetResponses, GetPlatformApiPlatformsIdGetData, GetPlatformApiPlatformsIdGetError, GetPlatformApiPlatformsIdGetErrors, GetPlatformApiPlatformsIdGetResponse, GetPlatformApiPlatformsIdGetResponses, GetPlatformFirmwareApiFirmwareGetData, GetPlatformFirmwareApiFirmwareGetError, GetPlatformFirmwareApiFirmwareGetErrors, GetPlatformFirmwareApiFirmwareGetResponse, GetPlatformFirmwareApiFirmwareGetResponses, GetPlatformsApiPlatformsGetData, GetPlatformsApiPlatformsGetError, GetPlatformsApiPlatformsGetErrors, GetPlatformsApiPlatformsGetResponse, GetPlatformsApiPlatformsGetResponses, GetRawAssetApiRawAssetsPathGetData, GetRawAssetApiRawAssetsPathGetError, GetRawAssetApiRawAssetsPathGetErrors, GetRawAssetApiRawAssetsPathGetResponses, GetRomApiRomsIdGetData, GetRomApiRomsIdGetError, GetRomApiRomsIdGetErrors, GetRomApiRomsIdGetResponse, GetRomApiRomsIdGetResponses, GetRomByHashApiRomsByHashGetData, GetRomByHashApiRomsByHashGetError, GetRomByHashApiRomsByHashGetErrors, GetRomByHashApiRomsByHashGetResponse, GetRomByHashApiRomsByHashGetResponses, GetRomByMetadataProviderApiRomsByMetadataProviderGetData, GetRomByMetadataProviderApiRomsByMetadataProviderGetError, GetRomByMetadataProviderApiRomsByMetadataProviderGetErrors, GetRomByMetadataProviderApiRomsByMetadataProviderGetResponse, GetRomByMetadataProviderApiRomsByMetadataProviderGetResponses, GetRomContentApiRomsIdContentFileNameGetData, GetRomContentApiRomsIdContentFileNameGetError, GetRomContentApiRomsIdContentFileNameGetErrors, GetRomContentApiRomsIdContentFileNameGetResponses, GetRomfileApiRomsFilesIdGetData, GetRomfileApiRomsFilesIdGetError, GetRomfileApiRomsFilesIdGetErrors, GetRomfileApiRomsFilesIdGetResponse, GetRomfileApiRomsFilesIdGetResponses, GetRomfileContentApiRomsfilesIdContentFileNameGetData, GetRomfileContentApiRomsfilesIdContentFileNameGetError, GetRomfileContentApiRomsfilesIdContentFileNameGetErrors, GetRomfileContentApiRomsfilesIdContentFileNameGetResponses, GetRomFiltersApiRomsFiltersGetData, GetRomFiltersApiRomsFiltersGetResponse, GetRomFiltersApiRomsFiltersGetResponses, GetRomNotesApiRomsIdNotesGetData, GetRomNotesApiRomsIdNotesGetError, GetRomNotesApiRomsIdNotesGetErrors, GetRomNotesApiRomsIdNotesGetResponse, GetRomNotesApiRomsIdNotesGetResponses, GetRomsApiRomsGetData, GetRomsApiRomsGetError, GetRomsApiRomsGetErrors, GetRomsApiRomsGetResponse, GetRomsApiRomsGetResponses, GetRoomsApiNetplayListGetData, GetRoomsApiNetplayListGetError, GetRoomsApiNetplayListGetErrors, GetRoomsApiNetplayListGetResponse, GetRoomsApiNetplayListGetResponses, GetSaveApiSavesIdGetData, GetSaveApiSavesIdGetError, GetSaveApiSavesIdGetErrors, GetSaveApiSavesIdGetResponse, GetSaveApiSavesIdGetResponses, GetSavesApiSavesGetData, GetSavesApiSavesGetError, GetSavesApiSavesGetErrors, GetSavesApiSavesGetResponse, GetSavesApiSavesGetResponses, GetSetupLibraryInfoApiSetupLibraryGetData, GetSetupLibraryInfoApiSetupLibraryGetResponses, GetSmartCollectionApiCollectionsSmartIdGetData, GetSmartCollectionApiCollectionsSmartIdGetError, GetSmartCollectionApiCollectionsSmartIdGetErrors, GetSmartCollectionApiCollectionsSmartIdGetResponse, GetSmartCollectionApiCollectionsSmartIdGetResponses, GetSmartCollectionsApiCollectionsSmartGetData, GetSmartCollectionsApiCollectionsSmartGetError, GetSmartCollectionsApiCollectionsSmartGetErrors, GetSmartCollectionsApiCollectionsSmartGetResponse, GetSmartCollectionsApiCollectionsSmartGetResponses, GetStateApiStatesIdGetData, GetStateApiStatesIdGetError, GetStateApiStatesIdGetErrors, GetStateApiStatesIdGetResponse, GetStateApiStatesIdGetResponses, GetStatesApiStatesGetData, GetStatesApiStatesGetError, GetStatesApiStatesGetErrors, GetStatesApiStatesGetResponse, GetStatesApiStatesGetResponses, GetSupportedPlatformsEndpointApiPlatformsSupportedGetData, GetSupportedPlatformsEndpointApiPlatformsSupportedGetResponse, GetSupportedPlatformsEndpointApiPlatformsSupportedGetResponses, GetTaskByIdApiTasksTaskIdGetData, GetTaskByIdApiTasksTaskIdGetError, GetTaskByIdApiTasksTaskIdGetErrors, GetTaskByIdApiTasksTaskIdGetResponse, GetTaskByIdApiTasksTaskIdGetResponses, GetTasksStatusApiTasksStatusGetData, GetTasksStatusApiTasksStatusGetResponse, GetTasksStatusApiTasksStatusGetResponses, GetUserApiUsersIdGetData, GetUserApiUsersIdGetError, GetUserApiUsersIdGetErrors, GetUserApiUsersIdGetResponse, GetUserApiUsersIdGetResponses, GetUsersApiUsersGetData, GetUsersApiUsersGetResponse, GetUsersApiUsersGetResponses, GetVirtualCollectionApiCollectionsVirtualIdGetData, GetVirtualCollectionApiCollectionsVirtualIdGetError, GetVirtualCollectionApiCollectionsVirtualIdGetErrors, GetVirtualCollectionApiCollectionsVirtualIdGetResponse, GetVirtualCollectionApiCollectionsVirtualIdGetResponses, GetVirtualCollectionsApiCollectionsVirtualGetData, GetVirtualCollectionsApiCollectionsVirtualGetError, GetVirtualCollectionsApiCollectionsVirtualGetErrors, GetVirtualCollectionsApiCollectionsVirtualGetResponse, GetVirtualCollectionsApiCollectionsVirtualGetResponses, HeadFirmwareContentApiFirmwareIdContentFileNameHeadData, HeadFirmwareContentApiFirmwareIdContentFileNameHeadError, HeadFirmwareContentApiFirmwareIdContentFileNameHeadErrors, HeadFirmwareContentApiFirmwareIdContentFileNameHeadResponses, HeadRawAssetApiRawAssetsPathHeadData, HeadRawAssetApiRawAssetsPathHeadError, HeadRawAssetApiRawAssetsPathHeadErrors, HeadRawAssetApiRawAssetsPathHeadResponses, HeadRomContentApiRomsIdContentFileNameHeadData, HeadRomContentApiRomsIdContentFileNameHeadError, HeadRomContentApiRomsIdContentFileNameHeadErrors, HeadRomContentApiRomsIdContentFileNameHeadResponses, HeartbeatApiHeartbeatGetData, HeartbeatApiHeartbeatGetResponse, HeartbeatApiHeartbeatGetResponses, HeartbeatResponse, HttpValidationError, IgdbAgeRating, IgdbMetadataMultiplayerMode, IgdbMetadataPlatform, IgdbRelatedGame, InviteLinkSchema, JobStatus, KekatsuDsFeedApiFeedsKekatsuPlatformSlugGetData, KekatsuDsFeedApiFeedsKekatsuPlatformSlugGetError, KekatsuDsFeedApiFeedsKekatsuPlatformSlugGetErrors, KekatsuDsFeedApiFeedsKekatsuPlatformSlugGetResponses, LaunchboxImage, ListTasksApiTasksGetData, ListTasksApiTasksGetResponse, ListTasksApiTasksGetResponses, LoginApiLoginPostData, LoginApiLoginPostResponses, LoginViaOpenidApiLoginOpenidGetData, LoginViaOpenidApiLoginOpenidGetResponses, LogoutApiLogoutPostData, LogoutApiLogoutPostResponses, ManualMetadata, MetadataHeartbeatApiHeartbeatMetadataSourceGetData, MetadataHeartbeatApiHeartbeatMetadataSourceGetError, MetadataHeartbeatApiHeartbeatMetadataSourceGetErrors, MetadataHeartbeatApiHeartbeatMetadataSourceGetResponse, MetadataHeartbeatApiHeartbeatMetadataSourceGetResponses, MetadataSourcesDict, MobyMetadataPlatform, NetplayIceServer, OidcDict, PkgiPs3FeedApiFeedsPkgiPs3ContentTypeGetData, PkgiPs3FeedApiFeedsPkgiPs3ContentTypeGetError, PkgiPs3FeedApiFeedsPkgiPs3ContentTypeGetErrors, PkgiPs3FeedApiFeedsPkgiPs3ContentTypeGetResponses, PkgiPspFeedApiFeedsPkgiPspContentTypeGetData, PkgiPspFeedApiFeedsPkgiPspContentTypeGetError, PkgiPspFeedApiFeedsPkgiPspContentTypeGetErrors, PkgiPspFeedApiFeedsPkgiPspContentTypeGetResponses, PkgiPsvitaFeedApiFeedsPkgiPsvitaContentTypeGetData, PkgiPsvitaFeedApiFeedsPkgiPsvitaContentTypeGetError, PkgiPsvitaFeedApiFeedsPkgiPsvitaContentTypeGetErrors, PkgiPsvitaFeedApiFeedsPkgiPsvitaContentTypeGetResponses, PlatformSchema, PlatformSchemaWritable, PlatformsWebrcadeFeedApiFeedsWebrcadeGetData, PlatformsWebrcadeFeedApiFeedsWebrcadeGetResponse, PlatformsWebrcadeFeedApiFeedsWebrcadeGetResponses, RaGameRomAchievement, RaProgression, RaUserGameProgression, RefreshRetroAchievementsApiUsersIdRaRefreshPostData, RefreshRetroAchievementsApiUsersIdRaRefreshPostError, RefreshRetroAchievementsApiUsersIdRaRefreshPostErrors, RefreshRetroAchievementsApiUsersIdRaRefreshPostResponses, RequestPasswordResetApiForgotPasswordPostData, RequestPasswordResetApiForgotPasswordPostError, RequestPasswordResetApiForgotPasswordPostErrors, RequestPasswordResetApiForgotPasswordPostResponses, ResetPasswordApiResetPasswordPostData, ResetPasswordApiResetPasswordPostError, ResetPasswordApiResetPasswordPostErrors, ResetPasswordApiResetPasswordPostResponses, Role, RomFileCategory, RomFileSchema, RomFiltersDict, RomFlashpointMetadata, RomGamelistMetadata, RomHasheousMetadata, RomHltbMetadata, RomIgdbMetadata, RomLaunchboxMetadata, RomMetadataSchema, RomMobyMetadata, RomRaMetadata, RomSsMetadata, RomUserSchema, RomUserStatus, RoomsResponse, RunAllTasksApiTasksRunPostData, RunAllTasksApiTasksRunPostResponse, RunAllTasksApiTasksRunPostResponses, RunSingleTaskApiTasksRunTaskNamePostData, RunSingleTaskApiTasksRunTaskNamePostError, RunSingleTaskApiTasksRunTaskNamePostErrors, RunSingleTaskApiTasksRunTaskNamePostResponse, RunSingleTaskApiTasksRunTaskNamePostResponses, SaveSchema, ScanStats, ScanTaskMeta, ScanTaskStatusResponse, ScreenshotSchema, SearchCoverApiSearchCoverGetData, SearchCoverApiSearchCoverGetError, SearchCoverApiSearchCoverGetErrors, SearchCoverApiSearchCoverGetResponse, SearchCoverApiSearchCoverGetResponses, SearchCoverSchema, SearchRomApiSearchRomsGetData, SearchRomApiSearchRomsGetError, SearchRomApiSearchRomsGetErrors, SearchRomApiSearchRomsGetResponse, SearchRomApiSearchRomsGetResponses, SearchRomSchema, SgdbResource, SiblingRomSchema, SiblingRomSchemaWritable, SimpleRomSchema, SimpleRomSchemaWritable, SmartCollectionSchema, StateSchema, StatsApiStatsGetData, StatsApiStatsGetResponse, StatsApiStatsGetResponses, StatsReturn, SystemDict, TaskExecutionResponse, TaskInfo, TasksDict, TaskType, TinfoilFeedFileSchema, TinfoilFeedSchema, TinfoilIndexFeedApiFeedsTinfoilGetData, TinfoilIndexFeedApiFeedsTinfoilGetError, TinfoilIndexFeedApiFeedsTinfoilGetErrors, TinfoilIndexFeedApiFeedsTinfoilGetResponse, TinfoilIndexFeedApiFeedsTinfoilGetResponses, TokenApiTokenPostData, TokenApiTokenPostError, TokenApiTokenPostErrors, TokenApiTokenPostResponse, TokenApiTokenPostResponses, TokenResponse, UpdateCollectionApiCollectionsIdPutData, UpdateCollectionApiCollectionsIdPutError, UpdateCollectionApiCollectionsIdPutErrors, UpdateCollectionApiCollectionsIdPutResponse, UpdateCollectionApiCollectionsIdPutResponses, UpdatePlatformApiPlatformsIdPutData, UpdatePlatformApiPlatformsIdPutError, UpdatePlatformApiPlatformsIdPutErrors, UpdatePlatformApiPlatformsIdPutResponse, UpdatePlatformApiPlatformsIdPutResponses, UpdateRomApiRomsIdPutData, UpdateRomApiRomsIdPutError, UpdateRomApiRomsIdPutErrors, UpdateRomApiRomsIdPutResponse, UpdateRomApiRomsIdPutResponses, UpdateRomNoteApiRomsIdNotesNoteIdPutData, UpdateRomNoteApiRomsIdNotesNoteIdPutError, UpdateRomNoteApiRomsIdNotesNoteIdPutErrors, UpdateRomNoteApiRomsIdNotesNoteIdPutResponse, UpdateRomNoteApiRomsIdNotesNoteIdPutResponses, UpdateRomUserApiRomsIdPropsPutData, UpdateRomUserApiRomsIdPropsPutError, UpdateRomUserApiRomsIdPropsPutErrors, UpdateRomUserApiRomsIdPropsPutResponse, UpdateRomUserApiRomsIdPropsPutResponses, UpdateSaveApiSavesIdPutData, UpdateSaveApiSavesIdPutError, UpdateSaveApiSavesIdPutErrors, UpdateSaveApiSavesIdPutResponse, UpdateSaveApiSavesIdPutResponses, UpdateSmartCollectionApiCollectionsSmartIdPutData, UpdateSmartCollectionApiCollectionsSmartIdPutError, UpdateSmartCollectionApiCollectionsSmartIdPutErrors, UpdateSmartCollectionApiCollectionsSmartIdPutResponse, UpdateSmartCollectionApiCollectionsSmartIdPutResponses, UpdateStateApiStatesIdPutData, UpdateStateApiStatesIdPutError, UpdateStateApiStatesIdPutErrors, UpdateStateApiStatesIdPutResponse, UpdateStateApiStatesIdPutResponses, UpdateStats, UpdateTaskMeta, UpdateTaskStatusResponse, UpdateUserApiUsersIdPutData, UpdateUserApiUsersIdPutError, UpdateUserApiUsersIdPutErrors, UpdateUserApiUsersIdPutResponse, UpdateUserApiUsersIdPutResponses, UserCollectionSchema, UserForm, UserNoteSchema, UserSchema, ValidationError, VirtualCollectionSchema, WatcherTaskMeta, WatcherTaskMetaWritable, WatcherTaskStatusResponse, WebrcadeFeedCategorySchema, WebrcadeFeedItemPropsSchema, WebrcadeFeedItemSchema, WebrcadeFeedSchema } from './types.gen'; diff --git a/src/clients/romm/sdk.gen.ts b/src/clients/romm/sdk.gen.ts new file mode 100644 index 0000000..a2d2582 --- /dev/null +++ b/src/clients/romm/sdk.gen.ts @@ -0,0 +1,1519 @@ +// This file is auto-generated by @hey-api/openapi-ts + +import { type Client, formDataBodySerializer, type Options as Options2, type TDataShape, urlSearchParamsBodySerializer } from './client'; +import { client } from './client.gen'; +import type { AddCollectionApiCollectionsPostData, AddCollectionApiCollectionsPostErrors, AddCollectionApiCollectionsPostResponses, AddExclusionApiConfigExcludePostData, AddExclusionApiConfigExcludePostResponses, AddFirmwareApiFirmwarePostData, AddFirmwareApiFirmwarePostErrors, AddFirmwareApiFirmwarePostResponses, AddPlatformApiPlatformsPostData, AddPlatformApiPlatformsPostErrors, AddPlatformApiPlatformsPostResponses, AddPlatformBindingApiConfigSystemPlatformsPostData, AddPlatformBindingApiConfigSystemPlatformsPostResponses, AddPlatformVersionApiConfigSystemVersionsPostData, AddPlatformVersionApiConfigSystemVersionsPostResponses, AddRomApiRomsPostData, AddRomApiRomsPostErrors, AddRomApiRomsPostResponses, AddRomManualsApiRomsIdManualsPostData, AddRomManualsApiRomsIdManualsPostErrors, AddRomManualsApiRomsIdManualsPostResponses, AddSaveApiSavesPostData, AddSaveApiSavesPostErrors, AddSaveApiSavesPostResponses, AddScreenshotApiScreenshotsPostData, AddScreenshotApiScreenshotsPostErrors, AddScreenshotApiScreenshotsPostResponses, AddSmartCollectionApiCollectionsSmartPostData, AddSmartCollectionApiCollectionsSmartPostErrors, AddSmartCollectionApiCollectionsSmartPostResponses, AddStateApiStatesPostData, AddStateApiStatesPostErrors, AddStateApiStatesPostResponses, AddUserApiUsersPostData, AddUserApiUsersPostErrors, AddUserApiUsersPostResponses, AuthOpenidApiOauthOpenidGetData, AuthOpenidApiOauthOpenidGetResponses, CreateInviteLinkApiUsersInviteLinkPostData, CreateInviteLinkApiUsersInviteLinkPostErrors, CreateInviteLinkApiUsersInviteLinkPostResponses, CreateRomNoteApiRomsIdNotesPostData, CreateRomNoteApiRomsIdNotesPostErrors, CreateRomNoteApiRomsIdNotesPostResponses, CreateSetupPlatformsApiSetupPlatformsPostData, CreateSetupPlatformsApiSetupPlatformsPostErrors, CreateSetupPlatformsApiSetupPlatformsPostResponses, CreateUserFromInviteApiUsersRegisterPostData, CreateUserFromInviteApiUsersRegisterPostErrors, CreateUserFromInviteApiUsersRegisterPostResponses, DeleteCollectionApiCollectionsIdDeleteData, DeleteCollectionApiCollectionsIdDeleteErrors, DeleteCollectionApiCollectionsIdDeleteResponses, DeleteExclusionApiConfigExcludeExclusionTypeExclusionValueDeleteData, DeleteExclusionApiConfigExcludeExclusionTypeExclusionValueDeleteErrors, DeleteExclusionApiConfigExcludeExclusionTypeExclusionValueDeleteResponses, DeleteFirmwareApiFirmwareDeletePostData, DeleteFirmwareApiFirmwareDeletePostErrors, DeleteFirmwareApiFirmwareDeletePostResponses, DeletePlatformApiPlatformsIdDeleteData, DeletePlatformApiPlatformsIdDeleteErrors, DeletePlatformApiPlatformsIdDeleteResponses, DeletePlatformBindingApiConfigSystemPlatformsFsSlugDeleteData, DeletePlatformBindingApiConfigSystemPlatformsFsSlugDeleteErrors, DeletePlatformBindingApiConfigSystemPlatformsFsSlugDeleteResponses, DeletePlatformVersionApiConfigSystemVersionsFsSlugDeleteData, DeletePlatformVersionApiConfigSystemVersionsFsSlugDeleteErrors, DeletePlatformVersionApiConfigSystemVersionsFsSlugDeleteResponses, DeleteRomManualsApiRomsIdManualsDeleteData, DeleteRomManualsApiRomsIdManualsDeleteErrors, DeleteRomManualsApiRomsIdManualsDeleteResponses, DeleteRomNoteApiRomsIdNotesNoteIdDeleteData, DeleteRomNoteApiRomsIdNotesNoteIdDeleteErrors, DeleteRomNoteApiRomsIdNotesNoteIdDeleteResponses, DeleteRomsApiRomsDeletePostData, DeleteRomsApiRomsDeletePostErrors, DeleteRomsApiRomsDeletePostResponses, DeleteSavesApiSavesDeletePostData, DeleteSavesApiSavesDeletePostErrors, DeleteSavesApiSavesDeletePostResponses, DeleteSmartCollectionApiCollectionsSmartIdDeleteData, DeleteSmartCollectionApiCollectionsSmartIdDeleteErrors, DeleteSmartCollectionApiCollectionsSmartIdDeleteResponses, DeleteStatesApiStatesDeletePostData, DeleteStatesApiStatesDeletePostErrors, DeleteStatesApiStatesDeletePostResponses, DeleteUserApiUsersIdDeleteData, DeleteUserApiUsersIdDeleteErrors, DeleteUserApiUsersIdDeleteResponses, DownloadRomsApiRomsDownloadGetData, DownloadRomsApiRomsDownloadGetErrors, DownloadRomsApiRomsDownloadGetResponses, ExportGamelistApiGamelistExportPostData, ExportGamelistApiGamelistExportPostErrors, ExportGamelistApiGamelistExportPostResponses, FpkgiFeedApiFeedsFpkgiPlatformSlugGetData, FpkgiFeedApiFeedsFpkgiPlatformSlugGetErrors, FpkgiFeedApiFeedsFpkgiPlatformSlugGetResponses, GetCollectionApiCollectionsIdGetData, GetCollectionApiCollectionsIdGetErrors, GetCollectionApiCollectionsIdGetResponses, GetCollectionsApiCollectionsGetData, GetCollectionsApiCollectionsGetErrors, GetCollectionsApiCollectionsGetResponses, GetConfigApiConfigGetData, GetConfigApiConfigGetResponses, GetCurrentUserApiUsersMeGetData, GetCurrentUserApiUsersMeGetResponses, GetFirmwareApiFirmwareIdGetData, GetFirmwareApiFirmwareIdGetErrors, GetFirmwareApiFirmwareIdGetResponses, GetFirmwareContentApiFirmwareIdContentFileNameGetData, GetFirmwareContentApiFirmwareIdContentFileNameGetErrors, GetFirmwareContentApiFirmwareIdContentFileNameGetResponses, GetPlatformApiPlatformsIdGetData, GetPlatformApiPlatformsIdGetErrors, GetPlatformApiPlatformsIdGetResponses, GetPlatformFirmwareApiFirmwareGetData, GetPlatformFirmwareApiFirmwareGetErrors, GetPlatformFirmwareApiFirmwareGetResponses, GetPlatformsApiPlatformsGetData, GetPlatformsApiPlatformsGetErrors, GetPlatformsApiPlatformsGetResponses, GetRawAssetApiRawAssetsPathGetData, GetRawAssetApiRawAssetsPathGetErrors, GetRawAssetApiRawAssetsPathGetResponses, GetRomApiRomsIdGetData, GetRomApiRomsIdGetErrors, GetRomApiRomsIdGetResponses, GetRomByHashApiRomsByHashGetData, GetRomByHashApiRomsByHashGetErrors, GetRomByHashApiRomsByHashGetResponses, GetRomByMetadataProviderApiRomsByMetadataProviderGetData, GetRomByMetadataProviderApiRomsByMetadataProviderGetErrors, GetRomByMetadataProviderApiRomsByMetadataProviderGetResponses, GetRomContentApiRomsIdContentFileNameGetData, GetRomContentApiRomsIdContentFileNameGetErrors, GetRomContentApiRomsIdContentFileNameGetResponses, GetRomfileApiRomsFilesIdGetData, GetRomfileApiRomsFilesIdGetErrors, GetRomfileApiRomsFilesIdGetResponses, GetRomfileContentApiRomsfilesIdContentFileNameGetData, GetRomfileContentApiRomsfilesIdContentFileNameGetErrors, GetRomfileContentApiRomsfilesIdContentFileNameGetResponses, GetRomFiltersApiRomsFiltersGetData, GetRomFiltersApiRomsFiltersGetResponses, GetRomNotesApiRomsIdNotesGetData, GetRomNotesApiRomsIdNotesGetErrors, GetRomNotesApiRomsIdNotesGetResponses, GetRomsApiRomsGetData, GetRomsApiRomsGetErrors, GetRomsApiRomsGetResponses, GetRoomsApiNetplayListGetData, GetRoomsApiNetplayListGetErrors, GetRoomsApiNetplayListGetResponses, GetSaveApiSavesIdGetData, GetSaveApiSavesIdGetErrors, GetSaveApiSavesIdGetResponses, GetSavesApiSavesGetData, GetSavesApiSavesGetErrors, GetSavesApiSavesGetResponses, GetSetupLibraryInfoApiSetupLibraryGetData, GetSetupLibraryInfoApiSetupLibraryGetResponses, GetSmartCollectionApiCollectionsSmartIdGetData, GetSmartCollectionApiCollectionsSmartIdGetErrors, GetSmartCollectionApiCollectionsSmartIdGetResponses, GetSmartCollectionsApiCollectionsSmartGetData, GetSmartCollectionsApiCollectionsSmartGetErrors, GetSmartCollectionsApiCollectionsSmartGetResponses, GetStateApiStatesIdGetData, GetStateApiStatesIdGetErrors, GetStateApiStatesIdGetResponses, GetStatesApiStatesGetData, GetStatesApiStatesGetErrors, GetStatesApiStatesGetResponses, GetSupportedPlatformsEndpointApiPlatformsSupportedGetData, GetSupportedPlatformsEndpointApiPlatformsSupportedGetResponses, GetTaskByIdApiTasksTaskIdGetData, GetTaskByIdApiTasksTaskIdGetErrors, GetTaskByIdApiTasksTaskIdGetResponses, GetTasksStatusApiTasksStatusGetData, GetTasksStatusApiTasksStatusGetResponses, GetUserApiUsersIdGetData, GetUserApiUsersIdGetErrors, GetUserApiUsersIdGetResponses, GetUsersApiUsersGetData, GetUsersApiUsersGetResponses, GetVirtualCollectionApiCollectionsVirtualIdGetData, GetVirtualCollectionApiCollectionsVirtualIdGetErrors, GetVirtualCollectionApiCollectionsVirtualIdGetResponses, GetVirtualCollectionsApiCollectionsVirtualGetData, GetVirtualCollectionsApiCollectionsVirtualGetErrors, GetVirtualCollectionsApiCollectionsVirtualGetResponses, HeadFirmwareContentApiFirmwareIdContentFileNameHeadData, HeadFirmwareContentApiFirmwareIdContentFileNameHeadErrors, HeadFirmwareContentApiFirmwareIdContentFileNameHeadResponses, HeadRawAssetApiRawAssetsPathHeadData, HeadRawAssetApiRawAssetsPathHeadErrors, HeadRawAssetApiRawAssetsPathHeadResponses, HeadRomContentApiRomsIdContentFileNameHeadData, HeadRomContentApiRomsIdContentFileNameHeadErrors, HeadRomContentApiRomsIdContentFileNameHeadResponses, HeartbeatApiHeartbeatGetData, HeartbeatApiHeartbeatGetResponses, KekatsuDsFeedApiFeedsKekatsuPlatformSlugGetData, KekatsuDsFeedApiFeedsKekatsuPlatformSlugGetErrors, KekatsuDsFeedApiFeedsKekatsuPlatformSlugGetResponses, ListTasksApiTasksGetData, ListTasksApiTasksGetResponses, LoginApiLoginPostData, LoginApiLoginPostResponses, LoginViaOpenidApiLoginOpenidGetData, LoginViaOpenidApiLoginOpenidGetResponses, LogoutApiLogoutPostData, LogoutApiLogoutPostResponses, MetadataHeartbeatApiHeartbeatMetadataSourceGetData, MetadataHeartbeatApiHeartbeatMetadataSourceGetErrors, MetadataHeartbeatApiHeartbeatMetadataSourceGetResponses, PkgiPs3FeedApiFeedsPkgiPs3ContentTypeGetData, PkgiPs3FeedApiFeedsPkgiPs3ContentTypeGetErrors, PkgiPs3FeedApiFeedsPkgiPs3ContentTypeGetResponses, PkgiPspFeedApiFeedsPkgiPspContentTypeGetData, PkgiPspFeedApiFeedsPkgiPspContentTypeGetErrors, PkgiPspFeedApiFeedsPkgiPspContentTypeGetResponses, PkgiPsvitaFeedApiFeedsPkgiPsvitaContentTypeGetData, PkgiPsvitaFeedApiFeedsPkgiPsvitaContentTypeGetErrors, PkgiPsvitaFeedApiFeedsPkgiPsvitaContentTypeGetResponses, PlatformsWebrcadeFeedApiFeedsWebrcadeGetData, PlatformsWebrcadeFeedApiFeedsWebrcadeGetResponses, RefreshRetroAchievementsApiUsersIdRaRefreshPostData, RefreshRetroAchievementsApiUsersIdRaRefreshPostErrors, RefreshRetroAchievementsApiUsersIdRaRefreshPostResponses, RequestPasswordResetApiForgotPasswordPostData, RequestPasswordResetApiForgotPasswordPostErrors, RequestPasswordResetApiForgotPasswordPostResponses, ResetPasswordApiResetPasswordPostData, ResetPasswordApiResetPasswordPostErrors, ResetPasswordApiResetPasswordPostResponses, RunAllTasksApiTasksRunPostData, RunAllTasksApiTasksRunPostResponses, RunSingleTaskApiTasksRunTaskNamePostData, RunSingleTaskApiTasksRunTaskNamePostErrors, RunSingleTaskApiTasksRunTaskNamePostResponses, SearchCoverApiSearchCoverGetData, SearchCoverApiSearchCoverGetErrors, SearchCoverApiSearchCoverGetResponses, SearchRomApiSearchRomsGetData, SearchRomApiSearchRomsGetErrors, SearchRomApiSearchRomsGetResponses, StatsApiStatsGetData, StatsApiStatsGetResponses, TinfoilIndexFeedApiFeedsTinfoilGetData, TinfoilIndexFeedApiFeedsTinfoilGetErrors, TinfoilIndexFeedApiFeedsTinfoilGetResponses, TokenApiTokenPostData, TokenApiTokenPostErrors, TokenApiTokenPostResponses, UpdateCollectionApiCollectionsIdPutData, UpdateCollectionApiCollectionsIdPutErrors, UpdateCollectionApiCollectionsIdPutResponses, UpdatePlatformApiPlatformsIdPutData, UpdatePlatformApiPlatformsIdPutErrors, UpdatePlatformApiPlatformsIdPutResponses, UpdateRomApiRomsIdPutData, UpdateRomApiRomsIdPutErrors, UpdateRomApiRomsIdPutResponses, UpdateRomNoteApiRomsIdNotesNoteIdPutData, UpdateRomNoteApiRomsIdNotesNoteIdPutErrors, UpdateRomNoteApiRomsIdNotesNoteIdPutResponses, UpdateRomUserApiRomsIdPropsPutData, UpdateRomUserApiRomsIdPropsPutErrors, UpdateRomUserApiRomsIdPropsPutResponses, UpdateSaveApiSavesIdPutData, UpdateSaveApiSavesIdPutErrors, UpdateSaveApiSavesIdPutResponses, UpdateSmartCollectionApiCollectionsSmartIdPutData, UpdateSmartCollectionApiCollectionsSmartIdPutErrors, UpdateSmartCollectionApiCollectionsSmartIdPutResponses, UpdateStateApiStatesIdPutData, UpdateStateApiStatesIdPutErrors, UpdateStateApiStatesIdPutResponses, UpdateUserApiUsersIdPutData, UpdateUserApiUsersIdPutErrors, UpdateUserApiUsersIdPutResponses } from './types.gen'; + +export type Options = Options2 & { + /** + * You can provide a client instance returned by `createClient()` instead of + * individual options. This might be also useful if you want to implement a + * custom client. + */ + client?: Client; + /** + * You can pass arbitrary values through the `meta` object. This can be + * used to access values that aren't defined as part of the SDK function. + */ + meta?: Record; +}; + +/** + * Heartbeat + * + * Endpoint to set the CSRF token in cache and return all the basic RomM config + * + * Returns: + * HeartbeatReturn: TypedDict structure with all the defined values in the HeartbeatReturn class. + */ +export const heartbeatApiHeartbeatGet = (options?: Options) => (options?.client ?? client).get({ url: '/api/heartbeat', ...options }); + +/** + * Metadata Heartbeat + * + * Endpoint to return the heartbeat of the metadata sources + */ +export const metadataHeartbeatApiHeartbeatMetadataSourceGet = (options: Options) => (options.client ?? client).get({ url: '/api/heartbeat/metadata/{source}', ...options }); + +/** + * Get Setup Library Info + * + * Get library structure information for setup wizard. + * + * Only accessible during initial setup (no admin users) or with authentication. + * + * Returns: + * - detected_structure: "struct_a" (roms/{platform}), "struct_b" ({platform}/roms), or None + * - existing_platforms: list of objects with fs_slug and rom_count + * - supported_platforms: list of all supported platforms with metadata + */ +export const getSetupLibraryInfoApiSetupLibraryGet = (options?: Options) => (options?.client ?? client).get({ + security: [{ scheme: 'bearer', type: 'http' }, { scheme: 'basic', type: 'http' }], + url: '/api/setup/library', + ...options +}); + +/** + * Create Setup Platforms + * + * Create platform folders during setup wizard. + * + * Only accessible during initial setup (no admin users) or with authentication. + * + * Args: + * platform_slugs: List of platform fs_slugs to create + * + * Returns: + * - success: bool + * - created_count: number of platforms created + * - message: success or error message + */ +export const createSetupPlatformsApiSetupPlatformsPost = (options: Options) => (options.client ?? client).post({ + security: [{ scheme: 'bearer', type: 'http' }, { scheme: 'basic', type: 'http' }], + url: '/api/setup/platforms', + ...options, + headers: { + 'Content-Type': 'application/json', + ...options.headers + } +}); + +/** + * Login + * + * Session login endpoint + * + * Args: + * request (Request): Fastapi Request object + * credentials: Defaults to Depends(HTTPBasic()). + * + * Raises: + * CredentialsException: Invalid credentials + * UserDisabledException: Auth is disabled + */ +export const loginApiLoginPost = (options?: Options) => (options?.client ?? client).post({ + security: [{ scheme: 'basic', type: 'http' }], + url: '/api/login', + ...options +}); + +/** + * Logout + * + * Session logout endpoint + * + * Args: + * request (Request): Fastapi Request object + */ +export const logoutApiLogoutPost = (options?: Options) => (options?.client ?? client).post({ url: '/api/logout', ...options }); + +/** + * Token + * + * OAuth2 token endpoint + * + * Args: + * form_data (Annotated[OAuth2RequestForm, Depends): Form Data with OAuth2 info + * + * Raises: + * HTTPException: Missing refresh token + * HTTPException: Invalid refresh token + * HTTPException: Missing username or password + * HTTPException: Invalid username or password + * HTTPException: Client credentials are not yet supported + * HTTPException: Invalid or unsupported grant type + * HTTPException: Insufficient scope + * + * Returns: + * TokenResponse: TypedDict with the new generated token info + */ +export const tokenApiTokenPost = (options?: Options) => (options?.client ?? client).post({ + ...urlSearchParamsBodySerializer, + url: '/api/token', + ...options, + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', + ...options?.headers + } +}); + +/** + * Login Via Openid + * + * OIDC login endpoint + * + * Args: + * request (Request): Fastapi Request object + * + * Raises: + * OIDCDisabledException: OAuth is disabled + * OIDCNotConfiguredException: OAuth not configured + * + * Returns: + * RedirectResponse: Redirect to OIDC provider + */ +export const loginViaOpenidApiLoginOpenidGet = (options?: Options) => (options?.client ?? client).get({ url: '/api/login/openid', ...options }); + +/** + * Auth Openid + * + * OIDC callback endpoint + * + * Args: + * request (Request): Fastapi Request object + * + * Raises: + * OIDCDisabledException: OAuth is disabled + * OIDCNotConfiguredException: OAuth not configured + * AuthCredentialsException: Invalid credentials + * UserDisabledException: Auth is disabled + * + * Returns: + * RedirectResponse: Redirect to home page + */ +export const authOpenidApiOauthOpenidGet = (options?: Options) => (options?.client ?? client).get({ url: '/api/oauth/openid', ...options }); + +/** + * Request Password Reset + * + * Request a password reset link for the user. + * + * Args: + * username (str): Username of the user requesting the reset + * Returns: + * None: Returns 200 OK status + */ +export const requestPasswordResetApiForgotPasswordPost = (options: Options) => (options.client ?? client).post({ + url: '/api/forgot-password', + ...options, + headers: { + 'Content-Type': 'application/json', + ...options.headers + } +}); + +/** + * Reset Password + * + * Reset password using the token. + * + * Args: + * token (str): Reset token from the URL + * new_password (str): New user password + * + * Returns: + * None: Returns 200 OK status + */ +export const resetPasswordApiResetPasswordPost = (options: Options) => (options.client ?? client).post({ + url: '/api/reset-password', + ...options, + headers: { + 'Content-Type': 'application/json', + ...options.headers + } +}); + +/** + * Get Users + * + * Get all users endpoint + * + * Args: + * request (Request): Fastapi Request object + * + * Returns: + * list[UserSchema]: All users stored in the RomM's database + */ +export const getUsersApiUsersGet = (options?: Options) => (options?.client ?? client).get({ + security: [{ scheme: 'bearer', type: 'http' }, { scheme: 'basic', type: 'http' }], + url: '/api/users', + ...options +}); + +/** + * Add User + * + * Create user endpoint + * + * Args: + * request (Request): Fastapi Requests object + * username (str): User username + * password (str): User password + * email (str): User email + * role (str): RomM Role object represented as string + * + * Returns: + * UserSchema: Newly created user + */ +export const addUserApiUsersPost = (options: Options) => (options.client ?? client).post({ + security: [{ scheme: 'bearer', type: 'http' }, { scheme: 'basic', type: 'http' }], + url: '/api/users', + ...options, + headers: { + 'Content-Type': 'application/json', + ...options.headers + } +}); + +/** + * Create Invite Link + * + * Create an invite link for a user. + * + * Args: + * request (Request): FastAPI Request object + * role (str): The role of the user + * + * Returns: + * InviteLinkSchema: Invite link + */ +export const createInviteLinkApiUsersInviteLinkPost = (options: Options) => (options.client ?? client).post({ + security: [{ scheme: 'bearer', type: 'http' }, { scheme: 'basic', type: 'http' }], + url: '/api/users/invite-link', + ...options +}); + +/** + * Create User From Invite + * + * Create user endpoint with invite link + * + * Args: + * username (str): User username + * email (str): User email + * password (str): User password + * token (str): Invite link token + * + * Returns: + * UserSchema: Newly created user + */ +export const createUserFromInviteApiUsersRegisterPost = (options: Options) => (options.client ?? client).post({ + url: '/api/users/register', + ...options, + headers: { + 'Content-Type': 'application/json', + ...options.headers + } +}); + +/** + * Get Current User + * + * Get current user endpoint + * + * Args: + * request (Request): Fastapi Request object + * + * Returns: + * UserSchema | None: Current user + */ +export const getCurrentUserApiUsersMeGet = (options?: Options) => (options?.client ?? client).get({ + security: [{ scheme: 'bearer', type: 'http' }, { scheme: 'basic', type: 'http' }], + url: '/api/users/me', + ...options +}); + +/** + * Delete User + * + * Delete a user by ID. + * + * Raises: + * HTTPException: User is not found in database + * HTTPException: User deleting itself + * HTTPException: User is the last admin user + */ +export const deleteUserApiUsersIdDelete = (options: Options) => (options.client ?? client).delete({ + security: [{ scheme: 'bearer', type: 'http' }, { scheme: 'basic', type: 'http' }], + url: '/api/users/{id}', + ...options +}); + +/** + * Get User + * + * Get user endpoint + * + * Args: + * request (Request): Fastapi Request object + * + * Returns: + * UserSchem: User stored in the RomM's database + */ +export const getUserApiUsersIdGet = (options: Options) => (options.client ?? client).get({ + security: [{ scheme: 'bearer', type: 'http' }, { scheme: 'basic', type: 'http' }], + url: '/api/users/{id}', + ...options +}); + +/** + * Update User + * + * Update user endpoint + * + * Args: + * request (Request): Fastapi Requests object + * user_id (int): User internal id + * form_data (Annotated[UserUpdateForm, Depends): Form Data with user updated info + * + * Raises: + * HTTPException: User is not found in database + * HTTPException: Username already in use by another user + * + * Returns: + * UserSchema: Updated user info + */ +export const updateUserApiUsersIdPut = (options: Options) => (options.client ?? client).put({ + ...urlSearchParamsBodySerializer, + security: [{ scheme: 'bearer', type: 'http' }, { scheme: 'basic', type: 'http' }], + url: '/api/users/{id}', + ...options, + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', + ...options.headers + } +}); + +/** + * Refresh RetroAchievements + * + * Refresh RetroAchievements progression data for a user. + */ +export const refreshRetroAchievementsApiUsersIdRaRefreshPost = (options: Options) => (options.client ?? client).post({ + security: [{ scheme: 'bearer', type: 'http' }, { scheme: 'basic', type: 'http' }], + url: '/api/users/{id}/ra/refresh', + ...options, + headers: { + 'Content-Type': 'application/json', + ...options.headers + } +}); + +/** + * Get Platforms + * + * Retrieve platforms. + */ +export const getPlatformsApiPlatformsGet = (options?: Options) => (options?.client ?? client).get({ + security: [{ scheme: 'bearer', type: 'http' }, { scheme: 'basic', type: 'http' }], + url: '/api/platforms', + ...options +}); + +/** + * Add Platform + * + * Create a platform. + */ +export const addPlatformApiPlatformsPost = (options: Options) => (options.client ?? client).post({ + security: [{ scheme: 'bearer', type: 'http' }, { scheme: 'basic', type: 'http' }], + url: '/api/platforms', + ...options, + headers: { + 'Content-Type': 'application/json', + ...options.headers + } +}); + +/** + * Get Supported Platforms Endpoint + * + * Retrieve the list of supported platforms. + */ +export const getSupportedPlatformsEndpointApiPlatformsSupportedGet = (options?: Options) => (options?.client ?? client).get({ + security: [{ scheme: 'bearer', type: 'http' }, { scheme: 'basic', type: 'http' }], + url: '/api/platforms/supported', + ...options +}); + +/** + * Delete Platform + * + * Delete a platform by ID. + */ +export const deletePlatformApiPlatformsIdDelete = (options: Options) => (options.client ?? client).delete({ + security: [{ scheme: 'bearer', type: 'http' }, { scheme: 'basic', type: 'http' }], + url: '/api/platforms/{id}', + ...options +}); + +/** + * Get Platform + * + * Retrieve a platform by ID. + */ +export const getPlatformApiPlatformsIdGet = (options: Options) => (options.client ?? client).get({ + security: [{ scheme: 'bearer', type: 'http' }, { scheme: 'basic', type: 'http' }], + url: '/api/platforms/{id}', + ...options +}); + +/** + * Update Platform + * + * Update a platform. + */ +export const updatePlatformApiPlatformsIdPut = (options: Options) => (options.client ?? client).put({ + security: [{ scheme: 'bearer', type: 'http' }, { scheme: 'basic', type: 'http' }], + url: '/api/platforms/{id}', + ...options, + headers: { + 'Content-Type': 'application/json', + ...options.headers + } +}); + +/** + * Get Roms + * + * Retrieve roms. + */ +export const getRomsApiRomsGet = (options?: Options) => (options?.client ?? client).get({ + security: [{ scheme: 'bearer', type: 'http' }, { scheme: 'basic', type: 'http' }], + url: '/api/roms', + ...options +}); + +/** + * Add Rom + * + * Upload a single rom. + */ +export const addRomApiRomsPost = (options: Options) => (options.client ?? client).post({ + security: [{ scheme: 'bearer', type: 'http' }, { scheme: 'basic', type: 'http' }], + url: '/api/roms', + ...options +}); + +/** + * Download Roms + * + * Download a list of roms as a zip file. + */ +export const downloadRomsApiRomsDownloadGet = (options: Options) => (options.client ?? client).get({ + security: [{ scheme: 'bearer', type: 'http' }, { scheme: 'basic', type: 'http' }], + url: '/api/roms/download', + ...options +}); + +/** + * Get Rom By Metadata Provider + * + * Retrieve a rom by metadata ID. + */ +export const getRomByMetadataProviderApiRomsByMetadataProviderGet = (options?: Options) => (options?.client ?? client).get({ + security: [{ scheme: 'bearer', type: 'http' }, { scheme: 'basic', type: 'http' }], + url: '/api/roms/by-metadata-provider', + ...options +}); + +/** + * Get Rom By Hash + */ +export const getRomByHashApiRomsByHashGet = (options?: Options) => (options?.client ?? client).get({ + security: [{ scheme: 'bearer', type: 'http' }, { scheme: 'basic', type: 'http' }], + url: '/api/roms/by-hash', + ...options +}); + +/** + * Get Rom Filters + */ +export const getRomFiltersApiRomsFiltersGet = (options?: Options) => (options?.client ?? client).get({ + security: [{ scheme: 'bearer', type: 'http' }, { scheme: 'basic', type: 'http' }], + url: '/api/roms/filters', + ...options +}); + +/** + * Get Rom + * + * Retrieve a rom by ID. + */ +export const getRomApiRomsIdGet = (options: Options) => (options.client ?? client).get({ + security: [{ scheme: 'bearer', type: 'http' }, { scheme: 'basic', type: 'http' }], + url: '/api/roms/{id}', + ...options +}); + +/** + * Update Rom + * + * Update a rom. + */ +export const updateRomApiRomsIdPut = (options: Options) => (options.client ?? client).put({ + ...formDataBodySerializer, + security: [{ scheme: 'bearer', type: 'http' }, { scheme: 'basic', type: 'http' }], + url: '/api/roms/{id}', + ...options, + headers: { + 'Content-Type': null, + ...options.headers + } +}); + +/** + * Get Rom Content + * + * Download a rom. + * + * This endpoint serves the content of the requested rom, as: + * - A single file for single file roms. + * - A zipped file for multi-part roms, including a .m3u file if applicable. + */ +export const getRomContentApiRomsIdContentFileNameGet = (options: Options) => (options.client ?? client).get({ + security: [{ scheme: 'bearer', type: 'http' }, { scheme: 'basic', type: 'http' }], + url: '/api/roms/{id}/content/{file_name}', + ...options +}); + +/** + * Head Rom Content + * + * Retrieve head information for a rom file download. + */ +export const headRomContentApiRomsIdContentFileNameHead = (options: Options) => (options.client ?? client).head({ + security: [{ scheme: 'bearer', type: 'http' }, { scheme: 'basic', type: 'http' }], + url: '/api/roms/{id}/content/{file_name}', + ...options +}); + +/** + * Delete Rom Manuals + * + * Delete manuals for a rom. + */ +export const deleteRomManualsApiRomsIdManualsDelete = (options: Options) => (options.client ?? client).delete({ + security: [{ scheme: 'bearer', type: 'http' }, { scheme: 'basic', type: 'http' }], + url: '/api/roms/{id}/manuals', + ...options +}); + +/** + * Add Rom Manuals + * + * Upload manuals for a rom. + */ +export const addRomManualsApiRomsIdManualsPost = (options: Options) => (options.client ?? client).post({ + security: [{ scheme: 'bearer', type: 'http' }, { scheme: 'basic', type: 'http' }], + url: '/api/roms/{id}/manuals', + ...options +}); + +/** + * Delete Roms + * + * Delete roms. + */ +export const deleteRomsApiRomsDeletePost = (options: Options) => (options.client ?? client).post({ + security: [{ scheme: 'bearer', type: 'http' }, { scheme: 'basic', type: 'http' }], + url: '/api/roms/delete', + ...options, + headers: { + 'Content-Type': 'application/json', + ...options.headers + } +}); + +/** + * Update Rom User + * + * Update rom data associated to the current user. + */ +export const updateRomUserApiRomsIdPropsPut = (options: Options) => (options.client ?? client).put({ + security: [{ scheme: 'bearer', type: 'http' }, { scheme: 'basic', type: 'http' }], + url: '/api/roms/{id}/props', + ...options, + headers: { + 'Content-Type': 'application/json', + ...options.headers + } +}); + +/** + * Get Romfile + * + * Retrieve a rom file by ID. + */ +export const getRomfileApiRomsFilesIdGet = (options: Options) => (options.client ?? client).get({ + security: [{ scheme: 'bearer', type: 'http' }, { scheme: 'basic', type: 'http' }], + url: '/api/roms/files/{id}', + ...options +}); + +/** + * Get Romfile Content + * + * Download a rom file. + */ +export const getRomfileContentApiRomsfilesIdContentFileNameGet = (options: Options) => (options.client ?? client).get({ + security: [{ scheme: 'bearer', type: 'http' }, { scheme: 'basic', type: 'http' }], + url: '/api/romsfiles/{id}/content/{file_name}', + ...options +}); + +/** + * Get Rom Notes + * + * Get all notes for a ROM. + */ +export const getRomNotesApiRomsIdNotesGet = (options: Options) => (options.client ?? client).get({ + security: [{ scheme: 'bearer', type: 'http' }, { scheme: 'basic', type: 'http' }], + url: '/api/roms/{id}/notes', + ...options +}); + +/** + * Create Rom Note + * + * Create a new note for a ROM. + */ +export const createRomNoteApiRomsIdNotesPost = (options: Options) => (options.client ?? client).post({ + security: [{ scheme: 'bearer', type: 'http' }, { scheme: 'basic', type: 'http' }], + url: '/api/roms/{id}/notes', + ...options, + headers: { + 'Content-Type': 'application/json', + ...options.headers + } +}); + +/** + * Delete Rom Note + * + * Delete a ROM note. + */ +export const deleteRomNoteApiRomsIdNotesNoteIdDelete = (options: Options) => (options.client ?? client).delete({ + security: [{ scheme: 'bearer', type: 'http' }, { scheme: 'basic', type: 'http' }], + url: '/api/roms/{id}/notes/{note_id}', + ...options +}); + +/** + * Update Rom Note + * + * Update a ROM note. + */ +export const updateRomNoteApiRomsIdNotesNoteIdPut = (options: Options) => (options.client ?? client).put({ + security: [{ scheme: 'bearer', type: 'http' }, { scheme: 'basic', type: 'http' }], + url: '/api/roms/{id}/notes/{note_id}', + ...options, + headers: { + 'Content-Type': 'application/json', + ...options.headers + } +}); + +/** + * Search Rom + * + * Search for rom in metadata providers + * + * Args: + * request (Request): FastAPI request + * rom_id (int): Rom ID + * source (str): Source of the rom + * search_term (str, optional): Search term. Defaults to None. + * search_by (str, optional): Search by name or ID. Defaults to "name". + * search_extended (bool, optional): Search extended info. Defaults to False. + * + * Returns: + * list[SearchRomSchema]: List of matched roms + */ +export const searchRomApiSearchRomsGet = (options: Options) => (options.client ?? client).get({ + security: [{ scheme: 'bearer', type: 'http' }, { scheme: 'basic', type: 'http' }], + url: '/api/search/roms', + ...options +}); + +/** + * Search Cover + */ +export const searchCoverApiSearchCoverGet = (options?: Options) => (options?.client ?? client).get({ + security: [{ scheme: 'bearer', type: 'http' }, { scheme: 'basic', type: 'http' }], + url: '/api/search/cover', + ...options +}); + +/** + * Get Saves + */ +export const getSavesApiSavesGet = (options?: Options) => (options?.client ?? client).get({ + security: [{ scheme: 'bearer', type: 'http' }, { scheme: 'basic', type: 'http' }], + url: '/api/saves', + ...options +}); + +/** + * Add Save + */ +export const addSaveApiSavesPost = (options: Options) => (options.client ?? client).post({ + security: [{ scheme: 'bearer', type: 'http' }, { scheme: 'basic', type: 'http' }], + url: '/api/saves', + ...options +}); + +/** + * Get Save + */ +export const getSaveApiSavesIdGet = (options: Options) => (options.client ?? client).get({ + security: [{ scheme: 'bearer', type: 'http' }, { scheme: 'basic', type: 'http' }], + url: '/api/saves/{id}', + ...options +}); + +/** + * Update Save + */ +export const updateSaveApiSavesIdPut = (options: Options) => (options.client ?? client).put({ + security: [{ scheme: 'bearer', type: 'http' }, { scheme: 'basic', type: 'http' }], + url: '/api/saves/{id}', + ...options +}); + +/** + * Delete Saves + * + * Delete saves. + */ +export const deleteSavesApiSavesDeletePost = (options: Options) => (options.client ?? client).post({ + security: [{ scheme: 'bearer', type: 'http' }, { scheme: 'basic', type: 'http' }], + url: '/api/saves/delete', + ...options, + headers: { + 'Content-Type': 'application/json', + ...options.headers + } +}); + +/** + * Get States + */ +export const getStatesApiStatesGet = (options?: Options) => (options?.client ?? client).get({ + security: [{ scheme: 'bearer', type: 'http' }, { scheme: 'basic', type: 'http' }], + url: '/api/states', + ...options +}); + +/** + * Add State + */ +export const addStateApiStatesPost = (options: Options) => (options.client ?? client).post({ + security: [{ scheme: 'bearer', type: 'http' }, { scheme: 'basic', type: 'http' }], + url: '/api/states', + ...options +}); + +/** + * Get State + */ +export const getStateApiStatesIdGet = (options: Options) => (options.client ?? client).get({ + security: [{ scheme: 'bearer', type: 'http' }, { scheme: 'basic', type: 'http' }], + url: '/api/states/{id}', + ...options +}); + +/** + * Update State + */ +export const updateStateApiStatesIdPut = (options: Options) => (options.client ?? client).put({ + security: [{ scheme: 'bearer', type: 'http' }, { scheme: 'basic', type: 'http' }], + url: '/api/states/{id}', + ...options +}); + +/** + * Delete States + * + * Delete states. + */ +export const deleteStatesApiStatesDeletePost = (options: Options) => (options.client ?? client).post({ + security: [{ scheme: 'bearer', type: 'http' }, { scheme: 'basic', type: 'http' }], + url: '/api/states/delete', + ...options, + headers: { + 'Content-Type': 'application/json', + ...options.headers + } +}); + +/** + * List Tasks + * + * List all available tasks grouped by task type. + * + * Args: + * request (Request): FastAPI Request object + * Returns: + * GroupedTasksDict: Dictionary with tasks grouped by their type (scheduled, manual, watcher) + */ +export const listTasksApiTasksGet = (options?: Options) => (options?.client ?? client).get({ + security: [{ scheme: 'bearer', type: 'http' }, { scheme: 'basic', type: 'http' }], + url: '/api/tasks', + ...options +}); + +/** + * Get Tasks Status + * + * Get all active, queued, completed, and failed tasks. + * + * Args: + * request (Request): FastAPI Request object + * Returns: + * list[TaskStatusResponse]: List of all tasks with their current status + */ +export const getTasksStatusApiTasksStatusGet = (options?: Options) => (options?.client ?? client).get({ + security: [{ scheme: 'bearer', type: 'http' }, { scheme: 'basic', type: 'http' }], + url: '/api/tasks/status', + ...options +}); + +/** + * Get Task By Id + * + * Get the status of a task by its job ID. + * + * Args: + * request (Request): FastAPI Request object + * task_id (str): Job ID of the task to retrieve status for + * Returns: + * TaskStatusResponse: Task status information + */ +export const getTaskByIdApiTasksTaskIdGet = (options: Options) => (options.client ?? client).get({ + security: [{ scheme: 'bearer', type: 'http' }, { scheme: 'basic', type: 'http' }], + url: '/api/tasks/{task_id}', + ...options +}); + +/** + * Run All Tasks + * + * Run all runnable tasks endpoint + * + * Args: + * request (Request): FastAPI Request object + * Returns: + * TaskExecutionResponse: Task execution response with details + */ +export const runAllTasksApiTasksRunPost = (options?: Options) => (options?.client ?? client).post({ + security: [{ scheme: 'bearer', type: 'http' }, { scheme: 'basic', type: 'http' }], + url: '/api/tasks/run', + ...options +}); + +/** + * Run Single Task + * + * Run a single task endpoint. + * + * Args: + * request (Request): FastAPI Request object + * task_name (str): Name of the task to run + * Returns: + * TaskExecutionResponse: Task execution response with details + */ +export const runSingleTaskApiTasksRunTaskNamePost = (options: Options) => (options.client ?? client).post({ + security: [{ scheme: 'bearer', type: 'http' }, { scheme: 'basic', type: 'http' }], + url: '/api/tasks/run/{task_name}', + ...options +}); + +/** + * Platforms Webrcade Feed + * + * Get webrcade feed endpoint + * https://docs.webrcade.com/feeds/format/ + * + * Args: + * request (Request): Fastapi Request object + * + * Returns: + * WebrcadeFeedSchema: Webrcade feed object schema + */ +export const platformsWebrcadeFeedApiFeedsWebrcadeGet = (options?: Options) => (options?.client ?? client).get({ + security: [{ scheme: 'bearer', type: 'http' }, { scheme: 'basic', type: 'http' }], + url: '/api/feeds/webrcade', + ...options +}); + +/** + * Tinfoil Index Feed + * + * Get tinfoil custom index feed endpoint + * https://blawar.github.io/tinfoil/custom_index/ + * + * Args: + * request (Request): Fastapi Request object + * slug (str, optional): Platform slug. Defaults to "switch". + * + * Returns: + * TinfoilFeedSchema: Tinfoil feed object schema + */ +export const tinfoilIndexFeedApiFeedsTinfoilGet = (options?: Options) => (options?.client ?? client).get({ + security: [{ scheme: 'bearer', type: 'http' }, { scheme: 'basic', type: 'http' }], + url: '/api/feeds/tinfoil', + ...options +}); + +/** + * Pkgi Ps3 Feed + * + * Get PKGi PS3 feed endpoint + * https://github.com/bucanero/pkgi-ps3 + * + * Args: + * request (Request): Fastapi Request object + * content_type (str): Content type (game, dlc, demo, update, patch, mod, translation, prototype) + * + * Returns: + * Response: txt file with PKGi PS3 database format + */ +export const pkgiPs3FeedApiFeedsPkgiPs3ContentTypeGet = (options: Options) => (options.client ?? client).get({ + security: [{ scheme: 'bearer', type: 'http' }, { scheme: 'basic', type: 'http' }], + url: '/api/feeds/pkgi/ps3/{content_type}', + ...options +}); + +/** + * Pkgi Psvita Feed + * + * Get PKGi PS Vita feed endpoint + * https://github.com/mmozeiko/pkgi + * + * Args: + * request (Request): Fastapi Request object + * content_type (str): Content type (game, dlc, demo, update, patch, mod, translation, prototype) + * + * Returns: + * Response: txt file with PKGi PS Vita database format + */ +export const pkgiPsvitaFeedApiFeedsPkgiPsvitaContentTypeGet = (options: Options) => (options.client ?? client).get({ + security: [{ scheme: 'bearer', type: 'http' }, { scheme: 'basic', type: 'http' }], + url: '/api/feeds/pkgi/psvita/{content_type}', + ...options +}); + +/** + * Pkgi Psp Feed + * + * Get PKGi PSP feed endpoint + * https://github.com/bucanero/pkgi-psp + * + * Args: + * request (Request): Fastapi Request object + * content_type (str): Content type (game, dlc, demo, update, patch, mod, translation, prototype) + * + * Returns: + * Response: txt file with PKGi PSP database format + */ +export const pkgiPspFeedApiFeedsPkgiPspContentTypeGet = (options: Options) => (options.client ?? client).get({ + security: [{ scheme: 'bearer', type: 'http' }, { scheme: 'basic', type: 'http' }], + url: '/api/feeds/pkgi/psp/{content_type}', + ...options +}); + +/** + * Fpkgi Feed + * + * https://github.com/ItsJokerZz/FPKGi + * + * Args: + * request (Request): Fastapi Request object + * platform_slug (str): Platform slug (ps4, ps5) + * + * Returns: + * Response: JSON file in FPKGi format + */ +export const fpkgiFeedApiFeedsFpkgiPlatformSlugGet = (options: Options) => (options.client ?? client).get({ + security: [{ scheme: 'bearer', type: 'http' }, { scheme: 'basic', type: 'http' }], + url: '/api/feeds/fpkgi/{platform_slug}', + ...options +}); + +/** + * Kekatsu Ds Feed + * + * Get Kekatsu DS feed endpoint + * https://github.com/cavv-dev/Kekatsu-DS + * + * Args: + * request (Request): Fastapi Request object + * platform_slug (str): Platform slug (nds, nintendo-ds, ds, gba, etc.) + * + * Returns: + * Response: Text file with Kekatsu DS database format + */ +export const kekatsuDsFeedApiFeedsKekatsuPlatformSlugGet = (options: Options) => (options.client ?? client).get({ + security: [{ scheme: 'bearer', type: 'http' }, { scheme: 'basic', type: 'http' }], + url: '/api/feeds/kekatsu/{platform_slug}', + ...options +}); + +/** + * Get Config + * + * Get config endpoint + * + * Returns: + * ConfigResponse: RomM's configuration + */ +export const getConfigApiConfigGet = (options?: Options) => (options?.client ?? client).get({ url: '/api/config', ...options }); + +/** + * Add Platform Binding + * + * Add platform binding to the configuration + */ +export const addPlatformBindingApiConfigSystemPlatformsPost = (options?: Options) => (options?.client ?? client).post({ + security: [{ scheme: 'bearer', type: 'http' }, { scheme: 'basic', type: 'http' }], + url: '/api/config/system/platforms', + ...options +}); + +/** + * Delete Platform Binding + * + * Delete platform binding from the configuration + */ +export const deletePlatformBindingApiConfigSystemPlatformsFsSlugDelete = (options: Options) => (options.client ?? client).delete({ + security: [{ scheme: 'bearer', type: 'http' }, { scheme: 'basic', type: 'http' }], + url: '/api/config/system/platforms/{fs_slug}', + ...options +}); + +/** + * Add Platform Version + * + * Add platform version to the configuration + */ +export const addPlatformVersionApiConfigSystemVersionsPost = (options?: Options) => (options?.client ?? client).post({ + security: [{ scheme: 'bearer', type: 'http' }, { scheme: 'basic', type: 'http' }], + url: '/api/config/system/versions', + ...options +}); + +/** + * Delete Platform Version + * + * Delete platform version from the configuration + */ +export const deletePlatformVersionApiConfigSystemVersionsFsSlugDelete = (options: Options) => (options.client ?? client).delete({ + security: [{ scheme: 'bearer', type: 'http' }, { scheme: 'basic', type: 'http' }], + url: '/api/config/system/versions/{fs_slug}', + ...options +}); + +/** + * Add Exclusion + * + * Add platform exclusion to the configuration + */ +export const addExclusionApiConfigExcludePost = (options?: Options) => (options?.client ?? client).post({ + security: [{ scheme: 'bearer', type: 'http' }, { scheme: 'basic', type: 'http' }], + url: '/api/config/exclude', + ...options +}); + +/** + * Delete Exclusion + * + * Delete platform binding from the configuration + */ +export const deleteExclusionApiConfigExcludeExclusionTypeExclusionValueDelete = (options: Options) => (options.client ?? client).delete({ + security: [{ scheme: 'bearer', type: 'http' }, { scheme: 'basic', type: 'http' }], + url: '/api/config/exclude/{exclusion_type}/{exclusion_value}', + ...options +}); + +/** + * Stats + * + * Endpoint to return the current RomM stats + * + * Returns: + * dict: Dictionary with all the stats + */ +export const statsApiStatsGet = (options?: Options) => (options?.client ?? client).get({ url: '/api/stats', ...options }); + +/** + * Get Raw Asset + * + * Download a single asset file + * + * Args: + * request (Request): Fastapi Request object + * path (str): Relative path to the asset file + * + * Returns: + * FileResponse: Returns a single asset file + * + * Raises: + * HTTPException: 404 if asset not found or access denied + */ +export const getRawAssetApiRawAssetsPathGet = (options: Options) => (options.client ?? client).get({ + security: [{ scheme: 'bearer', type: 'http' }, { scheme: 'basic', type: 'http' }], + url: '/api/raw/assets/{path}', + ...options +}); + +/** + * Head Raw Asset + */ +export const headRawAssetApiRawAssetsPathHead = (options: Options) => (options.client ?? client).head({ + security: [{ scheme: 'bearer', type: 'http' }, { scheme: 'basic', type: 'http' }], + url: '/api/raw/assets/{path}', + ...options +}); + +/** + * Add Screenshot + */ +export const addScreenshotApiScreenshotsPost = (options: Options) => (options.client ?? client).post({ + security: [{ scheme: 'bearer', type: 'http' }, { scheme: 'basic', type: 'http' }], + url: '/api/screenshots', + ...options +}); + +/** + * Get Platform Firmware + * + * Get firmware endpoint + * + * Args: + * request (Request): Fastapi Request object + * + * Returns: + * list[FirmwareSchema]: Firmware stored in the database + */ +export const getPlatformFirmwareApiFirmwareGet = (options?: Options) => (options?.client ?? client).get({ + security: [{ scheme: 'bearer', type: 'http' }, { scheme: 'basic', type: 'http' }], + url: '/api/firmware', + ...options +}); + +/** + * Add Firmware + * + * Upload firmware files endpoint + * + * Args: + * request (Request): Fastapi Request object + * platform_slug (str): Slug of the platform where to upload the files + * files (list[UploadFile], optional): List of files to upload + * + * Raises: + * HTTPException + * + * Returns: + * AddFirmwareResponse: Standard message response + */ +export const addFirmwareApiFirmwarePost = (options: Options) => (options.client ?? client).post({ + ...formDataBodySerializer, + security: [{ scheme: 'bearer', type: 'http' }, { scheme: 'basic', type: 'http' }], + url: '/api/firmware', + ...options, + headers: { + 'Content-Type': null, + ...options.headers + } +}); + +/** + * Get Firmware + * + * Get firmware endpoint + * + * Args: + * request (Request): Fastapi Request object + * id (int): Firmware internal id + * + * Returns: + * FirmwareSchema: Firmware stored in the database + */ +export const getFirmwareApiFirmwareIdGet = (options: Options) => (options.client ?? client).get({ + security: [{ scheme: 'bearer', type: 'http' }, { scheme: 'basic', type: 'http' }], + url: '/api/firmware/{id}', + ...options +}); + +/** + * Get Firmware Content + * + * Download firmware endpoint + * + * Args: + * request (Request): Fastapi Request object + * id (int): Rom internal id + * file_name (str): Required due to a bug in emulatorjs + * + * Returns: + * FileResponse: Returns the firmware file + */ +export const getFirmwareContentApiFirmwareIdContentFileNameGet = (options: Options) => (options.client ?? client).get({ + security: [{ scheme: 'bearer', type: 'http' }, { scheme: 'basic', type: 'http' }], + url: '/api/firmware/{id}/content/{file_name}', + ...options +}); + +/** + * Head Firmware Content + * + * Head firmware content endpoint + * + * Args: + * request (Request): Fastapi Request object + * id (int): Rom internal id + * file_name (str): Required due to a bug in emulatorjs + * + * Returns: + * FileResponse: Returns the response with headers + */ +export const headFirmwareContentApiFirmwareIdContentFileNameHead = (options: Options) => (options.client ?? client).head({ + security: [{ scheme: 'bearer', type: 'http' }, { scheme: 'basic', type: 'http' }], + url: '/api/firmware/{id}/content/{file_name}', + ...options +}); + +/** + * Delete Firmware + * + * Delete firmware. + */ +export const deleteFirmwareApiFirmwareDeletePost = (options: Options) => (options.client ?? client).post({ + security: [{ scheme: 'bearer', type: 'http' }, { scheme: 'basic', type: 'http' }], + url: '/api/firmware/delete', + ...options, + headers: { + 'Content-Type': 'application/json', + ...options.headers + } +}); + +/** + * Get Collections + * + * Get collections endpoint + * + * Args: + * request (Request): Fastapi Request object + * updated_after: Filter collections updated after this datetime + * + * Returns: + * list[CollectionSchema]: List of collections + */ +export const getCollectionsApiCollectionsGet = (options?: Options) => (options?.client ?? client).get({ + security: [{ scheme: 'bearer', type: 'http' }, { scheme: 'basic', type: 'http' }], + url: '/api/collections', + ...options +}); + +/** + * Add Collection + * + * Create collection endpoint + * + * Args: + * request (Request): Fastapi Request object + * + * Returns: + * CollectionSchema: Just created collection + */ +export const addCollectionApiCollectionsPost = (options?: Options) => (options?.client ?? client).post({ + ...formDataBodySerializer, + security: [{ scheme: 'bearer', type: 'http' }, { scheme: 'basic', type: 'http' }], + url: '/api/collections', + ...options, + headers: { + 'Content-Type': null, + ...options?.headers + } +}); + +/** + * Get Smart Collections + * + * Get smart collections endpoint + * + * Args: + * request (Request): Fastapi Request object + * updated_after: Filter smart collections updated after this datetime + * + * Returns: + * list[SmartCollectionSchema]: List of smart collections + */ +export const getSmartCollectionsApiCollectionsSmartGet = (options?: Options) => (options?.client ?? client).get({ + security: [{ scheme: 'bearer', type: 'http' }, { scheme: 'basic', type: 'http' }], + url: '/api/collections/smart', + ...options +}); + +/** + * Add Smart Collection + * + * Create smart collection endpoint + * + * Args: + * request (Request): Fastapi Request object + * + * Returns: + * SmartCollectionSchema: Just created smart collection + */ +export const addSmartCollectionApiCollectionsSmartPost = (options?: Options) => (options?.client ?? client).post({ + security: [{ scheme: 'bearer', type: 'http' }, { scheme: 'basic', type: 'http' }], + url: '/api/collections/smart', + ...options +}); + +/** + * Get Virtual Collections + * + * Get virtual collections endpoint + * + * Args: + * request (Request): Fastapi Request object + * + * Returns: + * list[VirtualCollectionSchema]: List of virtual collections + */ +export const getVirtualCollectionsApiCollectionsVirtualGet = (options: Options) => (options.client ?? client).get({ + security: [{ scheme: 'bearer', type: 'http' }, { scheme: 'basic', type: 'http' }], + url: '/api/collections/virtual', + ...options +}); + +/** + * Delete Collection + * + * Delete a collection by ID. + */ +export const deleteCollectionApiCollectionsIdDelete = (options: Options) => (options.client ?? client).delete({ + security: [{ scheme: 'bearer', type: 'http' }, { scheme: 'basic', type: 'http' }], + url: '/api/collections/{id}', + ...options +}); + +/** + * Get Collection + * + * Get collections endpoint + * + * Args: + * request (Request): Fastapi Request object + * id (int, optional): Collection id. Defaults to None. + * + * Returns: + * CollectionSchema: Collection + */ +export const getCollectionApiCollectionsIdGet = (options: Options) => (options.client ?? client).get({ + security: [{ scheme: 'bearer', type: 'http' }, { scheme: 'basic', type: 'http' }], + url: '/api/collections/{id}', + ...options +}); + +/** + * Update Collection + * + * Update collection endpoint + * + * Args: + * request (Request): Fastapi Request object + * + * Returns: + * CollectionSchema: Updated collection + */ +export const updateCollectionApiCollectionsIdPut = (options: Options) => (options.client ?? client).put({ + ...formDataBodySerializer, + security: [{ scheme: 'bearer', type: 'http' }, { scheme: 'basic', type: 'http' }], + url: '/api/collections/{id}', + ...options, + headers: { + 'Content-Type': null, + ...options.headers + } +}); + +/** + * Get Virtual Collection + * + * Get virtual collections endpoint + * + * Args: + * request (Request): Fastapi Request object + * id (str): Virtual collection id + * + * Returns: + * VirtualCollectionSchema: Virtual collection + */ +export const getVirtualCollectionApiCollectionsVirtualIdGet = (options: Options) => (options.client ?? client).get({ + security: [{ scheme: 'bearer', type: 'http' }, { scheme: 'basic', type: 'http' }], + url: '/api/collections/virtual/{id}', + ...options +}); + +/** + * Delete Smart Collection + * + * Delete a smart collection by ID. + */ +export const deleteSmartCollectionApiCollectionsSmartIdDelete = (options: Options) => (options.client ?? client).delete({ + security: [{ scheme: 'bearer', type: 'http' }, { scheme: 'basic', type: 'http' }], + url: '/api/collections/smart/{id}', + ...options +}); + +/** + * Get Smart Collection + * + * Get smart collection endpoint + * + * Args: + * request (Request): Fastapi Request object + * id (int): Smart collection id + * + * Returns: + * SmartCollectionSchema: Smart collection + */ +export const getSmartCollectionApiCollectionsSmartIdGet = (options: Options) => (options.client ?? client).get({ + security: [{ scheme: 'bearer', type: 'http' }, { scheme: 'basic', type: 'http' }], + url: '/api/collections/smart/{id}', + ...options +}); + +/** + * Update Smart Collection + * + * Update smart collection endpoint + * + * Args: + * request (Request): Fastapi Request object + * id (int): Smart collection id + * + * Returns: + * SmartCollectionSchema: Updated smart collection + */ +export const updateSmartCollectionApiCollectionsSmartIdPut = (options: Options) => (options.client ?? client).put({ + security: [{ scheme: 'bearer', type: 'http' }, { scheme: 'basic', type: 'http' }], + url: '/api/collections/smart/{id}', + ...options +}); + +/** + * Export Gamelist + * + * Export platforms/ROMs to gamelist.xml format and write to platform directories + */ +export const exportGamelistApiGamelistExportPost = (options: Options) => (options.client ?? client).post({ + security: [{ scheme: 'bearer', type: 'http' }, { scheme: 'basic', type: 'http' }], + url: '/api/gamelist/export', + ...options +}); + +/** + * Get Rooms + */ +export const getRoomsApiNetplayListGet = (options: Options) => (options.client ?? client).get({ + security: [{ scheme: 'bearer', type: 'http' }, { scheme: 'basic', type: 'http' }], + url: '/api/netplay/list', + ...options +}); diff --git a/src/clients/romm/types.gen.ts b/src/clients/romm/types.gen.ts new file mode 100644 index 0000000..cdd61b4 --- /dev/null +++ b/src/clients/romm/types.gen.ts @@ -0,0 +1,7936 @@ +// This file is auto-generated by @hey-api/openapi-ts + +export type ClientOptions = { + baseUrl: `${string}://${string}` | (string & {}); +}; + +/** + * AddFirmwareResponse + */ +export type AddFirmwareResponse = { + /** + * Uploaded + */ + uploaded: number; + /** + * Firmware + */ + firmware: Array; +}; + +/** + * Body_add_collection_api_collections_post + */ +export type BodyAddCollectionApiCollectionsPost = { + /** + * Artwork + */ + artwork?: Blob | File | null; +}; + +/** + * Body_add_firmware_api_firmware_post + */ +export type BodyAddFirmwareApiFirmwarePost = { + /** + * Files + */ + files: Array; +}; + +/** + * Body_add_platform_api_platforms_post + */ +export type BodyAddPlatformApiPlatformsPost = { + /** + * Fs Slug + * + * Platform slug. + */ + fs_slug: string; +}; + +/** + * Body_add_user_api_users_post + */ +export type BodyAddUserApiUsersPost = { + /** + * Username + */ + username: string; + /** + * Email + */ + email: string; + /** + * Password + */ + password: string; + /** + * Role + */ + role: string; +}; + +/** + * Body_create_user_from_invite_api_users_register_post + */ +export type BodyCreateUserFromInviteApiUsersRegisterPost = { + /** + * Username + */ + username: string; + /** + * Email + */ + email: string; + /** + * Password + */ + password: string; + /** + * Token + */ + token: string; +}; + +/** + * Body_delete_firmware_api_firmware_delete_post + */ +export type BodyDeleteFirmwareApiFirmwareDeletePost = { + /** + * Firmware + * + * List of firmware ids to delete from database. + */ + firmware: Array; + /** + * Delete From Fs + * + * List of firmware ids to delete from filesystem. + */ + delete_from_fs?: Array; +}; + +/** + * Body_delete_roms_api_roms_delete_post + */ +export type BodyDeleteRomsApiRomsDeletePost = { + /** + * Roms + * + * List of rom ids to delete from database. + */ + roms: Array; + /** + * Delete From Fs + * + * List of rom ids to delete from filesystem. + */ + delete_from_fs?: Array; +}; + +/** + * Body_delete_saves_api_saves_delete_post + */ +export type BodyDeleteSavesApiSavesDeletePost = { + /** + * Saves + * + * List of save ids to delete from database. + */ + saves: Array; +}; + +/** + * Body_delete_states_api_states_delete_post + */ +export type BodyDeleteStatesApiStatesDeletePost = { + /** + * States + * + * List of states ids to delete from database. + */ + states: Array; +}; + +/** + * Body_refresh_retro_achievements_api_users__id__ra_refresh_post + */ +export type BodyRefreshRetroAchievementsApiUsersIdRaRefreshPost = { + /** + * Incremental + * + * Whether to only retrieve RetroAchievements progression incrementally. + */ + incremental?: boolean; +}; + +/** + * Body_request_password_reset_api_forgot_password_post + */ +export type BodyRequestPasswordResetApiForgotPasswordPost = { + /** + * Username + */ + username: string; +}; + +/** + * Body_reset_password_api_reset_password_post + */ +export type BodyResetPasswordApiResetPasswordPost = { + /** + * Token + */ + token: string; + /** + * New Password + */ + new_password: string; +}; + +/** + * Body_token_api_token_post + */ +export type BodyTokenApiTokenPost = { + /** + * Grant Type + */ + grant_type?: string; + /** + * Scope + */ + scope?: string; + /** + * Username + */ + username?: string | null; + /** + * Password + */ + password?: string | null; + /** + * Client Id + */ + client_id?: string | null; + /** + * Client Secret + */ + client_secret?: string | null; + /** + * Refresh Token + */ + refresh_token?: string | null; +}; + +/** + * Body_update_collection_api_collections__id__put + */ +export type BodyUpdateCollectionApiCollectionsIdPut = { + /** + * Artwork + */ + artwork?: Blob | File | null; +}; + +/** + * Body_update_platform_api_platforms__id__put + */ +export type BodyUpdatePlatformApiPlatformsIdPut = { + /** + * Aspect Ratio + * + * Cover aspect ratio. + */ + aspect_ratio?: string | null; + /** + * Custom Name + * + * Custom platform name. + */ + custom_name?: string | null; +}; + +/** + * Body_update_rom_api_roms__id__put + */ +export type BodyUpdateRomApiRomsIdPut = { + /** + * Artwork + * + * Custom artwork to set as cover. + */ + artwork?: Blob | File | null; +}; + +/** + * Body_update_rom_user_api_roms__id__props_put + */ +export type BodyUpdateRomUserApiRomsIdPropsPut = { + /** + * Update Last Played + * + * Whether to update the last played date. + */ + update_last_played?: boolean; + /** + * Remove Last Played + * + * Whether to remove the last played date. + */ + remove_last_played?: boolean; +}; + +/** + * BulkOperationResponse + */ +export type BulkOperationResponse = { + /** + * Successful Items + */ + successful_items: number; + /** + * Failed Items + */ + failed_items: number; + /** + * Errors + */ + errors: Array; +}; + +/** + * CleanupStats + */ +export type CleanupStats = { + /** + * Platforms In Db + */ + platforms_in_db: number; + /** + * Roms In Db + */ + roms_in_db: number; + /** + * Platforms In Fs + */ + platforms_in_fs: number; + /** + * Roms In Fs + */ + roms_in_fs: number; + /** + * Removed Fs Platforms + */ + removed_fs_platforms: number; + /** + * Removed Fs Roms + */ + removed_fs_roms: number; +}; + +/** + * CleanupTaskMeta + */ +export type CleanupTaskMeta = { + cleanup_stats: CleanupStats | null; +}; + +/** + * CleanupTaskStatusResponse + */ +export type CleanupTaskStatusResponse = { + /** + * Task Name + */ + task_name: string; + /** + * Task Id + */ + task_id: string; + status: JobStatus; + /** + * Created At + */ + created_at: string | null; + /** + * Enqueued At + */ + enqueued_at: string | null; + /** + * Started At + */ + started_at: string | null; + /** + * Ended At + */ + ended_at: string | null; + /** + * Task Type + */ + task_type: 'cleanup'; + meta: CleanupTaskMeta; +}; + +/** + * CollectionSchema + */ +export type CollectionSchema = { + /** + * Name + */ + name: string; + /** + * Description + */ + description: string; + /** + * Rom Ids + */ + rom_ids: Array; + /** + * Rom Count + */ + rom_count: number; + /** + * Path Cover Small + */ + path_cover_small: string | null; + /** + * Path Cover Large + */ + path_cover_large: string | null; + /** + * Path Covers Small + */ + path_covers_small: Array; + /** + * Path Covers Large + */ + path_covers_large: Array; + /** + * Is Public + */ + is_public?: boolean; + /** + * Is Favorite + */ + is_favorite?: boolean; + /** + * Is Virtual + */ + is_virtual?: boolean; + /** + * Is Smart + */ + is_smart?: boolean; + /** + * Created At + */ + created_at: string; + /** + * Updated At + */ + updated_at: string; + /** + * Id + */ + id: number; + /** + * Url Cover + */ + url_cover: string | null; + /** + * User Id + */ + user_id: number; + /** + * User Username + */ + user__username: string; +}; + +/** + * ConfigResponse + */ +export type ConfigResponse = { + /** + * Config File Mounted + */ + CONFIG_FILE_MOUNTED: boolean; + /** + * Config File Writable + */ + CONFIG_FILE_WRITABLE: boolean; + /** + * Excluded Platforms + */ + EXCLUDED_PLATFORMS: Array; + /** + * Excluded Single Ext + */ + EXCLUDED_SINGLE_EXT: Array; + /** + * Excluded Single Files + */ + EXCLUDED_SINGLE_FILES: Array; + /** + * Excluded Multi Files + */ + EXCLUDED_MULTI_FILES: Array; + /** + * Excluded Multi Parts Ext + */ + EXCLUDED_MULTI_PARTS_EXT: Array; + /** + * Excluded Multi Parts Files + */ + EXCLUDED_MULTI_PARTS_FILES: Array; + /** + * Platforms Binding + */ + PLATFORMS_BINDING: { + [key: string]: string; + }; + /** + * Platforms Versions + */ + PLATFORMS_VERSIONS: { + [key: string]: string; + }; + /** + * Skip Hash Calculation + */ + SKIP_HASH_CALCULATION: boolean; + /** + * Ejs Debug + */ + EJS_DEBUG: boolean; + /** + * Ejs Cache Limit + */ + EJS_CACHE_LIMIT: number | null; + /** + * Ejs Disable Auto Unload + */ + EJS_DISABLE_AUTO_UNLOAD: boolean; + /** + * Ejs Disable Batch Bootup + */ + EJS_DISABLE_BATCH_BOOTUP: boolean; + /** + * Ejs Netplay Enabled + */ + EJS_NETPLAY_ENABLED: boolean; + /** + * Ejs Netplay Ice Servers + */ + EJS_NETPLAY_ICE_SERVERS: Array; + /** + * Ejs Settings + */ + EJS_SETTINGS: { + [key: string]: { + [key: string]: string; + }; + }; + /** + * Ejs Controls + */ + EJS_CONTROLS: { + [key: string]: EjsControls; + }; + /** + * Scan Metadata Priority + */ + SCAN_METADATA_PRIORITY: Array; + /** + * Scan Artwork Priority + */ + SCAN_ARTWORK_PRIORITY: Array; + /** + * Scan Region Priority + */ + SCAN_REGION_PRIORITY: Array; + /** + * Scan Language Priority + */ + SCAN_LANGUAGE_PRIORITY: Array; + /** + * Scan Media + */ + SCAN_MEDIA: Array; +}; + +/** + * ConversionStats + */ +export type ConversionStats = { + /** + * Processed + */ + processed: number; + /** + * Errors + */ + errors: number; + /** + * Total + */ + total: number; +}; + +/** + * ConversionTaskMeta + */ +export type ConversionTaskMeta = { + conversion_stats: ConversionStats | null; +}; + +/** + * ConversionTaskStatusResponse + */ +export type ConversionTaskStatusResponse = { + /** + * Task Name + */ + task_name: string; + /** + * Task Id + */ + task_id: string; + status: JobStatus; + /** + * Created At + */ + created_at: string | null; + /** + * Enqueued At + */ + enqueued_at: string | null; + /** + * Started At + */ + started_at: string | null; + /** + * Ended At + */ + ended_at: string | null; + /** + * Task Type + */ + task_type: 'conversion'; + meta: ConversionTaskMeta; +}; + +/** + * CustomLimitOffsetPage[SimpleRomSchema] + */ +export type CustomLimitOffsetPageSimpleRomSchema = { + /** + * Items + */ + items: Array; + /** + * Total + */ + total: number; + /** + * Limit + */ + limit: number; + /** + * Offset + */ + offset: number; + /** + * Char Index + */ + char_index: { + [key: string]: number; + }; + /** + * Rom Id Index + */ + rom_id_index: Array; + filter_values: RomFiltersDict; +}; + +/** + * DetailedRomSchema + */ +export type DetailedRomSchema = { + /** + * Id + */ + id: number; + /** + * Igdb Id + */ + igdb_id: number | null; + /** + * Sgdb Id + */ + sgdb_id: number | null; + /** + * Moby Id + */ + moby_id: number | null; + /** + * Ss Id + */ + ss_id: number | null; + /** + * Ra Id + */ + ra_id: number | null; + /** + * Launchbox Id + */ + launchbox_id: number | null; + /** + * Hasheous Id + */ + hasheous_id: number | null; + /** + * Tgdb Id + */ + tgdb_id: number | null; + /** + * Flashpoint Id + */ + flashpoint_id: string | null; + /** + * Hltb Id + */ + hltb_id: number | null; + /** + * Gamelist Id + */ + gamelist_id: string | null; + /** + * Platform Id + */ + platform_id: number; + /** + * Platform Slug + */ + platform_slug: string; + /** + * Platform Fs Slug + */ + platform_fs_slug: string; + /** + * Platform Custom Name + */ + platform_custom_name: string | null; + /** + * Platform Display Name + */ + platform_display_name: string; + /** + * Fs Name + */ + fs_name: string; + /** + * Fs Name No Tags + */ + fs_name_no_tags: string; + /** + * Fs Name No Ext + */ + fs_name_no_ext: string; + /** + * Fs Extension + */ + fs_extension: string; + /** + * Fs Path + */ + fs_path: string; + /** + * Fs Size Bytes + */ + fs_size_bytes: number; + /** + * Name + */ + name: string | null; + /** + * Slug + */ + slug: string | null; + /** + * Summary + */ + summary: string | null; + /** + * Alternative Names + */ + alternative_names: Array; + /** + * Youtube Video Id + */ + youtube_video_id: string | null; + metadatum: RomMetadataSchema; + igdb_metadata: RomIgdbMetadata | null; + moby_metadata: RomMobyMetadata | null; + ss_metadata: RomSsMetadata | null; + launchbox_metadata: RomLaunchboxMetadata | null; + hasheous_metadata: RomHasheousMetadata | null; + flashpoint_metadata: RomFlashpointMetadata | null; + hltb_metadata: RomHltbMetadata | null; + gamelist_metadata: RomGamelistMetadata | null; + manual_metadata: ManualMetadata | null; + /** + * Path Cover Small + */ + path_cover_small: string | null; + /** + * Path Cover Large + */ + path_cover_large: string | null; + /** + * Url Cover + */ + url_cover: string | null; + /** + * Has Manual + */ + has_manual: boolean; + /** + * Path Manual + */ + path_manual: string | null; + /** + * Url Manual + */ + url_manual: string | null; + /** + * Is Identifying + */ + is_identifying?: boolean; + /** + * Is Unidentified + */ + is_unidentified: boolean; + /** + * Is Identified + */ + is_identified: boolean; + /** + * Revision + */ + revision: string | null; + /** + * Regions + */ + regions: Array; + /** + * Languages + */ + languages: Array; + /** + * Tags + */ + tags: Array; + /** + * Crc Hash + */ + crc_hash: string | null; + /** + * Md5 Hash + */ + md5_hash: string | null; + /** + * Sha1 Hash + */ + sha1_hash: string | null; + /** + * Has Simple Single File + */ + has_simple_single_file: boolean; + /** + * Has Nested Single File + */ + has_nested_single_file: boolean; + /** + * Has Multiple Files + */ + has_multiple_files: boolean; + /** + * Files + */ + files: Array; + /** + * Full Path + */ + full_path: string; + /** + * Created At + */ + created_at: string; + /** + * Updated At + */ + updated_at: string; + /** + * Missing From Fs + */ + missing_from_fs: boolean; + /** + * Has Notes + */ + has_notes: boolean; + /** + * Siblings + */ + siblings: Array; + rom_user: RomUserSchema; + /** + * Merged Screenshots + */ + merged_screenshots: Array; + merged_ra_metadata: RomRaMetadata | null; + /** + * User Saves + */ + user_saves: Array; + /** + * User States + */ + user_states: Array; + /** + * User Screenshots + */ + user_screenshots: Array; + /** + * User Collections + */ + user_collections: Array; + /** + * All User Notes + */ + all_user_notes: Array; +}; + +/** + * EarnedAchievement + */ +export type EarnedAchievement = { + /** + * Id + */ + id: string; + /** + * Date + */ + date: string; + /** + * Date Hardcore + */ + date_hardcore?: string; +}; + +/** + * EjsControls + */ +export type EjsControls = { + /** + * 0 + */ + _0: { + [key: string]: EjsControlsButton; + }; + /** + * 1 + */ + _1: { + [key: string]: EjsControlsButton; + }; + /** + * 2 + */ + _2: { + [key: string]: EjsControlsButton; + }; + /** + * 3 + */ + _3: { + [key: string]: EjsControlsButton; + }; +}; + +/** + * EjsControlsButton + */ +export type EjsControlsButton = { + /** + * Value + */ + value?: string; + /** + * Value2 + */ + value2?: string; +}; + +/** + * EmulationDict + */ +export type EmulationDict = { + /** + * Disable Emulator Js + */ + DISABLE_EMULATOR_JS: boolean; + /** + * Disable Ruffle Rs + */ + DISABLE_RUFFLE_RS: boolean; +}; + +/** + * FilesystemDict + */ +export type FilesystemDict = { + /** + * Fs Platforms + */ + FS_PLATFORMS: Array; +}; + +/** + * FirmwareSchema + */ +export type FirmwareSchema = { + /** + * Id + */ + id: number; + /** + * File Name + */ + file_name: string; + /** + * File Name No Tags + */ + file_name_no_tags: string; + /** + * File Name No Ext + */ + file_name_no_ext: string; + /** + * File Extension + */ + file_extension: string; + /** + * File Path + */ + file_path: string; + /** + * File Size Bytes + */ + file_size_bytes: number; + /** + * Full Path + */ + full_path: string; + /** + * Is Verified + */ + is_verified: boolean; + /** + * Crc Hash + */ + crc_hash: string; + /** + * Md5 Hash + */ + md5_hash: string; + /** + * Sha1 Hash + */ + sha1_hash: string; + /** + * Missing From Fs + */ + missing_from_fs: boolean; + /** + * Created At + */ + created_at: string; + /** + * Updated At + */ + updated_at: string; +}; + +/** + * FrontendDict + */ +export type FrontendDict = { + /** + * Upload Timeout + */ + UPLOAD_TIMEOUT: number; + /** + * Disable Userpass Login + */ + DISABLE_USERPASS_LOGIN: boolean; + /** + * Youtube Base Url + */ + YOUTUBE_BASE_URL: string; +}; + +/** + * GenericTaskMeta + */ +export type GenericTaskMeta = { + [key: string]: unknown; +}; + +/** + * GenericTaskStatusResponse + */ +export type GenericTaskStatusResponse = { + /** + * Task Name + */ + task_name: string; + /** + * Task Id + */ + task_id: string; + status: JobStatus; + /** + * Created At + */ + created_at: string | null; + /** + * Enqueued At + */ + enqueued_at: string | null; + /** + * Started At + */ + started_at: string | null; + /** + * Ended At + */ + ended_at: string | null; + /** + * Task Type + */ + task_type: 'generic'; + meta: GenericTaskMeta; +}; + +/** + * HTTPValidationError + */ +export type HttpValidationError = { + /** + * Detail + */ + detail?: Array; +}; + +/** + * HeartbeatResponse + */ +export type HeartbeatResponse = { + SYSTEM: SystemDict; + METADATA_SOURCES: MetadataSourcesDict; + FILESYSTEM: FilesystemDict; + EMULATION: EmulationDict; + FRONTEND: FrontendDict; + OIDC: OidcDict; + TASKS: TasksDict; +}; + +/** + * IGDBAgeRating + */ +export type IgdbAgeRating = { + /** + * Rating + */ + rating: string; + /** + * Category + */ + category: string; + /** + * Rating Cover Url + */ + rating_cover_url: string; +}; + +/** + * IGDBMetadataMultiplayerMode + */ +export type IgdbMetadataMultiplayerMode = { + /** + * Campaigncoop + */ + campaigncoop: boolean; + /** + * Dropin + */ + dropin: boolean; + /** + * Lancoop + */ + lancoop: boolean; + /** + * Offlinecoop + */ + offlinecoop: boolean; + /** + * Offlinecoopmax + */ + offlinecoopmax: number; + /** + * Offlinemax + */ + offlinemax: number; + /** + * Onlinecoop + */ + onlinecoop: number; + /** + * Onlinecoopmax + */ + onlinecoopmax: number; + /** + * Onlinemax + */ + onlinemax: number; + /** + * Splitscreen + */ + splitscreen: boolean; + /** + * Splitscreenonline + */ + splitscreenonline: boolean; + platform: IgdbMetadataPlatform; +}; + +/** + * IGDBMetadataPlatform + */ +export type IgdbMetadataPlatform = { + /** + * Igdb Id + */ + igdb_id: number; + /** + * Name + */ + name: string; +}; + +/** + * IGDBRelatedGame + */ +export type IgdbRelatedGame = { + /** + * Id + */ + id: number; + /** + * Name + */ + name: string; + /** + * Slug + */ + slug: string; + /** + * Type + */ + type: string; + /** + * Cover Url + */ + cover_url: string; +}; + +/** + * InviteLinkSchema + */ +export type InviteLinkSchema = { + /** + * Token + */ + token: string; +}; + +/** + * JobStatus + * + * The Status of Job within its lifecycle at any given time. + */ +export type JobStatus = 'queued' | 'finished' | 'failed' | 'started' | 'deferred' | 'scheduled' | 'stopped' | 'canceled'; + +/** + * LaunchboxImage + */ +export type LaunchboxImage = { + /** + * Url + */ + url: string; + /** + * Type + */ + type?: string; + /** + * Region + */ + region?: string; +}; + +/** + * ManualMetadata + */ +export type ManualMetadata = { + /** + * Genres + */ + genres?: Array | null; + /** + * Franchises + */ + franchises?: Array | null; + /** + * Companies + */ + companies?: Array | null; + /** + * Game Modes + */ + game_modes?: Array | null; + /** + * Age Ratings + */ + age_ratings?: Array | null; + /** + * First Release Date + */ + first_release_date?: number | null; + /** + * Youtube Video Id + */ + youtube_video_id?: string | null; +}; + +/** + * MetadataSourcesDict + */ +export type MetadataSourcesDict = { + /** + * Any Source Enabled + */ + ANY_SOURCE_ENABLED: boolean; + /** + * Igdb Api Enabled + */ + IGDB_API_ENABLED: boolean; + /** + * Ss Api Enabled + */ + SS_API_ENABLED: boolean; + /** + * Moby Api Enabled + */ + MOBY_API_ENABLED: boolean; + /** + * Steamgriddb Api Enabled + */ + STEAMGRIDDB_API_ENABLED: boolean; + /** + * Ra Api Enabled + */ + RA_API_ENABLED: boolean; + /** + * Launchbox Api Enabled + */ + LAUNCHBOX_API_ENABLED: boolean; + /** + * Hasheous Api Enabled + */ + HASHEOUS_API_ENABLED: boolean; + /** + * Playmatch Api Enabled + */ + PLAYMATCH_API_ENABLED: boolean; + /** + * Tgdb Api Enabled + */ + TGDB_API_ENABLED: boolean; + /** + * Flashpoint Api Enabled + */ + FLASHPOINT_API_ENABLED: boolean; + /** + * Hltb Api Enabled + */ + HLTB_API_ENABLED: boolean; +}; + +/** + * MobyMetadataPlatform + */ +export type MobyMetadataPlatform = { + /** + * Moby Id + */ + moby_id: number; + /** + * Name + */ + name: string; +}; + +/** + * NetplayICEServer + */ +export type NetplayIceServer = { + /** + * Urls + */ + urls: string; + /** + * Username + */ + username?: string; + /** + * Credential + */ + credential?: string; +}; + +/** + * OIDCDict + */ +export type OidcDict = { + /** + * Enabled + */ + ENABLED: boolean; + /** + * Provider + */ + PROVIDER: string; +}; + +/** + * PlatformSchema + */ +export type PlatformSchema = { + /** + * Id + */ + id: number; + /** + * Slug + */ + slug: string; + /** + * Fs Slug + */ + fs_slug: string; + /** + * Rom Count + */ + rom_count: number; + /** + * Name + */ + name: string; + /** + * Igdb Slug + */ + igdb_slug: string | null; + /** + * Moby Slug + */ + moby_slug: string | null; + /** + * Hltb Slug + */ + hltb_slug: string | null; + /** + * Custom Name + */ + custom_name?: string | null; + /** + * Igdb Id + */ + igdb_id?: number | null; + /** + * Sgdb Id + */ + sgdb_id?: number | null; + /** + * Moby Id + */ + moby_id?: number | null; + /** + * Launchbox Id + */ + launchbox_id?: number | null; + /** + * Ss Id + */ + ss_id?: number | null; + /** + * Ra Id + */ + ra_id?: number | null; + /** + * Hasheous Id + */ + hasheous_id?: number | null; + /** + * Tgdb Id + */ + tgdb_id?: number | null; + /** + * Flashpoint Id + */ + flashpoint_id?: number | null; + /** + * Category + */ + category?: string | null; + /** + * Generation + */ + generation?: number | null; + /** + * Family Name + */ + family_name?: string | null; + /** + * Family Slug + */ + family_slug?: string | null; + /** + * Url + */ + url?: string | null; + /** + * Url Logo + */ + url_logo?: string | null; + /** + * Firmware + */ + firmware?: Array; + /** + * Aspect Ratio + */ + aspect_ratio?: string; + /** + * Created At + */ + created_at: string; + /** + * Updated At + */ + updated_at: string; + /** + * Fs Size Bytes + */ + fs_size_bytes: number; + /** + * Is Unidentified + */ + is_unidentified: boolean; + /** + * Is Identified + */ + is_identified: boolean; + /** + * Missing From Fs + */ + missing_from_fs: boolean; + /** + * Display Name + */ + readonly display_name: string; +}; + +/** + * RAGameRomAchievement + */ +export type RaGameRomAchievement = { + /** + * Ra Id + */ + ra_id: number | null; + /** + * Title + */ + title: string | null; + /** + * Description + */ + description: string | null; + /** + * Points + */ + points: number | null; + /** + * Num Awarded + */ + num_awarded: number | null; + /** + * Num Awarded Hardcore + */ + num_awarded_hardcore: number | null; + /** + * Badge Id + */ + badge_id: string | null; + /** + * Badge Url Lock + */ + badge_url_lock: string | null; + /** + * Badge Path Lock + */ + badge_path_lock: string | null; + /** + * Badge Url + */ + badge_url: string | null; + /** + * Badge Path + */ + badge_path: string | null; + /** + * Display Order + */ + display_order: number | null; + /** + * Type + */ + type: string | null; +}; + +/** + * RAProgression + */ +export type RaProgression = { + /** + * Total + */ + total?: number; + /** + * Results + */ + results?: Array; +}; + +/** + * RAUserGameProgression + */ +export type RaUserGameProgression = { + /** + * Rom Ra Id + */ + rom_ra_id: number | null; + /** + * Max Possible + */ + max_possible: number | null; + /** + * Num Awarded + */ + num_awarded: number | null; + /** + * Num Awarded Hardcore + */ + num_awarded_hardcore: number | null; + /** + * Most Recent Awarded Date + */ + most_recent_awarded_date?: string | null; + /** + * Earned Achievements + */ + earned_achievements: Array; +}; + +/** + * Role + */ +export type Role = 'viewer' | 'editor' | 'admin'; + +/** + * RomFileCategory + */ +export type RomFileCategory = 'game' | 'dlc' | 'hack' | 'manual' | 'patch' | 'update' | 'mod' | 'demo' | 'translation' | 'prototype' | 'cheat'; + +/** + * RomFileSchema + */ +export type RomFileSchema = { + /** + * Id + */ + id: number; + /** + * Rom Id + */ + rom_id: number; + /** + * File Name + */ + file_name: string; + /** + * File Path + */ + file_path: string; + /** + * File Size Bytes + */ + file_size_bytes: number; + /** + * Full Path + */ + full_path: string; + /** + * Created At + */ + created_at: string; + /** + * Updated At + */ + updated_at: string; + /** + * Last Modified + */ + last_modified: string; + /** + * Crc Hash + */ + crc_hash: string | null; + /** + * Md5 Hash + */ + md5_hash: string | null; + /** + * Sha1 Hash + */ + sha1_hash: string | null; + category: RomFileCategory | null; +}; + +/** + * RomFiltersDict + */ +export type RomFiltersDict = { + /** + * Genres + */ + genres: Array; + /** + * Franchises + */ + franchises: Array; + /** + * Collections + */ + collections: Array; + /** + * Companies + */ + companies: Array; + /** + * Game Modes + */ + game_modes: Array; + /** + * Age Ratings + */ + age_ratings: Array; + /** + * Player Counts + */ + player_counts: Array; + /** + * Regions + */ + regions: Array; + /** + * Languages + */ + languages: Array; + /** + * Platforms + */ + platforms: Array; +}; + +/** + * RomFlashpointMetadata + */ +export type RomFlashpointMetadata = { + /** + * Franchises + */ + franchises?: Array; + /** + * Companies + */ + companies?: Array; + /** + * Source + */ + source?: string | null; + /** + * Genres + */ + genres?: Array; + /** + * First Release Date + */ + first_release_date?: string; + /** + * Game Modes + */ + game_modes?: Array; + /** + * Status + */ + status?: string | null; + /** + * Version + */ + version?: string | null; + /** + * Language + */ + language?: string | null; + /** + * Notes + */ + notes?: string | null; +}; + +/** + * RomGamelistMetadata + */ +export type RomGamelistMetadata = { + /** + * Box2D Url + */ + box2d_url?: string | null; + /** + * Box2D Back Url + */ + box2d_back_url?: string | null; + /** + * Box3D Url + */ + box3d_url?: string | null; + /** + * Fanart Url + */ + fanart_url?: string | null; + /** + * Image Url + */ + image_url?: string | null; + /** + * Manual Url + */ + manual_url?: string | null; + /** + * Marquee Url + */ + marquee_url?: string | null; + /** + * Miximage Url + */ + miximage_url?: string | null; + /** + * Physical Url + */ + physical_url?: string | null; + /** + * Screenshot Url + */ + screenshot_url?: string | null; + /** + * Thumbnail Url + */ + thumbnail_url?: string | null; + /** + * Title Screen Url + */ + title_screen_url?: string | null; + /** + * Video Url + */ + video_url?: string | null; + /** + * Rating + */ + rating?: number | null; + /** + * First Release Date + */ + first_release_date?: string | null; + /** + * Companies + */ + companies?: Array | null; + /** + * Franchises + */ + franchises?: Array | null; + /** + * Genres + */ + genres?: Array | null; + /** + * Player Count + */ + player_count?: string | null; + /** + * Md5 Hash + */ + md5_hash?: string | null; + /** + * Box3D Path + */ + box3d_path?: string | null; + /** + * Miximage Path + */ + miximage_path?: string | null; + /** + * Physical Path + */ + physical_path?: string | null; + /** + * Marquee Path + */ + marquee_path?: string | null; + /** + * Video Path + */ + video_path?: string | null; +}; + +/** + * RomHLTBMetadata + */ +export type RomHltbMetadata = { + /** + * Main Story + */ + main_story?: number; + /** + * Main Story Count + */ + main_story_count?: number; + /** + * Main Plus Extra + */ + main_plus_extra?: number; + /** + * Main Plus Extra Count + */ + main_plus_extra_count?: number; + /** + * Completionist + */ + completionist?: number; + /** + * Completionist Count + */ + completionist_count?: number; + /** + * All Styles + */ + all_styles?: number; + /** + * All Styles Count + */ + all_styles_count?: number; + /** + * Release Year + */ + release_year?: number; + /** + * Review Score + */ + review_score?: number; + /** + * Review Count + */ + review_count?: number; + /** + * Popularity + */ + popularity?: number; + /** + * Completions + */ + completions?: number; +}; + +/** + * RomHasheousMetadata + */ +export type RomHasheousMetadata = { + /** + * Tosec Match + */ + tosec_match?: boolean; + /** + * Mame Arcade Match + */ + mame_arcade_match?: boolean; + /** + * Mame Mess Match + */ + mame_mess_match?: boolean; + /** + * Nointro Match + */ + nointro_match?: boolean; + /** + * Redump Match + */ + redump_match?: boolean; + /** + * Whdload Match + */ + whdload_match?: boolean; + /** + * Ra Match + */ + ra_match?: boolean; + /** + * Fbneo Match + */ + fbneo_match?: boolean; + /** + * Puredos Match + */ + puredos_match?: boolean; +}; + +/** + * RomIGDBMetadata + */ +export type RomIgdbMetadata = { + /** + * Total Rating + */ + total_rating?: string | null; + /** + * Aggregated Rating + */ + aggregated_rating?: string | null; + /** + * First Release Date + */ + first_release_date?: number | null; + /** + * Youtube Video Id + */ + youtube_video_id?: string | null; + /** + * Genres + */ + genres?: Array; + /** + * Franchises + */ + franchises?: Array; + /** + * Alternative Names + */ + alternative_names?: Array; + /** + * Collections + */ + collections?: Array; + /** + * Companies + */ + companies?: Array; + /** + * Game Modes + */ + game_modes?: Array; + /** + * Age Ratings + */ + age_ratings?: Array; + /** + * Platforms + */ + platforms?: Array; + /** + * Multiplayer Modes + */ + multiplayer_modes?: Array; + /** + * Player Count + */ + player_count?: string; + /** + * Expansions + */ + expansions?: Array; + /** + * Dlcs + */ + dlcs?: Array; + /** + * Remasters + */ + remasters?: Array; + /** + * Remakes + */ + remakes?: Array; + /** + * Expanded Games + */ + expanded_games?: Array; + /** + * Ports + */ + ports?: Array; + /** + * Similar Games + */ + similar_games?: Array; +}; + +/** + * RomLaunchboxMetadata + */ +export type RomLaunchboxMetadata = { + /** + * First Release Date + */ + first_release_date?: number | null; + /** + * Max Players + */ + max_players?: number; + /** + * Release Type + */ + release_type?: string; + /** + * Cooperative + */ + cooperative?: boolean; + /** + * Youtube Video Id + */ + youtube_video_id?: string; + /** + * Community Rating + */ + community_rating?: number; + /** + * Community Rating Count + */ + community_rating_count?: number; + /** + * Wikipedia Url + */ + wikipedia_url?: string; + /** + * Esrb + */ + esrb?: string; + /** + * Genres + */ + genres?: Array; + /** + * Companies + */ + companies?: Array; + /** + * Images + */ + images?: Array; +}; + +/** + * RomMetadataSchema + */ +export type RomMetadataSchema = { + /** + * Rom Id + */ + rom_id: number; + /** + * Genres + */ + genres: Array; + /** + * Franchises + */ + franchises: Array; + /** + * Collections + */ + collections: Array; + /** + * Companies + */ + companies: Array; + /** + * Game Modes + */ + game_modes: Array; + /** + * Age Ratings + */ + age_ratings: Array; + /** + * Player Count + */ + player_count: string; + /** + * First Release Date + */ + first_release_date: number | null; + /** + * Average Rating + */ + average_rating: number | null; +}; + +/** + * RomMobyMetadata + */ +export type RomMobyMetadata = { + /** + * Moby Score + */ + moby_score?: string | null; + /** + * Genres + */ + genres?: Array; + /** + * Alternate Titles + */ + alternate_titles?: Array; + /** + * Platforms + */ + platforms?: Array; +}; + +/** + * RomRAMetadata + */ +export type RomRaMetadata = { + /** + * First Release Date + */ + first_release_date?: number | null; + /** + * Genres + */ + genres?: Array; + /** + * Companies + */ + companies?: Array; + /** + * Achievements + */ + achievements?: Array; +}; + +/** + * RomSSMetadata + */ +export type RomSsMetadata = { + /** + * Bezel Url + */ + bezel_url?: string | null; + /** + * Box2D Url + */ + box2d_url?: string | null; + /** + * Box2D Side Url + */ + box2d_side_url?: string | null; + /** + * Box2D Back Url + */ + box2d_back_url?: string | null; + /** + * Box3D Url + */ + box3d_url?: string | null; + /** + * Fanart Url + */ + fanart_url?: string | null; + /** + * Fullbox Url + */ + fullbox_url?: string | null; + /** + * Logo Url + */ + logo_url?: string | null; + /** + * Manual Url + */ + manual_url?: string | null; + /** + * Marquee Url + */ + marquee_url?: string | null; + /** + * Miximage Url + */ + miximage_url?: string | null; + /** + * Physical Url + */ + physical_url?: string | null; + /** + * Screenshot Url + */ + screenshot_url?: string | null; + /** + * Steamgrid Url + */ + steamgrid_url?: string | null; + /** + * Title Screen Url + */ + title_screen_url?: string | null; + /** + * Video Url + */ + video_url?: string | null; + /** + * Video Normalized Url + */ + video_normalized_url?: string | null; + /** + * Bezel Path + */ + bezel_path?: string | null; + /** + * Box2D Back Path + */ + box2d_back_path?: string | null; + /** + * Box3D Path + */ + box3d_path?: string | null; + /** + * Fanart Path + */ + fanart_path?: string | null; + /** + * Miximage Path + */ + miximage_path?: string | null; + /** + * Physical Path + */ + physical_path?: string | null; + /** + * Marquee Path + */ + marquee_path?: string | null; + /** + * Logo Path + */ + logo_path?: string | null; + /** + * Video Path + */ + video_path?: string | null; + /** + * Ss Score + */ + ss_score?: string | null; + /** + * First Release Date + */ + first_release_date?: number | null; + /** + * Alternative Names + */ + alternative_names?: Array; + /** + * Companies + */ + companies?: Array; + /** + * Franchises + */ + franchises?: Array; + /** + * Game Modes + */ + game_modes?: Array; + /** + * Genres + */ + genres?: Array; + /** + * Player Count + */ + player_count?: string; +}; + +/** + * RomUserSchema + */ +export type RomUserSchema = { + /** + * Id + */ + id: number; + /** + * User Id + */ + user_id: number; + /** + * Rom Id + */ + rom_id: number; + /** + * Created At + */ + created_at: string; + /** + * Updated At + */ + updated_at: string; + /** + * Last Played + */ + last_played: string | null; + /** + * Is Main Sibling + */ + is_main_sibling: boolean; + /** + * Backlogged + */ + backlogged: boolean; + /** + * Now Playing + */ + now_playing: boolean; + /** + * Hidden + */ + hidden: boolean; + /** + * Rating + */ + rating: number; + /** + * Difficulty + */ + difficulty: number; + /** + * Completion + */ + completion: number; + status: RomUserStatus | null; + /** + * User Username + */ + user__username: string; +}; + +/** + * RomUserStatus + */ +export type RomUserStatus = 'incomplete' | 'finished' | 'completed_100' | 'retired' | 'never_playing'; + +/** + * RoomsResponse + */ +export type RoomsResponse = { + /** + * Room Name + */ + room_name: string; + /** + * Current + */ + current: number; + /** + * Max + */ + max: number; + /** + * Player Name + */ + player_name: string; + /** + * Haspassword + */ + hasPassword: boolean; +}; + +/** + * SGDBResource + */ +export type SgdbResource = { + /** + * Thumb + */ + thumb: string; + /** + * Url + */ + url: string; + /** + * Type + */ + type: string; +}; + +/** + * SaveSchema + */ +export type SaveSchema = { + /** + * Id + */ + id: number; + /** + * Rom Id + */ + rom_id: number; + /** + * User Id + */ + user_id: number; + /** + * File Name + */ + file_name: string; + /** + * File Name No Tags + */ + file_name_no_tags: string; + /** + * File Name No Ext + */ + file_name_no_ext: string; + /** + * File Extension + */ + file_extension: string; + /** + * File Path + */ + file_path: string; + /** + * File Size Bytes + */ + file_size_bytes: number; + /** + * Full Path + */ + full_path: string; + /** + * Download Path + */ + download_path: string; + /** + * Missing From Fs + */ + missing_from_fs: boolean; + /** + * Created At + */ + created_at: string; + /** + * Updated At + */ + updated_at: string; + /** + * Emulator + */ + emulator: string | null; + screenshot: ScreenshotSchema | null; +}; + +/** + * ScanStats + */ +export type ScanStats = { + /** + * Total Platforms + */ + total_platforms: number; + /** + * Total Roms + */ + total_roms: number; + /** + * Scanned Platforms + */ + scanned_platforms: number; + /** + * New Platforms + */ + new_platforms: number; + /** + * Identified Platforms + */ + identified_platforms: number; + /** + * Scanned Roms + */ + scanned_roms: number; + /** + * New Roms + */ + new_roms: number; + /** + * Identified Roms + */ + identified_roms: number; + /** + * Scanned Firmware + */ + scanned_firmware: number; + /** + * New Firmware + */ + new_firmware: number; +}; + +/** + * ScanTaskMeta + */ +export type ScanTaskMeta = { + scan_stats: ScanStats | null; +}; + +/** + * ScanTaskStatusResponse + */ +export type ScanTaskStatusResponse = { + /** + * Task Name + */ + task_name: string; + /** + * Task Id + */ + task_id: string; + status: JobStatus; + /** + * Created At + */ + created_at: string | null; + /** + * Enqueued At + */ + enqueued_at: string | null; + /** + * Started At + */ + started_at: string | null; + /** + * Ended At + */ + ended_at: string | null; + /** + * Task Type + */ + task_type: 'scan'; + meta: ScanTaskMeta; +}; + +/** + * ScreenshotSchema + */ +export type ScreenshotSchema = { + /** + * Id + */ + id: number; + /** + * Rom Id + */ + rom_id: number; + /** + * User Id + */ + user_id: number; + /** + * File Name + */ + file_name: string; + /** + * File Name No Tags + */ + file_name_no_tags: string; + /** + * File Name No Ext + */ + file_name_no_ext: string; + /** + * File Extension + */ + file_extension: string; + /** + * File Path + */ + file_path: string; + /** + * File Size Bytes + */ + file_size_bytes: number; + /** + * Full Path + */ + full_path: string; + /** + * Download Path + */ + download_path: string; + /** + * Missing From Fs + */ + missing_from_fs: boolean; + /** + * Created At + */ + created_at: string; + /** + * Updated At + */ + updated_at: string; +}; + +/** + * SearchCoverSchema + */ +export type SearchCoverSchema = { + /** + * Name + */ + name: string; + /** + * Resources + */ + resources: Array; +}; + +/** + * SearchRomSchema + */ +export type SearchRomSchema = { + /** + * Id + */ + id?: number | null; + /** + * Igdb Id + */ + igdb_id?: number | null; + /** + * Moby Id + */ + moby_id?: number | null; + /** + * Ss Id + */ + ss_id?: number | null; + /** + * Sgdb Id + */ + sgdb_id?: number | null; + /** + * Flashpoint Id + */ + flashpoint_id?: string | null; + /** + * Launchbox Id + */ + launchbox_id?: number | null; + /** + * Platform Id + */ + platform_id: number; + /** + * Name + */ + name: string; + /** + * Slug + */ + slug?: string; + /** + * Summary + */ + summary?: string; + /** + * Igdb Url Cover + */ + igdb_url_cover?: string; + /** + * Moby Url Cover + */ + moby_url_cover?: string; + /** + * Ss Url Cover + */ + ss_url_cover?: string; + /** + * Sgdb Url Cover + */ + sgdb_url_cover?: string; + /** + * Flashpoint Url Cover + */ + flashpoint_url_cover?: string; + /** + * Launchbox Url Cover + */ + launchbox_url_cover?: string; + /** + * Is Unidentified + */ + is_unidentified: boolean; + /** + * Is Identified + */ + is_identified: boolean; +}; + +/** + * SiblingRomSchema + */ +export type SiblingRomSchema = { + /** + * Id + */ + id: number; + /** + * Name + */ + name: string | null; + /** + * Fs Name No Tags + */ + fs_name_no_tags: string; + /** + * Fs Name No Ext + */ + fs_name_no_ext: string; + /** + * Sort Comparator + */ + readonly sort_comparator: string; +}; + +/** + * SimpleRomSchema + */ +export type SimpleRomSchema = { + /** + * Id + */ + id: number; + /** + * Igdb Id + */ + igdb_id: number | null; + /** + * Sgdb Id + */ + sgdb_id: number | null; + /** + * Moby Id + */ + moby_id: number | null; + /** + * Ss Id + */ + ss_id: number | null; + /** + * Ra Id + */ + ra_id: number | null; + /** + * Launchbox Id + */ + launchbox_id: number | null; + /** + * Hasheous Id + */ + hasheous_id: number | null; + /** + * Tgdb Id + */ + tgdb_id: number | null; + /** + * Flashpoint Id + */ + flashpoint_id: string | null; + /** + * Hltb Id + */ + hltb_id: number | null; + /** + * Gamelist Id + */ + gamelist_id: string | null; + /** + * Platform Id + */ + platform_id: number; + /** + * Platform Slug + */ + platform_slug: string; + /** + * Platform Fs Slug + */ + platform_fs_slug: string; + /** + * Platform Custom Name + */ + platform_custom_name: string | null; + /** + * Platform Display Name + */ + platform_display_name: string; + /** + * Fs Name + */ + fs_name: string; + /** + * Fs Name No Tags + */ + fs_name_no_tags: string; + /** + * Fs Name No Ext + */ + fs_name_no_ext: string; + /** + * Fs Extension + */ + fs_extension: string; + /** + * Fs Path + */ + fs_path: string; + /** + * Fs Size Bytes + */ + fs_size_bytes: number; + /** + * Name + */ + name: string | null; + /** + * Slug + */ + slug: string | null; + /** + * Summary + */ + summary: string | null; + /** + * Alternative Names + */ + alternative_names: Array; + /** + * Youtube Video Id + */ + youtube_video_id: string | null; + metadatum: RomMetadataSchema; + igdb_metadata: RomIgdbMetadata | null; + moby_metadata: RomMobyMetadata | null; + ss_metadata: RomSsMetadata | null; + launchbox_metadata: RomLaunchboxMetadata | null; + hasheous_metadata: RomHasheousMetadata | null; + flashpoint_metadata: RomFlashpointMetadata | null; + hltb_metadata: RomHltbMetadata | null; + gamelist_metadata: RomGamelistMetadata | null; + manual_metadata: ManualMetadata | null; + /** + * Path Cover Small + */ + path_cover_small: string | null; + /** + * Path Cover Large + */ + path_cover_large: string | null; + /** + * Url Cover + */ + url_cover: string | null; + /** + * Has Manual + */ + has_manual: boolean; + /** + * Path Manual + */ + path_manual: string | null; + /** + * Url Manual + */ + url_manual: string | null; + /** + * Is Identifying + */ + is_identifying?: boolean; + /** + * Is Unidentified + */ + is_unidentified: boolean; + /** + * Is Identified + */ + is_identified: boolean; + /** + * Revision + */ + revision: string | null; + /** + * Regions + */ + regions: Array; + /** + * Languages + */ + languages: Array; + /** + * Tags + */ + tags: Array; + /** + * Crc Hash + */ + crc_hash: string | null; + /** + * Md5 Hash + */ + md5_hash: string | null; + /** + * Sha1 Hash + */ + sha1_hash: string | null; + /** + * Has Simple Single File + */ + has_simple_single_file: boolean; + /** + * Has Nested Single File + */ + has_nested_single_file: boolean; + /** + * Has Multiple Files + */ + has_multiple_files: boolean; + /** + * Files + */ + files: Array; + /** + * Full Path + */ + full_path: string; + /** + * Created At + */ + created_at: string; + /** + * Updated At + */ + updated_at: string; + /** + * Missing From Fs + */ + missing_from_fs: boolean; + /** + * Has Notes + */ + has_notes: boolean; + /** + * Siblings + */ + siblings: Array; + rom_user: RomUserSchema; + /** + * Merged Screenshots + */ + merged_screenshots: Array; + merged_ra_metadata: RomRaMetadata | null; +}; + +/** + * SmartCollectionSchema + */ +export type SmartCollectionSchema = { + /** + * Name + */ + name: string; + /** + * Description + */ + description?: string; + /** + * Rom Ids + */ + rom_ids: Array; + /** + * Rom Count + */ + rom_count: number; + /** + * Path Cover Small + */ + path_cover_small: string | null; + /** + * Path Cover Large + */ + path_cover_large: string | null; + /** + * Path Covers Small + */ + path_covers_small: Array; + /** + * Path Covers Large + */ + path_covers_large: Array; + /** + * Is Public + */ + is_public?: boolean; + /** + * Is Favorite + */ + is_favorite?: boolean; + /** + * Is Virtual + */ + is_virtual?: boolean; + /** + * Is Smart + */ + is_smart?: boolean; + /** + * Created At + */ + created_at: string; + /** + * Updated At + */ + updated_at: string; + /** + * Id + */ + id: number; + /** + * Filter Criteria + */ + filter_criteria: { + [key: string]: unknown; + }; + /** + * Filter Summary + */ + filter_summary: string; + /** + * User Id + */ + user_id: number; + /** + * User Username + */ + user__username: string; +}; + +/** + * StateSchema + */ +export type StateSchema = { + /** + * Id + */ + id: number; + /** + * Rom Id + */ + rom_id: number; + /** + * User Id + */ + user_id: number; + /** + * File Name + */ + file_name: string; + /** + * File Name No Tags + */ + file_name_no_tags: string; + /** + * File Name No Ext + */ + file_name_no_ext: string; + /** + * File Extension + */ + file_extension: string; + /** + * File Path + */ + file_path: string; + /** + * File Size Bytes + */ + file_size_bytes: number; + /** + * Full Path + */ + full_path: string; + /** + * Download Path + */ + download_path: string; + /** + * Missing From Fs + */ + missing_from_fs: boolean; + /** + * Created At + */ + created_at: string; + /** + * Updated At + */ + updated_at: string; + /** + * Emulator + */ + emulator: string | null; + screenshot: ScreenshotSchema | null; +}; + +/** + * StatsReturn + */ +export type StatsReturn = { + /** + * Platforms + */ + PLATFORMS: number; + /** + * Roms + */ + ROMS: number; + /** + * Saves + */ + SAVES: number; + /** + * States + */ + STATES: number; + /** + * Screenshots + */ + SCREENSHOTS: number; + /** + * Total Filesize Bytes + */ + TOTAL_FILESIZE_BYTES: number; +}; + +/** + * SystemDict + */ +export type SystemDict = { + /** + * Version + */ + VERSION: string; + /** + * Show Setup Wizard + */ + SHOW_SETUP_WIZARD: boolean; +}; + +/** + * TaskExecutionResponse + */ +export type TaskExecutionResponse = { + /** + * Task Name + */ + task_name: string; + /** + * Task Id + */ + task_id: string; + status: JobStatus; + /** + * Created At + */ + created_at: string | null; + /** + * Enqueued At + */ + enqueued_at: string | null; +}; + +/** + * TaskInfo + */ +export type TaskInfo = { + /** + * Name + */ + name: string; + type: TaskType; + /** + * Manual Run + */ + manual_run: boolean; + /** + * Title + */ + title: string; + /** + * Description + */ + description: string; + /** + * Enabled + */ + enabled: boolean; + /** + * Cron String + */ + cron_string: string; +}; + +/** + * TaskType + * + * Enumeration of task types for categorization and UI display. + */ +export type TaskType = 'scan' | 'conversion' | 'cleanup' | 'update' | 'watcher' | 'generic'; + +/** + * TasksDict + */ +export type TasksDict = { + /** + * Enable Scheduled Rescan + */ + ENABLE_SCHEDULED_RESCAN: boolean; + /** + * Scheduled Rescan Cron + */ + SCHEDULED_RESCAN_CRON: string; + /** + * Enable Scheduled Update Switch Titledb + */ + ENABLE_SCHEDULED_UPDATE_SWITCH_TITLEDB: boolean; + /** + * Scheduled Update Switch Titledb Cron + */ + SCHEDULED_UPDATE_SWITCH_TITLEDB_CRON: string; + /** + * Enable Scheduled Update Launchbox Metadata + */ + ENABLE_SCHEDULED_UPDATE_LAUNCHBOX_METADATA: boolean; + /** + * Scheduled Update Launchbox Metadata Cron + */ + SCHEDULED_UPDATE_LAUNCHBOX_METADATA_CRON: string; + /** + * Enable Scheduled Convert Images To Webp + */ + ENABLE_SCHEDULED_CONVERT_IMAGES_TO_WEBP: boolean; + /** + * Scheduled Convert Images To Webp Cron + */ + SCHEDULED_CONVERT_IMAGES_TO_WEBP_CRON: string; +}; + +/** + * TinfoilFeedFileSchema + */ +export type TinfoilFeedFileSchema = { + /** + * Url + */ + url: string; + /** + * Size + */ + size: number; +}; + +/** + * TinfoilFeedSchema + */ +export type TinfoilFeedSchema = { + /** + * Files + */ + files: Array; + /** + * Directories + */ + directories: Array; + /** + * Titledb + */ + titledb?: { + [key: string]: { + [key: string]: unknown; + }; + }; + /** + * Success + */ + success?: string; + /** + * Error + */ + error?: string; +}; + +/** + * TokenResponse + */ +export type TokenResponse = { + /** + * Access Token + */ + access_token: string; + /** + * Refresh Token + */ + refresh_token?: string; + /** + * Token Type + */ + token_type: string; + /** + * Expires + */ + expires: number; +}; + +/** + * UpdateStats + */ +export type UpdateStats = { + /** + * Processed + */ + processed: number; + /** + * Total + */ + total: number; +}; + +/** + * UpdateTaskMeta + */ +export type UpdateTaskMeta = { + update_stats: UpdateStats | null; +}; + +/** + * UpdateTaskStatusResponse + */ +export type UpdateTaskStatusResponse = { + /** + * Task Name + */ + task_name: string; + /** + * Task Id + */ + task_id: string; + status: JobStatus; + /** + * Created At + */ + created_at: string | null; + /** + * Enqueued At + */ + enqueued_at: string | null; + /** + * Started At + */ + started_at: string | null; + /** + * Ended At + */ + ended_at: string | null; + /** + * Task Type + */ + task_type: 'update'; + meta: UpdateTaskMeta; +}; + +/** + * UserCollectionSchema + */ +export type UserCollectionSchema = { + /** + * Id + */ + id: number; + /** + * Name + */ + name: string; +}; + +/** + * UserForm + */ +export type UserForm = { + /** + * Username + */ + username?: string | null; + /** + * Password + */ + password?: string | null; + /** + * Email + */ + email?: string | null; + /** + * Role + */ + role?: string | null; + /** + * Enabled + */ + enabled?: boolean | null; + /** + * Ra Username + */ + ra_username?: string | null; + /** + * Avatar + */ + avatar?: Blob | File | null; + /** + * Ui Settings + */ + ui_settings?: string | null; +}; + +/** + * UserNoteSchema + */ +export type UserNoteSchema = { + /** + * Id + */ + id: number; + /** + * Title + */ + title: string; + /** + * Content + */ + content: string; + /** + * Is Public + */ + is_public: boolean; + /** + * Tags + */ + tags?: Array | null; + /** + * Created At + */ + created_at: string; + /** + * Updated At + */ + updated_at: string; + /** + * User Id + */ + user_id: number; + /** + * Username + */ + username: string; +}; + +/** + * UserSchema + */ +export type UserSchema = { + /** + * Id + */ + id: number; + /** + * Username + */ + username: string; + /** + * Email + */ + email: string | null; + /** + * Enabled + */ + enabled: boolean; + role: Role; + /** + * Oauth Scopes + */ + oauth_scopes: Array; + /** + * Avatar Path + */ + avatar_path: string; + /** + * Last Login + */ + last_login: string | null; + /** + * Last Active + */ + last_active: string | null; + /** + * Ra Username + */ + ra_username?: string | null; + ra_progression?: RaProgression | null; + /** + * Ui Settings + */ + ui_settings?: { + [key: string]: unknown; + } | null; + /** + * Created At + */ + created_at: string; + /** + * Updated At + */ + updated_at: string; +}; + +/** + * ValidationError + */ +export type ValidationError = { + /** + * Location + */ + loc: Array; + /** + * Message + */ + msg: string; + /** + * Error Type + */ + type: string; +}; + +/** + * VirtualCollectionSchema + */ +export type VirtualCollectionSchema = { + /** + * Name + */ + name: string; + /** + * Description + */ + description: string; + /** + * Rom Ids + */ + rom_ids: Array; + /** + * Rom Count + */ + rom_count: number; + /** + * Path Cover Small + */ + path_cover_small: string | null; + /** + * Path Cover Large + */ + path_cover_large: string | null; + /** + * Path Covers Small + */ + path_covers_small: Array; + /** + * Path Covers Large + */ + path_covers_large: Array; + /** + * Is Public + */ + is_public?: boolean; + /** + * Is Favorite + */ + is_favorite?: boolean; + /** + * Is Virtual + */ + is_virtual?: boolean; + /** + * Is Smart + */ + is_smart?: boolean; + /** + * Created At + */ + created_at: string; + /** + * Updated At + */ + updated_at: string; + /** + * Id + */ + id: string; + /** + * Type + */ + type: string; +}; + +/** + * WatcherTaskMeta + */ +export type WatcherTaskMeta = { + [key: string]: unknown; +}; + +/** + * WatcherTaskStatusResponse + */ +export type WatcherTaskStatusResponse = { + /** + * Task Name + */ + task_name: string; + /** + * Task Id + */ + task_id: string; + status: JobStatus; + /** + * Created At + */ + created_at: string | null; + /** + * Enqueued At + */ + enqueued_at: string | null; + /** + * Started At + */ + started_at: string | null; + /** + * Ended At + */ + ended_at: string | null; + /** + * Task Type + */ + task_type: 'watcher'; + meta: WatcherTaskMeta; +}; + +/** + * WebrcadeFeedCategorySchema + */ +export type WebrcadeFeedCategorySchema = { + /** + * Title + */ + title: string; + /** + * Longtitle + */ + longTitle?: string; + /** + * Background + */ + background?: string; + /** + * Thumbnail + */ + thumbnail?: string; + /** + * Description + */ + description?: string; + /** + * Items + */ + items: Array; +}; + +/** + * WebrcadeFeedItemPropsSchema + */ +export type WebrcadeFeedItemPropsSchema = { + /** + * Rom + */ + rom: string; +}; + +/** + * WebrcadeFeedItemSchema + */ +export type WebrcadeFeedItemSchema = { + /** + * Title + */ + title: string; + /** + * Longtitle + */ + longTitle?: string; + /** + * Description + */ + description?: string; + /** + * Type + */ + type: string; + /** + * Thumbnail + */ + thumbnail?: string; + /** + * Background + */ + background?: string; + props: WebrcadeFeedItemPropsSchema; +}; + +/** + * WebrcadeFeedSchema + */ +export type WebrcadeFeedSchema = { + /** + * Title + */ + title: string; + /** + * Longtitle + */ + longTitle?: string; + /** + * Description + */ + description?: string; + /** + * Thumbnail + */ + thumbnail?: string; + /** + * Background + */ + background?: string; + /** + * Categories + */ + categories: Array; +}; + +/** + * CustomLimitOffsetPage[SimpleRomSchema] + */ +export type CustomLimitOffsetPageSimpleRomSchemaWritable = { + /** + * Items + */ + items: Array; + /** + * Total + */ + total: number; + /** + * Limit + */ + limit: number; + /** + * Offset + */ + offset: number; + /** + * Char Index + */ + char_index: { + [key: string]: number; + }; + /** + * Rom Id Index + */ + rom_id_index: Array; + filter_values: RomFiltersDict; +}; + +/** + * DetailedRomSchema + */ +export type DetailedRomSchemaWritable = { + /** + * Id + */ + id: number; + /** + * Igdb Id + */ + igdb_id: number | null; + /** + * Sgdb Id + */ + sgdb_id: number | null; + /** + * Moby Id + */ + moby_id: number | null; + /** + * Ss Id + */ + ss_id: number | null; + /** + * Ra Id + */ + ra_id: number | null; + /** + * Launchbox Id + */ + launchbox_id: number | null; + /** + * Hasheous Id + */ + hasheous_id: number | null; + /** + * Tgdb Id + */ + tgdb_id: number | null; + /** + * Flashpoint Id + */ + flashpoint_id: string | null; + /** + * Hltb Id + */ + hltb_id: number | null; + /** + * Gamelist Id + */ + gamelist_id: string | null; + /** + * Platform Id + */ + platform_id: number; + /** + * Platform Slug + */ + platform_slug: string; + /** + * Platform Fs Slug + */ + platform_fs_slug: string; + /** + * Platform Custom Name + */ + platform_custom_name: string | null; + /** + * Platform Display Name + */ + platform_display_name: string; + /** + * Fs Name + */ + fs_name: string; + /** + * Fs Name No Tags + */ + fs_name_no_tags: string; + /** + * Fs Name No Ext + */ + fs_name_no_ext: string; + /** + * Fs Extension + */ + fs_extension: string; + /** + * Fs Path + */ + fs_path: string; + /** + * Fs Size Bytes + */ + fs_size_bytes: number; + /** + * Name + */ + name: string | null; + /** + * Slug + */ + slug: string | null; + /** + * Summary + */ + summary: string | null; + /** + * Alternative Names + */ + alternative_names: Array; + /** + * Youtube Video Id + */ + youtube_video_id: string | null; + metadatum: RomMetadataSchema; + igdb_metadata: RomIgdbMetadata | null; + moby_metadata: RomMobyMetadata | null; + ss_metadata: RomSsMetadata | null; + launchbox_metadata: RomLaunchboxMetadata | null; + hasheous_metadata: RomHasheousMetadata | null; + flashpoint_metadata: RomFlashpointMetadata | null; + hltb_metadata: RomHltbMetadata | null; + gamelist_metadata: RomGamelistMetadata | null; + manual_metadata: ManualMetadata | null; + /** + * Path Cover Small + */ + path_cover_small: string | null; + /** + * Path Cover Large + */ + path_cover_large: string | null; + /** + * Url Cover + */ + url_cover: string | null; + /** + * Has Manual + */ + has_manual: boolean; + /** + * Path Manual + */ + path_manual: string | null; + /** + * Url Manual + */ + url_manual: string | null; + /** + * Is Identifying + */ + is_identifying?: boolean; + /** + * Is Unidentified + */ + is_unidentified: boolean; + /** + * Is Identified + */ + is_identified: boolean; + /** + * Revision + */ + revision: string | null; + /** + * Regions + */ + regions: Array; + /** + * Languages + */ + languages: Array; + /** + * Tags + */ + tags: Array; + /** + * Crc Hash + */ + crc_hash: string | null; + /** + * Md5 Hash + */ + md5_hash: string | null; + /** + * Sha1 Hash + */ + sha1_hash: string | null; + /** + * Has Simple Single File + */ + has_simple_single_file: boolean; + /** + * Has Nested Single File + */ + has_nested_single_file: boolean; + /** + * Has Multiple Files + */ + has_multiple_files: boolean; + /** + * Files + */ + files: Array; + /** + * Full Path + */ + full_path: string; + /** + * Created At + */ + created_at: string; + /** + * Updated At + */ + updated_at: string; + /** + * Missing From Fs + */ + missing_from_fs: boolean; + /** + * Has Notes + */ + has_notes: boolean; + /** + * Siblings + */ + siblings: Array; + rom_user: RomUserSchema; + /** + * Merged Screenshots + */ + merged_screenshots: Array; + merged_ra_metadata: RomRaMetadata | null; + /** + * User Saves + */ + user_saves: Array; + /** + * User States + */ + user_states: Array; + /** + * User Screenshots + */ + user_screenshots: Array; + /** + * User Collections + */ + user_collections: Array; + /** + * All User Notes + */ + all_user_notes: Array; +}; + +/** + * GenericTaskMeta + */ +export type GenericTaskMetaWritable = { + [key: string]: unknown; +}; + +/** + * PlatformSchema + */ +export type PlatformSchemaWritable = { + /** + * Id + */ + id: number; + /** + * Slug + */ + slug: string; + /** + * Fs Slug + */ + fs_slug: string; + /** + * Rom Count + */ + rom_count: number; + /** + * Name + */ + name: string; + /** + * Igdb Slug + */ + igdb_slug: string | null; + /** + * Moby Slug + */ + moby_slug: string | null; + /** + * Hltb Slug + */ + hltb_slug: string | null; + /** + * Custom Name + */ + custom_name?: string | null; + /** + * Igdb Id + */ + igdb_id?: number | null; + /** + * Sgdb Id + */ + sgdb_id?: number | null; + /** + * Moby Id + */ + moby_id?: number | null; + /** + * Launchbox Id + */ + launchbox_id?: number | null; + /** + * Ss Id + */ + ss_id?: number | null; + /** + * Ra Id + */ + ra_id?: number | null; + /** + * Hasheous Id + */ + hasheous_id?: number | null; + /** + * Tgdb Id + */ + tgdb_id?: number | null; + /** + * Flashpoint Id + */ + flashpoint_id?: number | null; + /** + * Category + */ + category?: string | null; + /** + * Generation + */ + generation?: number | null; + /** + * Family Name + */ + family_name?: string | null; + /** + * Family Slug + */ + family_slug?: string | null; + /** + * Url + */ + url?: string | null; + /** + * Url Logo + */ + url_logo?: string | null; + /** + * Firmware + */ + firmware?: Array; + /** + * Aspect Ratio + */ + aspect_ratio?: string; + /** + * Created At + */ + created_at: string; + /** + * Updated At + */ + updated_at: string; + /** + * Fs Size Bytes + */ + fs_size_bytes: number; + /** + * Is Unidentified + */ + is_unidentified: boolean; + /** + * Is Identified + */ + is_identified: boolean; + /** + * Missing From Fs + */ + missing_from_fs: boolean; +}; + +/** + * SiblingRomSchema + */ +export type SiblingRomSchemaWritable = { + /** + * Id + */ + id: number; + /** + * Name + */ + name: string | null; + /** + * Fs Name No Tags + */ + fs_name_no_tags: string; + /** + * Fs Name No Ext + */ + fs_name_no_ext: string; +}; + +/** + * SimpleRomSchema + */ +export type SimpleRomSchemaWritable = { + /** + * Id + */ + id: number; + /** + * Igdb Id + */ + igdb_id: number | null; + /** + * Sgdb Id + */ + sgdb_id: number | null; + /** + * Moby Id + */ + moby_id: number | null; + /** + * Ss Id + */ + ss_id: number | null; + /** + * Ra Id + */ + ra_id: number | null; + /** + * Launchbox Id + */ + launchbox_id: number | null; + /** + * Hasheous Id + */ + hasheous_id: number | null; + /** + * Tgdb Id + */ + tgdb_id: number | null; + /** + * Flashpoint Id + */ + flashpoint_id: string | null; + /** + * Hltb Id + */ + hltb_id: number | null; + /** + * Gamelist Id + */ + gamelist_id: string | null; + /** + * Platform Id + */ + platform_id: number; + /** + * Platform Slug + */ + platform_slug: string; + /** + * Platform Fs Slug + */ + platform_fs_slug: string; + /** + * Platform Custom Name + */ + platform_custom_name: string | null; + /** + * Platform Display Name + */ + platform_display_name: string; + /** + * Fs Name + */ + fs_name: string; + /** + * Fs Name No Tags + */ + fs_name_no_tags: string; + /** + * Fs Name No Ext + */ + fs_name_no_ext: string; + /** + * Fs Extension + */ + fs_extension: string; + /** + * Fs Path + */ + fs_path: string; + /** + * Fs Size Bytes + */ + fs_size_bytes: number; + /** + * Name + */ + name: string | null; + /** + * Slug + */ + slug: string | null; + /** + * Summary + */ + summary: string | null; + /** + * Alternative Names + */ + alternative_names: Array; + /** + * Youtube Video Id + */ + youtube_video_id: string | null; + metadatum: RomMetadataSchema; + igdb_metadata: RomIgdbMetadata | null; + moby_metadata: RomMobyMetadata | null; + ss_metadata: RomSsMetadata | null; + launchbox_metadata: RomLaunchboxMetadata | null; + hasheous_metadata: RomHasheousMetadata | null; + flashpoint_metadata: RomFlashpointMetadata | null; + hltb_metadata: RomHltbMetadata | null; + gamelist_metadata: RomGamelistMetadata | null; + manual_metadata: ManualMetadata | null; + /** + * Path Cover Small + */ + path_cover_small: string | null; + /** + * Path Cover Large + */ + path_cover_large: string | null; + /** + * Url Cover + */ + url_cover: string | null; + /** + * Has Manual + */ + has_manual: boolean; + /** + * Path Manual + */ + path_manual: string | null; + /** + * Url Manual + */ + url_manual: string | null; + /** + * Is Identifying + */ + is_identifying?: boolean; + /** + * Is Unidentified + */ + is_unidentified: boolean; + /** + * Is Identified + */ + is_identified: boolean; + /** + * Revision + */ + revision: string | null; + /** + * Regions + */ + regions: Array; + /** + * Languages + */ + languages: Array; + /** + * Tags + */ + tags: Array; + /** + * Crc Hash + */ + crc_hash: string | null; + /** + * Md5 Hash + */ + md5_hash: string | null; + /** + * Sha1 Hash + */ + sha1_hash: string | null; + /** + * Has Simple Single File + */ + has_simple_single_file: boolean; + /** + * Has Nested Single File + */ + has_nested_single_file: boolean; + /** + * Has Multiple Files + */ + has_multiple_files: boolean; + /** + * Files + */ + files: Array; + /** + * Full Path + */ + full_path: string; + /** + * Created At + */ + created_at: string; + /** + * Updated At + */ + updated_at: string; + /** + * Missing From Fs + */ + missing_from_fs: boolean; + /** + * Has Notes + */ + has_notes: boolean; + /** + * Siblings + */ + siblings: Array; + rom_user: RomUserSchema; + /** + * Merged Screenshots + */ + merged_screenshots: Array; + merged_ra_metadata: RomRaMetadata | null; +}; + +/** + * WatcherTaskMeta + */ +export type WatcherTaskMetaWritable = { + [key: string]: unknown; +}; + +export type HeartbeatApiHeartbeatGetData = { + body?: never; + path?: never; + query?: never; + url: '/api/heartbeat'; +}; + +export type HeartbeatApiHeartbeatGetResponses = { + /** + * Successful Response + */ + 200: HeartbeatResponse; +}; + +export type HeartbeatApiHeartbeatGetResponse = HeartbeatApiHeartbeatGetResponses[keyof HeartbeatApiHeartbeatGetResponses]; + +export type MetadataHeartbeatApiHeartbeatMetadataSourceGetData = { + body?: never; + path: { + /** + * Source + */ + source: string; + }; + query?: never; + url: '/api/heartbeat/metadata/{source}'; +}; + +export type MetadataHeartbeatApiHeartbeatMetadataSourceGetErrors = { + /** + * Validation Error + */ + 422: HttpValidationError; +}; + +export type MetadataHeartbeatApiHeartbeatMetadataSourceGetError = MetadataHeartbeatApiHeartbeatMetadataSourceGetErrors[keyof MetadataHeartbeatApiHeartbeatMetadataSourceGetErrors]; + +export type MetadataHeartbeatApiHeartbeatMetadataSourceGetResponses = { + /** + * Response Metadata Heartbeat Api Heartbeat Metadata Source Get + * + * Successful Response + */ + 200: boolean; +}; + +export type MetadataHeartbeatApiHeartbeatMetadataSourceGetResponse = MetadataHeartbeatApiHeartbeatMetadataSourceGetResponses[keyof MetadataHeartbeatApiHeartbeatMetadataSourceGetResponses]; + +export type GetSetupLibraryInfoApiSetupLibraryGetData = { + body?: never; + path?: never; + query?: never; + url: '/api/setup/library'; +}; + +export type GetSetupLibraryInfoApiSetupLibraryGetResponses = { + /** + * Successful Response + */ + 200: unknown; +}; + +export type CreateSetupPlatformsApiSetupPlatformsPostData = { + /** + * Platform Slugs + */ + body: Array; + path?: never; + query?: never; + url: '/api/setup/platforms'; +}; + +export type CreateSetupPlatformsApiSetupPlatformsPostErrors = { + /** + * Validation Error + */ + 422: HttpValidationError; +}; + +export type CreateSetupPlatformsApiSetupPlatformsPostError = CreateSetupPlatformsApiSetupPlatformsPostErrors[keyof CreateSetupPlatformsApiSetupPlatformsPostErrors]; + +export type CreateSetupPlatformsApiSetupPlatformsPostResponses = { + /** + * Successful Response + */ + 201: unknown; +}; + +export type LoginApiLoginPostData = { + body?: never; + path?: never; + query?: never; + url: '/api/login'; +}; + +export type LoginApiLoginPostResponses = { + /** + * Successful Response + */ + 200: unknown; +}; + +export type LogoutApiLogoutPostData = { + body?: never; + path?: never; + query?: never; + url: '/api/logout'; +}; + +export type LogoutApiLogoutPostResponses = { + /** + * Successful Response + */ + 200: unknown; +}; + +export type TokenApiTokenPostData = { + body?: BodyTokenApiTokenPost; + path?: never; + query?: never; + url: '/api/token'; +}; + +export type TokenApiTokenPostErrors = { + /** + * Validation Error + */ + 422: HttpValidationError; +}; + +export type TokenApiTokenPostError = TokenApiTokenPostErrors[keyof TokenApiTokenPostErrors]; + +export type TokenApiTokenPostResponses = { + /** + * Successful Response + */ + 200: TokenResponse; +}; + +export type TokenApiTokenPostResponse = TokenApiTokenPostResponses[keyof TokenApiTokenPostResponses]; + +export type LoginViaOpenidApiLoginOpenidGetData = { + body?: never; + path?: never; + query?: never; + url: '/api/login/openid'; +}; + +export type LoginViaOpenidApiLoginOpenidGetResponses = { + /** + * Successful Response + */ + 200: unknown; +}; + +export type AuthOpenidApiOauthOpenidGetData = { + body?: never; + path?: never; + query?: never; + url: '/api/oauth/openid'; +}; + +export type AuthOpenidApiOauthOpenidGetResponses = { + /** + * Successful Response + */ + 200: unknown; +}; + +export type RequestPasswordResetApiForgotPasswordPostData = { + body: BodyRequestPasswordResetApiForgotPasswordPost; + path?: never; + query?: never; + url: '/api/forgot-password'; +}; + +export type RequestPasswordResetApiForgotPasswordPostErrors = { + /** + * Validation Error + */ + 422: HttpValidationError; +}; + +export type RequestPasswordResetApiForgotPasswordPostError = RequestPasswordResetApiForgotPasswordPostErrors[keyof RequestPasswordResetApiForgotPasswordPostErrors]; + +export type RequestPasswordResetApiForgotPasswordPostResponses = { + /** + * Successful Response + */ + 200: unknown; +}; + +export type ResetPasswordApiResetPasswordPostData = { + body: BodyResetPasswordApiResetPasswordPost; + path?: never; + query?: never; + url: '/api/reset-password'; +}; + +export type ResetPasswordApiResetPasswordPostErrors = { + /** + * Validation Error + */ + 422: HttpValidationError; +}; + +export type ResetPasswordApiResetPasswordPostError = ResetPasswordApiResetPasswordPostErrors[keyof ResetPasswordApiResetPasswordPostErrors]; + +export type ResetPasswordApiResetPasswordPostResponses = { + /** + * Successful Response + */ + 200: unknown; +}; + +export type GetUsersApiUsersGetData = { + body?: never; + path?: never; + query?: never; + url: '/api/users'; +}; + +export type GetUsersApiUsersGetResponses = { + /** + * Response Get Users Api Users Get + * + * Successful Response + */ + 200: Array; +}; + +export type GetUsersApiUsersGetResponse = GetUsersApiUsersGetResponses[keyof GetUsersApiUsersGetResponses]; + +export type AddUserApiUsersPostData = { + body: BodyAddUserApiUsersPost; + path?: never; + query?: never; + url: '/api/users'; +}; + +export type AddUserApiUsersPostErrors = { + /** + * Validation Error + */ + 422: HttpValidationError; +}; + +export type AddUserApiUsersPostError = AddUserApiUsersPostErrors[keyof AddUserApiUsersPostErrors]; + +export type AddUserApiUsersPostResponses = { + /** + * Successful Response + */ + 201: UserSchema; +}; + +export type AddUserApiUsersPostResponse = AddUserApiUsersPostResponses[keyof AddUserApiUsersPostResponses]; + +export type CreateInviteLinkApiUsersInviteLinkPostData = { + body?: never; + path?: never; + query: { + /** + * Role + */ + role: string; + }; + url: '/api/users/invite-link'; +}; + +export type CreateInviteLinkApiUsersInviteLinkPostErrors = { + /** + * Validation Error + */ + 422: HttpValidationError; +}; + +export type CreateInviteLinkApiUsersInviteLinkPostError = CreateInviteLinkApiUsersInviteLinkPostErrors[keyof CreateInviteLinkApiUsersInviteLinkPostErrors]; + +export type CreateInviteLinkApiUsersInviteLinkPostResponses = { + /** + * Successful Response + */ + 201: InviteLinkSchema; +}; + +export type CreateInviteLinkApiUsersInviteLinkPostResponse = CreateInviteLinkApiUsersInviteLinkPostResponses[keyof CreateInviteLinkApiUsersInviteLinkPostResponses]; + +export type CreateUserFromInviteApiUsersRegisterPostData = { + body: BodyCreateUserFromInviteApiUsersRegisterPost; + path?: never; + query?: never; + url: '/api/users/register'; +}; + +export type CreateUserFromInviteApiUsersRegisterPostErrors = { + /** + * Validation Error + */ + 422: HttpValidationError; +}; + +export type CreateUserFromInviteApiUsersRegisterPostError = CreateUserFromInviteApiUsersRegisterPostErrors[keyof CreateUserFromInviteApiUsersRegisterPostErrors]; + +export type CreateUserFromInviteApiUsersRegisterPostResponses = { + /** + * Successful Response + */ + 201: UserSchema; +}; + +export type CreateUserFromInviteApiUsersRegisterPostResponse = CreateUserFromInviteApiUsersRegisterPostResponses[keyof CreateUserFromInviteApiUsersRegisterPostResponses]; + +export type GetCurrentUserApiUsersMeGetData = { + body?: never; + path?: never; + query?: never; + url: '/api/users/me'; +}; + +export type GetCurrentUserApiUsersMeGetResponses = { + /** + * Response Get Current User Api Users Me Get + * + * Successful Response + */ + 200: UserSchema | null; +}; + +export type GetCurrentUserApiUsersMeGetResponse = GetCurrentUserApiUsersMeGetResponses[keyof GetCurrentUserApiUsersMeGetResponses]; + +export type DeleteUserApiUsersIdDeleteData = { + body?: never; + path: { + /** + * Id + * + * User internal id. + */ + id: number; + }; + query?: never; + url: '/api/users/{id}'; +}; + +export type DeleteUserApiUsersIdDeleteErrors = { + /** + * Bad Request + */ + 400: unknown; + /** + * Not Found + */ + 404: unknown; + /** + * Validation Error + */ + 422: HttpValidationError; +}; + +export type DeleteUserApiUsersIdDeleteError = DeleteUserApiUsersIdDeleteErrors[keyof DeleteUserApiUsersIdDeleteErrors]; + +export type DeleteUserApiUsersIdDeleteResponses = { + /** + * Successful Response + */ + 200: unknown; +}; + +export type GetUserApiUsersIdGetData = { + body?: never; + path: { + /** + * Id + */ + id: number; + }; + query?: never; + url: '/api/users/{id}'; +}; + +export type GetUserApiUsersIdGetErrors = { + /** + * Validation Error + */ + 422: HttpValidationError; +}; + +export type GetUserApiUsersIdGetError = GetUserApiUsersIdGetErrors[keyof GetUserApiUsersIdGetErrors]; + +export type GetUserApiUsersIdGetResponses = { + /** + * Successful Response + */ + 200: UserSchema; +}; + +export type GetUserApiUsersIdGetResponse = GetUserApiUsersIdGetResponses[keyof GetUserApiUsersIdGetResponses]; + +export type UpdateUserApiUsersIdPutData = { + body: UserForm; + path: { + /** + * Id + */ + id: number; + }; + query?: never; + url: '/api/users/{id}'; +}; + +export type UpdateUserApiUsersIdPutErrors = { + /** + * Validation Error + */ + 422: HttpValidationError; +}; + +export type UpdateUserApiUsersIdPutError = UpdateUserApiUsersIdPutErrors[keyof UpdateUserApiUsersIdPutErrors]; + +export type UpdateUserApiUsersIdPutResponses = { + /** + * Successful Response + */ + 200: UserSchema; +}; + +export type UpdateUserApiUsersIdPutResponse = UpdateUserApiUsersIdPutResponses[keyof UpdateUserApiUsersIdPutResponses]; + +export type RefreshRetroAchievementsApiUsersIdRaRefreshPostData = { + body?: BodyRefreshRetroAchievementsApiUsersIdRaRefreshPost; + path: { + /** + * Id + * + * User internal id. + */ + id: number; + }; + query?: never; + url: '/api/users/{id}/ra/refresh'; +}; + +export type RefreshRetroAchievementsApiUsersIdRaRefreshPostErrors = { + /** + * Not Found + */ + 404: unknown; + /** + * Validation Error + */ + 422: HttpValidationError; +}; + +export type RefreshRetroAchievementsApiUsersIdRaRefreshPostError = RefreshRetroAchievementsApiUsersIdRaRefreshPostErrors[keyof RefreshRetroAchievementsApiUsersIdRaRefreshPostErrors]; + +export type RefreshRetroAchievementsApiUsersIdRaRefreshPostResponses = { + /** + * Successful Response + */ + 200: unknown; +}; + +export type GetPlatformsApiPlatformsGetData = { + body?: never; + path?: never; + query?: { + /** + * Updated After + * + * Filter platforms updated after this datetime (ISO 8601 format with timezone information). + */ + updated_after?: string | null; + }; + url: '/api/platforms'; +}; + +export type GetPlatformsApiPlatformsGetErrors = { + /** + * Validation Error + */ + 422: HttpValidationError; +}; + +export type GetPlatformsApiPlatformsGetError = GetPlatformsApiPlatformsGetErrors[keyof GetPlatformsApiPlatformsGetErrors]; + +export type GetPlatformsApiPlatformsGetResponses = { + /** + * Response Get Platforms Api Platforms Get + * + * Successful Response + */ + 200: Array; +}; + +export type GetPlatformsApiPlatformsGetResponse = GetPlatformsApiPlatformsGetResponses[keyof GetPlatformsApiPlatformsGetResponses]; + +export type AddPlatformApiPlatformsPostData = { + body: BodyAddPlatformApiPlatformsPost; + path?: never; + query?: never; + url: '/api/platforms'; +}; + +export type AddPlatformApiPlatformsPostErrors = { + /** + * Validation Error + */ + 422: HttpValidationError; +}; + +export type AddPlatformApiPlatformsPostError = AddPlatformApiPlatformsPostErrors[keyof AddPlatformApiPlatformsPostErrors]; + +export type AddPlatformApiPlatformsPostResponses = { + /** + * Successful Response + */ + 201: PlatformSchema; +}; + +export type AddPlatformApiPlatformsPostResponse = AddPlatformApiPlatformsPostResponses[keyof AddPlatformApiPlatformsPostResponses]; + +export type GetSupportedPlatformsEndpointApiPlatformsSupportedGetData = { + body?: never; + path?: never; + query?: never; + url: '/api/platforms/supported'; +}; + +export type GetSupportedPlatformsEndpointApiPlatformsSupportedGetResponses = { + /** + * Response Get Supported Platforms Endpoint Api Platforms Supported Get + * + * Successful Response + */ + 200: Array; +}; + +export type GetSupportedPlatformsEndpointApiPlatformsSupportedGetResponse = GetSupportedPlatformsEndpointApiPlatformsSupportedGetResponses[keyof GetSupportedPlatformsEndpointApiPlatformsSupportedGetResponses]; + +export type DeletePlatformApiPlatformsIdDeleteData = { + body?: never; + path: { + /** + * Id + * + * Platform id. + */ + id: number; + }; + query?: never; + url: '/api/platforms/{id}'; +}; + +export type DeletePlatformApiPlatformsIdDeleteErrors = { + /** + * Not Found + */ + 404: unknown; + /** + * Validation Error + */ + 422: HttpValidationError; +}; + +export type DeletePlatformApiPlatformsIdDeleteError = DeletePlatformApiPlatformsIdDeleteErrors[keyof DeletePlatformApiPlatformsIdDeleteErrors]; + +export type DeletePlatformApiPlatformsIdDeleteResponses = { + /** + * Successful Response + */ + 200: unknown; +}; + +export type GetPlatformApiPlatformsIdGetData = { + body?: never; + path: { + /** + * Id + * + * Platform id. + */ + id: number; + }; + query?: never; + url: '/api/platforms/{id}'; +}; + +export type GetPlatformApiPlatformsIdGetErrors = { + /** + * Not Found + */ + 404: unknown; + /** + * Validation Error + */ + 422: HttpValidationError; +}; + +export type GetPlatformApiPlatformsIdGetError = GetPlatformApiPlatformsIdGetErrors[keyof GetPlatformApiPlatformsIdGetErrors]; + +export type GetPlatformApiPlatformsIdGetResponses = { + /** + * Successful Response + */ + 200: PlatformSchema; +}; + +export type GetPlatformApiPlatformsIdGetResponse = GetPlatformApiPlatformsIdGetResponses[keyof GetPlatformApiPlatformsIdGetResponses]; + +export type UpdatePlatformApiPlatformsIdPutData = { + body?: BodyUpdatePlatformApiPlatformsIdPut; + path: { + /** + * Id + * + * Platform id. + */ + id: number; + }; + query?: never; + url: '/api/platforms/{id}'; +}; + +export type UpdatePlatformApiPlatformsIdPutErrors = { + /** + * Not Found + */ + 404: unknown; + /** + * Validation Error + */ + 422: HttpValidationError; +}; + +export type UpdatePlatformApiPlatformsIdPutError = UpdatePlatformApiPlatformsIdPutErrors[keyof UpdatePlatformApiPlatformsIdPutErrors]; + +export type UpdatePlatformApiPlatformsIdPutResponses = { + /** + * Successful Response + */ + 200: PlatformSchema; +}; + +export type UpdatePlatformApiPlatformsIdPutResponse = UpdatePlatformApiPlatformsIdPutResponses[keyof UpdatePlatformApiPlatformsIdPutResponses]; + +export type GetRomsApiRomsGetData = { + body?: never; + path?: never; + query?: { + /** + * With Char Index + * + * Whether to get the char index. + */ + with_char_index?: boolean; + /** + * With Filter Values + * + * Whether to return filter values. + */ + with_filter_values?: boolean; + /** + * Search Term + * + * Search term to filter roms. + */ + search_term?: string | null; + /** + * Platform Ids + * + * Platform internal ids. Multiple values are allowed by repeating the parameter, and results that match any of the values will be returned. + */ + platform_ids?: Array | null; + /** + * Collection Id + * + * Collection internal id. + */ + collection_id?: number | null; + /** + * Virtual Collection Id + * + * Virtual collection internal id. + */ + virtual_collection_id?: string | null; + /** + * Smart Collection Id + * + * Smart collection internal id. + */ + smart_collection_id?: number | null; + /** + * Matched + * + * Whether the rom matched at least one metadata source. + */ + matched?: boolean | null; + /** + * Favorite + * + * Whether the rom is marked as favorite. + */ + favorite?: boolean | null; + /** + * Duplicate + * + * Whether the rom is marked as duplicate. + */ + duplicate?: boolean | null; + /** + * Last Played + * + * Whether the rom has a last played value for the current user. + */ + last_played?: boolean | null; + /** + * Playable + * + * Whether the rom is playable from the browser. + */ + playable?: boolean | null; + /** + * Missing + * + * Whether the rom is missing from the filesystem. + */ + missing?: boolean | null; + /** + * Has Ra + * + * Whether the rom has RetroAchievements data. + */ + has_ra?: boolean | null; + /** + * Verified + * + * Whether the rom is verified by Hasheous. + */ + verified?: boolean | null; + /** + * Group By Meta Id + * + * Whether to group roms by metadata ID (IGDB / Moby / ScreenScraper / RetroAchievements / LaunchBox). + */ + group_by_meta_id?: boolean; + /** + * Genres + * + * Associated genre. Multiple values are allowed by repeating the parameter, and results that match any of the values will be returned. + */ + genres?: Array | null; + /** + * Franchises + * + * Associated franchise. Multiple values are allowed by repeating the parameter, and results that match any of the values will be returned. + */ + franchises?: Array | null; + /** + * Collections + * + * Associated collection. Multiple values are allowed by repeating the parameter, and results that match any of the values will be returned. + */ + collections?: Array | null; + /** + * Companies + * + * Associated company. Multiple values are allowed by repeating the parameter, and results that match any of the values will be returned. + */ + companies?: Array | null; + /** + * Age Ratings + * + * Associated age rating. Multiple values are allowed by repeating the parameter, and results that match any of the values will be returned. + */ + age_ratings?: Array | null; + /** + * Statuses + * + * Game status, set by the current user. Multiple values are allowed by repeating the parameter, and results that match any of the values will be returned. + */ + statuses?: Array | null; + /** + * Regions + * + * Associated region tag. Multiple values are allowed by repeating the parameter, and results that match any of the values will be returned. + */ + regions?: Array | null; + /** + * Languages + * + * Associated language tag. Multiple values are allowed by repeating the parameter, and results that match any of the values will be returned. + */ + languages?: Array | null; + /** + * Player Counts + * + * Associated player count. Multiple values are allowed by repeating the parameter, and results that match any of the values will be returned. + */ + player_counts?: Array | null; + /** + * Genres Logic + * + * Logic operator for genres filter: 'any' (OR), 'all' (AND) or 'none' (NOT). + */ + genres_logic?: string; + /** + * Franchises Logic + * + * Logic operator for franchises filter: 'any' (OR), 'all' (AND) or 'none' (NOT). + */ + franchises_logic?: string; + /** + * Collections Logic + * + * Logic operator for collections filter: 'any' (OR), 'all' (AND) or 'none' (NOT). + */ + collections_logic?: string; + /** + * Companies Logic + * + * Logic operator for companies filter: 'any' (OR), 'all' (AND) or 'none' (NOT). + */ + companies_logic?: string; + /** + * Age Ratings Logic + * + * Logic operator for age ratings filter: 'any' (OR), 'all' (AND) or 'none' (NOT). + */ + age_ratings_logic?: string; + /** + * Regions Logic + * + * Logic operator for regions filter: 'any' (OR), 'all' (AND) or 'none' (NOT). + */ + regions_logic?: string; + /** + * Languages Logic + * + * Logic operator for languages filter: 'any' (OR), 'all' (AND) or 'none' (NOT). + */ + languages_logic?: string; + /** + * Statuses Logic + * + * Logic operator for statuses filter: 'any' (OR), 'all' (AND) or 'none' (NOT). + */ + statuses_logic?: string; + /** + * Player Counts Logic + * + * Logic operator for player counts filter: 'any' (OR), 'all' (AND) or 'none' (NOT). + */ + player_counts_logic?: string; + /** + * Order By + * + * Field to order results by. + */ + order_by?: string; + /** + * Order Dir + * + * Order direction, either 'asc' or 'desc'. + */ + order_dir?: string; + /** + * Updated After + * + * Filter roms updated after this datetime (ISO 8601 format with timezone information). + */ + updated_after?: string | null; + /** + * Limit + * + * Page size limit + */ + limit?: number; + /** + * Offset + * + * Page offset + */ + offset?: number; + }; + url: '/api/roms'; +}; + +export type GetRomsApiRomsGetErrors = { + /** + * Validation Error + */ + 422: HttpValidationError; +}; + +export type GetRomsApiRomsGetError = GetRomsApiRomsGetErrors[keyof GetRomsApiRomsGetErrors]; + +export type GetRomsApiRomsGetResponses = { + /** + * Successful Response + */ + 200: CustomLimitOffsetPageSimpleRomSchema; +}; + +export type GetRomsApiRomsGetResponse = GetRomsApiRomsGetResponses[keyof GetRomsApiRomsGetResponses]; + +export type AddRomApiRomsPostData = { + body?: never; + headers: { + /** + * X-Upload-Platform + * + * Platform internal id. + */ + 'x-upload-platform': number; + /** + * X-Upload-Filename + * + * The name of the file being uploaded. + */ + 'x-upload-filename': string; + }; + path?: never; + query?: never; + url: '/api/roms'; +}; + +export type AddRomApiRomsPostErrors = { + /** + * Bad Request + */ + 400: unknown; + /** + * Validation Error + */ + 422: HttpValidationError; +}; + +export type AddRomApiRomsPostError = AddRomApiRomsPostErrors[keyof AddRomApiRomsPostErrors]; + +export type AddRomApiRomsPostResponses = { + /** + * Successful Response + */ + 201: unknown; +}; + +export type DownloadRomsApiRomsDownloadGetData = { + body?: never; + path?: never; + query: { + /** + * Rom Ids + * + * Comma-separated list of ROM IDs to download as a zip file. + */ + rom_ids: string; + /** + * Filename + * + * Name for the zip file (optional). + */ + filename?: string | null; + }; + url: '/api/roms/download'; +}; + +export type DownloadRomsApiRomsDownloadGetErrors = { + /** + * Validation Error + */ + 422: HttpValidationError; +}; + +export type DownloadRomsApiRomsDownloadGetError = DownloadRomsApiRomsDownloadGetErrors[keyof DownloadRomsApiRomsDownloadGetErrors]; + +export type DownloadRomsApiRomsDownloadGetResponses = { + /** + * Successful Response + */ + 200: unknown; +}; + +export type GetRomByMetadataProviderApiRomsByMetadataProviderGetData = { + body?: never; + path?: never; + query?: { + /** + * Igdb Id + * + * IGDB ID to search by + */ + igdb_id?: number | null; + /** + * Moby Id + * + * MobyGames ID to search by + */ + moby_id?: number | null; + /** + * Ss Id + * + * ScreenScraper ID to search by + */ + ss_id?: number | null; + /** + * Ra Id + * + * RetroAchievements ID to search by + */ + ra_id?: number | null; + /** + * Launchbox Id + * + * LaunchBox ID to search by + */ + launchbox_id?: number | null; + /** + * Hasheous Id + * + * Hasheous ID to search by + */ + hasheous_id?: number | null; + /** + * Tgdb Id + * + * TGDB ID to search by + */ + tgdb_id?: number | null; + /** + * Flashpoint Id + * + * Flashpoint ID to search by + */ + flashpoint_id?: string | null; + /** + * Hltb Id + * + * HLTB ID to search by + */ + hltb_id?: number | null; + }; + url: '/api/roms/by-metadata-provider'; +}; + +export type GetRomByMetadataProviderApiRomsByMetadataProviderGetErrors = { + /** + * Bad Request + */ + 400: unknown; + /** + * Not Found + */ + 404: unknown; + /** + * Validation Error + */ + 422: HttpValidationError; +}; + +export type GetRomByMetadataProviderApiRomsByMetadataProviderGetError = GetRomByMetadataProviderApiRomsByMetadataProviderGetErrors[keyof GetRomByMetadataProviderApiRomsByMetadataProviderGetErrors]; + +export type GetRomByMetadataProviderApiRomsByMetadataProviderGetResponses = { + /** + * Successful Response + */ + 200: DetailedRomSchema; +}; + +export type GetRomByMetadataProviderApiRomsByMetadataProviderGetResponse = GetRomByMetadataProviderApiRomsByMetadataProviderGetResponses[keyof GetRomByMetadataProviderApiRomsByMetadataProviderGetResponses]; + +export type GetRomByHashApiRomsByHashGetData = { + body?: never; + path?: never; + query?: { + /** + * Crc Hash + * + * CRC hash value + */ + crc_hash?: string | null; + /** + * Md5 Hash + * + * MD5 hash value + */ + md5_hash?: string | null; + /** + * Sha1 Hash + * + * SHA1 hash value + */ + sha1_hash?: string | null; + }; + url: '/api/roms/by-hash'; +}; + +export type GetRomByHashApiRomsByHashGetErrors = { + /** + * Bad Request + */ + 400: unknown; + /** + * Not Found + */ + 404: unknown; + /** + * Validation Error + */ + 422: HttpValidationError; +}; + +export type GetRomByHashApiRomsByHashGetError = GetRomByHashApiRomsByHashGetErrors[keyof GetRomByHashApiRomsByHashGetErrors]; + +export type GetRomByHashApiRomsByHashGetResponses = { + /** + * Successful Response + */ + 200: DetailedRomSchema; +}; + +export type GetRomByHashApiRomsByHashGetResponse = GetRomByHashApiRomsByHashGetResponses[keyof GetRomByHashApiRomsByHashGetResponses]; + +export type GetRomFiltersApiRomsFiltersGetData = { + body?: never; + path?: never; + query?: never; + url: '/api/roms/filters'; +}; + +export type GetRomFiltersApiRomsFiltersGetResponses = { + /** + * Successful Response + */ + 200: RomFiltersDict; +}; + +export type GetRomFiltersApiRomsFiltersGetResponse = GetRomFiltersApiRomsFiltersGetResponses[keyof GetRomFiltersApiRomsFiltersGetResponses]; + +export type GetRomApiRomsIdGetData = { + body?: never; + path: { + /** + * Id + * + * Rom internal id. + */ + id: number; + }; + query?: never; + url: '/api/roms/{id}'; +}; + +export type GetRomApiRomsIdGetErrors = { + /** + * Not Found + */ + 404: unknown; + /** + * Validation Error + */ + 422: HttpValidationError; +}; + +export type GetRomApiRomsIdGetError = GetRomApiRomsIdGetErrors[keyof GetRomApiRomsIdGetErrors]; + +export type GetRomApiRomsIdGetResponses = { + /** + * Successful Response + */ + 200: DetailedRomSchema; +}; + +export type GetRomApiRomsIdGetResponse = GetRomApiRomsIdGetResponses[keyof GetRomApiRomsIdGetResponses]; + +export type UpdateRomApiRomsIdPutData = { + body?: BodyUpdateRomApiRomsIdPut; + path: { + /** + * Id + * + * Rom internal id. + */ + id: number; + }; + query?: { + /** + * Remove Cover + * + * Whether to remove the cover image for this rom. + */ + remove_cover?: boolean; + /** + * Unmatch Metadata + * + * Whether to remove the metadata matches for this game. + */ + unmatch_metadata?: boolean; + }; + url: '/api/roms/{id}'; +}; + +export type UpdateRomApiRomsIdPutErrors = { + /** + * Not Found + */ + 404: unknown; + /** + * Validation Error + */ + 422: HttpValidationError; +}; + +export type UpdateRomApiRomsIdPutError = UpdateRomApiRomsIdPutErrors[keyof UpdateRomApiRomsIdPutErrors]; + +export type UpdateRomApiRomsIdPutResponses = { + /** + * Successful Response + */ + 200: DetailedRomSchema; +}; + +export type UpdateRomApiRomsIdPutResponse = UpdateRomApiRomsIdPutResponses[keyof UpdateRomApiRomsIdPutResponses]; + +export type GetRomContentApiRomsIdContentFileNameGetData = { + body?: never; + path: { + /** + * Id + * + * Rom internal id. + */ + id: number; + /** + * File Name + * + * Zip file output name + */ + file_name: string; + }; + query?: { + /** + * File Ids + * + * Comma-separated list of file ids to download for multi-part roms. + */ + file_ids?: string | null; + }; + url: '/api/roms/{id}/content/{file_name}'; +}; + +export type GetRomContentApiRomsIdContentFileNameGetErrors = { + /** + * Not Found + */ + 404: unknown; + /** + * Validation Error + */ + 422: HttpValidationError; +}; + +export type GetRomContentApiRomsIdContentFileNameGetError = GetRomContentApiRomsIdContentFileNameGetErrors[keyof GetRomContentApiRomsIdContentFileNameGetErrors]; + +export type GetRomContentApiRomsIdContentFileNameGetResponses = { + /** + * Successful Response + */ + 200: unknown; +}; + +export type HeadRomContentApiRomsIdContentFileNameHeadData = { + body?: never; + path: { + /** + * Id + * + * Rom internal id. + */ + id: number; + /** + * File Name + * + * File name to download + */ + file_name: string; + }; + query?: { + /** + * File Ids + * + * Comma-separated list of file ids to download for multi-part roms. + */ + file_ids?: string | null; + }; + url: '/api/roms/{id}/content/{file_name}'; +}; + +export type HeadRomContentApiRomsIdContentFileNameHeadErrors = { + /** + * Not Found + */ + 404: unknown; + /** + * Validation Error + */ + 422: HttpValidationError; +}; + +export type HeadRomContentApiRomsIdContentFileNameHeadError = HeadRomContentApiRomsIdContentFileNameHeadErrors[keyof HeadRomContentApiRomsIdContentFileNameHeadErrors]; + +export type HeadRomContentApiRomsIdContentFileNameHeadResponses = { + /** + * Successful Response + */ + 200: unknown; +}; + +export type DeleteRomManualsApiRomsIdManualsDeleteData = { + body?: never; + path: { + /** + * Id + * + * Rom internal id. + */ + id: number; + }; + query?: never; + url: '/api/roms/{id}/manuals'; +}; + +export type DeleteRomManualsApiRomsIdManualsDeleteErrors = { + /** + * Not Found + */ + 404: unknown; + /** + * Validation Error + */ + 422: HttpValidationError; +}; + +export type DeleteRomManualsApiRomsIdManualsDeleteError = DeleteRomManualsApiRomsIdManualsDeleteErrors[keyof DeleteRomManualsApiRomsIdManualsDeleteErrors]; + +export type DeleteRomManualsApiRomsIdManualsDeleteResponses = { + /** + * Successful Response + */ + 200: unknown; +}; + +export type AddRomManualsApiRomsIdManualsPostData = { + body?: never; + headers: { + /** + * X-Upload-Filename + * + * The name of the file being uploaded. + */ + 'x-upload-filename': string; + }; + path: { + /** + * Id + * + * Rom internal id. + */ + id: number; + }; + query?: never; + url: '/api/roms/{id}/manuals'; +}; + +export type AddRomManualsApiRomsIdManualsPostErrors = { + /** + * Not Found + */ + 404: unknown; + /** + * Validation Error + */ + 422: HttpValidationError; +}; + +export type AddRomManualsApiRomsIdManualsPostError = AddRomManualsApiRomsIdManualsPostErrors[keyof AddRomManualsApiRomsIdManualsPostErrors]; + +export type AddRomManualsApiRomsIdManualsPostResponses = { + /** + * Successful Response + */ + 201: unknown; +}; + +export type DeleteRomsApiRomsDeletePostData = { + body: BodyDeleteRomsApiRomsDeletePost; + path?: never; + query?: never; + url: '/api/roms/delete'; +}; + +export type DeleteRomsApiRomsDeletePostErrors = { + /** + * Not Found + */ + 404: unknown; + /** + * Validation Error + */ + 422: HttpValidationError; +}; + +export type DeleteRomsApiRomsDeletePostError = DeleteRomsApiRomsDeletePostErrors[keyof DeleteRomsApiRomsDeletePostErrors]; + +export type DeleteRomsApiRomsDeletePostResponses = { + /** + * Successful Response + */ + 200: BulkOperationResponse; +}; + +export type DeleteRomsApiRomsDeletePostResponse = DeleteRomsApiRomsDeletePostResponses[keyof DeleteRomsApiRomsDeletePostResponses]; + +export type UpdateRomUserApiRomsIdPropsPutData = { + body?: BodyUpdateRomUserApiRomsIdPropsPut; + path: { + /** + * Id + * + * Rom internal id. + */ + id: number; + }; + query?: never; + url: '/api/roms/{id}/props'; +}; + +export type UpdateRomUserApiRomsIdPropsPutErrors = { + /** + * Not Found + */ + 404: unknown; + /** + * Validation Error + */ + 422: HttpValidationError; +}; + +export type UpdateRomUserApiRomsIdPropsPutError = UpdateRomUserApiRomsIdPropsPutErrors[keyof UpdateRomUserApiRomsIdPropsPutErrors]; + +export type UpdateRomUserApiRomsIdPropsPutResponses = { + /** + * Successful Response + */ + 200: RomUserSchema; +}; + +export type UpdateRomUserApiRomsIdPropsPutResponse = UpdateRomUserApiRomsIdPropsPutResponses[keyof UpdateRomUserApiRomsIdPropsPutResponses]; + +export type GetRomfileApiRomsFilesIdGetData = { + body?: never; + path: { + /** + * Id + * + * Rom file internal id. + */ + id: number; + }; + query?: never; + url: '/api/roms/files/{id}'; +}; + +export type GetRomfileApiRomsFilesIdGetErrors = { + /** + * Not Found + */ + 404: unknown; + /** + * Validation Error + */ + 422: HttpValidationError; +}; + +export type GetRomfileApiRomsFilesIdGetError = GetRomfileApiRomsFilesIdGetErrors[keyof GetRomfileApiRomsFilesIdGetErrors]; + +export type GetRomfileApiRomsFilesIdGetResponses = { + /** + * Successful Response + */ + 200: RomFileSchema; +}; + +export type GetRomfileApiRomsFilesIdGetResponse = GetRomfileApiRomsFilesIdGetResponses[keyof GetRomfileApiRomsFilesIdGetResponses]; + +export type GetRomfileContentApiRomsfilesIdContentFileNameGetData = { + body?: never; + path: { + /** + * Id + * + * Rom file internal id. + */ + id: number; + /** + * File Name + * + * File name to download + */ + file_name: string; + }; + query?: never; + url: '/api/romsfiles/{id}/content/{file_name}'; +}; + +export type GetRomfileContentApiRomsfilesIdContentFileNameGetErrors = { + /** + * Not Found + */ + 404: unknown; + /** + * Validation Error + */ + 422: HttpValidationError; +}; + +export type GetRomfileContentApiRomsfilesIdContentFileNameGetError = GetRomfileContentApiRomsfilesIdContentFileNameGetErrors[keyof GetRomfileContentApiRomsfilesIdContentFileNameGetErrors]; + +export type GetRomfileContentApiRomsfilesIdContentFileNameGetResponses = { + /** + * Successful Response + */ + 200: unknown; +}; + +export type GetRomNotesApiRomsIdNotesGetData = { + body?: never; + path: { + /** + * Id + * + * Rom internal id. + */ + id: number; + }; + query?: { + /** + * Public Only + * + * Only return public notes + */ + public_only?: boolean; + /** + * Search + * + * Search notes by title or content + */ + search?: string; + /** + * Tags + * + * Filter by tags + */ + tags?: Array; + }; + url: '/api/roms/{id}/notes'; +}; + +export type GetRomNotesApiRomsIdNotesGetErrors = { + /** + * Not Found + */ + 404: unknown; + /** + * Validation Error + */ + 422: HttpValidationError; +}; + +export type GetRomNotesApiRomsIdNotesGetError = GetRomNotesApiRomsIdNotesGetErrors[keyof GetRomNotesApiRomsIdNotesGetErrors]; + +export type GetRomNotesApiRomsIdNotesGetResponses = { + /** + * Response Get Rom Notes Api Roms Id Notes Get + * + * Successful Response + */ + 200: Array; +}; + +export type GetRomNotesApiRomsIdNotesGetResponse = GetRomNotesApiRomsIdNotesGetResponses[keyof GetRomNotesApiRomsIdNotesGetResponses]; + +export type CreateRomNoteApiRomsIdNotesPostData = { + /** + * Note Data + */ + body: { + [key: string]: unknown; + }; + path: { + /** + * Id + * + * Rom internal id. + */ + id: number; + }; + query?: never; + url: '/api/roms/{id}/notes'; +}; + +export type CreateRomNoteApiRomsIdNotesPostErrors = { + /** + * Not Found + */ + 404: unknown; + /** + * Validation Error + */ + 422: HttpValidationError; +}; + +export type CreateRomNoteApiRomsIdNotesPostError = CreateRomNoteApiRomsIdNotesPostErrors[keyof CreateRomNoteApiRomsIdNotesPostErrors]; + +export type CreateRomNoteApiRomsIdNotesPostResponses = { + /** + * Successful Response + */ + 200: UserNoteSchema; +}; + +export type CreateRomNoteApiRomsIdNotesPostResponse = CreateRomNoteApiRomsIdNotesPostResponses[keyof CreateRomNoteApiRomsIdNotesPostResponses]; + +export type DeleteRomNoteApiRomsIdNotesNoteIdDeleteData = { + body?: never; + path: { + /** + * Id + * + * Rom internal id. + */ + id: number; + /** + * Note Id + * + * Note id. + */ + note_id: number; + }; + query?: never; + url: '/api/roms/{id}/notes/{note_id}'; +}; + +export type DeleteRomNoteApiRomsIdNotesNoteIdDeleteErrors = { + /** + * Not Found + */ + 404: unknown; + /** + * Validation Error + */ + 422: HttpValidationError; +}; + +export type DeleteRomNoteApiRomsIdNotesNoteIdDeleteError = DeleteRomNoteApiRomsIdNotesNoteIdDeleteErrors[keyof DeleteRomNoteApiRomsIdNotesNoteIdDeleteErrors]; + +export type DeleteRomNoteApiRomsIdNotesNoteIdDeleteResponses = { + /** + * Response Delete Rom Note Api Roms Id Notes Note Id Delete + * + * Successful Response + */ + 200: { + [key: string]: unknown; + }; +}; + +export type DeleteRomNoteApiRomsIdNotesNoteIdDeleteResponse = DeleteRomNoteApiRomsIdNotesNoteIdDeleteResponses[keyof DeleteRomNoteApiRomsIdNotesNoteIdDeleteResponses]; + +export type UpdateRomNoteApiRomsIdNotesNoteIdPutData = { + /** + * Note Data + */ + body: { + [key: string]: unknown; + }; + path: { + /** + * Id + * + * Rom internal id. + */ + id: number; + /** + * Note Id + * + * Note id. + */ + note_id: number; + }; + query?: never; + url: '/api/roms/{id}/notes/{note_id}'; +}; + +export type UpdateRomNoteApiRomsIdNotesNoteIdPutErrors = { + /** + * Not Found + */ + 404: unknown; + /** + * Validation Error + */ + 422: HttpValidationError; +}; + +export type UpdateRomNoteApiRomsIdNotesNoteIdPutError = UpdateRomNoteApiRomsIdNotesNoteIdPutErrors[keyof UpdateRomNoteApiRomsIdNotesNoteIdPutErrors]; + +export type UpdateRomNoteApiRomsIdNotesNoteIdPutResponses = { + /** + * Successful Response + */ + 200: UserNoteSchema; +}; + +export type UpdateRomNoteApiRomsIdNotesNoteIdPutResponse = UpdateRomNoteApiRomsIdNotesNoteIdPutResponses[keyof UpdateRomNoteApiRomsIdNotesNoteIdPutResponses]; + +export type SearchRomApiSearchRomsGetData = { + body?: never; + path?: never; + query: { + /** + * Rom Id + */ + rom_id: number; + /** + * Search Term + */ + search_term?: string | null; + /** + * Search By + */ + search_by?: string; + }; + url: '/api/search/roms'; +}; + +export type SearchRomApiSearchRomsGetErrors = { + /** + * Validation Error + */ + 422: HttpValidationError; +}; + +export type SearchRomApiSearchRomsGetError = SearchRomApiSearchRomsGetErrors[keyof SearchRomApiSearchRomsGetErrors]; + +export type SearchRomApiSearchRomsGetResponses = { + /** + * Response Search Rom Api Search Roms Get + * + * Successful Response + */ + 200: Array; +}; + +export type SearchRomApiSearchRomsGetResponse = SearchRomApiSearchRomsGetResponses[keyof SearchRomApiSearchRomsGetResponses]; + +export type SearchCoverApiSearchCoverGetData = { + body?: never; + path?: never; + query?: { + /** + * Search Term + */ + search_term?: string; + }; + url: '/api/search/cover'; +}; + +export type SearchCoverApiSearchCoverGetErrors = { + /** + * Validation Error + */ + 422: HttpValidationError; +}; + +export type SearchCoverApiSearchCoverGetError = SearchCoverApiSearchCoverGetErrors[keyof SearchCoverApiSearchCoverGetErrors]; + +export type SearchCoverApiSearchCoverGetResponses = { + /** + * Response Search Cover Api Search Cover Get + * + * Successful Response + */ + 200: Array; +}; + +export type SearchCoverApiSearchCoverGetResponse = SearchCoverApiSearchCoverGetResponses[keyof SearchCoverApiSearchCoverGetResponses]; + +export type GetSavesApiSavesGetData = { + body?: never; + path?: never; + query?: { + /** + * Rom Id + */ + rom_id?: number | null; + /** + * Platform Id + */ + platform_id?: number | null; + }; + url: '/api/saves'; +}; + +export type GetSavesApiSavesGetErrors = { + /** + * Validation Error + */ + 422: HttpValidationError; +}; + +export type GetSavesApiSavesGetError = GetSavesApiSavesGetErrors[keyof GetSavesApiSavesGetErrors]; + +export type GetSavesApiSavesGetResponses = { + /** + * Response Get Saves Api Saves Get + * + * Successful Response + */ + 200: Array; +}; + +export type GetSavesApiSavesGetResponse = GetSavesApiSavesGetResponses[keyof GetSavesApiSavesGetResponses]; + +export type AddSaveApiSavesPostData = { + body?: never; + path?: never; + query: { + /** + * Rom Id + */ + rom_id: number; + /** + * Emulator + */ + emulator?: string | null; + }; + url: '/api/saves'; +}; + +export type AddSaveApiSavesPostErrors = { + /** + * Validation Error + */ + 422: HttpValidationError; +}; + +export type AddSaveApiSavesPostError = AddSaveApiSavesPostErrors[keyof AddSaveApiSavesPostErrors]; + +export type AddSaveApiSavesPostResponses = { + /** + * Successful Response + */ + 200: SaveSchema; +}; + +export type AddSaveApiSavesPostResponse = AddSaveApiSavesPostResponses[keyof AddSaveApiSavesPostResponses]; + +export type GetSaveApiSavesIdGetData = { + body?: never; + path: { + /** + * Id + */ + id: number; + }; + query?: never; + url: '/api/saves/{id}'; +}; + +export type GetSaveApiSavesIdGetErrors = { + /** + * Validation Error + */ + 422: HttpValidationError; +}; + +export type GetSaveApiSavesIdGetError = GetSaveApiSavesIdGetErrors[keyof GetSaveApiSavesIdGetErrors]; + +export type GetSaveApiSavesIdGetResponses = { + /** + * Successful Response + */ + 200: SaveSchema; +}; + +export type GetSaveApiSavesIdGetResponse = GetSaveApiSavesIdGetResponses[keyof GetSaveApiSavesIdGetResponses]; + +export type UpdateSaveApiSavesIdPutData = { + body?: never; + path: { + /** + * Id + */ + id: number; + }; + query?: never; + url: '/api/saves/{id}'; +}; + +export type UpdateSaveApiSavesIdPutErrors = { + /** + * Validation Error + */ + 422: HttpValidationError; +}; + +export type UpdateSaveApiSavesIdPutError = UpdateSaveApiSavesIdPutErrors[keyof UpdateSaveApiSavesIdPutErrors]; + +export type UpdateSaveApiSavesIdPutResponses = { + /** + * Successful Response + */ + 200: SaveSchema; +}; + +export type UpdateSaveApiSavesIdPutResponse = UpdateSaveApiSavesIdPutResponses[keyof UpdateSaveApiSavesIdPutResponses]; + +export type DeleteSavesApiSavesDeletePostData = { + body: BodyDeleteSavesApiSavesDeletePost; + path?: never; + query?: never; + url: '/api/saves/delete'; +}; + +export type DeleteSavesApiSavesDeletePostErrors = { + /** + * Bad Request + */ + 400: unknown; + /** + * Not Found + */ + 404: unknown; + /** + * Validation Error + */ + 422: HttpValidationError; +}; + +export type DeleteSavesApiSavesDeletePostError = DeleteSavesApiSavesDeletePostErrors[keyof DeleteSavesApiSavesDeletePostErrors]; + +export type DeleteSavesApiSavesDeletePostResponses = { + /** + * Response Delete Saves Api Saves Delete Post + * + * Successful Response + */ + 200: Array; +}; + +export type DeleteSavesApiSavesDeletePostResponse = DeleteSavesApiSavesDeletePostResponses[keyof DeleteSavesApiSavesDeletePostResponses]; + +export type GetStatesApiStatesGetData = { + body?: never; + path?: never; + query?: { + /** + * Rom Id + */ + rom_id?: number | null; + /** + * Platform Id + */ + platform_id?: number | null; + }; + url: '/api/states'; +}; + +export type GetStatesApiStatesGetErrors = { + /** + * Validation Error + */ + 422: HttpValidationError; +}; + +export type GetStatesApiStatesGetError = GetStatesApiStatesGetErrors[keyof GetStatesApiStatesGetErrors]; + +export type GetStatesApiStatesGetResponses = { + /** + * Response Get States Api States Get + * + * Successful Response + */ + 200: Array; +}; + +export type GetStatesApiStatesGetResponse = GetStatesApiStatesGetResponses[keyof GetStatesApiStatesGetResponses]; + +export type AddStateApiStatesPostData = { + body?: never; + path?: never; + query: { + /** + * Rom Id + */ + rom_id: number; + /** + * Emulator + */ + emulator?: string | null; + }; + url: '/api/states'; +}; + +export type AddStateApiStatesPostErrors = { + /** + * Validation Error + */ + 422: HttpValidationError; +}; + +export type AddStateApiStatesPostError = AddStateApiStatesPostErrors[keyof AddStateApiStatesPostErrors]; + +export type AddStateApiStatesPostResponses = { + /** + * Successful Response + */ + 200: StateSchema; +}; + +export type AddStateApiStatesPostResponse = AddStateApiStatesPostResponses[keyof AddStateApiStatesPostResponses]; + +export type GetStateApiStatesIdGetData = { + body?: never; + path: { + /** + * Id + */ + id: number; + }; + query?: never; + url: '/api/states/{id}'; +}; + +export type GetStateApiStatesIdGetErrors = { + /** + * Validation Error + */ + 422: HttpValidationError; +}; + +export type GetStateApiStatesIdGetError = GetStateApiStatesIdGetErrors[keyof GetStateApiStatesIdGetErrors]; + +export type GetStateApiStatesIdGetResponses = { + /** + * Successful Response + */ + 200: StateSchema; +}; + +export type GetStateApiStatesIdGetResponse = GetStateApiStatesIdGetResponses[keyof GetStateApiStatesIdGetResponses]; + +export type UpdateStateApiStatesIdPutData = { + body?: never; + path: { + /** + * Id + */ + id: number; + }; + query?: never; + url: '/api/states/{id}'; +}; + +export type UpdateStateApiStatesIdPutErrors = { + /** + * Validation Error + */ + 422: HttpValidationError; +}; + +export type UpdateStateApiStatesIdPutError = UpdateStateApiStatesIdPutErrors[keyof UpdateStateApiStatesIdPutErrors]; + +export type UpdateStateApiStatesIdPutResponses = { + /** + * Successful Response + */ + 200: StateSchema; +}; + +export type UpdateStateApiStatesIdPutResponse = UpdateStateApiStatesIdPutResponses[keyof UpdateStateApiStatesIdPutResponses]; + +export type DeleteStatesApiStatesDeletePostData = { + body: BodyDeleteStatesApiStatesDeletePost; + path?: never; + query?: never; + url: '/api/states/delete'; +}; + +export type DeleteStatesApiStatesDeletePostErrors = { + /** + * Bad Request + */ + 400: unknown; + /** + * Not Found + */ + 404: unknown; + /** + * Validation Error + */ + 422: HttpValidationError; +}; + +export type DeleteStatesApiStatesDeletePostError = DeleteStatesApiStatesDeletePostErrors[keyof DeleteStatesApiStatesDeletePostErrors]; + +export type DeleteStatesApiStatesDeletePostResponses = { + /** + * Response Delete States Api States Delete Post + * + * Successful Response + */ + 200: Array; +}; + +export type DeleteStatesApiStatesDeletePostResponse = DeleteStatesApiStatesDeletePostResponses[keyof DeleteStatesApiStatesDeletePostResponses]; + +export type ListTasksApiTasksGetData = { + body?: never; + path?: never; + query?: never; + url: '/api/tasks'; +}; + +export type ListTasksApiTasksGetResponses = { + /** + * Response List Tasks Api Tasks Get + * + * Successful Response + */ + 200: { + [key: string]: Array; + }; +}; + +export type ListTasksApiTasksGetResponse = ListTasksApiTasksGetResponses[keyof ListTasksApiTasksGetResponses]; + +export type GetTasksStatusApiTasksStatusGetData = { + body?: never; + path?: never; + query?: never; + url: '/api/tasks/status'; +}; + +export type GetTasksStatusApiTasksStatusGetResponses = { + /** + * Response Get Tasks Status Api Tasks Status Get + * + * Successful Response + */ + 200: Array; +}; + +export type GetTasksStatusApiTasksStatusGetResponse = GetTasksStatusApiTasksStatusGetResponses[keyof GetTasksStatusApiTasksStatusGetResponses]; + +export type GetTaskByIdApiTasksTaskIdGetData = { + body?: never; + path: { + /** + * Task Id + */ + task_id: string; + }; + query?: never; + url: '/api/tasks/{task_id}'; +}; + +export type GetTaskByIdApiTasksTaskIdGetErrors = { + /** + * Validation Error + */ + 422: HttpValidationError; +}; + +export type GetTaskByIdApiTasksTaskIdGetError = GetTaskByIdApiTasksTaskIdGetErrors[keyof GetTaskByIdApiTasksTaskIdGetErrors]; + +export type GetTaskByIdApiTasksTaskIdGetResponses = { + /** + * Response Get Task By Id Api Tasks Task Id Get + * + * Successful Response + */ + 200: ScanTaskStatusResponse | ConversionTaskStatusResponse | UpdateTaskStatusResponse | CleanupTaskStatusResponse | WatcherTaskStatusResponse | GenericTaskStatusResponse; +}; + +export type GetTaskByIdApiTasksTaskIdGetResponse = GetTaskByIdApiTasksTaskIdGetResponses[keyof GetTaskByIdApiTasksTaskIdGetResponses]; + +export type RunAllTasksApiTasksRunPostData = { + body?: never; + path?: never; + query?: never; + url: '/api/tasks/run'; +}; + +export type RunAllTasksApiTasksRunPostResponses = { + /** + * Response Run All Tasks Api Tasks Run Post + * + * Successful Response + */ + 200: Array; +}; + +export type RunAllTasksApiTasksRunPostResponse = RunAllTasksApiTasksRunPostResponses[keyof RunAllTasksApiTasksRunPostResponses]; + +export type RunSingleTaskApiTasksRunTaskNamePostData = { + body?: never; + path: { + /** + * Task Name + */ + task_name: string; + }; + query?: never; + url: '/api/tasks/run/{task_name}'; +}; + +export type RunSingleTaskApiTasksRunTaskNamePostErrors = { + /** + * Validation Error + */ + 422: HttpValidationError; +}; + +export type RunSingleTaskApiTasksRunTaskNamePostError = RunSingleTaskApiTasksRunTaskNamePostErrors[keyof RunSingleTaskApiTasksRunTaskNamePostErrors]; + +export type RunSingleTaskApiTasksRunTaskNamePostResponses = { + /** + * Successful Response + */ + 200: TaskExecutionResponse; +}; + +export type RunSingleTaskApiTasksRunTaskNamePostResponse = RunSingleTaskApiTasksRunTaskNamePostResponses[keyof RunSingleTaskApiTasksRunTaskNamePostResponses]; + +export type PlatformsWebrcadeFeedApiFeedsWebrcadeGetData = { + body?: never; + path?: never; + query?: never; + url: '/api/feeds/webrcade'; +}; + +export type PlatformsWebrcadeFeedApiFeedsWebrcadeGetResponses = { + /** + * Successful Response + */ + 200: WebrcadeFeedSchema; +}; + +export type PlatformsWebrcadeFeedApiFeedsWebrcadeGetResponse = PlatformsWebrcadeFeedApiFeedsWebrcadeGetResponses[keyof PlatformsWebrcadeFeedApiFeedsWebrcadeGetResponses]; + +export type TinfoilIndexFeedApiFeedsTinfoilGetData = { + body?: never; + path?: never; + query?: { + /** + * Slug + */ + slug?: string; + }; + url: '/api/feeds/tinfoil'; +}; + +export type TinfoilIndexFeedApiFeedsTinfoilGetErrors = { + /** + * Validation Error + */ + 422: HttpValidationError; +}; + +export type TinfoilIndexFeedApiFeedsTinfoilGetError = TinfoilIndexFeedApiFeedsTinfoilGetErrors[keyof TinfoilIndexFeedApiFeedsTinfoilGetErrors]; + +export type TinfoilIndexFeedApiFeedsTinfoilGetResponses = { + /** + * Successful Response + */ + 200: TinfoilFeedSchema; +}; + +export type TinfoilIndexFeedApiFeedsTinfoilGetResponse = TinfoilIndexFeedApiFeedsTinfoilGetResponses[keyof TinfoilIndexFeedApiFeedsTinfoilGetResponses]; + +export type PkgiPs3FeedApiFeedsPkgiPs3ContentTypeGetData = { + body?: never; + path: { + /** + * Content Type + * + * Content type + */ + content_type: string; + }; + query?: never; + url: '/api/feeds/pkgi/ps3/{content_type}'; +}; + +export type PkgiPs3FeedApiFeedsPkgiPs3ContentTypeGetErrors = { + /** + * Validation Error + */ + 422: HttpValidationError; +}; + +export type PkgiPs3FeedApiFeedsPkgiPs3ContentTypeGetError = PkgiPs3FeedApiFeedsPkgiPs3ContentTypeGetErrors[keyof PkgiPs3FeedApiFeedsPkgiPs3ContentTypeGetErrors]; + +export type PkgiPs3FeedApiFeedsPkgiPs3ContentTypeGetResponses = { + /** + * Successful Response + */ + 200: unknown; +}; + +export type PkgiPsvitaFeedApiFeedsPkgiPsvitaContentTypeGetData = { + body?: never; + path: { + /** + * Content Type + * + * Content type + */ + content_type: string; + }; + query?: never; + url: '/api/feeds/pkgi/psvita/{content_type}'; +}; + +export type PkgiPsvitaFeedApiFeedsPkgiPsvitaContentTypeGetErrors = { + /** + * Validation Error + */ + 422: HttpValidationError; +}; + +export type PkgiPsvitaFeedApiFeedsPkgiPsvitaContentTypeGetError = PkgiPsvitaFeedApiFeedsPkgiPsvitaContentTypeGetErrors[keyof PkgiPsvitaFeedApiFeedsPkgiPsvitaContentTypeGetErrors]; + +export type PkgiPsvitaFeedApiFeedsPkgiPsvitaContentTypeGetResponses = { + /** + * Successful Response + */ + 200: unknown; +}; + +export type PkgiPspFeedApiFeedsPkgiPspContentTypeGetData = { + body?: never; + path: { + /** + * Content Type + * + * Content type + */ + content_type: string; + }; + query?: never; + url: '/api/feeds/pkgi/psp/{content_type}'; +}; + +export type PkgiPspFeedApiFeedsPkgiPspContentTypeGetErrors = { + /** + * Validation Error + */ + 422: HttpValidationError; +}; + +export type PkgiPspFeedApiFeedsPkgiPspContentTypeGetError = PkgiPspFeedApiFeedsPkgiPspContentTypeGetErrors[keyof PkgiPspFeedApiFeedsPkgiPspContentTypeGetErrors]; + +export type PkgiPspFeedApiFeedsPkgiPspContentTypeGetResponses = { + /** + * Successful Response + */ + 200: unknown; +}; + +export type FpkgiFeedApiFeedsFpkgiPlatformSlugGetData = { + body?: never; + path: { + /** + * Platform Slug + */ + platform_slug: string; + }; + query?: never; + url: '/api/feeds/fpkgi/{platform_slug}'; +}; + +export type FpkgiFeedApiFeedsFpkgiPlatformSlugGetErrors = { + /** + * Validation Error + */ + 422: HttpValidationError; +}; + +export type FpkgiFeedApiFeedsFpkgiPlatformSlugGetError = FpkgiFeedApiFeedsFpkgiPlatformSlugGetErrors[keyof FpkgiFeedApiFeedsFpkgiPlatformSlugGetErrors]; + +export type FpkgiFeedApiFeedsFpkgiPlatformSlugGetResponses = { + /** + * Successful Response + */ + 200: unknown; +}; + +export type KekatsuDsFeedApiFeedsKekatsuPlatformSlugGetData = { + body?: never; + path: { + /** + * Platform Slug + */ + platform_slug: string; + }; + query?: never; + url: '/api/feeds/kekatsu/{platform_slug}'; +}; + +export type KekatsuDsFeedApiFeedsKekatsuPlatformSlugGetErrors = { + /** + * Validation Error + */ + 422: HttpValidationError; +}; + +export type KekatsuDsFeedApiFeedsKekatsuPlatformSlugGetError = KekatsuDsFeedApiFeedsKekatsuPlatformSlugGetErrors[keyof KekatsuDsFeedApiFeedsKekatsuPlatformSlugGetErrors]; + +export type KekatsuDsFeedApiFeedsKekatsuPlatformSlugGetResponses = { + /** + * Successful Response + */ + 200: unknown; +}; + +export type GetConfigApiConfigGetData = { + body?: never; + path?: never; + query?: never; + url: '/api/config'; +}; + +export type GetConfigApiConfigGetResponses = { + /** + * Successful Response + */ + 200: ConfigResponse; +}; + +export type GetConfigApiConfigGetResponse = GetConfigApiConfigGetResponses[keyof GetConfigApiConfigGetResponses]; + +export type AddPlatformBindingApiConfigSystemPlatformsPostData = { + body?: never; + path?: never; + query?: never; + url: '/api/config/system/platforms'; +}; + +export type AddPlatformBindingApiConfigSystemPlatformsPostResponses = { + /** + * Successful Response + */ + 200: unknown; +}; + +export type DeletePlatformBindingApiConfigSystemPlatformsFsSlugDeleteData = { + body?: never; + path: { + /** + * Fs Slug + */ + fs_slug: string; + }; + query?: never; + url: '/api/config/system/platforms/{fs_slug}'; +}; + +export type DeletePlatformBindingApiConfigSystemPlatformsFsSlugDeleteErrors = { + /** + * Validation Error + */ + 422: HttpValidationError; +}; + +export type DeletePlatformBindingApiConfigSystemPlatformsFsSlugDeleteError = DeletePlatformBindingApiConfigSystemPlatformsFsSlugDeleteErrors[keyof DeletePlatformBindingApiConfigSystemPlatformsFsSlugDeleteErrors]; + +export type DeletePlatformBindingApiConfigSystemPlatformsFsSlugDeleteResponses = { + /** + * Successful Response + */ + 200: unknown; +}; + +export type AddPlatformVersionApiConfigSystemVersionsPostData = { + body?: never; + path?: never; + query?: never; + url: '/api/config/system/versions'; +}; + +export type AddPlatformVersionApiConfigSystemVersionsPostResponses = { + /** + * Successful Response + */ + 200: unknown; +}; + +export type DeletePlatformVersionApiConfigSystemVersionsFsSlugDeleteData = { + body?: never; + path: { + /** + * Fs Slug + */ + fs_slug: string; + }; + query?: never; + url: '/api/config/system/versions/{fs_slug}'; +}; + +export type DeletePlatformVersionApiConfigSystemVersionsFsSlugDeleteErrors = { + /** + * Validation Error + */ + 422: HttpValidationError; +}; + +export type DeletePlatformVersionApiConfigSystemVersionsFsSlugDeleteError = DeletePlatformVersionApiConfigSystemVersionsFsSlugDeleteErrors[keyof DeletePlatformVersionApiConfigSystemVersionsFsSlugDeleteErrors]; + +export type DeletePlatformVersionApiConfigSystemVersionsFsSlugDeleteResponses = { + /** + * Successful Response + */ + 200: unknown; +}; + +export type AddExclusionApiConfigExcludePostData = { + body?: never; + path?: never; + query?: never; + url: '/api/config/exclude'; +}; + +export type AddExclusionApiConfigExcludePostResponses = { + /** + * Successful Response + */ + 200: unknown; +}; + +export type DeleteExclusionApiConfigExcludeExclusionTypeExclusionValueDeleteData = { + body?: never; + path: { + /** + * Exclusion Type + */ + exclusion_type: string; + /** + * Exclusion Value + */ + exclusion_value: string; + }; + query?: never; + url: '/api/config/exclude/{exclusion_type}/{exclusion_value}'; +}; + +export type DeleteExclusionApiConfigExcludeExclusionTypeExclusionValueDeleteErrors = { + /** + * Validation Error + */ + 422: HttpValidationError; +}; + +export type DeleteExclusionApiConfigExcludeExclusionTypeExclusionValueDeleteError = DeleteExclusionApiConfigExcludeExclusionTypeExclusionValueDeleteErrors[keyof DeleteExclusionApiConfigExcludeExclusionTypeExclusionValueDeleteErrors]; + +export type DeleteExclusionApiConfigExcludeExclusionTypeExclusionValueDeleteResponses = { + /** + * Successful Response + */ + 200: unknown; +}; + +export type StatsApiStatsGetData = { + body?: never; + path?: never; + query?: never; + url: '/api/stats'; +}; + +export type StatsApiStatsGetResponses = { + /** + * Successful Response + */ + 200: StatsReturn; +}; + +export type StatsApiStatsGetResponse = StatsApiStatsGetResponses[keyof StatsApiStatsGetResponses]; + +export type GetRawAssetApiRawAssetsPathGetData = { + body?: never; + path: { + /** + * Path + */ + path: string; + }; + query?: never; + url: '/api/raw/assets/{path}'; +}; + +export type GetRawAssetApiRawAssetsPathGetErrors = { + /** + * Validation Error + */ + 422: HttpValidationError; +}; + +export type GetRawAssetApiRawAssetsPathGetError = GetRawAssetApiRawAssetsPathGetErrors[keyof GetRawAssetApiRawAssetsPathGetErrors]; + +export type GetRawAssetApiRawAssetsPathGetResponses = { + /** + * Successful Response + */ + 200: unknown; +}; + +export type HeadRawAssetApiRawAssetsPathHeadData = { + body?: never; + path: { + /** + * Path + */ + path: string; + }; + query?: never; + url: '/api/raw/assets/{path}'; +}; + +export type HeadRawAssetApiRawAssetsPathHeadErrors = { + /** + * Validation Error + */ + 422: HttpValidationError; +}; + +export type HeadRawAssetApiRawAssetsPathHeadError = HeadRawAssetApiRawAssetsPathHeadErrors[keyof HeadRawAssetApiRawAssetsPathHeadErrors]; + +export type HeadRawAssetApiRawAssetsPathHeadResponses = { + /** + * Successful Response + */ + 200: unknown; +}; + +export type AddScreenshotApiScreenshotsPostData = { + body?: never; + path?: never; + query: { + /** + * Rom Id + */ + rom_id: number; + }; + url: '/api/screenshots'; +}; + +export type AddScreenshotApiScreenshotsPostErrors = { + /** + * Validation Error + */ + 422: HttpValidationError; +}; + +export type AddScreenshotApiScreenshotsPostError = AddScreenshotApiScreenshotsPostErrors[keyof AddScreenshotApiScreenshotsPostErrors]; + +export type AddScreenshotApiScreenshotsPostResponses = { + /** + * Successful Response + */ + 200: ScreenshotSchema; +}; + +export type AddScreenshotApiScreenshotsPostResponse = AddScreenshotApiScreenshotsPostResponses[keyof AddScreenshotApiScreenshotsPostResponses]; + +export type GetPlatformFirmwareApiFirmwareGetData = { + body?: never; + path?: never; + query?: { + /** + * Platform Id + */ + platform_id?: number | null; + }; + url: '/api/firmware'; +}; + +export type GetPlatformFirmwareApiFirmwareGetErrors = { + /** + * Validation Error + */ + 422: HttpValidationError; +}; + +export type GetPlatformFirmwareApiFirmwareGetError = GetPlatformFirmwareApiFirmwareGetErrors[keyof GetPlatformFirmwareApiFirmwareGetErrors]; + +export type GetPlatformFirmwareApiFirmwareGetResponses = { + /** + * Response Get Platform Firmware Api Firmware Get + * + * Successful Response + */ + 200: Array; +}; + +export type GetPlatformFirmwareApiFirmwareGetResponse = GetPlatformFirmwareApiFirmwareGetResponses[keyof GetPlatformFirmwareApiFirmwareGetResponses]; + +export type AddFirmwareApiFirmwarePostData = { + body: BodyAddFirmwareApiFirmwarePost; + path?: never; + query: { + /** + * Platform Id + */ + platform_id: number; + }; + url: '/api/firmware'; +}; + +export type AddFirmwareApiFirmwarePostErrors = { + /** + * Validation Error + */ + 422: HttpValidationError; +}; + +export type AddFirmwareApiFirmwarePostError = AddFirmwareApiFirmwarePostErrors[keyof AddFirmwareApiFirmwarePostErrors]; + +export type AddFirmwareApiFirmwarePostResponses = { + /** + * Successful Response + */ + 200: AddFirmwareResponse; +}; + +export type AddFirmwareApiFirmwarePostResponse = AddFirmwareApiFirmwarePostResponses[keyof AddFirmwareApiFirmwarePostResponses]; + +export type GetFirmwareApiFirmwareIdGetData = { + body?: never; + path: { + /** + * Id + */ + id: number; + }; + query?: never; + url: '/api/firmware/{id}'; +}; + +export type GetFirmwareApiFirmwareIdGetErrors = { + /** + * Validation Error + */ + 422: HttpValidationError; +}; + +export type GetFirmwareApiFirmwareIdGetError = GetFirmwareApiFirmwareIdGetErrors[keyof GetFirmwareApiFirmwareIdGetErrors]; + +export type GetFirmwareApiFirmwareIdGetResponses = { + /** + * Successful Response + */ + 200: FirmwareSchema; +}; + +export type GetFirmwareApiFirmwareIdGetResponse = GetFirmwareApiFirmwareIdGetResponses[keyof GetFirmwareApiFirmwareIdGetResponses]; + +export type GetFirmwareContentApiFirmwareIdContentFileNameGetData = { + body?: never; + path: { + /** + * Id + */ + id: number; + /** + * File Name + */ + file_name: string; + }; + query?: never; + url: '/api/firmware/{id}/content/{file_name}'; +}; + +export type GetFirmwareContentApiFirmwareIdContentFileNameGetErrors = { + /** + * Validation Error + */ + 422: HttpValidationError; +}; + +export type GetFirmwareContentApiFirmwareIdContentFileNameGetError = GetFirmwareContentApiFirmwareIdContentFileNameGetErrors[keyof GetFirmwareContentApiFirmwareIdContentFileNameGetErrors]; + +export type GetFirmwareContentApiFirmwareIdContentFileNameGetResponses = { + /** + * Successful Response + */ + 200: unknown; +}; + +export type HeadFirmwareContentApiFirmwareIdContentFileNameHeadData = { + body?: never; + path: { + /** + * Id + */ + id: number; + /** + * File Name + */ + file_name: string; + }; + query?: never; + url: '/api/firmware/{id}/content/{file_name}'; +}; + +export type HeadFirmwareContentApiFirmwareIdContentFileNameHeadErrors = { + /** + * Validation Error + */ + 422: HttpValidationError; +}; + +export type HeadFirmwareContentApiFirmwareIdContentFileNameHeadError = HeadFirmwareContentApiFirmwareIdContentFileNameHeadErrors[keyof HeadFirmwareContentApiFirmwareIdContentFileNameHeadErrors]; + +export type HeadFirmwareContentApiFirmwareIdContentFileNameHeadResponses = { + /** + * Successful Response + */ + 200: unknown; +}; + +export type DeleteFirmwareApiFirmwareDeletePostData = { + body: BodyDeleteFirmwareApiFirmwareDeletePost; + path?: never; + query?: never; + url: '/api/firmware/delete'; +}; + +export type DeleteFirmwareApiFirmwareDeletePostErrors = { + /** + * Validation Error + */ + 422: HttpValidationError; +}; + +export type DeleteFirmwareApiFirmwareDeletePostError = DeleteFirmwareApiFirmwareDeletePostErrors[keyof DeleteFirmwareApiFirmwareDeletePostErrors]; + +export type DeleteFirmwareApiFirmwareDeletePostResponses = { + /** + * Successful Response + */ + 200: BulkOperationResponse; +}; + +export type DeleteFirmwareApiFirmwareDeletePostResponse = DeleteFirmwareApiFirmwareDeletePostResponses[keyof DeleteFirmwareApiFirmwareDeletePostResponses]; + +export type GetCollectionsApiCollectionsGetData = { + body?: never; + path?: never; + query?: { + /** + * Updated After + * + * Filter collections updated after this datetime (ISO 8601 format with timezone information). + */ + updated_after?: string | null; + }; + url: '/api/collections'; +}; + +export type GetCollectionsApiCollectionsGetErrors = { + /** + * Validation Error + */ + 422: HttpValidationError; +}; + +export type GetCollectionsApiCollectionsGetError = GetCollectionsApiCollectionsGetErrors[keyof GetCollectionsApiCollectionsGetErrors]; + +export type GetCollectionsApiCollectionsGetResponses = { + /** + * Response Get Collections Api Collections Get + * + * Successful Response + */ + 200: Array; +}; + +export type GetCollectionsApiCollectionsGetResponse = GetCollectionsApiCollectionsGetResponses[keyof GetCollectionsApiCollectionsGetResponses]; + +export type AddCollectionApiCollectionsPostData = { + body?: BodyAddCollectionApiCollectionsPost; + path?: never; + query?: { + /** + * Is Public + */ + is_public?: boolean | null; + /** + * Is Favorite + */ + is_favorite?: boolean | null; + }; + url: '/api/collections'; +}; + +export type AddCollectionApiCollectionsPostErrors = { + /** + * Validation Error + */ + 422: HttpValidationError; +}; + +export type AddCollectionApiCollectionsPostError = AddCollectionApiCollectionsPostErrors[keyof AddCollectionApiCollectionsPostErrors]; + +export type AddCollectionApiCollectionsPostResponses = { + /** + * Successful Response + */ + 200: CollectionSchema; +}; + +export type AddCollectionApiCollectionsPostResponse = AddCollectionApiCollectionsPostResponses[keyof AddCollectionApiCollectionsPostResponses]; + +export type GetSmartCollectionsApiCollectionsSmartGetData = { + body?: never; + path?: never; + query?: { + /** + * Updated After + * + * Filter smart collections updated after this datetime (ISO 8601 format with timezone information). + */ + updated_after?: string | null; + }; + url: '/api/collections/smart'; +}; + +export type GetSmartCollectionsApiCollectionsSmartGetErrors = { + /** + * Validation Error + */ + 422: HttpValidationError; +}; + +export type GetSmartCollectionsApiCollectionsSmartGetError = GetSmartCollectionsApiCollectionsSmartGetErrors[keyof GetSmartCollectionsApiCollectionsSmartGetErrors]; + +export type GetSmartCollectionsApiCollectionsSmartGetResponses = { + /** + * Response Get Smart Collections Api Collections Smart Get + * + * Successful Response + */ + 200: Array; +}; + +export type GetSmartCollectionsApiCollectionsSmartGetResponse = GetSmartCollectionsApiCollectionsSmartGetResponses[keyof GetSmartCollectionsApiCollectionsSmartGetResponses]; + +export type AddSmartCollectionApiCollectionsSmartPostData = { + body?: never; + path?: never; + query?: { + /** + * Is Public + */ + is_public?: boolean | null; + }; + url: '/api/collections/smart'; +}; + +export type AddSmartCollectionApiCollectionsSmartPostErrors = { + /** + * Validation Error + */ + 422: HttpValidationError; +}; + +export type AddSmartCollectionApiCollectionsSmartPostError = AddSmartCollectionApiCollectionsSmartPostErrors[keyof AddSmartCollectionApiCollectionsSmartPostErrors]; + +export type AddSmartCollectionApiCollectionsSmartPostResponses = { + /** + * Successful Response + */ + 200: SmartCollectionSchema; +}; + +export type AddSmartCollectionApiCollectionsSmartPostResponse = AddSmartCollectionApiCollectionsSmartPostResponses[keyof AddSmartCollectionApiCollectionsSmartPostResponses]; + +export type GetVirtualCollectionsApiCollectionsVirtualGetData = { + body?: never; + path?: never; + query: { + /** + * Type + */ + type: string; + /** + * Limit + */ + limit?: number | null; + }; + url: '/api/collections/virtual'; +}; + +export type GetVirtualCollectionsApiCollectionsVirtualGetErrors = { + /** + * Validation Error + */ + 422: HttpValidationError; +}; + +export type GetVirtualCollectionsApiCollectionsVirtualGetError = GetVirtualCollectionsApiCollectionsVirtualGetErrors[keyof GetVirtualCollectionsApiCollectionsVirtualGetErrors]; + +export type GetVirtualCollectionsApiCollectionsVirtualGetResponses = { + /** + * Response Get Virtual Collections Api Collections Virtual Get + * + * Successful Response + */ + 200: Array; +}; + +export type GetVirtualCollectionsApiCollectionsVirtualGetResponse = GetVirtualCollectionsApiCollectionsVirtualGetResponses[keyof GetVirtualCollectionsApiCollectionsVirtualGetResponses]; + +export type DeleteCollectionApiCollectionsIdDeleteData = { + body?: never; + path: { + /** + * Id + * + * Collection internal id. + */ + id: number; + }; + query?: never; + url: '/api/collections/{id}'; +}; + +export type DeleteCollectionApiCollectionsIdDeleteErrors = { + /** + * Not Found + */ + 404: unknown; + /** + * Validation Error + */ + 422: HttpValidationError; +}; + +export type DeleteCollectionApiCollectionsIdDeleteError = DeleteCollectionApiCollectionsIdDeleteErrors[keyof DeleteCollectionApiCollectionsIdDeleteErrors]; + +export type DeleteCollectionApiCollectionsIdDeleteResponses = { + /** + * Successful Response + */ + 200: unknown; +}; + +export type GetCollectionApiCollectionsIdGetData = { + body?: never; + path: { + /** + * Id + */ + id: number; + }; + query?: never; + url: '/api/collections/{id}'; +}; + +export type GetCollectionApiCollectionsIdGetErrors = { + /** + * Validation Error + */ + 422: HttpValidationError; +}; + +export type GetCollectionApiCollectionsIdGetError = GetCollectionApiCollectionsIdGetErrors[keyof GetCollectionApiCollectionsIdGetErrors]; + +export type GetCollectionApiCollectionsIdGetResponses = { + /** + * Successful Response + */ + 200: CollectionSchema; +}; + +export type GetCollectionApiCollectionsIdGetResponse = GetCollectionApiCollectionsIdGetResponses[keyof GetCollectionApiCollectionsIdGetResponses]; + +export type UpdateCollectionApiCollectionsIdPutData = { + body?: BodyUpdateCollectionApiCollectionsIdPut; + path: { + /** + * Id + */ + id: number; + }; + query?: { + /** + * Remove Cover + */ + remove_cover?: boolean; + /** + * Is Public + */ + is_public?: boolean | null; + }; + url: '/api/collections/{id}'; +}; + +export type UpdateCollectionApiCollectionsIdPutErrors = { + /** + * Validation Error + */ + 422: HttpValidationError; +}; + +export type UpdateCollectionApiCollectionsIdPutError = UpdateCollectionApiCollectionsIdPutErrors[keyof UpdateCollectionApiCollectionsIdPutErrors]; + +export type UpdateCollectionApiCollectionsIdPutResponses = { + /** + * Successful Response + */ + 200: CollectionSchema; +}; + +export type UpdateCollectionApiCollectionsIdPutResponse = UpdateCollectionApiCollectionsIdPutResponses[keyof UpdateCollectionApiCollectionsIdPutResponses]; + +export type GetVirtualCollectionApiCollectionsVirtualIdGetData = { + body?: never; + path: { + /** + * Id + */ + id: string; + }; + query?: never; + url: '/api/collections/virtual/{id}'; +}; + +export type GetVirtualCollectionApiCollectionsVirtualIdGetErrors = { + /** + * Validation Error + */ + 422: HttpValidationError; +}; + +export type GetVirtualCollectionApiCollectionsVirtualIdGetError = GetVirtualCollectionApiCollectionsVirtualIdGetErrors[keyof GetVirtualCollectionApiCollectionsVirtualIdGetErrors]; + +export type GetVirtualCollectionApiCollectionsVirtualIdGetResponses = { + /** + * Successful Response + */ + 200: VirtualCollectionSchema; +}; + +export type GetVirtualCollectionApiCollectionsVirtualIdGetResponse = GetVirtualCollectionApiCollectionsVirtualIdGetResponses[keyof GetVirtualCollectionApiCollectionsVirtualIdGetResponses]; + +export type DeleteSmartCollectionApiCollectionsSmartIdDeleteData = { + body?: never; + path: { + /** + * Id + * + * Smart collection internal id. + */ + id: number; + }; + query?: never; + url: '/api/collections/smart/{id}'; +}; + +export type DeleteSmartCollectionApiCollectionsSmartIdDeleteErrors = { + /** + * Not Found + */ + 404: unknown; + /** + * Validation Error + */ + 422: HttpValidationError; +}; + +export type DeleteSmartCollectionApiCollectionsSmartIdDeleteError = DeleteSmartCollectionApiCollectionsSmartIdDeleteErrors[keyof DeleteSmartCollectionApiCollectionsSmartIdDeleteErrors]; + +export type DeleteSmartCollectionApiCollectionsSmartIdDeleteResponses = { + /** + * Successful Response + */ + 200: unknown; +}; + +export type GetSmartCollectionApiCollectionsSmartIdGetData = { + body?: never; + path: { + /** + * Id + */ + id: number; + }; + query?: never; + url: '/api/collections/smart/{id}'; +}; + +export type GetSmartCollectionApiCollectionsSmartIdGetErrors = { + /** + * Validation Error + */ + 422: HttpValidationError; +}; + +export type GetSmartCollectionApiCollectionsSmartIdGetError = GetSmartCollectionApiCollectionsSmartIdGetErrors[keyof GetSmartCollectionApiCollectionsSmartIdGetErrors]; + +export type GetSmartCollectionApiCollectionsSmartIdGetResponses = { + /** + * Successful Response + */ + 200: SmartCollectionSchema; +}; + +export type GetSmartCollectionApiCollectionsSmartIdGetResponse = GetSmartCollectionApiCollectionsSmartIdGetResponses[keyof GetSmartCollectionApiCollectionsSmartIdGetResponses]; + +export type UpdateSmartCollectionApiCollectionsSmartIdPutData = { + body?: never; + path: { + /** + * Id + */ + id: number; + }; + query?: { + /** + * Is Public + */ + is_public?: boolean | null; + }; + url: '/api/collections/smart/{id}'; +}; + +export type UpdateSmartCollectionApiCollectionsSmartIdPutErrors = { + /** + * Validation Error + */ + 422: HttpValidationError; +}; + +export type UpdateSmartCollectionApiCollectionsSmartIdPutError = UpdateSmartCollectionApiCollectionsSmartIdPutErrors[keyof UpdateSmartCollectionApiCollectionsSmartIdPutErrors]; + +export type UpdateSmartCollectionApiCollectionsSmartIdPutResponses = { + /** + * Successful Response + */ + 200: SmartCollectionSchema; +}; + +export type UpdateSmartCollectionApiCollectionsSmartIdPutResponse = UpdateSmartCollectionApiCollectionsSmartIdPutResponses[keyof UpdateSmartCollectionApiCollectionsSmartIdPutResponses]; + +export type ExportGamelistApiGamelistExportPostData = { + body?: never; + path?: never; + query: { + /** + * Platform Ids + * + * List of platform IDs to export + */ + platform_ids: Array; + /** + * Local Export + * + * Use local paths instead of URLs + */ + local_export?: boolean; + }; + url: '/api/gamelist/export'; +}; + +export type ExportGamelistApiGamelistExportPostErrors = { + /** + * Validation Error + */ + 422: HttpValidationError; +}; + +export type ExportGamelistApiGamelistExportPostError = ExportGamelistApiGamelistExportPostErrors[keyof ExportGamelistApiGamelistExportPostErrors]; + +export type ExportGamelistApiGamelistExportPostResponses = { + /** + * Successful Response + */ + 200: unknown; +}; + +export type GetRoomsApiNetplayListGetData = { + body?: never; + path?: never; + query: { + /** + * Game Id + */ + game_id: string; + }; + url: '/api/netplay/list'; +}; + +export type GetRoomsApiNetplayListGetErrors = { + /** + * Validation Error + */ + 422: HttpValidationError; +}; + +export type GetRoomsApiNetplayListGetError = GetRoomsApiNetplayListGetErrors[keyof GetRoomsApiNetplayListGetErrors]; + +export type GetRoomsApiNetplayListGetResponses = { + /** + * Response Get Rooms Api Netplay List Get + * + * Successful Response + */ + 200: { + [key: string]: RoomsResponse; + }; +}; + +export type GetRoomsApiNetplayListGetResponse = GetRoomsApiNetplayListGetResponses[keyof GetRoomsApiNetplayListGetResponses]; diff --git a/src/mainview/assets/favicon.ico b/src/mainview/assets/favicon.ico new file mode 100644 index 0000000..805e7ab --- /dev/null +++ b/src/mainview/assets/favicon.ico @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f61b110fcf674eba904af5cdcebfdcb75c5a1f2516af623823f14ed237f4cd27 +size 15406 diff --git a/src/mainview/assets/icons/LICENSE.md b/src/mainview/assets/icons/LICENSE.md new file mode 100644 index 0000000..d133948 --- /dev/null +++ b/src/mainview/assets/icons/LICENSE.md @@ -0,0 +1,28 @@ + + + Input Prompts (1.4.1) + + Created/distributed by Kenney (www.kenney.nl) + Creation date: 22-11-2025 + + ------------------------------ + + License: (Creative Commons Zero, CC0) + http://creativecommons.org/publicdomain/zero/1.0/ + + You can use this content for personal, educational, and commercial purposes. + + Support by crediting 'Kenney' or 'www.kenney.nl' (this is not a requirement) + + ------------------------------ + + • Website : www.kenney.nl + • Donate : www.kenney.nl/donate + + • Patreon : patreon.com/kenney + + Follow on social media for updates: + + • Twitter: twitter.com/KenneyNL + • Instagram: instagram.com/kenney_nl + • Mastodon: mastodon.gamedev.place/@kenney \ No newline at end of file diff --git a/src/mainview/assets/icons/controller_steamdeck.svg b/src/mainview/assets/icons/controller_steamdeck.svg new file mode 100644 index 0000000..1c47fae --- /dev/null +++ b/src/mainview/assets/icons/controller_steamdeck.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c0958d872aa2159bd19d8a7136cbc6b8ba8de8363b051792cbde72c6cf4559b3 +size 1159 diff --git a/src/mainview/assets/icons/controller_xbox360.svg b/src/mainview/assets/icons/controller_xbox360.svg new file mode 100644 index 0000000..b6b7d68 --- /dev/null +++ b/src/mainview/assets/icons/controller_xbox360.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:318e400448efb80c3d24e9594f87701607b33f29560f3f143db79333ecae330d +size 1796 diff --git a/src/mainview/assets/icons/controller_xbox_adaptive.svg b/src/mainview/assets/icons/controller_xbox_adaptive.svg new file mode 100644 index 0000000..f53bc12 --- /dev/null +++ b/src/mainview/assets/icons/controller_xbox_adaptive.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:cb23a69508412d3c33eb1d3d8fe65a707d10181c36fcee7c9d2797d0f8b706e6 +size 795 diff --git a/src/mainview/assets/icons/controller_xboxone.svg b/src/mainview/assets/icons/controller_xboxone.svg new file mode 100644 index 0000000..893d535 --- /dev/null +++ b/src/mainview/assets/icons/controller_xboxone.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9be34e824ae31392831ef31d948e57bb4fbe5718e2d4ebccb655e4edfa74a321 +size 1761 diff --git a/src/mainview/assets/icons/controller_xboxseries.svg b/src/mainview/assets/icons/controller_xboxseries.svg new file mode 100644 index 0000000..38440ae --- /dev/null +++ b/src/mainview/assets/icons/controller_xboxseries.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c425409da32a5bad6bff5bb4eba4919cb650a7476c5215c1f7a004553ab4af71 +size 1914 diff --git a/src/mainview/assets/icons/steamdeck_button_a.svg b/src/mainview/assets/icons/steamdeck_button_a.svg new file mode 100644 index 0000000..cad2e1e --- /dev/null +++ b/src/mainview/assets/icons/steamdeck_button_a.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:64c7e4560c68bbbdc824627aca50464eee2dab31323e06df5b4d8f8b33a7d453 +size 393 diff --git a/src/mainview/assets/icons/steamdeck_button_a_outline.svg b/src/mainview/assets/icons/steamdeck_button_a_outline.svg new file mode 100644 index 0000000..6d7831c --- /dev/null +++ b/src/mainview/assets/icons/steamdeck_button_a_outline.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d4e5a26168d9ca3cc5f880befea9cc851359f410d6582ea7397e0da51a08c685 +size 547 diff --git a/src/mainview/assets/icons/steamdeck_button_b.svg b/src/mainview/assets/icons/steamdeck_button_b.svg new file mode 100644 index 0000000..f18e8cf --- /dev/null +++ b/src/mainview/assets/icons/steamdeck_button_b.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:12061d33eb6596dc94ad551296502a9e15bd26c9199210db4728fa2a666f3ca0 +size 701 diff --git a/src/mainview/assets/icons/steamdeck_button_b_outline.svg b/src/mainview/assets/icons/steamdeck_button_b_outline.svg new file mode 100644 index 0000000..c3a64a3 --- /dev/null +++ b/src/mainview/assets/icons/steamdeck_button_b_outline.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ff2dff9ca5f8ef0e9d7f32ce97f83db807b7a67679d914c10ef0b5aaaf845f75 +size 855 diff --git a/src/mainview/assets/icons/steamdeck_button_guide.svg b/src/mainview/assets/icons/steamdeck_button_guide.svg new file mode 100644 index 0000000..9415be1 --- /dev/null +++ b/src/mainview/assets/icons/steamdeck_button_guide.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ab396288e7416aa7c77e15965df1c4e044f7ead5cfb41c5ec91b22fe674e1b58 +size 1271 diff --git a/src/mainview/assets/icons/steamdeck_button_guide_outline.svg b/src/mainview/assets/icons/steamdeck_button_guide_outline.svg new file mode 100644 index 0000000..8244dab --- /dev/null +++ b/src/mainview/assets/icons/steamdeck_button_guide_outline.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ce8837d7eb8629634d460433cd7876b6abaa3acc2c07b73fd84fb6fb15c09466 +size 1447 diff --git a/src/mainview/assets/icons/steamdeck_button_l1.svg b/src/mainview/assets/icons/steamdeck_button_l1.svg new file mode 100644 index 0000000..41b2321 --- /dev/null +++ b/src/mainview/assets/icons/steamdeck_button_l1.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4ed141c97ff2e8e2faebfa6a44023a0ff03992ec9f86e73d5ab605b7fe5f9c76 +size 426 diff --git a/src/mainview/assets/icons/steamdeck_button_l1_outline.svg b/src/mainview/assets/icons/steamdeck_button_l1_outline.svg new file mode 100644 index 0000000..bd98ae1 --- /dev/null +++ b/src/mainview/assets/icons/steamdeck_button_l1_outline.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a4cd2ea5c771366335c28b5e740fcbe55972a76dc84c349cc99fe009638df7c3 +size 562 diff --git a/src/mainview/assets/icons/steamdeck_button_l2.svg b/src/mainview/assets/icons/steamdeck_button_l2.svg new file mode 100644 index 0000000..c12dea2 --- /dev/null +++ b/src/mainview/assets/icons/steamdeck_button_l2.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ddf29d5d73bca72866462c0fd524f2c571d33d49aad9c1a7d5e6e1bfa5ada75e +size 649 diff --git a/src/mainview/assets/icons/steamdeck_button_l2_outline.svg b/src/mainview/assets/icons/steamdeck_button_l2_outline.svg new file mode 100644 index 0000000..3a0099b --- /dev/null +++ b/src/mainview/assets/icons/steamdeck_button_l2_outline.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3318865098ddb43321ea1453c6b1e69023864e1d265f67897b54f50049d8bce1 +size 785 diff --git a/src/mainview/assets/icons/steamdeck_button_l4.svg b/src/mainview/assets/icons/steamdeck_button_l4.svg new file mode 100644 index 0000000..560fc39 --- /dev/null +++ b/src/mainview/assets/icons/steamdeck_button_l4.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4a7035aef915bf4979c1bde49818bf8f049440d180521dfd1ff23eac202d9ef3 +size 414 diff --git a/src/mainview/assets/icons/steamdeck_button_l4_outline.svg b/src/mainview/assets/icons/steamdeck_button_l4_outline.svg new file mode 100644 index 0000000..f78be52 --- /dev/null +++ b/src/mainview/assets/icons/steamdeck_button_l4_outline.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d51139bd0d0b01b105bf83a230d712078526cae0b6d18771cc6049d74971cd2a +size 501 diff --git a/src/mainview/assets/icons/steamdeck_button_l5.svg b/src/mainview/assets/icons/steamdeck_button_l5.svg new file mode 100644 index 0000000..42210eb --- /dev/null +++ b/src/mainview/assets/icons/steamdeck_button_l5.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2894641a7e476549593156be0fd7669e35ccf0764fb00095492475799cf8b576 +size 650 diff --git a/src/mainview/assets/icons/steamdeck_button_l5_outline.svg b/src/mainview/assets/icons/steamdeck_button_l5_outline.svg new file mode 100644 index 0000000..2d6ad61 --- /dev/null +++ b/src/mainview/assets/icons/steamdeck_button_l5_outline.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a51be3d7ed213e0274d7f2998693d6b12f0b1fe5b255f4167246d71872236c1b +size 737 diff --git a/src/mainview/assets/icons/steamdeck_button_options.svg b/src/mainview/assets/icons/steamdeck_button_options.svg new file mode 100644 index 0000000..2b8c28f --- /dev/null +++ b/src/mainview/assets/icons/steamdeck_button_options.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e28902c7938c7d96fb783716a3e6a797134ad7bde925dff576c45f129bf12146 +size 442 diff --git a/src/mainview/assets/icons/steamdeck_button_options_outline.svg b/src/mainview/assets/icons/steamdeck_button_options_outline.svg new file mode 100644 index 0000000..bde6673 --- /dev/null +++ b/src/mainview/assets/icons/steamdeck_button_options_outline.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:779750ae626aac0bf66fa7540d6602dae218c5466416d63ad63956cb1a9e9b41 +size 640 diff --git a/src/mainview/assets/icons/steamdeck_button_quickaccess.svg b/src/mainview/assets/icons/steamdeck_button_quickaccess.svg new file mode 100644 index 0000000..5ce3d9a --- /dev/null +++ b/src/mainview/assets/icons/steamdeck_button_quickaccess.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:10ebe5420522f321303abb7a37cf97f42ef907040c3f51f372d1b25f74ab7d65 +size 785 diff --git a/src/mainview/assets/icons/steamdeck_button_quickaccess_outline.svg b/src/mainview/assets/icons/steamdeck_button_quickaccess_outline.svg new file mode 100644 index 0000000..fde02f2 --- /dev/null +++ b/src/mainview/assets/icons/steamdeck_button_quickaccess_outline.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d4466112c65466fedd9561829d9e103eed2b36295ebb059c4d6d71a01db29a7c +size 961 diff --git a/src/mainview/assets/icons/steamdeck_button_r1.svg b/src/mainview/assets/icons/steamdeck_button_r1.svg new file mode 100644 index 0000000..20da102 --- /dev/null +++ b/src/mainview/assets/icons/steamdeck_button_r1.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:cf6a3c9ab5f573f60e714cd7dbe4dc5b515923e315ad79b85d6213fd2c1e0533 +size 631 diff --git a/src/mainview/assets/icons/steamdeck_button_r1_outline.svg b/src/mainview/assets/icons/steamdeck_button_r1_outline.svg new file mode 100644 index 0000000..f9c24e8 --- /dev/null +++ b/src/mainview/assets/icons/steamdeck_button_r1_outline.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:033b6e7a75b5cdc3788baf8098f5aec68ab259e0937aea34dde32cbf743d9ce0 +size 767 diff --git a/src/mainview/assets/icons/steamdeck_button_r2.svg b/src/mainview/assets/icons/steamdeck_button_r2.svg new file mode 100644 index 0000000..a4c4e6b --- /dev/null +++ b/src/mainview/assets/icons/steamdeck_button_r2.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:21e2c8cbbb42d13344229211264fb3bc48addf84dc5cd0621d9efd2b412bbff3 +size 854 diff --git a/src/mainview/assets/icons/steamdeck_button_r2_outline.svg b/src/mainview/assets/icons/steamdeck_button_r2_outline.svg new file mode 100644 index 0000000..5b41e79 --- /dev/null +++ b/src/mainview/assets/icons/steamdeck_button_r2_outline.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:18d8de12ad48dbb3763ae49ecfe620823d61d7b52512f0ba1cb7c37d636c70c6 +size 990 diff --git a/src/mainview/assets/icons/steamdeck_button_r4.svg b/src/mainview/assets/icons/steamdeck_button_r4.svg new file mode 100644 index 0000000..e08f736 --- /dev/null +++ b/src/mainview/assets/icons/steamdeck_button_r4.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:fcfab10973a7e67d211e5c52a4fa9472ddae6bb5e791f2e1656d85987fc1ead0 +size 615 diff --git a/src/mainview/assets/icons/steamdeck_button_r4_outline.svg b/src/mainview/assets/icons/steamdeck_button_r4_outline.svg new file mode 100644 index 0000000..669c884 --- /dev/null +++ b/src/mainview/assets/icons/steamdeck_button_r4_outline.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:14bfa85d9d890827d759b5a4870188a4a2a7e4244a1c80432d35624f471307a1 +size 702 diff --git a/src/mainview/assets/icons/steamdeck_button_r5.svg b/src/mainview/assets/icons/steamdeck_button_r5.svg new file mode 100644 index 0000000..d19c02d --- /dev/null +++ b/src/mainview/assets/icons/steamdeck_button_r5.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:68fec480dfe5982f4b8af59b2f94ae637f382eb8ff01c3e682032db309950da7 +size 859 diff --git a/src/mainview/assets/icons/steamdeck_button_r5_outline.svg b/src/mainview/assets/icons/steamdeck_button_r5_outline.svg new file mode 100644 index 0000000..93c797e --- /dev/null +++ b/src/mainview/assets/icons/steamdeck_button_r5_outline.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e64068d1915bf084d6b76ce9dddded1d8dc977c5c81039d070fd1292a967d950 +size 946 diff --git a/src/mainview/assets/icons/steamdeck_button_view.svg b/src/mainview/assets/icons/steamdeck_button_view.svg new file mode 100644 index 0000000..054b9a4 --- /dev/null +++ b/src/mainview/assets/icons/steamdeck_button_view.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:305d27bdba89253cc27e9837589099730303ab8847c3aead27e37caa18b5c54c +size 434 diff --git a/src/mainview/assets/icons/steamdeck_button_view_outline.svg b/src/mainview/assets/icons/steamdeck_button_view_outline.svg new file mode 100644 index 0000000..6f63d97 --- /dev/null +++ b/src/mainview/assets/icons/steamdeck_button_view_outline.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:88f00f53712e58fe40a2700d9fce91f544c7c7a6ac493a2658f20660ed686b92 +size 677 diff --git a/src/mainview/assets/icons/steamdeck_button_x.svg b/src/mainview/assets/icons/steamdeck_button_x.svg new file mode 100644 index 0000000..b850753 --- /dev/null +++ b/src/mainview/assets/icons/steamdeck_button_x.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:505b595feca94a6dbb3b4bfb1f8213e108fab2d3419f265d7f42c7c1c1f3c711 +size 458 diff --git a/src/mainview/assets/icons/steamdeck_button_x_outline.svg b/src/mainview/assets/icons/steamdeck_button_x_outline.svg new file mode 100644 index 0000000..cd1a2ec --- /dev/null +++ b/src/mainview/assets/icons/steamdeck_button_x_outline.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:025d0ba752f08e010ebc8eec4970f0a9b85143f971626547059bab43da75e640 +size 612 diff --git a/src/mainview/assets/icons/steamdeck_button_y.svg b/src/mainview/assets/icons/steamdeck_button_y.svg new file mode 100644 index 0000000..ed91106 --- /dev/null +++ b/src/mainview/assets/icons/steamdeck_button_y.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c509a5a985e6c6ba9bbe6caa593571488ea4307d4d134632564742cc4f98dc03 +size 407 diff --git a/src/mainview/assets/icons/steamdeck_button_y_outline.svg b/src/mainview/assets/icons/steamdeck_button_y_outline.svg new file mode 100644 index 0000000..0752fe9 --- /dev/null +++ b/src/mainview/assets/icons/steamdeck_button_y_outline.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:86bb6b4010c8c9266d3dde3c2d6652e40af295b6a40dd2a3fc9d33fdd1f85d46 +size 561 diff --git a/src/mainview/assets/icons/steamdeck_dpad.svg b/src/mainview/assets/icons/steamdeck_dpad.svg new file mode 100644 index 0000000..399f6e9 --- /dev/null +++ b/src/mainview/assets/icons/steamdeck_dpad.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1d3528fa6ae21e2356484744c78754b455d9fce97974b5508ec424cce675f495 +size 363 diff --git a/src/mainview/assets/icons/steamdeck_dpad_all.svg b/src/mainview/assets/icons/steamdeck_dpad_all.svg new file mode 100644 index 0000000..689913c --- /dev/null +++ b/src/mainview/assets/icons/steamdeck_dpad_all.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4d2a5c8514420a260df791079f45d17f8e909ef939f2209fed8e37aad83a094a +size 365 diff --git a/src/mainview/assets/icons/steamdeck_dpad_down.svg b/src/mainview/assets/icons/steamdeck_dpad_down.svg new file mode 100644 index 0000000..b78660f --- /dev/null +++ b/src/mainview/assets/icons/steamdeck_dpad_down.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d7a0d403e36c41120882f5713927e828794cdff93f88f8d3cbea3d8384b322c9 +size 430 diff --git a/src/mainview/assets/icons/steamdeck_dpad_down_outline.svg b/src/mainview/assets/icons/steamdeck_dpad_down_outline.svg new file mode 100644 index 0000000..b89ee75 --- /dev/null +++ b/src/mainview/assets/icons/steamdeck_dpad_down_outline.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:30191d381376e36424aea24977e9681d3dbde19cee0755b764ad56c6ce0854db +size 502 diff --git a/src/mainview/assets/icons/steamdeck_dpad_horizontal.svg b/src/mainview/assets/icons/steamdeck_dpad_horizontal.svg new file mode 100644 index 0000000..62a1c2f --- /dev/null +++ b/src/mainview/assets/icons/steamdeck_dpad_horizontal.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7dfc37399407392f40eb8b0e048b14cdc603f8c3612183bce7dc8b9f3dd5df9e +size 450 diff --git a/src/mainview/assets/icons/steamdeck_dpad_horizontal_outline.svg b/src/mainview/assets/icons/steamdeck_dpad_horizontal_outline.svg new file mode 100644 index 0000000..806b155 --- /dev/null +++ b/src/mainview/assets/icons/steamdeck_dpad_horizontal_outline.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2018162f5cd92e868d9f40901deb481ec10b2934d91355f48b61a4154950b888 +size 450 diff --git a/src/mainview/assets/icons/steamdeck_dpad_left.svg b/src/mainview/assets/icons/steamdeck_dpad_left.svg new file mode 100644 index 0000000..e13fd31 --- /dev/null +++ b/src/mainview/assets/icons/steamdeck_dpad_left.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6fc565008a474f3c3899cc97854947a51700ce925523bf155ba77e7c28c658f6 +size 430 diff --git a/src/mainview/assets/icons/steamdeck_dpad_left_outline.svg b/src/mainview/assets/icons/steamdeck_dpad_left_outline.svg new file mode 100644 index 0000000..a45a2b1 --- /dev/null +++ b/src/mainview/assets/icons/steamdeck_dpad_left_outline.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ea55e89dd9c1af652abce093589d96ee3188e964a2adccd056e58e5e1b59c703 +size 502 diff --git a/src/mainview/assets/icons/steamdeck_dpad_none.svg b/src/mainview/assets/icons/steamdeck_dpad_none.svg new file mode 100644 index 0000000..64fe006 --- /dev/null +++ b/src/mainview/assets/icons/steamdeck_dpad_none.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9fb0ee7a390e4d99337147672a656fee244bd8f0d4f516f7ec7afd605a89e1af +size 554 diff --git a/src/mainview/assets/icons/steamdeck_dpad_right.svg b/src/mainview/assets/icons/steamdeck_dpad_right.svg new file mode 100644 index 0000000..cf3907e --- /dev/null +++ b/src/mainview/assets/icons/steamdeck_dpad_right.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5e3e358a70aaa5ea7236aef3504491051af91847466c349965cc345dd5b7dcb0 +size 430 diff --git a/src/mainview/assets/icons/steamdeck_dpad_right_outline.svg b/src/mainview/assets/icons/steamdeck_dpad_right_outline.svg new file mode 100644 index 0000000..22280f3 --- /dev/null +++ b/src/mainview/assets/icons/steamdeck_dpad_right_outline.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:579ef69456f160f697103915ce49692873318d7e7833630fcaa1489b314b13df +size 502 diff --git a/src/mainview/assets/icons/steamdeck_dpad_up.svg b/src/mainview/assets/icons/steamdeck_dpad_up.svg new file mode 100644 index 0000000..86b9113 --- /dev/null +++ b/src/mainview/assets/icons/steamdeck_dpad_up.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1eb952dcac0a986a5ab4f5cf61ee832504554cdc2df46b20dc0998a91b70e25b +size 430 diff --git a/src/mainview/assets/icons/steamdeck_dpad_up_outline.svg b/src/mainview/assets/icons/steamdeck_dpad_up_outline.svg new file mode 100644 index 0000000..6b1986e --- /dev/null +++ b/src/mainview/assets/icons/steamdeck_dpad_up_outline.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:addf544d6a58f5c888ea5cfb69300cb668eed3d6c83d130290cccd607679cb08 +size 502 diff --git a/src/mainview/assets/icons/steamdeck_dpad_vertical.svg b/src/mainview/assets/icons/steamdeck_dpad_vertical.svg new file mode 100644 index 0000000..2611724 --- /dev/null +++ b/src/mainview/assets/icons/steamdeck_dpad_vertical.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c880bf479bb69bd2aa126220f9c9b0967780ac558eb59080618d7e2b8bb15565 +size 450 diff --git a/src/mainview/assets/icons/steamdeck_dpad_vertical_outline.svg b/src/mainview/assets/icons/steamdeck_dpad_vertical_outline.svg new file mode 100644 index 0000000..dd2452b --- /dev/null +++ b/src/mainview/assets/icons/steamdeck_dpad_vertical_outline.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:71bd0cb736cb75b461b60ef75c84c8445e94b243eb0ceaa666f8130c989d9ae6 +size 450 diff --git a/src/mainview/assets/icons/steamdeck_stick_l.svg b/src/mainview/assets/icons/steamdeck_stick_l.svg new file mode 100644 index 0000000..16da128 --- /dev/null +++ b/src/mainview/assets/icons/steamdeck_stick_l.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c5097b1eab526cddc799ae77a6bf8d29b759408be2420357ba85b7441d6430e2 +size 973 diff --git a/src/mainview/assets/icons/steamdeck_stick_l_down.svg b/src/mainview/assets/icons/steamdeck_stick_l_down.svg new file mode 100644 index 0000000..16fc643 --- /dev/null +++ b/src/mainview/assets/icons/steamdeck_stick_l_down.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9be226409c17137a0541ee2416c05e3e5658bc99b183406217a72874c4002404 +size 1872 diff --git a/src/mainview/assets/icons/steamdeck_stick_l_horizontal.svg b/src/mainview/assets/icons/steamdeck_stick_l_horizontal.svg new file mode 100644 index 0000000..26dad8e --- /dev/null +++ b/src/mainview/assets/icons/steamdeck_stick_l_horizontal.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d194cf9c42a3e7a2270fc29867bb66756b63eeeded96ccc4181a84123d62e71a +size 2470 diff --git a/src/mainview/assets/icons/steamdeck_stick_l_left.svg b/src/mainview/assets/icons/steamdeck_stick_l_left.svg new file mode 100644 index 0000000..94b883a --- /dev/null +++ b/src/mainview/assets/icons/steamdeck_stick_l_left.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2fc7ece01211833e713b34c75073019e2632947d99aa0c4cd565bfd07ed7d474 +size 1746 diff --git a/src/mainview/assets/icons/steamdeck_stick_l_press.svg b/src/mainview/assets/icons/steamdeck_stick_l_press.svg new file mode 100644 index 0000000..6e3485f --- /dev/null +++ b/src/mainview/assets/icons/steamdeck_stick_l_press.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:caad8e34f27bf6c86592595bc35affda557cebc2b48a2226b272ceeafea94682 +size 1801 diff --git a/src/mainview/assets/icons/steamdeck_stick_l_right.svg b/src/mainview/assets/icons/steamdeck_stick_l_right.svg new file mode 100644 index 0000000..40d3bbb --- /dev/null +++ b/src/mainview/assets/icons/steamdeck_stick_l_right.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4554269a9685d991f69912613bef912be968e984926d915dfa75defb440b608c +size 1743 diff --git a/src/mainview/assets/icons/steamdeck_stick_l_up.svg b/src/mainview/assets/icons/steamdeck_stick_l_up.svg new file mode 100644 index 0000000..1d37fe8 --- /dev/null +++ b/src/mainview/assets/icons/steamdeck_stick_l_up.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:555342c2a3376ce6f4669e6fae17226b825636baf09b7473e38809a90ef722ec +size 1783 diff --git a/src/mainview/assets/icons/steamdeck_stick_l_vertical.svg b/src/mainview/assets/icons/steamdeck_stick_l_vertical.svg new file mode 100644 index 0000000..c6a25a2 --- /dev/null +++ b/src/mainview/assets/icons/steamdeck_stick_l_vertical.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2888956302e4c8db1be3ccc2d122114f084a1cf90029129a4ee5d6718722ee81 +size 2626 diff --git a/src/mainview/assets/icons/steamdeck_stick_r.svg b/src/mainview/assets/icons/steamdeck_stick_r.svg new file mode 100644 index 0000000..3db04a6 --- /dev/null +++ b/src/mainview/assets/icons/steamdeck_stick_r.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c8ba98ac6b7793d1033a230df73f9b51f9ba2205ec15febcc481597c165c0b65 +size 1155 diff --git a/src/mainview/assets/icons/steamdeck_stick_r_down.svg b/src/mainview/assets/icons/steamdeck_stick_r_down.svg new file mode 100644 index 0000000..32e8b32 --- /dev/null +++ b/src/mainview/assets/icons/steamdeck_stick_r_down.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:95b5f2817b66cf375210d54f7643a34f6c24c051d6be05ce945f7ec7355854b7 +size 2060 diff --git a/src/mainview/assets/icons/steamdeck_stick_r_horizontal.svg b/src/mainview/assets/icons/steamdeck_stick_r_horizontal.svg new file mode 100644 index 0000000..51874b5 --- /dev/null +++ b/src/mainview/assets/icons/steamdeck_stick_r_horizontal.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2ace97ffa08117b65500cb4c8028d669594093ed26d5c557bcf9404504d9c98e +size 2652 diff --git a/src/mainview/assets/icons/steamdeck_stick_r_left.svg b/src/mainview/assets/icons/steamdeck_stick_r_left.svg new file mode 100644 index 0000000..94a6b60 --- /dev/null +++ b/src/mainview/assets/icons/steamdeck_stick_r_left.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d4f4719bde017509ace548ec8acdfab2db09f584b4fc107ba91ba42583c308f7 +size 1928 diff --git a/src/mainview/assets/icons/steamdeck_stick_r_press.svg b/src/mainview/assets/icons/steamdeck_stick_r_press.svg new file mode 100644 index 0000000..85d3f41 --- /dev/null +++ b/src/mainview/assets/icons/steamdeck_stick_r_press.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ffb32bd4f1c3b306e2d0f9bcbdb82ac1d1e4641821417e08196bff8d6b72ac94 +size 1983 diff --git a/src/mainview/assets/icons/steamdeck_stick_r_right.svg b/src/mainview/assets/icons/steamdeck_stick_r_right.svg new file mode 100644 index 0000000..603ba41 --- /dev/null +++ b/src/mainview/assets/icons/steamdeck_stick_r_right.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1483899f0410e6d31297c716aa7e41eb9aaff562446f7bc421aec6ebe4a9a063 +size 1925 diff --git a/src/mainview/assets/icons/steamdeck_stick_r_up.svg b/src/mainview/assets/icons/steamdeck_stick_r_up.svg new file mode 100644 index 0000000..3db7b85 --- /dev/null +++ b/src/mainview/assets/icons/steamdeck_stick_r_up.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:0875649bc82d1bf4ce801141dac1466b9d949e0d48c423cbff2ede43a90b926a +size 1965 diff --git a/src/mainview/assets/icons/steamdeck_stick_r_vertical.svg b/src/mainview/assets/icons/steamdeck_stick_r_vertical.svg new file mode 100644 index 0000000..d42520c --- /dev/null +++ b/src/mainview/assets/icons/steamdeck_stick_r_vertical.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:fa02fa1bc473de5754e2035d49ab6fc71d9e454a7b98e8a63d2e01556e5207f8 +size 2808 diff --git a/src/mainview/assets/icons/steamdeck_stick_side_l.svg b/src/mainview/assets/icons/steamdeck_stick_side_l.svg new file mode 100644 index 0000000..52c2d9d --- /dev/null +++ b/src/mainview/assets/icons/steamdeck_stick_side_l.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e9308f9e55d337b912b07b217a3f64944056f61ad0e8bb58d536ca74c338689e +size 619 diff --git a/src/mainview/assets/icons/steamdeck_stick_side_r.svg b/src/mainview/assets/icons/steamdeck_stick_side_r.svg new file mode 100644 index 0000000..38138b9 --- /dev/null +++ b/src/mainview/assets/icons/steamdeck_stick_side_r.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e4682d72fcfcb6c0254329583ce76d8d3f3b29aba14cd5a5d2555e88ec2a4599 +size 822 diff --git a/src/mainview/assets/icons/steamdeck_stick_top_l.svg b/src/mainview/assets/icons/steamdeck_stick_top_l.svg new file mode 100644 index 0000000..1cb11ac --- /dev/null +++ b/src/mainview/assets/icons/steamdeck_stick_top_l.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ae7b1aaf3079a22cae6738d0d05af87176749c13f18e386621a1e92f90a438ef +size 750 diff --git a/src/mainview/assets/icons/steamdeck_stick_top_r.svg b/src/mainview/assets/icons/steamdeck_stick_top_r.svg new file mode 100644 index 0000000..6644ce1 --- /dev/null +++ b/src/mainview/assets/icons/steamdeck_stick_top_r.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5a5485cc4428eab269ffe3b502e09c5de6a8c71ea24181282a44950c90dddfa4 +size 987 diff --git a/src/mainview/assets/icons/steamdeck_trackpad.svg b/src/mainview/assets/icons/steamdeck_trackpad.svg new file mode 100644 index 0000000..b0d0b43 --- /dev/null +++ b/src/mainview/assets/icons/steamdeck_trackpad.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:be26548a9b95f1b4a23a84bebe4cfe22e0059ff98e8cf93ea2b3b852b7b87678 +size 259 diff --git a/src/mainview/assets/icons/steamdeck_trackpad_all.svg b/src/mainview/assets/icons/steamdeck_trackpad_all.svg new file mode 100644 index 0000000..b473427 --- /dev/null +++ b/src/mainview/assets/icons/steamdeck_trackpad_all.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:dc1496e6ba14470957c05fa63b8c5632c6f0a2d67dc00e64283ccd9936951f0e +size 3481 diff --git a/src/mainview/assets/icons/steamdeck_trackpad_all_outline.svg b/src/mainview/assets/icons/steamdeck_trackpad_all_outline.svg new file mode 100644 index 0000000..0acdfcf --- /dev/null +++ b/src/mainview/assets/icons/steamdeck_trackpad_all_outline.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4d1a4fa8532205636afb7f9bed6ad35f9a579001d3f9aaf355f031e135ef57e4 +size 3447 diff --git a/src/mainview/assets/icons/steamdeck_trackpad_down.svg b/src/mainview/assets/icons/steamdeck_trackpad_down.svg new file mode 100644 index 0000000..01caf48 --- /dev/null +++ b/src/mainview/assets/icons/steamdeck_trackpad_down.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6610083c2617e70fa891cb3d84c14ed6f4b6fac07b99e880de2e266230ce6fb5 +size 1140 diff --git a/src/mainview/assets/icons/steamdeck_trackpad_down_outline.svg b/src/mainview/assets/icons/steamdeck_trackpad_down_outline.svg new file mode 100644 index 0000000..11e0036 --- /dev/null +++ b/src/mainview/assets/icons/steamdeck_trackpad_down_outline.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:0a12fe445841f76bc2484aa93a7011930551ae2406f80cac2eea5b7fb25d933c +size 1176 diff --git a/src/mainview/assets/icons/steamdeck_trackpad_horizontal.svg b/src/mainview/assets/icons/steamdeck_trackpad_horizontal.svg new file mode 100644 index 0000000..28de11c --- /dev/null +++ b/src/mainview/assets/icons/steamdeck_trackpad_horizontal.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:fd147eda18aaa56b1197e2f60a6275d60dd7dddb10a86debe32975388ddcc87e +size 1888 diff --git a/src/mainview/assets/icons/steamdeck_trackpad_horizontal_outline.svg b/src/mainview/assets/icons/steamdeck_trackpad_horizontal_outline.svg new file mode 100644 index 0000000..278c9b4 --- /dev/null +++ b/src/mainview/assets/icons/steamdeck_trackpad_horizontal_outline.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9015119d6f627099f2d677d901f43952376ca7afc1d7e6b6209680e10a0256a0 +size 1906 diff --git a/src/mainview/assets/icons/steamdeck_trackpad_l.svg b/src/mainview/assets/icons/steamdeck_trackpad_l.svg new file mode 100644 index 0000000..a1f88f1 --- /dev/null +++ b/src/mainview/assets/icons/steamdeck_trackpad_l.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b45643dd9abc485963dbce06107b2ca5419b456173b9a2db8f9d5c79c6c385af +size 303 diff --git a/src/mainview/assets/icons/steamdeck_trackpad_l_all.svg b/src/mainview/assets/icons/steamdeck_trackpad_l_all.svg new file mode 100644 index 0000000..b7efe99 --- /dev/null +++ b/src/mainview/assets/icons/steamdeck_trackpad_l_all.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ec76144c82feac5da4b6611f2c12f5d99e3934b44f98f86874a164e0d236bb1e +size 3525 diff --git a/src/mainview/assets/icons/steamdeck_trackpad_l_all_outline.svg b/src/mainview/assets/icons/steamdeck_trackpad_l_all_outline.svg new file mode 100644 index 0000000..4e2fee3 --- /dev/null +++ b/src/mainview/assets/icons/steamdeck_trackpad_l_all_outline.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:eb49a0b7d2daa0a742719d9cd6d81b085fbaa5f38b6fe9ff8328c6dda5fb09ae +size 3491 diff --git a/src/mainview/assets/icons/steamdeck_trackpad_l_down.svg b/src/mainview/assets/icons/steamdeck_trackpad_l_down.svg new file mode 100644 index 0000000..92d666b --- /dev/null +++ b/src/mainview/assets/icons/steamdeck_trackpad_l_down.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:52238c1c1b42c537537bd6de99283cf728e17c739e130050ec2aa0562bbb4f91 +size 1184 diff --git a/src/mainview/assets/icons/steamdeck_trackpad_l_down_outline.svg b/src/mainview/assets/icons/steamdeck_trackpad_l_down_outline.svg new file mode 100644 index 0000000..bc12121 --- /dev/null +++ b/src/mainview/assets/icons/steamdeck_trackpad_l_down_outline.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1df7547c88fe536cb863ba12e276f5843df19bcbaf7e2d077f650f1da8efdc16 +size 1220 diff --git a/src/mainview/assets/icons/steamdeck_trackpad_l_horizontal.svg b/src/mainview/assets/icons/steamdeck_trackpad_l_horizontal.svg new file mode 100644 index 0000000..6d7dced --- /dev/null +++ b/src/mainview/assets/icons/steamdeck_trackpad_l_horizontal.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a5650d2e335646c56d8c01c2457eb2a4cc07fdb1f3b7bd338e339d4b8dddfaca +size 1932 diff --git a/src/mainview/assets/icons/steamdeck_trackpad_l_horizontal_outline.svg b/src/mainview/assets/icons/steamdeck_trackpad_l_horizontal_outline.svg new file mode 100644 index 0000000..8408ee5 --- /dev/null +++ b/src/mainview/assets/icons/steamdeck_trackpad_l_horizontal_outline.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:563cae2e2c63ec2f1099c65ab72ea9fe1d9e0f3c52c3bec1d438f23bd26710d4 +size 1950 diff --git a/src/mainview/assets/icons/steamdeck_trackpad_l_left.svg b/src/mainview/assets/icons/steamdeck_trackpad_l_left.svg new file mode 100644 index 0000000..ecc1f82 --- /dev/null +++ b/src/mainview/assets/icons/steamdeck_trackpad_l_left.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:06d6bc3fb2c8972ab521e74ba864e561a53c6b38dfa44822439b7f48eb9153c9 +size 1135 diff --git a/src/mainview/assets/icons/steamdeck_trackpad_l_left_outline.svg b/src/mainview/assets/icons/steamdeck_trackpad_l_left_outline.svg new file mode 100644 index 0000000..64fa5ba --- /dev/null +++ b/src/mainview/assets/icons/steamdeck_trackpad_l_left_outline.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:0475b50e455267c5d2c104efd5f9fefc6fc083cbfb1786e187f70a17edf19860 +size 1169 diff --git a/src/mainview/assets/icons/steamdeck_trackpad_l_outline.svg b/src/mainview/assets/icons/steamdeck_trackpad_l_outline.svg new file mode 100644 index 0000000..16d52e2 --- /dev/null +++ b/src/mainview/assets/icons/steamdeck_trackpad_l_outline.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7871b326d25fdf503d2d4c783f6ff14f6b757a9015d652aa0bdb48b0d79e2f47 +size 390 diff --git a/src/mainview/assets/icons/steamdeck_trackpad_l_right.svg b/src/mainview/assets/icons/steamdeck_trackpad_l_right.svg new file mode 100644 index 0000000..93edbe8 --- /dev/null +++ b/src/mainview/assets/icons/steamdeck_trackpad_l_right.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c504bb0135959dba2fba9b5dfaca389dd9b34848a77ab0b324b5540845c040c0 +size 1166 diff --git a/src/mainview/assets/icons/steamdeck_trackpad_l_right_outline.svg b/src/mainview/assets/icons/steamdeck_trackpad_l_right_outline.svg new file mode 100644 index 0000000..f62a5e8 --- /dev/null +++ b/src/mainview/assets/icons/steamdeck_trackpad_l_right_outline.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:988dabcc69fb35427b0abfd7157b27857d6b3c55874f772fdab8cf55138a5cde +size 1220 diff --git a/src/mainview/assets/icons/steamdeck_trackpad_l_up.svg b/src/mainview/assets/icons/steamdeck_trackpad_l_up.svg new file mode 100644 index 0000000..5271c33 --- /dev/null +++ b/src/mainview/assets/icons/steamdeck_trackpad_l_up.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b0990da55ad9cd0d3409e3fa3cd37d6c37c8b3d8aac42fc1e5fb693cb2f1e10d +size 1149 diff --git a/src/mainview/assets/icons/steamdeck_trackpad_l_up_outline.svg b/src/mainview/assets/icons/steamdeck_trackpad_l_up_outline.svg new file mode 100644 index 0000000..cfa305c --- /dev/null +++ b/src/mainview/assets/icons/steamdeck_trackpad_l_up_outline.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8658a5db3db7d6629b571341b565740148b855d9667d6d7e9e79b4b69e23a71a +size 1190 diff --git a/src/mainview/assets/icons/steamdeck_trackpad_l_vertical.svg b/src/mainview/assets/icons/steamdeck_trackpad_l_vertical.svg new file mode 100644 index 0000000..6064738 --- /dev/null +++ b/src/mainview/assets/icons/steamdeck_trackpad_l_vertical.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b7007d4b2b3bbef01f3ff6b15c089f51d41416b95a50a189030ec7e20724e649 +size 1963 diff --git a/src/mainview/assets/icons/steamdeck_trackpad_l_vertical_outline.svg b/src/mainview/assets/icons/steamdeck_trackpad_l_vertical_outline.svg new file mode 100644 index 0000000..b3afa7f --- /dev/null +++ b/src/mainview/assets/icons/steamdeck_trackpad_l_vertical_outline.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ea4be96132fb49aef45d18d2a6eb33d5f20a18e325e68b6a7d6204e940eea8b7 +size 1974 diff --git a/src/mainview/assets/icons/steamdeck_trackpad_left.svg b/src/mainview/assets/icons/steamdeck_trackpad_left.svg new file mode 100644 index 0000000..e744586 --- /dev/null +++ b/src/mainview/assets/icons/steamdeck_trackpad_left.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5ff260c3b91b78202538deb107dc265ed62b3ea8a81f21c44e8f9671551ed8c4 +size 1091 diff --git a/src/mainview/assets/icons/steamdeck_trackpad_left_outline.svg b/src/mainview/assets/icons/steamdeck_trackpad_left_outline.svg new file mode 100644 index 0000000..106ff75 --- /dev/null +++ b/src/mainview/assets/icons/steamdeck_trackpad_left_outline.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:30f72593cdd5821e8f4805a34d1b31137267d5d3313c2e1f00ea3763e555d5fb +size 1125 diff --git a/src/mainview/assets/icons/steamdeck_trackpad_outline.svg b/src/mainview/assets/icons/steamdeck_trackpad_outline.svg new file mode 100644 index 0000000..0edce19 --- /dev/null +++ b/src/mainview/assets/icons/steamdeck_trackpad_outline.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4670243235e4c221f94963180deea51dc700f27d223eee0025a9e4992c80d279 +size 346 diff --git a/src/mainview/assets/icons/steamdeck_trackpad_r.svg b/src/mainview/assets/icons/steamdeck_trackpad_r.svg new file mode 100644 index 0000000..3774b87 --- /dev/null +++ b/src/mainview/assets/icons/steamdeck_trackpad_r.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5aa01a46c32b48fb553ee2e0a8eff0b93c5fd0b126e87c9af7aaa892c61c899c +size 555 diff --git a/src/mainview/assets/icons/steamdeck_trackpad_r_all.svg b/src/mainview/assets/icons/steamdeck_trackpad_r_all.svg new file mode 100644 index 0000000..9407c41 --- /dev/null +++ b/src/mainview/assets/icons/steamdeck_trackpad_r_all.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b5f7c65e802097c7050c483553f96c67c0370ad137a8c4af15609f362160df4d +size 3777 diff --git a/src/mainview/assets/icons/steamdeck_trackpad_r_all_outline.svg b/src/mainview/assets/icons/steamdeck_trackpad_r_all_outline.svg new file mode 100644 index 0000000..e90ddf3 --- /dev/null +++ b/src/mainview/assets/icons/steamdeck_trackpad_r_all_outline.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:dd1719a7fa15f53406687508725a8cea6a3aa3aacb2b891b7ea0174c5b8a3271 +size 3743 diff --git a/src/mainview/assets/icons/steamdeck_trackpad_r_down.svg b/src/mainview/assets/icons/steamdeck_trackpad_r_down.svg new file mode 100644 index 0000000..ffb873a --- /dev/null +++ b/src/mainview/assets/icons/steamdeck_trackpad_r_down.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:61b8afcf65ecd565f97fd68c5fad5e281fdc671e136fbae63f2f9a227fb6619d +size 1436 diff --git a/src/mainview/assets/icons/steamdeck_trackpad_r_down_outline.svg b/src/mainview/assets/icons/steamdeck_trackpad_r_down_outline.svg new file mode 100644 index 0000000..3da4684 --- /dev/null +++ b/src/mainview/assets/icons/steamdeck_trackpad_r_down_outline.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:55471edff62579cd3955deb9bd827c4108c85141fea35eb1fbcc6ffed39f0357 +size 1472 diff --git a/src/mainview/assets/icons/steamdeck_trackpad_r_horizontal.svg b/src/mainview/assets/icons/steamdeck_trackpad_r_horizontal.svg new file mode 100644 index 0000000..14f249b --- /dev/null +++ b/src/mainview/assets/icons/steamdeck_trackpad_r_horizontal.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2a17cccc04d939ee6e351e4a476abb062c9d057d022228d57bc3efb2ed736010 +size 2184 diff --git a/src/mainview/assets/icons/steamdeck_trackpad_r_horizontal_outline.svg b/src/mainview/assets/icons/steamdeck_trackpad_r_horizontal_outline.svg new file mode 100644 index 0000000..e44c63b --- /dev/null +++ b/src/mainview/assets/icons/steamdeck_trackpad_r_horizontal_outline.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3444459e7af85cc54c3148646fddfec9b76610ea26151a02a543cb3e7fb3f3d0 +size 2202 diff --git a/src/mainview/assets/icons/steamdeck_trackpad_r_left.svg b/src/mainview/assets/icons/steamdeck_trackpad_r_left.svg new file mode 100644 index 0000000..b2cde66 --- /dev/null +++ b/src/mainview/assets/icons/steamdeck_trackpad_r_left.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:37cb922a162b88b301c7232b0424ca1ea057d6884009a133ef3ed838272af862 +size 1387 diff --git a/src/mainview/assets/icons/steamdeck_trackpad_r_left_outline.svg b/src/mainview/assets/icons/steamdeck_trackpad_r_left_outline.svg new file mode 100644 index 0000000..9adda12 --- /dev/null +++ b/src/mainview/assets/icons/steamdeck_trackpad_r_left_outline.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ae216ad04ab7e2090811438d8e7929a3ba28f5125ee74ac1367ab5419618c56b +size 1421 diff --git a/src/mainview/assets/icons/steamdeck_trackpad_r_outline.svg b/src/mainview/assets/icons/steamdeck_trackpad_r_outline.svg new file mode 100644 index 0000000..05cd4a4 --- /dev/null +++ b/src/mainview/assets/icons/steamdeck_trackpad_r_outline.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ce3b1bbbb5c95a1fbf6b61a10a6f432f70306d2fb4472059e6a89c76902e1d28 +size 642 diff --git a/src/mainview/assets/icons/steamdeck_trackpad_r_right.svg b/src/mainview/assets/icons/steamdeck_trackpad_r_right.svg new file mode 100644 index 0000000..d3d9cf0 --- /dev/null +++ b/src/mainview/assets/icons/steamdeck_trackpad_r_right.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4dfd3a7be5905d9b1dbd839e2f43556e7f0e85af2b4cf8e8773cc65cfa463a7d +size 1418 diff --git a/src/mainview/assets/icons/steamdeck_trackpad_r_right_outline.svg b/src/mainview/assets/icons/steamdeck_trackpad_r_right_outline.svg new file mode 100644 index 0000000..d3fc57f --- /dev/null +++ b/src/mainview/assets/icons/steamdeck_trackpad_r_right_outline.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9db979bef06d806c1b63a94134a4254da22c4e9f0fdbc2679c486f6f8f81700e +size 1472 diff --git a/src/mainview/assets/icons/steamdeck_trackpad_r_up.svg b/src/mainview/assets/icons/steamdeck_trackpad_r_up.svg new file mode 100644 index 0000000..7cd428c --- /dev/null +++ b/src/mainview/assets/icons/steamdeck_trackpad_r_up.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2514ea2880a31c93bb1a180fbac29e532f9beffecfd7cd2e1cca6ee7cf060e15 +size 1401 diff --git a/src/mainview/assets/icons/steamdeck_trackpad_r_up_outline.svg b/src/mainview/assets/icons/steamdeck_trackpad_r_up_outline.svg new file mode 100644 index 0000000..c0488da --- /dev/null +++ b/src/mainview/assets/icons/steamdeck_trackpad_r_up_outline.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9ad8a2c54ee3b4d8e9cf47ccfe8d8901f193910d2c6de9928a6ae26d2f59be22 +size 1442 diff --git a/src/mainview/assets/icons/steamdeck_trackpad_r_vertical.svg b/src/mainview/assets/icons/steamdeck_trackpad_r_vertical.svg new file mode 100644 index 0000000..d8ad878 --- /dev/null +++ b/src/mainview/assets/icons/steamdeck_trackpad_r_vertical.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c7b588e810d86ac65971cdb8bb470fbc39609cb7ab0da5510ae627fe126fd486 +size 2215 diff --git a/src/mainview/assets/icons/steamdeck_trackpad_r_vertical_outline.svg b/src/mainview/assets/icons/steamdeck_trackpad_r_vertical_outline.svg new file mode 100644 index 0000000..b34a19f --- /dev/null +++ b/src/mainview/assets/icons/steamdeck_trackpad_r_vertical_outline.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:04235734f1f356250436cc2cce8f74aeee4ac871aa0c0e777bfc905a05e35210 +size 2226 diff --git a/src/mainview/assets/icons/steamdeck_trackpad_right.svg b/src/mainview/assets/icons/steamdeck_trackpad_right.svg new file mode 100644 index 0000000..719301a --- /dev/null +++ b/src/mainview/assets/icons/steamdeck_trackpad_right.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d2544aa9e808dc245494a8fa51cc835f79eb3d2111972c8216fc15702968e531 +size 1122 diff --git a/src/mainview/assets/icons/steamdeck_trackpad_right_outline.svg b/src/mainview/assets/icons/steamdeck_trackpad_right_outline.svg new file mode 100644 index 0000000..0d14980 --- /dev/null +++ b/src/mainview/assets/icons/steamdeck_trackpad_right_outline.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5e376bd569c0b4047f39df9436de0632ea15d901f1800d896705f9a2f8fc62ea +size 1176 diff --git a/src/mainview/assets/icons/steamdeck_trackpad_up.svg b/src/mainview/assets/icons/steamdeck_trackpad_up.svg new file mode 100644 index 0000000..26980b2 --- /dev/null +++ b/src/mainview/assets/icons/steamdeck_trackpad_up.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:0ac41e64a5e3457de8df5a89497bc427b17f5255342e1522c6070d2d66d09624 +size 1105 diff --git a/src/mainview/assets/icons/steamdeck_trackpad_up_outline.svg b/src/mainview/assets/icons/steamdeck_trackpad_up_outline.svg new file mode 100644 index 0000000..781df21 --- /dev/null +++ b/src/mainview/assets/icons/steamdeck_trackpad_up_outline.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e7e82e9a5570d2b27d0bffc36bd5ebb7f69dcc32e6b5e66385014e2e79f5cfcd +size 1146 diff --git a/src/mainview/assets/icons/steamdeck_trackpad_vertical.svg b/src/mainview/assets/icons/steamdeck_trackpad_vertical.svg new file mode 100644 index 0000000..4116cfd --- /dev/null +++ b/src/mainview/assets/icons/steamdeck_trackpad_vertical.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6f2e7f4b510e0f0afce22569a9a4d9078008b1c5863131ca65b9b322ee0f27cc +size 1919 diff --git a/src/mainview/assets/icons/steamdeck_trackpad_vertical_outline.svg b/src/mainview/assets/icons/steamdeck_trackpad_vertical_outline.svg new file mode 100644 index 0000000..14c6c3f --- /dev/null +++ b/src/mainview/assets/icons/steamdeck_trackpad_vertical_outline.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e296851ee5138d878307fe283b28e53c61d7c4c33c4d234cdf3bbe1b0e318a9c +size 1930 diff --git a/src/mainview/assets/icons/xbox_button_a.svg b/src/mainview/assets/icons/xbox_button_a.svg new file mode 100644 index 0000000..cad2e1e --- /dev/null +++ b/src/mainview/assets/icons/xbox_button_a.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:64c7e4560c68bbbdc824627aca50464eee2dab31323e06df5b4d8f8b33a7d453 +size 393 diff --git a/src/mainview/assets/icons/xbox_button_a_outline.svg b/src/mainview/assets/icons/xbox_button_a_outline.svg new file mode 100644 index 0000000..6d7831c --- /dev/null +++ b/src/mainview/assets/icons/xbox_button_a_outline.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d4e5a26168d9ca3cc5f880befea9cc851359f410d6582ea7397e0da51a08c685 +size 547 diff --git a/src/mainview/assets/icons/xbox_button_b.svg b/src/mainview/assets/icons/xbox_button_b.svg new file mode 100644 index 0000000..f18e8cf --- /dev/null +++ b/src/mainview/assets/icons/xbox_button_b.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:12061d33eb6596dc94ad551296502a9e15bd26c9199210db4728fa2a666f3ca0 +size 701 diff --git a/src/mainview/assets/icons/xbox_button_b_outline.svg b/src/mainview/assets/icons/xbox_button_b_outline.svg new file mode 100644 index 0000000..c3a64a3 --- /dev/null +++ b/src/mainview/assets/icons/xbox_button_b_outline.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ff2dff9ca5f8ef0e9d7f32ce97f83db807b7a67679d914c10ef0b5aaaf845f75 +size 855 diff --git a/src/mainview/assets/icons/xbox_button_back.svg b/src/mainview/assets/icons/xbox_button_back.svg new file mode 100644 index 0000000..d518c7c --- /dev/null +++ b/src/mainview/assets/icons/xbox_button_back.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7434affb7ceac8dd3696909a0714cea37c0bec64a91f4e15e9b0aea4697e1156 +size 1951 diff --git a/src/mainview/assets/icons/xbox_button_back_icon.svg b/src/mainview/assets/icons/xbox_button_back_icon.svg new file mode 100644 index 0000000..e460a45 --- /dev/null +++ b/src/mainview/assets/icons/xbox_button_back_icon.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:77cad0eeed560822554363d6c7f5cb6b445bb5ab260a3a6b859719124ce6bb69 +size 514 diff --git a/src/mainview/assets/icons/xbox_button_back_icon_outline.svg b/src/mainview/assets/icons/xbox_button_back_icon_outline.svg new file mode 100644 index 0000000..a5ccfd9 --- /dev/null +++ b/src/mainview/assets/icons/xbox_button_back_icon_outline.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:63ea92a43b0be2e44443356eebddad1a90c242021c600168d1e61ad86f86dc25 +size 738 diff --git a/src/mainview/assets/icons/xbox_button_back_outline.svg b/src/mainview/assets/icons/xbox_button_back_outline.svg new file mode 100644 index 0000000..fd33959 --- /dev/null +++ b/src/mainview/assets/icons/xbox_button_back_outline.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:02b899ab04cadea673438b7feca7cd8a066abafe81e943b516fe9bcf449d9879 +size 2155 diff --git a/src/mainview/assets/icons/xbox_button_color_a.svg b/src/mainview/assets/icons/xbox_button_color_a.svg new file mode 100644 index 0000000..ff6bdb4 --- /dev/null +++ b/src/mainview/assets/icons/xbox_button_color_a.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:63d1a6d0798c09c70f1bd25cf03dce39bd0c04e721240fda62facd5dafe08bdc +size 393 diff --git a/src/mainview/assets/icons/xbox_button_color_a_outline.svg b/src/mainview/assets/icons/xbox_button_color_a_outline.svg new file mode 100644 index 0000000..f5dc982 --- /dev/null +++ b/src/mainview/assets/icons/xbox_button_color_a_outline.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d33a9f18c0cdf7ca926e961c0d9d826ee8927bc0be81d553d65d7e2efe80640a +size 547 diff --git a/src/mainview/assets/icons/xbox_button_color_b.svg b/src/mainview/assets/icons/xbox_button_color_b.svg new file mode 100644 index 0000000..688e5f5 --- /dev/null +++ b/src/mainview/assets/icons/xbox_button_color_b.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1a50644b6cb5a59564a3fdb977b16abb33ebe356e65e1b610dc2f8fb21e49fe0 +size 701 diff --git a/src/mainview/assets/icons/xbox_button_color_b_outline.svg b/src/mainview/assets/icons/xbox_button_color_b_outline.svg new file mode 100644 index 0000000..569382d --- /dev/null +++ b/src/mainview/assets/icons/xbox_button_color_b_outline.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:0f61ae78cc74aa117567405fb0a010428612e7c8948c327c51daf37e7ecccda0 +size 855 diff --git a/src/mainview/assets/icons/xbox_button_color_x.svg b/src/mainview/assets/icons/xbox_button_color_x.svg new file mode 100644 index 0000000..fb8d856 --- /dev/null +++ b/src/mainview/assets/icons/xbox_button_color_x.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:49840e42f7aa78d107a3c496a15093b4bdf6a114b0141807f86facdbe0461154 +size 458 diff --git a/src/mainview/assets/icons/xbox_button_color_x_outline.svg b/src/mainview/assets/icons/xbox_button_color_x_outline.svg new file mode 100644 index 0000000..7b64da4 --- /dev/null +++ b/src/mainview/assets/icons/xbox_button_color_x_outline.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7053702fdf5ea1192bbd85bbaedf5e52a5dd0ad9752f904d3698f74ac8f08395 +size 612 diff --git a/src/mainview/assets/icons/xbox_button_color_y.svg b/src/mainview/assets/icons/xbox_button_color_y.svg new file mode 100644 index 0000000..d43f2d6 --- /dev/null +++ b/src/mainview/assets/icons/xbox_button_color_y.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:27436f37e982d0e2502a761d889b7502faa3fcfabf0a868dcf85bfe204dfeb38 +size 407 diff --git a/src/mainview/assets/icons/xbox_button_color_y_outline.svg b/src/mainview/assets/icons/xbox_button_color_y_outline.svg new file mode 100644 index 0000000..235e8b5 --- /dev/null +++ b/src/mainview/assets/icons/xbox_button_color_y_outline.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3b980fcdc9a7322e83319eff8fa4acb8f92842012fca0759519c9de0dcf99f90 +size 561 diff --git a/src/mainview/assets/icons/xbox_button_menu.svg b/src/mainview/assets/icons/xbox_button_menu.svg new file mode 100644 index 0000000..c31c68e --- /dev/null +++ b/src/mainview/assets/icons/xbox_button_menu.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6e69a539c8a57ed461cf2690a5422abd94acad05b1c7f51b879bbad8c239c3f6 +size 399 diff --git a/src/mainview/assets/icons/xbox_button_menu_outline.svg b/src/mainview/assets/icons/xbox_button_menu_outline.svg new file mode 100644 index 0000000..4f8e62f --- /dev/null +++ b/src/mainview/assets/icons/xbox_button_menu_outline.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b3452fb97956b9d4621f117a4531e88d52d90595f96a12caa4e369972e733059 +size 553 diff --git a/src/mainview/assets/icons/xbox_button_share.svg b/src/mainview/assets/icons/xbox_button_share.svg new file mode 100644 index 0000000..510d150 --- /dev/null +++ b/src/mainview/assets/icons/xbox_button_share.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a41542a974ce5facd1fb77358c7c3154b8edc9dc410ecd4bf88e4a2ab0307e38 +size 505 diff --git a/src/mainview/assets/icons/xbox_button_share_outline.svg b/src/mainview/assets/icons/xbox_button_share_outline.svg new file mode 100644 index 0000000..1ada28e --- /dev/null +++ b/src/mainview/assets/icons/xbox_button_share_outline.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ff0c3b9a2a176e559286e312ec453fb75d85f999e311359b4df1e4753b5a8246 +size 729 diff --git a/src/mainview/assets/icons/xbox_button_start.svg b/src/mainview/assets/icons/xbox_button_start.svg new file mode 100644 index 0000000..20d6e7b --- /dev/null +++ b/src/mainview/assets/icons/xbox_button_start.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7e998659999f39d153e720069b4bad23212177235c27a0fc3df01290bdfe2008 +size 1902 diff --git a/src/mainview/assets/icons/xbox_button_start_icon.svg b/src/mainview/assets/icons/xbox_button_start_icon.svg new file mode 100644 index 0000000..5afbcdb --- /dev/null +++ b/src/mainview/assets/icons/xbox_button_start_icon.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:056d71b452eb23402750237502bcb4c6c2911789da756b2b621cfe16bf48a38e +size 530 diff --git a/src/mainview/assets/icons/xbox_button_start_icon_outline.svg b/src/mainview/assets/icons/xbox_button_start_icon_outline.svg new file mode 100644 index 0000000..5b054f0 --- /dev/null +++ b/src/mainview/assets/icons/xbox_button_start_icon_outline.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a19f7786983c0363fb6ceb1af83d100cd504c9d7f3a2694830dc28c2133767dd +size 796 diff --git a/src/mainview/assets/icons/xbox_button_start_outline.svg b/src/mainview/assets/icons/xbox_button_start_outline.svg new file mode 100644 index 0000000..f2bf0e2 --- /dev/null +++ b/src/mainview/assets/icons/xbox_button_start_outline.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f6f797c40b3de7629a1dcf5d62bdbf0587b43aa790c7c7d0a6cef7cb299baafd +size 2126 diff --git a/src/mainview/assets/icons/xbox_button_view.svg b/src/mainview/assets/icons/xbox_button_view.svg new file mode 100644 index 0000000..5656316 --- /dev/null +++ b/src/mainview/assets/icons/xbox_button_view.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d9f3bd3869469d006b3c2786ef7598f4470483371764390dbe2cb557873dde9c +size 483 diff --git a/src/mainview/assets/icons/xbox_button_view_outline.svg b/src/mainview/assets/icons/xbox_button_view_outline.svg new file mode 100644 index 0000000..d5fab9c --- /dev/null +++ b/src/mainview/assets/icons/xbox_button_view_outline.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:bec7a4076d86f83a29c2aef6f2ec11350c3186b472a0814108ab7f80b8cc8681 +size 637 diff --git a/src/mainview/assets/icons/xbox_button_x.svg b/src/mainview/assets/icons/xbox_button_x.svg new file mode 100644 index 0000000..b850753 --- /dev/null +++ b/src/mainview/assets/icons/xbox_button_x.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:505b595feca94a6dbb3b4bfb1f8213e108fab2d3419f265d7f42c7c1c1f3c711 +size 458 diff --git a/src/mainview/assets/icons/xbox_button_x_outline.svg b/src/mainview/assets/icons/xbox_button_x_outline.svg new file mode 100644 index 0000000..cd1a2ec --- /dev/null +++ b/src/mainview/assets/icons/xbox_button_x_outline.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:025d0ba752f08e010ebc8eec4970f0a9b85143f971626547059bab43da75e640 +size 612 diff --git a/src/mainview/assets/icons/xbox_button_y.svg b/src/mainview/assets/icons/xbox_button_y.svg new file mode 100644 index 0000000..ed91106 --- /dev/null +++ b/src/mainview/assets/icons/xbox_button_y.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c509a5a985e6c6ba9bbe6caa593571488ea4307d4d134632564742cc4f98dc03 +size 407 diff --git a/src/mainview/assets/icons/xbox_button_y_outline.svg b/src/mainview/assets/icons/xbox_button_y_outline.svg new file mode 100644 index 0000000..0752fe9 --- /dev/null +++ b/src/mainview/assets/icons/xbox_button_y_outline.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:86bb6b4010c8c9266d3dde3c2d6652e40af295b6a40dd2a3fc9d33fdd1f85d46 +size 561 diff --git a/src/mainview/assets/icons/xbox_dpad.svg b/src/mainview/assets/icons/xbox_dpad.svg new file mode 100644 index 0000000..399f6e9 --- /dev/null +++ b/src/mainview/assets/icons/xbox_dpad.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1d3528fa6ae21e2356484744c78754b455d9fce97974b5508ec424cce675f495 +size 363 diff --git a/src/mainview/assets/icons/xbox_dpad_all.svg b/src/mainview/assets/icons/xbox_dpad_all.svg new file mode 100644 index 0000000..689913c --- /dev/null +++ b/src/mainview/assets/icons/xbox_dpad_all.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4d2a5c8514420a260df791079f45d17f8e909ef939f2209fed8e37aad83a094a +size 365 diff --git a/src/mainview/assets/icons/xbox_dpad_down.svg b/src/mainview/assets/icons/xbox_dpad_down.svg new file mode 100644 index 0000000..b78660f --- /dev/null +++ b/src/mainview/assets/icons/xbox_dpad_down.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d7a0d403e36c41120882f5713927e828794cdff93f88f8d3cbea3d8384b322c9 +size 430 diff --git a/src/mainview/assets/icons/xbox_dpad_down_outline.svg b/src/mainview/assets/icons/xbox_dpad_down_outline.svg new file mode 100644 index 0000000..b89ee75 --- /dev/null +++ b/src/mainview/assets/icons/xbox_dpad_down_outline.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:30191d381376e36424aea24977e9681d3dbde19cee0755b764ad56c6ce0854db +size 502 diff --git a/src/mainview/assets/icons/xbox_dpad_horizontal.svg b/src/mainview/assets/icons/xbox_dpad_horizontal.svg new file mode 100644 index 0000000..62a1c2f --- /dev/null +++ b/src/mainview/assets/icons/xbox_dpad_horizontal.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7dfc37399407392f40eb8b0e048b14cdc603f8c3612183bce7dc8b9f3dd5df9e +size 450 diff --git a/src/mainview/assets/icons/xbox_dpad_horizontal_outline.svg b/src/mainview/assets/icons/xbox_dpad_horizontal_outline.svg new file mode 100644 index 0000000..806b155 --- /dev/null +++ b/src/mainview/assets/icons/xbox_dpad_horizontal_outline.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2018162f5cd92e868d9f40901deb481ec10b2934d91355f48b61a4154950b888 +size 450 diff --git a/src/mainview/assets/icons/xbox_dpad_left.svg b/src/mainview/assets/icons/xbox_dpad_left.svg new file mode 100644 index 0000000..e13fd31 --- /dev/null +++ b/src/mainview/assets/icons/xbox_dpad_left.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6fc565008a474f3c3899cc97854947a51700ce925523bf155ba77e7c28c658f6 +size 430 diff --git a/src/mainview/assets/icons/xbox_dpad_left_outline.svg b/src/mainview/assets/icons/xbox_dpad_left_outline.svg new file mode 100644 index 0000000..a45a2b1 --- /dev/null +++ b/src/mainview/assets/icons/xbox_dpad_left_outline.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ea55e89dd9c1af652abce093589d96ee3188e964a2adccd056e58e5e1b59c703 +size 502 diff --git a/src/mainview/assets/icons/xbox_dpad_none.svg b/src/mainview/assets/icons/xbox_dpad_none.svg new file mode 100644 index 0000000..64fe006 --- /dev/null +++ b/src/mainview/assets/icons/xbox_dpad_none.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9fb0ee7a390e4d99337147672a656fee244bd8f0d4f516f7ec7afd605a89e1af +size 554 diff --git a/src/mainview/assets/icons/xbox_dpad_right.svg b/src/mainview/assets/icons/xbox_dpad_right.svg new file mode 100644 index 0000000..cf3907e --- /dev/null +++ b/src/mainview/assets/icons/xbox_dpad_right.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5e3e358a70aaa5ea7236aef3504491051af91847466c349965cc345dd5b7dcb0 +size 430 diff --git a/src/mainview/assets/icons/xbox_dpad_right_outline.svg b/src/mainview/assets/icons/xbox_dpad_right_outline.svg new file mode 100644 index 0000000..22280f3 --- /dev/null +++ b/src/mainview/assets/icons/xbox_dpad_right_outline.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:579ef69456f160f697103915ce49692873318d7e7833630fcaa1489b314b13df +size 502 diff --git a/src/mainview/assets/icons/xbox_dpad_round.svg b/src/mainview/assets/icons/xbox_dpad_round.svg new file mode 100644 index 0000000..e474ff5 --- /dev/null +++ b/src/mainview/assets/icons/xbox_dpad_round.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:fdaa4d1d05fa80a942d3fcdcee09c60775a968295bbf41da317c6aa5a43525d3 +size 662 diff --git a/src/mainview/assets/icons/xbox_dpad_round_all.svg b/src/mainview/assets/icons/xbox_dpad_round_all.svg new file mode 100644 index 0000000..60445b2 --- /dev/null +++ b/src/mainview/assets/icons/xbox_dpad_round_all.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:871de2254417c805f77012ffdb010309dec38283b3b635ad7d61b76769bacc22 +size 1066 diff --git a/src/mainview/assets/icons/xbox_dpad_round_down.svg b/src/mainview/assets/icons/xbox_dpad_round_down.svg new file mode 100644 index 0000000..6b598c6 --- /dev/null +++ b/src/mainview/assets/icons/xbox_dpad_round_down.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f8434c98d7758cf012651c7443800910e4c8f6aae0ce72cb2418f0cf01cbaa4e +size 850 diff --git a/src/mainview/assets/icons/xbox_dpad_round_horizontal.svg b/src/mainview/assets/icons/xbox_dpad_round_horizontal.svg new file mode 100644 index 0000000..6f171d6 --- /dev/null +++ b/src/mainview/assets/icons/xbox_dpad_round_horizontal.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:064105df2298c56b525b6c69fc359ae6c990646538e049adee74c25cb5b25fcd +size 1012 diff --git a/src/mainview/assets/icons/xbox_dpad_round_left.svg b/src/mainview/assets/icons/xbox_dpad_round_left.svg new file mode 100644 index 0000000..7338c3c --- /dev/null +++ b/src/mainview/assets/icons/xbox_dpad_round_left.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b673a622fe7cc42dbdf77f6882b80eed2892cbb9c22e6f26bc48758aac9a23fd +size 850 diff --git a/src/mainview/assets/icons/xbox_dpad_round_right.svg b/src/mainview/assets/icons/xbox_dpad_round_right.svg new file mode 100644 index 0000000..1be378f --- /dev/null +++ b/src/mainview/assets/icons/xbox_dpad_round_right.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7f393e7a4740f94d8fd5ca25ce280e5f7653113f9a88344748fdf9ca30613eaa +size 869 diff --git a/src/mainview/assets/icons/xbox_dpad_round_up.svg b/src/mainview/assets/icons/xbox_dpad_round_up.svg new file mode 100644 index 0000000..866b66c --- /dev/null +++ b/src/mainview/assets/icons/xbox_dpad_round_up.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c19b4a283803112ad29943f10bb45d7b954e9311903cf5155a0258cd35c63acc +size 850 diff --git a/src/mainview/assets/icons/xbox_dpad_round_vertical.svg b/src/mainview/assets/icons/xbox_dpad_round_vertical.svg new file mode 100644 index 0000000..8198e4e --- /dev/null +++ b/src/mainview/assets/icons/xbox_dpad_round_vertical.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:85c390a005e8b316f9639ad825d9e7b51caeca34763630520542146e3f2d204f +size 1018 diff --git a/src/mainview/assets/icons/xbox_dpad_up.svg b/src/mainview/assets/icons/xbox_dpad_up.svg new file mode 100644 index 0000000..86b9113 --- /dev/null +++ b/src/mainview/assets/icons/xbox_dpad_up.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1eb952dcac0a986a5ab4f5cf61ee832504554cdc2df46b20dc0998a91b70e25b +size 430 diff --git a/src/mainview/assets/icons/xbox_dpad_up_outline.svg b/src/mainview/assets/icons/xbox_dpad_up_outline.svg new file mode 100644 index 0000000..6b1986e --- /dev/null +++ b/src/mainview/assets/icons/xbox_dpad_up_outline.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:addf544d6a58f5c888ea5cfb69300cb668eed3d6c83d130290cccd607679cb08 +size 502 diff --git a/src/mainview/assets/icons/xbox_dpad_vertical.svg b/src/mainview/assets/icons/xbox_dpad_vertical.svg new file mode 100644 index 0000000..2611724 --- /dev/null +++ b/src/mainview/assets/icons/xbox_dpad_vertical.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c880bf479bb69bd2aa126220f9c9b0967780ac558eb59080618d7e2b8bb15565 +size 450 diff --git a/src/mainview/assets/icons/xbox_dpad_vertical_outline.svg b/src/mainview/assets/icons/xbox_dpad_vertical_outline.svg new file mode 100644 index 0000000..dd2452b --- /dev/null +++ b/src/mainview/assets/icons/xbox_dpad_vertical_outline.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:71bd0cb736cb75b461b60ef75c84c8445e94b243eb0ceaa666f8130c989d9ae6 +size 450 diff --git a/src/mainview/assets/icons/xbox_elite_paddle_bottom_left.svg b/src/mainview/assets/icons/xbox_elite_paddle_bottom_left.svg new file mode 100644 index 0000000..52c239d --- /dev/null +++ b/src/mainview/assets/icons/xbox_elite_paddle_bottom_left.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8da852aebf3e6fae8d4c948788ccf307da56b88d4868db953883e74c720bc3f9 +size 567 diff --git a/src/mainview/assets/icons/xbox_elite_paddle_bottom_left_outline.svg b/src/mainview/assets/icons/xbox_elite_paddle_bottom_left_outline.svg new file mode 100644 index 0000000..7120d9f --- /dev/null +++ b/src/mainview/assets/icons/xbox_elite_paddle_bottom_left_outline.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:35991e0d928aea134de39d636653d974aa6c21d34769eadc609539febff16bcc +size 1061 diff --git a/src/mainview/assets/icons/xbox_elite_paddle_bottom_right.svg b/src/mainview/assets/icons/xbox_elite_paddle_bottom_right.svg new file mode 100644 index 0000000..c4871c8 --- /dev/null +++ b/src/mainview/assets/icons/xbox_elite_paddle_bottom_right.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:18b491ffb161fb2b1ef01f101885ded956109eac01328f0a257712b7c876e6d9 +size 564 diff --git a/src/mainview/assets/icons/xbox_elite_paddle_bottom_right_outline.svg b/src/mainview/assets/icons/xbox_elite_paddle_bottom_right_outline.svg new file mode 100644 index 0000000..20d6668 --- /dev/null +++ b/src/mainview/assets/icons/xbox_elite_paddle_bottom_right_outline.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:fbfd0d3a44c9ad37c3c62898c1928874eb7dea630b4afcf9c15dbc6b594007db +size 1071 diff --git a/src/mainview/assets/icons/xbox_elite_paddle_top_left.svg b/src/mainview/assets/icons/xbox_elite_paddle_top_left.svg new file mode 100644 index 0000000..cd79e77 --- /dev/null +++ b/src/mainview/assets/icons/xbox_elite_paddle_top_left.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9f23a3c0fe71a6bf93d81865fe965669f6ad08e3674eed82a01077b44a9d703d +size 472 diff --git a/src/mainview/assets/icons/xbox_elite_paddle_top_left_outline.svg b/src/mainview/assets/icons/xbox_elite_paddle_top_left_outline.svg new file mode 100644 index 0000000..1edb090 --- /dev/null +++ b/src/mainview/assets/icons/xbox_elite_paddle_top_left_outline.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c7334a752926f8448811e9fcd4e32f61244197e69d381055c7d129ba203c8155 +size 852 diff --git a/src/mainview/assets/icons/xbox_elite_paddle_top_right.svg b/src/mainview/assets/icons/xbox_elite_paddle_top_right.svg new file mode 100644 index 0000000..67438bd --- /dev/null +++ b/src/mainview/assets/icons/xbox_elite_paddle_top_right.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e4c89659fdde3c5e433c7394e1afc5c030d96fa72b949363c7a2953c548ea3dd +size 480 diff --git a/src/mainview/assets/icons/xbox_elite_paddle_top_right_outline.svg b/src/mainview/assets/icons/xbox_elite_paddle_top_right_outline.svg new file mode 100644 index 0000000..dab5ed0 --- /dev/null +++ b/src/mainview/assets/icons/xbox_elite_paddle_top_right_outline.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d4172297395f54b61268a0e0ec0927c5d037d05d3e9f14639cd12e50b6cde1bb +size 888 diff --git a/src/mainview/assets/icons/xbox_guide.svg b/src/mainview/assets/icons/xbox_guide.svg new file mode 100644 index 0000000..53f5565 --- /dev/null +++ b/src/mainview/assets/icons/xbox_guide.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:00cb4ae70d051095b4ce83ecdfd89c377eb2265cea256141415787aefc969cda +size 1341 diff --git a/src/mainview/assets/icons/xbox_guide_outline.svg b/src/mainview/assets/icons/xbox_guide_outline.svg new file mode 100644 index 0000000..347314d --- /dev/null +++ b/src/mainview/assets/icons/xbox_guide_outline.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:99139c295ea685ceaffd723d12818f4990b6518faeb32d83b15ba3db4eda3093 +size 1545 diff --git a/src/mainview/assets/icons/xbox_lb.svg b/src/mainview/assets/icons/xbox_lb.svg new file mode 100644 index 0000000..1eca73b --- /dev/null +++ b/src/mainview/assets/icons/xbox_lb.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6463d4c86715f1445838dd502e2060cc1719bcc66af705a15efb69fa9949c36c +size 611 diff --git a/src/mainview/assets/icons/xbox_lb_outline.svg b/src/mainview/assets/icons/xbox_lb_outline.svg new file mode 100644 index 0000000..7e8e517 --- /dev/null +++ b/src/mainview/assets/icons/xbox_lb_outline.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8646bcb49937539bb150f5f6713448dcae0bfdedc27ffd6e16767cb16f15211a +size 721 diff --git a/src/mainview/assets/icons/xbox_ls.svg b/src/mainview/assets/icons/xbox_ls.svg new file mode 100644 index 0000000..01e9967 --- /dev/null +++ b/src/mainview/assets/icons/xbox_ls.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a202f65349b029b1f640bfb839bfe26fca598f4ed13fb39e14d3a0346569a71c +size 926 diff --git a/src/mainview/assets/icons/xbox_ls_outline.svg b/src/mainview/assets/icons/xbox_ls_outline.svg new file mode 100644 index 0000000..8c91570 --- /dev/null +++ b/src/mainview/assets/icons/xbox_ls_outline.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:91b1a0c4268d5a5170dd3efd0247c9bd376afef16e2a846223f3da593376e331 +size 1080 diff --git a/src/mainview/assets/icons/xbox_lt.svg b/src/mainview/assets/icons/xbox_lt.svg new file mode 100644 index 0000000..b64f7c2 --- /dev/null +++ b/src/mainview/assets/icons/xbox_lt.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a9dd0f7df719f2a57e071fc5c00d951bcedb2e3a5db676a2167138a83bdbeefb +size 402 diff --git a/src/mainview/assets/icons/xbox_lt_outline.svg b/src/mainview/assets/icons/xbox_lt_outline.svg new file mode 100644 index 0000000..abd0f87 --- /dev/null +++ b/src/mainview/assets/icons/xbox_lt_outline.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:fac6ac0a51b3baba208708b17a0834c63a56ee19e32a276f705a9858a9518f47 +size 518 diff --git a/src/mainview/assets/icons/xbox_rb.svg b/src/mainview/assets/icons/xbox_rb.svg new file mode 100644 index 0000000..a92e079 --- /dev/null +++ b/src/mainview/assets/icons/xbox_rb.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:066ac893d3baa92d4ba9e3b7e12b1829cce3cdf7d0676fbab4eb56d4cf17e63b +size 793 diff --git a/src/mainview/assets/icons/xbox_rb_outline.svg b/src/mainview/assets/icons/xbox_rb_outline.svg new file mode 100644 index 0000000..b5f20f4 --- /dev/null +++ b/src/mainview/assets/icons/xbox_rb_outline.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c18817fc50574852e77826d07764f3f33a7a8f0897782f9f5020a486e8954456 +size 903 diff --git a/src/mainview/assets/icons/xbox_rs.svg b/src/mainview/assets/icons/xbox_rs.svg new file mode 100644 index 0000000..6ec52c0 --- /dev/null +++ b/src/mainview/assets/icons/xbox_rs.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:44bb273b93df6389733a43902fcc684b0397b1135a49bb0d170634c2a81ffcc2 +size 1127 diff --git a/src/mainview/assets/icons/xbox_rs_outline.svg b/src/mainview/assets/icons/xbox_rs_outline.svg new file mode 100644 index 0000000..52bc780 --- /dev/null +++ b/src/mainview/assets/icons/xbox_rs_outline.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:311f37d779cbca12b87f8e35cac9c5ec5e1b490872d4b32100cc724c3187399e +size 1275 diff --git a/src/mainview/assets/icons/xbox_rt.svg b/src/mainview/assets/icons/xbox_rt.svg new file mode 100644 index 0000000..fc45523 --- /dev/null +++ b/src/mainview/assets/icons/xbox_rt.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a31df1a73f3d04cdebbd2c639d273b19d840e0736a7fcc2039ac521b76652b57 +size 603 diff --git a/src/mainview/assets/icons/xbox_rt_outline.svg b/src/mainview/assets/icons/xbox_rt_outline.svg new file mode 100644 index 0000000..0b3e8f0 --- /dev/null +++ b/src/mainview/assets/icons/xbox_rt_outline.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:bf6220a227abbba88caf0b26b4511114df31d59d3181bcca1bad13e3648dfa0b +size 719 diff --git a/src/mainview/assets/icons/xbox_stick_l.svg b/src/mainview/assets/icons/xbox_stick_l.svg new file mode 100644 index 0000000..16da128 --- /dev/null +++ b/src/mainview/assets/icons/xbox_stick_l.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c5097b1eab526cddc799ae77a6bf8d29b759408be2420357ba85b7441d6430e2 +size 973 diff --git a/src/mainview/assets/icons/xbox_stick_l_down.svg b/src/mainview/assets/icons/xbox_stick_l_down.svg new file mode 100644 index 0000000..16fc643 --- /dev/null +++ b/src/mainview/assets/icons/xbox_stick_l_down.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9be226409c17137a0541ee2416c05e3e5658bc99b183406217a72874c4002404 +size 1872 diff --git a/src/mainview/assets/icons/xbox_stick_l_horizontal.svg b/src/mainview/assets/icons/xbox_stick_l_horizontal.svg new file mode 100644 index 0000000..26dad8e --- /dev/null +++ b/src/mainview/assets/icons/xbox_stick_l_horizontal.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d194cf9c42a3e7a2270fc29867bb66756b63eeeded96ccc4181a84123d62e71a +size 2470 diff --git a/src/mainview/assets/icons/xbox_stick_l_left.svg b/src/mainview/assets/icons/xbox_stick_l_left.svg new file mode 100644 index 0000000..94b883a --- /dev/null +++ b/src/mainview/assets/icons/xbox_stick_l_left.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2fc7ece01211833e713b34c75073019e2632947d99aa0c4cd565bfd07ed7d474 +size 1746 diff --git a/src/mainview/assets/icons/xbox_stick_l_press.svg b/src/mainview/assets/icons/xbox_stick_l_press.svg new file mode 100644 index 0000000..6e3485f --- /dev/null +++ b/src/mainview/assets/icons/xbox_stick_l_press.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:caad8e34f27bf6c86592595bc35affda557cebc2b48a2226b272ceeafea94682 +size 1801 diff --git a/src/mainview/assets/icons/xbox_stick_l_right.svg b/src/mainview/assets/icons/xbox_stick_l_right.svg new file mode 100644 index 0000000..40d3bbb --- /dev/null +++ b/src/mainview/assets/icons/xbox_stick_l_right.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4554269a9685d991f69912613bef912be968e984926d915dfa75defb440b608c +size 1743 diff --git a/src/mainview/assets/icons/xbox_stick_l_up.svg b/src/mainview/assets/icons/xbox_stick_l_up.svg new file mode 100644 index 0000000..1d37fe8 --- /dev/null +++ b/src/mainview/assets/icons/xbox_stick_l_up.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:555342c2a3376ce6f4669e6fae17226b825636baf09b7473e38809a90ef722ec +size 1783 diff --git a/src/mainview/assets/icons/xbox_stick_l_vertical.svg b/src/mainview/assets/icons/xbox_stick_l_vertical.svg new file mode 100644 index 0000000..c6a25a2 --- /dev/null +++ b/src/mainview/assets/icons/xbox_stick_l_vertical.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2888956302e4c8db1be3ccc2d122114f084a1cf90029129a4ee5d6718722ee81 +size 2626 diff --git a/src/mainview/assets/icons/xbox_stick_r.svg b/src/mainview/assets/icons/xbox_stick_r.svg new file mode 100644 index 0000000..3db04a6 --- /dev/null +++ b/src/mainview/assets/icons/xbox_stick_r.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c8ba98ac6b7793d1033a230df73f9b51f9ba2205ec15febcc481597c165c0b65 +size 1155 diff --git a/src/mainview/assets/icons/xbox_stick_r_down.svg b/src/mainview/assets/icons/xbox_stick_r_down.svg new file mode 100644 index 0000000..32e8b32 --- /dev/null +++ b/src/mainview/assets/icons/xbox_stick_r_down.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:95b5f2817b66cf375210d54f7643a34f6c24c051d6be05ce945f7ec7355854b7 +size 2060 diff --git a/src/mainview/assets/icons/xbox_stick_r_horizontal.svg b/src/mainview/assets/icons/xbox_stick_r_horizontal.svg new file mode 100644 index 0000000..51874b5 --- /dev/null +++ b/src/mainview/assets/icons/xbox_stick_r_horizontal.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2ace97ffa08117b65500cb4c8028d669594093ed26d5c557bcf9404504d9c98e +size 2652 diff --git a/src/mainview/assets/icons/xbox_stick_r_left.svg b/src/mainview/assets/icons/xbox_stick_r_left.svg new file mode 100644 index 0000000..94a6b60 --- /dev/null +++ b/src/mainview/assets/icons/xbox_stick_r_left.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d4f4719bde017509ace548ec8acdfab2db09f584b4fc107ba91ba42583c308f7 +size 1928 diff --git a/src/mainview/assets/icons/xbox_stick_r_press.svg b/src/mainview/assets/icons/xbox_stick_r_press.svg new file mode 100644 index 0000000..85d3f41 --- /dev/null +++ b/src/mainview/assets/icons/xbox_stick_r_press.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ffb32bd4f1c3b306e2d0f9bcbdb82ac1d1e4641821417e08196bff8d6b72ac94 +size 1983 diff --git a/src/mainview/assets/icons/xbox_stick_r_right.svg b/src/mainview/assets/icons/xbox_stick_r_right.svg new file mode 100644 index 0000000..603ba41 --- /dev/null +++ b/src/mainview/assets/icons/xbox_stick_r_right.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1483899f0410e6d31297c716aa7e41eb9aaff562446f7bc421aec6ebe4a9a063 +size 1925 diff --git a/src/mainview/assets/icons/xbox_stick_r_up.svg b/src/mainview/assets/icons/xbox_stick_r_up.svg new file mode 100644 index 0000000..3db7b85 --- /dev/null +++ b/src/mainview/assets/icons/xbox_stick_r_up.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:0875649bc82d1bf4ce801141dac1466b9d949e0d48c423cbff2ede43a90b926a +size 1965 diff --git a/src/mainview/assets/icons/xbox_stick_r_vertical.svg b/src/mainview/assets/icons/xbox_stick_r_vertical.svg new file mode 100644 index 0000000..d42520c --- /dev/null +++ b/src/mainview/assets/icons/xbox_stick_r_vertical.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:fa02fa1bc473de5754e2035d49ab6fc71d9e454a7b98e8a63d2e01556e5207f8 +size 2808 diff --git a/src/mainview/assets/icons/xbox_stick_side_l.svg b/src/mainview/assets/icons/xbox_stick_side_l.svg new file mode 100644 index 0000000..52c2d9d --- /dev/null +++ b/src/mainview/assets/icons/xbox_stick_side_l.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e9308f9e55d337b912b07b217a3f64944056f61ad0e8bb58d536ca74c338689e +size 619 diff --git a/src/mainview/assets/icons/xbox_stick_side_r.svg b/src/mainview/assets/icons/xbox_stick_side_r.svg new file mode 100644 index 0000000..38138b9 --- /dev/null +++ b/src/mainview/assets/icons/xbox_stick_side_r.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e4682d72fcfcb6c0254329583ce76d8d3f3b29aba14cd5a5d2555e88ec2a4599 +size 822 diff --git a/src/mainview/assets/icons/xbox_stick_top_l.svg b/src/mainview/assets/icons/xbox_stick_top_l.svg new file mode 100644 index 0000000..1cb11ac --- /dev/null +++ b/src/mainview/assets/icons/xbox_stick_top_l.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ae7b1aaf3079a22cae6738d0d05af87176749c13f18e386621a1e92f90a438ef +size 750 diff --git a/src/mainview/assets/icons/xbox_stick_top_r.svg b/src/mainview/assets/icons/xbox_stick_top_r.svg new file mode 100644 index 0000000..6644ce1 --- /dev/null +++ b/src/mainview/assets/icons/xbox_stick_top_r.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5a5485cc4428eab269ffe3b502e09c5de6a8c71ea24181282a44950c90dddfa4 +size 987 diff --git a/src/mainview/components/AnimatedBackground.tsx b/src/mainview/components/AnimatedBackground.tsx new file mode 100644 index 0000000..dec7ce8 --- /dev/null +++ b/src/mainview/components/AnimatedBackground.tsx @@ -0,0 +1,62 @@ +import React, { createContext, Ref, useContext, useState } from 'react'; +import { twMerge } from 'tailwind-merge'; +import { useSessionStorage } from 'usehooks-ts'; + +export const AnimatedBackgroundContext = createContext({} as { setBackground: (url: string) => void; }); + +export function AnimatedBackground (data: { + children?: any; + backgroundKey?: string; + backgroundUrl?: string; + ref?: Ref; + className?: string; + animated?: boolean, +}) +{ + const [lastBackgroundUrl, setLastBackgroundUrl] = data.backgroundUrl ? useSessionStorage( + `${data.backgroundKey!}-last`, + data.backgroundUrl, + ) : useState(); + + const [backgroundUrl, setBackgroundUrl] = data.backgroundUrl ? useSessionStorage( + data.backgroundKey!, + data.backgroundUrl, + ) : useState(data.backgroundUrl); + + function handleSetBackground (url: string) + { + setLastBackgroundUrl(backgroundUrl); + setBackgroundUrl(url); + } + + const bgColor = "bg-base-content"; + + let backgroundStyle = (url: string) => `linear-gradient( + color-mix(in srgb, var(--color-base-300) 60%, transparent), + color-mix(in srgb, var(--color-base-100) 80%, transparent) + ), url('${url}') center / cover`; + + return ( + +
+ {!!lastBackgroundUrl &&
} + {!!backgroundUrl &&
} +
+ {data.animated &&
+
+
+
+
+
+
+
+
+
+
} + {data.children} +
+
+ ); +} \ No newline at end of file diff --git a/src/mainview/components/AutoFocus.tsx b/src/mainview/components/AutoFocus.tsx new file mode 100644 index 0000000..160b801 --- /dev/null +++ b/src/mainview/components/AutoFocus.tsx @@ -0,0 +1,30 @@ +import { doesFocusableExist, getCurrentFocusKey } from "@noriginmedia/norigin-spatial-navigation"; +import { useEffect } from "react"; + +export function AutoFocus (data: { focus: () => void; force?: boolean; delay?: number; }) +{ + useEffect(() => + { + let delayTimeout: number | undefined; + + if (data.force || !getCurrentFocusKey() || !doesFocusableExist(getCurrentFocusKey())) + { + if (data.delay) + { + delayTimeout = window.setTimeout(() => data.focus(), data.delay); + } else + { + data.focus(); + } + + } + return () => + { + if (delayTimeout) + { + window.clearTimeout(delayTimeout); + } + }; + }, []); + return <>; +} \ No newline at end of file diff --git a/src/mainview/components/CardList.tsx b/src/mainview/components/CardList.tsx new file mode 100644 index 0000000..939cacd --- /dev/null +++ b/src/mainview/components/CardList.tsx @@ -0,0 +1,82 @@ +import +{ + FocusContext, + useFocusable, +} from "@noriginmedia/norigin-spatial-navigation"; +import { GameMeta } from "../../shared/constants"; +import GameCard, { GameCardSkeleton } from "./GameCard"; +import { JSX, useEffect, useMemo, useState } from "react"; +import { useLocalStorage } from "usehooks-ts"; +import { useScrollSave } from "../scripts/utils"; +import classNames from "classnames"; + +export interface GameMetaExtra extends GameMeta +{ + preview?: JSX.Element; + badge?: JSX.Element; + focusKey: string; +} + +export function CardList (data: { + id: string; + type?: string; + games: GameMetaExtra[]; + grid?: boolean; + onSelectGame?: (id: number) => void; + onGameFocus?: (id: number) => void; +}) +{ + const { ref, focusKey } = useFocusable({ + focusKey: data.id, + }); + + function BuildGame (g: GameMetaExtra, i: number) + { + let preview: JSX.Element | string | undefined = g.preview; + if (!preview && g.previewUrl) + { + preview = g.previewUrl; + } + return ( + + { + data.onGameFocus?.(g.id); + }} + onAction={() => data.onSelectGame?.(g.id)} + preview={preview} + badge={g.badge} + id={g.id} + /> + ); + } + + return ( +
    + { + e.preventDefault(); + e.stopPropagation(); + }} + style={{ scrollbarWidth: "none" }} + > + + {data.games.map(BuildGame)} + +
+ ); +} diff --git a/src/mainview/components/CollectionsDetail.tsx b/src/mainview/components/CollectionsDetail.tsx new file mode 100644 index 0000000..080a2ad --- /dev/null +++ b/src/mainview/components/CollectionsDetail.tsx @@ -0,0 +1,54 @@ +import { AnimatedBackground } from './AnimatedBackground'; +import { FocusContext, useFocusable } from '@noriginmedia/norigin-spatial-navigation'; +import { HeaderUI } from './Header'; +import { GameList, GameListFilter } from './GameList'; +import { Search, Settings2 } from 'lucide-react'; +import ShortcutPrompt from './ShortcutPrompt'; +import { selfFocusSmart } from '../scripts/utils'; +import { JSX, Suspense, useEffect, useState } from 'react'; +import Shortcuts from './Shortcuts'; +import { AutoFocus } from './AutoFocus'; + +export interface CollectionsDetailParams +{ + id?: string; + setBackground: (url: string) => void; + filters: GameListFilter; + headerTitle?: JSX.Element; + title?: JSX.Element; + footer?: JSX.Element; +} + +export function CollectionsDetail (data: CollectionsDetailParams) +{ + const focusKey = `game-list-${data.id}-${data.filters.platformIds?.join()}-${data.filters.collectionId}`; + const { ref, focusSelf } = useFocusable({ + focusKey, + preferredChildFocusKey: `${focusKey}-list`, + }); + + return ( + + +
+ }, { id: "filter", icon: }]} /> +
+
+
+ {data.title} + + + + +
+
+
+
+ {data.footer} +
+ +
+
+
+ ); +} \ No newline at end of file diff --git a/src/mainview/components/Filters.tsx b/src/mainview/components/Filters.tsx new file mode 100644 index 0000000..898a49d --- /dev/null +++ b/src/mainview/components/Filters.tsx @@ -0,0 +1,78 @@ +import +{ + FocusContext, + useFocusable, +} from "@noriginmedia/norigin-spatial-navigation"; +import SvgIcon from "./SvgIcon"; +import classNames from "classnames"; + +function FilterCat ( + data: { + id: string; + children?: any; + active: boolean; + onFocus: () => void; + } & FilterOption, +) +{ + const { ref, focusSelf, focused } = useFocusable({ + focusKey: data.id, + onFocus: data.onFocus, + onEnterPress: data.onAction, + }); + return ( +
  • + {data.children ?? data.label} +
  • + ); +} + +export function FilterUI (data: { + id: string; + options: Record; + selected: string; + setSelected: (id: string) => void; +}) +{ + const { ref, focusKey } = useFocusable({ focusKey: `filter-${data.id}` }); + return ( +
    + +
      +
    • + +
    • + {Object.entries(data.options)?.map(([id, option]) => ( + data.setSelected(id)} + active={id === data.selected} + {...option} + /> + ))} +
    • + +
    • +
    +
    +
    + + ); +} diff --git a/src/mainview/components/GameCard.tsx b/src/mainview/components/GameCard.tsx new file mode 100644 index 0000000..857b805 --- /dev/null +++ b/src/mainview/components/GameCard.tsx @@ -0,0 +1,91 @@ +import { useFocusable } from "@noriginmedia/norigin-spatial-navigation"; +import classNames from "classnames"; +import { JSX, useEffect } from "react"; +import { twMerge } from "tailwind-merge"; + +export function GameCardSkeleton () +{ + return ( +
  • +
    +
    +
    +
    +
    +
  • + ); +} + +export default function GameCard (data: { + title: string; + type?: string; + subtitle: string; + preview?: string | JSX.Element; + focusKey: string; + index: number; + id: number; + badge?: JSX.Element; + onFocus?: (id: number) => void; + onAction?: () => void; +}) +{ + const { ref, focused, focusSelf } = useFocusable({ + focusKey: data.focusKey, + onFocus: () => data.onFocus?.(data.id), + onEnterPress: () => data.onAction?.(), + }); + + useEffect(() => + { + if (focused) + { + (ref.current as HTMLElement).scrollIntoView({ + behavior: "smooth", + inline: "center", + block: 'center' + }); + } + }, [focused]); + + return ( +
  • +
    + {typeof data.preview === "string" ? ( + + ) : ( + data.preview + )}
    + +
    {data.badge}
    +
    +
    + {data.title} +
    +
    {data.subtitle}
    +
    +
  • + ); +} diff --git a/src/mainview/components/GameList.tsx b/src/mainview/components/GameList.tsx new file mode 100644 index 0000000..79d75aa --- /dev/null +++ b/src/mainview/components/GameList.tsx @@ -0,0 +1,74 @@ +import { keepPreviousData, useQuery, useSuspenseQuery } from "@tanstack/react-query"; +import { getRomsApiRomsGetOptions } from "../../clients/romm/@tanstack/react-query.gen"; +import { GameMetaExtra, CardList } from "./CardList"; +import { DefaultRommStaleTime, RPC_URL } from "../../shared/constants"; +import { useLocation, useNavigate } from "@tanstack/react-router"; +import { Suspense, useEffect } from "react"; +import { SaveSource } from "../scripts/spatialNavigation"; +import { gamesQueryOptions } from "../query-options"; + +export interface GameListFilter +{ + platformIds?: number[]; + collectionId?: number; +} + +export interface GameListParams +{ + id: string, + filters?: GameListFilter, + grid?: boolean, + setBackground?: (url: string) => void; + onGameSelect?: (id: number) => void; +} + +export function GameList (data: GameListParams) +{ + const games = useSuspenseQuery(gamesQueryOptions(data.filters)); + const navigator = useNavigate(); + const location = useLocation(); + + const handleFocus = (id: number) => + { + const game = games.data?.items.find((g) => g.id === id); + if (game) + { + data.setBackground?.( + `${RPC_URL(__HOST__)}/api/romm${game.path_cover_small}`, + ); + } + }; + + function handleDefaultSelect (id: number) + { + SaveSource('details', location.pathname); + navigator({ to: '/game/$id', params: { id: String(id) }, viewTransition: { types: ['zoom-in'] } }); + }; + + return ( + <> + + Date.parse(b.rom_user.last_played ?? b.updated_at) - + Date.parse(a.rom_user.last_played ?? a.updated_at), + ) + .map( + (g) => + ({ + id: g.id, + focusKey: g.slug ?? `game-${g.id}`, + title: g.name ?? "", + subtitle: g.platform_display_name ?? "", + previewUrl: `${RPC_URL(__HOST__)}/api/romm${g.path_cover_large}`, + }) satisfies GameMetaExtra, + )} + onGameFocus={handleFocus} + onSelectGame={id => data.onGameSelect ? data.onGameSelect(id) : handleDefaultSelect(id)} + /> + + ); +} \ No newline at end of file diff --git a/src/mainview/components/GamepadIcon.tsx b/src/mainview/components/GamepadIcon.tsx deleted file mode 100644 index 197aac0..0000000 --- a/src/mainview/components/GamepadIcon.tsx +++ /dev/null @@ -1,23 +0,0 @@ -import React from "react"; - -export default function GamepadIcon({ - platform, - variant, - button, - text, -}: { - platform: "xbox" | "playstation" | "nintendo"; - variant: string; - button: string; - text?: string; -}) { - return ( -
    - - {text} - -
    - ); -} diff --git a/src/mainview/components/Header.tsx b/src/mainview/components/Header.tsx new file mode 100644 index 0000000..65ce4e6 --- /dev/null +++ b/src/mainview/components/Header.tsx @@ -0,0 +1,191 @@ +import +{ + FocusContext, + useFocusable, +} from "@noriginmedia/norigin-spatial-navigation"; +import classNames from "classnames"; +import +{ + BatteryFull, + Bell, + Bluetooth, + Clock, + Lock, + Power, + ShieldAlert, + Sun, + User, + Wifi, +} from "lucide-react"; +import { RoundButton } from "./RoundButton"; +import { useQuery } from "@tanstack/react-query"; +import { getCurrentUserApiUsersMeGetOptions, statsApiStatsGetOptions } from "../../clients/romm/@tanstack/react-query.gen"; +import { RPC_URL } from "../../shared/constants"; +import { JSX } from "react"; +import { useLocation, useNavigate } from "@tanstack/react-router"; +import { SaveSource } from "../scripts/spatialNavigation"; + +function HeaderAvatar (data: { + id: string; + imageSrc?: string | string[]; + className?: string; + active?: boolean; + status?: HeaderAccount['status']; + locked?: boolean; + type?: HeaderAccount['type']; + onSelect?: () => void; +}) +{ + const { ref, focused } = useFocusable({ focusKey: data.id, onEnterPress: data.onSelect }); + const bgColors = { + primary: " text-primary-content", + secondary: " text-secondary-content", + accent: " text-accent-content", + base: "bg-base-100", + none: undefined, + }; + + return ( +
    + {data.imageSrc ? ( +
    + + {typeof data.imageSrc === 'string' && } + {Array.isArray(data.imageSrc) && data.imageSrc.map((s, i) => + { + if (i === (data.imageSrc!.length - 1)) + { + return ; + } + return ; + })} + +
    + ) : ( + + )} + + +
    + ); +} + +export interface HeaderButton +{ + id: string; + icon: JSX.Element; + external?: boolean; +} + +export interface HeaderAccount +{ + id: string; + previewUrl?: string | string[]; + status?: "status-error" | "status-success" | "status-neutral"; + type?: "base" | "primary" | "secondary" | "accent"; + locked?: boolean; + action?: () => void; +} + +export function HeaderUI (data: { buttons?: HeaderButton[]; accounts?: HeaderAccount[], buttonElements?: JSX.Element[] | JSX.Element; title?: JSX.Element; }) +{ + const { ref, focusKey } = useFocusable({ focusKey: "header-elements" }); + const navigate = useNavigate(); + const location = useLocation(); + const rommOnline = useQuery({ + ...statsApiStatsGetOptions(), + refetchInterval: 30000, + retry: false, + }); + const user = useQuery({ + ...getCurrentUserApiUsersMeGetOptions(), + refetchOnWindowFocus: false, + retry: 1 + }); + + let indicator = "status-neutral"; + if (user.isError) + { + indicator = "status-error"; + } else if (!user.isPending && rommOnline.isSuccess) + { + indicator = "status-success"; + } + + const accounts: HeaderAccount[] = [{ + id: 'romm', previewUrl: [ + `${RPC_URL(__HOST__)}/api/romm/assets/logos/romm_logo_xbox_one_square.svg`, + ], + action: () => + { + SaveSource('settings', location.pathname); + navigate({ to: '/settings/accounts', viewTransition: { types: ['zoom-in'] }, search: { focus: 'rommAddress' } }); + }, + status: user.data ? "status-success" : 'status-error', + type: 'secondary' + }, ...data.accounts ?? []]; + + return ( + +
    +
    + {accounts?.map(a => )} + {data.title} +
    +
    +
    + + + +
    + + +
    +
    + + 100% +
    +
    + {!!data.buttons &&
    } +
    + {data.buttonElements ?? data.buttons?.map(b => )} +
    +
    +
    +
    + ); +} diff --git a/src/mainview/components/LoadingCardList.tsx b/src/mainview/components/LoadingCardList.tsx new file mode 100644 index 0000000..eba404f --- /dev/null +++ b/src/mainview/components/LoadingCardList.tsx @@ -0,0 +1,24 @@ +import classNames from 'classnames'; +import { GameCardSkeleton } from './GameCard'; + +export default function LoadingCardList (data: { placeholderCount: number, grid?: boolean; }) +{ + return ( +
      + { + e.preventDefault(); + e.stopPropagation(); + }} + style={{ scrollbarWidth: "none" }} + > + {new Array(data.placeholderCount).fill(1).map(p => )} +
    + ); +} diff --git a/src/mainview/components/RoundButton.tsx b/src/mainview/components/RoundButton.tsx new file mode 100644 index 0000000..68ef701 --- /dev/null +++ b/src/mainview/components/RoundButton.tsx @@ -0,0 +1,39 @@ +import { useFocusable } from "@noriginmedia/norigin-spatial-navigation"; +import classNames from "classnames"; +import { JSX } from "react"; +import { twMerge } from 'tailwind-merge'; + +export function RoundButton (data: { + id: string; + icon: JSX.Element; + className?: string; + external?: boolean; + action?: () => void; +}) +{ + const { ref, focused } = useFocusable({ + focusKey: data.id, + onEnterPress: data.action, + }); + return ( +
    + {data.icon} +
    + ); +} diff --git a/src/mainview/components/SaveScroll.tsx b/src/mainview/components/SaveScroll.tsx new file mode 100644 index 0000000..9c63a17 --- /dev/null +++ b/src/mainview/components/SaveScroll.tsx @@ -0,0 +1,7 @@ +import { ScrollSaveParams, useScrollSave } from "../scripts/utils"; + +export default function ScrollSave (data: ScrollSaveParams) +{ + useScrollSave(data); + return <>; +} \ No newline at end of file diff --git a/src/mainview/components/ShortcutPrompt.tsx b/src/mainview/components/ShortcutPrompt.tsx new file mode 100644 index 0000000..065b2bc --- /dev/null +++ b/src/mainview/components/ShortcutPrompt.tsx @@ -0,0 +1,29 @@ +import React, { MouseEventHandler } from "react"; +import SvgIcon, { IconType } from "./SvgIcon"; +import classNames from "classnames"; +import { twMerge } from "tailwind-merge"; + +export default function ShortcutPrompt (data: { + icon: IconType; + label?: string; + className?: string; + onClick?: MouseEventHandler; +}) +{ + return ( + + + {data.label} + + ); +} diff --git a/src/mainview/components/Shortcuts.tsx b/src/mainview/components/Shortcuts.tsx new file mode 100644 index 0000000..581b891 --- /dev/null +++ b/src/mainview/components/Shortcuts.tsx @@ -0,0 +1,14 @@ +import React from 'react'; +import ShortcutPrompt from './ShortcutPrompt'; + +export default function Shortcuts () +{ + return ( +
    + + + + +
    + ); +} diff --git a/src/mainview/components/SvgIcon.tsx b/src/mainview/components/SvgIcon.tsx new file mode 100644 index 0000000..66a5a26 --- /dev/null +++ b/src/mainview/components/SvgIcon.tsx @@ -0,0 +1,32 @@ +import "virtual:svg-icons/register"; +import { StaticAssetPath } from "../gen/static-icon-assets.gen"; + +type OnlySvgIcon = T extends `${infer Rest}.svg` + ? Rest + : never; +type StripSvg = T extends `${infer Rest}.svg` ? Rest : T; +type ReplaceSlash = T extends `${infer Left}/${infer Right}` + ? `${Left}-${ReplaceSlash}` + : T; +type IconName = ReplaceSlash>>; +export type IconType = IconName; + +export default function SvgIcon ({ + icon, + prefix = "icon", + className, + ...props +}: { + icon: IconType; + prefix?: string; + className?: string; +}) +{ + const symbolId = `#${prefix}-${icon}`; + + return ( + + ); +} diff --git a/src/mainview/contexts/ToasterContext.tsx b/src/mainview/contexts/ToasterContext.tsx new file mode 100644 index 0000000..e5ef1e5 --- /dev/null +++ b/src/mainview/contexts/ToasterContext.tsx @@ -0,0 +1,76 @@ +import classNames from "classnames"; +import { CircleX, Cross, X } from "lucide-react"; +import { createContext, JSX, useContext, useEffect, useState } from "react"; +import toast, { ToastBar, Toaster } from "react-hot-toast"; + +let toasterGlobalId = 0; + +const ToastersContext = createContext( + {} as { + showToaster: (data: Toast) => void; + }, +); + +export function useToasters () +{ + const toasters = useContext(ToastersContext); + return { ...toasters }; +} + +interface Toast +{ + message: string | JSX.Element; + type: "success" | "info" | "error" | "warning"; + duration?: number; + icon?: JSX.Element; +} + +interface ToastExtra extends Toast +{ + timeout?: NodeJS.Timeout; + id: number; +} + +function ToastComponent (data: { toast: Toast; }) +{ + return ( +
    + + {data.toast.icon} + {data.toast.message} + +
    + ); +} + +export function Toasters () +{ + const [visibleToasters, setVisible] = useState([]); + useEffect(() => + { + return () => + { + visibleToasters.filter((t) => t.timeout).forEach((t) => clearTimeout(t.timeout)); + }; + }, [setVisible]); + + return ( + + {(t) => + {({ icon, message }) => ( + <> + {icon} + {message} + {t.type !== 'loading' && ( + + )} + + )} + } + + ); +} diff --git a/src/mainview/gen/routeTree.gen.ts b/src/mainview/gen/routeTree.gen.ts new file mode 100644 index 0000000..0dae4b6 --- /dev/null +++ b/src/mainview/gen/routeTree.gen.ts @@ -0,0 +1,178 @@ +/* eslint-disable */ + +// @ts-nocheck + +// noinspection JSUnusedGlobalSymbols + +// This file was automatically generated by TanStack Router. +// You should NOT make any changes in this file as it will be overwritten. +// Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. + +import { Route as rootRouteImport } from './../routes/__root' +import { Route as SettingsRouteRouteImport } from './../routes/settings/route' +import { Route as IndexRouteImport } from './../routes/index' +import { Route as SettingsAccountsRouteImport } from './../routes/settings/accounts' +import { Route as PlatformIdRouteImport } from './../routes/platform/$id' +import { Route as GameIdRouteImport } from './../routes/game/$id' +import { Route as CollectionIdRouteImport } from './../routes/collection/$id' + +const SettingsRouteRoute = SettingsRouteRouteImport.update({ + id: '/settings', + path: '/settings', + getParentRoute: () => rootRouteImport, +} as any) +const IndexRoute = IndexRouteImport.update({ + id: '/', + path: '/', + getParentRoute: () => rootRouteImport, +} as any) +const SettingsAccountsRoute = SettingsAccountsRouteImport.update({ + id: '/accounts', + path: '/accounts', + getParentRoute: () => SettingsRouteRoute, +} as any) +const PlatformIdRoute = PlatformIdRouteImport.update({ + id: '/platform/$id', + path: '/platform/$id', + getParentRoute: () => rootRouteImport, +} as any) +const GameIdRoute = GameIdRouteImport.update({ + id: '/game/$id', + path: '/game/$id', + getParentRoute: () => rootRouteImport, +} as any) +const CollectionIdRoute = CollectionIdRouteImport.update({ + id: '/collection/$id', + path: '/collection/$id', + getParentRoute: () => rootRouteImport, +} as any) + +export interface FileRoutesByFullPath { + '/': typeof IndexRoute + '/settings': typeof SettingsRouteRouteWithChildren + '/collection/$id': typeof CollectionIdRoute + '/game/$id': typeof GameIdRoute + '/platform/$id': typeof PlatformIdRoute + '/settings/accounts': typeof SettingsAccountsRoute +} +export interface FileRoutesByTo { + '/': typeof IndexRoute + '/settings': typeof SettingsRouteRouteWithChildren + '/collection/$id': typeof CollectionIdRoute + '/game/$id': typeof GameIdRoute + '/platform/$id': typeof PlatformIdRoute + '/settings/accounts': typeof SettingsAccountsRoute +} +export interface FileRoutesById { + __root__: typeof rootRouteImport + '/': typeof IndexRoute + '/settings': typeof SettingsRouteRouteWithChildren + '/collection/$id': typeof CollectionIdRoute + '/game/$id': typeof GameIdRoute + '/platform/$id': typeof PlatformIdRoute + '/settings/accounts': typeof SettingsAccountsRoute +} +export interface FileRouteTypes { + fileRoutesByFullPath: FileRoutesByFullPath + fullPaths: + | '/' + | '/settings' + | '/collection/$id' + | '/game/$id' + | '/platform/$id' + | '/settings/accounts' + fileRoutesByTo: FileRoutesByTo + to: + | '/' + | '/settings' + | '/collection/$id' + | '/game/$id' + | '/platform/$id' + | '/settings/accounts' + id: + | '__root__' + | '/' + | '/settings' + | '/collection/$id' + | '/game/$id' + | '/platform/$id' + | '/settings/accounts' + fileRoutesById: FileRoutesById +} +export interface RootRouteChildren { + IndexRoute: typeof IndexRoute + SettingsRouteRoute: typeof SettingsRouteRouteWithChildren + CollectionIdRoute: typeof CollectionIdRoute + GameIdRoute: typeof GameIdRoute + PlatformIdRoute: typeof PlatformIdRoute +} + +declare module '@tanstack/react-router' { + interface FileRoutesByPath { + '/settings': { + id: '/settings' + path: '/settings' + fullPath: '/settings' + preLoaderRoute: typeof SettingsRouteRouteImport + parentRoute: typeof rootRouteImport + } + '/': { + id: '/' + path: '/' + fullPath: '/' + preLoaderRoute: typeof IndexRouteImport + parentRoute: typeof rootRouteImport + } + '/settings/accounts': { + id: '/settings/accounts' + path: '/accounts' + fullPath: '/settings/accounts' + preLoaderRoute: typeof SettingsAccountsRouteImport + parentRoute: typeof SettingsRouteRoute + } + '/platform/$id': { + id: '/platform/$id' + path: '/platform/$id' + fullPath: '/platform/$id' + preLoaderRoute: typeof PlatformIdRouteImport + parentRoute: typeof rootRouteImport + } + '/game/$id': { + id: '/game/$id' + path: '/game/$id' + fullPath: '/game/$id' + preLoaderRoute: typeof GameIdRouteImport + parentRoute: typeof rootRouteImport + } + '/collection/$id': { + id: '/collection/$id' + path: '/collection/$id' + fullPath: '/collection/$id' + preLoaderRoute: typeof CollectionIdRouteImport + parentRoute: typeof rootRouteImport + } + } +} + +interface SettingsRouteRouteChildren { + SettingsAccountsRoute: typeof SettingsAccountsRoute +} + +const SettingsRouteRouteChildren: SettingsRouteRouteChildren = { + SettingsAccountsRoute: SettingsAccountsRoute, +} + +const SettingsRouteRouteWithChildren = SettingsRouteRoute._addFileChildren( + SettingsRouteRouteChildren, +) + +const rootRouteChildren: RootRouteChildren = { + IndexRoute: IndexRoute, + SettingsRouteRoute: SettingsRouteRouteWithChildren, + CollectionIdRoute: CollectionIdRoute, + GameIdRoute: GameIdRoute, + PlatformIdRoute: PlatformIdRoute, +} +export const routeTree = rootRouteImport + ._addFileChildren(rootRouteChildren) + ._addFileTypes() diff --git a/src/mainview/gen/static-icon-assets.gen.ts b/src/mainview/gen/static-icon-assets.gen.ts new file mode 100644 index 0000000..cb3fe1b --- /dev/null +++ b/src/mainview/gen/static-icon-assets.gen.ts @@ -0,0 +1,483 @@ +// This file is auto-generated. Do not edit it manually. + + +export type StaticAssetPath = + 'LICENSE.md' | + 'controller_steamdeck.svg' | + 'controller_xbox360.svg' | + 'controller_xbox_adaptive.svg' | + 'controller_xboxone.svg' | + 'controller_xboxseries.svg' | + 'steamdeck_button_a.svg' | + 'steamdeck_button_a_outline.svg' | + 'steamdeck_button_b.svg' | + 'steamdeck_button_b_outline.svg' | + 'steamdeck_button_guide.svg' | + 'steamdeck_button_guide_outline.svg' | + 'steamdeck_button_l1.svg' | + 'steamdeck_button_l1_outline.svg' | + 'steamdeck_button_l2.svg' | + 'steamdeck_button_l2_outline.svg' | + 'steamdeck_button_l4.svg' | + 'steamdeck_button_l4_outline.svg' | + 'steamdeck_button_l5.svg' | + 'steamdeck_button_l5_outline.svg' | + 'steamdeck_button_options.svg' | + 'steamdeck_button_options_outline.svg' | + 'steamdeck_button_quickaccess.svg' | + 'steamdeck_button_quickaccess_outline.svg' | + 'steamdeck_button_r1.svg' | + 'steamdeck_button_r1_outline.svg' | + 'steamdeck_button_r2.svg' | + 'steamdeck_button_r2_outline.svg' | + 'steamdeck_button_r4.svg' | + 'steamdeck_button_r4_outline.svg' | + 'steamdeck_button_r5.svg' | + 'steamdeck_button_r5_outline.svg' | + 'steamdeck_button_view.svg' | + 'steamdeck_button_view_outline.svg' | + 'steamdeck_button_x.svg' | + 'steamdeck_button_x_outline.svg' | + 'steamdeck_button_y.svg' | + 'steamdeck_button_y_outline.svg' | + 'steamdeck_dpad.svg' | + 'steamdeck_dpad_all.svg' | + 'steamdeck_dpad_down.svg' | + 'steamdeck_dpad_down_outline.svg' | + 'steamdeck_dpad_horizontal.svg' | + 'steamdeck_dpad_horizontal_outline.svg' | + 'steamdeck_dpad_left.svg' | + 'steamdeck_dpad_left_outline.svg' | + 'steamdeck_dpad_none.svg' | + 'steamdeck_dpad_right.svg' | + 'steamdeck_dpad_right_outline.svg' | + 'steamdeck_dpad_up.svg' | + 'steamdeck_dpad_up_outline.svg' | + 'steamdeck_dpad_vertical.svg' | + 'steamdeck_dpad_vertical_outline.svg' | + 'steamdeck_stick_l.svg' | + 'steamdeck_stick_l_down.svg' | + 'steamdeck_stick_l_horizontal.svg' | + 'steamdeck_stick_l_left.svg' | + 'steamdeck_stick_l_press.svg' | + 'steamdeck_stick_l_right.svg' | + 'steamdeck_stick_l_up.svg' | + 'steamdeck_stick_l_vertical.svg' | + 'steamdeck_stick_r.svg' | + 'steamdeck_stick_r_down.svg' | + 'steamdeck_stick_r_horizontal.svg' | + 'steamdeck_stick_r_left.svg' | + 'steamdeck_stick_r_press.svg' | + 'steamdeck_stick_r_right.svg' | + 'steamdeck_stick_r_up.svg' | + 'steamdeck_stick_r_vertical.svg' | + 'steamdeck_stick_side_l.svg' | + 'steamdeck_stick_side_r.svg' | + 'steamdeck_stick_top_l.svg' | + 'steamdeck_stick_top_r.svg' | + 'steamdeck_trackpad.svg' | + 'steamdeck_trackpad_all.svg' | + 'steamdeck_trackpad_all_outline.svg' | + 'steamdeck_trackpad_down.svg' | + 'steamdeck_trackpad_down_outline.svg' | + 'steamdeck_trackpad_horizontal.svg' | + 'steamdeck_trackpad_horizontal_outline.svg' | + 'steamdeck_trackpad_l.svg' | + 'steamdeck_trackpad_l_all.svg' | + 'steamdeck_trackpad_l_all_outline.svg' | + 'steamdeck_trackpad_l_down.svg' | + 'steamdeck_trackpad_l_down_outline.svg' | + 'steamdeck_trackpad_l_horizontal.svg' | + 'steamdeck_trackpad_l_horizontal_outline.svg' | + 'steamdeck_trackpad_l_left.svg' | + 'steamdeck_trackpad_l_left_outline.svg' | + 'steamdeck_trackpad_l_outline.svg' | + 'steamdeck_trackpad_l_right.svg' | + 'steamdeck_trackpad_l_right_outline.svg' | + 'steamdeck_trackpad_l_up.svg' | + 'steamdeck_trackpad_l_up_outline.svg' | + 'steamdeck_trackpad_l_vertical.svg' | + 'steamdeck_trackpad_l_vertical_outline.svg' | + 'steamdeck_trackpad_left.svg' | + 'steamdeck_trackpad_left_outline.svg' | + 'steamdeck_trackpad_outline.svg' | + 'steamdeck_trackpad_r.svg' | + 'steamdeck_trackpad_r_all.svg' | + 'steamdeck_trackpad_r_all_outline.svg' | + 'steamdeck_trackpad_r_down.svg' | + 'steamdeck_trackpad_r_down_outline.svg' | + 'steamdeck_trackpad_r_horizontal.svg' | + 'steamdeck_trackpad_r_horizontal_outline.svg' | + 'steamdeck_trackpad_r_left.svg' | + 'steamdeck_trackpad_r_left_outline.svg' | + 'steamdeck_trackpad_r_outline.svg' | + 'steamdeck_trackpad_r_right.svg' | + 'steamdeck_trackpad_r_right_outline.svg' | + 'steamdeck_trackpad_r_up.svg' | + 'steamdeck_trackpad_r_up_outline.svg' | + 'steamdeck_trackpad_r_vertical.svg' | + 'steamdeck_trackpad_r_vertical_outline.svg' | + 'steamdeck_trackpad_right.svg' | + 'steamdeck_trackpad_right_outline.svg' | + 'steamdeck_trackpad_up.svg' | + 'steamdeck_trackpad_up_outline.svg' | + 'steamdeck_trackpad_vertical.svg' | + 'steamdeck_trackpad_vertical_outline.svg' | + 'xbox_button_a.svg' | + 'xbox_button_a_outline.svg' | + 'xbox_button_b.svg' | + 'xbox_button_b_outline.svg' | + 'xbox_button_back.svg' | + 'xbox_button_back_icon.svg' | + 'xbox_button_back_icon_outline.svg' | + 'xbox_button_back_outline.svg' | + 'xbox_button_color_a.svg' | + 'xbox_button_color_a_outline.svg' | + 'xbox_button_color_b.svg' | + 'xbox_button_color_b_outline.svg' | + 'xbox_button_color_x.svg' | + 'xbox_button_color_x_outline.svg' | + 'xbox_button_color_y.svg' | + 'xbox_button_color_y_outline.svg' | + 'xbox_button_menu.svg' | + 'xbox_button_menu_outline.svg' | + 'xbox_button_share.svg' | + 'xbox_button_share_outline.svg' | + 'xbox_button_start.svg' | + 'xbox_button_start_icon.svg' | + 'xbox_button_start_icon_outline.svg' | + 'xbox_button_start_outline.svg' | + 'xbox_button_view.svg' | + 'xbox_button_view_outline.svg' | + 'xbox_button_x.svg' | + 'xbox_button_x_outline.svg' | + 'xbox_button_y.svg' | + 'xbox_button_y_outline.svg' | + 'xbox_dpad.svg' | + 'xbox_dpad_all.svg' | + 'xbox_dpad_down.svg' | + 'xbox_dpad_down_outline.svg' | + 'xbox_dpad_horizontal.svg' | + 'xbox_dpad_horizontal_outline.svg' | + 'xbox_dpad_left.svg' | + 'xbox_dpad_left_outline.svg' | + 'xbox_dpad_none.svg' | + 'xbox_dpad_right.svg' | + 'xbox_dpad_right_outline.svg' | + 'xbox_dpad_round.svg' | + 'xbox_dpad_round_all.svg' | + 'xbox_dpad_round_down.svg' | + 'xbox_dpad_round_horizontal.svg' | + 'xbox_dpad_round_left.svg' | + 'xbox_dpad_round_right.svg' | + 'xbox_dpad_round_up.svg' | + 'xbox_dpad_round_vertical.svg' | + 'xbox_dpad_up.svg' | + 'xbox_dpad_up_outline.svg' | + 'xbox_dpad_vertical.svg' | + 'xbox_dpad_vertical_outline.svg' | + 'xbox_elite_paddle_bottom_left.svg' | + 'xbox_elite_paddle_bottom_left_outline.svg' | + 'xbox_elite_paddle_bottom_right.svg' | + 'xbox_elite_paddle_bottom_right_outline.svg' | + 'xbox_elite_paddle_top_left.svg' | + 'xbox_elite_paddle_top_left_outline.svg' | + 'xbox_elite_paddle_top_right.svg' | + 'xbox_elite_paddle_top_right_outline.svg' | + 'xbox_guide.svg' | + 'xbox_guide_outline.svg' | + 'xbox_lb.svg' | + 'xbox_lb_outline.svg' | + 'xbox_ls.svg' | + 'xbox_ls_outline.svg' | + 'xbox_lt.svg' | + 'xbox_lt_outline.svg' | + 'xbox_rb.svg' | + 'xbox_rb_outline.svg' | + 'xbox_rs.svg' | + 'xbox_rs_outline.svg' | + 'xbox_rt.svg' | + 'xbox_rt_outline.svg' | + 'xbox_stick_l.svg' | + 'xbox_stick_l_down.svg' | + 'xbox_stick_l_horizontal.svg' | + 'xbox_stick_l_left.svg' | + 'xbox_stick_l_press.svg' | + 'xbox_stick_l_right.svg' | + 'xbox_stick_l_up.svg' | + 'xbox_stick_l_vertical.svg' | + 'xbox_stick_r.svg' | + 'xbox_stick_r_down.svg' | + 'xbox_stick_r_horizontal.svg' | + 'xbox_stick_r_left.svg' | + 'xbox_stick_r_press.svg' | + 'xbox_stick_r_right.svg' | + 'xbox_stick_r_up.svg' | + 'xbox_stick_r_vertical.svg' | + 'xbox_stick_side_l.svg' | + 'xbox_stick_side_r.svg' | + 'xbox_stick_top_l.svg' | + 'xbox_stick_top_r.svg'; + +/** + * Represents the known directories containing static assets. + * '.' represents the root directory. + */ +export type StaticAssetDirectory = + '.'; + +/** + * Represents the relative paths of files located *directly* within a specific directory. + * Use '.' for the root directory. + * @template Dir - A directory path string literal type from StaticAssetDirectory (e.g., 'icons/', 'icons/sun/', '.'). + */ +export type FilesInFolder = + Dir extends '.' + ? Exclude + : Extract extends infer Match + ? Match extends `${Dir}${infer FileName}` + ? FileName extends `${string}/${string}` + ? never + : Match + : never + : never; + + + +const assets = new Set([ + 'LICENSE.md', + 'controller_steamdeck.svg', + 'controller_xbox360.svg', + 'controller_xbox_adaptive.svg', + 'controller_xboxone.svg', + 'controller_xboxseries.svg', + 'steamdeck_button_a.svg', + 'steamdeck_button_a_outline.svg', + 'steamdeck_button_b.svg', + 'steamdeck_button_b_outline.svg', + 'steamdeck_button_guide.svg', + 'steamdeck_button_guide_outline.svg', + 'steamdeck_button_l1.svg', + 'steamdeck_button_l1_outline.svg', + 'steamdeck_button_l2.svg', + 'steamdeck_button_l2_outline.svg', + 'steamdeck_button_l4.svg', + 'steamdeck_button_l4_outline.svg', + 'steamdeck_button_l5.svg', + 'steamdeck_button_l5_outline.svg', + 'steamdeck_button_options.svg', + 'steamdeck_button_options_outline.svg', + 'steamdeck_button_quickaccess.svg', + 'steamdeck_button_quickaccess_outline.svg', + 'steamdeck_button_r1.svg', + 'steamdeck_button_r1_outline.svg', + 'steamdeck_button_r2.svg', + 'steamdeck_button_r2_outline.svg', + 'steamdeck_button_r4.svg', + 'steamdeck_button_r4_outline.svg', + 'steamdeck_button_r5.svg', + 'steamdeck_button_r5_outline.svg', + 'steamdeck_button_view.svg', + 'steamdeck_button_view_outline.svg', + 'steamdeck_button_x.svg', + 'steamdeck_button_x_outline.svg', + 'steamdeck_button_y.svg', + 'steamdeck_button_y_outline.svg', + 'steamdeck_dpad.svg', + 'steamdeck_dpad_all.svg', + 'steamdeck_dpad_down.svg', + 'steamdeck_dpad_down_outline.svg', + 'steamdeck_dpad_horizontal.svg', + 'steamdeck_dpad_horizontal_outline.svg', + 'steamdeck_dpad_left.svg', + 'steamdeck_dpad_left_outline.svg', + 'steamdeck_dpad_none.svg', + 'steamdeck_dpad_right.svg', + 'steamdeck_dpad_right_outline.svg', + 'steamdeck_dpad_up.svg', + 'steamdeck_dpad_up_outline.svg', + 'steamdeck_dpad_vertical.svg', + 'steamdeck_dpad_vertical_outline.svg', + 'steamdeck_stick_l.svg', + 'steamdeck_stick_l_down.svg', + 'steamdeck_stick_l_horizontal.svg', + 'steamdeck_stick_l_left.svg', + 'steamdeck_stick_l_press.svg', + 'steamdeck_stick_l_right.svg', + 'steamdeck_stick_l_up.svg', + 'steamdeck_stick_l_vertical.svg', + 'steamdeck_stick_r.svg', + 'steamdeck_stick_r_down.svg', + 'steamdeck_stick_r_horizontal.svg', + 'steamdeck_stick_r_left.svg', + 'steamdeck_stick_r_press.svg', + 'steamdeck_stick_r_right.svg', + 'steamdeck_stick_r_up.svg', + 'steamdeck_stick_r_vertical.svg', + 'steamdeck_stick_side_l.svg', + 'steamdeck_stick_side_r.svg', + 'steamdeck_stick_top_l.svg', + 'steamdeck_stick_top_r.svg', + 'steamdeck_trackpad.svg', + 'steamdeck_trackpad_all.svg', + 'steamdeck_trackpad_all_outline.svg', + 'steamdeck_trackpad_down.svg', + 'steamdeck_trackpad_down_outline.svg', + 'steamdeck_trackpad_horizontal.svg', + 'steamdeck_trackpad_horizontal_outline.svg', + 'steamdeck_trackpad_l.svg', + 'steamdeck_trackpad_l_all.svg', + 'steamdeck_trackpad_l_all_outline.svg', + 'steamdeck_trackpad_l_down.svg', + 'steamdeck_trackpad_l_down_outline.svg', + 'steamdeck_trackpad_l_horizontal.svg', + 'steamdeck_trackpad_l_horizontal_outline.svg', + 'steamdeck_trackpad_l_left.svg', + 'steamdeck_trackpad_l_left_outline.svg', + 'steamdeck_trackpad_l_outline.svg', + 'steamdeck_trackpad_l_right.svg', + 'steamdeck_trackpad_l_right_outline.svg', + 'steamdeck_trackpad_l_up.svg', + 'steamdeck_trackpad_l_up_outline.svg', + 'steamdeck_trackpad_l_vertical.svg', + 'steamdeck_trackpad_l_vertical_outline.svg', + 'steamdeck_trackpad_left.svg', + 'steamdeck_trackpad_left_outline.svg', + 'steamdeck_trackpad_outline.svg', + 'steamdeck_trackpad_r.svg', + 'steamdeck_trackpad_r_all.svg', + 'steamdeck_trackpad_r_all_outline.svg', + 'steamdeck_trackpad_r_down.svg', + 'steamdeck_trackpad_r_down_outline.svg', + 'steamdeck_trackpad_r_horizontal.svg', + 'steamdeck_trackpad_r_horizontal_outline.svg', + 'steamdeck_trackpad_r_left.svg', + 'steamdeck_trackpad_r_left_outline.svg', + 'steamdeck_trackpad_r_outline.svg', + 'steamdeck_trackpad_r_right.svg', + 'steamdeck_trackpad_r_right_outline.svg', + 'steamdeck_trackpad_r_up.svg', + 'steamdeck_trackpad_r_up_outline.svg', + 'steamdeck_trackpad_r_vertical.svg', + 'steamdeck_trackpad_r_vertical_outline.svg', + 'steamdeck_trackpad_right.svg', + 'steamdeck_trackpad_right_outline.svg', + 'steamdeck_trackpad_up.svg', + 'steamdeck_trackpad_up_outline.svg', + 'steamdeck_trackpad_vertical.svg', + 'steamdeck_trackpad_vertical_outline.svg', + 'xbox_button_a.svg', + 'xbox_button_a_outline.svg', + 'xbox_button_b.svg', + 'xbox_button_b_outline.svg', + 'xbox_button_back.svg', + 'xbox_button_back_icon.svg', + 'xbox_button_back_icon_outline.svg', + 'xbox_button_back_outline.svg', + 'xbox_button_color_a.svg', + 'xbox_button_color_a_outline.svg', + 'xbox_button_color_b.svg', + 'xbox_button_color_b_outline.svg', + 'xbox_button_color_x.svg', + 'xbox_button_color_x_outline.svg', + 'xbox_button_color_y.svg', + 'xbox_button_color_y_outline.svg', + 'xbox_button_menu.svg', + 'xbox_button_menu_outline.svg', + 'xbox_button_share.svg', + 'xbox_button_share_outline.svg', + 'xbox_button_start.svg', + 'xbox_button_start_icon.svg', + 'xbox_button_start_icon_outline.svg', + 'xbox_button_start_outline.svg', + 'xbox_button_view.svg', + 'xbox_button_view_outline.svg', + 'xbox_button_x.svg', + 'xbox_button_x_outline.svg', + 'xbox_button_y.svg', + 'xbox_button_y_outline.svg', + 'xbox_dpad.svg', + 'xbox_dpad_all.svg', + 'xbox_dpad_down.svg', + 'xbox_dpad_down_outline.svg', + 'xbox_dpad_horizontal.svg', + 'xbox_dpad_horizontal_outline.svg', + 'xbox_dpad_left.svg', + 'xbox_dpad_left_outline.svg', + 'xbox_dpad_none.svg', + 'xbox_dpad_right.svg', + 'xbox_dpad_right_outline.svg', + 'xbox_dpad_round.svg', + 'xbox_dpad_round_all.svg', + 'xbox_dpad_round_down.svg', + 'xbox_dpad_round_horizontal.svg', + 'xbox_dpad_round_left.svg', + 'xbox_dpad_round_right.svg', + 'xbox_dpad_round_up.svg', + 'xbox_dpad_round_vertical.svg', + 'xbox_dpad_up.svg', + 'xbox_dpad_up_outline.svg', + 'xbox_dpad_vertical.svg', + 'xbox_dpad_vertical_outline.svg', + 'xbox_elite_paddle_bottom_left.svg', + 'xbox_elite_paddle_bottom_left_outline.svg', + 'xbox_elite_paddle_bottom_right.svg', + 'xbox_elite_paddle_bottom_right_outline.svg', + 'xbox_elite_paddle_top_left.svg', + 'xbox_elite_paddle_top_left_outline.svg', + 'xbox_elite_paddle_top_right.svg', + 'xbox_elite_paddle_top_right_outline.svg', + 'xbox_guide.svg', + 'xbox_guide_outline.svg', + 'xbox_lb.svg', + 'xbox_lb_outline.svg', + 'xbox_ls.svg', + 'xbox_ls_outline.svg', + 'xbox_lt.svg', + 'xbox_lt_outline.svg', + 'xbox_rb.svg', + 'xbox_rb_outline.svg', + 'xbox_rs.svg', + 'xbox_rs_outline.svg', + 'xbox_rt.svg', + 'xbox_rt_outline.svg', + 'xbox_stick_l.svg', + 'xbox_stick_l_down.svg', + 'xbox_stick_l_horizontal.svg', + 'xbox_stick_l_left.svg', + 'xbox_stick_l_press.svg', + 'xbox_stick_l_right.svg', + 'xbox_stick_l_up.svg', + 'xbox_stick_l_vertical.svg', + 'xbox_stick_r.svg', + 'xbox_stick_r_down.svg', + 'xbox_stick_r_horizontal.svg', + 'xbox_stick_r_left.svg', + 'xbox_stick_r_press.svg', + 'xbox_stick_r_right.svg', + 'xbox_stick_r_up.svg', + 'xbox_stick_r_vertical.svg', + 'xbox_stick_side_l.svg', + 'xbox_stick_side_r.svg', + 'xbox_stick_top_l.svg', + 'xbox_stick_top_r.svg' +]); + +// Store basePath resolved from Vite config +const BASE_PATH = "./"; + + +/** + * Gets the URL for a specific static asset + * @param path Path to the asset + * @returns The URL for the asset + */ +export function staticAssets(path: StaticAssetPath): string { + if (!assets.has(path)) { + throw new Error( + "Static asset does not exist in static assets directory" + ); + } + return `${BASE_PATH}${path}`; +} + diff --git a/src/mainview/index.css b/src/mainview/index.css index 06141ff..4ab6cc4 100644 --- a/src/mainview/index.css +++ b/src/mainview/index.css @@ -1,4 +1,6 @@ @import "tailwindcss"; +@import 'animate.css'; +@plugin "daisyui"; @theme { --color-dark: #333333; @@ -8,6 +10,26 @@ --color-primary: #E5FF00; --color-alt: #4656E6; --color-alert: #E60012; + --game-card-height: calc(var(--spacing) * 100); + --game-card-width: calc(var(--spacing) * 64); + + --animate-wiggle: wiggle 0.3s ease-in-out 1; + + @keyframes wiggle { + + 0%, + 100% { + transform: perspective(400px) rotate3d(0, 1, 0, 2deg); + } + + 50% { + transform: perspective(400px) rotate3d(0, 1, 0, -2deg); + } + } +} + +symbol path { + fill: var(--color-base-content) !important; } html { @@ -16,8 +38,220 @@ html { text-rendering: optimizeLegibility; } -body { +@layer components { + .game-card { + @apply rounded-2xl; + } + + .menu-icon svg { + @apply sm:size-8 md:size-10; + } + + .header-icon svg { + @apply w-8 h-8 min-w-8 min-h-8; + } + + .header-icon-small svg { + @apply w-6 h-6 min-w-6 min-h-6; + } + + .card-list { + display: flex; + } + + .card-grid { + display: grid; + grid-template-columns: repeat(auto-fill, var(--game-card-width)); + grid-auto-rows: var(--game-card-height); + padding-bottom: 16px; + } + + .no-scrollbar { + scrollbar-width: none; + } + + &::view-transition-old(.game-card), + &::view-transition-new(.game-card) { + height: 100%; + width: 100%; + } + + html:active-view-transition-type(zoom-in) { + + &::view-transition-old(root) { + animation: fade-out 300ms ease-in forwards; + } + + &::view-transition-new(root) { + animation: zoom-in-fade-in 300ms ease-in-out forwards; + } + } + + html:active-view-transition-type(zoom-out) { + + &::view-transition-old(root) { + animation: zoom-out-fade-out 300ms ease-in-out forwards; + } + + &::view-transition-new(root) { + animation: zoom-start-small-in-fade-in 300ms ease-in-out forwards; + } + } + + @keyframes fade-out { + from { + opacity: 1; + } + + to { + opacity: 0; + } + } + + @keyframes zoom-start-small-in-fade-in { + from { + scale: 95%; + opacity: 0; + } + + to { + scale: 100%; + opacity: 1; + } + } + + @keyframes zoom-in-fade-out { + from { + scale: 100%; + opacity: 1; + } + + to { + scale: 105%; + opacity: 0; + } + } + + @keyframes zoom-in-fade-in { + from { + scale: 105%; + opacity: 0; + } + + to { + scale: 100%; + opacity: 1; + } + } } -#root { + +/* Background */ +#container { + position: relative; + height: 100%; + width: 100%; + margin: 0px auto; + padding: 0px auto; +} + +#container-inside { + position: relative; + min-width: 960px; + max-width: 1280px; + height: auto; + min-height: 100%; + margin: 0px auto; + padding: 0px auto; + overflow: visible; +} + +#circle-small { + -webkit-animation: circle-small-scale 3s ease-in-out infinite alternate; + animation: circle-small-scale 3s ease-in-out infinite alternate; + animation-timing-function: cubic-bezier(.6, 0, .4, 1); + animation-delay: 0s; + position: absolute; + top: 200px; + left: -150px; + width: 300px; + height: 300px; + border-radius: 50%; + opacity: 0.2; +} + +#circle-medium { + -webkit-animation: circle-small-scale 3s ease-in-out infinite alternate; + animation: circle-small-scale 3s ease-in-out infinite alternate; + animation-timing-function: cubic-bezier(.6, 0, .4, 1); + animation-delay: 0.3s; + position: absolute; + top: 50px; + left: -300px; + width: 600px; + height: 600px; + border-radius: 50%; + opacity: 0.15; +} + +#circle-large { + -webkit-animation: circle-small-scale 3s ease-in-out infinite alternate; + animation: circle-small-scale 3s ease-in-out infinite alternate; + animation-timing-function: cubic-bezier(.6, 0, .4, 1); + animation-delay: 0.6s; + position: absolute; + top: -100px; + left: -450px; + width: 900px; + height: 900px; + border-radius: 50%; + opacity: 0.1; +} + +#circle-xlarge { + -webkit-animation: circle-small-scale 3s ease-in-out infinite alternate; + animation: circle-small-scale 3s ease-in-out infinite alternate; + animation-timing-function: cubic-bezier(.6, 0, .4, 1); + animation-delay: 0.9s; + position: absolute; + top: -250px; + left: -600px; + width: 1200px; + height: 1200px; + border-radius: 50%; + opacity: 0.05; +} + +#circle-xxlarge { + -webkit-animation: circle-small-scale 3s ease-in-out infinite alternate; + animation: circle-small-scale 3s ease-in-out infinite alternate; + animation-timing-function: cubic-bezier(.6, 0, .4, 1); + animation-delay: 1.2s; + position: absolute; + top: -400px; + left: -750px; + width: 1500px; + height: 1500px; + border-radius: 50%; + opacity: 0.025; +} + +@-webkit-keyframes circle-small-scale { + 0% { + -webkit-transform: scale(1.0); + } + + 100% { + -webkit-transform: scale(1.1); + } +} + +@keyframes circle-small-scale { + 0% { + transform: scale(1.0); + } + + 100% { + transform: scale(1.1); + } } \ No newline at end of file diff --git a/src/mainview/index.html b/src/mainview/index.html index fea9b76..849550e 100644 --- a/src/mainview/index.html +++ b/src/mainview/index.html @@ -1,12 +1,13 @@ - + + GameFlow +
    - - \ No newline at end of file + diff --git a/src/mainview/index.tsx b/src/mainview/index.tsx index d9a6f78..b31c0ef 100644 --- a/src/mainview/index.tsx +++ b/src/mainview/index.tsx @@ -1,30 +1,92 @@ import { StrictMode } from "react"; import { createRoot } from "react-dom/client"; import "./index.css"; -import { createRouter, RouterProvider } from "@tanstack/react-router"; -import { routeTree } from "./routeTree.gen"; +import +{ + createHashHistory, + createRouter, + Link, + RouterProvider, +} from "@tanstack/react-router"; +import { routeTree } from "./gen/routeTree.gen"; +import { QueryClient } from "@tanstack/react-query"; +import { AppType } from "../bun/api/rpc"; +import { RPC_URL } from "../shared/constants"; +import "./scripts/gamepads"; +import "./scripts/windowEvents"; +import { Toasters } from "./contexts/ToasterContext"; +import { client as rommClient } from "../clients/romm/client.gen"; +import { setupRouterSsrQueryIntegration } from "@tanstack/react-router-ssr-query"; +import "./scripts/spatialNavigation"; +import +{ + treaty +} from '@elysiajs/eden'; + +const hashHistory = createHashHistory({}); + +export const client = treaty(RPC_URL(__HOST__), { + keepDomain: true, + fetch: { + credentials: 'include', + } +}); + +rommClient.setConfig({ + baseUrl: `${RPC_URL(__HOST__)}/api/romm`, + credentials: "include", + mode: "cors", +}); + +const queryClient = new QueryClient(); + +export interface RouterContext +{ + queryClient: QueryClient; +} // Set up a Router instance -const router = createRouter({ +export const Router = createRouter({ routeTree, + history: hashHistory, defaultPreload: "intent", + context: { queryClient }, scrollRestoration: true, + scrollToTopSelectors: ["[save-scroll]"], + defaultNotFoundComponent: () => + { + return ( +
    +

    {window.location.href} Not found!

    + Go home +
    + ); + }, }); // Register things for typesafety declare module "@tanstack/react-router" { - interface Register { - router: typeof router; + interface Register + { + router: typeof Router; } } +setupRouterSsrQueryIntegration({ + router: Router, + queryClient, + wrapQueryClient: true, +}); + const rootElement = document.getElementById("root")!; -if (!rootElement.innerHTML) { +if (!rootElement.innerHTML) +{ const root = createRoot(rootElement); root.render( - + + , ); } diff --git a/src/mainview/query-options.ts b/src/mainview/query-options.ts new file mode 100644 index 0000000..3cf00dc --- /dev/null +++ b/src/mainview/query-options.ts @@ -0,0 +1,24 @@ +import { keepPreviousData, queryOptions } from "@tanstack/react-query"; +import { getRomApiRomsIdGetOptions, getRomsApiRomsGetOptions } from "../clients/romm/@tanstack/react-query.gen"; +import { GameListFilter } from "./components/GameList"; +import { DefaultRommStaleTime } from "../shared/constants"; + +export function gamesQueryOptions (filter?: GameListFilter) +{ + return queryOptions({ + ...getRomsApiRomsGetOptions({ query: { order_by: "updated_at", platform_ids: filter?.platformIds, collection_id: filter?.collectionId } }), + refetchOnWindowFocus: false, + placeholderData: keepPreviousData, + staleTime: DefaultRommStaleTime + }); +} + +export function gameQueryOptions (id: number) +{ + return queryOptions({ + ...getRomApiRomsIdGetOptions({ path: { id } }), + refetchOnWindowFocus: false, + placeholderData: keepPreviousData, + staleTime: DefaultRommStaleTime + }); +} \ No newline at end of file diff --git a/src/mainview/routeTree.gen.ts b/src/mainview/routeTree.gen.ts deleted file mode 100644 index d1b5749..0000000 --- a/src/mainview/routeTree.gen.ts +++ /dev/null @@ -1,77 +0,0 @@ -/* eslint-disable */ - -// @ts-nocheck - -// noinspection JSUnusedGlobalSymbols - -// This file was automatically generated by TanStack Router. -// You should NOT make any changes in this file as it will be overwritten. -// Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. - -import { Route as rootRouteImport } from './routes/__root' -import { Route as GameDetailsRouteImport } from './routes/GameDetails' -import { Route as DashboardRouteImport } from './routes/Dashboard' - -const GameDetailsRoute = GameDetailsRouteImport.update({ - id: '/GameDetails', - path: '/GameDetails', - getParentRoute: () => rootRouteImport, -} as any) -const DashboardRoute = DashboardRouteImport.update({ - id: '/Dashboard', - path: '/Dashboard', - getParentRoute: () => rootRouteImport, -} as any) - -export interface FileRoutesByFullPath { - '/Dashboard': typeof DashboardRoute - '/GameDetails': typeof GameDetailsRoute -} -export interface FileRoutesByTo { - '/Dashboard': typeof DashboardRoute - '/GameDetails': typeof GameDetailsRoute -} -export interface FileRoutesById { - __root__: typeof rootRouteImport - '/Dashboard': typeof DashboardRoute - '/GameDetails': typeof GameDetailsRoute -} -export interface FileRouteTypes { - fileRoutesByFullPath: FileRoutesByFullPath - fullPaths: '/Dashboard' | '/GameDetails' - fileRoutesByTo: FileRoutesByTo - to: '/Dashboard' | '/GameDetails' - id: '__root__' | '/Dashboard' | '/GameDetails' - fileRoutesById: FileRoutesById -} -export interface RootRouteChildren { - DashboardRoute: typeof DashboardRoute - GameDetailsRoute: typeof GameDetailsRoute -} - -declare module '@tanstack/react-router' { - interface FileRoutesByPath { - '/GameDetails': { - id: '/GameDetails' - path: '/GameDetails' - fullPath: '/GameDetails' - preLoaderRoute: typeof GameDetailsRouteImport - parentRoute: typeof rootRouteImport - } - '/Dashboard': { - id: '/Dashboard' - path: '/Dashboard' - fullPath: '/Dashboard' - preLoaderRoute: typeof DashboardRouteImport - parentRoute: typeof rootRouteImport - } - } -} - -const rootRouteChildren: RootRouteChildren = { - DashboardRoute: DashboardRoute, - GameDetailsRoute: GameDetailsRoute, -} -export const routeTree = rootRouteImport - ._addFileChildren(rootRouteChildren) - ._addFileTypes() diff --git a/src/mainview/routes/Dashboard.tsx b/src/mainview/routes/Dashboard.tsx deleted file mode 100644 index 42219ce..0000000 --- a/src/mainview/routes/Dashboard.tsx +++ /dev/null @@ -1,225 +0,0 @@ -import React, { useEffect, useState } from "react"; -import { - Plus, - Search, - Settings, - Power, - Sun, - Wifi, - BatteryFull, - Gamepad2, - Bluetooth, - Settings2, - Bell, - HardDrive, -} from "lucide-react"; -import { createFileRoute, Link, linkOptions } from "@tanstack/react-router"; -import "gamepad.css/styles.min.css"; -import GamepadIcon from "../components/GamepadIcon"; -import Clock from "../components/Clock"; -import classNames from "classnames"; - -export const Route = createFileRoute("/Dashboard")({ - component: ConsoleHomeUI, -}); - -const games = [ - { - title: "The Legend of Zelda", - subtitle: "Link's Awakening", - }, - { - title: "Captain Toad", - subtitle: "Treasure Tracker", - focused: true, - }, - { - title: "Crash Bandicoot", - subtitle: "N. Sane Trilogy", - }, - { - title: "Super Mario", - subtitle: "Odyssey", - }, - { - title: "Animal Crossing", - subtitle: "New Horizons", - }, -]; - -export default function ConsoleHomeUI() { - const [focus, setFocus] = useState(1); - - useEffect(() => { - const onKey = (e: KeyboardEvent) => { - if (e.key === "ArrowRight") - setFocus((i) => Math.min(i + 1, games.length - 1)); - if (e.key === "ArrowLeft") setFocus((i) => Math.max(i - 1, 0)); - }; - window.addEventListener("keydown", onKey); - return () => window.removeEventListener("keydown", onKey); - }, []); - - return ( -
    - {/* Top bar */} -
    -
    -
    -
    - -
    - -
    - - - - -
    - - 100% -
    -
    -
    - -
    -
    - -
    -
    -
    -
    - - {/* Filter bar */} -
    - -
    - - - -
    - -
    - - {/* Game carousel */} -
    - {games.map((g, i) => { - const focused = i === focus; - return ( -
    -
    -
    -
    - -
    -
    -
    -
    {g.title}
    -
    {g.subtitle}
    -
    -
    - ); - })} -
    - - {/* Menu */} - -
    - - - - - - - - Settings - -
    - - {/* Bottom bar */} -
    -
    - - - Continue - - - - Back - - - - Close - - - - Options - -
    -
    -
    - ); -} - -function CircleIcon({ - to, - active, - highlight, -}: { - to?: any; - active?: boolean; - highlight?: boolean; - label?: string; -}) { - return ( - - - - ); -} diff --git a/src/mainview/routes/GameDetails.tsx b/src/mainview/routes/GameDetails.tsx deleted file mode 100644 index 3dcf5bc..0000000 --- a/src/mainview/routes/GameDetails.tsx +++ /dev/null @@ -1,110 +0,0 @@ -import React, { useEffect, useState } from "react"; -import { Bell, Library, Store, Settings, Gamepad2 } from "lucide-react"; -import { createFileRoute } from "@tanstack/react-router"; - -const games = [ - "Halo Infinite", - "Cyberpunk", - "Hades", - "Stardew Valley", - "Neon Skies", - "Void Runner", - "Rogue Light", - "Drift City", -]; - -export const Route = createFileRoute("/GameDetails")({ - loader: ({ params }) => params.postId, - component: GameDetailsUI, -}); - -export function GameDetailsUI() { - // In a component! - const { postId } = Route.useParams(); - - return ( -
    - {/* Header */} -
    -
    -
    Now Playing
    -

    - Halo Infinite -

    -
    - Action · FPS · Sci-Fi -
    -
    - -
    - - 3 -
    -
    - - {/* Content split */} -
    - {/* Cover / media */} -
    -
    - - {/* Primary action */} - -
    - - {/* Details */} -
    - {/* Description */} -

    - Experience the epic sci-fi saga and master chief’s greatest journey - yet. Explore vast open worlds, engage in tactical combat, and - uncover the mysteries of Zeta Halo. -

    - - {/* Metadata */} -
    - - - - -
    - - {/* Actions */} -
    - - - -
    -
    -
    - - {/* Footer hints */} -
    - A Play - B Back - Y Options -
    -
    - ); -} - -function Detail({ label, value }: { label: string; value: string }) { - return ( -
    -
    - {label} -
    -
    {value}
    -
    - ); -} - -function SecondaryButton({ label }: { label: string }) { - return ( - - ); -} diff --git a/src/mainview/routes/__root.tsx b/src/mainview/routes/__root.tsx index d40c1d5..9241e11 100644 --- a/src/mainview/routes/__root.tsx +++ b/src/mainview/routes/__root.tsx @@ -1,16 +1,23 @@ -import { Link, Outlet, createRootRoute } from "@tanstack/react-router"; +import { Outlet, createRootRouteWithContext } from "@tanstack/react-router"; import { TanStackRouterDevtools } from "@tanstack/react-router-devtools"; -import { Gamepad2, Library, Settings, Store } from "lucide-react"; +import { ReactQueryDevtools } from "@tanstack/react-query-devtools"; +import { RouterContext } from ".."; -export const Route = createRootRoute({ +export const Route = createRootRouteWithContext()({ component: RootComponent, }); -function RootComponent() { +function RootComponent () +{ return (
    - -
    + {import.meta.env.DEV && false && + <> + + + + } + ); } diff --git a/src/mainview/routes/collection/$id.tsx b/src/mainview/routes/collection/$id.tsx new file mode 100644 index 0000000..e034998 --- /dev/null +++ b/src/mainview/routes/collection/$id.tsx @@ -0,0 +1,28 @@ +import { createFileRoute, useNavigate } from '@tanstack/react-router'; +import { useEventListener, useSessionStorage } from 'usehooks-ts'; +import { CollectionsDetail } from '../../components/CollectionsDetail'; +import { getRomsApiRomsGetOptions } from '../../../clients/romm/@tanstack/react-query.gen'; +import { DefaultRommStaleTime } from '../../../shared/constants'; + +export const Route = createFileRoute('/collection/$id')({ + component: RouteComponent, + loader: ({ params, context }) => context.queryClient.fetchQuery({ + ...getRomsApiRomsGetOptions({ query: { collection_id: Number(params.id) } }), + staleTime: DefaultRommStaleTime, + }) +}); + +function RouteComponent () +{ + const { id } = Route.useParams(); + const [, setBackground] = useSessionStorage( + "home-background", + undefined, + ); + const navigate = useNavigate(); + useEventListener("cancel", () => navigate({ to: "/", viewTransition: { types: ['zoom-out'] } })); + + return ( + + ); +} diff --git a/src/mainview/routes/game/$id.tsx b/src/mainview/routes/game/$id.tsx new file mode 100644 index 0000000..b407da8 --- /dev/null +++ b/src/mainview/routes/game/$id.tsx @@ -0,0 +1,241 @@ +import { createFileRoute, useNavigate, useRouter } from "@tanstack/react-router"; +import { getRomApiRomsIdGetOptions } from "../../../clients/romm/@tanstack/react-query.gen"; +import { DefaultRommStaleTime, RPC_URL } from "../../../shared/constants"; +import { twJoin, twMerge } from "tailwind-merge"; +import { JSX, Ref, RefObject, useEffect, useMemo, useRef, useState } from "react"; +import { FocusContext, getCurrentFocusKey, setFocus, useFocusable } from "@noriginmedia/norigin-spatial-navigation"; +import classNames from "classnames"; +import { Clock, HardDrive, Image, Play, Settings, Trophy } from "lucide-react"; +import ShortcutPrompt from "../../components/ShortcutPrompt"; +import { HeaderUI } from "../../components/Header"; +import prettyBytes from 'pretty-bytes'; +import { DetailedRomSchema } from "../../../clients/romm"; +import { useEventListener } from "usehooks-ts"; +import { PopSource } from "../../scripts/spatialNavigation"; +import { gameQueryOptions } from "../../query-options"; +import { AnimatedBackground } from "../../components/AnimatedBackground"; + +export const Route = createFileRoute("/game/$id")({ + loader: ({ params, context }) => context.queryClient.fetchQuery(gameQueryOptions(Number(params.id))), + component: GameDetailsUI, + pendingComponent: GameDetailsUIPending +}); + +function GameDetailsUIPending () +{ + return +
    + +
    + +
    +
    +
    ; +} + +export function GameDetailsUI () +{ + // In a component! + const { id } = Route.useParams(); + const data = Route.useLoaderData(); + const { ref, focusKey, focusSelf } = useFocusable({ focusKey: "game-details", preferredChildFocusKey: "main-details" }); + const backgroundImage = `${RPC_URL(__HOST__)}/api/romm${data.path_cover_small}`; + const mainAreaRef = useRef(null); + + useEffect(() => + { + focusSelf(); + }, []); + + return ( + +
    + +
    + +
    +
    +
    Screenshots
    + +
    +
    +
    + +
    +
    +
    +
    + ); +} + +function Details (data: { mainAreaRef: RefObject, game: DetailedRomSchema; }) +{ + const { ref, focusKey } = useFocusable({ + focusKey: 'main-details', onFocus: () => + { + data.mainAreaRef.current?.scrollIntoView({ block: 'start', behavior: 'smooth' }); + }, + preferredChildFocusKey: "play-btn", + saveLastFocusedChild: false + }); + const navigate = useNavigate(); + const platformCoverImg = `${RPC_URL(__HOST__)}/api/romm/assets/platforms/${data.game.platform_slug}.svg`; + const gameCoverImg = `${RPC_URL(__HOST__)}/api/romm${data.game.path_cover_large}`; + useEventListener("cancel", () => + { + navigate({ to: PopSource('details') ?? '/', viewTransition: { types: ['zoom-out'] } }); + }); + + return
    + +
    +
    + +
    + +
    +
    + } >{data.game.rom_user.last_played ? new Date(data.game.rom_user.last_played).toDateString() : "Never"} + } >{prettyBytes(data.game.fs_size_bytes)} + } >{data.game.platform_display_name} +
    +

    + {data.game.summary} +

    + +
    +
    +
    +
    ; +} + +function Screenshot (data: { url: string; index: number; setFocused?: (index: number) => void; }) +{ + const { ref, focused, focusSelf } = useFocusable({ + focusKey: `screenshot-${data.index}`, + onFocus: () => + { + (ref.current as HTMLElement).scrollIntoView({ inline: 'center', behavior: 'smooth' }); + data.setFocused?.(data.index); + } + }); + return ; +} + +function Screenshots (data: { screenshots: string[]; }) +{ + const [focusedScreenshot, setFocusedScreenshot] = useState(-1); + const { ref, focusKey } = useFocusable({ + focusKey: 'screenshot-list', + onFocus: () => (ref.current as HTMLElement).scrollIntoView({ block: 'center', behavior: 'smooth' }), + onBlur: () => setFocusedScreenshot(-1) + }); + + return
    + +
    + {data.screenshots.map((s, i) => )} +
    +
    {data.screenshots.map((s, i) => + { + const focused = i === focusedScreenshot; + return ; + })}
    +
    +
    ; +} + +function PlayButton () +{ + const { focused, ref } = useFocusable({ + focusKey: "play-btn" + }); + return ( +
    + +

    Play

    +
    + ); +} + +// + +function ActionButtons (data: { game: DetailedRomSchema; }) +{ + const [hoverText, setHoverText] = useState(undefined); + const { ref, focusKey } = useFocusable({ focusKey: 'actions', onBlur: () => setHoverText(undefined) }); + + return
    + + setHoverText("")} type='primary' id="play"> +
    + {!!data.game.merged_ra_metadata?.achievements && setHoverText("Achievements")} type="base" id="achievements" > +
    +
    + + {`${data.game.merged_ra_metadata.achievements.filter(a => a.type).length}/${data.game.merged_ra_metadata.achievements.length}`} +
    + +
    +
    } + setHoverText("Settings")} type="base" id="settings" icon={} /> + {!!hoverText &&

    {hoverText}

    } +
    +
    ; +} + +function Shortcuts () +{ + const { ref, focusKey } = useFocusable({ focusKey: "action-buttons" }); + return
    + + + + + + +
    ; +} + +function Detail (data: { icon: JSX.Element; children?: any | any[]; }) +{ + return ( +
    + {data.icon} + {data.children} +
    + ); +} + +function ActionButton (data: { id: string, icon?: JSX.Element, children?: any | any[]; className?: string; type: "primary" | 'base' | "accent"; onFocus?: () => void; }) +{ + const { ref, focused } = useFocusable({ focusKey: data.id, onFocus: data.onFocus }); + const styles = { + primary: twMerge("bg-primary text-primary-content rounded-full size-21 hover:bg-base-content hover:text-base-300 hover:ring-7 hover:ring-primary", + classNames({ + "bg-base-content text-base-300 ring-7 ring-primary": focused + })), + base: twMerge(" text-base-content border-dashed border-base-content/20 border-2", classNames({ + "bg-base-content text-base-300 ring-7 ring-primary": focused + })), + accent: twMerge("bg-primary text-primary-content ", classNames({ + "bg-base-content text-base-300 ring-7 ring-primary": focused + })) + }; + return ( + + ); +} \ No newline at end of file diff --git a/src/mainview/routes/index.tsx b/src/mainview/routes/index.tsx new file mode 100644 index 0000000..88870ee --- /dev/null +++ b/src/mainview/routes/index.tsx @@ -0,0 +1,326 @@ +import { JSX, Suspense, useContext } from "react"; +import +{ + Gamepad2, + Settings, + MessageSquare, + ShoppingBag, + Image, + Search, + Power, + OctagonAlert, +} from "lucide-react"; +import +{ + createFileRoute, + useLocation, + useNavigate, +} from "@tanstack/react-router"; +import { useSuspenseQuery } from "@tanstack/react-query"; +import +{ + FocusContext, + useFocusable, +} from "@noriginmedia/norigin-spatial-navigation"; +import classNames from "classnames"; +import { DefaultRommStaleTime, RPC_URL } from "../../shared/constants"; +import { useLocalStorage, useSessionStorage } from "usehooks-ts"; +import +{ + getCollectionsApiCollectionsGetOptions, + getPlatformsApiPlatformsGetOptions, +} from "../../clients/romm/@tanstack/react-query.gen"; +import { CardList } from "../components/CardList"; +import { HeaderUI } from "../components/Header"; +import { FilterUI } from "../components/Filters"; +import { AnimatedBackground, AnimatedBackgroundContext } from "../components/AnimatedBackground"; +import { GameList } from "../components/GameList"; +import { SaveSource } from "../scripts/spatialNavigation"; +import LoadingCardList from "../components/LoadingCardList"; +import { AutoFocus } from "../components/AutoFocus"; +import SaveScroll from "../components/SaveScroll"; +import { ErrorBoundary } from "react-error-boundary"; +import { twMerge } from "tailwind-merge"; +import Shortcuts from "../components/Shortcuts"; + +export const Route = createFileRoute("/")({ + component: ConsoleHomeUI, + +}); + +const filters = { + consoles: { + label: "Consoles", + }, + games: { + label: "Games", + }, + collections: { + label: "Collections", + }, +}; + +function PlatformList (data: { id: string, setBackground: (url: string) => void; }) +{ + const navigate = useNavigate(); + const { data: platforms } = useSuspenseQuery({ + ...getPlatformsApiPlatformsGetOptions(), + refetchOnWindowFocus: false, + staleTime: DefaultRommStaleTime, + }); + + return ( + Date.parse(a.updated_at) - Date.parse(b.updated_at)) + .map((g) => ({ + id: g.id, + focusKey: g.slug, + title: g.display_name, + subtitle: g.family_name ?? "", + previewUrl: g.url_logo ?? "", + badge: ( + + {g.rom_count} + + ), + preview: ( +
    + +
    + ), + }))} + onSelectGame={(id) => + { + navigate({ to: `/platform/${id}`, viewTransition: { types: ['zoom-in'] } }); + }} + onGameFocus={(id) => + { + data.setBackground( + `https://picsum.photos/id/${10 + (id ?? 0)}/1920/1080.webp`, + ); + }} + /> + ); +} + +function CollectionList (data: { id: string, setBackground: (url: string) => void; }) +{ + const navigate = useNavigate(); + const { data: collections } = useSuspenseQuery({ + ...getCollectionsApiCollectionsGetOptions(), + refetchOnWindowFocus: false, + staleTime: DefaultRommStaleTime + }); + + return ( + Date.parse(a.updated_at) - Date.parse(b.updated_at)) + .map((g) => ({ + id: g.id, + title: g.name, + focusKey: `collection-${g.id}`, + subtitle: g.user__username, + previewUrl: `${RPC_URL(__HOST__)}/api/romm/${g.path_covers_large[0]}`, + badge: ( + + {g.rom_count} + + ), + }))} + onSelectGame={(id) => + { + navigate({ to: `/collection/${id}`, viewTransition: { types: ['zoom-in'] } }); + }} + onGameFocus={(id) => + { + data.setBackground( + `https://picsum.photos/id/${10 + (id ?? 0)}/1920/1080.webp`, + ); + }} + /> + ); +} + +function HomeList (data: { + selectedFilter: keyof typeof filters; +}) +{ + const bg = useContext(AnimatedBackgroundContext); + + const { ref, focused, focusKey, focusSelf } = useFocusable({ + focusKey: "home-list", + preferredChildFocusKey: `${data.selectedFilter}-list` + }); + + const lists = { + consoles: , + games: , + collections: , + }; + + return ( + +
    +
    + + + Error! Task failed successfully. +
    + }> + }> + {lists[data.selectedFilter]} + + + + +
    + +
    + ); +} + +export default function ConsoleHomeUI () +{ + const [selectedFilter, setSelectedFilter] = useLocalStorage< + keyof typeof filters + >("home-filter-selected", "games"); + + const { ref, focusKey, focusSelf } = useFocusable({ + forceFocus: true, + autoRestoreFocus: false, + saveLastFocusedChild: false, + focusKey: "Home", + preferredChildFocusKey: `home-list`, + }); + + return ( + + +
    + }, + { id: "power-button", icon: , external: true } + ]} /> +
    +
    + +
    + +
    +
    + +
    +
    + +
    +
    +
    + +
    +
    +
    + ); +} + +function MainMenu (data: {}) +{ + const { ref, focusKey, hasFocusedChild } = useFocusable({ + focusKey: `main-menu`, + trackChildren: true, + onBlur: (layout, props, details) => { }, + }); + const location = useLocation(); + const navigate = useNavigate(); + return ( +
      + + navigate({ to: "/" })} + icon={} + label="Home" + type="secondary" + /> + } label="News" /> + } label="Shop" /> + } label="Album" /> + } + label="Controllers" + /> + + { + SaveSource('settings', location.pathname); + navigate({ to: "/settings/accounts", viewTransition: { types: ['zoom-in'] } }); + }} + icon={} + label="Settings" + type="accent" + /> + +
    + ); +} + +function CircleIcon (data: { + action?: () => void; + type?: "secondary" | "accent"; + label?: string; + icon?: JSX.Element; +}) +{ + const { ref, focused } = useFocusable({ + focusKey: `navigation-icon-${data.label}`, + onEnterPress: data.action, + }); + const typeClasses = { + secondary: "bg-secondary text-secondary-content", + accent: "bg-accent text-accent-content", + none: "bg-base-content", + }; + return ( +
  • + {data.icon} +
  • + ); +} \ No newline at end of file diff --git a/src/mainview/routes/platform/$id.tsx b/src/mainview/routes/platform/$id.tsx new file mode 100644 index 0000000..3a8eff0 --- /dev/null +++ b/src/mainview/routes/platform/$id.tsx @@ -0,0 +1,62 @@ +import { createFileRoute, useNavigate } from "@tanstack/react-router"; +import +{ + getPlatformApiPlatformsIdGetOptions, + getRomsApiRomsGetOptions, +} from "../../../clients/romm/@tanstack/react-query.gen"; +import { useEventListener, useSessionStorage } from "usehooks-ts"; +import { CollectionsDetail } from "../../components/CollectionsDetail"; +import { useQuery, useSuspenseQuery } from "@tanstack/react-query"; +import { DefaultRommStaleTime, RPC_PORT, RPC_URL } from "../../../shared/constants"; +import { Suspense } from "react"; + +export const Route = createFileRoute("/platform/$id")({ + component: RouteComponent +}); + +function PlatformSlug () +{ + const { id } = Route.useParams(); + const { data: platform } = useSuspenseQuery({ ...getPlatformApiPlatformsIdGetOptions({ path: { id: Number(id) } }), staleTime: DefaultRommStaleTime }); + + return
    + + {platform.display_name} +
    ; +} + +function PlatformTitle () +{ + const { id } = Route.useParams(); + const { data: platform } = useSuspenseQuery({ ...getPlatformApiPlatformsIdGetOptions({ path: { id: Number(id) } }), staleTime: DefaultRommStaleTime }); + + return
    + +
    + + {platform.display_name} +
    +
    ; +} + +function RouteComponent () +{ + const { id } = Route.useParams(); + + const [, setBackground] = useSessionStorage( + "home-background", + undefined, + ); + const navigate = useNavigate(); + useEventListener("cancel", () => navigate({ to: "/", viewTransition: { types: ['zoom-out'] } })); + + return ( +
    + } + setBackground={setBackground} + filters={{ platformIds: [Number(id)] }} + /> +
    + ); +} diff --git a/src/mainview/routes/settings/accounts.tsx b/src/mainview/routes/settings/accounts.tsx new file mode 100644 index 0000000..ebb66a9 --- /dev/null +++ b/src/mainview/routes/settings/accounts.tsx @@ -0,0 +1,385 @@ +import +{ + FocusContext, + FocusDetails, + useFocusable, +} from "@noriginmedia/norigin-spatial-navigation"; +import { QueriesResults, useIsMutating, useMutation, useQuery, UseQueryResult } from "@tanstack/react-query"; +import { createFileRoute, useSearch } from "@tanstack/react-router"; +import classNames from "classnames"; +import { DoorOpen, Key, Link, Lock, User } from "lucide-react"; +import +{ + ChangeEventHandler, + createContext, + FocusEventHandler, + HTMLInputTypeAttribute, + JSX, + useCallback, + useContext, + useEffect, + useMemo, + useRef, + useState, +} from "react"; +import { client } from "../.."; +import { SettingsType } from "../../../shared/constants"; +import +{ + getCurrentUserApiUsersMeGetOptions, + loginApiLoginPostMutation, + logoutApiLogoutPostMutation, + statsApiStatsGetOptions, +} from "../../../clients/romm/@tanstack/react-query.gen"; +import { useToasters } from "../../contexts/ToasterContext"; +import { UserSchema } from "../../../clients/romm"; +import toast from "react-hot-toast"; +import { twMerge } from "tailwind-merge"; + +export const Route = createFileRoute("/settings/accounts")({ + component: RouteComponent, +}); + +const OptionContext = createContext( + {} as { + focused: boolean; + focus: (focusDetails?: FocusDetails | undefined) => void; + eventTarget: EventTarget; + }, +); + +function useOptionContext (params?: { onOptionEnterPress?: () => void; }) +{ + const context = useContext(OptionContext); + useEffect(() => + { + if (params?.onOptionEnterPress) + { + context.eventTarget.addEventListener( + "onEnterPress", + params.onOptionEnterPress, + ); + } + + return () => + { + if (params?.onOptionEnterPress) + { + context.eventTarget.removeEventListener( + "onEnterPress", + params.onOptionEnterPress, + ); + } + }; + }, [context.eventTarget]); + return context; +} + +function OptionSpace (data: { + id?: string; + className?: string; + focusable?: boolean; + children: JSX.Element; + label?: string | JSX.Element; +}) +{ + const eventTarget = useMemo(() => new EventTarget(), []); + const { ref, focused, focusSelf, focusKey, hasFocusedChild } = useFocusable({ + focusKey: data.id, + focusable: data.focusable !== false, + trackChildren: true, + onEnterPress () + { + eventTarget.dispatchEvent(new CustomEvent("onEnterPress")); + }, + }); + + return ( + +
  • + {typeof data.label === "string" ? ( + + ) : ( + data.label + )} + {data.children} +
  • +
    +
    + ); +} + +function OptionInput (data: { + name: string; + type: HTMLInputTypeAttribute; + className?: string; + placeholder?: string; + icon?: JSX.Element; + value?: string; + onBlur?: FocusEventHandler; + onChange?: ChangeEventHandler; +}) +{ + const inputRef = useRef(null); + const option = useOptionContext({ + onOptionEnterPress () + { + inputRef.current?.focus(); + }, + }); + + return ( + + ); +} + +type KeysWithValueAssignableTo = { + [K in keyof T]: Exclude extends Value ? K : never; +}[keyof T]; + +function Option (data: { + label: string; + id: KeysWithValueAssignableTo; + type: HTMLInputTypeAttribute; + placeholder?: string; + icon?: JSX.Element; +}) +{ + const [dirty, setDirty] = useState(false); + const [localValue, setLocalValue] = useState(); + useQuery({ + enabled: !!data.id, + queryKey: ["setting", data.id], + queryFn: async () => + { + const value = (await client.api.settings({ id: data.id! }).get()).data?.value; + if (!dirty) + { + setLocalValue(String(value)); + } + return value; + }, + }); + const setSettingMultation = useMutation({ + mutationKey: ["setting", data.id], + mutationFn: (value: any) => + client.api.settings({ id: data.id! }).post({ value }).then(d => d.status) + }); + + const handleSave = useCallback(() => + { + if (dirty) + { + setDirty(false); + setSettingMultation.mutate(localValue); + } + }, [dirty, setDirty, localValue]); + + return ( + + + { + setLocalValue(e.currentTarget.value); + setDirty(true); + }} + value={localValue} + /> + + ); +} + +function Button (data: { children?: any, disabled?: boolean, type: "reset" | "button" | "submit" | undefined; } & InteractParams & FocusParams) +{ + const { ref, focused } = useFocusable({ + focusKey: data.type, + onEnterPress: data.onAction, + onFocus: data.onFocus + }); + return ; +} + +function LoginControls (data: { user: UseQueryResult; }) +{ + const isMutatingRomm = useIsMutating({ mutationKey: ["romm", "auth"] }) > 0; + const logoutMutation = useMutation({ + mutationKey: ["romm", "auth", "logout"], mutationFn: () => window.cookieStore.delete({ name: "romm_session" }), + onSuccess: async (d, v, r, c) => + { + c.client.invalidateQueries({ queryKey: ["romm", "auth"] }); + } + }); + return
    + {data.user.isError &&
    +
    } + {data.user.isSuccess &&
    Logged In As: {data.user.data?.username}
    } + + +
    ; +} + +function RouteComponent () +{ + const { focus } = Route.useSearch(); + const { ref, focusKey, focusSelf } = useFocusable({ + preferredChildFocusKey: focus + }); + const rommOnline = useQuery({ + ...statsApiStatsGetOptions(), + refetchInterval: 30000, + retry: false, + }); + + const user = useQuery({ + ...getCurrentUserApiUsersMeGetOptions(), + queryKey: ['romm', 'auth', "login"], + refetchOnWindowFocus: false, + retry: 0 + }); + + useEffect(() => + { + if (focus) + { + focusSelf(); + } + }, [focus]); + + const loginMutation = useMutation({ + mutationKey: ["romm", "login"], + ...loginApiLoginPostMutation(), + onSuccess: (d, v, r, c) => + { + c.client.invalidateQueries({ queryKey: ['romm', 'auth'] }); + }, + onError: (e) => + { + console.error(e); + }, + }); + + let indicator = ""; + if (rommOnline.isError) + { + indicator = "status-error"; + } else if (rommOnline.isSuccess) + { + indicator = "status-success"; + } + + return ( + +
      +
      +
      +

      Romm

      +
      +
      +
    +
    + ); +} diff --git a/src/mainview/routes/settings/route.tsx b/src/mainview/routes/settings/route.tsx new file mode 100644 index 0000000..e38738f --- /dev/null +++ b/src/mainview/routes/settings/route.tsx @@ -0,0 +1,177 @@ +import +{ + FocusContext, + useFocusable, +} from "@noriginmedia/norigin-spatial-navigation"; +import +{ + Outlet, + Link, + createFileRoute, + useMatchRoute, + useNavigate, +} from "@tanstack/react-router"; +import { retainSearchParams, ViewTransitionOptions } from "@tanstack/router-core"; +import classNames from "classnames"; +import +{ + ArrowBigLeft, + FingerprintPattern, + Info, + MonitorCog, +} from "lucide-react"; +import { JSX, useEffect } from "react"; +import { useEventListener } from "usehooks-ts"; +import ShortcutPrompt from "../../components/ShortcutPrompt"; +import { twMerge } from "tailwind-merge"; +import z from "zod"; +import { SettingsSchema } from "../../../shared/constants"; +import { PopSource } from "../../scripts/spatialNavigation"; + +export const Route = createFileRoute("/settings")({ + component: SettingsUI, + validateSearch: z.object({ + focus: z.keyof(SettingsSchema).optional() + }) +}); + +function MenuItem (data: { + route: string; + return?: boolean; + viewTransition?: boolean | ViewTransitionOptions; + icon: JSX.Element; + focusSelect?: boolean; + className?: string; + linkClassName?: string; + label: string; +}) +{ + const matchRoute = useMatchRoute(); + const navigate = useNavigate(); + const acitve = matchRoute({ to: data.route }); + const handleNonFocusSelect = () => navigate({ to: data.return ? PopSource('settings') ?? data.route : data.route, viewTransition: data.viewTransition }); + const { ref, focusSelf, focused } = useFocusable({ + focusKey: data.route, + forceFocus: !!acitve, + onFocus: () => + { + if (data.focusSelect) + { + navigate({ to: data.route }); + } + (ref.current as HTMLElement).scrollIntoView({ inline: 'center' }); + }, + onEnterPress: + data.focusSelect !== true + ? handleNonFocusSelect + : undefined, + }); + return ( +
  • +
    +
    + {data.icon} + {data.label} +
    +
    +
  • + ); +} + +function SettingsMenu (data: {}) +{ + const { ref, focusKey } = useFocusable({ + focusable: true, + focusKey: 'settings-menu', + preferredChildFocusKey: "/settings/accounts" + }); + + return
      + + } + /> + } + /> + } + /> + } + /> + +
    ; +} + +export function SettingsUI () +{ + const navigate = useNavigate(); + const { ref, focusKey, focusSelf } = useFocusable({ + focusKey: "settings-page-layout", + preferredChildFocusKey: 'settings-menu' + }); + + useEventListener("cancel", () => navigate({ to: PopSource('settings') ?? "/", viewTransition: { types: ['zoom-out'] } })); + useEffect(() => + { + focusSelf(); + }, []); + + return ( + +
    +
    + +
    +
    + +
    +
    +
    + navigate({ to: "/" })} + icon="steamdeck_button_b" + label="Back" + /> +
    +
    +
    + ); +} diff --git a/src/mainview/scripts/gamepads.ts b/src/mainview/scripts/gamepads.ts new file mode 100644 index 0000000..9c3820e --- /dev/null +++ b/src/mainview/scripts/gamepads.ts @@ -0,0 +1,149 @@ +import { navigateByDirection } from "@noriginmedia/norigin-spatial-navigation"; + +let loopStarted = false; + +window.addEventListener("gamepadconnected", (evt) => { + if (!loopStarted) { + requestAnimationFrame(updateStatus); + loopStarted = true; + } +}); +window.addEventListener("gamepaddisconnected", (evt) => { + +}); + +const throttleMap = new Map(); +const throttleAcceleration = new Map(); +function throttleNav (key: string, dir: string, event: Event) +{ + const minSpeed = 150; + const maxSpeed = 300; + const currentDate = new Date(); + const lastTime = throttleMap.get(key); + const acceleration = throttleAcceleration.get(key) ?? 0; + const speed = Math.max(maxSpeed - (maxSpeed - minSpeed) * (acceleration / 6),minSpeed); + if ((currentDate.getTime() - (lastTime ?? 0) > speed)) + { + navigateByDirection(dir, { event }) + throttleMap.set(key, currentDate.getTime()); + throttleAcceleration.set(key, acceleration + 1); + } +} + +window.addEventListener('keydown', e => +{ + if (e.key === 'Escape') + { + window.dispatchEvent(new Event('cancel')); + } +}) + +function updateStatus () { + for (const gamepad of navigator.getGamepads().filter(g => !!g)) + { + const gamepadEvent = new GamepadEvent('gamepad-navigation', { gamepad, }); + + if (gamepad.buttons[0].pressed) + { + if (!throttleMap.has('enter')) + { + window.dispatchEvent(new KeyboardEvent('keydown',{key: 'Enter', code: 'Enter', charCode: 13, keyCode: 13, view: window, bubbles: true})); + throttleMap.set('enter', 0); + } + } else + { + if (throttleMap.delete('enter')) + { + window.dispatchEvent(new KeyboardEvent('keyup', {key: 'Enter'})); + } + } + + if (gamepad.buttons[1].pressed) + { + if (!throttleMap.has('cancel')) + { + window.dispatchEvent(new Event('cancel')); + throttleMap.set('cancel', 0); + } + } else + { + throttleMap.delete('cancel'); + } + + if (gamepad.buttons[12].pressed) + { + throttleNav('gp-up', "up", gamepadEvent); + } else + { + throttleAcceleration.delete('gp-up'); + throttleMap.delete('gp-up'); + } + if (gamepad.buttons[13].pressed) + { + throttleNav('gp-down', "down", gamepadEvent); + } else + { + throttleAcceleration.delete('gp-down'); + throttleMap.delete('gp-down'); + } + if (gamepad.buttons[14].pressed) + { + throttleNav('gp-left', "left", gamepadEvent); + } else + { + throttleAcceleration.delete('gp-left'); + throttleMap.delete('gp-left'); + } + if (gamepad.buttons[15].pressed) + { + throttleNav('gp-right', "right", gamepadEvent); + } else + { + throttleAcceleration.delete('gp-right'); + throttleMap.delete('gp-right'); + } + + const deadzone = 0.5; + const cancelDeadzone = 0.3; + + function AxisControls () + { + if (gamepad.axes[0] > deadzone) + { + throttleNav('gpa-right', "right", gamepadEvent); + return; + } + else if (gamepad.axes[0] < -deadzone) + { + throttleNav('gpa-left', "left", gamepadEvent); + return; + } + else if ((throttleMap.has('gpa-left') || throttleMap.has('gpa-left')) && gamepad.axes[0] < cancelDeadzone && gamepad.axes[0] > -cancelDeadzone) + { + throttleAcceleration.delete('gpa-right'); + throttleAcceleration.delete('gpa-left'); + throttleMap.delete('gpa-left'); + throttleMap.delete('gpa-left'); + } + + if (gamepad.axes[1] > deadzone) + { + throttleNav('gpa-down', "down", gamepadEvent); + } + else if (gamepad.axes[1] < -deadzone) + { + throttleNav('gpa-up', "up", gamepadEvent); + } else + { + throttleAcceleration.delete('gpa-up'); + throttleAcceleration.delete('gpa-down'); + throttleMap.delete('gpa-up'); + throttleMap.delete('gpa-down'); + } + } + + AxisControls(); + } + + requestAnimationFrame(updateStatus); +} \ No newline at end of file diff --git a/src/mainview/scripts/spatialNavigation.ts b/src/mainview/scripts/spatialNavigation.ts new file mode 100644 index 0000000..b79b98f --- /dev/null +++ b/src/mainview/scripts/spatialNavigation.ts @@ -0,0 +1,117 @@ +import +{ + init, + SpatialNavigation, +} from "@noriginmedia/norigin-spatial-navigation"; + +init({ + shouldFocusDOMNode: false, + throttle: 200, +}); + +let addFocusable = SpatialNavigation.addFocusable.bind(SpatialNavigation); +let removeFocusable = SpatialNavigation.removeFocusable.bind(SpatialNavigation); + +type SaveFocusType = "session" | "local"; + +type HistorySourceType = "settings" | 'details'; +const historySourceMap = new Map(); + +export function SaveSource (id: HistorySourceType, url: string) +{ + historySourceMap.set(id, url); +} + +export function HasSource (id: HistorySourceType) +{ + return historySourceMap.has(id); +} + +export function PopSource (id: HistorySourceType) +{ + const source = historySourceMap.get(id); + historySourceMap.delete(id); + return source; +} + +SpatialNavigation.addFocusable = (toAdd) => +{ + addFocusable(toAdd); + const component: { + lastFocusedChildKey?: string; + preferredChildFocusKey?: string; + node: HTMLElement; + focusKey: string; + } = (SpatialNavigation as any).focusableComponents[toAdd.focusKey]; + if (component.node?.hasAttribute("save-child-focus")) + { + const storageKey = `${component.focusKey}-last-child-focus`; + const saveChildFocus = component.node.getAttribute( + "save-child-focus", + ) as SaveFocusType; + + if (saveChildFocus === "session" && sessionStorage.getItem(storageKey)) + { + SpatialNavigation.saveLastFocusedChildKey( + component as any, + sessionStorage.getItem(storageKey)!, + ); + + } else if (saveChildFocus === "local" && localStorage.getItem(storageKey)) + { + SpatialNavigation.saveLastFocusedChildKey( + component as any, + localStorage.getItem(storageKey)!, + ); + } + } +}; + +// Override remove callback to insert custom functionality like saving to storage +SpatialNavigation.removeFocusable = ({ focusKey }) => +{ + const component: { + lastFocusedChildKey?: string; + node: HTMLElement; + focusKey: string; + } = (SpatialNavigation as any).focusableComponents[focusKey]; + + if (component) + { + if (component.node?.hasAttribute("save-child-focus")) + { + const saveChildFocus = component.node.getAttribute( + "save-child-focus", + ) as SaveFocusType; + const storageKey = `${component.focusKey}-last-child-focus`; + if (saveChildFocus === "session") + { + if (component.lastFocusedChildKey) + { + sessionStorage.setItem(storageKey, component.lastFocusedChildKey); + } else + { + //sessionStorage.removeItem(storageKey); + } + } else if (saveChildFocus === "local") + { + if (component.lastFocusedChildKey) + { + localStorage.setItem(storageKey, component.lastFocusedChildKey); + } else + { + //localStorage.removeItem(storageKey); + } + } + } + + removeFocusable(component); + } + + +}; + +SpatialNavigation.saveLastFocusedChildKey = (component, focusKey) => +{ + component.lastFocusedChildKey = focusKey; +}; diff --git a/src/mainview/scripts/utils.ts b/src/mainview/scripts/utils.ts new file mode 100644 index 0000000..2075eb7 --- /dev/null +++ b/src/mainview/scripts/utils.ts @@ -0,0 +1,58 @@ +import { doesFocusableExist, getCurrentFocusKey } from "@noriginmedia/norigin-spatial-navigation"; +import { RefObject, useEffect } from "react"; + +export function selfFocusSmart (shouldFocus: boolean, focusSelf: () => void) +{ + if (shouldFocus && (!getCurrentFocusKey() || !doesFocusableExist(getCurrentFocusKey()))) + { + console.log("Self Focus"); + focusSelf(); + } +} + +export type ScrollSaveParams = { + id: string; + ref: RefObject; + storage?: "session" | "local"; + shouldSave?: boolean; +}; +export function useScrollSave (data: ScrollSaveParams) +{ + useEffect(() => + { + const storage = data.storage === "local" ? localStorage : sessionStorage; + const key = `scroll-${data.id}`; + const element = data.ref.current; + if (element) + { + if (storage.getItem(key)) + { + const scrollData = JSON.parse(storage.getItem(key)!); + element.scrollLeft = scrollData.x; + element.scrollTop = scrollData.y; + } + } + + function scrollHandler (e: Event) + { + if (!data.shouldSave || data.shouldSave === true) + { + const currentTarget = e.currentTarget as HTMLElement; + storage.setItem( + key, + JSON.stringify({ + x: currentTarget.scrollLeft, + y: currentTarget.scrollTop, + }), + ); + } + + } + + element?.addEventListener("scrollend", scrollHandler); + + return () => element?.removeEventListener("scrollend", scrollHandler); + }, [data.id, data.ref.current, data.storage]); + + return { ref: data.ref }; +} diff --git a/src/mainview/scripts/windowEvents.ts b/src/mainview/scripts/windowEvents.ts new file mode 100644 index 0000000..1e69486 --- /dev/null +++ b/src/mainview/scripts/windowEvents.ts @@ -0,0 +1,19 @@ +import { client } from "../index"; + +window.addEventListener("resize", () => +{ + client.api.settings({ id: 'windowSize' }).post({ value: { width: window.innerWidth, height: window.innerHeight } }); +}); + +let lastWindowPosX: number = window.screenX; +let lastWindowPosY: number = window.screenY; +var screenPositionInternal: NodeJS.Timeout = setInterval(() => +{ + if (lastWindowPosX != window.screenX || lastWindowPosY != window.screenY) + { + client.api.settings({ id: 'windowPosition' }).post({ value: { x: window.screenX, y: window.screenY } }); + } + + lastWindowPosX = window.screenX; + lastWindowPosY = window.screenY; +}, 1000); \ No newline at end of file diff --git a/src/mainview/types.d.ts b/src/mainview/types.d.ts new file mode 100644 index 0000000..93275b9 --- /dev/null +++ b/src/mainview/types.d.ts @@ -0,0 +1,28 @@ +declare const __HOST__: string; + +global +{ + declare module "react" { + interface HTMLAttributes extends AriaAttributes, DOMAttributes + { + // extends React's HTMLAttributes + "save-child-focus"?: SaveFocusType; + "save-scroll"?: boolean; + } + } +} + +interface FocusParams +{ + onFocus?: () => void; +} + +interface InteractParams +{ + onAction?: () => void; +} + +interface FilterOption extends FocusParams, InteractParams +{ + label: string; +} diff --git a/src/shared/constants.ts b/src/shared/constants.ts new file mode 100644 index 0000000..8411b57 --- /dev/null +++ b/src/shared/constants.ts @@ -0,0 +1,28 @@ + +import * as z from 'zod'; + +export const SERVER_PORT = 5173; +export const SERVER_URL = (host: string) => `http://${host}:${SERVER_PORT}`; +export const WINDOW_PORT = 4656; +export const RPC_PORT = 8787; +export const RPC_URL = (host: string) => `http://${host}:${RPC_PORT}`; +export const SOCKETS_URL = (host: string) => `ws://${host}:${RPC_PORT}`; + +export const DefaultRommStaleTime = 60 * 1000; // A minute +export const GameMetaSchema = z.object({ + id: z.number(), + title: z.string(), + subtitle: z.string(), + previewUrl: z.url().optional() +}); + +export type GameMeta = z.infer; + +export const SettingsSchema = z.object({ + rommAddress: z.url().optional(), + disableBlur: z.boolean().default(false), + windowSize: z.object({ width: z.number(), height: z.number() }).default({ width: 1280, height: 800 }), + windowPosition: z.object({ x: z.number(), y: z.number() }).optional(), +}); + +export type SettingsType = z.infer; \ No newline at end of file diff --git a/tailwind.config.js b/tailwind.config.js index 4e4372b..186a367 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -1,5 +1,5 @@ /** @type {import('tailwindcss').Config} */ export default { content: ["./src/mainview/**/*.{html,js,ts,jsx,tsx}"], - plugins: [], + plugins: ["tailwindcss-animate"], } \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json index b38f88e..432273f 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -16,5 +16,5 @@ "noUnusedParameters": true, "noFallthroughCasesInSwitch": true }, - "include": ["src", "vite.config.ts"] + "include": ["src", "vite.config.ts", "vite-env-override.d.ts"] } \ No newline at end of file diff --git a/vite-env-override.d.ts b/vite-env-override.d.ts new file mode 100644 index 0000000..e77ef3b --- /dev/null +++ b/vite-env-override.d.ts @@ -0,0 +1,3 @@ +/// +/// +/// \ No newline at end of file diff --git a/vite.config.ts b/vite.config.ts index 1dbe011..992af76 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -1,26 +1,79 @@ import { defineConfig } from "vite"; import react from "@vitejs/plugin-react"; -import tailwindcss from '@tailwindcss/vite' -import { tanstackRouter } from '@tanstack/router-plugin/vite' +import tailwindcss from '@tailwindcss/vite'; +import { tanstackRouter } from '@tanstack/router-plugin/vite'; +import { createSvgIconsPlugin } from 'vite-plugin-svg-icons-ng'; +import path from "node:path"; +import staticAssetsPlugin from 'vite-static-assets-plugin'; +import { host } from "./src/bun/utils"; -export default defineConfig({ - plugins: [ - tailwindcss(), - tanstackRouter({ - target: 'react', - routesDirectory: "./routes/", - generatedRouteTree: "./routeTree.gen.ts", - autoCodeSplitting: true, - }), - react(), - ], - root: "src/mainview", - build: { - outDir: "../../dist", - emptyOutDir: true, - }, - server: { - port: 5173, - strictPort: true, - }, +export default defineConfig(() => +{ + const production = process.env.NODE_ENV === 'production'; + console.log(`Building Vite in ${process.env.NODE_ENV}`); + + return { + base: './', + plugins: [ + staticAssetsPlugin({ + directory: 'src/mainview/assets/icons', + outputFile: 'src/mainview/gen/static-icon-assets.gen.ts' + }), + tailwindcss(), + tanstackRouter({ + target: 'react', + routesDirectory: "./routes/", + generatedRouteTree: "./gen/routeTree.gen.ts", + autoCodeSplitting: true, + routeFileIgnorePrefix: "-", + quoteStyle: "single" + }), + react({ + babel: { + plugins: ['babel-plugin-react-compiler'], + }, + }), + createSvgIconsPlugin({ + // Specify the icon folder to be cached + iconDirs: [path.resolve(process.cwd(), 'src/mainview/assets/icons')], + }) + ], + root: "src/mainview", + build: { + outDir: "../../dist", + minify: production, + sourcemap: production ? false : 'inline', + rollupOptions: { + output: { + manualChunks: (id + ) => + { + if (id + .includes + ('node_modules')) + { + return 'vendor'; + } + + if (id.endsWith('SvgIcon.tsx')) + { + return 'icons'; + } + + return null; + }, + } + }, + emptyOutDir: true, + }, + server: { + port: 5173, + strictPort: true, + allowedHosts: true, + host, + }, + define: { + __HOST__: JSON.stringify(host) + } + }; }); \ No newline at end of file