diff --git a/package-lock.json b/package-lock.json index 8a6318d..4cf7476 100644 --- a/package-lock.json +++ b/package-lock.json @@ -23,7 +23,8 @@ "@types/react-router-dom": "^5.3.3", "@vitejs/plugin-react": "^4.2.1", "typescript": "^5.3.3", - "vite": "^5.0.0" + "vite": "^5.0.0", + "wrangler": "^4.63.0" } }, "node_modules/@babel/code-frame": { @@ -57,6 +58,7 @@ "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@babel/code-frame": "^7.29.0", "@babel/generator": "^7.29.0", @@ -317,6 +319,152 @@ "node": ">=6.9.0" } }, + "node_modules/@cloudflare/kv-asset-handler": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@cloudflare/kv-asset-handler/-/kv-asset-handler-0.4.2.tgz", + "integrity": "sha512-SIOD2DxrRRwQ+jgzlXCqoEFiKOFqaPjhnNTGKXSRLvp1HiOvapLaFG2kEr9dYQTYe8rKrd9uvDUzmAITeNyaHQ==", + "dev": true, + "license": "MIT OR Apache-2.0", + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@cloudflare/unenv-preset": { + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/@cloudflare/unenv-preset/-/unenv-preset-2.12.0.tgz", + "integrity": "sha512-NK4vN+2Z/GbfGS4BamtbbVk1rcu5RmqaYGiyHJQrA09AoxdZPHDF3W/EhgI0YSK8p3vRo/VNCtbSJFPON7FWMQ==", + "dev": true, + "license": "MIT OR Apache-2.0", + "peerDependencies": { + "unenv": "2.0.0-rc.24", + "workerd": "^1.20260115.0" + }, + "peerDependenciesMeta": { + "workerd": { + "optional": true + } + } + }, + "node_modules/@cloudflare/workerd-darwin-64": { + "version": "1.20260205.0", + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-64/-/workerd-darwin-64-1.20260205.0.tgz", + "integrity": "sha512-ToOItqcirmWPwR+PtT+Q4bdjTn/63ZxhJKEfW4FNn7FxMTS1Tw5dml0T0mieOZbCpcvY8BdvPKFCSlJuI8IVHQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=16" + } + }, + "node_modules/@cloudflare/workerd-darwin-arm64": { + "version": "1.20260205.0", + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-arm64/-/workerd-darwin-arm64-1.20260205.0.tgz", + "integrity": "sha512-402ZqLz+LrG0NDXp7Hn7IZbI0DyhjNfjAlVenb0K3yod9KCuux0u3NksNBvqJx0mIGHvVR4K05h+jfT5BTHqGA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=16" + } + }, + "node_modules/@cloudflare/workerd-linux-64": { + "version": "1.20260205.0", + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-64/-/workerd-linux-64-1.20260205.0.tgz", + "integrity": "sha512-rz9jBzazIA18RHY+osa19hvsPfr0LZI1AJzIjC6UqkKKphcTpHBEQ25Xt8cIA34ivMIqeENpYnnmpDFesLkfcQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=16" + } + }, + "node_modules/@cloudflare/workerd-linux-arm64": { + "version": "1.20260205.0", + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-arm64/-/workerd-linux-arm64-1.20260205.0.tgz", + "integrity": "sha512-jr6cKpMM/DBEbL+ATJ9rYue758CKp0SfA/nXt5vR32iINVJrb396ye9iat2y9Moa/PgPKnTrFgmT6urUmG3IUg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=16" + } + }, + "node_modules/@cloudflare/workerd-windows-64": { + "version": "1.20260205.0", + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-windows-64/-/workerd-windows-64-1.20260205.0.tgz", + "integrity": "sha512-SMPW5jCZYOG7XFIglSlsgN8ivcl0pCrSAYxCwxtWvZ88whhcDB/aISNtiQiDZujPH8tIo2hE5dEkxW7tGEwc3A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=16" + } + }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "node_modules/@emnapi/runtime": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.8.1.tgz", + "integrity": "sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, "node_modules/@esbuild/aix-ppc64": { "version": "0.21.5", "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", @@ -606,6 +754,23 @@ "node": ">=12" } }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.0.tgz", + "integrity": "sha512-6m0sfQfxfQfy1qRuecMkJlf1cIzTOgyaeXaiVaaki8/v+WB+U4hc6ik15ZW6TAllRlg/WuQXxWj1jx6C+dfy3w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, "node_modules/@esbuild/netbsd-x64": { "version": "0.21.5", "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", @@ -623,6 +788,23 @@ "node": ">=12" } }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.0.tgz", + "integrity": "sha512-fWgqR8uNbCQ/GGv0yhzttj6sU/9Z5/Sv/VGU3F5OuXK6J6SlriONKrQ7tNlwBrJZXRYk5jUhuWvF7GYzGguBZQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, "node_modules/@esbuild/openbsd-x64": { "version": "0.21.5", "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", @@ -640,6 +822,23 @@ "node": ">=12" } }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.0.tgz", + "integrity": "sha512-nyvsBccxNAsNYz2jVFYwEGuRRomqZ149A39SHWk4hV0jWxKM0hjBPm3AmdxcbHiFLbBSwG6SbpIcUbXjgyECfA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, "node_modules/@esbuild/sunos-x64": { "version": "0.21.5", "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", @@ -708,6 +907,496 @@ "node": ">=12" } }, + "node_modules/@img/colour": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@img/colour/-/colour-1.0.0.tgz", + "integrity": "sha512-A5P/LfWGFSl6nsckYtjw9da+19jB8hkJ6ACTGcDfEJ0aE+l2n2El7dsVM7UVHZQ9s2lmYMWlrS21YLy2IR1LUw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/@img/sharp-darwin-arm64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.34.5.tgz", + "integrity": "sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-arm64": "1.2.4" + } + }, + "node_modules/@img/sharp-darwin-x64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.34.5.tgz", + "integrity": "sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-x64": "1.2.4" + } + }, + "node_modules/@img/sharp-libvips-darwin-arm64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.2.4.tgz", + "integrity": "sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-darwin-x64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.2.4.tgz", + "integrity": "sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-arm": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.2.4.tgz", + "integrity": "sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-arm64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.2.4.tgz", + "integrity": "sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-ppc64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.2.4.tgz", + "integrity": "sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-riscv64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-riscv64/-/sharp-libvips-linux-riscv64-1.2.4.tgz", + "integrity": "sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-s390x": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.2.4.tgz", + "integrity": "sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-x64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.2.4.tgz", + "integrity": "sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-arm64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.2.4.tgz", + "integrity": "sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-x64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.2.4.tgz", + "integrity": "sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-linux-arm": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.34.5.tgz", + "integrity": "sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-arm64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.34.5.tgz", + "integrity": "sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm64": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-ppc64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.34.5.tgz", + "integrity": "sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-ppc64": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-riscv64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-riscv64/-/sharp-linux-riscv64-0.34.5.tgz", + "integrity": "sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-riscv64": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-s390x": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.34.5.tgz", + "integrity": "sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-s390x": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-x64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.34.5.tgz", + "integrity": "sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-x64": "1.2.4" + } + }, + "node_modules/@img/sharp-linuxmusl-arm64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.34.5.tgz", + "integrity": "sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-arm64": "1.2.4" + } + }, + "node_modules/@img/sharp-linuxmusl-x64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.34.5.tgz", + "integrity": "sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-x64": "1.2.4" + } + }, + "node_modules/@img/sharp-wasm32": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.34.5.tgz", + "integrity": "sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==", + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT", + "optional": true, + "dependencies": { + "@emnapi/runtime": "^1.7.0" + }, + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-arm64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.34.5.tgz", + "integrity": "sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-ia32": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.34.5.tgz", + "integrity": "sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-x64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.34.5.tgz", + "integrity": "sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, "node_modules/@ionic/core": { "version": "8.7.17", "resolved": "https://registry.npmjs.org/@ionic/core/-/core-8.7.17.tgz", @@ -821,6 +1510,35 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "node_modules/@poppinss/colors": { + "version": "4.1.6", + "resolved": "https://registry.npmjs.org/@poppinss/colors/-/colors-4.1.6.tgz", + "integrity": "sha512-H9xkIdFswbS8n1d6vmRd8+c10t2Qe+rZITbbDHHkQixH5+2x1FDGmi/0K+WgWiqQFKPSlIYB7jlH6Kpfn6Fleg==", + "dev": true, + "license": "MIT", + "dependencies": { + "kleur": "^4.1.5" + } + }, + "node_modules/@poppinss/dumper": { + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/@poppinss/dumper/-/dumper-0.6.5.tgz", + "integrity": "sha512-NBdYIb90J7LfOI32dOewKI1r7wnkiH6m920puQ3qHUeZkxNkQiFnXVWoE6YtFSv6QOiPPf7ys6i+HWWecDz7sw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@poppinss/colors": "^4.1.5", + "@sindresorhus/is": "^7.0.2", + "supports-color": "^10.0.0" + } + }, + "node_modules/@poppinss/exception": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@poppinss/exception/-/exception-1.2.3.tgz", + "integrity": "sha512-dCED+QRChTVatE9ibtoaxc+WkdzOSjYTKi/+uacHWIsfodVfpsueo3+DKpgU5Px8qXjgmXkSvhXvSCz3fnP9lw==", + "dev": true, + "license": "MIT" + }, "node_modules/@rolldown/pluginutils": { "version": "1.0.0-beta.27", "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.27.tgz", @@ -1170,6 +1888,26 @@ "win32" ] }, + "node_modules/@sindresorhus/is": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-7.2.0.tgz", + "integrity": "sha512-P1Cz1dWaFfR4IR+U13mqqiGsLFf1KbayybWwdd2vfctdV6hDpUkgCY0nKOLLTMSoRd/jJNjtbqzf13K8DCCXQw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sindresorhus/is?sponsor=1" + } + }, + "node_modules/@speed-highlight/core": { + "version": "1.2.14", + "resolved": "https://registry.npmjs.org/@speed-highlight/core/-/core-1.2.14.tgz", + "integrity": "sha512-G4ewlBNhUtlLvrJTb88d2mdy2KRijzs4UhnlrOSRT4bmjh/IqNElZa3zkrZ+TC47TwtlDWzVLFADljF1Ijp5hA==", + "dev": true, + "license": "CC0-1.0" + }, "node_modules/@stencil/core": { "version": "4.38.0", "resolved": "https://registry.npmjs.org/@stencil/core/-/core-4.38.0.tgz", @@ -1265,6 +2003,7 @@ "integrity": "sha512-cisd7gxkzjBKU2GgdYrTdtQx1SORymWyaAFhaxQPK9bYO9ot3Y5OikQRvY0VYQtvwjeQnizCINJAenh/V7MK2w==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@types/prop-types": "*", "csstype": "^3.2.2" @@ -1334,6 +2073,13 @@ "baseline-browser-mapping": "dist/cli.js" } }, + "node_modules/blake3-wasm": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/blake3-wasm/-/blake3-wasm-2.1.5.tgz", + "integrity": "sha512-F1+K8EbfOZE49dtoPtmxUQrpXaBIl3ICvasLh+nJta0xkz+9kF/7uet9fLnwKqhDrmj6g+6K3Tw9yQPUg2ka5g==", + "dev": true, + "license": "MIT" + }, "node_modules/browserslist": { "version": "4.28.1", "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz", @@ -1354,6 +2100,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "baseline-browser-mapping": "^2.9.0", "caniuse-lite": "^1.0.30001759", @@ -1396,6 +2143,20 @@ "dev": true, "license": "MIT" }, + "node_modules/cookie": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.1.1.tgz", + "integrity": "sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, "node_modules/csstype": { "version": "3.2.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", @@ -1421,6 +2182,16 @@ } } }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, "node_modules/electron-to-chromium": { "version": "1.5.286", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.286.tgz", @@ -1428,6 +2199,16 @@ "dev": true, "license": "ISC" }, + "node_modules/error-stack-parser-es": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/error-stack-parser-es/-/error-stack-parser-es-1.0.5.tgz", + "integrity": "sha512-5qucVt2XcuGMcEGgWI7i+yZpmpByQ8J1lHhcL7PwqCwu9FPP3VUXzT4ltHe5i2z9dePwEHcDVOAfSnHsOlCXRA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, "node_modules/esbuild": { "version": "0.21.5", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", @@ -1572,6 +2353,16 @@ "node": ">=6" } }, + "node_modules/kleur": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", + "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/loose-envify": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", @@ -1594,6 +2385,27 @@ "yallist": "^3.0.2" } }, + "node_modules/miniflare": { + "version": "4.20260205.0", + "resolved": "https://registry.npmjs.org/miniflare/-/miniflare-4.20260205.0.tgz", + "integrity": "sha512-jG1TknEDeFqcq/z5gsOm1rKeg4cNG7ruWxEuiPxl3pnQumavxo8kFpeQC6XKVpAhh2PI9ODGyIYlgd77sTHl5g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@cspotcode/source-map-support": "0.8.1", + "sharp": "^0.34.5", + "undici": "7.18.2", + "workerd": "1.20260205.0", + "ws": "8.18.0", + "youch": "4.1.0-beta.10" + }, + "bin": { + "miniflare": "bootstrap.js" + }, + "engines": { + "node": ">=18.0.0" + } + }, "node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", @@ -1645,6 +2457,13 @@ "isarray": "0.0.1" } }, + "node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "dev": true, + "license": "MIT" + }, "node_modules/picocolors": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", @@ -1697,6 +2516,7 @@ "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", "license": "MIT", + "peer": true, "dependencies": { "loose-envify": "^1.1.0" }, @@ -1709,6 +2529,7 @@ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", "license": "MIT", + "peer": true, "dependencies": { "loose-envify": "^1.1.0", "scheduler": "^0.23.2" @@ -1738,6 +2559,7 @@ "resolved": "https://registry.npmjs.org/react-router/-/react-router-5.3.4.tgz", "integrity": "sha512-Ys9K+ppnJah3QuaRiLxk+jDWOR1MekYQrlytiXxC1RyfbdsZkS5pvKAzCCr031xHixZwpnsYNT5xysdFHQaYsA==", "license": "MIT", + "peer": true, "dependencies": { "@babel/runtime": "^7.12.13", "history": "^4.9.0", @@ -1758,6 +2580,7 @@ "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-5.3.4.tgz", "integrity": "sha512-m4EqFMHv/Ih4kpcBCONHbkT68KoAeHN4p3lAGoNryfHi0dMy0kCzEZakiKRsvg5wHZ/JLrLW8o8KomWiz/qbYQ==", "license": "MIT", + "peer": true, "dependencies": { "@babel/runtime": "^7.12.13", "history": "^4.9.0", @@ -1953,6 +2776,64 @@ "semver": "bin/semver.js" } }, + "node_modules/sharp": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.34.5.tgz", + "integrity": "sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==", + "dev": true, + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "@img/colour": "^1.0.0", + "detect-libc": "^2.1.2", + "semver": "^7.7.3" + }, + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-darwin-arm64": "0.34.5", + "@img/sharp-darwin-x64": "0.34.5", + "@img/sharp-libvips-darwin-arm64": "1.2.4", + "@img/sharp-libvips-darwin-x64": "1.2.4", + "@img/sharp-libvips-linux-arm": "1.2.4", + "@img/sharp-libvips-linux-arm64": "1.2.4", + "@img/sharp-libvips-linux-ppc64": "1.2.4", + "@img/sharp-libvips-linux-riscv64": "1.2.4", + "@img/sharp-libvips-linux-s390x": "1.2.4", + "@img/sharp-libvips-linux-x64": "1.2.4", + "@img/sharp-libvips-linuxmusl-arm64": "1.2.4", + "@img/sharp-libvips-linuxmusl-x64": "1.2.4", + "@img/sharp-linux-arm": "0.34.5", + "@img/sharp-linux-arm64": "0.34.5", + "@img/sharp-linux-ppc64": "0.34.5", + "@img/sharp-linux-riscv64": "0.34.5", + "@img/sharp-linux-s390x": "0.34.5", + "@img/sharp-linux-x64": "0.34.5", + "@img/sharp-linuxmusl-arm64": "0.34.5", + "@img/sharp-linuxmusl-x64": "0.34.5", + "@img/sharp-wasm32": "0.34.5", + "@img/sharp-win32-arm64": "0.34.5", + "@img/sharp-win32-ia32": "0.34.5", + "@img/sharp-win32-x64": "0.34.5" + } + }, + "node_modules/sharp/node_modules/semver": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/source-map-js": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", @@ -1963,6 +2844,19 @@ "node": ">=0.10.0" } }, + "node_modules/supports-color": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-10.2.2.tgz", + "integrity": "sha512-SS+jx45GF1QjgEXQx4NJZV9ImqmO2NPz5FNsIHrsDjh2YsHnawpan7SNQ1o8NuhrbHZy9AZhIoCUiCeaW/C80g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, "node_modules/tiny-invariant": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.3.tgz", @@ -1995,6 +2889,27 @@ "node": ">=14.17" } }, + "node_modules/undici": { + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/undici/-/undici-7.18.2.tgz", + "integrity": "sha512-y+8YjDFzWdQlSE9N5nzKMT3g4a5UBX1HKowfdXh0uvAnTaqqwqB92Jt4UXBAeKekDs5IaDKyJFR4X1gYVCgXcw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20.18.1" + } + }, + "node_modules/unenv": { + "version": "2.0.0-rc.24", + "resolved": "https://registry.npmjs.org/unenv/-/unenv-2.0.0-rc.24.tgz", + "integrity": "sha512-i7qRCmY42zmCwnYlh9H2SvLEypEFGye5iRmEMKjcGi7zk9UquigRjFtTLz0TYqr0ZGLZhaMHl/foy1bZR+Cwlw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "pathe": "^2.0.3" + } + }, "node_modules/update-browserslist-db": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", @@ -2038,6 +2953,7 @@ "integrity": "sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "esbuild": "^0.21.3", "postcss": "^8.4.43", @@ -2092,12 +3008,556 @@ } } }, + "node_modules/workerd": { + "version": "1.20260205.0", + "resolved": "https://registry.npmjs.org/workerd/-/workerd-1.20260205.0.tgz", + "integrity": "sha512-CcMH5clHwrH8VlY7yWS9C/G/C8g9czIz1yU3akMSP9Z3CkEMFSoC3GGdj5G7Alw/PHEeez1+1IrlYger4pwu+w==", + "dev": true, + "hasInstallScript": true, + "license": "Apache-2.0", + "peer": true, + "bin": { + "workerd": "bin/workerd" + }, + "engines": { + "node": ">=16" + }, + "optionalDependencies": { + "@cloudflare/workerd-darwin-64": "1.20260205.0", + "@cloudflare/workerd-darwin-arm64": "1.20260205.0", + "@cloudflare/workerd-linux-64": "1.20260205.0", + "@cloudflare/workerd-linux-arm64": "1.20260205.0", + "@cloudflare/workerd-windows-64": "1.20260205.0" + } + }, + "node_modules/wrangler": { + "version": "4.63.0", + "resolved": "https://registry.npmjs.org/wrangler/-/wrangler-4.63.0.tgz", + "integrity": "sha512-+R04jF7Eb8K3KRMSgoXpcIdLb8GC62eoSGusYh1pyrSMm/10E0hbKkd7phMJO4HxXc6R7mOHC5SSoX9eof30Uw==", + "dev": true, + "license": "MIT OR Apache-2.0", + "dependencies": { + "@cloudflare/kv-asset-handler": "0.4.2", + "@cloudflare/unenv-preset": "2.12.0", + "blake3-wasm": "2.1.5", + "esbuild": "0.27.0", + "miniflare": "4.20260205.0", + "path-to-regexp": "6.3.0", + "unenv": "2.0.0-rc.24", + "workerd": "1.20260205.0" + }, + "bin": { + "wrangler": "bin/wrangler.js", + "wrangler2": "bin/wrangler.js" + }, + "engines": { + "node": ">=20.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + }, + "peerDependencies": { + "@cloudflare/workers-types": "^4.20260205.0" + }, + "peerDependenciesMeta": { + "@cloudflare/workers-types": { + "optional": true + } + } + }, + "node_modules/wrangler/node_modules/@esbuild/aix-ppc64": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.0.tgz", + "integrity": "sha512-KuZrd2hRjz01y5JK9mEBSD3Vj3mbCvemhT466rSuJYeE/hjuBrHfjjcjMdTm/sz7au+++sdbJZJmuBwQLuw68A==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/wrangler/node_modules/@esbuild/android-arm": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.0.tgz", + "integrity": "sha512-j67aezrPNYWJEOHUNLPj9maeJte7uSMM6gMoxfPC9hOg8N02JuQi/T7ewumf4tNvJadFkvLZMlAq73b9uwdMyQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/wrangler/node_modules/@esbuild/android-arm64": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.0.tgz", + "integrity": "sha512-CC3vt4+1xZrs97/PKDkl0yN7w8edvU2vZvAFGD16n9F0Cvniy5qvzRXjfO1l94efczkkQE6g1x0i73Qf5uthOQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/wrangler/node_modules/@esbuild/android-x64": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.0.tgz", + "integrity": "sha512-wurMkF1nmQajBO1+0CJmcN17U4BP6GqNSROP8t0X/Jiw2ltYGLHpEksp9MpoBqkrFR3kv2/te6Sha26k3+yZ9Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/wrangler/node_modules/@esbuild/darwin-arm64": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.0.tgz", + "integrity": "sha512-uJOQKYCcHhg07DL7i8MzjvS2LaP7W7Pn/7uA0B5S1EnqAirJtbyw4yC5jQ5qcFjHK9l6o/MX9QisBg12kNkdHg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/wrangler/node_modules/@esbuild/darwin-x64": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.0.tgz", + "integrity": "sha512-8mG6arH3yB/4ZXiEnXof5MK72dE6zM9cDvUcPtxhUZsDjESl9JipZYW60C3JGreKCEP+p8P/72r69m4AZGJd5g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/wrangler/node_modules/@esbuild/freebsd-arm64": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.0.tgz", + "integrity": "sha512-9FHtyO988CwNMMOE3YIeci+UV+x5Zy8fI2qHNpsEtSF83YPBmE8UWmfYAQg6Ux7Gsmd4FejZqnEUZCMGaNQHQw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/wrangler/node_modules/@esbuild/freebsd-x64": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.0.tgz", + "integrity": "sha512-zCMeMXI4HS/tXvJz8vWGexpZj2YVtRAihHLk1imZj4efx1BQzN76YFeKqlDr3bUWI26wHwLWPd3rwh6pe4EV7g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/wrangler/node_modules/@esbuild/linux-arm": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.0.tgz", + "integrity": "sha512-t76XLQDpxgmq2cNXKTVEB7O7YMb42atj2Re2Haf45HkaUpjM2J0UuJZDuaGbPbamzZ7bawyGFUkodL+zcE+jvQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/wrangler/node_modules/@esbuild/linux-arm64": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.0.tgz", + "integrity": "sha512-AS18v0V+vZiLJyi/4LphvBE+OIX682Pu7ZYNsdUHyUKSoRwdnOsMf6FDekwoAFKej14WAkOef3zAORJgAtXnlQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/wrangler/node_modules/@esbuild/linux-ia32": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.0.tgz", + "integrity": "sha512-Mz1jxqm/kfgKkc/KLHC5qIujMvnnarD9ra1cEcrs7qshTUSksPihGrWHVG5+osAIQ68577Zpww7SGapmzSt4Nw==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/wrangler/node_modules/@esbuild/linux-loong64": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.0.tgz", + "integrity": "sha512-QbEREjdJeIreIAbdG2hLU1yXm1uu+LTdzoq1KCo4G4pFOLlvIspBm36QrQOar9LFduavoWX2msNFAAAY9j4BDg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/wrangler/node_modules/@esbuild/linux-mips64el": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.0.tgz", + "integrity": "sha512-sJz3zRNe4tO2wxvDpH/HYJilb6+2YJxo/ZNbVdtFiKDufzWq4JmKAiHy9iGoLjAV7r/W32VgaHGkk35cUXlNOg==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/wrangler/node_modules/@esbuild/linux-ppc64": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.0.tgz", + "integrity": "sha512-z9N10FBD0DCS2dmSABDBb5TLAyF1/ydVb+N4pi88T45efQ/w4ohr/F/QYCkxDPnkhkp6AIpIcQKQ8F0ANoA2JA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/wrangler/node_modules/@esbuild/linux-riscv64": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.0.tgz", + "integrity": "sha512-pQdyAIZ0BWIC5GyvVFn5awDiO14TkT/19FTmFcPdDec94KJ1uZcmFs21Fo8auMXzD4Tt+diXu1LW1gHus9fhFQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/wrangler/node_modules/@esbuild/linux-s390x": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.0.tgz", + "integrity": "sha512-hPlRWR4eIDDEci953RI1BLZitgi5uqcsjKMxwYfmi4LcwyWo2IcRP+lThVnKjNtk90pLS8nKdroXYOqW+QQH+w==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/wrangler/node_modules/@esbuild/linux-x64": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.0.tgz", + "integrity": "sha512-1hBWx4OUJE2cab++aVZ7pObD6s+DK4mPGpemtnAORBvb5l/g5xFGk0vc0PjSkrDs0XaXj9yyob3d14XqvnQ4gw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/wrangler/node_modules/@esbuild/netbsd-x64": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.0.tgz", + "integrity": "sha512-xbbOdfn06FtcJ9d0ShxxvSn2iUsGd/lgPIO2V3VZIPDbEaIj1/3nBBe1AwuEZKXVXkMmpr6LUAgMkLD/4D2PPA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/wrangler/node_modules/@esbuild/openbsd-x64": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.0.tgz", + "integrity": "sha512-aCwlRdSNMNxkGGqQajMUza6uXzR/U0dIl1QmLjPtRbLOx3Gy3otfFu/VjATy4yQzo9yFDGTxYDo1FfAD9oRD2A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/wrangler/node_modules/@esbuild/sunos-x64": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.0.tgz", + "integrity": "sha512-Q1KY1iJafM+UX6CFEL+F4HRTgygmEW568YMqDA5UV97AuZSm21b7SXIrRJDwXWPzr8MGr75fUZPV67FdtMHlHA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/wrangler/node_modules/@esbuild/win32-arm64": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.0.tgz", + "integrity": "sha512-W1eyGNi6d+8kOmZIwi/EDjrL9nxQIQ0MiGqe/AWc6+IaHloxHSGoeRgDRKHFISThLmsewZ5nHFvGFWdBYlgKPg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/wrangler/node_modules/@esbuild/win32-ia32": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.0.tgz", + "integrity": "sha512-30z1aKL9h22kQhilnYkORFYt+3wp7yZsHWus+wSKAJR8JtdfI76LJ4SBdMsCopTR3z/ORqVu5L1vtnHZWVj4cQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/wrangler/node_modules/@esbuild/win32-x64": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.0.tgz", + "integrity": "sha512-aIitBcjQeyOhMTImhLZmtxfdOcuNRpwlPNmlFKPcHQYPhEssw75Cl1TSXJXpMkzaua9FUetx/4OQKq7eJul5Cg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/wrangler/node_modules/esbuild": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.0.tgz", + "integrity": "sha512-jd0f4NHbD6cALCyGElNpGAOtWxSq46l9X/sWB0Nzd5er4Kz2YTm+Vl0qKFT9KUJvD8+fiO8AvoHhFvEatfVixA==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.27.0", + "@esbuild/android-arm": "0.27.0", + "@esbuild/android-arm64": "0.27.0", + "@esbuild/android-x64": "0.27.0", + "@esbuild/darwin-arm64": "0.27.0", + "@esbuild/darwin-x64": "0.27.0", + "@esbuild/freebsd-arm64": "0.27.0", + "@esbuild/freebsd-x64": "0.27.0", + "@esbuild/linux-arm": "0.27.0", + "@esbuild/linux-arm64": "0.27.0", + "@esbuild/linux-ia32": "0.27.0", + "@esbuild/linux-loong64": "0.27.0", + "@esbuild/linux-mips64el": "0.27.0", + "@esbuild/linux-ppc64": "0.27.0", + "@esbuild/linux-riscv64": "0.27.0", + "@esbuild/linux-s390x": "0.27.0", + "@esbuild/linux-x64": "0.27.0", + "@esbuild/netbsd-arm64": "0.27.0", + "@esbuild/netbsd-x64": "0.27.0", + "@esbuild/openbsd-arm64": "0.27.0", + "@esbuild/openbsd-x64": "0.27.0", + "@esbuild/openharmony-arm64": "0.27.0", + "@esbuild/sunos-x64": "0.27.0", + "@esbuild/win32-arm64": "0.27.0", + "@esbuild/win32-ia32": "0.27.0", + "@esbuild/win32-x64": "0.27.0" + } + }, + "node_modules/wrangler/node_modules/path-to-regexp": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.3.0.tgz", + "integrity": "sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/ws": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", + "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, "node_modules/yallist": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", "dev": true, "license": "ISC" + }, + "node_modules/youch": { + "version": "4.1.0-beta.10", + "resolved": "https://registry.npmjs.org/youch/-/youch-4.1.0-beta.10.tgz", + "integrity": "sha512-rLfVLB4FgQneDr0dv1oddCVZmKjcJ6yX6mS4pU82Mq/Dt9a3cLZQ62pDBL4AUO+uVrCvtWz3ZFUL2HFAFJ/BXQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@poppinss/colors": "^4.1.5", + "@poppinss/dumper": "^0.6.4", + "@speed-highlight/core": "^1.2.7", + "cookie": "^1.0.2", + "youch-core": "^0.3.3" + } + }, + "node_modules/youch-core": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/youch-core/-/youch-core-0.3.3.tgz", + "integrity": "sha512-ho7XuGjLaJ2hWHoK8yFnsUGy2Y5uDpqSTq1FkHLK4/oqKtyUU1AFbOOxY4IpC9f0fTLjwYbslUz0Po5BpD1wrA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@poppinss/exception": "^1.2.2", + "error-stack-parser-es": "^1.0.5" + } } } } diff --git a/package.json b/package.json index 1dba0ca..d286280 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,14 @@ "build": "vite build", "preview": "vite preview", "test": "node --test server/**/*.test.mjs", - "test:steam": "node scripts/steam-cli.mjs" + "oauth": "node workers/oauth-proxy.mjs", + "worker:dev": "wrangler dev --config workers/wrangler.toml", + "worker:deploy": "wrangler deploy --config workers/wrangler.toml", + "fetch:steam": "node scripts/fetch-steam.mjs", + "fetch:gog": "node scripts/fetch-gog.mjs", + "fetch:epic": "node scripts/fetch-epic.mjs", + "fetch:amazon": "node scripts/fetch-amazon.mjs", + "fetch:all": "node scripts/fetch-all.mjs" }, "dependencies": { "@ionic/react": "^8.0.0", @@ -26,6 +33,7 @@ "@types/react-router-dom": "^5.3.3", "@vitejs/plugin-react": "^4.2.1", "typescript": "^5.3.3", - "vite": "^5.0.0" + "vite": "^5.0.0", + "wrangler": "^4.63.0" } } diff --git a/scripts/fetch-all.mjs b/scripts/fetch-all.mjs deleted file mode 100644 index e3cffd0..0000000 --- a/scripts/fetch-all.mjs +++ /dev/null @@ -1,42 +0,0 @@ -import { spawn } from "node:child_process"; -import { fileURLToPath } from "node:url"; -import { dirname, join } from "node:path"; - -const __dirname = dirname(fileURLToPath(import.meta.url)); - -const runScript = (scriptName) => { - return new Promise((resolve, reject) => { - const scriptPath = join(__dirname, scriptName); - const child = spawn("node", [scriptPath], { - stdio: "inherit", - cwd: __dirname, - }); - - child.on("close", (code) => { - if (code === 0) { - resolve(); - } else { - reject(new Error(`${scriptName} exited with code ${code}`)); - } - }); - - child.on("error", reject); - }); -}; - -const run = async () => { - console.log("Starte alle API-Importer...\n"); - - try { - await runScript("fetch-steam.mjs"); - await runScript("fetch-epic.mjs"); - await runScript("fetch-gog.mjs"); - await runScript("fetch-blizzard.mjs"); - console.log("\n✓ Alle Importer erfolgreich ausgeführt."); - } catch (error) { - console.error("\n✗ Fehler beim Ausführen der Importer:", error.message); - process.exit(1); - } -}; - -run(); diff --git a/scripts/fetch-blizzard.mjs b/scripts/fetch-blizzard.mjs deleted file mode 100644 index 5d7b99c..0000000 --- a/scripts/fetch-blizzard.mjs +++ /dev/null @@ -1,183 +0,0 @@ -import fs from "fs"; -import path from "path"; - -/** - * Blizzard Account Library Importer - * Nutzt OAuth 2.0 für Authentifizierung - * - * Unterstützt: - * - World of Warcraft - * - Diablo - * - Overwatch - * - StarCraft - * - Warcraft III - * - Heroes of the Storm - * - Hearthstone - */ - -const loadConfig = () => { - const configPath = path.join(process.cwd(), "config.local.json"); - try { - if (fs.existsSync(configPath)) { - return JSON.parse(fs.readFileSync(configPath, "utf-8")); - } - } catch (error) { - console.log("⚠️ Config nicht lesbar, nutze Defaults"); - } - return { - blizzard: { - clientId: "", - clientSecret: "", - accountName: "", - region: "eu", - }, - }; -}; - -const fetchBlizzardGames = async ({ clientId, clientSecret, region }) => { - // OAuth 2.0 Token Endpoint - const tokenUrl = `https://${region}.battle.net/oauth/token`; - const libraryUrl = `https://${region}.api.blizzard.com/d3/profile/${clientId}/hero`; - - try { - // Schritt 1: Bearer Token holen (Client Credentials Flow) - const tokenResponse = await fetch(tokenUrl, { - method: "POST", - headers: { - "Content-Type": "application/x-www-form-urlencoded", - Authorization: `Basic ${Buffer.from(`${clientId}:${clientSecret}`).toString("base64")}`, - }, - body: new URLSearchParams({ - grant_type: "client_credentials", - scope: "d3.profile.us", - }), - }); - - if (!tokenResponse.ok) { - throw new Error( - `Token-Fehler: ${tokenResponse.status} - ${await tokenResponse.text()}`, - ); - } - - const { access_token } = await tokenResponse.json(); - - // Schritt 2: Games/Accountinfo laden - const gamesResponse = await fetch(libraryUrl, { - headers: { - Authorization: `Bearer ${access_token}`, - "User-Agent": "WhatToPlay/1.0", - }, - }); - - if (!gamesResponse.ok) { - console.warn( - `⚠️ Blizzard API: ${gamesResponse.status} - Möglicherweise falscher Region oder Credentials`, - ); - return []; - } - - const data = await gamesResponse.json(); - - // Blizzard gibt Heros statt Games zurück - // Wir extrahieren Informationen über verfügbare Spiele - return data.heroes || []; - } catch (error) { - console.error(`❌ Blizzard Fehler: ${error.message}`); - return []; - } -}; - -const buildBlizzardEntry = (hero, gameType = "Diablo III") => ({ - id: `blizzard-${hero.id}`, - title: `${gameType} - ${hero.name}`, - platform: "Blizzard", - class: hero.class, - level: hero.level, - experience: hero.experience, - killed: hero.kills?.elites || 0, - hardcore: hero.hardcore || false, - lastPlayed: hero.lastUpdated - ? new Date(hero.lastUpdated).toISOString() - : null, - url: `https://www.diablo3.com/en/profile/${hero.id}/`, -}); - -const buildTextFile = (game) => { - const lines = [ - `# ${game.title}`, - "", - `**Plattform**: ${game.platform}`, - `**Charaktertyp**: ${game.class || "Unbekannt"}`, - `**Level**: ${game.level || "N/A"}`, - game.hardcore ? `**Hardcore**: Ja ⚔️` : "", - `**Elite-Kills**: ${game.killed || 0}`, - `**Erfahrung**: ${game.experience || 0}`, - game.lastPlayed - ? `**Zuletzt gespielt**: ${new Date(game.lastPlayed).toLocaleDateString("de-DE")}` - : "", - "", - `[Im Profil anschauen](${game.url})`, - ]; - - return lines.filter(Boolean).join("\n"); -}; - -const writeBlizzardData = async (games) => { - const dataDir = path.join(process.cwd(), "public/data"); - const textDir = path.join(dataDir, "blizzard-text"); - - // Stelle sicher dass Verzeichnisse existieren - if (!fs.existsSync(dataDir)) fs.mkdirSync(dataDir, { recursive: true }); - if (!fs.existsSync(textDir)) fs.mkdirSync(textDir, { recursive: true }); - - // Schreibe JSON-Datei - fs.writeFileSync( - path.join(dataDir, "blizzard.json"), - JSON.stringify(games, null, 2), - "utf-8", - ); - - // Schreibe Text-Dateien für jeden Hero - games.forEach((game) => { - const textFile = `${game.id}.txt`; - const filePath = path.join(textDir, textFile); - const content = buildTextFile(game); - fs.writeFileSync(filePath, content, "utf-8"); - }); - - return games.length; -}; - -const main = async () => { - const config = loadConfig(); - const { clientId, clientSecret, region } = config.blizzard || {}; - - if (!clientId || !clientSecret) { - console.log( - "⚠️ Blizzard: Keine Credentials - Überspringe\n → Für iOS/Web: Backend mit OAuth benötigt\n → Siehe docs/BLIZZARD-SETUP.md für Development-Setup", - ); - return; - } - - console.log("⏳ Blizzard-Games laden..."); - const games = await fetchBlizzardGames({ - clientId, - clientSecret, - region: region || "eu", - }); - - if (games.length === 0) { - console.log( - "⚠️ Keine Blizzard-Games gefunden\n → Stelle sicher dass der Account mit Heros in Diablo III hat", - ); - return; - } - - // Verarbeite jeden Hero - const processedGames = games.map((hero) => buildBlizzardEntry(hero)); - - const count = await writeBlizzardData(processedGames); - console.log(`✓ Blizzard-Export fertig: ${count} Charaktere`); -}; - -main().catch(console.error); diff --git a/scripts/fetch-epic.mjs b/scripts/fetch-epic.mjs deleted file mode 100644 index d55c68c..0000000 --- a/scripts/fetch-epic.mjs +++ /dev/null @@ -1,96 +0,0 @@ -import { mkdir, readFile, writeFile } from "node:fs/promises"; - -const loadConfig = async () => { - const configUrl = new URL("../config.local.json", import.meta.url); - try { - const raw = await readFile(configUrl, "utf-8"); - return JSON.parse(raw); - } catch { - return {}; - } -}; - -const sanitizeFileName = (value) => { - const normalized = value - .toLowerCase() - .replace(/[^a-z0-9]+/g, "-") - .replace(/^-+|-+$/g, ""); - return normalized || "spiel"; -}; - -const fetchEpicGames = async ({ accountId, accessToken }) => { - // ⚠️ Epic Games Store hat KEINE öffentliche API! - // Legendary (Python CLI) funktioniert nicht auf iOS/Web - // Lösung: Backend mit Epic OAuth oder manuelle Import-Funktion - console.warn("⚠️ Epic Games: Keine öffentliche API verfügbar"); - console.log(" → Für iOS/Web: Backend mit Epic OAuth benötigt"); - console.log(" → Alternative: Manuelle Library-Import-Funktion\n"); - return []; -}; - -const buildEpicEntry = (game) => ({ - id: game.id || game.catalogItemId, - title: game.title || game.displayName, - platform: "PC", - lastPlayed: game.lastPlayed || null, - playtimeHours: game.playtimeMinutes - ? Math.round((game.playtimeMinutes / 60) * 10) / 10 - : 0, - tags: game.categories || [], - url: game.productSlug - ? `https://store.epicgames.com/en-US/p/${game.productSlug}` - : null, -}); - -const buildTextFile = (entry) => { - const lines = [ - `Titel: ${entry.title}`, - `Epic ID: ${entry.id}`, - `Zuletzt gespielt: ${entry.lastPlayed ?? "-"}`, - `Spielzeit (h): ${entry.playtimeHours ?? 0}`, - `Store: ${entry.url ?? "-"}`, - "Quelle: epic", - ]; - return lines.join("\n") + "\n"; -}; - -const writeOutputs = async (entries) => { - const dataDir = new URL("../public/data/", import.meta.url); - const textDir = new URL("../public/data/epic-text/", import.meta.url); - - await mkdir(dataDir, { recursive: true }); - await mkdir(textDir, { recursive: true }); - - const jsonPath = new URL("epic.json", dataDir); - await writeFile(jsonPath, JSON.stringify(entries, null, 2) + "\n", "utf-8"); - - await Promise.all( - entries.map(async (entry) => { - const fileName = `${sanitizeFileName(entry.title)}__${entry.id}.txt`; - const filePath = new URL(fileName, textDir); - await writeFile(filePath, buildTextFile(entry), "utf-8"); - }), - ); -}; - -const run = async () => { - const config = await loadConfig(); - const accountId = config.epic?.accountId || process.env.EPIC_ACCOUNT_ID; - const accessToken = config.epic?.accessToken || process.env.EPIC_ACCESS_TOKEN; - - if (!accountId || !accessToken) { - console.warn( - "Epic-Zugangsdaten nicht gesetzt. Erstelle leere Datei als Platzhalter.", - ); - } - - const games = await fetchEpicGames({ accountId, accessToken }); - const entries = games.map(buildEpicEntry); - await writeOutputs(entries); - console.log(`Epic-Export fertig: ${entries.length} Spiele.`); -}; - -run().catch((error) => { - console.error(error); - process.exit(1); -}); diff --git a/scripts/fetch-gog.mjs b/scripts/fetch-gog.mjs deleted file mode 100644 index 0f08613..0000000 --- a/scripts/fetch-gog.mjs +++ /dev/null @@ -1,112 +0,0 @@ -import { mkdir, readFile, writeFile } from "node:fs/promises"; - -const loadConfig = async () => { - const configUrl = new URL("../config.local.json", import.meta.url); - try { - const raw = await readFile(configUrl, "utf-8"); - return JSON.parse(raw); - } catch { - return {}; - } -}; - -const sanitizeFileName = (value) => { - const normalized = value - .toLowerCase() - .replace(/[^a-z0-9]+/g, "-") - .replace(/^-+|-+$/g, ""); - return normalized || "spiel"; -}; - -const fetchGogGames = async ({ userId, accessToken }) => { - if (!userId || !accessToken) { - console.warn("⚠️ GOG: Keine Credentials - Überspringe"); - console.log(" → Für iOS/Web: Backend mit OAuth benötigt"); - console.log(" → Development: Token aus Browser DevTools kopieren\n"); - return []; - } - - try { - // GOG Galaxy Library API (wie Heroic Launcher) - const url = `https://galaxy-library.gog.com/users/${userId}/releases`; - const response = await fetch(url, { - headers: { - Authorization: `Bearer ${accessToken}`, - "User-Agent": "WhatToPlay/1.0", - }, - }); - - if (!response.ok) { - throw new Error(`GOG API Fehler: ${response.status}`); - } - - const payload = await response.json(); - - // Galaxy API gibt items zurück, nicht owned - return payload.items || []; - } catch (error) { - console.error("GOG API-Aufruf fehlgeschlagen:", error.message); - console.log("💡 Tipp: Token abgelaufen? Neu aus gog.com holen\n"); - return []; - } -}; - -const buildGogEntry = (game) => ({ - // Galaxy Library API gibt external_id (GOG Product ID) - id: String(game.external_id || game.id), - title: game.title || `GOG Game ${game.external_id}`, - platform: "PC", - lastPlayed: game.date_created - ? new Date(game.date_created * 1000).toISOString() - : null, - playtimeHours: 0, // Galaxy API hat keine Spielzeit in /releases endpoint - tags: [], - url: `https://www.gog.com/game/${game.external_id}`, -}); - -const buildTextFile = (entry) => { - const lines = [ - `Titel: ${entry.title}`, - `GOG ID: ${entry.id}`, - `Zuletzt gespielt: ${entry.lastPlayed ?? "-"}`, - `Spielzeit (h): ${entry.playtimeHours ?? 0}`, - `Store: ${entry.url}`, - "Quelle: gog", - ]; - return lines.join("\n") + "\n"; -}; - -const writeOutputs = async (entries) => { - const dataDir = new URL("../public/data/", import.meta.url); - const textDir = new URL("../public/data/gog-text/", import.meta.url); - - await mkdir(dataDir, { recursive: true }); - await mkdir(textDir, { recursive: true }); - - const jsonPath = new URL("gog.json", dataDir); - await writeFile(jsonPath, JSON.stringify(entries, null, 2) + "\n", "utf-8"); - - await Promise.all( - entries.map(async (entry) => { - const fileName = `${sanitizeFileName(entry.title)}__${entry.id}.txt`; - const filePath = new URL(fileName, textDir); - await writeFile(filePath, buildTextFile(entry), "utf-8"); - }), - ); -}; - -const run = async () => { - const config = await loadConfig(); - const userId = config.gog?.userId || process.env.GOG_USER_ID; - const accessToken = config.gog?.accessToken || process.env.GOG_ACCESS_TOKEN; - - const games = await fetchGogGames({ userId, accessToken }); - const entries = games.map(buildGogEntry); - await writeOutputs(entries); - console.log(`GOG-Export fertig: ${entries.length} Spiele.`); -}; - -run().catch((error) => { - console.error(error); - process.exit(1); -}); diff --git a/src/App.tsx b/src/App.tsx index 0cbadb6..a8bbf9e 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -23,7 +23,6 @@ import LibraryPage from "./pages/Library/LibraryPage"; import PlaylistsPage from "./pages/Playlists/PlaylistsPage"; import SettingsPage from "./pages/Settings/SettingsPage"; import SettingsDetailPage from "./pages/Settings/SettingsDetailPage"; -import SettingsTutorialPage from "./pages/Settings/SettingsTutorialPage"; import "./App.css"; @@ -43,11 +42,6 @@ export default function App() { path="/settings/:serviceId" component={SettingsDetailPage} /> - diff --git a/src/components/TutorialModal.tsx b/src/components/TutorialModal.tsx deleted file mode 100644 index a4611db..0000000 --- a/src/components/TutorialModal.tsx +++ /dev/null @@ -1,141 +0,0 @@ -import React from "react"; -import { - IonPopover, - IonHeader, - IonToolbar, - IonTitle, - IonContent, - IonButtons, - IonButton, - IonIcon, - IonCard, - IonCardContent, - IonCardHeader, - IonCardTitle, - IonText, -} from "@ionic/react"; -import { closeOutline } from "ionicons/icons"; - -import { TUTORIALS, type TutorialStep } from "../data/tutorials"; - -interface TutorialModalProps { - service: string | null; - onClose: () => void; - anchorEvent?: Event; -} - -export default function TutorialModal({ - service, - onClose, - anchorEvent, -}: TutorialModalProps) { - const tutorial = service ? TUTORIALS[service] : null; - - return ( - - - - - {tutorial?.title} - - - - - - - - - - - {tutorial && ( - <> -
- {tutorial.steps.map((step: TutorialStep) => ( - - - - {step.title} - - - -

{step.description}

- {step.code && ( -
- {step.code} -
- )} - {step.hint && ( -
- 💡 {step.hint} -
- )} -
-
- ))} -
- - - - - 💡 Tipps - - - -
    - {tutorial.tips.map((tip: string) => ( -
  • - {tip} -
  • - ))} -
-
-
- -
- - )} - - - ); -} diff --git a/src/pages/Library/LibraryPage.tsx b/src/pages/Library/LibraryPage.tsx index 38660cb..b8300ba 100644 --- a/src/pages/Library/LibraryPage.tsx +++ b/src/pages/Library/LibraryPage.tsx @@ -237,8 +237,7 @@ export default function LibraryPage() {

Spielebibliothek

- Konsolidierte Übersicht aus Steam, Epic Games und GOG. Duplikate - werden automatisch zusammengeführt. + Deine Spiele aus Steam.

diff --git a/src/pages/Settings/SettingsDetailPage.tsx b/src/pages/Settings/SettingsDetailPage.tsx index bac311d..77f1be3 100644 --- a/src/pages/Settings/SettingsDetailPage.tsx +++ b/src/pages/Settings/SettingsDetailPage.tsx @@ -12,14 +12,11 @@ import { IonLabel, IonList, IonPage, - IonSelect, - IonSelectOption, IonText, IonTitle, IonToolbar, } from "@ionic/react"; import { - informationCircleOutline, refreshOutline, saveOutline, settingsOutline, @@ -45,37 +42,15 @@ const SERVICE_META = { steam: { title: "Steam", description: "Deine Steam-Bibliothek", - tutorialKey: "steam", - }, - gog: { - title: "GOG", - description: "GOG Galaxy Bibliothek", - tutorialKey: "gog", - }, - epic: { - title: "Epic Games", - description: "Epic Games Launcher", - tutorialKey: "epic", - }, - amazon: { - title: "Amazon Games", - description: "Prime Gaming / Luna", - tutorialKey: "amazon", - }, - blizzard: { - title: "Blizzard", - description: "Battle.net / WoW / Diablo", - tutorialKey: "blizzard", }, data: { title: "Datenverwaltung", description: "Export, Import und Reset", - tutorialKey: null, }, } as const; type ServiceId = keyof typeof SERVICE_META; -const PROVIDER_IDS = ["steam", "gog", "epic", "amazon", "blizzard"] as const; +const PROVIDER_IDS = ["steam"] as const; export default function SettingsDetailPage() { const { serviceId } = useParams(); @@ -97,51 +72,19 @@ export default function SettingsDetailPage() { if (isTestMode) { try { const response = await fetch("/api/config/load"); - const responseText = await response.text(); - console.log("API Response Status:", response.status); - console.log("API Response Text:", responseText); - if (response.ok) { - const testConfig = JSON.parse(responseText); + const testConfig = await response.json(); loadedConfig = { ...loadedConfig, ...testConfig }; - console.log("Test-Modus: Geladene Config:", loadedConfig); - setAlertMessage("🛠️ Test-Modus: config.local.json geladen"); - setShowAlert(true); - } else { - console.error( - "API /api/config/load fehlgeschlagen:", - response.status, - responseText, - ); + console.log("✓ Test-Modus: config.local.json geladen", testConfig); } } catch (error) { - console.error( - "Test-Modus aktiv, aber config.local.json nicht ladbar", - error, - ); - } - } - - // Query-Parameter für Steam-Seite übernehmen - if (serviceId === "steam") { - const query = new URLSearchParams(window.location.search); - const steamIdParam = query.get("steamid") ?? query.get("steamId") ?? ""; - const apiKeyParam = query.get("apikey") ?? query.get("apiKey") ?? ""; - - if (steamIdParam || apiKeyParam) { - loadedConfig = { - ...loadedConfig, - steam: { - ...loadedConfig.steam, - ...(steamIdParam ? { steamId: steamIdParam } : {}), - ...(apiKeyParam ? { apiKey: apiKeyParam } : {}), - }, - }; + console.warn("config.local.json konnte nicht geladen werden", error); } } setConfig(loadedConfig); }; + loadConfig(); }, [serviceId]); @@ -167,6 +110,8 @@ export default function SettingsDetailPage() { setApiOutput("Rufe API auf..."); try { + let result: { games: any[]; count: number } | null = null; + if (service === "steam") { const steamConfig = config.steam; if (!steamConfig?.apiKey || !steamConfig?.steamId) { @@ -176,7 +121,6 @@ export default function SettingsDetailPage() { return; } - // Rufe Backend-Endpoint auf (statt direkt Steam API wegen CORS) const response = await fetch("/api/steam/refresh", { method: "POST", headers: { "Content-Type": "application/json" }, @@ -194,32 +138,31 @@ export default function SettingsDetailPage() { return; } - const result = await response.json(); - - // Spiele in Database speichern - await db.saveGames(result.games); - - setApiOutput( - `✓ ${result.games.length} Spiele geladen und gespeichert\n\nBeispiel:\n${JSON.stringify(result.games.slice(0, 2), null, 2)}`, - ); + result = await response.json(); } - const updatedConfig = { - ...config, - [service]: { - ...config[service], - lastRefresh: new Date().toISOString(), - }, - }; - setConfig(updatedConfig); - await ConfigService.saveConfig(updatedConfig); - setAlertMessage(`✓ ${service.toUpperCase()} aktualisiert`); - setShowAlert(true); + if (result) { + await db.saveGames(result.games); + + const updatedConfig = { + ...config, + [service]: { + ...config[service], + lastRefresh: new Date().toISOString(), + }, + }; + setConfig(updatedConfig); + await ConfigService.saveConfig(updatedConfig); + + setApiOutput( + `✓ ${result.count} Spiele abgerufen\n\nBeispiel:\n${JSON.stringify(result.games.slice(0, 2), null, 2)}`, + ); + setAlertMessage(`✓ ${result.count} Spiele aktualisiert`); + setShowAlert(true); + } } catch (error) { const errorMsg = error instanceof Error ? error.message : String(error); - setApiOutput( - `❌ Fehler: ${errorMsg}\n\n💡 Tipp: Führe stattdessen im Terminal aus:\nnpm run fetch:steam`, - ); + setApiOutput(`❌ Fehler: ${errorMsg}`); setAlertMessage("Aktualisierung fehlgeschlagen"); setShowAlert(true); } @@ -364,16 +307,6 @@ export default function SettingsDetailPage() { /> - - - Anleitung anzeigen - -
)} - {serviceId === "gog" && ( - <> - - - GOG User ID - - handleDraftChange("gog", { - userId: e.detail.value || "", - }) - } - /> - - - Access Token - - handleDraftChange("gog", { - accessToken: e.detail.value || "", - }) - } - /> - - - - - Anleitung anzeigen - - -
- handleSaveService("gog")} - > - - Speichern - -
- - )} - - {serviceId === "epic" && ( - <> - - - Account E-Mail - - handleDraftChange("epic", { - email: e.detail.value || "", - }) - } - /> - - - Import-Methode - - handleDraftChange("epic", { - method: e.detail.value || "manual", - }) - } - > - - Manuelle JSON-Upload - - - OAuth (benötigt Backend) - - - - - - - - Epic hat keine öffentliche API. Nutze manuellen Import oder - Backend OAuth. - - - - - Anleitung anzeigen - - -
- handleSaveService("epic")} - > - - Speichern - -
- - )} - - {serviceId === "amazon" && ( - <> - - - Account E-Mail - - handleDraftChange("amazon", { - email: e.detail.value || "", - }) - } - /> - - - Import-Methode - - handleDraftChange("amazon", { - method: e.detail.value || "manual", - }) - } - > - - Manuelle JSON-Upload - - - OAuth (benötigt Backend) - - - - - - - Anleitung anzeigen - - -
- handleSaveService("amazon")} - > - - Speichern - -
- - )} - - {serviceId === "blizzard" && ( - <> - - - Client ID - - handleDraftChange("blizzard", { - clientId: e.detail.value || "", - }) - } - /> - - - Client Secret - - handleDraftChange("blizzard", { - clientSecret: e.detail.value || "", - }) - } - /> - - - Region - - handleDraftChange("blizzard", { - region: e.detail.value || "eu", - }) - } - > - 🇺🇸 North America - 🇪🇺 Europe - 🇰🇷 Korea - 🇹🇼 Taiwan - - - - - - Anleitung anzeigen - - -
- handleSaveService("blizzard")} - > - - Speichern - -
- - )} - {serviceId === "data" && ( <> diff --git a/src/pages/Settings/SettingsPage.tsx b/src/pages/Settings/SettingsPage.tsx index 2f681a4..9b1dda6 100644 --- a/src/pages/Settings/SettingsPage.tsx +++ b/src/pages/Settings/SettingsPage.tsx @@ -16,9 +16,6 @@ import { cloudOutline, cogOutline, gameControllerOutline, - globeOutline, - shieldOutline, - storefrontOutline, } from "ionicons/icons"; import "./SettingsPage.css"; @@ -46,34 +43,6 @@ export default function SettingsPage() { Steam API Key · Steam ID - - - GOG - Token - - - - Epic Games - Import - - - - Amazon Games - Import - - - - Blizzard - OAuth - diff --git a/src/pages/Settings/SettingsTutorialPage.css b/src/pages/Settings/SettingsTutorialPage.css deleted file mode 100644 index ca7c868..0000000 --- a/src/pages/Settings/SettingsTutorialPage.css +++ /dev/null @@ -1,58 +0,0 @@ -.settings-tutorial-section { - padding: 8px 16px 16px; -} - -.settings-tutorial-step { - margin-bottom: 20px; - padding: 16px; - background: #ffffff; - border-radius: 12px; - box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08); -} - -.settings-tutorial-step h3 { - margin: 0 0 12px 0; - font-size: 1.1rem; - font-weight: 600; - color: #1f2937; -} - -.settings-tutorial-step p { - margin: 0 0 12px 0; - line-height: 1.6; - color: #4b5563; -} - -.settings-tutorial-code { - background: #f9fafb; - border: 1px solid #e5e7eb; - border-radius: 8px; - padding: 12px; - margin: 12px 0; - white-space: pre-wrap; - font-family: "Monaco", "Courier New", monospace; - font-size: 0.85rem; - color: #374151; - overflow-x: auto; -} - -.settings-tutorial-hint { - margin-top: 12px; - padding: 12px; - background: #fef3c7; - border-left: 4px solid #f59e0b; - border-radius: 6px; - font-size: 0.9rem; - color: #92400e; - line-height: 1.5; -} - -.settings-tutorial-hint::before { - content: "💡 "; - font-size: 1rem; -} - -.settings-tutorial-empty { - padding: 24px; - text-align: center; -} diff --git a/src/pages/Settings/SettingsTutorialPage.tsx b/src/pages/Settings/SettingsTutorialPage.tsx deleted file mode 100644 index d65ef58..0000000 --- a/src/pages/Settings/SettingsTutorialPage.tsx +++ /dev/null @@ -1,101 +0,0 @@ -import React, { useMemo } from "react"; -import { - IonBackButton, - IonButtons, - IonContent, - IonHeader, - IonIcon, - IonPage, - IonText, - IonTitle, - IonToolbar, - IonCard, - IonCardContent, - IonCardHeader, - IonCardTitle, -} from "@ionic/react"; -import { useParams } from "react-router-dom"; - -import { TUTORIALS } from "../../data/tutorials"; - -import "./SettingsTutorialPage.css"; - -interface TutorialRouteParams { - serviceId: string; -} - -export default function SettingsTutorialPage() { - const { serviceId } = useParams(); - const tutorial = useMemo(() => TUTORIALS[serviceId], [serviceId]); - - if (!tutorial) { - return ( - - - - - - - Anleitung - - - -
- Keine Anleitung verfügbar. -
-
-
- ); - } - - return ( - - - - - - - - {tutorial.title} - - - - - -
- {tutorial.steps.map((step, index) => ( - - - {step.title} - - -

{step.description}

- {step.code && ( -
{step.code}
- )} - {step.hint && ( -
{step.hint}
- )} -
-
- ))} -
- -
- - - Tipps - - -
    - {tutorial.tips.map((tip) => ( -
  • {tip}
  • - ))} -
-
-
-
-
-
- ); -} diff --git a/src/services/ConfigService.ts b/src/services/ConfigService.ts index 3188d81..6c48405 100644 --- a/src/services/ConfigService.ts +++ b/src/services/ConfigService.ts @@ -6,29 +6,8 @@ import { db } from "./Database"; export interface ServiceConfig { steam?: { - apiKey: string; - steamId: string; - lastRefresh?: string; - }; - gog?: { - userId: string; - accessToken: string; - lastRefresh?: string; - }; - epic?: { - email?: string; - method?: "oauth" | "manual"; - lastRefresh?: string; - }; - amazon?: { - email?: string; - method?: "oauth" | "manual"; - lastRefresh?: string; - }; - blizzard?: { - clientId: string; - clientSecret: string; - region: "us" | "eu" | "kr" | "tw"; + apiKey?: string; + steamId?: string; lastRefresh?: string; }; } @@ -142,17 +121,6 @@ export class ConfigService { if (!config.steam.steamId) errors.push("Steam: Steam ID fehlt"); } - if (config.gog) { - if (!config.gog.userId) errors.push("GOG: User ID fehlt"); - if (!config.gog.accessToken) errors.push("GOG: Access Token fehlt"); - } - - if (config.blizzard) { - if (!config.blizzard.clientId) errors.push("Blizzard: Client ID fehlt"); - if (!config.blizzard.clientSecret) - errors.push("Blizzard: Client Secret fehlt"); - } - return { valid: errors.length === 0, errors, diff --git a/src/services/Database.ts b/src/services/Database.ts index 2a363c8..770bee5 100644 --- a/src/services/Database.ts +++ b/src/services/Database.ts @@ -5,29 +5,33 @@ export interface DbConfig { steam?: { - apiKey: string; - steamId: string; + apiKey?: string; + steamId?: string; lastRefresh?: string; }; gog?: { - userId: string; - accessToken: string; + userId?: string; + accessToken?: string; + refreshToken?: string; lastRefresh?: string; }; epic?: { email?: string; + accessToken?: string; method?: "oauth" | "manual"; lastRefresh?: string; }; amazon?: { email?: string; + manualGames?: Array<{ name: string; gameId?: string; source?: string }>; method?: "oauth" | "manual"; lastRefresh?: string; }; blizzard?: { - clientId: string; - clientSecret: string; - region: "us" | "eu" | "kr" | "tw"; + clientId?: string; + clientSecret?: string; + accessToken?: string; + region?: "us" | "eu" | "kr" | "tw"; lastRefresh?: string; }; }