diff --git a/.gitignore b/.gitignore index 880e27d..e7e5c74 100644 --- a/.gitignore +++ b/.gitignore @@ -28,7 +28,6 @@ downloads gameflow-deck.code-workspace .env.local src/tests/mock-roms/db.sqlite -src/tests/mock-roms/store src/tests/mock-config bin .config/flatpak/repo diff --git a/.versionrc b/.versionrc deleted file mode 100644 index fa5c461..0000000 --- a/.versionrc +++ /dev/null @@ -1,18 +0,0 @@ -{ - "packageFiles": [ - { - "filename": "package.json", - "type": "json" - } - ], - "bumpFiles": [ - { - "filename": "package.json", - "type": "json" - }, - { - "filename": "src/packages/gameflow-sdk/package.json", - "type": "json" - } - ] -} \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 0a70168..8334db8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,13 +1,6 @@ # Changelog -All notable changes to this project will be documented in this file. See [commit-and-tag-version](https://github.com/absolute-version/commit-and-tag-version) for commit guidelines. - -## [1.6.0](https://github.com/simeonradivoev/gameflow-deck/compare/v1.5.0...v1.6.0) (2026-05-09) - - -### Features - -* Implemented public plugin system accessible from the store. ([38cb752](https://github.com/simeonradivoev/gameflow-deck/commit/38cb7525527b5ad4f6eb284cdad0001fd87eaf7e)) +All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. ## [1.5.0](https://github.com/simeonradivoev/gameflow-deck/compare/v1.4.0...v1.5.0) (2026-05-05) diff --git a/README.md b/README.md index 0e5864e..d806d89 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Gameflow Deck +# Gameflow Deck A Cross-Platform open source Retro gaming frontend designed for handheld and controllers. Focused on building a simple user experience and intuitive UI as a curated community driven experience. @@ -7,12 +7,6 @@ Focused on building a simple user experience and intuitive UI as a curated commu > This app is actively in development, it is constantly changing and improving. > It will have an opinionated design and will be used as an experiment in discovering a good UX. -## Community - -Join us on Discord, where you can ask questions, submit ideas and get help. - -[![](https://invidget.switchblade.xyz/R9KakhY67d)](https://discord.gg/R9KakhY67d) - ## Features ### Integrations diff --git a/bun.lock b/bun.lock index f005808..3568727 100644 --- a/bun.lock +++ b/bun.lock @@ -7,54 +7,53 @@ "dependencies": { "7zip-bin": "^5.2.0", "@auth/core": "^0.34.3", - "@elysiajs/cors": "^1.4.2", - "@elysiajs/eden": "^1.4.9", - "@jimp/wasm-webp": "^1.6.1", + "@elysiajs/cors": "^1.4.1", + "@elysiajs/eden": "^1.4.6", + "@jimp/wasm-webp": "^1.6.0", "@phalcode/ts-igdb-client": "^1.0.26", "cheerio": "^1.2.0", - "conf": "^15.1.0", - "drizzle-orm": "^0.45.2", - "elysia": "^1.4.28", - "fs-extra": "^11.3.5", + "conf": "^15.0.2", + "drizzle-orm": "^0.45.1", + "elysia": "^1.4.22", + "fs-extra": "^11.3.3", "get-folder-size": "^5.0.0", "ini": "^6.0.0", - "jimp": "^1.6.1", + "jimp": "^1.6.0", "mustache": "^4.2.0", "node-7z": "^3.0.0", "node-disk-info": "^1.3.0", - "node-downloader-helper": "^2.1.11", + "node-downloader-helper": "^2.1.10", "node-stream-zip": "^1.15.0", "node-unrar-js": "^2.0.2", "open": "^11.0.0", - "p-queue": "^9.2.0", + "p-queue": "^9.1.2", "pathe": "^2.0.3", "slugify": "^1.6.9", "smol-toml": "^1.6.1", - "systeminformation": "^5.31.6", - "tapable": "^2.3.3", - "tough-cookie": "^6.0.1", + "systeminformation": "^5.31.5", + "tapable": "^2.3.0", + "tough-cookie": "^6.0.0", "tough-cookie-file-store": "^3.3.0", "unzip-stream": "^0.3.4", "webview-bun": "^2.4.0", - "zod": "^4.4.3", + "zod": "^4.3.6", }, "devDependencies": { - "@ap0nia/eden": "^1.6.1", + "@ap0nia/eden": "^1.0.0-next.22", "@ap0nia/eden-tanstack-query": "^1.0.0-next.22", "@emulatorjs/emulatorjs": "^4.2.3", - "@hey-api/openapi-ts": "^0.91.1", + "@hey-api/openapi-ts": "^0.91.0", "@noriginmedia/norigin-spatial-navigation": "^3.1.0", "@tailwindcss/typography": "^0.5.19", - "@tailwindcss/vite": "^4.3.0", - "@tanstack/react-form": "^1.32.0", - "@tanstack/react-query": "^5.100.10", - "@tanstack/react-query-devtools": "^5.100.10", - "@tanstack/react-query-persist-client": "^5.100.10", - "@tanstack/react-router": "^1.169.2", - "@tanstack/react-router-devtools": "^1.166.13", - "@tanstack/react-router-ssr-query": "^1.166.12", - "@tanstack/router-plugin": "^1.167.35", - "@tanstack/zod-adapter": "^1.166.9", + "@tailwindcss/vite": "^4.1.18", + "@tanstack/react-form": "^1.28.0", + "@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", + "@tanstack/zod-adapter": "^1.162.4", "@types/adm-zip": "^0.5.8", "@types/audiosprite": "^0.7.3", "@types/bun": "latest", @@ -65,95 +64,63 @@ "@types/mustache": "^4.2.6", "@types/node-7z": "^2.1.11", "@types/rclone.js": "^0.6.3", - "@types/react": "^19.2.14", + "@types/react": "^19.2.9", "@types/react-dom": "^19.2.3", "@types/unzip-stream": "^0.3.4", - "@vitejs/plugin-react": "^5.2.0", - "adm-zip": "^0.5.17", + "@vitejs/plugin-react": "^5.1.2", + "adm-zip": "^0.5.16", "animate.css": "^4.1.1", "app-builder-bin": "^5.0.0-alpha.13", "audiosprite": "^0.7.2", "babel-plugin-react-compiler": "^1.0.0", "classnames": "^2.5.1", - "commit-and-tag-version": "^12.7.3", "concurrently": "^9.2.1", "cross-env": "^10.1.0", - "daisyui": "^5.5.19", - "drizzle-kit": "^0.31.10", + "daisyui": "^5.5.14", + "drizzle-kit": "^0.31.9", + "dts-bundle-generator": "^9.5.1", "eden-tanstack-query": "^0.0.9", "howler": "^2.2.4", - "idb-keyval": "^6.2.2", "lucide-react": "^0.563.0", "pretty-bytes": "^7.1.0", "pretty-ms": "^9.3.0", - "react": "^19.2.6", - "react-dom": "^19.2.6", - "react-error-boundary": "^6.1.1", + "react": "^19.2.4", + "react-dom": "^19.2.4", + "react-error-boundary": "^6.1.0", "react-hot-toast": "^2.6.0", "react-markdown": "^10.1.0", - "react-qr-code": "^2.0.21", - "sass-embedded": "^1.99.0", - "tailwind-merge": "^3.6.0", - "tailwindcss": "^4.3.0", + "react-qr-code": "^2.0.18", + "sass-embedded": "^1.97.3", + "standard-version": "^9.5.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.3", - "vite-plugin-svg-icons-ng": "^1.9.1", + "vite": "^7.3.1", + "vite-plugin-svg-icons-ng": "^1.5.2", "vite-static-assets-plugin": "^1.2.2", "vite-tsconfig-paths": "^6.1.1", - }, - }, - "src/packages/gameflow-sdk": { - "name": "@simeonradivoev/gameflow-sdk", - "version": "1.6.0", - "bin": { - "gameflow-build": "build.ts", - }, - "peerDependencies": { - "7zip-bin": "^5.2.0", - "@auth/core": "^0.34.3", - "cheerio": "^1.2.0", - "conf": "^15.1.0", - "drizzle-orm": "^0.45.2", - "elysia": "^1.4.28", - "fs-extra": "^11.3.5", - "get-folder-size": "^5.0.0", - "ini": "^6.0.0", - "jimp": "^1.6.1", - "mustache": "^4.2.0", - "node-7z": "^3.0.0", - "node-disk-info": "^1.3.0", - "node-downloader-helper": "^2.1.11", - "node-stream-zip": "^1.15.0", - "node-unrar-js": "^2.0.2", - "open": "^11.0.0", - "p-queue": "^9.2.0", - "pathe": "^2.0.3", - "slugify": "^1.6.9", - "smol-toml": "^1.6.1", - "tapable": "^2.3.3", - "unzip-stream": "^0.3.4", - "zod": "^4.4.3", + "zod-to-ts": "^2.0.0", }, }, }, "packages": { "7zip-bin": ["7zip-bin@5.2.0", "", {}, "sha512-ukTPVhqG4jNzMro2qA9HSCSSVJN3aN7tlb+hfqYCt3ER0yWroeA2VR38MNrOHLQ/cVj+DaIMad0kFCtWWowh/A=="], - "@ap0nia/eden": ["@ap0nia/eden@1.6.1", "", { "dependencies": { "elysia": "1.2.15" } }, "sha512-jlsUyh4PsYNnMcPuQ3IJq0hhDNnyRNGYx+MSAJlcgKs4En9qrokLorSbTRvVjA1Mdx4VdzEADcPn99Kbph0SOw=="], + "@ap0nia/eden": ["@ap0nia/eden@1.0.0-next.22", "", { "peerDependencies": { "elysia": "^1.3.1" } }, "sha512-9iH09koK29Yuem80fz8nCt9iHVcJqxUo2QHAr4psI02PhvL70n6aWVo/hlHyYXwOSsSgRQlLl1vPmiulFOUFoA=="], "@ap0nia/eden-tanstack-query": ["@ap0nia/eden-tanstack-query@1.0.0-next.22", "", {}, "sha512-eSQ98G4TYzrAdsfRekrvqIrTqrAUFy+YpibZ5fj5KL6/R6FcrS2U2F51iML98baXT4MTpOJARY9p+7x0hiA8Qw=="], "@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.29.0", "", { "dependencies": { "@babel/helper-validator-identifier": "^7.28.5", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" } }, "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw=="], + "@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=="], - "@babel/core": ["@babel/core@7.29.0", "", { "dependencies": { "@babel/code-frame": "^7.29.0", "@babel/generator": "^7.29.0", "@babel/helper-compilation-targets": "^7.28.6", "@babel/helper-module-transforms": "^7.28.6", "@babel/helpers": "^7.28.6", "@babel/parser": "^7.29.0", "@babel/template": "^7.28.6", "@babel/traverse": "^7.29.0", "@babel/types": "^7.29.0", "@jridgewell/remapping": "^2.3.5", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", "json5": "^2.2.3", "semver": "^6.3.1" } }, "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA=="], + "@babel/core": ["@babel/core@7.28.6", "", { "dependencies": { "@babel/code-frame": "^7.28.6", "@babel/generator": "^7.28.6", "@babel/helper-compilation-targets": "^7.28.6", "@babel/helper-module-transforms": "^7.28.6", "@babel/helpers": "^7.28.6", "@babel/parser": "^7.28.6", "@babel/template": "^7.28.6", "@babel/traverse": "^7.28.6", "@babel/types": "^7.28.6", "@jridgewell/remapping": "^2.3.5", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", "json5": "^2.2.3", "semver": "^6.3.1" } }, "sha512-H3mcG6ZDLTlYfaSNi0iOKkigqMFvkTKlGUYlD8GW7nNOYRrevuA46iTypPyv+06V3fEmvvazfntkBU34L0azAw=="], - "@babel/generator": ["@babel/generator@7.29.1", "", { "dependencies": { "@babel/parser": "^7.29.0", "@babel/types": "^7.29.0", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" } }, "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw=="], + "@babel/generator": ["@babel/generator@7.28.6", "", { "dependencies": { "@babel/parser": "^7.28.6", "@babel/types": "^7.28.6", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" } }, "sha512-lOoVRwADj8hjf7al89tvQ2a1lf53Z+7tiXMgpZJL3maQPDxh0DgLMN62B2MKUOFcoodBHLMbDM6WAbKgNy5Suw=="], "@babel/helper-compilation-targets": ["@babel/helper-compilation-targets@7.28.6", "", { "dependencies": { "@babel/compat-data": "^7.28.6", "@babel/helper-validator-option": "^7.27.1", "browserslist": "^4.24.0", "lru-cache": "^5.1.1", "semver": "^6.3.1" } }, "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA=="], @@ -173,7 +140,7 @@ "@babel/helpers": ["@babel/helpers@7.28.6", "", { "dependencies": { "@babel/template": "^7.28.6", "@babel/types": "^7.28.6" } }, "sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw=="], - "@babel/parser": ["@babel/parser@7.29.3", "", { "dependencies": { "@babel/types": "^7.29.0" }, "bin": "./bin/babel-parser.js" }, "sha512-b3ctpQwp+PROvU/cttc4OYl4MzfJUWy6FZg+PMXfzmt/+39iHVF0sDfqay8TQM3JA2EUOyKcFZt75jWriQijsA=="], + "@babel/parser": ["@babel/parser@7.28.6", "", { "dependencies": { "@babel/types": "^7.28.6" }, "bin": "./bin/babel-parser.js" }, "sha512-TeR9zWR18BvbfPmGbLampPMW+uW1NZnJlRuuHso8i87QZNq2JRF9i6RgxRqtEq+wQGsS19NNTWr2duhnE49mfQ=="], "@babel/plugin-syntax-jsx": ["@babel/plugin-syntax-jsx@7.28.6", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.28.6" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-wgEmr06G6sIpqr8YDwA2dSRTE3bJ+V0IfpzfSY3Lfgd7YWOaAdlykvJi13ZKBt8cZHfgH1IXN+CL656W3uUa4w=="], @@ -195,9 +162,9 @@ "@drizzle-team/brocli": ["@drizzle-team/brocli@0.10.2", "", {}, "sha512-z33Il7l5dKjUgGULTqBsQBQwckHh5AbIuxhdsIxDDiZAzBOrZO6q9ogcWC65kU382AfynTfgNumVcNIjuIua6w=="], - "@elysiajs/cors": ["@elysiajs/cors@1.4.2", "", { "peerDependencies": { "elysia": ">= 1.4.0" } }, "sha512-FTCcbH35brTLigF1W7BYySRZomgI/dBEMK9BgK9RP9Nez7zmpGh4koL/Yr1BFv8nYz7CfhRvcM8d/c+XnwMaVQ=="], + "@elysiajs/cors": ["@elysiajs/cors@1.4.1", "", { "peerDependencies": { "elysia": ">= 1.4.0" } }, "sha512-lQfad+F3r4mNwsxRKbXyJB8Jg43oAOXjRwn7sKUL6bcOW3KjUqUimTS+woNpO97efpzjtDE0tEjGk9DTw8lqTQ=="], - "@elysiajs/eden": ["@elysiajs/eden@1.4.9", "", { "peerDependencies": { "elysia": ">=1.4.19" } }, "sha512-3CKVD4ycVjB8nCNssfmhnUuq3SzSHkUES3v5PNCFr9LxIrx39/HVRAZ8z2sLxrFqzUs48dCBZaxoZzJ5UUVHDA=="], + "@elysiajs/eden": ["@elysiajs/eden@1.4.6", "", { "peerDependencies": { "elysia": ">=1.4.19" } }, "sha512-Tsa4NwXEWg/u73vWiYZQ3L5/ecgZSxqiEjYwpS+4qBKXeTZqZKl2hcgHJSVBL+InEDMi35Xugct7qyAXE5oM4Q=="], "@emulatorjs/core-81": ["@emulatorjs/core-81@4.2.3", "", { "dependencies": { "@emulatorjs/emulatorjs": "latest" } }, "sha512-oPQEqjpR3z7Yedte4u3sOXDZ4NXAykNcbENjYcB+x3QshF8I+3MQCo8kINOT2lsqqgx91WR4kmEaYQqU39YsDA=="], @@ -357,13 +324,13 @@ "@esbuild/win32-x64": ["@esbuild/win32-x64@0.25.12", "", { "os": "win32", "cpu": "x64" }, "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA=="], - "@hey-api/codegen-core": ["@hey-api/codegen-core@0.6.1", "", { "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-khTIpxhKEAqmRmeLUnAFJQs4Sbg9RPokovJk9rRcC8B5MWH1j3/BRSqfpAIiJUBDU1+nbVg2RVCV+eQ174cdvw=="], + "@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.1", "", { "dependencies": { "@hey-api/codegen-core": "0.6.1", "@hey-api/json-schema-ref-parser": "1.2.3", "@hey-api/shared": "0.1.1", "@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-d16WR35UtthK/ihAIwJaKxrj/zvb5LbYwtVJCyZFFMin2qzDU8Y3Lpk78ensAykrLoaDLzpd0iIyt9JCP5Qmww=="], + "@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.1", "", { "dependencies": { "@hey-api/codegen-core": "0.6.1", "@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-/irgNGXw9TL5aKB3S7jCLgh07vgDFkYjSjz7vEWO9xEe6MUhx76zSFzkPspk2UrLghYayvmaKPf1ky4XjNI9ZQ=="], + "@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=="], @@ -375,63 +342,63 @@ "@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=="], - "@jimp/core": ["@jimp/core@1.6.1", "", { "dependencies": { "@jimp/file-ops": "1.6.1", "@jimp/types": "1.6.1", "@jimp/utils": "1.6.1", "await-to-js": "^3.0.0", "exif-parser": "^0.1.12", "file-type": "^21.3.3", "mime": "3" } }, "sha512-+BoKC5G6hkrSy501zcJ2EpfnllP+avPevcBfRcZe/CW+EwEfY6X1EZ8QWyT7NpDIvEEJb1fdJnMMfUnFkxmw9A=="], + "@jimp/core": ["@jimp/core@1.6.0", "", { "dependencies": { "@jimp/file-ops": "1.6.0", "@jimp/types": "1.6.0", "@jimp/utils": "1.6.0", "await-to-js": "^3.0.0", "exif-parser": "^0.1.12", "file-type": "^16.0.0", "mime": "3" } }, "sha512-EQQlKU3s9QfdJqiSrZWNTxBs3rKXgO2W+GxNXDtwchF3a4IqxDheFX1ti+Env9hdJXDiYLp2jTRjlxhPthsk8w=="], - "@jimp/diff": ["@jimp/diff@1.6.1", "", { "dependencies": { "@jimp/plugin-resize": "1.6.1", "@jimp/types": "1.6.1", "@jimp/utils": "1.6.1", "pixelmatch": "^5.3.0" } }, "sha512-YkKDPdHjLgo1Api3+Bhc0GLAygldlpt97NfOKoNg1U6IUNXA6X2MgosCjPfSBiSvJvrrz1fsIR+/4cfYXBI/HQ=="], + "@jimp/diff": ["@jimp/diff@1.6.0", "", { "dependencies": { "@jimp/plugin-resize": "1.6.0", "@jimp/types": "1.6.0", "@jimp/utils": "1.6.0", "pixelmatch": "^5.3.0" } }, "sha512-+yUAQ5gvRC5D1WHYxjBHZI7JBRusGGSLf8AmPRPCenTzh4PA+wZ1xv2+cYqQwTfQHU5tXYOhA0xDytfHUf1Zyw=="], - "@jimp/file-ops": ["@jimp/file-ops@1.6.1", "", {}, "sha512-T+gX6osHjprbDRad0/B71Evyre7ZdVY1z/gFGEG9Z8KOtZPKboWvPeP2UjbZYWQLy9UKCPQX1FNAnDiOPkJL7w=="], + "@jimp/file-ops": ["@jimp/file-ops@1.6.0", "", {}, "sha512-Dx/bVDmgnRe1AlniRpCKrGRm5YvGmUwbDzt+MAkgmLGf+jvBT75hmMEZ003n9HQI/aPnm/YKnXjg/hOpzNCpHQ=="], - "@jimp/js-bmp": ["@jimp/js-bmp@1.6.1", "", { "dependencies": { "@jimp/core": "1.6.1", "@jimp/types": "1.6.1", "@jimp/utils": "1.6.1", "bmp-ts": "^1.0.9" } }, "sha512-xzWzNT4/u5zGrTT3Tme9sGU7YzIKxi13+BCQwLqACbt5DXf9SAfdzRkopZQnmDko+6In5nqaT89Gjs43/WdnYQ=="], + "@jimp/js-bmp": ["@jimp/js-bmp@1.6.0", "", { "dependencies": { "@jimp/core": "1.6.0", "@jimp/types": "1.6.0", "@jimp/utils": "1.6.0", "bmp-ts": "^1.0.9" } }, "sha512-FU6Q5PC/e3yzLyBDXupR3SnL3htU7S3KEs4e6rjDP6gNEOXRFsWs6YD3hXuXd50jd8ummy+q2WSwuGkr8wi+Gw=="], - "@jimp/js-gif": ["@jimp/js-gif@1.6.1", "", { "dependencies": { "@jimp/core": "1.6.1", "@jimp/types": "1.6.1", "gifwrap": "^0.10.1", "omggif": "^1.0.10" } }, "sha512-YjY2W26rQa05XhanYhRZ7dingCiNN+T2Ymb1JiigIbABY0B28wHE3v3Cf1/HZPWGu0hOg36ylaKgV5KxF2M58w=="], + "@jimp/js-gif": ["@jimp/js-gif@1.6.0", "", { "dependencies": { "@jimp/core": "1.6.0", "@jimp/types": "1.6.0", "gifwrap": "^0.10.1", "omggif": "^1.0.10" } }, "sha512-N9CZPHOrJTsAUoWkWZstLPpwT5AwJ0wge+47+ix3++SdSL/H2QzyMqxbcDYNFe4MoI5MIhATfb0/dl/wmX221g=="], - "@jimp/js-jpeg": ["@jimp/js-jpeg@1.6.1", "", { "dependencies": { "@jimp/core": "1.6.1", "@jimp/types": "1.6.1", "jpeg-js": "^0.4.4" } }, "sha512-HT9H3yOmlOFzYmdI15IYdfy6ggQhSRIaHeA+OTJSEORXBqEo97sUZu/DsgHIcX5NJ7TkJBTgZ9BZXsV6UbsyMg=="], + "@jimp/js-jpeg": ["@jimp/js-jpeg@1.6.0", "", { "dependencies": { "@jimp/core": "1.6.0", "@jimp/types": "1.6.0", "jpeg-js": "^0.4.4" } }, "sha512-6vgFDqeusblf5Pok6B2DUiMXplH8RhIKAryj1yn+007SIAQ0khM1Uptxmpku/0MfbClx2r7pnJv9gWpAEJdMVA=="], - "@jimp/js-png": ["@jimp/js-png@1.6.1", "", { "dependencies": { "@jimp/core": "1.6.1", "@jimp/types": "1.6.1", "pngjs": "^7.0.0" } }, "sha512-SZ/KVhI5UjcSzzlXsXdIi/LhJ7UShf2NkMOtVrbZQcGzsqNtynAelrOXeoTxcanfVqmNhAoVHg8yR2cYoqrYjA=="], + "@jimp/js-png": ["@jimp/js-png@1.6.0", "", { "dependencies": { "@jimp/core": "1.6.0", "@jimp/types": "1.6.0", "pngjs": "^7.0.0" } }, "sha512-AbQHScy3hDDgMRNfG0tPjL88AV6qKAILGReIa3ATpW5QFjBKpisvUaOqhzJ7Reic1oawx3Riyv152gaPfqsBVg=="], - "@jimp/js-tiff": ["@jimp/js-tiff@1.6.1", "", { "dependencies": { "@jimp/core": "1.6.1", "@jimp/types": "1.6.1", "utif2": "^4.1.0" } }, "sha512-jDG/eJquID1M4MBlKMmDRBmz2TpXMv7TUyu2nIRUxhlUc2ogC82T+VQUkca9GJH1BBJ9dx5sSE5dGkWNjIbZxw=="], + "@jimp/js-tiff": ["@jimp/js-tiff@1.6.0", "", { "dependencies": { "@jimp/core": "1.6.0", "@jimp/types": "1.6.0", "utif2": "^4.1.0" } }, "sha512-zhReR8/7KO+adijj3h0ZQUOiun3mXUv79zYEAKvE0O+rP7EhgtKvWJOZfRzdZSNv0Pu1rKtgM72qgtwe2tFvyw=="], - "@jimp/plugin-blit": ["@jimp/plugin-blit@1.6.1", "", { "dependencies": { "@jimp/types": "1.6.1", "@jimp/utils": "1.6.1", "zod": "^3.23.8" } }, "sha512-MwnI7C7K81uWddY9FLw1fCOIy6SsPIUftUz36Spt7jisCn8/40DhQMlSxpxTNelnZb/2SnloFimQfRZAmHLOqQ=="], + "@jimp/plugin-blit": ["@jimp/plugin-blit@1.6.0", "", { "dependencies": { "@jimp/types": "1.6.0", "@jimp/utils": "1.6.0", "zod": "^3.23.8" } }, "sha512-M+uRWl1csi7qilnSK8uxK4RJMSuVeBiO1AY0+7APnfUbQNZm6hCe0CCFv1Iyw1D/Dhb8ph8fQgm5mwM0eSxgVA=="], - "@jimp/plugin-blur": ["@jimp/plugin-blur@1.6.1", "", { "dependencies": { "@jimp/core": "1.6.1", "@jimp/utils": "1.6.1" } }, "sha512-lIo7Tzp5jQu30EFFSK/phXANK3citKVEjepDjQ6ljHoIFtuMRrnybnmI2Md24ulvWlDaz+hh3n6qrMb8ydwhZQ=="], + "@jimp/plugin-blur": ["@jimp/plugin-blur@1.6.0", "", { "dependencies": { "@jimp/core": "1.6.0", "@jimp/utils": "1.6.0" } }, "sha512-zrM7iic1OTwUCb0g/rN5y+UnmdEsT3IfuCXCJJNs8SZzP0MkZ1eTvuwK9ZidCuMo4+J3xkzCidRwYXB5CyGZTw=="], - "@jimp/plugin-circle": ["@jimp/plugin-circle@1.6.1", "", { "dependencies": { "@jimp/types": "1.6.1", "zod": "^3.23.8" } }, "sha512-kK1PavY6cKHNNKce37vdV4Tmpc1/zDKngGoeOV3j+EMatoHFZUinV3s6F9aWryPs3A0xhCLZgdJ6Zeea1d5LCQ=="], + "@jimp/plugin-circle": ["@jimp/plugin-circle@1.6.0", "", { "dependencies": { "@jimp/types": "1.6.0", "zod": "^3.23.8" } }, "sha512-xt1Gp+LtdMKAXfDp3HNaG30SPZW6AQ7dtAtTnoRKorRi+5yCJjKqXRgkewS5bvj8DEh87Ko1ydJfzqS3P2tdWw=="], - "@jimp/plugin-color": ["@jimp/plugin-color@1.6.1", "", { "dependencies": { "@jimp/core": "1.6.1", "@jimp/types": "1.6.1", "@jimp/utils": "1.6.1", "tinycolor2": "^1.6.0", "zod": "^3.23.8" } }, "sha512-LtUN1vAP+LRlZAtTNVhDRSiXx+26Kbz3zJaG6a5k59gQ95jgT5mknnF8lxkHcqJthM4MEk3/tPxkdJpEybyF/A=="], + "@jimp/plugin-color": ["@jimp/plugin-color@1.6.0", "", { "dependencies": { "@jimp/core": "1.6.0", "@jimp/types": "1.6.0", "@jimp/utils": "1.6.0", "tinycolor2": "^1.6.0", "zod": "^3.23.8" } }, "sha512-J5q8IVCpkBsxIXM+45XOXTrsyfblyMZg3a9eAo0P7VPH4+CrvyNQwaYatbAIamSIN1YzxmO3DkIZXzRjFSz1SA=="], - "@jimp/plugin-contain": ["@jimp/plugin-contain@1.6.1", "", { "dependencies": { "@jimp/core": "1.6.1", "@jimp/plugin-blit": "1.6.1", "@jimp/plugin-resize": "1.6.1", "@jimp/types": "1.6.1", "@jimp/utils": "1.6.1", "zod": "^3.23.8" } }, "sha512-m0qhrfA8jkTqretGv4w+T/ADFR4GwBpE0sCOC2uJ0dzr44/ddOMsIdrpi89kabqYiPYIrxkgdCVCLm3zn1Vkkg=="], + "@jimp/plugin-contain": ["@jimp/plugin-contain@1.6.0", "", { "dependencies": { "@jimp/core": "1.6.0", "@jimp/plugin-blit": "1.6.0", "@jimp/plugin-resize": "1.6.0", "@jimp/types": "1.6.0", "@jimp/utils": "1.6.0", "zod": "^3.23.8" } }, "sha512-oN/n+Vdq/Qg9bB4yOBOxtY9IPAtEfES8J1n9Ddx+XhGBYT1/QTU/JYkGaAkIGoPnyYvmLEDqMz2SGihqlpqfzQ=="], - "@jimp/plugin-cover": ["@jimp/plugin-cover@1.6.1", "", { "dependencies": { "@jimp/core": "1.6.1", "@jimp/plugin-crop": "1.6.1", "@jimp/plugin-resize": "1.6.1", "@jimp/types": "1.6.1", "zod": "^3.23.8" } }, "sha512-hZytnsth0zoll6cPf434BrT+p/v569Wr5tyO6Dp0dH1IDPhzhB5F38sZGMLDo7bzQiN9JFVB3fxkcJ/WYCJ3Mg=="], + "@jimp/plugin-cover": ["@jimp/plugin-cover@1.6.0", "", { "dependencies": { "@jimp/core": "1.6.0", "@jimp/plugin-crop": "1.6.0", "@jimp/plugin-resize": "1.6.0", "@jimp/types": "1.6.0", "zod": "^3.23.8" } }, "sha512-Iow0h6yqSC269YUJ8HC3Q/MpCi2V55sMlbkkTTx4zPvd8mWZlC0ykrNDeAy9IJegrQ7v5E99rJwmQu25lygKLA=="], - "@jimp/plugin-crop": ["@jimp/plugin-crop@1.6.1", "", { "dependencies": { "@jimp/core": "1.6.1", "@jimp/types": "1.6.1", "@jimp/utils": "1.6.1", "zod": "^3.23.8" } }, "sha512-EerRSLlclXyKDnYc/H9w/1amZW7b7v3OGi/VlerPd2M/pAu5X8TkyYWtfqYCXnNp1Ixtd8oCo9zGfY9zoXT4rg=="], + "@jimp/plugin-crop": ["@jimp/plugin-crop@1.6.0", "", { "dependencies": { "@jimp/core": "1.6.0", "@jimp/types": "1.6.0", "@jimp/utils": "1.6.0", "zod": "^3.23.8" } }, "sha512-KqZkEhvs+21USdySCUDI+GFa393eDIzbi1smBqkUPTE+pRwSWMAf01D5OC3ZWB+xZsNla93BDS9iCkLHA8wang=="], - "@jimp/plugin-displace": ["@jimp/plugin-displace@1.6.1", "", { "dependencies": { "@jimp/types": "1.6.1", "@jimp/utils": "1.6.1", "zod": "^3.23.8" } }, "sha512-K07QVl7xQwIfD6KfxRV/c3E9e7ZBXxUXdWuvoTWcKHL2qV48MOF5Nqbz/aJW4ThnQARIsxvYlZjPFiqkCjlU+g=="], + "@jimp/plugin-displace": ["@jimp/plugin-displace@1.6.0", "", { "dependencies": { "@jimp/types": "1.6.0", "@jimp/utils": "1.6.0", "zod": "^3.23.8" } }, "sha512-4Y10X9qwr5F+Bo5ME356XSACEF55485j5nGdiyJ9hYzjQP9nGgxNJaZ4SAOqpd+k5sFaIeD7SQ0Occ26uIng5Q=="], - "@jimp/plugin-dither": ["@jimp/plugin-dither@1.6.1", "", { "dependencies": { "@jimp/types": "1.6.1" } }, "sha512-+2V+GCV2WycMoX1/z977TkZ8Zq/4MVSKElHYatgUqtwXMi2fDK2gKYU2g9V39IqFvTJsTIsK0+58VFz/ROBVew=="], + "@jimp/plugin-dither": ["@jimp/plugin-dither@1.6.0", "", { "dependencies": { "@jimp/types": "1.6.0" } }, "sha512-600d1RxY0pKwgyU0tgMahLNKsqEcxGdbgXadCiVCoGd6V6glyCvkNrnnwC0n5aJ56Htkj88PToSdF88tNVZEEQ=="], - "@jimp/plugin-fisheye": ["@jimp/plugin-fisheye@1.6.1", "", { "dependencies": { "@jimp/types": "1.6.1", "@jimp/utils": "1.6.1", "zod": "^3.23.8" } }, "sha512-XtS5ZyoZ0vxZxJ6gkqI63SivhtI58vX95foMPM+cyzYkRsJXMOYCr8DScxF5bp4Xr003NjYm/P+7+08tibwzHA=="], + "@jimp/plugin-fisheye": ["@jimp/plugin-fisheye@1.6.0", "", { "dependencies": { "@jimp/types": "1.6.0", "@jimp/utils": "1.6.0", "zod": "^3.23.8" } }, "sha512-E5QHKWSCBFtpgZarlmN3Q6+rTQxjirFqo44ohoTjzYVrDI6B6beXNnPIThJgPr0Y9GwfzgyarKvQuQuqCnnfbA=="], - "@jimp/plugin-flip": ["@jimp/plugin-flip@1.6.1", "", { "dependencies": { "@jimp/types": "1.6.1", "zod": "^3.23.8" } }, "sha512-ws38W/sGj7LobNRayQ83garxiktOyWxM5vO/y4a/2cy9v65SLEUzVkrj+oeAaUSSObdz4HcCEla7XtGlnAGAaA=="], + "@jimp/plugin-flip": ["@jimp/plugin-flip@1.6.0", "", { "dependencies": { "@jimp/types": "1.6.0", "zod": "^3.23.8" } }, "sha512-/+rJVDuBIVOgwoyVkBjUFHtP+wmW0r+r5OQ2GpatQofToPVbJw1DdYWXlwviSx7hvixTWLKVgRWQ5Dw862emDg=="], - "@jimp/plugin-hash": ["@jimp/plugin-hash@1.6.1", "", { "dependencies": { "@jimp/core": "1.6.1", "@jimp/js-bmp": "1.6.1", "@jimp/js-jpeg": "1.6.1", "@jimp/js-png": "1.6.1", "@jimp/js-tiff": "1.6.1", "@jimp/plugin-color": "1.6.1", "@jimp/plugin-resize": "1.6.1", "@jimp/types": "1.6.1", "@jimp/utils": "1.6.1", "any-base": "^1.1.0" } }, "sha512-sZt6ZcMX6i8vFWb4GYnw0pR/o9++ef0dTVcboTB5B/g7nrxCODIB4wfEkJ/YqZM5wUvol77K1qeS0/rVO6z21A=="], + "@jimp/plugin-hash": ["@jimp/plugin-hash@1.6.0", "", { "dependencies": { "@jimp/core": "1.6.0", "@jimp/js-bmp": "1.6.0", "@jimp/js-jpeg": "1.6.0", "@jimp/js-png": "1.6.0", "@jimp/js-tiff": "1.6.0", "@jimp/plugin-color": "1.6.0", "@jimp/plugin-resize": "1.6.0", "@jimp/types": "1.6.0", "@jimp/utils": "1.6.0", "any-base": "^1.1.0" } }, "sha512-wWzl0kTpDJgYVbZdajTf+4NBSKvmI3bRI8q6EH9CVeIHps9VWVsUvEyb7rpbcwVLWYuzDtP2R0lTT6WeBNQH9Q=="], - "@jimp/plugin-mask": ["@jimp/plugin-mask@1.6.1", "", { "dependencies": { "@jimp/types": "1.6.1", "zod": "^3.23.8" } }, "sha512-SIG0/FcmEj3tkwFxc7fAGLO8o4uNzMpSOdQOhbCgxefQKq5wOVMk9BQx/sdMPBwtMLr9WLq0GzLA/rk6t2v20A=="], + "@jimp/plugin-mask": ["@jimp/plugin-mask@1.6.0", "", { "dependencies": { "@jimp/types": "1.6.0", "zod": "^3.23.8" } }, "sha512-Cwy7ExSJMZszvkad8NV8o/Z92X2kFUFM8mcDAhNVxU0Q6tA0op2UKRJY51eoK8r6eds/qak3FQkXakvNabdLnA=="], - "@jimp/plugin-print": ["@jimp/plugin-print@1.6.1", "", { "dependencies": { "@jimp/core": "1.6.1", "@jimp/js-jpeg": "1.6.1", "@jimp/js-png": "1.6.1", "@jimp/plugin-blit": "1.6.1", "@jimp/types": "1.6.1", "parse-bmfont-ascii": "^1.0.6", "parse-bmfont-binary": "^1.0.6", "parse-bmfont-xml": "^1.1.6", "simple-xml-to-json": "^1.2.2", "zod": "^3.23.8" } }, "sha512-BYVz/X3Xzv8XYilVeDy11NOp0h7BTDjlOtu0BekIFHP1yHVd24AXNzbOy52XlzYZWQ0Dl36HOHEpl/nSNrzc6w=="], + "@jimp/plugin-print": ["@jimp/plugin-print@1.6.0", "", { "dependencies": { "@jimp/core": "1.6.0", "@jimp/js-jpeg": "1.6.0", "@jimp/js-png": "1.6.0", "@jimp/plugin-blit": "1.6.0", "@jimp/types": "1.6.0", "parse-bmfont-ascii": "^1.0.6", "parse-bmfont-binary": "^1.0.6", "parse-bmfont-xml": "^1.1.6", "simple-xml-to-json": "^1.2.2", "zod": "^3.23.8" } }, "sha512-zarTIJi8fjoGMSI/M3Xh5yY9T65p03XJmPsuNet19K/Q7mwRU6EV2pfj+28++2PV2NJ+htDF5uecAlnGyxFN2A=="], - "@jimp/plugin-quantize": ["@jimp/plugin-quantize@1.6.1", "", { "dependencies": { "image-q": "^4.0.0", "zod": "^3.23.8" } }, "sha512-J2En9PLURfP+vwYDtuZ9T8yBW6BWYZBScydAjRiPBmJfEhTcNQqiiQODrZf7EqbbX/Sy5H6dAeRiqkgoV9N6Ww=="], + "@jimp/plugin-quantize": ["@jimp/plugin-quantize@1.6.0", "", { "dependencies": { "image-q": "^4.0.0", "zod": "^3.23.8" } }, "sha512-EmzZ/s9StYQwbpG6rUGBCisc3f64JIhSH+ncTJd+iFGtGo0YvSeMdAd+zqgiHpfZoOL54dNavZNjF4otK+mvlg=="], - "@jimp/plugin-resize": ["@jimp/plugin-resize@1.6.1", "", { "dependencies": { "@jimp/core": "1.6.1", "@jimp/types": "1.6.1", "zod": "^3.23.8" } }, "sha512-CLkrtJoIz2HdWnpYiN6p8KYcPc00rCH/SUu6o+lfZL05Q4uhecJlnvXuj9x+U6mDn3ldPmJj6aZqMHuUJzdVqg=="], + "@jimp/plugin-resize": ["@jimp/plugin-resize@1.6.0", "", { "dependencies": { "@jimp/core": "1.6.0", "@jimp/types": "1.6.0", "zod": "^3.23.8" } }, "sha512-uSUD1mqXN9i1SGSz5ov3keRZ7S9L32/mAQG08wUwZiEi5FpbV0K8A8l1zkazAIZi9IJzLlTauRNU41Mi8IF9fA=="], - "@jimp/plugin-rotate": ["@jimp/plugin-rotate@1.6.1", "", { "dependencies": { "@jimp/core": "1.6.1", "@jimp/plugin-crop": "1.6.1", "@jimp/plugin-resize": "1.6.1", "@jimp/types": "1.6.1", "@jimp/utils": "1.6.1", "zod": "^3.23.8" } }, "sha512-nOjVjbbj705B02ksysKnh0POAwEBXZtJ9zQ5qC+X7Tavl3JNn+P3BzQovbBxLPSbUSld6XID9z5ijin4PtOAUg=="], + "@jimp/plugin-rotate": ["@jimp/plugin-rotate@1.6.0", "", { "dependencies": { "@jimp/core": "1.6.0", "@jimp/plugin-crop": "1.6.0", "@jimp/plugin-resize": "1.6.0", "@jimp/types": "1.6.0", "@jimp/utils": "1.6.0", "zod": "^3.23.8" } }, "sha512-JagdjBLnUZGSG4xjCLkIpQOZZ3Mjbg8aGCCi4G69qR+OjNpOeGI7N2EQlfK/WE8BEHOW5vdjSyglNqcYbQBWRw=="], - "@jimp/plugin-threshold": ["@jimp/plugin-threshold@1.6.1", "", { "dependencies": { "@jimp/core": "1.6.1", "@jimp/plugin-color": "1.6.1", "@jimp/plugin-hash": "1.6.1", "@jimp/types": "1.6.1", "@jimp/utils": "1.6.1", "zod": "^3.23.8" } }, "sha512-JOKv9F8s6tnVLf4sB/2fF0F339EFnHvgEdFYugO6VhowKLsap0pEZmLyE/DlRnYtIj2RddHZVxVMp/eKJ04l2Q=="], + "@jimp/plugin-threshold": ["@jimp/plugin-threshold@1.6.0", "", { "dependencies": { "@jimp/core": "1.6.0", "@jimp/plugin-color": "1.6.0", "@jimp/plugin-hash": "1.6.0", "@jimp/types": "1.6.0", "@jimp/utils": "1.6.0", "zod": "^3.23.8" } }, "sha512-M59m5dzLoHOVWdM41O8z9SyySzcDn43xHseOH0HavjsfQsT56GGCC4QzU1banJidbUrePhzoEdS42uFE8Fei8w=="], - "@jimp/types": ["@jimp/types@1.6.1", "", { "dependencies": { "zod": "^3.23.8" } }, "sha512-leI7YbveTNi565m910XgIOwXyuu074H5qazAD1357HImJSv2hqxnWXpwxQbadGWZ7goZRYBDZy5lpqud0p7q5w=="], + "@jimp/types": ["@jimp/types@1.6.0", "", { "dependencies": { "zod": "^3.23.8" } }, "sha512-7UfRsiKo5GZTAATxm2qQ7jqmUXP0DxTArztllTcYdyw6Xi5oT4RaoXynVtCD4UyLK5gJgkZJcwonoijrhYFKfg=="], - "@jimp/utils": ["@jimp/utils@1.6.1", "", { "dependencies": { "@jimp/types": "1.6.1", "tinycolor2": "^1.6.0" } }, "sha512-veFPRd93FCnS7AgmCkPgARVGoDRrJ9cm1ujuNyA+UfQ5VKbED2002sm5XfFLFwTsKC8j04heTrwe+tU1dluXOw=="], + "@jimp/utils": ["@jimp/utils@1.6.0", "", { "dependencies": { "@jimp/types": "1.6.0", "tinycolor2": "^1.6.0" } }, "sha512-gqFTGEosKbOkYF/WFj26jMHOI5OH2jeP1MmC/zbK6BF6VJBf8rIC5898dPfSzZEbSA0wbbV5slbntWVc5PKLFA=="], - "@jimp/wasm-webp": ["@jimp/wasm-webp@1.6.1", "", { "dependencies": { "@jsquash/webp": "^1.4.0", "zod": "^3.23.8" } }, "sha512-t+Wqkde4xQHP/UZ4bDiDo3pbhFz32E7FvQCUkuFdJDmEDl6gPCs6LQiQVBmumUQYTeVLiLtLzlM9j8s7yF0sXQ=="], + "@jimp/wasm-webp": ["@jimp/wasm-webp@1.6.0", "", { "dependencies": { "@jsquash/webp": "^1.4.0", "zod": "^3.23.8" } }, "sha512-P0zUpK6n2XIAn8bt0F6rhSn1+FgteBTrL+TBb6Oqw8v5qEDJoNYkd6LlfZYN8YwtRBTBdZ8GFnWsg2Sar+qOkA=="], "@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=="], @@ -449,8 +416,6 @@ "@jsquash/webp": ["@jsquash/webp@1.5.0", "", { "dependencies": { "wasm-feature-detect": "^1.2.11" } }, "sha512-KggLoj2MnRSfIqTeKe1EmbljTX2vuV7mh79k89PCL1pyqiDULcPM1L47twxXt0hkb68F70bXiL31MxsuoZtKFw=="], - "@nodable/entities": ["@nodable/entities@2.1.0", "", {}, "sha512-nyT7T3nbMyBI/lvr6L5TyWbFJAI9FTgVRakNoBqCD+PmID8DzFrrNdLLtHMwMszOtqZa8PAOV24ZqDnQrhQINA=="], - "@node-minify/clean-css": ["@node-minify/clean-css@9.0.1", "", { "dependencies": { "@node-minify/utils": "9.0.1", "clean-css": "5.3.3" } }, "sha512-GHTMmjGloRvNzqdG7foI0iZeS2QmuYCQvdASJP9sCKjkpH45bygODpXPYKnlzUEpQgYvPK9Q3GxqYnVY9SdoqA=="], "@node-minify/core": ["@node-minify/core@9.0.2", "", { "dependencies": { "@node-minify/utils": "9.0.1", "glob": "10.3.3", "mkdirp": "3.0.1" } }, "sha512-FNhv29Wom6wKrrFKaeAfmZqz7TX5A1E6P+bpd0VIc+DYWMLUIhAViS8riaZg3A1oD0s06s+5BG2Fg7RqMKiKHw=="], @@ -459,6 +424,12 @@ "@node-minify/utils": ["@node-minify/utils@9.0.1", "", { "dependencies": { "gzip-size": "6.0.0" } }, "sha512-aC1+mhKTP3IMa2VcuGl3ui92LO/7CPQWldNGzu3BVGKiMNJ70AKJW/R6huuYCSuQyHDGM9oFwiVClsZnFxn67g=="], + "@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@3.1.0", "", { "dependencies": { "@noriginmedia/norigin-spatial-navigation-core": "^3.1.0", "@noriginmedia/norigin-spatial-navigation-react": "^3.1.0" } }, "sha512-KPge4ocpDFde7cpZ2aqrPrKmxOxkue983NsfpmE/vX4k2l+Ik8UkucCWGqkcy81TXkEyRhdsYwFTRePNB5qUCg=="], "@noriginmedia/norigin-spatial-navigation-core": ["@noriginmedia/norigin-spatial-navigation-core@3.1.0", "", { "dependencies": { "lodash-es": "^4.17.21" } }, "sha512-AFxJHurTqy+I3NLnaXsLUBa9FZjUryMNFEdLpPrITSqDjk525aINeLMOK1PN7WTiK5xpHL0pbpw0+uVOfWgp4w=="], @@ -501,7 +472,7 @@ "@pkgjs/parseargs": ["@pkgjs/parseargs@0.11.0", "", {}, "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg=="], - "@rolldown/pluginutils": ["@rolldown/pluginutils@1.0.0-rc.3", "", {}, "sha512-eybk3TjzzzV97Dlj5c+XrBFW57eTNhzod66y9HrBlzJ6NsCrWCp/2kaPS3K9wJmurBC0Tdw4yPjXKZqlznim3Q=="], + "@rolldown/pluginutils": ["@rolldown/pluginutils@1.0.0-beta.53", "", {}, "sha512-vENRlFU4YbrwVqNDZ7fLvy+JR1CRkyr01jhSiDpE1u6py3OMzQfztQU2jxykW3ALNxO4kSlqIDeYyD0Y9RcQeQ=="], "@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.56.0", "", { "os": "android", "cpu": "arm" }, "sha512-LNKIPA5k8PF1+jAFomGe3qN3bbIgJe/IlpDBwuVjrDKrJhVWywgnJvflMt/zkbVNLFtF1+94SljYQS6e99klnw=="], @@ -553,96 +524,92 @@ "@rollup/rollup-win32-x64-msvc": ["@rollup/rollup-win32-x64-msvc@4.56.0", "", { "os": "win32", "cpu": "x64" }, "sha512-H8AE9Ur/t0+1VXujj90w0HrSOuv0Nq9r1vSZF2t5km20NTfosQsGGUXDaKdQZzwuLts7IyL1fYT4hM95TI9c4g=="], - "@simeonradivoev/gameflow-sdk": ["@simeonradivoev/gameflow-sdk@workspace:src/packages/gameflow-sdk"], - "@sinclair/typebox": ["@sinclair/typebox@0.34.48", "", {}, "sha512-kKJTNuK3AQOrgjjotVxMrCn1sUJwM76wMszfq1kdU4uYVJjvEWuFQ6HgvLt4Xz3fSmZlTOxJ/Ie13KnIcWQXFA=="], "@socket.io/component-emitter": ["@socket.io/component-emitter@3.1.2", "", {}, "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA=="], - "@tailwindcss/node": ["@tailwindcss/node@4.3.0", "", { "dependencies": { "@jridgewell/remapping": "^2.3.5", "enhanced-resolve": "^5.21.0", "jiti": "^2.6.1", "lightningcss": "1.32.0", "magic-string": "^0.30.21", "source-map-js": "^1.2.1", "tailwindcss": "4.3.0" } }, "sha512-aFb4gUhFOgdh9AXo4IzBEOzBkkAxm9VigwDJnMIYv3lcfXCJVesNfbEaBl4BNgVRyid92AmdviqwBUBRKSeY3g=="], + "@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.3.0", "", { "optionalDependencies": { "@tailwindcss/oxide-android-arm64": "4.3.0", "@tailwindcss/oxide-darwin-arm64": "4.3.0", "@tailwindcss/oxide-darwin-x64": "4.3.0", "@tailwindcss/oxide-freebsd-x64": "4.3.0", "@tailwindcss/oxide-linux-arm-gnueabihf": "4.3.0", "@tailwindcss/oxide-linux-arm64-gnu": "4.3.0", "@tailwindcss/oxide-linux-arm64-musl": "4.3.0", "@tailwindcss/oxide-linux-x64-gnu": "4.3.0", "@tailwindcss/oxide-linux-x64-musl": "4.3.0", "@tailwindcss/oxide-wasm32-wasi": "4.3.0", "@tailwindcss/oxide-win32-arm64-msvc": "4.3.0", "@tailwindcss/oxide-win32-x64-msvc": "4.3.0" } }, "sha512-F7HZGBeN9I0/AuuJS5PwcD8xayx5ri5GhjYUDBEVYUkexyA/giwbDNjRVrxSezE3T250OU2K/wp/ltWx3UOefg=="], + "@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=="], - "@tailwindcss/oxide-android-arm64": ["@tailwindcss/oxide-android-arm64@4.3.0", "", { "os": "android", "cpu": "arm64" }, "sha512-TJPiq67tKlLuObP6RkwvVGDoxCMBVtDgKkLfa/uyj7/FyxvQwHS+UOnVrXXgbEsfUaMgiVvC4KbJnRr26ho4Ng=="], + "@tailwindcss/oxide-android-arm64": ["@tailwindcss/oxide-android-arm64@4.1.18", "", { "os": "android", "cpu": "arm64" }, "sha512-dJHz7+Ugr9U/diKJA0W6N/6/cjI+ZTAoxPf9Iz9BFRF2GzEX8IvXxFIi/dZBloVJX/MZGvRuFA9rqwdiIEZQ0Q=="], - "@tailwindcss/oxide-darwin-arm64": ["@tailwindcss/oxide-darwin-arm64@4.3.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-oMN/WZRb+SO37BmUElEgeEWuU8E/HXRkiODxJxLe1UTHVXLrdVSgfaJV7pSlhRGMSOiXLuxTIjfsF3wYvz8cgQ=="], + "@tailwindcss/oxide-darwin-arm64": ["@tailwindcss/oxide-darwin-arm64@4.1.18", "", { "os": "darwin", "cpu": "arm64" }, "sha512-Gc2q4Qhs660bhjyBSKgq6BYvwDz4G+BuyJ5H1xfhmDR3D8HnHCmT/BSkvSL0vQLy/nkMLY20PQ2OoYMO15Jd0A=="], - "@tailwindcss/oxide-darwin-x64": ["@tailwindcss/oxide-darwin-x64@4.3.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-N6CUmu4a6bKVADfw77p+iw6Yd9Q3OBhe0veaDX+QazfuVYlQsHfDgxBrsjQ/IW+zywL8mTrNd0SdJT/zgtvMdA=="], + "@tailwindcss/oxide-darwin-x64": ["@tailwindcss/oxide-darwin-x64@4.1.18", "", { "os": "darwin", "cpu": "x64" }, "sha512-FL5oxr2xQsFrc3X9o1fjHKBYBMD1QZNyc1Xzw/h5Qu4XnEBi3dZn96HcHm41c/euGV+GRiXFfh2hUCyKi/e+yw=="], - "@tailwindcss/oxide-freebsd-x64": ["@tailwindcss/oxide-freebsd-x64@4.3.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-zDL5hBkQdH5C6MpqbK3gQAgP80tsMwSI26vjOzjJtNCMUo0lFgOItzHKBIupOZNQxt3ouPH7RPhvNhiTfCe5CQ=="], + "@tailwindcss/oxide-freebsd-x64": ["@tailwindcss/oxide-freebsd-x64@4.1.18", "", { "os": "freebsd", "cpu": "x64" }, "sha512-Fj+RHgu5bDodmV1dM9yAxlfJwkkWvLiRjbhuO2LEtwtlYlBgiAT4x/j5wQr1tC3SANAgD+0YcmWVrj8R9trVMA=="], - "@tailwindcss/oxide-linux-arm-gnueabihf": ["@tailwindcss/oxide-linux-arm-gnueabihf@4.3.0", "", { "os": "linux", "cpu": "arm" }, "sha512-R06HdNi7A7OEoMsf6d4tjZ71RCWnZQPHj2mnotSFURjNLdBC+cIgXQ7l81CqeoiQftjf6OOblxXMInMgN2VzMA=="], + "@tailwindcss/oxide-linux-arm-gnueabihf": ["@tailwindcss/oxide-linux-arm-gnueabihf@4.1.18", "", { "os": "linux", "cpu": "arm" }, "sha512-Fp+Wzk/Ws4dZn+LV2Nqx3IilnhH51YZoRaYHQsVq3RQvEl+71VGKFpkfHrLM/Li+kt5c0DJe/bHXK1eHgDmdiA=="], - "@tailwindcss/oxide-linux-arm64-gnu": ["@tailwindcss/oxide-linux-arm64-gnu@4.3.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-qTJHELX8jetjhRQHCLilkVLmybpzNQAtaI/gaoVoidn/ufbNDbAo8KlK2J+yPoc8wQxvDxCmh/5lr8nC1+lTbg=="], + "@tailwindcss/oxide-linux-arm64-gnu": ["@tailwindcss/oxide-linux-arm64-gnu@4.1.18", "", { "os": "linux", "cpu": "arm64" }, "sha512-S0n3jboLysNbh55Vrt7pk9wgpyTTPD0fdQeh7wQfMqLPM/Hrxi+dVsLsPrycQjGKEQk85Kgbx+6+QnYNiHalnw=="], - "@tailwindcss/oxide-linux-arm64-musl": ["@tailwindcss/oxide-linux-arm64-musl@4.3.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-Z6sukiQsngnWO+l39X4pPbiWT81IC+PLKF+PHxIlyZbGNb9MODfYlXEVlFvej5BOZInWX01kVyzeLvHsXhfczQ=="], + "@tailwindcss/oxide-linux-arm64-musl": ["@tailwindcss/oxide-linux-arm64-musl@4.1.18", "", { "os": "linux", "cpu": "arm64" }, "sha512-1px92582HkPQlaaCkdRcio71p8bc8i/ap5807tPRDK/uw953cauQBT8c5tVGkOwrHMfc2Yh6UuxaH4vtTjGvHg=="], - "@tailwindcss/oxide-linux-x64-gnu": ["@tailwindcss/oxide-linux-x64-gnu@4.3.0", "", { "os": "linux", "cpu": "x64" }, "sha512-DRNdQRpSGzRGfARVuVkxvM8Q12nh19l4BF/G7zGA1oe+9wcC6saFBHTISrpIcKzhiXtSrlSrluCfvMuledoCTQ=="], + "@tailwindcss/oxide-linux-x64-gnu": ["@tailwindcss/oxide-linux-x64-gnu@4.1.18", "", { "os": "linux", "cpu": "x64" }, "sha512-v3gyT0ivkfBLoZGF9LyHmts0Isc8jHZyVcbzio6Wpzifg/+5ZJpDiRiUhDLkcr7f/r38SWNe7ucxmGW3j3Kb/g=="], - "@tailwindcss/oxide-linux-x64-musl": ["@tailwindcss/oxide-linux-x64-musl@4.3.0", "", { "os": "linux", "cpu": "x64" }, "sha512-Z0IADbDo8bh6I7h2IQMx601AdXBLfFpEdUotft86evd/8ZPflZe9COPO8Q1vw+pfLWIUo9zN/JGZvwuAJqduqg=="], + "@tailwindcss/oxide-linux-x64-musl": ["@tailwindcss/oxide-linux-x64-musl@4.1.18", "", { "os": "linux", "cpu": "x64" }, "sha512-bhJ2y2OQNlcRwwgOAGMY0xTFStt4/wyU6pvI6LSuZpRgKQwxTec0/3Scu91O8ir7qCR3AuepQKLU/kX99FouqQ=="], - "@tailwindcss/oxide-wasm32-wasi": ["@tailwindcss/oxide-wasm32-wasi@4.3.0", "", { "dependencies": { "@emnapi/core": "^1.10.0", "@emnapi/runtime": "^1.10.0", "@emnapi/wasi-threads": "^1.2.1", "@napi-rs/wasm-runtime": "^1.1.4", "@tybys/wasm-util": "^0.10.1", "tslib": "^2.8.1" }, "cpu": "none" }, "sha512-HNZGOUxEmElksYR7S6sC5jTeNGpobAsy9u7Gu0AskJ8/20FR9GqebUyB+HBcU/ax6BHuiuJi+Oda4B+YX6H1yA=="], + "@tailwindcss/oxide-wasm32-wasi": ["@tailwindcss/oxide-wasm32-wasi@4.1.18", "", { "dependencies": { "@emnapi/core": "^1.7.1", "@emnapi/runtime": "^1.7.1", "@emnapi/wasi-threads": "^1.1.0", "@napi-rs/wasm-runtime": "^1.1.0", "@tybys/wasm-util": "^0.10.1", "tslib": "^2.4.0" }, "cpu": "none" }, "sha512-LffYTvPjODiP6PT16oNeUQJzNVyJl1cjIebq/rWWBF+3eDst5JGEFSc5cWxyRCJ0Mxl+KyIkqRxk1XPEs9x8TA=="], - "@tailwindcss/oxide-win32-arm64-msvc": ["@tailwindcss/oxide-win32-arm64-msvc@4.3.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-Pe+RPVTi1T+qymuuRpcdvwSVZjnll/f7n8gBxMMh3xLTctMDKqpdfGimbMyioqtLhUYZxdJ9wGNhV7MKHvgZsQ=="], + "@tailwindcss/oxide-win32-arm64-msvc": ["@tailwindcss/oxide-win32-arm64-msvc@4.1.18", "", { "os": "win32", "cpu": "arm64" }, "sha512-HjSA7mr9HmC8fu6bdsZvZ+dhjyGCLdotjVOgLA2vEqxEBZaQo9YTX4kwgEvPCpRh8o4uWc4J/wEoFzhEmjvPbA=="], - "@tailwindcss/oxide-win32-x64-msvc": ["@tailwindcss/oxide-win32-x64-msvc@4.3.0", "", { "os": "win32", "cpu": "x64" }, "sha512-Mvrf2kXW/yeW/OTezZlCGOirXRcUuLIBx/5Y12BaPM7wJoryG6dfS/NJL8aBPqtTEx/Vm4T4vKzFUcKDT+TKUA=="], + "@tailwindcss/oxide-win32-x64-msvc": ["@tailwindcss/oxide-win32-x64-msvc@4.1.18", "", { "os": "win32", "cpu": "x64" }, "sha512-bJWbyYpUlqamC8dpR7pfjA0I7vdF6t5VpUGMWRkXVE3AXgIZjYUYAK7II1GNaxR8J1SSrSrppRar8G++JekE3Q=="], "@tailwindcss/typography": ["@tailwindcss/typography@0.5.19", "", { "dependencies": { "postcss-selector-parser": "6.0.10" }, "peerDependencies": { "tailwindcss": ">=3.0.0 || insiders || >=4.0.0-alpha.20 || >=4.0.0-beta.1" } }, "sha512-w31dd8HOx3k9vPtcQh5QHP9GwKcgbMp87j58qi6xgiBnFFtKEAgCWnDw4qUT8aHwkCp8bKvb/KGKWWHedP0AAg=="], - "@tailwindcss/vite": ["@tailwindcss/vite@4.3.0", "", { "dependencies": { "@tailwindcss/node": "4.3.0", "@tailwindcss/oxide": "4.3.0", "tailwindcss": "4.3.0" }, "peerDependencies": { "vite": "^5.2.0 || ^6 || ^7 || ^8" } }, "sha512-t6J3OrB5Fc0ExuhohouH0fWUGMYL6PTLhW+E7zIk/pdbnJARZDCwjBznFnkh5ynRnIRSI4YjtTH0t6USjJISrw=="], + "@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/devtools-event-client": ["@tanstack/devtools-event-client@0.4.3", "", { "bin": { "intent": "bin/intent.js" } }, "sha512-OZI6QyULw0FI0wjgmeYzCIfbgPsOEzwJtCpa69XrfLMtNXLGnz3d/dIabk7frg0TmHo+Ah49w5I4KC7Tufwsvw=="], + "@tanstack/devtools-event-client": ["@tanstack/devtools-event-client@0.4.0", "", {}, "sha512-RPfGuk2bDZgcu9bAJodvO2lnZeHuz4/71HjZ0bGb/SPg8+lyTA+RLSKQvo7fSmPSi8/vcH3aKQ8EM9ywf1olaw=="], - "@tanstack/form-core": ["@tanstack/form-core@1.32.0", "", { "dependencies": { "@tanstack/devtools-event-client": "^0.4.1", "@tanstack/pacer-lite": "^0.1.1", "@tanstack/store": "^0.9.1" } }, "sha512-Tn5VRDSjyqjmaet2tJMuEWDRFyrCaon03vxXPlSSaiSs6C/N7lCIwGCXJbZXEUq1kTj8jYN9qyXHbsz4LQHcow=="], + "@tanstack/form-core": ["@tanstack/form-core@1.28.0", "", { "dependencies": { "@tanstack/devtools-event-client": "^0.4.0", "@tanstack/pacer-lite": "^0.1.1", "@tanstack/store": "^0.7.7" } }, "sha512-MX3YveB6SKHAJ2yUwp+Ca/PCguub8bVEnLcLUbFLwdkSRMkP0lMGdaZl+F0JuEgZw56c6iFoRyfILhS7OQpydA=="], - "@tanstack/history": ["@tanstack/history@1.161.6", "", {}, "sha512-NaOGLRrddszbQj9upGat6HG/4TKvXLvu+osAIgfxPYA+eIvYKv8GKDJOrY2D3/U9MRnKfMWD7bU4jeD4xmqyIg=="], + "@tanstack/history": ["@tanstack/history@1.154.14", "", {}, "sha512-xyIfof8eHBuub1CkBnbKNKQXeRZC4dClhmzePHVOEel4G7lk/dW+TQ16da7CFdeNLv6u6Owf5VoBQxoo6DFTSA=="], "@tanstack/pacer-lite": ["@tanstack/pacer-lite@0.1.1", "", {}, "sha512-y/xtNPNt/YeyoVxE/JCx+T7yjEzpezmbb+toK8DDD1P4m7Kzs5YR956+7OKexG3f8aXgC3rLZl7b1V+yNUSy5w=="], - "@tanstack/query-core": ["@tanstack/query-core@5.100.10", "", {}, "sha512-8UR0yJR+GiQ40m3lPhUr0xbfAupe6GSQiksSBSa9SM2NjezFyxXCIA69/lz8cSoNKZLrw1/PktIyQBJcVeMi3w=="], + "@tanstack/query-core": ["@tanstack/query-core@5.90.20", "", {}, "sha512-OMD2HLpNouXEfZJWcKeVKUgQ5n+n3A2JFmBaScpNDUqSrQSjiveC7dKMe53uJUg1nDG16ttFPz2xfilz6i2uVg=="], - "@tanstack/query-devtools": ["@tanstack/query-devtools@5.100.10", "", {}, "sha512-3DmJf25hDPus5IpVvp6ujXv6bKV2zPzI9vpbAmpJigsL/H6DPvPjmf7/Q9yVKEke//8fgeQ45abjgnLuyYxAiw=="], + "@tanstack/query-devtools": ["@tanstack/query-devtools@5.93.0", "", {}, "sha512-+kpsx1NQnOFTZsw6HAFCW3HkKg0+2cepGtAWXjiiSOJJ1CtQpt72EE2nyZb+AjAbLRPoeRmPJ8MtQd8r8gsPdg=="], - "@tanstack/query-persist-client-core": ["@tanstack/query-persist-client-core@5.100.10", "", { "dependencies": { "@tanstack/query-core": "5.100.10" } }, "sha512-O9Pey40DhTTDBABS0bHr+KNL5/VMf6PrqjexS8WoDDtnkaoWM+y0MSe0V9E5W+BwvkjM33mB3aYcCxa175gZTQ=="], + "@tanstack/react-form": ["@tanstack/react-form@1.28.0", "", { "dependencies": { "@tanstack/form-core": "1.28.0", "@tanstack/react-store": "^0.8.0" }, "peerDependencies": { "react": "^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-ibLcf5QkTogV0Ly944CuqGxWTpHyreNA4Cy8Wtky7zE9wtE3HVapQt4/hUuXo51zihfTkv5URiXpoTSKF5Xosg=="], - "@tanstack/react-form": ["@tanstack/react-form@1.32.0", "", { "dependencies": { "@tanstack/form-core": "1.32.0", "@tanstack/react-store": "^0.9.1" }, "peerDependencies": { "react": "^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-6WP5SQTA6/H9crCpvpq3ZppYWqtrdE5NjOy6ebABi6uAQPqhfTzrdjS9t40mCZCFtGI5585OhJV6zBP/KN2zcw=="], + "@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": ["@tanstack/react-query@5.100.10", "", { "dependencies": { "@tanstack/query-core": "5.100.10" }, "peerDependencies": { "react": "^18 || ^19" } }, "sha512-FLaZf2RCrA/Zgp4aiu5tG3TyasTRO7aZ99skxQpr3Hg/zXOhu6yq5FZCYQ/tRaJtM9ylnoK8tFK7PolXQadv6Q=="], + "@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-query-devtools": ["@tanstack/react-query-devtools@5.100.10", "", { "dependencies": { "@tanstack/query-devtools": "5.100.10" }, "peerDependencies": { "@tanstack/react-query": "^5.100.10", "react": "^18 || ^19" } }, "sha512-zes0+o9ef5rAZXJ9f/SeaLs2nufJaeVkZkl/Or9NGrWVF41kL9Od9ED9nCwtQlgiF2VGtrzhEw5AU/igAO+aAg=="], + "@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-query-persist-client": ["@tanstack/react-query-persist-client@5.100.10", "", { "dependencies": { "@tanstack/query-persist-client-core": "5.100.10" }, "peerDependencies": { "@tanstack/react-query": "^5.100.10", "react": "^18 || ^19" } }, "sha512-EImacngLXYEtzlrIPf8IAqKN3foS7cmSj4GWqsHJvc7K+8fy2c3s7mdV8oTJeii/TvrzO4X9fcnXi6tUHMIOHA=="], + "@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": ["@tanstack/react-router@1.169.2", "", { "dependencies": { "@tanstack/history": "1.161.6", "@tanstack/react-store": "^0.9.3", "@tanstack/router-core": "1.169.2", "isbot": "^5.1.22" }, "peerDependencies": { "react": ">=18.0.0 || >=19.0.0", "react-dom": ">=18.0.0 || >=19.0.0" } }, "sha512-OJM7Kguc7ERnweaNRWsyWgIKcl3z23rD1B4jaxjzd9RGdnzpt2HfrWa9rggbT0Hfzhfo4D2ZmsfoTme035tniQ=="], + "@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-router-devtools": ["@tanstack/react-router-devtools@1.166.13", "", { "dependencies": { "@tanstack/router-devtools-core": "1.167.3" }, "peerDependencies": { "@tanstack/react-router": "^1.168.15", "@tanstack/router-core": "^1.168.11", "react": ">=18.0.0 || >=19.0.0", "react-dom": ">=18.0.0 || >=19.0.0" }, "optionalPeers": ["@tanstack/router-core"] }, "sha512-6yKRFFJrEEOiGp5RAAuGCYsl81M4XAhJmLcu9PKj+HZle4A3dsP60lwHoqQYWHMK9nKKFkdXR+D8qxzxqtQbEA=="], + "@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/react-router-ssr-query": ["@tanstack/react-router-ssr-query@1.166.12", "", { "dependencies": { "@tanstack/router-ssr-query-core": "1.168.0" }, "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-yDUIoEh+PimAcWmk/2BE0EkI8TwLVeToNzoIuwahmTtBUR+ptZPWbtiPjudO8JZ0BhT3odHtuOn1eBOK0/4NAQ=="], + "@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/react-store": ["@tanstack/react-store@0.9.3", "", { "dependencies": { "@tanstack/store": "0.9.3", "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-y2iHd/N9OkoQbFJLUX1T9vbc2O9tjH0pQRgTcx1/Nz4IlwLvkgpuglXUx+mXt0g5ZDFrEeDnONPqkbfxXJKwRg=="], + "@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-core": ["@tanstack/router-core@1.169.2", "", { "dependencies": { "@tanstack/history": "1.161.6", "cookie-es": "^3.0.0", "seroval": "^1.5.4", "seroval-plugins": "^1.5.4" } }, "sha512-5sm0DJF1A7Mz+9gy4Gz/lLovNailK3yot4vYvz9MkBUPw26uLnhQiR8hSCYxucjE0wD6Mdlc5l+Z0/XTlZ7xHw=="], + "@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-devtools-core": ["@tanstack/router-devtools-core@1.167.3", "", { "dependencies": { "clsx": "^2.1.1", "goober": "^2.1.16" }, "peerDependencies": { "@tanstack/router-core": "^1.168.11", "csstype": "^3.0.10" }, "optionalPeers": ["csstype"] }, "sha512-fJ1VMhyQgnoashTrP763c2HRc9kofgF61L7Jb3F6eTHAmCKtGVx8BRtiFt37sr3U0P0jmaaiiSPGP6nT5JtVNg=="], + "@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-generator": ["@tanstack/router-generator@1.166.42", "", { "dependencies": { "@babel/types": "^7.28.5", "@tanstack/router-core": "1.169.2", "@tanstack/router-utils": "1.161.8", "@tanstack/virtual-file-routes": "1.161.7", "jiti": "^2.7.0", "magic-string": "^0.30.21", "prettier": "^3.5.0", "zod": "^3.24.2" } }, "sha512-2qBWC0t78r6b3vI+AbnvCZcFAvbYBDlLuWZrTjQbcjUmwG3qyeQp983tJyDuj9wb5//adG1tgAGXZkJ3aDwdBg=="], + "@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-plugin": ["@tanstack/router-plugin@1.167.35", "", { "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.169.2", "@tanstack/router-generator": "1.166.42", "@tanstack/router-utils": "1.161.8", "@tanstack/virtual-file-routes": "1.161.7", "chokidar": "^3.6.0", "unplugin": "^3.0.0", "zod": "^3.24.2" }, "peerDependencies": { "@rsbuild/core": ">=1.0.2 || ^2.0.0", "@tanstack/react-router": "^1.169.2", "vite": ">=5.0.0 || >=6.0.0 || >=7.0.0 || >=8.0.0", "vite-plugin-solid": "^2.11.10 || ^3.0.0-0", "webpack": ">=5.92.0" }, "optionalPeers": ["@rsbuild/core", "@tanstack/react-router", "vite", "vite-plugin-solid", "webpack"] }, "sha512-UAScU5VAzLYVY4FML/Cbc5S5TucT4I8Ata05yozGOe4ZfepTKRffA5xWLtD2N+ov5svdv0KTX/kqlZnYPe28mA=="], + "@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=="], - "@tanstack/router-ssr-query-core": ["@tanstack/router-ssr-query-core@1.168.0", "", { "peerDependencies": { "@tanstack/query-core": ">=5.90.0", "@tanstack/router-core": ">=1.127.0" } }, "sha512-5yBUAF1d9z2kOFKoz1spvpvkMSTmRnRXEwi+bGKfrXYmt7CfHu3Pk8KUFMln67uQoKQ9VTkcd5tLkjJVrZ2/AQ=="], + "@tanstack/store": ["@tanstack/store@0.7.7", "", {}, "sha512-xa6pTan1bcaqYDS9BDpSiS63qa6EoDkPN9RsRaxHuDdVDNntzq3xNwR5YKTU/V3SkSyC9T4YVOPh2zRQN0nhIQ=="], - "@tanstack/router-utils": ["@tanstack/router-utils@1.161.8", "", { "dependencies": { "@babel/core": "^7.28.5", "@babel/generator": "^7.28.5", "@babel/parser": "^7.28.5", "@babel/types": "^7.28.5", "ansis": "^4.1.0", "babel-dead-code-elimination": "^1.0.12", "diff": "^8.0.2", "pathe": "^2.0.3", "tinyglobby": "^0.2.15" } }, "sha512-xyiLWEKjfBAVhauDSSjXxyf7s8elU6SM+V050sbkofvGmIIvkwPFtDsX7Gvwh14kBd6iCwAT+RiPvXTxAptY0Q=="], + "@tanstack/virtual-file-routes": ["@tanstack/virtual-file-routes@1.154.7", "", {}, "sha512-cHHDnewHozgjpI+MIVp9tcib6lYEQK5MyUr0ChHpHFGBl8Xei55rohFK0I0ve/GKoHeioaK42Smd8OixPp6CTg=="], - "@tanstack/store": ["@tanstack/store@0.9.3", "", {}, "sha512-8reSzl/qGWGGVKhBoxXPMWzATSbZLZFWhwBAFO9NAyp0TxzfBP0mIrGb8CP8KrQTmvzXlR/vFPPUrHTLBGyFyw=="], - - "@tanstack/virtual-file-routes": ["@tanstack/virtual-file-routes@1.161.7", "", { "bin": { "intent": "bin/intent.js" } }, "sha512-olW33+Cn+bsCsZKPwEGhlkqS6w3M2slFv11JIobdnCFKMLG97oAI2kWKdx5/zsywTL8flpnoIgaZZPlQTFYhdQ=="], - - "@tanstack/zod-adapter": ["@tanstack/zod-adapter@1.166.9", "", { "peerDependencies": { "@tanstack/react-router": ">=1.43.2", "zod": "^3.23.8" } }, "sha512-HHllQ/CKGi8YBbftv6OmzojtHM6Rk4UszAFICAgUMbwiqtKqjlIZQ/7mv2IPNxBb8YlOQgzyQ4jz2UTEXIi6YA=="], + "@tanstack/zod-adapter": ["@tanstack/zod-adapter@1.162.4", "", { "peerDependencies": { "@tanstack/react-router": ">=1.43.2", "zod": "^3.23.8" } }, "sha512-sO4n2o9F7gZKHZb/nW/fMcDaeVcbFZ2a7zCA+GkaHJwRmhKKlQQ0dae9pc8wOMMG+QkfH1Wysq+tg2RNvm/kpg=="], "@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/adm-zip": ["@types/adm-zip@0.5.8", "", { "dependencies": { "@types/node": "*" } }, "sha512-RVVH7QvZYbN+ihqZ4kX/dMiowf6o+Jk1fNwiSdx0NahBJLU787zkULhGhJM8mf/obmLGmgdMM0bXsQTmyfbR7Q=="], "@types/audiosprite": ["@types/audiosprite@0.7.3", "", {}, "sha512-P4rUuHPt2kWPMqyObfh1SfqS2H/ZuTxByh00ecuI2tOdvP5b8NznuBeQgemDXV9v8b4pewFPB9G3BuYRONqD7A=="], @@ -655,7 +622,7 @@ "@types/babel__traverse": ["@types/babel__traverse@7.28.0", "", { "dependencies": { "@babel/types": "^7.28.2" } }, "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q=="], - "@types/bun": ["@types/bun@1.3.14", "", { "dependencies": { "bun-types": "1.3.14" } }, "sha512-h1hFqFVcvAvD9j9K7ZW7vd82aSA+rTdznZa+5bwvCwqSB1jmmfLcbIWhOLx1/+boy/xmjgCs/OMUL8hRJSmnPw=="], + "@types/bun": ["@types/bun@1.3.6", "", { "dependencies": { "bun-types": "1.3.6" } }, "sha512-uWCv6FO/8LcpREhenN1d1b6fcspAB+cefwD7uti8C8VffIv0Um08TKMn98FynpTiU38+y2dUO55T11NgDt8VAA=="], "@types/cookie": ["@types/cookie@0.6.0", "", {}, "sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA=="], @@ -695,7 +662,7 @@ "@types/rclone.js": ["@types/rclone.js@0.6.3", "", { "dependencies": { "@types/node": "*" } }, "sha512-BssKAAVRY//fxGKso8SatyOwiD7X0toDofNnVxZlIXmN7UHrn2UBTxldNAjgUvWA91qJyeEPfKmeJpZVhLugXg=="], - "@types/react": ["@types/react@19.2.14", "", { "dependencies": { "csstype": "^3.2.2" } }, "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w=="], + "@types/react": ["@types/react@19.2.9", "", { "dependencies": { "csstype": "^3.2.2" } }, "sha512-Lpo8kgb/igvMIPeNV2rsYKTgaORYdO1XGVZ4Qz3akwOj0ySGYMPlQWa8BaLn0G63D1aSaAQ5ldR06wCpChQCjA=="], "@types/react-dom": ["@types/react-dom@19.2.3", "", { "peerDependencies": { "@types/react": "^19.2.0" } }, "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ=="], @@ -705,17 +672,19 @@ "@ungap/structured-clone": ["@ungap/structured-clone@1.3.0", "", {}, "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g=="], - "@vitejs/plugin-react": ["@vitejs/plugin-react@5.2.0", "", { "dependencies": { "@babel/core": "^7.29.0", "@babel/plugin-transform-react-jsx-self": "^7.27.1", "@babel/plugin-transform-react-jsx-source": "^7.27.1", "@rolldown/pluginutils": "1.0.0-rc.3", "@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 || ^8.0.0" } }, "sha512-YmKkfhOAi3wsB1PhJq5Scj3GXMn3WvtQ/JC0xoopuHoXSdmtdStOpFrYaT1kie2YgFBcIe64ROzMYRjCrYOdYw=="], + "@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=="], "JSONStream": ["JSONStream@1.3.5", "", { "dependencies": { "jsonparse": "^1.2.0", "through": ">=2.2.7 <3" }, "bin": { "JSONStream": "./bin.js" } }, "sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ=="], + "abort-controller": ["abort-controller@3.0.0", "", { "dependencies": { "event-target-shim": "^5.0.0" } }, "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg=="], + "accepts": ["accepts@1.3.8", "", { "dependencies": { "mime-types": "~2.1.34", "negotiator": "0.6.3" } }, "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw=="], "acorn": ["acorn@8.15.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg=="], "add-stream": ["add-stream@1.0.0", "", {}, "sha512-qQLMr+8o0WC4FZGQTcJiKBVC59JylcPSrTtk6usvmIDFUOCKegapy1VHQwRbFMOFyb/inzUVqHs+eMYKDM1YeQ=="], - "adm-zip": ["adm-zip@0.5.17", "", {}, "sha512-+Ut8d9LLqwEvHHJl1+PIHqoyDxFgVN847JTVM3Izi3xHDWPE4UtzzXysMZQs64DMcrJfBeS/uoEP4AD3HQHnQQ=="], + "adm-zip": ["adm-zip@0.5.16", "", {}, "sha512-TGw5yVi4saajsSEgz25grObGHEUaDrniwvA2qwSC060KfqGPdglhvPMA2lPIoxs3PQIItj2iag35fONcQqgUaQ=="], "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=="], @@ -727,7 +696,7 @@ "ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], - "ansi-styles": ["ansi-styles@3.2.1", "", { "dependencies": { "color-convert": "^1.9.0" } }, "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA=="], + "ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], "ansis": ["ansis@4.2.0", "", {}, "sha512-HqZ5rWlFjGiV0tDm3UxxgNRqsOTniqoKZu0pIAfh7TZQMGuZK+hH0drySty0si0QXj1ieop4+SkSfPZBPPkHig=="], @@ -743,6 +712,8 @@ "arrify": ["arrify@1.0.1", "", {}, "sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA=="], + "ast-types": ["ast-types@0.16.1", "", { "dependencies": { "tslib": "^2.0.1" } }, "sha512-6t10qk83GOG8p0vKmaCr8eiilZwO171AvbROMtvvNiwrTly62t+7XkA8RdIIVbpMhCASAsxgAzdRSwh6nw/5Dg=="], + "async": ["async@0.9.2", "", {}, "sha512-l6ToIJIotphWahxxHyzK9bnLR6kM4jJIIgLShZeqLY7iboHoGkdgFl7W2/Ivi4SkMJYGKqW8vSuk0uKUj6qsSw=="], "asynckit": ["asynckit@0.4.0", "", {}, "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="], @@ -763,6 +734,8 @@ "balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], + "base64-js": ["base64-js@1.5.1", "", {}, "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="], + "base64id": ["base64id@2.0.0", "", {}, "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog=="], "baseline-browser-mapping": ["baseline-browser-mapping@2.9.17", "", { "bin": { "baseline-browser-mapping": "dist/cli.js" } }, "sha512-agD0MgJFUP/4nvjqzIB29zRPUuCF7Ge6mEv9s8dHrtYD7QWXRcx75rOADE/d5ah1NI+0vkDl0yorDd5U852IQQ=="], @@ -783,11 +756,13 @@ "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-from": ["buffer-from@1.1.2", "", {}, "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ=="], "buffers": ["buffers@0.1.1", "", {}, "sha512-9q/rDEGSb/Qsvv2qvzIzdluL5k7AaJOTrw23z9reQthrbF7is4CtlT0DXyO1oei2DCp4uojjzQ7igaSHp1kAEQ=="], - "bun-types": ["bun-types@1.3.14", "", { "dependencies": { "@types/node": "*" } }, "sha512-4N0ig0fEomHt5R0KCFWjovxow98rIoRwKolrYdCcknNwMekCXRnWEUvgu5soYV8QXtVsrUD8B95MBOZGPvr6KQ=="], + "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=="], @@ -807,7 +782,7 @@ "chainsaw": ["chainsaw@0.1.0", "", { "dependencies": { "traverse": ">=0.3.0 <0.4" } }, "sha512-75kWfWt6MEKNC8xYXIdRpDehRYY/tNSgwKaJq+dbbDcxORuVrrQ+SEHoWsniVn9XPYfP4gmdWIeDk/4YNp1rNQ=="], - "chalk": ["chalk@2.4.2", "", { "dependencies": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", "supports-color": "^5.3.0" } }, "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ=="], + "chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="], "character-entities": ["character-entities@2.0.2", "", {}, "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ=="], @@ -833,9 +808,9 @@ "clsx": ["clsx@2.1.1", "", {}, "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA=="], - "color-convert": ["color-convert@1.9.3", "", { "dependencies": { "color-name": "1.1.3" } }, "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg=="], + "color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="], - "color-name": ["color-name@1.1.3", "", {}, "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw=="], + "color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="], "color-support": ["color-support@1.1.3", "", { "bin": { "color-support": "bin.js" } }, "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg=="], @@ -849,8 +824,6 @@ "commander": ["commander@14.0.2", "", {}, "sha512-TywoWNNRbhoD0BXs1P3ZEScW8W5iKrnbithIl0YH+uCmBd0QpPOA8yc82DS3BIE5Ma6FnBVUsJ7wVUDz4dvOWQ=="], - "commit-and-tag-version": ["commit-and-tag-version@12.7.3", "", { "dependencies": { "chalk": "^2.4.2", "conventional-changelog": "4.0.0", "conventional-changelog-config-spec": "2.1.0", "conventional-changelog-conventionalcommits": "6.1.0", "conventional-recommended-bump": "7.0.1", "detect-indent": "^6.1.0", "detect-newline": "^3.1.0", "dotgitignore": "^2.1.0", "fast-xml-parser": "^5.5.6", "figures": "^3.2.0", "find-up": "^5.0.0", "git-semver-tags": "^5.0.1", "semver": "^7.7.2", "yaml": "^2.6.0", "yargs": "^17.7.2" }, "bin": { "commit-and-tag-version": "bin/cli.js" } }, "sha512-rbauuCDU98yEHMy/LrNNu8HLTuGv7C2kN/3GXC59L18aJGii0eiryCESb1SEHXNFem2/2ngWG/Pq6qaCqw3aCw=="], - "compare-func": ["compare-func@2.0.0", "", { "dependencies": { "array-ify": "^1.0.0", "dot-prop": "^5.1.0" } }, "sha512-zHig5N+tPWARooBnb0Zx1MFcdfpyJrfTJ3Y5L+IFvUm8rM74hHz66z0gw0x4tijh5CorKkKUCnW82R2vmpeCRA=="], "concat-map": ["concat-map@0.0.1", "", {}, "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="], @@ -859,51 +832,51 @@ "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.1.0", "", { "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-Uy5YN9KEu0WWDaZAVJ5FAmZoaJt9rdK6kH+utItPyGsCqCgaTKkrmZx3zoE0/3q6S3bcp3Ihkk+ZqPxWxFK5og=="], + "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=="], - "conventional-changelog": ["conventional-changelog@4.0.0", "", { "dependencies": { "conventional-changelog-angular": "^6.0.0", "conventional-changelog-atom": "^3.0.0", "conventional-changelog-codemirror": "^3.0.0", "conventional-changelog-conventionalcommits": "^6.0.0", "conventional-changelog-core": "^5.0.0", "conventional-changelog-ember": "^3.0.0", "conventional-changelog-eslint": "^4.0.0", "conventional-changelog-express": "^3.0.0", "conventional-changelog-jquery": "^4.0.0", "conventional-changelog-jshint": "^3.0.0", "conventional-changelog-preset-loader": "^3.0.0" } }, "sha512-JbZjwE1PzxQCvm+HUTIr+pbSekS8qdOZzMakdFyPtdkEWwFvwEJYONzjgMm0txCb2yBcIcfKDmg8xtCKTdecNQ=="], + "conventional-changelog": ["conventional-changelog@3.1.25", "", { "dependencies": { "conventional-changelog-angular": "^5.0.12", "conventional-changelog-atom": "^2.0.8", "conventional-changelog-codemirror": "^2.0.8", "conventional-changelog-conventionalcommits": "^4.5.0", "conventional-changelog-core": "^4.2.1", "conventional-changelog-ember": "^2.0.9", "conventional-changelog-eslint": "^3.0.9", "conventional-changelog-express": "^2.0.6", "conventional-changelog-jquery": "^3.0.11", "conventional-changelog-jshint": "^2.0.9", "conventional-changelog-preset-loader": "^2.3.4" } }, "sha512-ryhi3fd1mKf3fSjbLXOfK2D06YwKNic1nC9mWqybBHdObPd8KJ2vjaXZfYj1U23t+V8T8n0d7gwnc9XbIdFbyQ=="], - "conventional-changelog-angular": ["conventional-changelog-angular@6.0.0", "", { "dependencies": { "compare-func": "^2.0.0" } }, "sha512-6qLgrBF4gueoC7AFVHu51nHL9pF9FRjXrH+ceVf7WmAfH3gs+gEYOkvxhjMPjZu57I4AGUGoNTY8V7Hrgf1uqg=="], + "conventional-changelog-angular": ["conventional-changelog-angular@5.0.13", "", { "dependencies": { "compare-func": "^2.0.0", "q": "^1.5.1" } }, "sha512-i/gipMxs7s8L/QeuavPF2hLnJgH6pEZAttySB6aiQLWcX3puWDL3ACVmvBhJGxnAy52Qc15ua26BufY6KpmrVA=="], - "conventional-changelog-atom": ["conventional-changelog-atom@3.0.0", "", {}, "sha512-pnN5bWpH+iTUWU3FaYdw5lJmfWeqSyrUkG+wyHBI9tC1dLNnHkbAOg1SzTQ7zBqiFrfo55h40VsGXWMdopwc5g=="], + "conventional-changelog-atom": ["conventional-changelog-atom@2.0.8", "", { "dependencies": { "q": "^1.5.1" } }, "sha512-xo6v46icsFTK3bb7dY/8m2qvc8sZemRgdqLb/bjpBsH2UyOS8rKNTgcb5025Hri6IpANPApbXMg15QLb1LJpBw=="], - "conventional-changelog-codemirror": ["conventional-changelog-codemirror@3.0.0", "", {}, "sha512-wzchZt9HEaAZrenZAUUHMCFcuYzGoZ1wG/kTRMICxsnW5AXohYMRxnyecP9ob42Gvn5TilhC0q66AtTPRSNMfw=="], + "conventional-changelog-codemirror": ["conventional-changelog-codemirror@2.0.8", "", { "dependencies": { "q": "^1.5.1" } }, "sha512-z5DAsn3uj1Vfp7po3gpt2Boc+Bdwmw2++ZHa5Ak9k0UKsYAO5mH1UBTN0qSCuJZREIhX6WU4E1p3IW2oRCNzQw=="], "conventional-changelog-config-spec": ["conventional-changelog-config-spec@2.1.0", "", {}, "sha512-IpVePh16EbbB02V+UA+HQnnPIohgXvJRxHcS5+Uwk4AT5LjzCZJm5sp/yqs5C6KZJ1jMsV4paEV13BN1pvDuxQ=="], - "conventional-changelog-conventionalcommits": ["conventional-changelog-conventionalcommits@6.1.0", "", { "dependencies": { "compare-func": "^2.0.0" } }, "sha512-3cS3GEtR78zTfMzk0AizXKKIdN4OvSh7ibNz6/DPbhWWQu7LqE/8+/GqSodV+sywUR2gpJAdP/1JFf4XtN7Zpw=="], + "conventional-changelog-conventionalcommits": ["conventional-changelog-conventionalcommits@4.6.3", "", { "dependencies": { "compare-func": "^2.0.0", "lodash": "^4.17.15", "q": "^1.5.1" } }, "sha512-LTTQV4fwOM4oLPad317V/QNQ1FY4Hju5qeBIM1uTHbrnCE+Eg4CdRZ3gO2pUeR+tzWdp80M2j3qFFEDWVqOV4g=="], - "conventional-changelog-core": ["conventional-changelog-core@5.0.2", "", { "dependencies": { "add-stream": "^1.0.0", "conventional-changelog-writer": "^6.0.0", "conventional-commits-parser": "^4.0.0", "dateformat": "^3.0.3", "get-pkg-repo": "^4.2.1", "git-raw-commits": "^3.0.0", "git-remote-origin-url": "^2.0.0", "git-semver-tags": "^5.0.0", "normalize-package-data": "^3.0.3", "read-pkg": "^3.0.0", "read-pkg-up": "^3.0.0" } }, "sha512-RhQOcDweXNWvlRwUDCpaqXzbZemKPKncCWZG50Alth72WITVd6nhVk9MJ6w1k9PFNBcZ3YwkdkChE+8+ZwtUug=="], + "conventional-changelog-core": ["conventional-changelog-core@4.2.4", "", { "dependencies": { "add-stream": "^1.0.0", "conventional-changelog-writer": "^5.0.0", "conventional-commits-parser": "^3.2.0", "dateformat": "^3.0.0", "get-pkg-repo": "^4.0.0", "git-raw-commits": "^2.0.8", "git-remote-origin-url": "^2.0.0", "git-semver-tags": "^4.1.1", "lodash": "^4.17.15", "normalize-package-data": "^3.0.0", "q": "^1.5.1", "read-pkg": "^3.0.0", "read-pkg-up": "^3.0.0", "through2": "^4.0.0" } }, "sha512-gDVS+zVJHE2v4SLc6B0sLsPiloR0ygU7HaDW14aNJE1v4SlqJPILPl/aJC7YdtRE4CybBf8gDwObBvKha8Xlyg=="], - "conventional-changelog-ember": ["conventional-changelog-ember@3.0.0", "", {}, "sha512-7PYthCoSxIS98vWhVcSphMYM322OxptpKAuHYdVspryI0ooLDehRXWeRWgN+zWSBXKl/pwdgAg8IpLNSM1/61A=="], + "conventional-changelog-ember": ["conventional-changelog-ember@2.0.9", "", { "dependencies": { "q": "^1.5.1" } }, "sha512-ulzIReoZEvZCBDhcNYfDIsLTHzYHc7awh+eI44ZtV5cx6LVxLlVtEmcO+2/kGIHGtw+qVabJYjdI5cJOQgXh1A=="], - "conventional-changelog-eslint": ["conventional-changelog-eslint@4.0.0", "", {}, "sha512-nEZ9byP89hIU0dMx37JXQkE1IpMmqKtsaR24X7aM3L6Yy/uAtbb+ogqthuNYJkeO1HyvK7JsX84z8649hvp43Q=="], + "conventional-changelog-eslint": ["conventional-changelog-eslint@3.0.9", "", { "dependencies": { "q": "^1.5.1" } }, "sha512-6NpUCMgU8qmWmyAMSZO5NrRd7rTgErjrm4VASam2u5jrZS0n38V7Y9CzTtLT2qwz5xEChDR4BduoWIr8TfwvXA=="], - "conventional-changelog-express": ["conventional-changelog-express@3.0.0", "", {}, "sha512-HqxihpUMfIuxvlPvC6HltA4ZktQEUan/v3XQ77+/zbu8No/fqK3rxSZaYeHYant7zRxQNIIli7S+qLS9tX9zQA=="], + "conventional-changelog-express": ["conventional-changelog-express@2.0.6", "", { "dependencies": { "q": "^1.5.1" } }, "sha512-SDez2f3iVJw6V563O3pRtNwXtQaSmEfTCaTBPCqn0oG0mfkq0rX4hHBq5P7De2MncoRixrALj3u3oQsNK+Q0pQ=="], - "conventional-changelog-jquery": ["conventional-changelog-jquery@4.0.0", "", {}, "sha512-TTIN5CyzRMf8PUwyy4IOLmLV2DFmPtasKN+x7EQKzwSX8086XYwo+NeaeA3VUT8bvKaIy5z/JoWUvi7huUOgaw=="], + "conventional-changelog-jquery": ["conventional-changelog-jquery@3.0.11", "", { "dependencies": { "q": "^1.5.1" } }, "sha512-x8AWz5/Td55F7+o/9LQ6cQIPwrCjfJQ5Zmfqi8thwUEKHstEn4kTIofXub7plf1xvFA2TqhZlq7fy5OmV6BOMw=="], - "conventional-changelog-jshint": ["conventional-changelog-jshint@3.0.0", "", { "dependencies": { "compare-func": "^2.0.0" } }, "sha512-bQof4byF4q+n+dwFRkJ/jGf9dCNUv4/kCDcjeCizBvfF81TeimPZBB6fT4HYbXgxxfxWXNl/i+J6T0nI4by6DA=="], + "conventional-changelog-jshint": ["conventional-changelog-jshint@2.0.9", "", { "dependencies": { "compare-func": "^2.0.0", "q": "^1.5.1" } }, "sha512-wMLdaIzq6TNnMHMy31hql02OEQ8nCQfExw1SE0hYL5KvU+JCTuPaDO+7JiogGT2gJAxiUGATdtYYfh+nT+6riA=="], - "conventional-changelog-preset-loader": ["conventional-changelog-preset-loader@3.0.0", "", {}, "sha512-qy9XbdSLmVnwnvzEisjxdDiLA4OmV3o8db+Zdg4WiFw14fP3B6XNz98X0swPPpkTd/pc1K7+adKgEDM1JCUMiA=="], + "conventional-changelog-preset-loader": ["conventional-changelog-preset-loader@2.3.4", "", {}, "sha512-GEKRWkrSAZeTq5+YjUZOYxdHq+ci4dNwHvpaBC3+ENalzFWuCWa9EZXSuZBpkr72sMdKB+1fyDV4takK1Lf58g=="], - "conventional-changelog-writer": ["conventional-changelog-writer@6.0.1", "", { "dependencies": { "conventional-commits-filter": "^3.0.0", "dateformat": "^3.0.3", "handlebars": "^4.7.7", "json-stringify-safe": "^5.0.1", "meow": "^8.1.2", "semver": "^7.0.0", "split": "^1.0.1" }, "bin": { "conventional-changelog-writer": "cli.js" } }, "sha512-359t9aHorPw+U+nHzUXHS5ZnPBOizRxfQsWT5ZDHBfvfxQOAik+yfuhKXG66CN5LEWPpMNnIMHUTCKeYNprvHQ=="], + "conventional-changelog-writer": ["conventional-changelog-writer@5.0.1", "", { "dependencies": { "conventional-commits-filter": "^2.0.7", "dateformat": "^3.0.0", "handlebars": "^4.7.7", "json-stringify-safe": "^5.0.1", "lodash": "^4.17.15", "meow": "^8.0.0", "semver": "^6.0.0", "split": "^1.0.0", "through2": "^4.0.0" }, "bin": { "conventional-changelog-writer": "cli.js" } }, "sha512-5WsuKUfxW7suLblAbFnxAcrvf6r+0b7GvNaWUwUIk0bXMnENP/PEieGKVUQrjPqwPT4o3EPAASBXiY6iHooLOQ=="], - "conventional-commits-filter": ["conventional-commits-filter@3.0.0", "", { "dependencies": { "lodash.ismatch": "^4.4.0", "modify-values": "^1.0.1" } }, "sha512-1ymej8b5LouPx9Ox0Dw/qAO2dVdfpRFq28e5Y0jJEU8ZrLdy0vOSkkIInwmxErFGhg6SALro60ZrwYFVTUDo4Q=="], + "conventional-commits-filter": ["conventional-commits-filter@2.0.7", "", { "dependencies": { "lodash.ismatch": "^4.4.0", "modify-values": "^1.0.0" } }, "sha512-ASS9SamOP4TbCClsRHxIHXRfcGCnIoQqkvAzCSbZzTFLfcTqJVugB0agRgsEELsqaeWgsXv513eS116wnlSSPA=="], - "conventional-commits-parser": ["conventional-commits-parser@4.0.0", "", { "dependencies": { "JSONStream": "^1.3.5", "is-text-path": "^1.0.1", "meow": "^8.1.2", "split2": "^3.2.2" }, "bin": { "conventional-commits-parser": "cli.js" } }, "sha512-WRv5j1FsVM5FISJkoYMR6tPk07fkKT0UodruX4je86V4owk451yjXAKzKAPOs9l7y59E2viHUS9eQ+dfUA9NSg=="], + "conventional-commits-parser": ["conventional-commits-parser@3.2.4", "", { "dependencies": { "JSONStream": "^1.0.4", "is-text-path": "^1.0.1", "lodash": "^4.17.15", "meow": "^8.0.0", "split2": "^3.0.0", "through2": "^4.0.0" }, "bin": { "conventional-commits-parser": "cli.js" } }, "sha512-nK7sAtfi+QXbxHCYfhpZsfRtaitZLIA6889kFIouLvz6repszQDgxBu7wf2WbU+Dco7sAnNCJYERCwt54WPC2Q=="], - "conventional-recommended-bump": ["conventional-recommended-bump@7.0.1", "", { "dependencies": { "concat-stream": "^2.0.0", "conventional-changelog-preset-loader": "^3.0.0", "conventional-commits-filter": "^3.0.0", "conventional-commits-parser": "^4.0.0", "git-raw-commits": "^3.0.0", "git-semver-tags": "^5.0.0", "meow": "^8.1.2" }, "bin": { "conventional-recommended-bump": "cli.js" } }, "sha512-Ft79FF4SlOFvX4PkwFDRnaNiIVX7YbmqGU0RwccUaiGvgp3S0a8ipR2/Qxk31vclDNM+GSdJOVs2KrsUCjblVA=="], + "conventional-recommended-bump": ["conventional-recommended-bump@6.1.0", "", { "dependencies": { "concat-stream": "^2.0.0", "conventional-changelog-preset-loader": "^2.3.4", "conventional-commits-filter": "^2.0.7", "conventional-commits-parser": "^3.2.0", "git-raw-commits": "^2.0.8", "git-semver-tags": "^4.1.1", "meow": "^8.0.0", "q": "^1.5.1" }, "bin": { "conventional-recommended-bump": "cli.js" } }, "sha512-uiApbSiNGM/kkdL9GTOLAqC4hbptObFo4wW2QRyHsKciGAfQuLU1ShZ1BIVI/+K2BE/W1AWYQMCXAsv4dyKPaw=="], "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@3.1.1", "", {}, "sha512-UaXxwISYJPTr9hwQxMFYZ7kNhSXboMXP+Z3TRX6f1/NyaGPfuNUZOWP1pUEb75B2HjfklIYLVRfWiFZJyC6Npg=="], + "cookie-es": ["cookie-es@2.0.0", "", {}, "sha512-RAj4E421UYRgqokKUmotqAwuplYw15qtdXfY+hGzgCJ/MBjCVZcSoHK/kH9kocfjRjcDME7IiDWR/1WX1TM2Pg=="], "core-util-is": ["core-util-is@1.0.3", "", {}, "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ=="], @@ -917,7 +890,7 @@ "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@3.2.1", "", { "dependencies": { "mdn-data": "2.27.1", "source-map-js": "^1.2.1" } }, "sha512-X7sjQzceUhu1u7Y/ylrRZFU2FS6LRiFVp6rKLPg23y3x3c3DOKAwuXGDp+PAGjh6CSnCjYeAul8pcT8bAl+lSA=="], + "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=="], @@ -929,7 +902,7 @@ "cycle": ["cycle@1.0.3", "", {}, "sha512-TVF6svNzeQCOpjCqsy0/CSy8VgObG3wXusJ73xW2GbG5rGx7lC8zxDSURicsXI2UsGdi2L0QNRCi745/wUDvsA=="], - "daisyui": ["daisyui@5.5.19", "", {}, "sha512-pbFAkl1VCEh/MPCeclKL61I/MqRIFFhNU7yiXoDDRapXN4/qNCoMxeCCswyxEEhqL5eiTTfwHvucFtOE71C9sA=="], + "daisyui": ["daisyui@5.5.14", "", {}, "sha512-L47rvw7I7hK68TA97VB8Ee0woHew+/ohR6Lx6Ah/krfISOqcG4My7poNpX5Mo5/ytMxiR40fEaz6njzDi7cuSg=="], "dargs": ["dargs@7.0.0", "", {}, "sha512-2iy1EkLdlBzQGvbweYRFxmFath8+K7+AKB0TlhHWkNuH+TmovaMH/Wp7V7R4u7f4SnX3OgLsU9t1NI9ioDnUpg=="], @@ -985,9 +958,11 @@ "dotgitignore": ["dotgitignore@2.1.0", "", { "dependencies": { "find-up": "^3.0.0", "minimatch": "^3.0.4" } }, "sha512-sCm11ak2oY6DglEPpCB8TixLjWAxd3kJTs6UIcSasNYxXdFPV+YKlye92c8H4kKFqV5qYMIh7d+cYecEg0dIkA=="], - "drizzle-kit": ["drizzle-kit@0.31.10", "", { "dependencies": { "@drizzle-team/brocli": "^0.10.2", "@esbuild-kit/esm-loader": "^2.5.5", "esbuild": "^0.25.4", "tsx": "^4.21.0" }, "bin": { "drizzle-kit": "bin.cjs" } }, "sha512-7OZcmQUrdGI+DUNNsKBn1aW8qSoKuTH7d0mYgSP8bAzdFzKoovxEFnoGQp2dVs82EOJeYycqRtciopszwUf8bw=="], + "drizzle-kit": ["drizzle-kit@0.31.9", "", { "dependencies": { "@drizzle-team/brocli": "^0.10.2", "@esbuild-kit/esm-loader": "^2.5.5", "esbuild": "^0.25.4", "esbuild-register": "^3.5.0" }, "bin": { "drizzle-kit": "bin.cjs" } }, "sha512-GViD3IgsXn7trFyBUUHyTFBpH/FsHTxYJ66qdbVggxef4UBPHRYxQaRzYLTuekYnk9i5FIEL9pbBIwMqX/Uwrg=="], - "drizzle-orm": ["drizzle-orm@0.45.2", "", { "peerDependencies": { "@aws-sdk/client-rds-data": ">=3", "@cloudflare/workers-types": ">=4", "@electric-sql/pglite": ">=0.2.0", "@libsql/client": ">=0.10.0", "@libsql/client-wasm": ">=0.10.0", "@neondatabase/serverless": ">=0.10.0", "@op-engineering/op-sqlite": ">=2", "@opentelemetry/api": "^1.4.1", "@planetscale/database": ">=1.13", "@prisma/client": "*", "@tidbcloud/serverless": "*", "@types/better-sqlite3": "*", "@types/pg": "*", "@types/sql.js": "*", "@upstash/redis": ">=1.34.7", "@vercel/postgres": ">=0.8.0", "@xata.io/client": "*", "better-sqlite3": ">=7", "bun-types": "*", "expo-sqlite": ">=14.0.0", "gel": ">=2", "knex": "*", "kysely": "*", "mysql2": ">=2", "pg": ">=8", "postgres": ">=3", "sql.js": ">=1", "sqlite3": ">=5" }, "optionalPeers": ["@aws-sdk/client-rds-data", "@cloudflare/workers-types", "@electric-sql/pglite", "@libsql/client", "@libsql/client-wasm", "@neondatabase/serverless", "@op-engineering/op-sqlite", "@opentelemetry/api", "@planetscale/database", "@prisma/client", "@tidbcloud/serverless", "@types/better-sqlite3", "@types/pg", "@types/sql.js", "@upstash/redis", "@vercel/postgres", "@xata.io/client", "better-sqlite3", "bun-types", "expo-sqlite", "gel", "knex", "kysely", "mysql2", "pg", "postgres", "sql.js", "sqlite3"] }, "sha512-kY0BSaTNYWnoDMVoyY8uxmyHjpJW1geOmBMdSSicKo9CIIWkSxMIj2rkeSR51b8KAPB7m+qysjuHme5nKP+E5Q=="], + "drizzle-orm": ["drizzle-orm@0.45.1", "", { "peerDependencies": { "@aws-sdk/client-rds-data": ">=3", "@cloudflare/workers-types": ">=4", "@electric-sql/pglite": ">=0.2.0", "@libsql/client": ">=0.10.0", "@libsql/client-wasm": ">=0.10.0", "@neondatabase/serverless": ">=0.10.0", "@op-engineering/op-sqlite": ">=2", "@opentelemetry/api": "^1.4.1", "@planetscale/database": ">=1.13", "@prisma/client": "*", "@tidbcloud/serverless": "*", "@types/better-sqlite3": "*", "@types/pg": "*", "@types/sql.js": "*", "@upstash/redis": ">=1.34.7", "@vercel/postgres": ">=0.8.0", "@xata.io/client": "*", "better-sqlite3": ">=7", "bun-types": "*", "expo-sqlite": ">=14.0.0", "gel": ">=2", "knex": "*", "kysely": "*", "mysql2": ">=2", "pg": ">=8", "postgres": ">=3", "sql.js": ">=1", "sqlite3": ">=5" }, "optionalPeers": ["@aws-sdk/client-rds-data", "@cloudflare/workers-types", "@electric-sql/pglite", "@libsql/client", "@libsql/client-wasm", "@neondatabase/serverless", "@op-engineering/op-sqlite", "@opentelemetry/api", "@planetscale/database", "@prisma/client", "@tidbcloud/serverless", "@types/better-sqlite3", "@types/pg", "@types/sql.js", "@upstash/redis", "@vercel/postgres", "@xata.io/client", "better-sqlite3", "bun-types", "expo-sqlite", "gel", "knex", "kysely", "mysql2", "pg", "postgres", "sql.js", "sqlite3"] }, "sha512-Te0FOdKIistGNPMq2jscdqngBRfBpC8uMFVwqjf6gtTVJHIQ/dosgV/CLBU2N4ZJBsXL5savCba9b0YJskKdcA=="], + + "dts-bundle-generator": ["dts-bundle-generator@9.5.1", "", { "dependencies": { "typescript": ">=5.0.2", "yargs": "^17.6.0" }, "bin": { "dts-bundle-generator": "dist/bin/dts-bundle-generator.js" } }, "sha512-DxpJOb2FNnEyOzMkG11sxO2dmxPjthoVWxfKqWYJ/bI/rT1rvTMktF5EKjAYrRZu6Z6t3NhOUZ0sZ5ZXevOfbA=="], "dunder-proto": ["dunder-proto@1.0.1", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-errors": "^1.3.0", "gopd": "^1.2.0" } }, "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A=="], @@ -999,7 +974,7 @@ "electron-to-chromium": ["electron-to-chromium@1.5.277", "", {}, "sha512-wKXFZw4erWmmOz5N/grBoJ2XrNJGDFMu2+W5ACHza5rHtvsqrK4gb6rnLC7XxKB9WlJ+RmyQatuEXmtm86xbnw=="], - "elysia": ["elysia@1.4.28", "", { "dependencies": { "cookie": "^1.1.1", "exact-mirror": "^0.2.7", "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-Vrx8sBnvq8squS/3yNBzR1jBXI+SgmnmvwawPjNuEHndUe5l1jV2Gp6JJ4ulDkEB8On6bWmmuyPpA+bq4t+WYg=="], + "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=="], @@ -1009,7 +984,7 @@ "engine.io-parser": ["engine.io-parser@5.2.3", "", {}, "sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q=="], - "enhanced-resolve": ["enhanced-resolve@5.21.0", "", { "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.3.3" } }, "sha512-otxSQPw4lkOZWkHpB3zaEQs6gWYEsmX4xQF68ElXC/TWvGxGMSGOvoNbaLXm6/cS/fSfHtsEdw90y20PCd+sCA=="], + "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=="], @@ -1027,15 +1002,23 @@ "esbuild": ["esbuild@0.25.12", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.25.12", "@esbuild/android-arm": "0.25.12", "@esbuild/android-arm64": "0.25.12", "@esbuild/android-x64": "0.25.12", "@esbuild/darwin-arm64": "0.25.12", "@esbuild/darwin-x64": "0.25.12", "@esbuild/freebsd-arm64": "0.25.12", "@esbuild/freebsd-x64": "0.25.12", "@esbuild/linux-arm": "0.25.12", "@esbuild/linux-arm64": "0.25.12", "@esbuild/linux-ia32": "0.25.12", "@esbuild/linux-loong64": "0.25.12", "@esbuild/linux-mips64el": "0.25.12", "@esbuild/linux-ppc64": "0.25.12", "@esbuild/linux-riscv64": "0.25.12", "@esbuild/linux-s390x": "0.25.12", "@esbuild/linux-x64": "0.25.12", "@esbuild/netbsd-arm64": "0.25.12", "@esbuild/netbsd-x64": "0.25.12", "@esbuild/openbsd-arm64": "0.25.12", "@esbuild/openbsd-x64": "0.25.12", "@esbuild/openharmony-arm64": "0.25.12", "@esbuild/sunos-x64": "0.25.12", "@esbuild/win32-arm64": "0.25.12", "@esbuild/win32-ia32": "0.25.12", "@esbuild/win32-x64": "0.25.12" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg=="], + "esbuild-register": ["esbuild-register@3.6.0", "", { "dependencies": { "debug": "^4.3.4" }, "peerDependencies": { "esbuild": ">=0.12 <1" } }, "sha512-H2/S7Pm8a9CL1uhp9OvjwrBh5Pvx0H8qVOxNu8Wed9Y7qv56MPtq+GGM8RJpq6glYJn9Wspr8uw7l55uyinNeg=="], + "escalade": ["escalade@3.2.0", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="], "escape-string-regexp": ["escape-string-regexp@1.0.5", "", {}, "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg=="], + "esprima": ["esprima@4.0.1", "", { "bin": { "esparse": "./bin/esparse.js", "esvalidate": "./bin/esvalidate.js" } }, "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A=="], + "estree-util-is-identifier-name": ["estree-util-is-identifier-name@3.0.0", "", {}, "sha512-hFtqIDZTIUZ9BXLb8y4pYGyk6+wekIivNVTcmvk8NoOh+VeRn5y6cEHzbURrWbfp1fIqdVipilzj+lfaadNZmg=="], + "event-target-shim": ["event-target-shim@5.0.1", "", {}, "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ=="], + "eventemitter3": ["eventemitter3@5.0.4", "", {}, "sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw=="], - "exact-mirror": ["exact-mirror@0.2.7", "", { "peerDependencies": { "@sinclair/typebox": "^0.34.15" }, "optionalPeers": ["@sinclair/typebox"] }, "sha512-+MeEmDcLA4o/vjK2zujgk+1VTxPR4hdp23qLqkWfStbECtAq9gmsvQa3LW6z/0GXZyHJobrCnmy1cdeE7BjsYg=="], + "events": ["events@3.3.0", "", {}, "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q=="], + + "exact-mirror": ["exact-mirror@0.2.6", "", { "peerDependencies": { "@sinclair/typebox": "^0.34.15" }, "optionalPeers": ["@sinclair/typebox"] }, "sha512-7s059UIx9/tnOKSySzUk5cPGkoILhTE4p6ncf6uIPaQ+9aRBQzQjc9+q85l51+oZ+P6aBxh084pD0CzBQPcFUA=="], "exif-parser": ["exif-parser@0.1.12", "", {}, "sha512-c2bQfLNbMzLPmzQuOr8fy0csy84WmwnER81W88DzTp9CYNPJ6yzOj2EZAh9pywYpqHnshVLHQJ8WzldAyfY+Iw=="], @@ -1049,11 +1032,11 @@ "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=="], - "fast-xml-builder": ["fast-xml-builder@1.1.9", "", { "dependencies": { "path-expression-matcher": "^1.1.3" } }, "sha512-jcyKVSEX13iseJqg7n/KWw+xnu/7fdrZ333Fac54KjHDIELVCfDDJXYIm6DTJ0Su4gSzrhqiK0DzY/wZbF40mw=="], - - "fast-xml-parser": ["fast-xml-parser@5.7.3", "", { "dependencies": { "@nodable/entities": "^2.1.0", "fast-xml-builder": "^1.1.7", "path-expression-matcher": "^1.5.0", "strnum": "^2.2.3" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-C0AaNuC+mscy6vrAQKAc/rMq+zAPHodfHGZu4sGVehvAQt/JLG1O5zEcYcXSY5zSqr4YVgxsB+pHXTq0i7eDlg=="], + "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=="], @@ -1061,7 +1044,7 @@ "figures": ["figures@3.2.0", "", { "dependencies": { "escape-string-regexp": "^1.0.5" } }, "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg=="], - "file-type": ["file-type@21.3.4", "", { "dependencies": { "@tokenizer/inflate": "^0.4.1", "strtok3": "^10.3.4", "token-types": "^6.1.1", "uint8array-extras": "^1.4.0" } }, "sha512-Ievi/yy8DS3ygGvT47PjSfdFoX+2isQueoYP1cntFW1JLYAuS4GD7NUPGg4zv2iZfV52uDyk5w5Z0TdpRS6Q1g=="], + "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=="], @@ -1075,7 +1058,7 @@ "formdata-polyfill": ["formdata-polyfill@4.0.10", "", { "dependencies": { "fetch-blob": "^3.1.2" } }, "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g=="], - "fs-extra": ["fs-extra@11.3.5", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-eKpRKAovdpZtR1WopLHxlBWvAgPny3c4gX1G5Jhwmmw4XJj0ifSD5qB5TOo8hmA0wlRKDAOAhEE1yVPgs6Fgcg=="], + "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=="], @@ -1099,11 +1082,11 @@ "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=="], - "git-raw-commits": ["git-raw-commits@3.0.0", "", { "dependencies": { "dargs": "^7.0.0", "meow": "^8.1.2", "split2": "^3.2.2" }, "bin": { "git-raw-commits": "cli.js" } }, "sha512-b5OHmZ3vAgGrDn/X0kS+9qCfNKWe4K/jFnhwzVWWg0/k5eLa3060tZShrRg8Dja5kPc+YjS0Gc6y7cRr44Lpjw=="], + "git-raw-commits": ["git-raw-commits@2.0.11", "", { "dependencies": { "dargs": "^7.0.0", "lodash": "^4.17.15", "meow": "^8.0.0", "split2": "^3.0.0", "through2": "^4.0.0" }, "bin": { "git-raw-commits": "cli.js" } }, "sha512-VnctFhw+xfj8Va1xtfEqCUD2XDrbAPSJx+hSrE5K7fGdjZruW7XV+QOrN7LF/RJyvspRiD2I0asWsxFp0ya26A=="], "git-remote-origin-url": ["git-remote-origin-url@2.0.0", "", { "dependencies": { "gitconfiglocal": "^1.0.0", "pify": "^2.3.0" } }, "sha512-eU+GGrZgccNJcsDH5LkXR3PB9M958hxc7sbA8DFJjrv9j4L2P/eZfKhM+QD6wyzpiv+b1BpK0XrYCxkovtjSLw=="], - "git-semver-tags": ["git-semver-tags@5.0.1", "", { "dependencies": { "meow": "^8.1.2", "semver": "^7.0.0" }, "bin": { "git-semver-tags": "cli.js" } }, "sha512-hIvOeZwRbQ+7YEUmCkHqo8FOLQZCEn18yevLHADlFPZY02KJGsu5FZt9YW/lybfK2uhWFI7Qg/07LekJiTv7iA=="], + "git-semver-tags": ["git-semver-tags@4.1.1", "", { "dependencies": { "meow": "^8.0.0", "semver": "^6.0.0" }, "bin": { "git-semver-tags": "cli.js" } }, "sha512-OWyMt5zBe7xFs8vglMmhM9lRQzCWL3WjHtxNNfJTMngGym7pC1kh8sP6jevfydJ6LP3ZvGxfb6ABYgPUM0mtsA=="], "gitconfiglocal": ["gitconfiglocal@1.0.0", "", { "dependencies": { "ini": "^1.3.2" } }, "sha512-spLUXeTAVHxDtKsJc8FkFVgFtMdEN9qPGpL23VfSHx4fP4+Ds097IXLvymbnDH8FnmxX5Nr9bPw3A+AQ6mWEaQ=="], @@ -1121,7 +1104,7 @@ "gzip-size": ["gzip-size@6.0.0", "", { "dependencies": { "duplexer": "^0.1.2" } }, "sha512-ax7ZYomf6jqPTQ4+XCpUGyXKHk5WweS+e05MBO4/y3WJ5RkmPXNKvX+bx1behVILVwr6JSQvZAku021CHPXG3Q=="], - "handlebars": ["handlebars@4.7.9", "", { "dependencies": { "minimist": "^1.2.5", "neo-async": "^2.6.2", "source-map": "^0.6.1", "wordwrap": "^1.0.0" }, "optionalDependencies": { "uglify-js": "^3.1.4" }, "bin": { "handlebars": "bin/handlebars" } }, "sha512-4E71E0rpOaQuJR2A3xDZ+GM1HyWYv1clR58tC8emQNeQe3RH7MAzSbat+V0wG78LQBo6m6bzSG/L4pBuCsgnUQ=="], + "handlebars": ["handlebars@4.7.8", "", { "dependencies": { "minimist": "^1.2.5", "neo-async": "^2.6.2", "source-map": "^0.6.1", "wordwrap": "^1.0.0" }, "optionalDependencies": { "uglify-js": "^3.1.4" }, "bin": { "handlebars": "bin/handlebars" } }, "sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ=="], "hard-rejection": ["hard-rejection@2.1.0", "", {}, "sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA=="], @@ -1155,13 +1138,11 @@ "iconv-lite": ["iconv-lite@0.6.3", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw=="], - "idb-keyval": ["idb-keyval@6.2.2", "", {}, "sha512-yjD9nARJ/jb1g+CvD0tlhUHOrJ9Sy0P8T9MF3YaLlHnSRpwPfpTX0XIvpmw3gAJUmEu3FiICLBDPXVwyEvrleg=="], - "ieee754": ["ieee754@1.2.1", "", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="], "image-q": ["image-q@4.0.0", "", { "dependencies": { "@types/node": "16.9.1" } }, "sha512-PfJGVgIfKQJuq3s0tTDOKtztksibuUEbJQIYT3by6wctQo+Rdlh7ef4evJ5NCdxY4CfMbvFkocEwbl4BF8RlJw=="], - "immutable": ["immutable@5.1.5", "", {}, "sha512-t7xcm2siw+hlUM68I+UEOK+z84RzmN59as9DZ7P1l0994DKUWV7UXBMQZVxaoMSRQ+PBZbHCOoBt7a2wxOMt+A=="], + "immutable": ["immutable@5.1.4", "", {}, "sha512-p6u1bG3YSnINT5RQmx/yRZBpenIl30kVxkTLDyHLIMk0gict704Q9n+thfDI7lTRm9vXdDYutVzXhzcThxTnXA=="], "indent-string": ["indent-string@4.0.0", "", {}, "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg=="], @@ -1181,7 +1162,7 @@ "is-binary-path": ["is-binary-path@2.1.0", "", { "dependencies": { "binary-extensions": "^2.0.0" } }, "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw=="], - "is-core-module": ["is-core-module@2.16.2", "", { "dependencies": { "hasown": "^2.0.3" } }, "sha512-evOr8xfXKxE6qSR0hSXL2r3sd7ALj8+7jQEUvPYcm5sgZFdJ+AYzT6yNmJenvIYQBgIGwfwz08sL8zoL7yq2BA=="], + "is-core-module": ["is-core-module@2.16.1", "", { "dependencies": { "hasown": "^2.0.2" } }, "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w=="], "is-decimal": ["is-decimal@2.0.1", "", {}, "sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A=="], @@ -1219,7 +1200,7 @@ "jackspeak": ["jackspeak@2.3.6", "", { "dependencies": { "@isaacs/cliui": "^8.0.2" }, "optionalDependencies": { "@pkgjs/parseargs": "^0.11.0" } }, "sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ=="], - "jimp": ["jimp@1.6.1", "", { "dependencies": { "@jimp/core": "1.6.1", "@jimp/diff": "1.6.1", "@jimp/js-bmp": "1.6.1", "@jimp/js-gif": "1.6.1", "@jimp/js-jpeg": "1.6.1", "@jimp/js-png": "1.6.1", "@jimp/js-tiff": "1.6.1", "@jimp/plugin-blit": "1.6.1", "@jimp/plugin-blur": "1.6.1", "@jimp/plugin-circle": "1.6.1", "@jimp/plugin-color": "1.6.1", "@jimp/plugin-contain": "1.6.1", "@jimp/plugin-cover": "1.6.1", "@jimp/plugin-crop": "1.6.1", "@jimp/plugin-displace": "1.6.1", "@jimp/plugin-dither": "1.6.1", "@jimp/plugin-fisheye": "1.6.1", "@jimp/plugin-flip": "1.6.1", "@jimp/plugin-hash": "1.6.1", "@jimp/plugin-mask": "1.6.1", "@jimp/plugin-print": "1.6.1", "@jimp/plugin-quantize": "1.6.1", "@jimp/plugin-resize": "1.6.1", "@jimp/plugin-rotate": "1.6.1", "@jimp/plugin-threshold": "1.6.1", "@jimp/types": "1.6.1", "@jimp/utils": "1.6.1" } }, "sha512-hNQh6rZtWfSVWSNVmvq87N5BPJsNH7k7I7qyrXf9DOma9xATQk3fsyHazCQe51nCjdkoWdTmh0vD7bjVSLoxxw=="], + "jimp": ["jimp@1.6.0", "", { "dependencies": { "@jimp/core": "1.6.0", "@jimp/diff": "1.6.0", "@jimp/js-bmp": "1.6.0", "@jimp/js-gif": "1.6.0", "@jimp/js-jpeg": "1.6.0", "@jimp/js-png": "1.6.0", "@jimp/js-tiff": "1.6.0", "@jimp/plugin-blit": "1.6.0", "@jimp/plugin-blur": "1.6.0", "@jimp/plugin-circle": "1.6.0", "@jimp/plugin-color": "1.6.0", "@jimp/plugin-contain": "1.6.0", "@jimp/plugin-cover": "1.6.0", "@jimp/plugin-crop": "1.6.0", "@jimp/plugin-displace": "1.6.0", "@jimp/plugin-dither": "1.6.0", "@jimp/plugin-fisheye": "1.6.0", "@jimp/plugin-flip": "1.6.0", "@jimp/plugin-hash": "1.6.0", "@jimp/plugin-mask": "1.6.0", "@jimp/plugin-print": "1.6.0", "@jimp/plugin-quantize": "1.6.0", "@jimp/plugin-resize": "1.6.0", "@jimp/plugin-rotate": "1.6.0", "@jimp/plugin-threshold": "1.6.0", "@jimp/types": "1.6.0", "@jimp/utils": "1.6.0" } }, "sha512-YcwCHw1kiqEeI5xRpDlPPBGL2EOpBKLwO4yIBJcXWHPj5PnA5urGq0jbyhM5KoNpypQ6VboSoxc9D8HyfvngSg=="], "jiti": ["jiti@2.6.1", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ=="], @@ -1251,29 +1232,29 @@ "kind-of": ["kind-of@6.0.3", "", {}, "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw=="], - "lightningcss": ["lightningcss@1.32.0", "", { "dependencies": { "detect-libc": "^2.0.3" }, "optionalDependencies": { "lightningcss-android-arm64": "1.32.0", "lightningcss-darwin-arm64": "1.32.0", "lightningcss-darwin-x64": "1.32.0", "lightningcss-freebsd-x64": "1.32.0", "lightningcss-linux-arm-gnueabihf": "1.32.0", "lightningcss-linux-arm64-gnu": "1.32.0", "lightningcss-linux-arm64-musl": "1.32.0", "lightningcss-linux-x64-gnu": "1.32.0", "lightningcss-linux-x64-musl": "1.32.0", "lightningcss-win32-arm64-msvc": "1.32.0", "lightningcss-win32-x64-msvc": "1.32.0" } }, "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ=="], + "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=="], - "lightningcss-android-arm64": ["lightningcss-android-arm64@1.32.0", "", { "os": "android", "cpu": "arm64" }, "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg=="], + "lightningcss-android-arm64": ["lightningcss-android-arm64@1.30.2", "", { "os": "android", "cpu": "arm64" }, "sha512-BH9sEdOCahSgmkVhBLeU7Hc9DWeZ1Eb6wNS6Da8igvUwAe0sqROHddIlvU06q3WyXVEOYDZ6ykBZQnjTbmo4+A=="], - "lightningcss-darwin-arm64": ["lightningcss-darwin-arm64@1.32.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ=="], + "lightningcss-darwin-arm64": ["lightningcss-darwin-arm64@1.30.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-ylTcDJBN3Hp21TdhRT5zBOIi73P6/W0qwvlFEk22fkdXchtNTOU4Qc37SkzV+EKYxLouZ6M4LG9NfZ1qkhhBWA=="], - "lightningcss-darwin-x64": ["lightningcss-darwin-x64@1.32.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w=="], + "lightningcss-darwin-x64": ["lightningcss-darwin-x64@1.30.2", "", { "os": "darwin", "cpu": "x64" }, "sha512-oBZgKchomuDYxr7ilwLcyms6BCyLn0z8J0+ZZmfpjwg9fRVZIR5/GMXd7r9RH94iDhld3UmSjBM6nXWM2TfZTQ=="], - "lightningcss-freebsd-x64": ["lightningcss-freebsd-x64@1.32.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig=="], + "lightningcss-freebsd-x64": ["lightningcss-freebsd-x64@1.30.2", "", { "os": "freebsd", "cpu": "x64" }, "sha512-c2bH6xTrf4BDpK8MoGG4Bd6zAMZDAXS569UxCAGcA7IKbHNMlhGQ89eRmvpIUGfKWNVdbhSbkQaWhEoMGmGslA=="], - "lightningcss-linux-arm-gnueabihf": ["lightningcss-linux-arm-gnueabihf@1.32.0", "", { "os": "linux", "cpu": "arm" }, "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw=="], + "lightningcss-linux-arm-gnueabihf": ["lightningcss-linux-arm-gnueabihf@1.30.2", "", { "os": "linux", "cpu": "arm" }, "sha512-eVdpxh4wYcm0PofJIZVuYuLiqBIakQ9uFZmipf6LF/HRj5Bgm0eb3qL/mr1smyXIS1twwOxNWndd8z0E374hiA=="], - "lightningcss-linux-arm64-gnu": ["lightningcss-linux-arm64-gnu@1.32.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ=="], + "lightningcss-linux-arm64-gnu": ["lightningcss-linux-arm64-gnu@1.30.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-UK65WJAbwIJbiBFXpxrbTNArtfuznvxAJw4Q2ZGlU8kPeDIWEX1dg3rn2veBVUylA2Ezg89ktszWbaQnxD/e3A=="], - "lightningcss-linux-arm64-musl": ["lightningcss-linux-arm64-musl@1.32.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg=="], + "lightningcss-linux-arm64-musl": ["lightningcss-linux-arm64-musl@1.30.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-5Vh9dGeblpTxWHpOx8iauV02popZDsCYMPIgiuw97OJ5uaDsL86cnqSFs5LZkG3ghHoX5isLgWzMs+eD1YzrnA=="], - "lightningcss-linux-x64-gnu": ["lightningcss-linux-x64-gnu@1.32.0", "", { "os": "linux", "cpu": "x64" }, "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA=="], + "lightningcss-linux-x64-gnu": ["lightningcss-linux-x64-gnu@1.30.2", "", { "os": "linux", "cpu": "x64" }, "sha512-Cfd46gdmj1vQ+lR6VRTTadNHu6ALuw2pKR9lYq4FnhvgBc4zWY1EtZcAc6EffShbb1MFrIPfLDXD6Xprbnni4w=="], - "lightningcss-linux-x64-musl": ["lightningcss-linux-x64-musl@1.32.0", "", { "os": "linux", "cpu": "x64" }, "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg=="], + "lightningcss-linux-x64-musl": ["lightningcss-linux-x64-musl@1.30.2", "", { "os": "linux", "cpu": "x64" }, "sha512-XJaLUUFXb6/QG2lGIW6aIk6jKdtjtcffUT0NKvIqhSBY3hh9Ch+1LCeH80dR9q9LBjG3ewbDjnumefsLsP6aiA=="], - "lightningcss-win32-arm64-msvc": ["lightningcss-win32-arm64-msvc@1.32.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw=="], + "lightningcss-win32-arm64-msvc": ["lightningcss-win32-arm64-msvc@1.30.2", "", { "os": "win32", "cpu": "arm64" }, "sha512-FZn+vaj7zLv//D/192WFFVA0RgHawIcHqLX9xuWiQt7P0PtdFEVaxgF9rjM/IRYHQXNnk61/H/gb2Ei+kUQ4xQ=="], - "lightningcss-win32-x64-msvc": ["lightningcss-win32-x64-msvc@1.32.0", "", { "os": "win32", "cpu": "x64" }, "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q=="], + "lightningcss-win32-x64-msvc": ["lightningcss-win32-x64-msvc@1.30.2", "", { "os": "win32", "cpu": "x64" }, "sha512-5g1yc73p+iAkid5phb4oVFMB45417DkRevRbt/El/gKXJk4jid+vPFF/AXbxn05Aky8PapwzZrdJShv5C0avjw=="], "lines-and-columns": ["lines-and-columns@1.2.4", "", {}, "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg=="], @@ -1329,12 +1310,14 @@ "mdast-util-to-string": ["mdast-util-to-string@4.0.0", "", { "dependencies": { "@types/mdast": "^4.0.0" } }, "sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg=="], - "mdn-data": ["mdn-data@2.27.1", "", {}, "sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ=="], + "mdn-data": ["mdn-data@2.0.30", "", {}, "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA=="], "memoirist": ["memoirist@0.4.0", "", {}, "sha512-zxTgA0mSYELa66DimuNQDvyLq36AwDlTuVRbnQtB+VuTcKWm5Qc4z3WkSpgsFWHNhexqkIooqpv4hdcqrX5Nmg=="], "meow": ["meow@8.1.2", "", { "dependencies": { "@types/minimist": "^1.2.0", "camelcase-keys": "^6.2.2", "decamelize-keys": "^1.1.0", "hard-rejection": "^2.1.0", "minimist-options": "4.1.0", "normalize-package-data": "^3.0.0", "read-pkg-up": "^7.0.1", "redent": "^3.0.0", "trim-newlines": "^3.0.0", "type-fest": "^0.18.0", "yargs-parser": "^20.2.3" } }, "sha512-r85E3NdZ+mpYk1C6RjPFEMSE+s1iZMuHtsHAqY0DT3jZczl0diWUZ8g6oU7h0M9cD2EL+PzaYghhCLzR0ZNn5Q=="], + "merge2": ["merge2@1.4.1", "", {}, "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg=="], + "micromark": ["micromark@4.0.2", "", { "dependencies": { "@types/debug": "^4.0.0", "debug": "^4.0.0", "decode-named-character-reference": "^1.0.0", "devlop": "^1.0.0", "micromark-core-commonmark": "^2.0.0", "micromark-factory-space": "^2.0.0", "micromark-util-character": "^2.0.0", "micromark-util-chunked": "^2.0.0", "micromark-util-combine-extensions": "^2.0.0", "micromark-util-decode-numeric-character-reference": "^2.0.0", "micromark-util-encode": "^2.0.0", "micromark-util-normalize-identifier": "^2.0.0", "micromark-util-resolve-all": "^2.0.0", "micromark-util-sanitize-uri": "^2.0.0", "micromark-util-subtokenize": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA=="], "micromark-core-commonmark": ["micromark-core-commonmark@2.0.3", "", { "dependencies": { "decode-named-character-reference": "^1.0.0", "devlop": "^1.0.0", "micromark-factory-destination": "^2.0.0", "micromark-factory-label": "^2.0.0", "micromark-factory-space": "^2.0.0", "micromark-factory-title": "^2.0.0", "micromark-factory-whitespace": "^2.0.0", "micromark-util-character": "^2.0.0", "micromark-util-chunked": "^2.0.0", "micromark-util-classify-character": "^2.0.0", "micromark-util-html-tag-name": "^2.0.0", "micromark-util-normalize-identifier": "^2.0.0", "micromark-util-resolve-all": "^2.0.0", "micromark-util-subtokenize": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg=="], @@ -1377,6 +1360,8 @@ "micromark-util-types": ["micromark-util-types@2.0.2", "", {}, "sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA=="], + "micromatch": ["micromatch@4.0.8", "", { "dependencies": { "braces": "^3.0.3", "picomatch": "^2.3.1" } }, "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA=="], + "mime": ["mime@1.6.0", "", { "bin": { "mime": "cli.js" } }, "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg=="], "mime-db": ["mime-db@1.52.0", "", {}, "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="], @@ -1419,12 +1404,14 @@ "node-domexception": ["node-domexception@1.0.0", "", {}, "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ=="], - "node-downloader-helper": ["node-downloader-helper@2.1.11", "", { "bin": { "ndh": "bin/ndh" } }, "sha512-882fH2C9AWdiPCwz/2beq5t8FGMZK9Dx8TJUOIxzMCbvG7XUKM5BuJwN5f0NKo4SCQK6jR4p2TPm54mYGdGchQ=="], + "node-downloader-helper": ["node-downloader-helper@2.1.10", "", { "bin": { "ndh": "bin/ndh" } }, "sha512-8LdieUd4Bqw/CzfZLf30h+1xSAq3riWSDfWKsPJYz8EULoWxjS1vw6BGLYFZDxQgXjDR7UmC9UpQ0oV93U98Fg=="], "node-fetch": ["node-fetch@3.3.2", "", { "dependencies": { "data-uri-to-buffer": "^4.0.0", "fetch-blob": "^3.1.4", "formdata-polyfill": "^4.0.10" } }, "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA=="], "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=="], "node-stream-zip": ["node-stream-zip@1.15.0", "", {}, "sha512-LN4fydt9TqhZhThkZIVQnF9cwjU3qmUH9h78Mx/K7d3VvfRqqwthLwJEUOEL0QPZ0XQmNN7be5Ggit5+4dq3Bw=="], @@ -1463,7 +1450,7 @@ "p-locate": ["p-locate@5.0.0", "", { "dependencies": { "p-limit": "^3.0.2" } }, "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw=="], - "p-queue": ["p-queue@9.2.0", "", { "dependencies": { "eventemitter3": "^5.0.4", "p-timeout": "^7.0.0" } }, "sha512-dWgLE8AH0HjQ9fe74pUkKkvzzYT18Inp4zra3lKHnnwqGvcfcUBrvF2EAVX+envufDNBOzpPq/IBUONDbI7+3g=="], + "p-queue": ["p-queue@9.1.2", "", { "dependencies": { "eventemitter3": "^5.0.1", "p-timeout": "^7.0.0" } }, "sha512-ktsDOALzTYTWWF1PbkNVg2rOt+HaOaMWJMUnt7T3qf5tvZ1L8dBW3tObzprBcXNMKkwj+yFSLqHso0x+UFcJXw=="], "p-timeout": ["p-timeout@7.0.1", "", {}, "sha512-AxTM2wDGORHGEkPCt8yqxOTMgpfbEHqF51f/5fJCmwFC3C/zNcGT63SymH2ttOAaiIws2zVg4+izQCjrakcwHg=="], @@ -1491,8 +1478,6 @@ "path-exists": ["path-exists@4.0.0", "", {}, "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w=="], - "path-expression-matcher": ["path-expression-matcher@1.5.0", "", {}, "sha512-cbrerZV+6rvdQrrD+iGMcZFEiiSrbv9Tfdkvnusy6y0x0GKBXREFg/Y65GhIfm0tnLntThhzCnfKwp1WRjeCyQ=="], - "path-is-absolute": ["path-is-absolute@1.0.1", "", {}, "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg=="], "path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="], @@ -1505,6 +1490,8 @@ "pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="], + "peek-readable": ["peek-readable@4.1.0", "", {}, "sha512-ZI3LnwUv5nOGbQzD9c2iDG6toheuXSZP5esSHBjopsXH4dg19soufvpUGA3uohi5anFtGb2lhAVdHzH6R/Evvg=="], + "perfect-debounce": ["perfect-debounce@2.1.0", "", {}, "sha512-LjgdTytVFXeUgtHZr9WYViYSM/g8MkcTPYDlPa3cDqMirHjKiSZPYd6DoL7pK8AJQr+uWkQvCjHNdiMqsrJs+g=="], "picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="], @@ -1541,6 +1528,8 @@ "pretty-ms": ["pretty-ms@9.3.0", "", { "dependencies": { "parse-ms": "^4.0.0" } }, "sha512-gjVS5hOP+M3wMm5nmNOucbIrqudzs9v/57bWRHQWLYklXqoXKrVfYW2W9+glfGsqtPgpiz5WwyEEB+ksXIx3gQ=="], + "process": ["process@0.11.10", "", {}, "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A=="], + "process-nextick-args": ["process-nextick-args@2.0.1", "", {}, "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="], "prop-types": ["prop-types@15.8.1", "", { "dependencies": { "loose-envify": "^1.4.0", "object-assign": "^4.1.1", "react-is": "^16.13.1" } }, "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg=="], @@ -1549,19 +1538,23 @@ "proxy-from-env": ["proxy-from-env@2.1.0", "", {}, "sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA=="], + "q": ["q@1.5.1", "", {}, "sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw=="], + "qr.js": ["qr.js@0.0.0", "", {}, "sha512-c4iYnWb+k2E+vYpRimHqSu575b1/wKl4XFeJGpFmrJQz5I88v9aY2czh7s0w36srfCM1sXgC/xpoJz5dJfq+OQ=="], "qs": ["qs@6.15.0", "", { "dependencies": { "side-channel": "^1.1.0" } }, "sha512-mAZTtNCeetKMH+pSjrb76NAM8V9a05I9aBZOHztWy/UqcJdQYNsf59vrRKWnojAT9Y+GbIvoTBC++CPHqpDBhQ=="], + "queue-microtask": ["queue-microtask@1.2.3", "", {}, "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A=="], + "quick-lru": ["quick-lru@4.0.1", "", {}, "sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g=="], "rc9": ["rc9@2.1.2", "", { "dependencies": { "defu": "^6.1.4", "destr": "^2.0.3" } }, "sha512-btXCnMmRIBINM2LDZoEmOogIZU7Qe7zn4BpomSKZ/ykbLObuBdvG+mFq11DL6fjH1DRwHhrlgtYWG96bJiC7Cg=="], - "react": ["react@19.2.6", "", {}, "sha512-sfWGGfavi0xr8Pg0sVsyHMAOziVYKgPLNrS7ig+ivMNb3wbCBw3KxtflsGBAwD3gYQlE/AEZsTLgToRrSCjb0Q=="], + "react": ["react@19.2.4", "", {}, "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ=="], - "react-dom": ["react-dom@19.2.6", "", { "dependencies": { "scheduler": "^0.27.0" }, "peerDependencies": { "react": "^19.2.6" } }, "sha512-0prMI+hvBbPjsWnxDLxlCGyM8PN6UuWjEUCYmZhO67xIV9Xasa/r/vDnq+Xyq4Lo27g8QSbO5YzARu0D1Sps3g=="], + "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.1", "", { "peerDependencies": { "react": "^18.0.0 || ^19.0.0" } }, "sha512-BrYwPOdXi5mqkk5lw+Uvt0ThHx32rCt3BkukS4X23A2AIWDPSGX6iaWTc0y9TU/mHDA/6qOSGel+B2ERkOvD1w=="], + "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=="], @@ -1569,7 +1562,7 @@ "react-markdown": ["react-markdown@10.1.0", "", { "dependencies": { "@types/hast": "^3.0.0", "@types/mdast": "^4.0.0", "devlop": "^1.0.0", "hast-util-to-jsx-runtime": "^2.0.0", "html-url-attributes": "^3.0.0", "mdast-util-to-hast": "^13.0.0", "remark-parse": "^11.0.0", "remark-rehype": "^11.0.0", "unified": "^11.0.0", "unist-util-visit": "^5.0.0", "vfile": "^6.0.0" }, "peerDependencies": { "@types/react": ">=18", "react": ">=18" } }, "sha512-qKxVopLT/TyA6BX3Ue5NwabOsAzm0Q7kAPwq6L+wWDwisYs7R8vZ0nRXqq6rkueboxpkjvLGU9fWifiX/ZZFxQ=="], - "react-qr-code": ["react-qr-code@2.0.21", "", { "dependencies": { "prop-types": "^15.8.1", "qr.js": "0.0.0" }, "peerDependencies": { "react": "*" } }, "sha512-xaywjo0eaF4S3LOz6ns5eoPbM2E+q9HYl4VATYpxK4bBniOhQ9noY2RJ9G4SnZFhUwzx63FUT6KdHzfKgUwyuQ=="], + "react-qr-code": ["react-qr-code@2.0.18", "", { "dependencies": { "prop-types": "^15.8.1", "qr.js": "0.0.0" }, "peerDependencies": { "react": "*" } }, "sha512-v1Jqz7urLMhkO6jkgJuBYhnqvXagzceg3qJUWayuCK/c6LTIonpWbwxR1f1APGd4xrW/QcQEovNrAojbUz65Tg=="], "react-refresh": ["react-refresh@0.18.0", "", {}, "sha512-QgT5//D3jfjJb6Gsjxv0Slpj23ip+HtOpnNgnb2S5zU3CB26G/IDPGoy4RJB42wzFE46DRsstbW6tKHoKbhAxw=="], @@ -1579,8 +1572,12 @@ "readable-stream": ["readable-stream@3.6.2", "", { "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", "util-deprecate": "^1.0.1" } }, "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA=="], + "readable-web-to-node-stream": ["readable-web-to-node-stream@3.0.4", "", { "dependencies": { "readable-stream": "^4.7.0" } }, "sha512-9nX56alTf5bwXQ3ZDipHJhusu9NTQJ/CVPtb/XHAJCXihZeitfJvIRS4GqQ/mfIoOE3IelHMrpayVrosdHBuLw=="], + "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=="], + "redent": ["redent@3.0.0", "", { "dependencies": { "indent-string": "^4.0.0", "strip-indent": "^3.0.0" } }, "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg=="], "remark-parse": ["remark-parse@11.0.0", "", { "dependencies": { "@types/mdast": "^4.0.0", "mdast-util-from-markdown": "^2.0.0", "micromark-util-types": "^2.0.0", "unified": "^11.0.0" } }, "sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA=="], @@ -1593,61 +1590,65 @@ "requires-port": ["requires-port@1.0.0", "", {}, "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ=="], - "resolve": ["resolve@1.22.12", "", { "dependencies": { "es-errors": "^1.3.0", "is-core-module": "^2.16.1", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" } }, "sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA=="], + "resolve": ["resolve@1.22.11", "", { "dependencies": { "is-core-module": "^2.16.1", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" } }, "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ=="], "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=="], "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.1.2", "", {}, "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="], "safer-buffer": ["safer-buffer@2.1.2", "", {}, "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="], - "sass": ["sass@1.99.0", "", { "dependencies": { "chokidar": "^4.0.0", "immutable": "^5.1.5", "source-map-js": ">=0.6.2 <2.0.0" }, "optionalDependencies": { "@parcel/watcher": "^2.4.1" }, "bin": { "sass": "sass.js" } }, "sha512-kgW13M54DUB7IsIRM5LvJkNlpH+WhMpooUcaWGFARkF1Tc82v9mIWkCbCYf+MBvpIUBSeSOTilpZjEPr2VYE6Q=="], + "sass": ["sass@1.97.3", "", { "dependencies": { "chokidar": "^4.0.0", "immutable": "^5.0.2", "source-map-js": ">=0.6.2 <2.0.0" }, "optionalDependencies": { "@parcel/watcher": "^2.4.1" }, "bin": { "sass": "sass.js" } }, "sha512-fDz1zJpd5GycprAbu4Q2PV/RprsRtKC/0z82z0JLgdytmcq0+ujJbJ/09bPGDxCLkKY3Np5cRAOcWiVkLXJURg=="], - "sass-embedded": ["sass-embedded@1.99.0", "", { "dependencies": { "@bufbuild/protobuf": "^2.5.0", "colorjs.io": "^0.5.0", "immutable": "^5.1.5", "rxjs": "^7.4.0", "supports-color": "^8.1.1", "sync-child-process": "^1.0.2", "varint": "^6.0.0" }, "optionalDependencies": { "sass-embedded-all-unknown": "1.99.0", "sass-embedded-android-arm": "1.99.0", "sass-embedded-android-arm64": "1.99.0", "sass-embedded-android-riscv64": "1.99.0", "sass-embedded-android-x64": "1.99.0", "sass-embedded-darwin-arm64": "1.99.0", "sass-embedded-darwin-x64": "1.99.0", "sass-embedded-linux-arm": "1.99.0", "sass-embedded-linux-arm64": "1.99.0", "sass-embedded-linux-musl-arm": "1.99.0", "sass-embedded-linux-musl-arm64": "1.99.0", "sass-embedded-linux-musl-riscv64": "1.99.0", "sass-embedded-linux-musl-x64": "1.99.0", "sass-embedded-linux-riscv64": "1.99.0", "sass-embedded-linux-x64": "1.99.0", "sass-embedded-unknown-all": "1.99.0", "sass-embedded-win32-arm64": "1.99.0", "sass-embedded-win32-x64": "1.99.0" }, "bin": { "sass": "dist/bin/sass.js" } }, "sha512-gF/juR1aX02lZHkvwxdF80SapkQeg2fetoDF6gIQkNbSw5YEUFspMkyGTjPjgZSgIHuZpy+Wz4PlebKnLXMjdg=="], + "sass-embedded": ["sass-embedded@1.97.3", "", { "dependencies": { "@bufbuild/protobuf": "^2.5.0", "colorjs.io": "^0.5.0", "immutable": "^5.0.2", "rxjs": "^7.4.0", "supports-color": "^8.1.1", "sync-child-process": "^1.0.2", "varint": "^6.0.0" }, "optionalDependencies": { "sass-embedded-all-unknown": "1.97.3", "sass-embedded-android-arm": "1.97.3", "sass-embedded-android-arm64": "1.97.3", "sass-embedded-android-riscv64": "1.97.3", "sass-embedded-android-x64": "1.97.3", "sass-embedded-darwin-arm64": "1.97.3", "sass-embedded-darwin-x64": "1.97.3", "sass-embedded-linux-arm": "1.97.3", "sass-embedded-linux-arm64": "1.97.3", "sass-embedded-linux-musl-arm": "1.97.3", "sass-embedded-linux-musl-arm64": "1.97.3", "sass-embedded-linux-musl-riscv64": "1.97.3", "sass-embedded-linux-musl-x64": "1.97.3", "sass-embedded-linux-riscv64": "1.97.3", "sass-embedded-linux-x64": "1.97.3", "sass-embedded-unknown-all": "1.97.3", "sass-embedded-win32-arm64": "1.97.3", "sass-embedded-win32-x64": "1.97.3" }, "bin": { "sass": "dist/bin/sass.js" } }, "sha512-eKzFy13Nk+IRHhlAwP3sfuv+PzOrvzUkwJK2hdoCKYcWGSdmwFpeGpWmyewdw8EgBnsKaSBtgf/0b2K635ecSA=="], - "sass-embedded-all-unknown": ["sass-embedded-all-unknown@1.99.0", "", { "dependencies": { "sass": "1.99.0" }, "cpu": [ "!arm", "!x64", "!arm64", ] }, "sha512-qPIRG8Uhjo6/OKyAKixTnwMliTz+t9K6Duk0mx5z+K7n0Ts38NSJz2sjDnc7cA/8V9Lb3q09H38dZ1CLwD+ssw=="], + "sass-embedded-all-unknown": ["sass-embedded-all-unknown@1.97.3", "", { "dependencies": { "sass": "1.97.3" }, "cpu": [ "!arm", "!x64", "!arm64", ] }, "sha512-t6N46NlPuXiY3rlmG6/+1nwebOBOaLFOOVqNQOC2cJhghOD4hh2kHNQQTorCsbY9S1Kir2la1/XLBwOJfui0xg=="], - "sass-embedded-android-arm": ["sass-embedded-android-arm@1.99.0", "", { "os": "android", "cpu": "arm" }, "sha512-EHvJ0C7/VuP78Qr6f8gIUVUmCqIorEQpw2yp3cs3SMg02ZuumlhjXvkTcFBxHmFdFR23vTNk1WnhY6QSeV1nFQ=="], + "sass-embedded-android-arm": ["sass-embedded-android-arm@1.97.3", "", { "os": "android", "cpu": "arm" }, "sha512-cRTtf/KV/q0nzGZoUzVkeIVVFv3L/tS1w4WnlHapphsjTXF/duTxI8JOU1c/9GhRPiMdfeXH7vYNcMmtjwX7jg=="], - "sass-embedded-android-arm64": ["sass-embedded-android-arm64@1.99.0", "", { "os": "android", "cpu": "arm64" }, "sha512-fNHhdnP23yqqieCbAdym4N47AleSwjbNt6OYIYx4DdACGdtERjQB4iOX/TaKsW034MupfF7SjnAAK8w7Ptldtg=="], + "sass-embedded-android-arm64": ["sass-embedded-android-arm64@1.97.3", "", { "os": "android", "cpu": "arm64" }, "sha512-aiZ6iqiHsUsaDx0EFbbmmA0QgxicSxVVN3lnJJ0f1RStY0DthUkquGT5RJ4TPdaZ6ebeJWkboV4bra+CP766eA=="], - "sass-embedded-android-riscv64": ["sass-embedded-android-riscv64@1.99.0", "", { "os": "android", "cpu": "none" }, "sha512-4zqDFRvgGDTL5vTHuIhRxUpXFoh0Cy7Gm5Ywk19ASd8Settmd14YdPRZPmMxfgS1GH292PofV1fq1ifiSEJWBw=="], + "sass-embedded-android-riscv64": ["sass-embedded-android-riscv64@1.97.3", "", { "os": "android", "cpu": "none" }, "sha512-zVEDgl9JJodofGHobaM/q6pNETG69uuBIGQHRo789jloESxxZe82lI3AWJQuPmYCOG5ElfRthqgv89h3gTeLYA=="], - "sass-embedded-android-x64": ["sass-embedded-android-x64@1.99.0", "", { "os": "android", "cpu": "x64" }, "sha512-Uk53k/dGYt04RjOL4gFjZ0Z9DH9DKh8IA8WsXUkNqsxerAygoy3zqRBS2zngfE9K2jiOM87q+1R1p87ory9oQQ=="], + "sass-embedded-android-x64": ["sass-embedded-android-x64@1.97.3", "", { "os": "android", "cpu": "x64" }, "sha512-3ke0le7ZKepyXn/dKKspYkpBC0zUk/BMciyP5ajQUDy4qJwobd8zXdAq6kOkdiMB+d9UFJOmEkvgFJHl3lqwcw=="], - "sass-embedded-darwin-arm64": ["sass-embedded-darwin-arm64@1.99.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-u61/7U3IGLqoO6gL+AHeiAtlTPFwJK1+964U8gp45ZN0hzh1yrARf5O1mivXv8NnNgJvbG2wWJbiNZP0lG/lTg=="], + "sass-embedded-darwin-arm64": ["sass-embedded-darwin-arm64@1.97.3", "", { "os": "darwin", "cpu": "arm64" }, "sha512-fuqMTqO4gbOmA/kC5b9y9xxNYw6zDEyfOtMgabS7Mz93wimSk2M1quQaTJnL98Mkcsl2j+7shNHxIS/qpcIDDA=="], - "sass-embedded-darwin-x64": ["sass-embedded-darwin-x64@1.99.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-j/kkk/NcXdIameLezSfXjgCiBkVcA+G60AXrX768/3g0miK1g7M9dj7xOhCb1i7/wQeiEI3rw2LLuO63xRIn4A=="], + "sass-embedded-darwin-x64": ["sass-embedded-darwin-x64@1.97.3", "", { "os": "darwin", "cpu": "x64" }, "sha512-b/2RBs/2bZpP8lMkyZ0Px0vkVkT8uBd0YXpOwK7iOwYkAT8SsO4+WdVwErsqC65vI5e1e5p1bb20tuwsoQBMVA=="], - "sass-embedded-linux-arm": ["sass-embedded-linux-arm@1.99.0", "", { "os": "linux", "cpu": "arm" }, "sha512-d4IjJZrX2+AwB2YCy1JySwdptJECNP/WfAQLUl8txI3ka8/d3TUI155GtelnoZUkio211PwIeFvvAeZ9RXPQnw=="], + "sass-embedded-linux-arm": ["sass-embedded-linux-arm@1.97.3", "", { "os": "linux", "cpu": "arm" }, "sha512-2lPQ7HQQg4CKsH18FTsj2hbw5GJa6sBQgDsls+cV7buXlHjqF8iTKhAQViT6nrpLK/e8nFCoaRgSqEC8xMnXuA=="], - "sass-embedded-linux-arm64": ["sass-embedded-linux-arm64@1.99.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-btNcFpItcB56L40n8hDeL7sRSMLDXQ56nB5h2deddJx1n60rpKSElJmkaDGHtpkrY+CTtDRV0FZDjHeTJddYew=="], + "sass-embedded-linux-arm64": ["sass-embedded-linux-arm64@1.97.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-IP1+2otCT3DuV46ooxPaOKV1oL5rLjteRzf8ldZtfIEcwhSgSsHgA71CbjYgLEwMY9h4jeal8Jfv3QnedPvSjg=="], - "sass-embedded-linux-musl-arm": ["sass-embedded-linux-musl-arm@1.99.0", "", { "os": "linux", "cpu": "arm" }, "sha512-2gvHOupgIw3ytatXT4nFUow71LFbuOZPEwG+HUzcNQDH8ue4Ez8cr03vsv5MDv3lIjOKcXwDvWD980t18MwkoQ=="], + "sass-embedded-linux-musl-arm": ["sass-embedded-linux-musl-arm@1.97.3", "", { "os": "linux", "cpu": "arm" }, "sha512-cBTMU68X2opBpoYsSZnI321gnoaiMBEtc+60CKCclN6PCL3W3uXm8g4TLoil1hDD6mqU9YYNlVG6sJ+ZNef6Lg=="], - "sass-embedded-linux-musl-arm64": ["sass-embedded-linux-musl-arm64@1.99.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-Hi2bt/IrM5P4FBKz6EcHAlniwfpoz9mnTdvSd58y+avA3SANM76upIkAdSayA8ZGwyL3gZokru1AKDPF9lJDNw=="], + "sass-embedded-linux-musl-arm64": ["sass-embedded-linux-musl-arm64@1.97.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-Lij0SdZCsr+mNRSyDZ7XtJpXEITrYsaGbOTz5e6uFLJ9bmzUbV7M8BXz2/cA7bhfpRPT7/lwRKPdV4+aR9Ozcw=="], - "sass-embedded-linux-musl-riscv64": ["sass-embedded-linux-musl-riscv64@1.99.0", "", { "os": "linux", "cpu": "none" }, "sha512-mKqGvVaJ9rHMqyZsF0kikQe4NO0f4osb67+X6nLhBiVDKvyazQHJ3zJQreNefIE36yL2sjHIclSB//MprzaQDg=="], + "sass-embedded-linux-musl-riscv64": ["sass-embedded-linux-musl-riscv64@1.97.3", "", { "os": "linux", "cpu": "none" }, "sha512-sBeLFIzMGshR4WmHAD4oIM7WJVkSoCIEwutzptFtGlSlwfNiijULp+J5hA2KteGvI6Gji35apR5aWj66wEn/iA=="], - "sass-embedded-linux-musl-x64": ["sass-embedded-linux-musl-x64@1.99.0", "", { "os": "linux", "cpu": "x64" }, "sha512-huhgOMmOc30r7CH7qbRbT9LerSEGSnWuS4CYNOskr9BvNeQp4dIneFufNRGZ7hkOAxUM8DglxIZJN/cyAT95Ew=="], + "sass-embedded-linux-musl-x64": ["sass-embedded-linux-musl-x64@1.97.3", "", { "os": "linux", "cpu": "x64" }, "sha512-/oWJ+OVrDg7ADDQxRLC/4g1+Nsz1g4mkYS2t6XmyMJKFTFK50FVI2t5sOdFH+zmMp+nXHKM036W94y9m4jjEcw=="], - "sass-embedded-linux-riscv64": ["sass-embedded-linux-riscv64@1.99.0", "", { "os": "linux", "cpu": "none" }, "sha512-mevFPIFAVhrH90THifxLfOntFmHtcEKOcdWnep2gJ0X4DVva4AiVIRlQe/7w9JFx5+gnDRE1oaJJkzuFUuYZsA=="], + "sass-embedded-linux-riscv64": ["sass-embedded-linux-riscv64@1.97.3", "", { "os": "linux", "cpu": "none" }, "sha512-l3IfySApLVYdNx0Kjm7Zehte1CDPZVcldma3dZt+TfzvlAEerM6YDgsk5XEj3L8eHBCgHgF4A0MJspHEo2WNfA=="], - "sass-embedded-linux-x64": ["sass-embedded-linux-x64@1.99.0", "", { "os": "linux", "cpu": "x64" }, "sha512-9k7IkULqIZdCIVt4Mboryt6vN8Mjmm3EhI1P3mClU5y5i3wLK5ExC3cbVWk047KsID/fvB1RLslqghXJx5BoxA=="], + "sass-embedded-linux-x64": ["sass-embedded-linux-x64@1.97.3", "", { "os": "linux", "cpu": "x64" }, "sha512-Kwqwc/jSSlcpRjULAOVbndqEy2GBzo6OBmmuBVINWUaJLJ8Kczz3vIsDUWLfWz/kTEw9FHBSiL0WCtYLVAXSLg=="], - "sass-embedded-unknown-all": ["sass-embedded-unknown-all@1.99.0", "", { "dependencies": { "sass": "1.99.0" }, "os": [ "!linux", "!win32", "!darwin", "!android", ] }, "sha512-P7MxiUtL/XzGo3PX0CaB8lNNEFLQWKikPA8pbKytx9ZCLZSDkt2NJcdAbblB/sqMs4AV3EK2NadV8rI/diq3xg=="], + "sass-embedded-unknown-all": ["sass-embedded-unknown-all@1.97.3", "", { "dependencies": { "sass": "1.97.3" }, "os": [ "!linux", "!win32", "!darwin", "!android", ] }, "sha512-/GHajyYJmvb0IABUQHbVHf1nuHPtIDo/ClMZ81IDr59wT5CNcMe7/dMNujXwWugtQVGI5UGmqXWZQCeoGnct8Q=="], - "sass-embedded-win32-arm64": ["sass-embedded-win32-arm64@1.99.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-8whpsW7S+uO8QApKfQuc36m3P9EISzbVZOgC79goob4qGy09u8Gz/rYvw8h1prJDSjltpHGhOzBE6LDz7WvzVw=="], + "sass-embedded-win32-arm64": ["sass-embedded-win32-arm64@1.97.3", "", { "os": "win32", "cpu": "arm64" }, "sha512-RDGtRS1GVvQfMGAmVXNxYiUOvPzn9oO1zYB/XUM9fudDRnieYTcUytpNTQZLs6Y1KfJxgt5Y+giRceC92fT8Uw=="], - "sass-embedded-win32-x64": ["sass-embedded-win32-x64@1.99.0", "", { "os": "win32", "cpu": "x64" }, "sha512-ipuOv1R2K4MHeuCEAZGpuUbAgma4gb0sdacyrTjJtMOy/OY9UvWfVlwErdB09KIkp4fPDpQJDJfvYN6bC8jeNg=="], + "sass-embedded-win32-x64": ["sass-embedded-win32-x64@1.97.3", "", { "os": "win32", "cpu": "x64" }, "sha512-SFRa2lED9UEwV6vIGeBXeBOLKF+rowF3WmNfb/BzhxmdAsKofCXrJ8ePW7OcDVrvNEbTOGwhsReIsF5sH8fVaw=="], - "sax": ["sax@1.6.0", "", {}, "sha512-6R3J5M4AcbtLUdZmRv2SygeVaM7IhrLXu9BmnOGmmACak8fiUtOsYNWUS4uK7upbmHIBbLBeFeI//477BKLBzA=="], + "sax": ["sax@1.4.4", "", {}, "sha512-1n3r/tGXO6b6VXMdFT54SHzT9ytu9yr7TaELowdYpMqY/Ao7EnlQGmAQ1+RatX7Tkkdm6hONI2owqNx2aZj5Sw=="], "scheduler": ["scheduler@0.27.0", "", {}, "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q=="], @@ -1655,9 +1656,9 @@ "semver": ["semver@7.7.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="], - "seroval": ["seroval@1.5.4", "", {}, "sha512-46uFvgrXTVxZcUorgSSRZ4y+ieqLLQRMlG4bnCZKW3qI6BZm7Rg4ntMW4p1mILEEBZWrFlcpp0AyIIlM6jD9iw=="], + "seroval": ["seroval@1.4.2", "", {}, "sha512-N3HEHRCZYn3cQbsC4B5ldj9j+tHdf4JZoYPlcI4rRYu0Xy4qN8MQf1Z08EibzB0WpgRG5BGK08FTrmM66eSzKQ=="], - "seroval-plugins": ["seroval-plugins@1.5.4", "", { "peerDependencies": { "seroval": "^1.0" } }, "sha512-S0xQPhUTefAhNvNWFg0c1J8qJArHt5KdtJ/cFAofo06KD1MVSeFWyl4iiu+ApDIuw0WhjpOfCdgConOfAnLgkw=="], + "seroval-plugins": ["seroval-plugins@1.4.2", "", { "peerDependencies": { "seroval": "^1.0" } }, "sha512-X7p4MEDTi+60o2sXZ4bnDBhgsUYDSkQEvzYZuJyFqWg9jcoPsHts5nrg5O956py2wyt28lUrBxk0M0/wU8URpA=="], "shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "^3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="], @@ -1687,7 +1688,7 @@ "socket.io-parser": ["socket.io-parser@4.2.5", "", { "dependencies": { "@socket.io/component-emitter": "~3.1.0", "debug": "~4.4.1" } }, "sha512-bPMmpy/5WWKHea5Y/jYAP6k74A+hvmRCQaJuJB6I/ML5JZq/KfNieUVo/3Mh7SAqn7TyFdIo6wqYHInG1MU1bQ=="], - "source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="], + "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=="], @@ -1709,6 +1710,8 @@ "stack-trace": ["stack-trace@0.0.10", "", {}, "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg=="], + "standard-version": ["standard-version@9.5.0", "", { "dependencies": { "chalk": "^2.4.2", "conventional-changelog": "3.1.25", "conventional-changelog-config-spec": "2.1.0", "conventional-changelog-conventionalcommits": "4.6.3", "conventional-recommended-bump": "6.1.0", "detect-indent": "^6.0.0", "detect-newline": "^3.1.0", "dotgitignore": "^2.1.0", "figures": "^3.1.0", "find-up": "^5.0.0", "git-semver-tags": "^4.0.0", "semver": "^7.1.1", "stringify-package": "^1.0.1", "yargs": "^16.0.0" }, "bin": { "standard-version": "bin/cli.js" } }, "sha512-3zWJ/mmZQsOaO+fOlsa0+QK90pwhNd042qEcw6hKFNoLFs7peGyvPffpEBbK/DSGPbyOvli0mUIFv5A4qTjh2Q=="], + "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=="], @@ -1717,6 +1720,8 @@ "stringify-entities": ["stringify-entities@4.0.4", "", { "dependencies": { "character-entities-html4": "^2.0.0", "character-entities-legacy": "^3.0.0" } }, "sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg=="], + "stringify-package": ["stringify-package@1.0.1", "", {}, "sha512-sa4DUQsYciMP1xhKWGuFM04fB0LG/9DlluZoSVywUMRNvzid6XucHK0/90xGxRoHrAaROrcHK1aPKaijCtSrhg=="], + "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=="], @@ -1725,8 +1730,6 @@ "strip-indent": ["strip-indent@3.0.0", "", { "dependencies": { "min-indent": "^1.0.0" } }, "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ=="], - "strnum": ["strnum@2.2.3", "", {}, "sha512-oKx6RUCuHfT3oyVjtnrmn19H1SiCqgJSg+54XqURKp5aCMbrXrhLjRN9TjuwMjiYstZ0MzDrHqkGZ5dFTKd+zg=="], - "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=="], @@ -1741,33 +1744,35 @@ "supports-preserve-symlinks-flag": ["supports-preserve-symlinks-flag@1.0.0", "", {}, "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w=="], - "svg-icon-baker": ["svg-icon-baker@2.0.1", "", { "dependencies": { "css-tree": "^3.2.1", "fast-xml-builder": "^1.1.5", "fast-xml-parser": "^5.7.2", "svgo": "^4.0.1" } }, "sha512-1QWVlle2fSUra129CEKpo5sn4hLGa0KCd7v8kX+PkD8e1x8fAQXB5rkc8J8mXTHe6iSzcOS7j4Y2K+q9RaUoNQ=="], - - "svgo": ["svgo@4.0.1", "", { "dependencies": { "commander": "^11.1.0", "css-select": "^5.1.0", "css-tree": "^3.0.1", "css-what": "^6.1.0", "csso": "^5.0.5", "picocolors": "^1.1.1", "sax": "^1.5.0" }, "bin": "./bin/svgo.js" }, "sha512-XDpWUOPC6FEibaLzjfe0ucaV0YrOjYotGJO1WpF0Zd+n6ZGEQUsSugaoLq9QkEZtAfQIxT42UChcssDVPP3+/w=="], + "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=="], "sync-child-process": ["sync-child-process@1.0.2", "", { "dependencies": { "sync-message-port": "^1.0.0" } }, "sha512-8lD+t2KrrScJ/7KXCSyfhT3/hRq78rC0wBFqNJXv3mZyn6hW2ypM05JmlSvtqRbeq6jqA94oHbxAr2vYsJ8vDA=="], "sync-message-port": ["sync-message-port@1.2.0", "", {}, "sha512-gAQ9qrUN/UCypHtGFbbe7Rc/f9bzO88IwrG8TDo/aMKAApKyD6E3W4Cm0EfhfBb6Z6SKt59tTCTfD+n1xmAvMg=="], - "systeminformation": ["systeminformation@5.31.6", "", { "os": "!aix", "bin": { "systeminformation": "lib/cli.js" } }, "sha512-Uv2b2uGGM6ns+26czgW2cYRabYdnswM0ddSOOlryHOaelzsmDSet1iM/NT7VOYxW8x/BW+HkY+b1Ve2pLTSGSA=="], + "systeminformation": ["systeminformation@5.31.5", "", { "os": "!aix", "bin": { "systeminformation": "lib/cli.js" } }, "sha512-5SyLdip4/3alxD4Kh+63bUQTJmu7YMfYQTC+koZy7X73HgNqZSD2P4wOZQWtUncvPvcEmnfIjCoygN4MRoEejQ=="], "tagged-tag": ["tagged-tag@1.0.0", "", {}, "sha512-yEFYrVhod+hdNyx7g5Bnkkb0G6si8HJurOoOEgC8B/O0uXLHlaey/65KRv6cuWBNhBgHKAROVpc7QyYqE5gFng=="], - "tailwind-merge": ["tailwind-merge@3.6.0", "", {}, "sha512-uxL7qAVQriqRQPAyK3pj66VqskWqoZ37PW94jwOTwNfq/z9oyu1V+eqrZqtR2+fCiXdYOZe/Modt8GtvqNzu+w=="], + "tailwind-merge": ["tailwind-merge@3.4.0", "", {}, "sha512-uSaO4gnW+b3Y2aWoWfFpX62vn2sR3skfhbjsEnaBI81WD1wBLlHZe5sWf0AqjksNdYTbGBEd0UasQMT3SNV15g=="], - "tailwindcss": ["tailwindcss@4.3.0", "", {}, "sha512-y6nxMGB1nMW9R6k96e5gdIFzcfL/gTJRNaqGes1YvkLnPVXzWgbqFF2yLC0T8G774n24cx3Pe8XrKoniCOAH+Q=="], + "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.3", "", {}, "sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A=="], + "tapable": ["tapable@2.3.0", "", {}, "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg=="], - "terser": ["terser@5.36.0", "", { "dependencies": { "@jridgewell/source-map": "^0.3.3", "acorn": "^8.8.2", "commander": "^2.20.0", "source-map-support": "~0.5.20" }, "bin": { "terser": "bin/terser" } }, "sha512-IYV9eNMuFAV4THUspIRXkLakHnV6XO7FEdtKjf/mDyrnqUg9LnlOn6/RwRvM9SZjR4GUq8Nk8zj67FzVARr74w=="], + "terser": ["terser@5.46.0", "", { "dependencies": { "@jridgewell/source-map": "^0.3.3", "acorn": "^8.15.0", "commander": "^2.20.0", "source-map-support": "~0.5.20" }, "bin": { "terser": "bin/terser" } }, "sha512-jTwoImyr/QbOWFFso3YoU3ik0jBBDJ6JTOQiy/J2YxVJdZCc+5u7skhNwiOR3FQIygFqVUPHl7qbbxtjW2K3Qg=="], "text-extensions": ["text-extensions@1.9.0", "", {}, "sha512-wiBrwC1EhBelW12Zy26JeOUkQ5mRu+5o8rpsJk5+2t+Y5vE7e842qtZDQ2g1NpX/29HdyFeJ4nSIhI47ENSxlQ=="], "through": ["through@2.3.8", "", {}, "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg=="], - "through2": ["through2@2.0.5", "", { "dependencies": { "readable-stream": "~2.3.6", "xtend": "~4.0.1" } }, "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ=="], + "through2": ["through2@4.0.2", "", { "dependencies": { "readable-stream": "3" } }, "sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw=="], + + "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=="], "tinycolor2": ["tinycolor2@1.6.0", "", {}, "sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw=="], @@ -1783,7 +1788,7 @@ "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=="], - "tough-cookie": ["tough-cookie@6.0.1", "", { "dependencies": { "tldts": "^7.0.5" } }, "sha512-LktZQb3IeoUWB9lqR5EWTHgW/VTITCXg4D21M+lvybRVdylLrRMnqaIONLVb5mav8vM19m44HIcGq4qASeu2Qw=="], + "tough-cookie": ["tough-cookie@6.0.0", "", { "dependencies": { "tldts": "^7.0.5" } }, "sha512-kXuRi1mtaKMrsLUxz3sQYvVl37B0Ns6MzfrtV5DvJceE9bPyspOqk9xxv7XbZWcfLWbFmm997vl83qUWVJA64w=="], "tough-cookie-file-store": ["tough-cookie-file-store@3.3.0", "", { "dependencies": { "tough-cookie": "^6.0.0" } }, "sha512-FbO/cOi/jp4wweo8soVNG/ZjDsgpBZWqaxWwu7gRKvsjg/Qt44kStp87VLfJnin749DlTbZDYvV1wuSr5jly2g=="], @@ -1835,7 +1840,7 @@ "universalify": ["universalify@2.0.1", "", {}, "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw=="], - "unplugin": ["unplugin@3.0.0", "", { "dependencies": { "@jridgewell/remapping": "^2.3.5", "picomatch": "^4.0.3", "webpack-virtual-modules": "^0.6.2" } }, "sha512-0Mqk3AT2TZCXWKdcoaufeXNukv2mTrEZExeXlHIOZXdqYoHHr4n51pymnwV8x2BOVxwXbK2HLlI7usrqMpycdg=="], + "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=="], "unzip-stream": ["unzip-stream@0.3.4", "", { "dependencies": { "binary": "^0.3.0", "mkdirp": "^0.5.1" } }, "sha512-PyofABPVv+d7fL7GOpusx7eRT9YETY2X04PhwbSipdj6bMxVCFJrr+nm0Mxqbf9hUiTin/UsnuFWBXlDZFy0Cw=="], @@ -1861,9 +1866,9 @@ "vfile-message": ["vfile-message@4.0.3", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-stringify-position": "^4.0.0" } }, "sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw=="], - "vite": ["vite@7.3.3", "", { "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-/4XH147Ui7OGTjg3HbdWe5arnZQSbfuRzdr9Ec7TQi5I7R+ir0Rlc9GIvD4v0XZurELqA035KVXJXpR61xhiTA=="], + "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.9.1", "", { "dependencies": { "svg-icon-baker": "2.0.1", "tinyglobby": "^0.2.16" }, "peerDependencies": { "vite": ">=5.0.0" } }, "sha512-g00nlit2havo0VRxpLiPkeJfMYt0DL/RO8X5HHop72rbMEZB5H1Fk7qXLWbTIO2/PkwJ8zSq0+h28ItaE1YQHQ=="], + "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=="], @@ -1911,42 +1916,22 @@ "yallist": ["yallist@3.1.1", "", {}, "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="], - "yaml": ["yaml@2.8.4", "", { "bin": { "yaml": "bin.mjs" } }, "sha512-ml/JPOj9fOQK8RNnWojA67GbZ0ApXAUlN2UQclwv2eVgTgn7O9gg9o7paZWKMp4g0H3nTLtS9LVzhkpOFIKzog=="], - "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=="], "yocto-queue": ["yocto-queue@0.1.0", "", {}, "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q=="], - "zod": ["zod@4.4.3", "", {}, "sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ=="], + "zod": ["zod@4.3.6", "", {}, "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg=="], + + "zod-to-ts": ["zod-to-ts@2.0.0", "", { "peerDependencies": { "typescript": "^5.0.0", "zod": "^3.25.0 || ^4.0.0" } }, "sha512-aHsUgIl+CQutKAxtRNeZslLCLXoeuSq+j5HU7q3kvi/c2KIAo6q4YjT7/lwFfACxLB923ELHYMkHmlxiqFy4lw=="], "zwitch": ["zwitch@2.0.4", "", {}, "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A=="], - "@ap0nia/eden/elysia": ["elysia@1.2.15", "", { "dependencies": { "@sinclair/typebox": "^0.34.15", "cookie": "^1.0.2", "memoirist": "^0.3.0", "openapi-types": "^12.1.3" }, "peerDependencies": { "typescript": ">= 5.0.0" }, "optionalPeers": ["typescript"] }, "sha512-/oUSNb83jIWAGi6uSmbQ7Uy0RSJ9NimbVToSLnYS8jjsGId3zgdHqprsdf4rIMInOmEM8skjsFhZ4x8C5AB6+w=="], - - "@babel/core/@babel/traverse": ["@babel/traverse@7.29.0", "", { "dependencies": { "@babel/code-frame": "^7.29.0", "@babel/generator": "^7.29.0", "@babel/helper-globals": "^7.28.0", "@babel/parser": "^7.29.0", "@babel/template": "^7.28.6", "@babel/types": "^7.29.0", "debug": "^4.3.1" } }, "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA=="], - - "@babel/core/@babel/types": ["@babel/types@7.29.0", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.28.5" } }, "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A=="], - "@babel/core/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], - "@babel/generator/@babel/types": ["@babel/types@7.29.0", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.28.5" } }, "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A=="], - "@babel/helper-compilation-targets/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], - "@babel/parser/@babel/types": ["@babel/types@7.29.0", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.28.5" } }, "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A=="], - - "@babel/template/@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/template/@babel/parser": ["@babel/parser@7.28.6", "", { "dependencies": { "@babel/types": "^7.28.6" }, "bin": "./bin/babel-parser.js" }, "sha512-TeR9zWR18BvbfPmGbLampPMW+uW1NZnJlRuuHso8i87QZNq2JRF9i6RgxRqtEq+wQGsS19NNTWr2duhnE49mfQ=="], - - "@babel/traverse/@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/traverse/@babel/generator": ["@babel/generator@7.28.6", "", { "dependencies": { "@babel/parser": "^7.28.6", "@babel/types": "^7.28.6", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" } }, "sha512-lOoVRwADj8hjf7al89tvQ2a1lf53Z+7tiXMgpZJL3maQPDxh0DgLMN62B2MKUOFcoodBHLMbDM6WAbKgNy5Suw=="], - - "@babel/traverse/@babel/parser": ["@babel/parser@7.28.6", "", { "dependencies": { "@babel/types": "^7.28.6" }, "bin": "./bin/babel-parser.js" }, "sha512-TeR9zWR18BvbfPmGbLampPMW+uW1NZnJlRuuHso8i87QZNq2JRF9i6RgxRqtEq+wQGsS19NNTWr2duhnE49mfQ=="], - "@esbuild-kit/core-utils/esbuild": ["esbuild@0.18.20", "", { "optionalDependencies": { "@esbuild/android-arm": "0.18.20", "@esbuild/android-arm64": "0.18.20", "@esbuild/android-x64": "0.18.20", "@esbuild/darwin-arm64": "0.18.20", "@esbuild/darwin-x64": "0.18.20", "@esbuild/freebsd-arm64": "0.18.20", "@esbuild/freebsd-x64": "0.18.20", "@esbuild/linux-arm": "0.18.20", "@esbuild/linux-arm64": "0.18.20", "@esbuild/linux-ia32": "0.18.20", "@esbuild/linux-loong64": "0.18.20", "@esbuild/linux-mips64el": "0.18.20", "@esbuild/linux-ppc64": "0.18.20", "@esbuild/linux-riscv64": "0.18.20", "@esbuild/linux-s390x": "0.18.20", "@esbuild/linux-x64": "0.18.20", "@esbuild/netbsd-x64": "0.18.20", "@esbuild/openbsd-x64": "0.18.20", "@esbuild/sunos-x64": "0.18.20", "@esbuild/win32-arm64": "0.18.20", "@esbuild/win32-ia32": "0.18.20", "@esbuild/win32-x64": "0.18.20" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA=="], "@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=="], @@ -1955,6 +1940,8 @@ "@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=="], + "@jimp/core/file-type": ["file-type@16.5.4", "", { "dependencies": { "readable-web-to-node-stream": "^3.0.0", "strtok3": "^6.2.4", "token-types": "^4.1.1" } }, "sha512-/yFHK0aGjFEgDJjEKP0pWCplsPFPhwyfwevf/pVxiN0tmE4L9LmwWxWukdJSHdoCli4VgQLehjJtwQBnqmsKcw=="], + "@jimp/core/mime": ["mime@3.0.0", "", { "bin": { "mime": "cli.js" } }, "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A=="], "@jimp/plugin-blit/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], @@ -1995,49 +1982,39 @@ "@node-minify/core/mkdirp": ["mkdirp@3.0.1", "", { "bin": { "mkdirp": "dist/cjs/src/bin.js" } }, "sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg=="], - "@tailwindcss/node/jiti": ["jiti@2.7.0", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ=="], + "@node-minify/terser/terser": ["terser@5.36.0", "", { "dependencies": { "@jridgewell/source-map": "^0.3.3", "acorn": "^8.8.2", "commander": "^2.20.0", "source-map-support": "~0.5.20" }, "bin": { "terser": "bin/terser" } }, "sha512-IYV9eNMuFAV4THUspIRXkLakHnV6XO7FEdtKjf/mDyrnqUg9LnlOn6/RwRvM9SZjR4GUq8Nk8zj67FzVARr74w=="], - "@tailwindcss/oxide-wasm32-wasi/@emnapi/core": ["@emnapi/core@1.10.0", "", { "dependencies": { "@emnapi/wasi-threads": "1.2.1", "tslib": "^2.4.0" }, "bundled": true }, "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw=="], + "@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=="], - "@tailwindcss/oxide-wasm32-wasi/@emnapi/runtime": ["@emnapi/runtime@1.10.0", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA=="], + "@tailwindcss/oxide-wasm32-wasi/@emnapi/runtime": ["@emnapi/runtime@1.8.1", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg=="], - "@tailwindcss/oxide-wasm32-wasi/@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.2.1", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w=="], + "@tailwindcss/oxide-wasm32-wasi/@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.1.0", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ=="], - "@tailwindcss/oxide-wasm32-wasi/@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@1.1.4", "", { "dependencies": { "@tybys/wasm-util": "^0.10.1" }, "peerDependencies": { "@emnapi/core": "^1.7.1", "@emnapi/runtime": "^1.7.1" }, "bundled": true }, "sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow=="], + "@tailwindcss/oxide-wasm32-wasi/@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@1.1.1", "", { "dependencies": { "@emnapi/core": "^1.7.1", "@emnapi/runtime": "^1.7.1", "@tybys/wasm-util": "^0.10.1" }, "bundled": true }, "sha512-p64ah1M1ld8xjWv3qbvFwHiFVWrq1yFvV4f7w+mzaqiR4IlSgkqhcRdHwsGgomwzBH51sRY4NEowLxnaBjcW/A=="], "@tailwindcss/oxide-wasm32-wasi/@tybys/wasm-util": ["@tybys/wasm-util@0.10.1", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg=="], "@tailwindcss/oxide-wasm32-wasi/tslib": ["tslib@2.8.1", "", { "bundled": true }, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], - "@tanstack/router-generator/@babel/types": ["@babel/types@7.29.0", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.28.5" } }, "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A=="], + "@tanstack/react-store/@tanstack/store": ["@tanstack/store@0.8.0", "", {}, "sha512-Om+BO0YfMZe//X2z0uLF2j+75nQga6TpTJgLJQBiq85aOyZNIhkCgleNcud2KQg4k4v9Y9l+Uhru3qWMPGTOzQ=="], - "@tanstack/router-generator/jiti": ["jiti@2.7.0", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ=="], + "@tanstack/router-core/@tanstack/store": ["@tanstack/store@0.8.0", "", {}, "sha512-Om+BO0YfMZe//X2z0uLF2j+75nQga6TpTJgLJQBiq85aOyZNIhkCgleNcud2KQg4k4v9Y9l+Uhru3qWMPGTOzQ=="], "@tanstack/router-generator/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], "@tanstack/router-plugin/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], - "@tanstack/router-utils/@babel/types": ["@babel/types@7.29.0", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.28.5" } }, "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A=="], - - "@tanstack/router-utils/tinyglobby": ["tinyglobby@0.2.16", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.4" } }, "sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg=="], - - "@types/babel__core/@babel/parser": ["@babel/parser@7.28.6", "", { "dependencies": { "@babel/types": "^7.28.6" }, "bin": "./bin/babel-parser.js" }, "sha512-TeR9zWR18BvbfPmGbLampPMW+uW1NZnJlRuuHso8i87QZNq2JRF9i6RgxRqtEq+wQGsS19NNTWr2duhnE49mfQ=="], - - "@types/babel__template/@babel/parser": ["@babel/parser@7.28.6", "", { "dependencies": { "@babel/types": "^7.28.6" }, "bin": "./bin/babel-parser.js" }, "sha512-TeR9zWR18BvbfPmGbLampPMW+uW1NZnJlRuuHso8i87QZNq2JRF9i6RgxRqtEq+wQGsS19NNTWr2duhnE49mfQ=="], - "anymatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], - "babel-dead-code-elimination/@babel/core": ["@babel/core@7.28.6", "", { "dependencies": { "@babel/code-frame": "^7.28.6", "@babel/generator": "^7.28.6", "@babel/helper-compilation-targets": "^7.28.6", "@babel/helper-module-transforms": "^7.28.6", "@babel/helpers": "^7.28.6", "@babel/parser": "^7.28.6", "@babel/template": "^7.28.6", "@babel/traverse": "^7.28.6", "@babel/types": "^7.28.6", "@jridgewell/remapping": "^2.3.5", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", "json5": "^2.2.3", "semver": "^6.3.1" } }, "sha512-H3mcG6ZDLTlYfaSNi0iOKkigqMFvkTKlGUYlD8GW7nNOYRrevuA46iTypPyv+06V3fEmvvazfntkBU34L0azAw=="], - - "babel-dead-code-elimination/@babel/parser": ["@babel/parser@7.28.6", "", { "dependencies": { "@babel/types": "^7.28.6" }, "bin": "./bin/babel-parser.js" }, "sha512-TeR9zWR18BvbfPmGbLampPMW+uW1NZnJlRuuHso8i87QZNq2JRF9i6RgxRqtEq+wQGsS19NNTWr2duhnE49mfQ=="], - "c12/chokidar": ["chokidar@5.0.0", "", { "dependencies": { "readdirp": "^5.0.0" } }, "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw=="], - "chalk/supports-color": ["supports-color@5.5.0", "", { "dependencies": { "has-flag": "^3.0.0" } }, "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow=="], + "chalk/supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="], + + "clean-css/source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="], "compare-func/dot-prop": ["dot-prop@5.3.0", "", { "dependencies": { "is-obj": "^2.0.0" } }, "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q=="], - "concurrently/chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="], + "conventional-changelog-writer/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], "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=="], @@ -2051,12 +2028,18 @@ "engine.io/cookie": ["cookie@0.7.2", "", {}, "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w=="], + "get-pkg-repo/through2": ["through2@2.0.5", "", { "dependencies": { "readable-stream": "~2.3.6", "xtend": "~4.0.1" } }, "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ=="], + "get-pkg-repo/yargs": ["yargs@16.2.0", "", { "dependencies": { "cliui": "^7.0.2", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", "string-width": "^4.2.0", "y18n": "^5.0.5", "yargs-parser": "^20.2.2" } }, "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw=="], + "git-semver-tags/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], + "gitconfiglocal/ini": ["ini@1.3.8", "", {}, "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew=="], "glob/minimatch": ["minimatch@3.1.5", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w=="], + "handlebars/source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="], + "handlebars/wordwrap": ["wordwrap@1.0.0", "", {}, "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q=="], "hosted-git-info/lru-cache": ["lru-cache@6.0.0", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA=="], @@ -2067,12 +2050,8 @@ "http-proxy/eventemitter3": ["eventemitter3@4.0.7", "", {}, "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw=="], - "http-server/chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="], - "image-q/@types/node": ["@types/node@16.9.1", "", {}, "sha512-QpLcX9ZSsq3YYUUnD3nFDY8H7wctAhQj/TFKL8Ya8v5fMm3CFXxo8zStsLAl780ltoYoo1WvKUVGBQK+1ifr7g=="], - "is-core-module/hasown": ["hasown@2.0.3", "", { "dependencies": { "function-bind": "^1.1.2" } }, "sha512-ej4AhfhfL2Q2zpMmLo7U1Uv9+PyhIZpgQLGT1F9miIGmiCJIoCgSmczFdrc97mWT4kVY72KA+WnnhJ5pghSvSg=="], - "load-json-file/pify": ["pify@3.0.0", "", {}, "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg=="], "meow/read-pkg-up": ["read-pkg-up@7.0.1", "", { "dependencies": { "find-up": "^4.1.0", "read-pkg": "^5.2.0", "type-fest": "^0.8.1" } }, "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg=="], @@ -2081,6 +2060,8 @@ "meow/yargs-parser": ["yargs-parser@20.2.9", "", {}, "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w=="], + "micromatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], + "minimist-options/is-plain-obj": ["is-plain-obj@1.1.0", "", {}, "sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg=="], "nypm/citty": ["citty@0.2.0", "", {}, "sha512-8csy5IBFI2ex2hTVpaHN2j+LNE199AgiI7y4dMintrr8i0lQiFn+0AWMZrWdHKIgMOer65f8IThysYhoReqjWA=="], @@ -2103,40 +2084,34 @@ "read-pkg-up/find-up": ["find-up@2.1.0", "", { "dependencies": { "locate-path": "^2.0.0" } }, "sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ=="], + "readable-web-to-node-stream/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=="], + "readdirp/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], + "recast/source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="], + "sass/chokidar": ["chokidar@4.0.3", "", { "dependencies": { "readdirp": "^4.0.1" } }, "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA=="], + "source-map-support/source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="], + + "standard-version/chalk": ["chalk@2.4.2", "", { "dependencies": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", "supports-color": "^5.3.0" } }, "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ=="], + + "standard-version/yargs": ["yargs@16.2.0", "", { "dependencies": { "cliui": "^7.0.2", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", "string-width": "^4.2.0", "y18n": "^5.0.5", "yargs-parser": "^20.2.2" } }, "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw=="], + "string_decoder/safe-buffer": ["safe-buffer@5.2.1", "", {}, "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="], - "svgo/commander": ["commander@11.1.0", "", {}, "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ=="], + "svgo/commander": ["commander@7.2.0", "", {}, "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw=="], "terser/commander": ["commander@2.20.3", "", {}, "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ=="], - "through2/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=="], - - "tough-cookie-file-store/tough-cookie": ["tough-cookie@6.0.0", "", { "dependencies": { "tldts": "^7.0.5" } }, "sha512-kXuRi1mtaKMrsLUxz3sQYvVl37B0Ns6MzfrtV5DvJceE9bPyspOqk9xxv7XbZWcfLWbFmm997vl83qUWVJA64w=="], - "tsx/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=="], "vite/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=="], - "vite-plugin-svg-icons-ng/tinyglobby": ["tinyglobby@0.2.16", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.4" } }, "sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg=="], - "vite-static-assets-plugin/chalk": ["chalk@5.6.2", "", {}, "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA=="], "winston/async": ["async@1.0.0", "", {}, "sha512-5mO7DX4CbJzp9zjaFXusQQ4tzKJARjNB1Ih1pVBi8wkbmXy/xzIDgEMXxWePLzt2OdFwaxfneIlT1nCiXubrPQ=="], - "wrap-ansi/ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], - - "wrap-ansi-cjs/ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], - - "xml2js/sax": ["sax@1.4.4", "", {}, "sha512-1n3r/tGXO6b6VXMdFT54SHzT9ytu9yr7TaELowdYpMqY/Ao7EnlQGmAQ1+RatX7Tkkdm6hONI2owqNx2aZj5Sw=="], - - "@ap0nia/eden/elysia/cookie": ["cookie@1.1.1", "", {}, "sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ=="], - - "@ap0nia/eden/elysia/memoirist": ["memoirist@0.3.1", "", {}, "sha512-lmk4Z45IuVZPT67nxAdD3rAsNExxMEBFXgCeJGJnoLkYOjmZnJ8Hmi+MGdl9oLKtAENFAAgG8FvV3Z8BNiqy8w=="], - "@esbuild-kit/core-utils/esbuild/@esbuild/android-arm": ["@esbuild/android-arm@0.18.20", "", { "os": "android", "cpu": "arm" }, "sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw=="], "@esbuild-kit/core-utils/esbuild/@esbuild/android-arm64": ["@esbuild/android-arm64@0.18.20", "", { "os": "android", "cpu": "arm64" }, "sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ=="], @@ -2187,38 +2162,28 @@ "@isaacs/cliui/wrap-ansi/ansi-styles": ["ansi-styles@6.2.3", "", {}, "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg=="], + "@jimp/core/file-type/strtok3": ["strtok3@6.3.0", "", { "dependencies": { "@tokenizer/token": "^0.3.0", "peek-readable": "^4.1.0" } }, "sha512-fZtbhtvI9I48xDSywd/somNqgUHl2L2cstmXCCif0itOf96jeW18MBSyrLuNicYQVkvpOxkZtkzujiTJ9LW5Jw=="], + + "@jimp/core/file-type/token-types": ["token-types@4.2.1", "", { "dependencies": { "@tokenizer/token": "^0.3.0", "ieee754": "^1.2.1" } }, "sha512-6udB24Q737UD/SDsKAHI9FCRP7Bqc9D/MQUV02ORQg5iskjtLJlZJNdN4kKtcdtwCeWIwIHDGaUsTsCCAa8sFQ=="], + "@node-minify/core/glob/minimatch": ["minimatch@9.0.9", "", { "dependencies": { "brace-expansion": "^2.0.2" } }, "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg=="], - "@tanstack/router-utils/tinyglobby/picomatch": ["picomatch@4.0.4", "", {}, "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A=="], - - "babel-dead-code-elimination/@babel/core/@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-dead-code-elimination/@babel/core/@babel/generator": ["@babel/generator@7.28.6", "", { "dependencies": { "@babel/parser": "^7.28.6", "@babel/types": "^7.28.6", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" } }, "sha512-lOoVRwADj8hjf7al89tvQ2a1lf53Z+7tiXMgpZJL3maQPDxh0DgLMN62B2MKUOFcoodBHLMbDM6WAbKgNy5Suw=="], - - "babel-dead-code-elimination/@babel/core/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], + "@node-minify/terser/terser/commander": ["commander@2.20.3", "", {}, "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ=="], "c12/chokidar/readdirp": ["readdirp@5.0.0", "", {}, "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ=="], - "chalk/supports-color/has-flag": ["has-flag@3.0.0", "", {}, "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw=="], - - "concurrently/chalk/ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], - - "concurrently/chalk/supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="], - "csso/css-tree/mdn-data": ["mdn-data@2.0.28", "", {}, "sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g=="], "dotgitignore/find-up/locate-path": ["locate-path@3.0.0", "", { "dependencies": { "p-locate": "^3.0.0", "path-exists": "^3.0.0" } }, "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A=="], + "get-pkg-repo/through2/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=="], + "get-pkg-repo/yargs/cliui": ["cliui@7.0.4", "", { "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.0", "wrap-ansi": "^7.0.0" } }, "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ=="], "get-pkg-repo/yargs/yargs-parser": ["yargs-parser@20.2.9", "", {}, "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w=="], "hosted-git-info/lru-cache/yallist": ["yallist@4.0.0", "", {}, "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="], - "http-server/chalk/ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], - - "http-server/chalk/supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="], - "meow/read-pkg-up/find-up": ["find-up@4.1.0", "", { "dependencies": { "locate-path": "^5.0.0", "path-exists": "^4.0.0" } }, "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw=="], "meow/read-pkg-up/read-pkg": ["read-pkg@5.2.0", "", { "dependencies": { "@types/normalize-package-data": "^2.4.0", "normalize-package-data": "^2.5.0", "parse-json": "^5.0.0", "type-fest": "^0.6.0" } }, "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg=="], @@ -2233,7 +2198,13 @@ "sass/chokidar/readdirp": ["readdirp@4.1.2", "", {}, "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg=="], - "through2/readable-stream/string_decoder": ["string_decoder@1.1.1", "", { "dependencies": { "safe-buffer": "~5.1.0" } }, "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg=="], + "standard-version/chalk/ansi-styles": ["ansi-styles@3.2.1", "", { "dependencies": { "color-convert": "^1.9.0" } }, "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA=="], + + "standard-version/chalk/supports-color": ["supports-color@5.5.0", "", { "dependencies": { "has-flag": "^3.0.0" } }, "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow=="], + + "standard-version/yargs/cliui": ["cliui@7.0.4", "", { "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.0", "wrap-ansi": "^7.0.0" } }, "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ=="], + + "standard-version/yargs/yargs-parser": ["yargs-parser@20.2.9", "", {}, "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w=="], "tsx/esbuild/@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.27.2", "", { "os": "aix", "cpu": "ppc64" }, "sha512-GZMB+a0mOMZs4MpDbj8RJp4cw+w1WV5NYD6xzgvzUJ5Ek2jerwfO2eADyI6ExDSUED+1X8aMbegahsJi+8mgpw=="], @@ -2287,8 +2258,6 @@ "tsx/esbuild/@esbuild/win32-x64": ["@esbuild/win32-x64@0.27.2", "", { "os": "win32", "cpu": "x64" }, "sha512-sRdU18mcKf7F+YgheI/zGf5alZatMUTKj/jNS6l744f9u3WFu4v7twcUI9vu4mknF4Y9aDlblIie0IM+5xxaqQ=="], - "vite-plugin-svg-icons-ng/tinyglobby/picomatch": ["picomatch@4.0.4", "", {}, "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A=="], - "vite/esbuild/@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.27.2", "", { "os": "aix", "cpu": "ppc64" }, "sha512-GZMB+a0mOMZs4MpDbj8RJp4cw+w1WV5NYD6xzgvzUJ5Ek2jerwfO2eADyI6ExDSUED+1X8aMbegahsJi+8mgpw=="], "vite/esbuild/@esbuild/android-arm": ["@esbuild/android-arm@0.27.2", "", { "os": "android", "cpu": "arm" }, "sha512-DVNI8jlPa7Ujbr1yjU2PfUSRtAUZPG9I1RwW4F4xFB1Imiu2on0ADiI/c3td+KmDtVKNbi+nffGDQMfcIMkwIA=="], @@ -2341,19 +2310,13 @@ "vite/esbuild/@esbuild/win32-x64": ["@esbuild/win32-x64@0.27.2", "", { "os": "win32", "cpu": "x64" }, "sha512-sRdU18mcKf7F+YgheI/zGf5alZatMUTKj/jNS6l744f9u3WFu4v7twcUI9vu4mknF4Y9aDlblIie0IM+5xxaqQ=="], - "wrap-ansi-cjs/ansi-styles/color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="], - - "wrap-ansi/ansi-styles/color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="], - "@node-minify/core/glob/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="], - "concurrently/chalk/ansi-styles/color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="], - "dotgitignore/find-up/locate-path/p-locate": ["p-locate@3.0.0", "", { "dependencies": { "p-limit": "^2.0.0" } }, "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ=="], "dotgitignore/find-up/locate-path/path-exists": ["path-exists@3.0.0", "", {}, "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ=="], - "http-server/chalk/ansi-styles/color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="], + "get-pkg-repo/through2/readable-stream/string_decoder": ["string_decoder@1.1.1", "", { "dependencies": { "safe-buffer": "~5.1.0" } }, "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg=="], "meow/read-pkg-up/find-up/locate-path": ["locate-path@5.0.0", "", { "dependencies": { "p-locate": "^4.1.0" } }, "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g=="], @@ -2367,16 +2330,12 @@ "read-pkg-up/find-up/locate-path/path-exists": ["path-exists@3.0.0", "", {}, "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ=="], - "wrap-ansi-cjs/ansi-styles/color-convert/color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="], + "standard-version/chalk/ansi-styles/color-convert": ["color-convert@1.9.3", "", { "dependencies": { "color-name": "1.1.3" } }, "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg=="], - "wrap-ansi/ansi-styles/color-convert/color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="], - - "concurrently/chalk/ansi-styles/color-convert/color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="], + "standard-version/chalk/supports-color/has-flag": ["has-flag@3.0.0", "", {}, "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw=="], "dotgitignore/find-up/locate-path/p-locate/p-limit": ["p-limit@2.3.0", "", { "dependencies": { "p-try": "^2.0.0" } }, "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w=="], - "http-server/chalk/ansi-styles/color-convert/color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="], - "meow/read-pkg-up/find-up/locate-path/p-locate": ["p-locate@4.1.0", "", { "dependencies": { "p-limit": "^2.2.0" } }, "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A=="], "meow/read-pkg-up/read-pkg/normalize-package-data/hosted-git-info": ["hosted-git-info@2.8.9", "", {}, "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw=="], @@ -2385,6 +2344,8 @@ "read-pkg-up/find-up/locate-path/p-locate/p-limit": ["p-limit@1.3.0", "", { "dependencies": { "p-try": "^1.0.0" } }, "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q=="], + "standard-version/chalk/ansi-styles/color-convert/color-name": ["color-name@1.1.3", "", {}, "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw=="], + "meow/read-pkg-up/find-up/locate-path/p-locate/p-limit": ["p-limit@2.3.0", "", { "dependencies": { "p-try": "^2.0.0" } }, "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w=="], "read-pkg-up/find-up/locate-path/p-locate/p-limit/p-try": ["p-try@1.0.0", "", {}, "sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww=="], diff --git a/package.json b/package.json index 913be66..0f246cb 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "email": "work@simeonradivoev.com", "url": "https://simeonradivoev.com" }, - "version": "1.6.0", + "version": "1.5.0", "description": "Game Launcher", "icon": "./src/mainview/assets/icon.svg", "main": "./src/bun/index.ts", @@ -18,9 +18,6 @@ }, "packageManager": "bun@1.3.9", "type": "module", - "workspaces": [ - "./src/packages/gameflow-sdk" - ], "scripts": { "dev": "NODE_ENV=development bun run build:vite && conc 'bun run ./scripts/dev.ts'", "dev:hmr": "PUBLIC_ACCESS=true conc -k 'bun run hmr' 'bun run ./scripts/dev.ts'", @@ -30,7 +27,6 @@ "build:prod:vite": "NODE_ENV=production bun run build:vite", "build:dev:vite": "NODE_ENV=development bun run build:vite", "build": "bun run build:vite && bun run ./scripts/package-bun.ts", - "build:non-compiled": "bun run build:vite && NON_COMPILED=true bun run ./scripts/package-bun.ts", "build:prod": "NODE_ENV=production bun run build", "build:linux": "TARGET=bun-linux-x64 bun run build", "openapi-ts": "bun run ./scripts/romm/openapi-ts.ts", @@ -46,71 +42,66 @@ "flatpak:install": "bun run flatpak:build && flatpak --user install --reinstall \"$PWD/.config/flatpak/repo\" com.simeonradivoev.gameflow-deck", "build:prod:appimage": "bun run build:prod && bun run ./scripts/build-appimage.ts", "build:dev:appimage": "bun run build && bun run ./scripts/build-appimage.ts", - "version:generate": "commit-and-tag-version --sign", + "version:generate": "standard-version --sign", "package:Linux": "bun run build:prod:appimage", "package:Windows": "bun run build:prod", "download:chromium": "bun scripts/download-chromium.ts --out=./bin/chromium", "download:nwjs": "bun scripts/download-nw.ts", "build:audiosprites": "bun ./scripts/generate-audio-sprites.ts", "tsc": "tsc --noEmit", - "publish:sdk": "bun publish --cwd ./src/packages/gameflow-sdk/ --access public" + "build:sdk": "bun ./scripts/build-sdk.ts", + "publish:sdk": "bun build:sdk && bun publish --cwd ./dist-sdk/ --access public" }, "dependencies": { "7zip-bin": "^5.2.0", "@auth/core": "^0.34.3", - "@elysiajs/cors": "^1.4.2", - "@elysiajs/eden": "^1.4.9", - "@jimp/wasm-webp": "^1.6.1", + "@elysiajs/cors": "^1.4.1", + "@elysiajs/eden": "^1.4.6", + "@jimp/wasm-webp": "^1.6.0", "@phalcode/ts-igdb-client": "^1.0.26", "cheerio": "^1.2.0", - "conf": "^15.1.0", - "drizzle-orm": "^0.45.2", - "elysia": "^1.4.28", - "fs-extra": "^11.3.5", + "conf": "^15.0.2", + "drizzle-orm": "^0.45.1", + "elysia": "^1.4.22", + "fs-extra": "^11.3.3", "get-folder-size": "^5.0.0", "ini": "^6.0.0", - "jimp": "^1.6.1", + "jimp": "^1.6.0", "mustache": "^4.2.0", "node-7z": "^3.0.0", "node-disk-info": "^1.3.0", - "node-downloader-helper": "^2.1.11", + "node-downloader-helper": "^2.1.10", "node-stream-zip": "^1.15.0", "node-unrar-js": "^2.0.2", "open": "^11.0.0", - "p-queue": "^9.2.0", + "p-queue": "^9.1.2", "pathe": "^2.0.3", "slugify": "^1.6.9", "smol-toml": "^1.6.1", - "systeminformation": "^5.31.6", - "tapable": "^2.3.3", - "tough-cookie": "^6.0.1", + "systeminformation": "^5.31.5", + "tapable": "^2.3.0", + "tough-cookie": "^6.0.0", "tough-cookie-file-store": "^3.3.0", "unzip-stream": "^0.3.4", "webview-bun": "^2.4.0", - "zod": "^4.4.3" - }, - "overrides": { - "@tanstack/router-generator": { - "zod": "^3.23.8" - } + "zod": "^4.3.6" }, "devDependencies": { - "@ap0nia/eden": "^1.6.1", + "@ap0nia/eden": "^1.0.0-next.22", "@ap0nia/eden-tanstack-query": "^1.0.0-next.22", "@emulatorjs/emulatorjs": "^4.2.3", - "@hey-api/openapi-ts": "^0.91.1", + "@hey-api/openapi-ts": "^0.91.0", "@noriginmedia/norigin-spatial-navigation": "^3.1.0", "@tailwindcss/typography": "^0.5.19", - "@tailwindcss/vite": "^4.3.0", - "@tanstack/react-form": "^1.32.0", - "@tanstack/react-query": "^5.100.10", - "@tanstack/react-query-devtools": "^5.100.10", - "@tanstack/react-query-persist-client": "^5.100.10", - "@tanstack/react-router": "^1.169.2", - "@tanstack/react-router-devtools": "^1.166.13", - "@tanstack/react-router-ssr-query": "^1.166.12", - "@tanstack/router-plugin": "^1.167.35", - "@tanstack/zod-adapter": "^1.166.9", + "@tailwindcss/vite": "^4.1.18", + "@tanstack/react-form": "^1.28.0", + "@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", + "@tanstack/zod-adapter": "^1.162.4", "@types/adm-zip": "^0.5.8", "@types/audiosprite": "^0.7.3", "@types/bun": "latest", @@ -121,42 +112,43 @@ "@types/mustache": "^4.2.6", "@types/node-7z": "^2.1.11", "@types/rclone.js": "^0.6.3", - "@types/react": "^19.2.14", + "@types/react": "^19.2.9", "@types/react-dom": "^19.2.3", "@types/unzip-stream": "^0.3.4", - "@vitejs/plugin-react": "^5.2.0", - "adm-zip": "^0.5.17", + "@vitejs/plugin-react": "^5.1.2", + "adm-zip": "^0.5.16", "animate.css": "^4.1.1", "app-builder-bin": "^5.0.0-alpha.13", "audiosprite": "^0.7.2", "babel-plugin-react-compiler": "^1.0.0", "classnames": "^2.5.1", - "commit-and-tag-version": "^12.7.3", "concurrently": "^9.2.1", "cross-env": "^10.1.0", - "daisyui": "^5.5.19", - "drizzle-kit": "^0.31.10", + "daisyui": "^5.5.14", + "drizzle-kit": "^0.31.9", + "dts-bundle-generator": "^9.5.1", "eden-tanstack-query": "^0.0.9", "howler": "^2.2.4", - "idb-keyval": "^6.2.2", "lucide-react": "^0.563.0", "pretty-bytes": "^7.1.0", "pretty-ms": "^9.3.0", - "react": "^19.2.6", - "react-dom": "^19.2.6", - "react-error-boundary": "^6.1.1", + "react": "^19.2.4", + "react-dom": "^19.2.4", + "react-error-boundary": "^6.1.0", "react-hot-toast": "^2.6.0", "react-markdown": "^10.1.0", - "react-qr-code": "^2.0.21", - "sass-embedded": "^1.99.0", - "tailwind-merge": "^3.6.0", - "tailwindcss": "^4.3.0", + "react-qr-code": "^2.0.18", + "sass-embedded": "^1.97.3", + "standard-version": "^9.5.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.3", - "vite-plugin-svg-icons-ng": "^1.9.1", + "vite": "^7.3.1", + "vite-plugin-svg-icons-ng": "^1.5.2", "vite-static-assets-plugin": "^1.2.2", - "vite-tsconfig-paths": "^6.1.1" + "vite-tsconfig-paths": "^6.1.1", + "zod-to-ts": "^2.0.0" } -} \ No newline at end of file +} diff --git a/scripts/build-sdk.ts b/scripts/build-sdk.ts new file mode 100644 index 0000000..11ee929 --- /dev/null +++ b/scripts/build-sdk.ts @@ -0,0 +1,64 @@ +import path from 'node:path'; +import appPkg from '../package.json'; +import sdkTsConfig from './sdk/sdk.tsconfig.json'; +import sdkPackage from './sdk/package.json'; +import { emptyDir } from 'fs-extra'; +import { generateDtsBundle } from 'dts-bundle-generator'; +import { zodToTs, createAuxiliaryTypeStore, printNode } from 'zod-to-ts'; +import fs from 'node:fs/promises'; + +import * as types from './sdk/sdk'; + +const zodTypeRegex = /z\.infer/gm; + +async function generateApiDeclarations () +{ + const tmpConfigPath = "./scripts/sdk/sdk.tsconfig.json"; + const outDir = path.join(path.dirname(tmpConfigPath), sdkTsConfig.compilerOptions.outDir); + await emptyDir(outDir); + + const results = generateDtsBundle([{ + filePath: './scripts/sdk/sdk.ts', + output: { + inlineDeclareGlobals: true, + sortNodes: true, + } + },], { preferredConfigPath: './scripts/sdk/sdk.tsconfig.json' }); + + const auxiliaryTypeStore = createAuxiliaryTypeStore(); + + await Bun.write('./dist-sdk/index.d.ts', results.map(r => + { + const result = r; + return result.replaceAll(zodTypeRegex, (e, name) => + { + const schema = types[name as keyof typeof types]; + if (schema) + { + try + { + const { node } = zodToTs(schema as any, { auxiliaryTypeStore, unrepresentable: 'any' }); + return printNode(node); + } catch (error) + { + console.error(error); + return e; + } + } + return e; + }); + })); + + const pkg = { + ...sdkPackage, + license: appPkg.license, + version: appPkg.version, + repository: appPkg.repository, + author: appPkg.author, + peerDependencies: appPkg.dependencies + }; + await Bun.write(path.join(outDir, 'package.json'), JSON.stringify(pkg, null, 3)); + await fs.cp('./scripts/sdk/README.md', path.join(outDir, 'README.md')); +} + +await generateApiDeclarations(); \ No newline at end of file diff --git a/scripts/dev.ts b/scripts/dev.ts index 1331f36..ffc843c 100644 --- a/scripts/dev.ts +++ b/scripts/dev.ts @@ -85,13 +85,6 @@ watch("./src/bun", { recursive: true }, (event, filename) => restart(); }); -watch("./src/packages", { recursive: true }, (event, filename) => -{ - if (restarting) return; - console.log(`[watcher] ${event}: ${filename} — restarting...`); - restart(); -}); - let server: Bun.Subprocess | undefined = spawnServer(); if (!process.env.HEADLESS) { diff --git a/src/packages/gameflow-sdk/README.md b/scripts/sdk/README.md similarity index 53% rename from src/packages/gameflow-sdk/README.md rename to scripts/sdk/README.md index 8338233..7ac9193 100644 --- a/src/packages/gameflow-sdk/README.md +++ b/scripts/sdk/README.md @@ -13,18 +13,3 @@ The package must expose a main script gameflow will import and validate. It must For the plugin to show up in the UI for download. It must be published to NPM with the `gameflow-plugin` keyword. Gameflow uses bun to install plugins as packages from npmjs. Follow publishing instruction check the [NPM Docs](https://docs.npmjs.com/packages-and-modules/contributing-packages-to-the-registry) - -## Dependencies - -Peer dependencies will not be installed when the run adds the plugin package. They are provided by gameflow. -All peer dependencies can be marked as external as gameflow provides it. There is a helper build script that does all that for you, to run it use. - -`bunx gameflow-build --entry=index.ts` - -supported arguments are -`--entry` the entry of the app to build -`--outdir` Where to build. Default is 'dist' -`--minify` Minify the code. Default is 'false' -`--sourcemap` Include a source map. Default is 'none' - -If you want to include dependencies that gameflow does not provide you have to bundle them in. Gameflow does not load dependencies for you. diff --git a/scripts/sdk/package.json b/scripts/sdk/package.json new file mode 100644 index 0000000..17d855e --- /dev/null +++ b/scripts/sdk/package.json @@ -0,0 +1,9 @@ +{ + "name": "@simeonradivoev/gameflow-sdk", + "types": "index.d.ts", + "description": "plugin SDK for the Gameflow Deck Launcher", + "keywords": [ + "gameflow", + "sdk" + ] +} \ No newline at end of file diff --git a/scripts/sdk/sdk.ts b/scripts/sdk/sdk.ts new file mode 100644 index 0000000..6568653 --- /dev/null +++ b/scripts/sdk/sdk.ts @@ -0,0 +1,18 @@ +import { SettingsType } from '@/shared/constants'; +import Conf from 'conf'; +import { AppEventMap } from '../../src/bun/types/types'; +import EventEmitter from "node:events"; +import { TaskQueue } from '@/bun/api/task-queue'; + +export * from '../../src/bun/types/types.schema'; +export * from '../../src/bun/types/types'; +export * from '../../src/bun/api/hooks/app'; +export * from '../../src/shared/constants'; +export * from '../../src/shared/types'; +export * from '../../src/shared/utils'; + +export declare const config: Conf; +export declare let events: EventEmitter; +export declare let taskQueue: TaskQueue; + +export { }; \ No newline at end of file diff --git a/src/packages/gameflow-sdk/sdk.tsconfig.json b/scripts/sdk/sdk.tsconfig.json similarity index 52% rename from src/packages/gameflow-sdk/sdk.tsconfig.json rename to scripts/sdk/sdk.tsconfig.json index 707544a..8da436e 100644 --- a/src/packages/gameflow-sdk/sdk.tsconfig.json +++ b/scripts/sdk/sdk.tsconfig.json @@ -17,6 +17,26 @@ "outDir": "../../dist-sdk", "types": [ "node" - ] + ], + "paths": { + "@/*": [ + "../../src/*" + ], + "~/*": [ + "../../*" + ], + "@shared/*": [ + "../../src/shared/*" + ], + "@clients/*": [ + "../../src/clients/*" + ], + "@schema/*": [ + "../../src/bun/api/schema/*" + ], + "@queries/*": [ + "../../src/mainview/scripts/queries/*" + ] + } } } \ No newline at end of file diff --git a/src/bun/api/app.ts b/src/bun/api/app.ts index 4695726..db06c81 100644 --- a/src/bun/api/app.ts +++ b/src/bun/api/app.ts @@ -1,5 +1,5 @@ -import { TaskQueue, AppEventMap } from "@simeonradivoev/gameflow-sdk"; +import { TaskQueue } from "./task-queue"; import { Database } from "bun:sqlite"; import { CookieJar } from 'tough-cookie'; import FileCookieStore from 'tough-cookie-file-store'; @@ -8,7 +8,7 @@ import { migrate } from "drizzle-orm/bun-sqlite/migrator"; import { BunSQLiteDatabase, drizzle } from "drizzle-orm/bun-sqlite"; import Conf from "conf"; import projectPackage from '~/package.json'; -import { SettingsType, SettingsSchema } from '@simeonradivoev/gameflow-sdk/shared'; +import { SettingsSchema, SettingsType } from "@shared/constants"; import { client } from "@clients/romm/client.gen"; import * as schema from "@schema/app"; import cacheSchema from "@schema/cache"; @@ -24,6 +24,7 @@ import controls from './controls/controls'; import { RunAPIServer } from "./rpc"; import { RunBunServer } from "../server"; import ReloadPluginsJob from "./jobs/reload-plugins-job"; +import { AppEventMap } from "../types/types"; export let config: Conf; export let customEmulators: Conf>; @@ -116,13 +117,6 @@ export async function cleanup () cleannedUp = true; } -/** Reset the cleanup flags. This is mainly used by tests since they run the same app. */ -export async function resetCleanup () -{ - cleaningUp = false; - cleannedUp = false; -} - export async function reloadDatabase () { await ensureDir(config.get('downloadPath')); diff --git a/src/bun/api/auth.ts b/src/bun/api/auth.ts index 2cd6e3f..47ea019 100644 --- a/src/bun/api/auth.ts +++ b/src/bun/api/auth.ts @@ -138,12 +138,6 @@ export async function checkLoginAndRefreshTwitch () export async function checkLoginAndRefreshRomm () { - //TODO: move to plugin logic - if (plugins.plugins['com.simeonradivoev.gameflow.romm'].config?.get('clientApiToken')) - { - return { hasLogin: true }; - } - const access_token = await secrets.get({ service: 'gameflow', name: 'romm_access_token' }); if (!access_token) { diff --git a/src/bun/api/cache.ts b/src/bun/api/cache.ts index 04abd1e..cdad6b1 100644 --- a/src/bun/api/cache.ts +++ b/src/bun/api/cache.ts @@ -1,7 +1,7 @@ import { eq } from "drizzle-orm"; import { cache } from "./app"; import cacheSchema from "@schema/cache"; -import { GithubReleaseSchema } from '@simeonradivoev/gameflow-sdk/shared'; +import { GithubReleaseSchema } from "@/shared/constants"; import PQueue from "p-queue"; import z from "zod"; @@ -11,8 +11,7 @@ export const CACHE_KEYS = { STORE_GAME_MANIFEST: 'store-game-manifest' } as const; -// we aggressively cache github data so burst of calls is fine. -export const githubRequestQueue = new PQueue({ intervalCap: 60, interval: 1000 * 60 * 60, strict: true }); +export const githubRequestQueue = new PQueue({ intervalCap: 10, interval: 1000 * 60 * 10, strict: true }); export async function getOrCached (key: string, getter: (lastValue: T | undefined) => Promise, options?: { expireMs?: number; force?: boolean; }): Promise { diff --git a/src/bun/api/controls/windows.ts b/src/bun/api/controls/windows.ts index 2621c26..40fc7d9 100644 --- a/src/bun/api/controls/windows.ts +++ b/src/bun/api/controls/windows.ts @@ -72,6 +72,7 @@ export class GamepadWindows implements IGamepadBackend private index: number; private buffer = new ArrayBuffer(16); private view = new DataView(this.buffer); + private prevButtons = 0; private currButtons = 0; constructor(index = 0) { this.index = index; } diff --git a/src/bun/api/drives.ts b/src/bun/api/drives.ts index 99452d8..a7f0565 100644 --- a/src/bun/api/drives.ts +++ b/src/bun/api/drives.ts @@ -1,7 +1,7 @@ import si from 'systeminformation'; import fs from 'node:fs'; import os from "node:os"; -import { Drive } from '@simeonradivoev/gameflow-sdk/shared'; +import { Drive } from '@/shared/types'; async function getAccess (path: string) { diff --git a/src/bun/api/emulatorjs/emulatorjs.ts b/src/bun/api/emulatorjs/emulatorjs.ts index d733d34..d770a43 100644 --- a/src/bun/api/emulatorjs/emulatorjs.ts +++ b/src/bun/api/emulatorjs/emulatorjs.ts @@ -5,7 +5,7 @@ import z from "zod"; import path from 'node:path'; import { config, events, plugins } from "../app"; import { getLocalGame, updateLocalLastPlayed } from "../games/services/statusService"; -import { SaveFileChange } from "@simeonradivoev/gameflow-sdk/shared"; +import { SaveFileChange } from "@/shared/types"; // TODO: use the retroarch cores based on ES-DE export const cores: Record = { diff --git a/src/bun/api/games/collections.ts b/src/bun/api/games/collections.ts index ae31430..1a49a12 100644 --- a/src/bun/api/games/collections.ts +++ b/src/bun/api/games/collections.ts @@ -1,6 +1,6 @@ import Elysia, { status } from "elysia"; import { plugins } from "../app"; -import { FrontEndCollection } from "@simeonradivoev/gameflow-sdk/shared"; +import { FrontEndCollection } from "@/shared/types"; export default new Elysia() .get('/collections', async () => diff --git a/src/bun/api/games/games.ts b/src/bun/api/games/games.ts index d922b36..1b73e78 100644 --- a/src/bun/api/games/games.ts +++ b/src/bun/api/games/games.ts @@ -4,8 +4,7 @@ import { and, desc, eq, getTableColumns, inArray, like, sql } from "drizzle-orm" import z from "zod"; import * as schema from "@schema/app"; import fs from "node:fs/promises"; -import { SERVER_URL } from "@shared/constants"; -import { CommandEntry, DownloadLookupEntry, DownloadsLookupFilterValues, GameListFilterSchema } from '@simeonradivoev/gameflow-sdk/shared'; +import { GameListFilterSchema, SERVER_URL } from "@shared/constants"; import { InstallJob } from "../jobs/install-job"; import path from "node:path"; import { convertLocalToFrontend, getLocalGameMatch, getSourceGameDetailed } from "./services/utils"; @@ -23,7 +22,7 @@ import { LaunchGameJob } from "../jobs/launch-game-job"; import { cores } from "../emulatorjs/emulatorjs"; import { findEmulatorPluginIntegration } from "../store/services/emulatorsService"; import { ImportJob } from "../jobs/import-job"; -import { EmulatorSourceEntryType, EmulatorSystem, FrontEndFilterLists, FrontEndFilterSets, FrontEndGameType, FrontEndGameTypeDetailedEmulator, FrontEndGameTypeWithIds, FrontEndId, GameLookup } from "@simeonradivoev/gameflow-sdk/shared"; +import { EmulatorSourceEntryType, EmulatorSystem, FrontEndFilterLists, FrontEndFilterSets, FrontEndGameType, FrontEndGameTypeDetailedEmulator, FrontEndGameTypeWithIds, FrontEndId, GameLookup } from "@/shared/types"; // A custom jimp that supports webp const Jimp = createJimp({ @@ -454,18 +453,18 @@ export default new Elysia() }, { params: z.object({ id: z.string(), source: z.string() }), }) - .post('/game/:source/:id/install', async ({ params: { id, source }, body }) => + .post('/game/:source/:id/install', async ({ params: { id, source }, body: { downloadId } }) => { if (!taskQueue.findJob(InstallJob.query({ source, id }), InstallJob)) { - return taskQueue.enqueue(InstallJob.query({ source, id }), new InstallJob(id, source, body)); + return taskQueue.enqueue(InstallJob.query({ source, id }), new InstallJob(id, source, { downloadId })); } else { return status('Not Implemented'); } }, { params: z.object({ id: z.string(), source: z.string() }), - body: z.object({ downloadId: z.string().optional() }).optional(), + body: z.object({ downloadId: z.string().optional() }), response: z.any() }) .delete('/game/:source/:id/install', async ({ params: { id, source } }) => @@ -512,25 +511,7 @@ export default new Elysia() await plugins.hooks.games.gameLookup.promise(matches, { source, id }); return Array.from(matches.values()).flatMap(m => m); }) - .get('/game/:source/:id/commands', async ({ params: { id, source }, set }) => - { - const validCommands = await getValidLaunchCommandsForGame(source, id); - if (validCommands instanceof Error) - { - return errorToResponse(validCommands, set); - } - return validCommands as { - commands: CommandEntry[]; - gameId: FrontEndId; - source?: string; - sourceId?: string; - } | undefined; - }, { - response: z.object({ - commands: z.custom().array() - }) - }) - .post('/game/:source/:id/play', async ({ params: { id, source }, body: { command_id }, set }) => + .post('/game/:source/:id/play', async ({ params: { id, source }, body, set }) => { const validCommands = await getValidLaunchCommandsForGame(source, id); if (validCommands) @@ -543,7 +524,7 @@ export default new Elysia() { try { - const validCommand = command_id ? validCommands.commands.find(c => c.id === command_id) : validCommands.commands[0]; + const validCommand = body.command_id ? validCommands.commands.find(c => c.id === body.command_id) : validCommands.commands[0]; if (validCommand) { // launch command waits for the game to exit, we don't want that. @@ -694,10 +675,7 @@ export default new Elysia() .post('/add/custom', async ({ body: { source, id, platformId, gamePath } }) => { if (taskQueue.hasActiveOfType(ImportJob)) return status("Conflict", "Import Job Already Running"); - const data = await taskQueue.enqueue(ImportJob.query({ source, id }), new ImportJob(source, id, gamePath, platformId), { - throwOnCancel: true - - }); + const data = await taskQueue.enqueue(ImportJob.id, new ImportJob(source, id, gamePath, platformId), true); return { source: 'local', id: data.localId }; }, { body: z.object({ @@ -706,41 +684,4 @@ export default new Elysia() gamePath: z.string(), platformId: z.number() }) - }).get('/downloads/lookup', async ({ query: { search, page, rows, orderBy, sortDirection, source } }) => - { - const matches = new Map(); - await plugins.hooks.games.downloadsLookup.promise(matches, { search, page, rows, orderBy, sortDirection, source }); - const allValues = Array.from(matches.values()); - return { hadMatchers: matches.size > 0, matches: allValues.flatMap(m => m.items), totalCount: allValues.reduce((p, c) => p + c.count, 0) }; - }, { - query: z.object({ - search: z.string().optional(), - page: z.coerce.number().optional(), - rows: z.coerce.number().optional(), - orderBy: z.string().optional(), - sortDirection: z.literal(["desc", "asc"]).optional(), - source: z.string().optional() - }) - }).get('/download/lookup/:source/:id', async ({ params: { source, id } }) => - { - const match = await plugins.hooks.games.downloadLookup.promise({ source, id }); - if (!match) return status("Not Found"); - return match; - }).get('/download/file/info', async ({ query: { file_url } }) => - { - const response = await fetch(file_url, { method: "HEAD" }); - if (!response.ok) return status('Internal Server Error', response.statusText); - return { size: Number(response.headers.get('content-length')), content_type: response.headers.get('content-type') }; - }, { - query: z.object({ file_url: z.url() }) - }).get('/download/lookup/filters', async () => - { - const filters: DownloadsLookupFilterValues = { - source: [], - orderBy: [] - }; - - await plugins.hooks.games.downloadsLookupFilters.promise({ filters }); - - return filters; }); \ No newline at end of file diff --git a/src/bun/api/games/platforms.ts b/src/bun/api/games/platforms.ts index 10aaf42..de888ba 100644 --- a/src/bun/api/games/platforms.ts +++ b/src/bun/api/games/platforms.ts @@ -4,7 +4,7 @@ import { and, count, eq, getTableColumns, not, notExists, or } from "drizzle-orm import { config, db, plugins } from "../app"; import * as schema from "@schema/app"; import { findPlatform } from "./services/utils"; -import { FrontEndPlatformType } from "@simeonradivoev/gameflow-sdk/shared"; +import { FrontEndPlatformType } from "@/shared/types"; export default new Elysia() .get('/platforms', async () => diff --git a/src/bun/api/games/services/launchGameService.ts b/src/bun/api/games/services/launchGameService.ts index 490850d..248d6f2 100644 --- a/src/bun/api/games/services/launchGameService.ts +++ b/src/bun/api/games/services/launchGameService.ts @@ -6,7 +6,7 @@ import { config, taskQueue } from '../../app'; import { LaunchGameJob } from '../../jobs/launch-game-job'; import { getStoreEmulatorPackage } from '../../store/services/gamesService'; import { getOrCachedScoopPackage } from '../../store/services/emulatorsService'; -import { CommandEntry, EmulatorSourceEntryType, FrontEndId } from '@simeonradivoev/gameflow-sdk/shared'; +import { CommandEntry, EmulatorSourceEntryType, FrontEndId } from '@/shared/types'; export async function launchCommand (validCommand: CommandEntry, id: FrontEndId, source?: string, sourceId?: string) { diff --git a/src/bun/api/games/services/statusService.ts b/src/bun/api/games/services/statusService.ts index 1eaed5b..05bade3 100644 --- a/src/bun/api/games/services/statusService.ts +++ b/src/bun/api/games/services/statusService.ts @@ -8,10 +8,9 @@ import z from "zod"; import { InstallJob, InstallJobStates } from "../../jobs/install-job"; import { LaunchGameJob } from "../../jobs/launch-game-job"; import * as appSchema from "@schema/app"; -import { RPC_URL } from "@/shared/constants"; -import { DownloadSourceSchema } from '@simeonradivoev/gameflow-sdk/shared'; +import { DownloadSourceSchema, RPC_URL } from "@/shared/constants"; import { host } from "@/bun/utils/host"; -import { CommandEntry, FrontEndId, GameLookup, GameStatusType, LocalDownloadFileEntry } from "@simeonradivoev/gameflow-sdk/shared"; +import { CommandEntry, FrontEndId, GameLookup, GameStatusType, LocalDownloadFileEntry } from "@/shared/types"; export class CommandSearchError extends Error { @@ -116,15 +115,11 @@ export async function update (source: string, id: string) const paths_screenshots: string[] = [...sourceGame.paths_screenshots.map(s => `${RPC_URL(host)}${s}`)]; if (paths_screenshots.length <= 0 && sourceGame.igdb_id) { - const matches = new Map(); - await plugins.hooks.games.gameLookup.promise(matches, { source: 'igdb', id: String(sourceGame.igdb_id) }); - if (matches.size > 0) + const matches: GameLookup[] = []; + await plugins.hooks.games.gameLookup.promise({ source: 'igdb', id: String(sourceGame.igdb_id), matches }); + if (matches.length > 0) { - const firstMatches = matches.values().next().value; - if (firstMatches && firstMatches.length > 0) - { - paths_screenshots.push(...firstMatches[0].screenshotUrls); - } + paths_screenshots.push(...matches[0].screenshotUrls); } } @@ -249,31 +244,7 @@ export async function getValidLaunchCommandsForGame (source: string, id: string) commands: commands.filter(c => c.valid), gameId: { id: String(localGame.id), source: 'local' }, source: localGame.source ?? source, - sourceId: localGame.source_id ? String(localGame.source_id) : id, - }; - } - else - { - return new CommandSearchError('missing-emulator', `Missing One Of Emulators: ${Array.from(new Set(commands.filter(e => e.emulator && e.emulator !== "OS-SHELL").map(e => e.emulator))).join(', ')}`); - } - } else if (source === 'emulator') - { - const commands = await plugins.hooks.games.buildLaunchCommands.promise({ - source, - sourceId: id, - id: { source: source, id: id }, - systemSlug: "", - gamePath: null - }); - - if (commands instanceof Error || !commands) return commands; - - const validCommand = commands.find(c => c.valid); - if (validCommand) - { - return { - commands: commands.filter(c => c.valid), - gameId: { id, source } + sourceId: String(localGame.source_id) ?? id, }; } else diff --git a/src/bun/api/games/services/utils.ts b/src/bun/api/games/services/utils.ts index 9bef2f4..fd4b2d9 100644 --- a/src/bun/api/games/services/utils.ts +++ b/src/bun/api/games/services/utils.ts @@ -8,7 +8,7 @@ import { RPC_URL } from "@shared/constants"; import { hashFile } from "@/bun/utils"; import { host } from "@/bun/utils/host"; import * as emulatorSchema from "@schema/emulators"; -import { DownloadFileEntry, FrontEndGameType, FrontEndGameTypeDetailed, GameLookup, LocalDownloadFileEntry, LocalGameMetadata, ProgressStats } from "@simeonradivoev/gameflow-sdk/shared"; +import { DownloadFileEntry, FrontEndGameType, FrontEndGameTypeDetailed, GameLookup, LocalDownloadFileEntry, LocalGameMetadata } from "@/shared/types"; export async function calculateSize (installPath: string | null) { @@ -467,40 +467,4 @@ export async function createLocalGame (info: { }); return id; -} - -export async function downloadGame (ctx: { - downloads: DownloadFileEntry[], - auth?: string, - id: string, - abortSignal?: AbortSignal, - setProgress?: (progress: number, state: "download" | "extract", info: Partial>) => void, - extract_path?: string; - path_fs?: string; - -}): Promise -{ - const downloadedFiles = await plugins.hooks.downloadFiles.promise({ - id: ctx.id, - auth: ctx.auth, - files: ctx.downloads, - downloadPath: config.get('downloadPath'), - abortSignal: ctx.abortSignal, - updateProgress: (stats) => ctx.setProgress?.(stats.progress, 'download', stats) - }); - - if (!downloadedFiles) - { - return; - } - - const finalFiles = await plugins.hooks.postDownloadFiles.promise({ - files: downloadedFiles.files, - source: downloadedFiles.source, - extract_path: ctx.extract_path, - downloadPath: config.get('downloadPath'), - path_fs: ctx.path_fs - }) ?? downloadedFiles.files; - - return finalFiles; } \ No newline at end of file diff --git a/src/bun/api/hooks/app.ts b/src/bun/api/hooks/app.ts new file mode 100644 index 0000000..bd549ca --- /dev/null +++ b/src/bun/api/hooks/app.ts @@ -0,0 +1,12 @@ +import AuthHooks from "./auth"; +import EmulatorHooks from "./emulators"; +import GameHooks from "./games"; +import StoreHooks from "./store"; + +export default class GameflowHooks +{ + games = new GameHooks(); + emulators = new EmulatorHooks(); + auth = new AuthHooks(); + store = new StoreHooks(); +} \ No newline at end of file diff --git a/src/packages/gameflow-sdk/hooks/auth.ts b/src/bun/api/hooks/auth.ts similarity index 81% rename from src/packages/gameflow-sdk/hooks/auth.ts rename to src/bun/api/hooks/auth.ts index cb8dd1b..992d91e 100644 --- a/src/packages/gameflow-sdk/hooks/auth.ts +++ b/src/bun/api/hooks/auth.ts @@ -1,6 +1,5 @@ - +import { DownloadFileEntry } from "@/shared/types"; import { AsyncSeriesHook } from "tapable"; -import { DownloadFileEntry } from "../shared"; export default class AuthHooks { diff --git a/src/packages/gameflow-sdk/hooks/emulators.ts b/src/bun/api/hooks/emulators.ts similarity index 73% rename from src/packages/gameflow-sdk/hooks/emulators.ts rename to src/bun/api/hooks/emulators.ts index d852d06..402bb21 100644 --- a/src/packages/gameflow-sdk/hooks/emulators.ts +++ b/src/bun/api/hooks/emulators.ts @@ -1,11 +1,9 @@ - -import { EmulatorPostInstallContextType } from "../index"; -import { DownloadFileEntry, EmulatorSourceEntryType, EmulatorSystem } from "../shared"; +import { EmulatorPostInstallContext } from "@/bun/types/types"; +import { DownloadFileEntry, EmulatorSourceEntryType, EmulatorSystem } from "@/shared/types"; import { AsyncSeriesBailHook, AsyncSeriesHook } from "tapable"; export default class EmulatorHooks { - /** Download emulator bios files */ fetchBiosDownload = new AsyncSeriesBailHook<[ctx: { emulator: string; systems: EmulatorSystem[]; @@ -15,10 +13,8 @@ export default class EmulatorHooks /** * Triggered when emulator is downloaded or updated */ - emulatorPostInstall = new AsyncSeriesHook<[ctx: EmulatorPostInstallContextType], { emulator: string; }>(['ctx']); - /** Find locations of emulators on the system. Be it already installed ones or ones downloaded by the store. */ + emulatorPostInstall = new AsyncSeriesHook<[ctx: EmulatorPostInstallContext], { emulator: string; }>(['ctx']); findEmulatorSource = new AsyncSeriesHook<[ctx: { emulator: string; sources: EmulatorSourceEntryType[]; }]>(['ctx']); - /** Match emulators for a given system */ findEmulatorForSystem = new AsyncSeriesHook<[ctx: { system: string; emulators: string[]; }]>(['ctx']); constructor() @@ -28,7 +24,7 @@ export default class EmulatorHooks { return { ...tap, - fn: async (ctx: EmulatorPostInstallContextType, ...rest: any[]) => + fn: async (ctx: EmulatorPostInstallContext, ...rest: any[]) => { if (ctx.emulator === tap.emulator) { diff --git a/src/packages/gameflow-sdk/hooks/games.ts b/src/bun/api/hooks/games.ts similarity index 67% rename from src/packages/gameflow-sdk/hooks/games.ts rename to src/bun/api/hooks/games.ts index 314b138..bb1f4bc 100644 --- a/src/packages/gameflow-sdk/hooks/games.ts +++ b/src/bun/api/hooks/games.ts @@ -1,32 +1,30 @@ - -import { EmulatorPackageType, GameListFilterType, CommandEntry, DownloadInfo, EmulatorSourceEntryType, EmulatorSupport, EmulatorSystem, FrontEndCollection, FrontEndFilterSets, FrontEndGameType, FrontEndGameTypeDetailed, FrontEndGameTypeWithIds, FrontEndId, FrontEndPlatformType, GameLookup, SaveFileChange, SaveSlots, DownloadLookupEntry, DownloadLookupDetails, DownloadsLookupFilterValues, DownloadsLookupFilter } from '../shared'; -import { SyncBailHook, AsyncSeriesHook, AsyncSeriesBailHook, AsyncSeriesWaterfallHook } from 'tapable'; +import { EmulatorPackageType, GameListFilterType } from '@/shared/constants'; +import { CommandEntry, DownloadInfo, EmulatorSourceEntryType, EmulatorSupport, EmulatorSystem, FrontEndCollection, FrontEndFilterSets, FrontEndGameType, FrontEndGameTypeDetailed, FrontEndGameTypeWithIds, FrontEndId, FrontEndPlatformType, GameLookup, SaveFileChange, SaveSlots } from '@/shared/types'; +import { SyncBailHook, AsyncSeriesHook, AsyncSeriesBailHook, Hook, AsyncSeriesWaterfallHook } from 'tapable'; export default class GameHooks { - /** Build commands the game can be launched with. */ buildLaunchCommands = new AsyncSeriesBailHook<[ctx: { source: string | null; sourceId: string | null; id: FrontEndId; systemSlug: string; gamePath: string | null, - /** The glob pattern for the main executable of the game */ mainGlob?: string | null, }], CommandEntry[] | Error | undefined>(['ctx']); /** override the launch command for an emulator + * @param ctx.autoValidCommands The auto generated command for example based on the ES-DE listing + * @param ctx.emulator The emulator ID if any + * @param ctx.game.source The source of the game + * @param ctx.game.sourceId The ID of the source. This could be for example the ROMM ID the game was * @returns The argument list to be used when running the emulator. * If no emulator bin in the command entry is found the actual command will be used as the bin. */ emulatorLaunch = new AsyncSeriesBailHook<[ctx: { - /** The auto generated command for example based on the ES-DE listing */ autoValidCommand: CommandEntry; - /** Don't actually launch just see if it can be launched */ dryRun: boolean, game: { - /** The source of the game */ source?: string; - /** The ID of the source. This could be for example the ROMM ID the game was */ sourceId?: string; id: FrontEndId; platformSlug?: string; @@ -43,36 +41,34 @@ export default class GameHooks }], EmulatorSupport | undefined, { emulator: string; }>(['ctx']); /** * Fetches and returns a list of games converted to frontend. + * @param ctx.localGameIds This is local game ids in the format '@' */ fetchGames = new AsyncSeriesHook<[ctx: { query: GameListFilterType; games: FrontEndGameTypeWithIds[]; }]>(['ctx']); - /** Return all filters the users can apply for a give source. */ fetchFilters = new AsyncSeriesHook<[ctx: { source?: string; filters: FrontEndFilterSets; }]>(['ctx']); - /** Get game metadata */ fetchGame = new AsyncSeriesBailHook<[ctx: { source: string; localGame?: FrontEndGameTypeDetailed; id: string; }], FrontEndGameTypeDetailed | undefined>(['ctx']); - /** Search for a given game based on the igdb id or ra id. */ searchGame = new AsyncSeriesBailHook<[ctx: { source: string; igdb_id?: number; ra_id?: number; }], FrontEndGameTypeDetailed | undefined>(['ctx']); - /** Get download file URLs */ + /** Get download file URLs + * @param ctx.checksum Check if file already exists using checksums + */ fetchDownloads = new AsyncSeriesBailHook<[ctx: { source: string; id: string; - /** If there are multiple downloads, use the one with same ID */ downloadId?: string; }], DownloadInfo[] | undefined>(['ctx']); - /** Get the paths to rom files. This is mainly used for emulator js. */ fetchRomFiles = new AsyncSeriesBailHook<[ctx: { source: string; id: string; @@ -90,7 +86,6 @@ export default class GameHooks source: string; id: string; }], FrontEndPlatformType | undefined>(['ctx']); - /** Lookup a given platform with a given slug or id. This may or may not exist. */ platformLookup = new AsyncSeriesBailHook<[ctx: { source?: string; id?: string; @@ -101,23 +96,6 @@ export default class GameHooks name?: string; family_name?: string; } | undefined>(['ctx']); - /** Lookup downloads based on a search pattern. - * This is just downloads. Doesn't actually have to be a game. - * This is mainly used to manually add games from outside sources */ - downloadsLookup = new AsyncSeriesWaterfallHook<[matches: Map, ctx: { - page?: number; - rows?: number; - } & DownloadsLookupFilter]>(['matches', 'ctx']); - /** List all available filters */ - downloadsLookupFilters = new AsyncSeriesHook<[ctx: { - filters: DownloadsLookupFilterValues; - }]>(['ctx']); - /** Look for the files for a download the user can pick from */ - downloadLookup = new AsyncSeriesBailHook<[ctx: { source: string, id: string; }], DownloadLookupDetails | undefined>(['ctx']); - /** Look up game metadata based on a search */ gameLookup = new AsyncSeriesWaterfallHook<[matches: Map, ctx: { source?: string, id?: string; @@ -126,7 +104,6 @@ export default class GameHooks fetchPlatforms = new AsyncSeriesHook<[ctx: { platforms: FrontEndPlatformType[]; }]>(['ctx']); - /** Called before the game is played. */ prePlay = new AsyncSeriesHook<[ctx: { source: string, id: string; @@ -138,25 +115,20 @@ export default class GameHooks }; }]>(["ctx"]); /** - * Called after the game process has finished. + * @param changedSaveFiles Auto detected changed files. This is mainly used to see what changed during gameplay + * @param validChangedSaveFiles This will be final valid changes to be saved using save integrations like rclone */ postPlay = new AsyncSeriesHook<[ctx: { source: string, id: string; saveFolderSlots?: SaveSlots; - /** Auto detected changed files. This is mainly used to see what changed during gameplay */ changedSaveFiles: { subPath: string, cwd: string; }[], - /** This will be final valid changes to be saved using save integrations like rclone */ validChangedSaveFiles: Record, - /** The command that was used to launch the game */ command: CommandEntry; gameInfo: { platformSlug?: string; }; }]>(["ctx"]); - /** Called after game install - * This includes game being downloaded and registered in the database. - */ postInstall = new AsyncSeriesHook<[ctx: { source: string, id: string; diff --git a/src/packages/gameflow-sdk/hooks/store.ts b/src/bun/api/hooks/store.ts similarity index 86% rename from src/packages/gameflow-sdk/hooks/store.ts rename to src/bun/api/hooks/store.ts index c7f43e5..b08cee5 100644 --- a/src/packages/gameflow-sdk/hooks/store.ts +++ b/src/bun/api/hooks/store.ts @@ -1,4 +1,5 @@ -import { FrontEndEmulator, FrontEndEmulatorDetailed, FrontEndGameTypeDetailed, EmulatorDownloadInfoType } from "../shared"; +import { EmulatorDownloadInfoType } from "@/shared/constants"; +import { FrontEndEmulator, FrontEndEmulatorDetailed, FrontEndGameTypeDetailed } from "@/shared/types"; import { AsyncSeriesBailHook, AsyncSeriesHook } from "tapable"; export default class StoreHooks diff --git a/src/bun/api/jobs/bios-download-job.ts b/src/bun/api/jobs/bios-download-job.ts index 7a4edba..be46c5f 100644 --- a/src/bun/api/jobs/bios-download-job.ts +++ b/src/bun/api/jobs/bios-download-job.ts @@ -1,44 +1,35 @@ -import { IJob, JobContext } from "@simeonradivoev/gameflow-sdk/task-queue"; +import z from "zod"; +import { IJob, JobContext } from "../task-queue"; import { config, plugins } from "../app"; import { simulateProgress } from "@/bun/utils"; import { Downloader } from "@/bun/utils/downloader"; import path from 'node:path'; import { ensureDir } from "fs-extra"; import { buildStoreFrontendEmulatorSystems, getStoreEmulatorPackage } from "../store/services/gamesService"; -import { DownloadJobData } from "@simeonradivoev/gameflow-sdk/shared"; -interface BiosDownloadJobData extends DownloadJobData -{ - emulator: string; -} - -export class BiosDownloadJob implements IJob +export class BiosDownloadJob implements IJob, "download"> { static id = "bios-download-job" as const; + static dataSchema = z.object({ emulator: z.string() }); static query = (q: { id: string; }) => `${BiosDownloadJob.id}-${q.id}`; group: string = "bios-download"; - data: BiosDownloadJobData; + emulator: string; dryRun: boolean; constructor(emulator: string, init?: { dryRun?: boolean; }) { - this.data = { - emulator, - name: "Download Emulator Bios" - }; + this.emulator = emulator; this.dryRun = init?.dryRun ?? false; } - async start (context: JobContext, BiosDownloadJobData, "download">) + async start (context: JobContext, "download">, z.infer, "download">) { - const emulator = await getStoreEmulatorPackage(this.data.emulator); + const emulator = await getStoreEmulatorPackage(this.emulator); if (!emulator) throw new Error("Could Not Find Emulator"); - this.data.name = `${emulator.name} Bios`; - this.data.preview_url = emulator.logo; const systems = await buildStoreFrontendEmulatorSystems(emulator); - const biosFolder = path.join(config.get('downloadPath'), "bios", this.data.emulator); + const biosFolder = path.join(config.get('downloadPath'), "bios", this.emulator); await ensureDir(biosFolder); - const files = await plugins.hooks.emulators.fetchBiosDownload.promise({ emulator: this.data.emulator, systems, biosFolder }); + const files = await plugins.hooks.emulators.fetchBiosDownload.promise({ emulator: this.emulator, systems, biosFolder }); if (!files) throw new Error("Could not find source to download from"); @@ -54,12 +45,9 @@ export class BiosDownloadJob implements IJob const downloader = new Downloader('bios-download', files.files, biosFolder, { signal: context.abortSignal, headers, - onProgress: (stats) => + onProgress (stats) { context.setProgress(stats.progress, "download"); - this.data.downloaded = stats.downloaded; - this.data.speed = stats.speed; - this.data.total = stats.total; }, }); @@ -69,6 +57,6 @@ export class BiosDownloadJob implements IJob exposeData () { - return this.data; + return { emulator: this.emulator }; } } \ No newline at end of file diff --git a/src/bun/api/jobs/emulator-download-job.ts b/src/bun/api/jobs/emulator-download-job.ts index de9f538..7dbaf6e 100644 --- a/src/bun/api/jobs/emulator-download-job.ts +++ b/src/bun/api/jobs/emulator-download-job.ts @@ -1,54 +1,46 @@ -import { DownloadJobData, EmulatorPackageType } from '@simeonradivoev/gameflow-sdk/shared'; +import { EmulatorPackageType } from "@/shared/constants"; import { getStoreEmulatorPackage } from "../store/services/gamesService"; -import { IJob, JobContext } from "@simeonradivoev/gameflow-sdk/task-queue"; +import { IJob, JobContext } from "../task-queue"; +import z from "zod"; import { config, plugins } from "../app"; import path from 'node:path'; import Seven from 'node-7z'; import fs from "node:fs/promises"; import { Downloader } from "@/bun/utils/downloader"; import { ensureDir, move } from "fs-extra"; -import { isArchive, simulateProgress } from "@/bun/utils"; +import { simulateProgress } from "@/bun/utils"; import { path7za } from "7zip-bin"; import { getEmulatorDownload, getEmulatorPath } from "../store/services/emulatorsService"; import { $ } from "bun"; -import { EmulatorSourceEntryType } from "@simeonradivoev/gameflow-sdk/shared"; +import { EmulatorSourceEntryType } from "@/shared/types"; type EmulatorDownloadStates = "download" | "extract"; -interface EmulatorDownloadJobData extends DownloadJobData -{ - emulator: string; -} - -export class EmulatorDownloadJob implements IJob +export class EmulatorDownloadJob implements IJob, EmulatorDownloadStates> { static id = "download-emulator" as const; + static dataSchema = z.object({ emulator: z.string() }); + emulator: string; downloadSource: string; emulatorPackage?: EmulatorPackageType; dryRun: boolean; isUpdate: boolean; - data: EmulatorDownloadJobData = { - name: "Download Emulator", - emulator: "" - }; constructor(emulator: string, downloadSource: string, init?: { dryRun?: boolean; isUpdate?: boolean; }) { - this.data.emulator = emulator; + this.emulator = emulator; this.downloadSource = downloadSource; this.dryRun = init?.dryRun ?? false; this.isUpdate = init?.isUpdate ?? false; } - async start (context: JobContext) + async start (context: JobContext, EmulatorDownloadStates>) { - this.emulatorPackage = await getStoreEmulatorPackage(this.data.emulator); + this.emulatorPackage = await getStoreEmulatorPackage(this.emulator); if (!this.emulatorPackage) throw new Error("Emulator not found"); - this.data.name = this.emulatorPackage.name; - this.data.preview_url = this.emulatorPackage.logo; const { url, info } = await getEmulatorDownload(this.emulatorPackage, this.downloadSource); - const emulatorsFolder = getEmulatorPath(this.data.emulator); + const emulatorsFolder = getEmulatorPath(this.emulator); if (this.dryRun) { @@ -57,33 +49,29 @@ export class EmulatorDownloadJob implements IJob + onProgress (stats) { context.setProgress(stats.progress, 'download'); - this.data.total = stats.total; - this.data.downloaded = stats.downloaded; - this.data.speed = stats.speed; }, }); const destinationPaths = await downloader.start(); - context.abortSignal.throwIfAborted(); if (destinationPaths) { - const archive = isArchive(destinationPaths[0]); + const isArchive = destinationPaths[0].endsWith('.7z') || destinationPaths[0].endsWith('.zip') || destinationPaths[0].endsWith('.tar'); const isAppImage = destinationPaths[0].endsWith(".AppImage"); - if (!archive && !isAppImage) + if (!isArchive && !isAppImage) { throw new Error("Invalid Download Type"); } - if (archive) + if (isArchive) { if (destinationPaths[0]) { @@ -132,10 +120,10 @@ export class EmulatorDownloadJob implements IJob e.type === 'store')?.binPath ?? emulatorsFolder, info, @@ -148,7 +136,7 @@ export class EmulatorDownloadJob implements IJob -{ - static id = "update-store" as const; - static dataSchema = z.never(); - packageName: string; - storeVersion: string; - - constructor() - { - this.packageName = process.env.STORE_PACKAGE_NAME ?? "@simeonradivoev/gameflow-store"; - this.storeVersion = process.env.STORE_VERSION ?? "^0.1.0"; - } - - async start (context: JobContext) - { - const storeFolder = getStoreRootFolder(); - await ensureDir(storeFolder); - const storePackageFile = Bun.file(path.join(storeFolder, "package.json")); - if (!await storePackageFile.exists()) - { - await storePackageFile.write(JSON.stringify({ dependencies: {} }, null, 3)); - } - - const storePackage = await Bun.file(path.join(storeFolder, "package.json")).json(); - - if (IsPluginAllowed(sdkPkg.name)) - { - if (!storePackage.dependencies?.[sdkPkg.name] || storePackage.dependencies?.[sdkPkg.name] !== sdkPkg.version) - { - let response = await runBunPackageCommand(["add", `${sdkPkg.name}@${sdkPkg.version}`, "--registry", PluginRegistry, '--omit', 'peer']); - console.log(response); - } - - // probably just means we couldn't find a version of the sdk, just install latest - if (storePackage.dependencies?.[sdkPkg.name] !== sdkPkg.version) - { - let response = await runBunPackageCommand(["add", '--exact', `${sdkPkg.name}@latest`, "--registry", PluginRegistry, '--omit', 'peer']); - console.log(response); - } - } else - { - console.log("Ignoring SDK package"); - } - - if (process.env.CUSTOM_STORE_PATH) return; - - if (!storePackage.dependencies?.['@simeonradivoev/gameflow-store']) - { - context.setProgress(0.5, "Adding Store"); - let response = await runBunPackageCommand(["add", `${this.packageName}@${this.storeVersion}`, "--registry", PluginRegistry, '--omit', 'peer']); - console.log(response); - } - } -} \ No newline at end of file diff --git a/src/bun/api/jobs/import-job.ts b/src/bun/api/jobs/import-job.ts index 7f080c7..3e608a4 100644 --- a/src/bun/api/jobs/import-job.ts +++ b/src/bun/api/jobs/import-job.ts @@ -1,32 +1,21 @@ -import { eq, inArray, or } from "drizzle-orm"; +import { eq, or } from "drizzle-orm"; import { db, plugins } from "../app"; -import { createLocalGame, downloadGame } from "../games/services/utils"; -import { IJob, JobContext } from "@simeonradivoev/gameflow-sdk/task-queue"; +import { createLocalGame } from "../games/services/utils"; +import { IJob, JobContext } from "../task-queue"; import * as schema from "@schema/app"; -import { DownloadJobData, GameLookup } from "@simeonradivoev/gameflow-sdk/shared"; -import { isUrl } from "@/shared/utils"; -import { basename } from "node:path"; -import path from 'node:path'; -import { isArchive } from "@/bun/utils"; +import z from "zod"; +import { GameLookup } from "@/shared/types"; -interface ImportJobData extends DownloadJobData -{ - localId: number | null; -} - -export class ImportJob implements IJob +export class ImportJob implements IJob, string> { static id = "import-job" as const; - static query = (q: { source: string; id: string; }) => `${ImportJob.id}-${q.source}-${q.id}`; - data: ImportJobData = { - localId: null, - name: "Import Game" - }; + static dataSchema = z.object({ localId: z.number().nullable() }); group?: 'import-job'; gamePath: string; source: string; id: string; platformId: number; + localId: number | null = null; constructor(source: string, id: string, gamePath: string, platformId: number) { @@ -36,20 +25,18 @@ export class ImportJob implements IJob this.platformId = platformId; } - exposeData () + exposeData (): z.infer { - return this.data; + return { localId: this.localId }; } - async start (context: JobContext, ImportJobData, string>): Promise + async start (context: JobContext, string>, z.infer, string>): Promise { const matchesMap = new Map(); await plugins.hooks.games.gameLookup.promise(matchesMap, { source: this.source, id: this.id }); const matches = matchesMap.values().next().value; if (!matches || matches.length <= 0) throw Error("Could not Find Game"); const match = matches[0]; - this.data.name = match.name; - this.data.preview_url = match.coverUrl; let cover: Buffer | undefined = undefined; let coverType: string | undefined = undefined; @@ -63,56 +50,24 @@ export class ImportJob implements IJob } } - const platformMatch = match.platforms.find(p => p.id === this.platformId); - - const finalFiles: string[] = []; - - if (isUrl(this.gamePath)) - { - const archive = isArchive(this.gamePath); - const downloadedFiles = await downloadGame({ - downloads: [{ - file_path: this.id, - file_name: basename(this.gamePath), - url: new URL(this.gamePath) - }], - extract_path: archive ? '.tmp' : undefined, - path_fs: path.join('roms', platformMatch?.slug ?? this.source, this.id), - abortSignal: context.abortSignal, - id: `game-${this.source}-${this.id}`, - setProgress: (progress, state, info) => - { - context.setProgress(progress, state); - this.data.speed = info.speed; - this.data.total = info.total; - this.data.downloaded = info.downloaded; - }, - }); - - if (downloadedFiles) - finalFiles.push(...downloadedFiles); - } else - { - finalFiles.push(this.gamePath); - } - const localSearchFilters: any[] = []; if (match.igdb_id) localSearchFilters.push(eq(schema.games.igdb_id, match.igdb_id)); if (match.slug) localSearchFilters.push(eq(schema.games.slug, match.slug)); localSearchFilters.push(eq(schema.games.name, match.name)); - localSearchFilters.push(inArray(schema.games.path_fs, finalFiles)); + localSearchFilters.push(eq(schema.games.path_fs, this.gamePath)); const existingLocalGame = await db.query.games.findFirst({ where: or(...localSearchFilters) }); - context.abortSignal.throwIfAborted(); if (existingLocalGame) throw new Error("Game Already Exists"); - this.data.localId = await createLocalGame({ + const platformMatch = match.platforms.find(p => p.id === this.platformId); + + this.localId = await createLocalGame({ name: match.name, system_slug: platformMatch?.slug, source: undefined, source_id: undefined, slug: match.slug, - path_fs: finalFiles[0], + path_fs: this.gamePath, summary: match.summary, igdb_id: match.igdb_id, ra_id: undefined, diff --git a/src/bun/api/jobs/install-job.ts b/src/bun/api/jobs/install-job.ts index 3d3c867..b6809e2 100644 --- a/src/bun/api/jobs/install-job.ts +++ b/src/bun/api/jobs/install-job.ts @@ -1,12 +1,17 @@ -import { IJob, JobContext } from "@simeonradivoev/gameflow-sdk/task-queue"; +import { IJob, JobContext } from "../task-queue"; import fs from 'node:fs/promises'; import path from 'node:path'; import { config, events, plugins } from "../app"; import { simulateProgress } from "@/bun/utils"; +import { Downloader } from "@/bun/utils/downloader"; +import Seven from 'node-7z'; import z from "zod"; -import { checkFiles, createLocalGame, downloadGame } from "../games/services/utils"; -import { ensureDir } from "fs-extra"; -import { DownloadInfo, DownloadJobData } from "@simeonradivoev/gameflow-sdk/shared"; +import { checkFiles, createLocalGame } from "../games/services/utils"; +import { ensureDir, move } from "fs-extra"; +import { path7za } from "7zip-bin"; +import StreamZip from 'node-stream-zip'; +import { which } from "bun"; +import { DownloadInfo } from "@/shared/types"; interface JobConfig { @@ -17,7 +22,7 @@ interface JobConfig export type InstallJobStates = 'download' | 'extract'; -export class InstallJob implements IJob +export class InstallJob implements IJob { static id = "install-job" as const; static query = (q: { source: string; id: string; }) => `${InstallJob.id}-${q.source}-${q.id}`; @@ -29,9 +34,6 @@ export class InstallJob implements IJob public localGameId?: number; public group = InstallJob.id; public localPath?: string; - data: DownloadJobData = { - name: "Install Game" - }; constructor(id: string, source: string, config?: JobConfig) { @@ -40,7 +42,7 @@ export class InstallJob implements IJob this.source = source; } - public async start (cx: JobContext) + public async start (cx: JobContext) { cx.setProgress(0, 'download'); await fs.mkdir(config.get('downloadPath'), { recursive: true }); @@ -56,31 +58,131 @@ export class InstallJob implements IJob if (!info) throw new Error(`Could not find downloader for source ${this.source}`); - this.data.name = info.name; - this.data.preview_url = info.coverUrl; - const files = await checkFiles(info.files, !!info.extract_path); + if (this.config?.dryDownload !== true && files.some(f => !f.exists || !f.matches)) { - const downloadedFiles = await downloadGame({ - downloads: files.filter(f => !f.exists || !f.matches), - extract_path: info.extract_path, - path_fs: info.path_fs, - abortSignal: cx.abortSignal, - auth: info.auth, - id: `game-${this.source}-${this.gameId}`, - setProgress: (process, state, info) => + const headers: Record = {}; + if (info.auth) + headers['Authorization'] = info.auth; + const downloader = new Downloader(`game-${this.source}-${this.gameId}`, + files.filter(f => !f.exists || !f.matches), + config.get('downloadPath'), { - cx.setProgress(process, state); - this.data.downloaded = info.downloaded; - this.data.speed = info.speed; - this.data.total = info.total; - }, - }); + signal: cx.abortSignal, + headers, + onProgress (stats) + { + cx.setProgress(stats.progress, 'download'); + }, + }); - if (downloadedFiles) + const downloadedFiles = await downloader.start(); + if (!downloadedFiles) + { + return; + } + + if (info.extract_path && downloadedFiles) + { + let progress = 0; + const progressDelta = 1 / downloadedFiles.length; + const extractPath = path.join(config.get('downloadPath'), info.path_fs ?? '', info.extract_path); + + for (const filePath of downloadedFiles) + { + await new Promise(async (resolve, reject) => + { + let sevenZipPath = process.env.ZIP7_PATH ?? path7za; + + if (filePath.endsWith('.rar')) + { + let newPath: string | undefined; + if (process.platform === 'win32' && await fs.exists("C:\\Program Files\\7-Zip\\7z.exe")) + { + newPath = "C:\\Program Files\\7-Zip\\7z.exe"; + } else + { + newPath = which('7z') ?? undefined; + } + + if (!newPath) + { + await fs.rm(filePath); + reject(new Error("No RAR Support")); + return; + } + + sevenZipPath = newPath; + } + + let rejected = false; + const seven = Seven.extractFull(filePath, extractPath, { $bin: sevenZipPath, $progress: true }); + seven.on('progress', p => + { + cx.setProgress(progress + p.percent * progressDelta, "extract"); + }); + seven.on('error', e => + { + reject(e); + rejected = true; + }); + seven.on('end', async () => + { + if (rejected) return; + await fs.rm(filePath); + resolve(true); + }); + }).catch(async e => + { + if (filePath.endsWith('.zip')) + { + cx.setProgress(0, "extract"); + console.error(e); + console.warn("Could not extract", filePath, "with 7zip trying zip extractor"); + await ensureDir(extractPath); + const zip = new StreamZip.async({ file: filePath }); + let entryCount = await zip.entriesCount; + let entryCounter = entryCount; + zip.on('extract', (entry, outPath) => + { + entryCounter--; + cx.setProgress(progress + (1 - (entryCounter / entryCount)) * 100 * progressDelta, "extract"); + }); + const count = await zip.extract(null, extractPath); + console.log(`Extracted ${count} entries`); + await zip.close(); + await fs.rm(filePath); + } else + { + throw e; + } + }); + + progress += progressDelta * 100; + } + + // check if 1 root folder we need to get rid of + const contents = await fs.readdir(extractPath); + if (contents.length === 1) + { + const stat = await fs.stat(path.join(extractPath, contents[0])); + if (stat.isDirectory()) + { + console.log("Found 1 root folder, using that instead"); + const tmpGameFolder = `${extractPath} (1)`; + await move(path.join(extractPath, contents[0]), tmpGameFolder, { overwrite: true }); + await move(tmpGameFolder, extractPath, { overwrite: true }); + } + } + + finalFiles.push(extractPath); + + } else + { finalFiles.push(...downloadedFiles); + } } if (this.config?.dryDownload === true && info.extract_path) @@ -91,7 +193,7 @@ export class InstallJob implements IJob const coverResponse = await fetch(info.coverUrl); const cover = Buffer.from(await coverResponse.arrayBuffer()); - cx.abortSignal.throwIfAborted(); + if (cx.abortSignal.aborted) return; this.localGameId = await createLocalGame({ cover, diff --git a/src/bun/api/jobs/jobs.ts b/src/bun/api/jobs/jobs.ts index 5471e56..328c04e 100644 --- a/src/bun/api/jobs/jobs.ts +++ b/src/bun/api/jobs/jobs.ts @@ -3,24 +3,22 @@ import z, { _ZodType } from "zod"; import { taskQueue } from "../app"; import { LoginJob } from "./login-job"; import TwitchLoginJob from "./twitch-login-job"; -import EnsureStore from "./ensure-store"; +import UpdateStoreJob from "./update-store"; import { EmulatorDownloadJob } from "./emulator-download-job"; import { getErrorMessage } from "@/bun/utils"; -import { BaseEvent, IJob } from "@simeonradivoev/gameflow-sdk/task-queue"; +import { IJob } from "../task-queue"; import { LaunchGameJob } from "./launch-game-job"; import { BiosDownloadJob } from "./bios-download-job"; import { InstallJob } from "./install-job"; import ReloadPluginsJob from "./reload-plugins-job"; -import { FrontEndJob } from "@simeonradivoev/gameflow-sdk/shared"; function registerJob< const Path extends string, - Schema, + const Schema extends z.ZodTypeAny, + const Query extends z.ZodTypeAny, const States extends string, -> (_job: { - id: Path; - query?: (q: any) => string; -} & (new (...args: any[]) => IJob)) + T extends IJob, States> +> (_job: { id: Path; dataSchema: Schema; query?: (q: any) => string; } & (new (...args: any[]) => T)) { return new Elysia().ws(_job.id, { body: z.discriminatedUnion('type', [ @@ -32,9 +30,9 @@ function registerJob< type: z.literal(['data', 'started', 'progress']), state: z.string().optional(), progress: z.number(), - data: z.custom() + data: _job.dataSchema }), - z.object({ type: z.literal(['completed', 'ended']), data: z.custom() }), + z.object({ type: z.literal(['completed', 'ended']), data: _job.dataSchema }), z.object({ type: z.literal('waiting') }), z.object({ type: z.literal('error'), error: z.string() }) ]), @@ -44,7 +42,7 @@ function registerJob< const job = taskQueue.findJob(jobId, _job); if (job) { - ws.send({ type: 'data', state: job.state, progress: job.progress, data: job.job.exposeData?.() as Schema }); + ws.send({ type: 'data', state: job.state, progress: job.progress, data: job.job.exposeData?.() }); } else { ws.send({ type: 'waiting' }); @@ -104,87 +102,10 @@ function registerJob< } export const jobs = new Elysia({ prefix: '/api/jobs' }) - .ws('/list', { - response: z.discriminatedUnion('type', [ - z.object({ type: z.literal("allJobs"), active: z.custom().array(), queued: z.custom().array() }), - z.object({ type: z.literal("started"), job: z.custom() }), - z.object({ type: z.literal("progress"), job: z.custom() }), - z.object({ type: z.literal("queued"), job: z.custom() }), - z.object({ type: z.literal("aborted"), id: z.string() }), - z.object({ type: z.literal("ended"), id: z.string() }), - ]), - body: z.discriminatedUnion('type', [ - z.object({ type: z.literal("cancel"), id: z.string() }) - ]), - message (ws, message) - { - switch (message.type) - { - case "cancel": - taskQueue.cancelJob(message.id); - break; - } - }, - open (ws) - { - ws.send({ - type: 'allJobs', - active: taskQueue.getActiveJobs().map(j => - { - const job: FrontEndJob = { - id: j.id, - data: j.job.exposeData?.(), - progress: j.progress, - state: j.state, - status: j.status - }; - - return job; - }), - queued: taskQueue.getQueuedJobs()?.map(j => - { - const job: FrontEndJob = { - id: j.id, - data: j.job.exposeData?.(), - progress: j.progress, - state: j.state, - status: j.status - }; - - return job; - }) ?? [] - }); - - (ws.data as any).dispose = [taskQueue.on('started', (e: BaseEvent) => - { - ws.send({ type: "started", job: { id: e.id, data: e.job.job.exposeData?.(), progress: e.job.progress, state: e.job.state, status: e.job.status } }); - }), - taskQueue.on('progress', (e: BaseEvent) => - { - ws.send({ type: "progress", job: { id: e.id, data: e.job.job.exposeData?.(), progress: e.job.progress, state: e.job.state, status: e.job.status } }); - }), - taskQueue.on('queued', (e: BaseEvent) => - { - ws.send({ type: "queued", job: { id: e.id, data: e.job.job.exposeData?.(), progress: e.job.progress, state: e.job.state, status: e.job.status } }); - }), - taskQueue.on('abort', (e: BaseEvent) => - { - ws.send({ type: "aborted", id: e.id }); - }), - taskQueue.on('ended', (e: BaseEvent) => - { - ws.send({ type: "ended", id: e.id }); - })]; - }, - close (ws, code, reason) - { - (ws.data as any).dispose.forEach((d: any) => d()); - }, - }) .use(registerJob(LaunchGameJob)) .use(registerJob(LoginJob)) .use(registerJob(TwitchLoginJob)) - .use(registerJob(EnsureStore)) + .use(registerJob(UpdateStoreJob)) .use(registerJob(BiosDownloadJob)) .use(registerJob(InstallJob)) .use(registerJob(ReloadPluginsJob)) diff --git a/src/bun/api/jobs/launch-game-job.ts b/src/bun/api/jobs/launch-game-job.ts index 3ce0e83..d81c25c 100644 --- a/src/bun/api/jobs/launch-game-job.ts +++ b/src/bun/api/jobs/launch-game-job.ts @@ -1,13 +1,13 @@ import z from "zod"; -import { IJob, JobContext } from "@simeonradivoev/gameflow-sdk/task-queue"; -import { ActiveGameSchema, ActiveGameType } from "@simeonradivoev/gameflow-sdk"; +import { IJob, JobContext } from "../task-queue"; +import { ActiveGameSchema, ActiveGameType } from "@/bun/types/types.schema"; import { config, db, events, plugins } from "../app"; import * as appSchema from "@schema/app"; import { eq } from "drizzle-orm"; import { spawn } from 'node:child_process'; import { updateLocalLastPlayed } from "../games/services/statusService"; import { getErrorMessage } from "@/bun/utils"; -import { CommandEntry, FrontEndId, SaveSlots } from "@simeonradivoev/gameflow-sdk/shared"; +import { CommandEntry, FrontEndId, SaveSlots } from "@/shared/types"; export class LaunchGameJob implements IJob, string> { diff --git a/src/bun/api/jobs/login-job.ts b/src/bun/api/jobs/login-job.ts index fb5d69a..f0726bd 100644 --- a/src/bun/api/jobs/login-job.ts +++ b/src/bun/api/jobs/login-job.ts @@ -1,5 +1,5 @@ import Elysia, { status } from "elysia"; -import { IJob, JobContext } from "@simeonradivoev/gameflow-sdk/task-queue"; +import { IJob, JobContext } from "../task-queue"; import { LOGIN_PORT, SERVER_URL } from "@/shared/constants"; import { host, localIp } from "@/bun/utils/host"; import cors from "@elysiajs/cors"; diff --git a/src/bun/api/jobs/plugin-operation-job.ts b/src/bun/api/jobs/plugin-operation-job.ts deleted file mode 100644 index db39819..0000000 --- a/src/bun/api/jobs/plugin-operation-job.ts +++ /dev/null @@ -1,62 +0,0 @@ -import z from "zod"; -import { IJob, JobContext } from "@simeonradivoev/gameflow-sdk"; -import { plugins } from "../app"; -import { canUninstall, runBunPackageCommand } from "../plugins/services"; -import { getPlugin, registerPlugin, unregisterPlugin } from "../plugins/register-plugins"; -import { PluginRegistry } from "@/shared/constants"; - -export default class PluginOperationJob implements IJob -{ - static id = "plugin-operation-job" as const; - static dataSchema = z.never(); - group = "plugin-operations"; - operation: "add" | "update" | "remove"; - plugin: string; - - constructor(operation: "add" | "update" | "remove", plugin: string) - { - this.plugin = plugin; - this.operation = operation; - } - - async start (context: JobContext, never, string>) - { - switch (this.operation) - { - case "add": - //TODO: find the latest compatible version with the current sdk version - const addResponse = await runBunPackageCommand(["add", this.plugin, '--omit', 'peer', "--registry", PluginRegistry]); - console.log(addResponse); - const addPlugin = await getPlugin(this.plugin, plugins); - if (!addPlugin) throw new Error(`${this.plugin} Not Found`); - await registerPlugin(addPlugin, 'store', plugins); - break; - case "update": - const existingPlugin = plugins.plugins[this.plugin]; - if (!existingPlugin) throw new Error(`${this.plugin} Not Found`); - if (!existingPlugin.update?.new) throw new Error(`No Update Found`); - let updatePlugin = await getPlugin(this.plugin, plugins); - if (!updatePlugin) throw new Error(`${this.plugin} Not Found`); - await unregisterPlugin(this.plugin, plugins); - const updateResponse = await runBunPackageCommand(["update", `${this.plugin}@${existingPlugin.update?.new}`, '--omit', 'peer', "--registry", PluginRegistry, '--latest']); - console.log(updateResponse); - updatePlugin = await getPlugin(this.plugin, plugins); - if (!updatePlugin) throw new Error(`Something Went Wrong during update. Missing Plugin: ${this.plugin}`); - await registerPlugin(updatePlugin, existingPlugin.source, plugins); - break; - case "remove": - const removePlugin = plugins.plugins[this.plugin]; - if (!removePlugin) throw new Error(`${this.plugin} Not Found`); - if (!canUninstall(removePlugin.description, removePlugin.source)) - { - throw new Error("Uninstall Not Allowed"); - } - const response = await runBunPackageCommand(['remove', this.plugin, "--registry", PluginRegistry, '--omit', 'peer']); - console.log(response); - await unregisterPlugin(this.plugin, plugins); - break; - } - - - } -} \ No newline at end of file diff --git a/src/bun/api/jobs/reload-plugins-job.ts b/src/bun/api/jobs/reload-plugins-job.ts index 5e404d3..4796fc8 100644 --- a/src/bun/api/jobs/reload-plugins-job.ts +++ b/src/bun/api/jobs/reload-plugins-job.ts @@ -1,5 +1,5 @@ import z from "zod"; -import { IJob, JobContext } from "@simeonradivoev/gameflow-sdk"; +import { IJob, JobContext } from "../task-queue"; import { plugins } from "../app"; export default class ReloadPluginsJob implements IJob diff --git a/src/bun/api/jobs/self-update-job.ts b/src/bun/api/jobs/self-update-job.ts index ca2684e..05ac4e6 100644 --- a/src/bun/api/jobs/self-update-job.ts +++ b/src/bun/api/jobs/self-update-job.ts @@ -1,5 +1,5 @@ import z from "zod"; -import { IJob, JobContext } from "@simeonradivoev/gameflow-sdk"; +import { IJob, JobContext } from "../task-queue"; import { events } from "../app"; import { Downloader } from "@/bun/utils/downloader"; import path from 'node:path'; diff --git a/src/bun/api/jobs/test-download-job.ts b/src/bun/api/jobs/test-download-job.ts deleted file mode 100644 index 313b00b..0000000 --- a/src/bun/api/jobs/test-download-job.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { DownloadJobData } from "@simeonradivoev/gameflow-sdk/shared"; -import { IJob, JobContext } from "@simeonradivoev/gameflow-sdk/task-queue"; -import { sleep } from "bun"; - -export class TestDownloadJob implements IJob -{ - data: DownloadJobData = { - speed: 1686, - downloaded: 0, - total: 6615841, - name: "Test Download Job" - }; - - group = "test-download"; - - async start (context: JobContext, DownloadJobData, string>): Promise - { - for (let i = 0; i < 10; i++) - { - await sleep(1000); - context.setProgress(i / 10 * 100, 'download'); - if (context.abortSignal.aborted) return; - } - } - exposeData (): DownloadJobData - { - return this.data; - } - -} \ No newline at end of file diff --git a/src/bun/api/jobs/twitch-login-job.ts b/src/bun/api/jobs/twitch-login-job.ts index 42d98a9..1023e83 100644 --- a/src/bun/api/jobs/twitch-login-job.ts +++ b/src/bun/api/jobs/twitch-login-job.ts @@ -1,4 +1,4 @@ -import { IJob, JobContext } from "@simeonradivoev/gameflow-sdk"; +import { IJob, JobContext } from "../task-queue"; import secrets from "../secrets"; import open from "open"; import z from "zod"; diff --git a/src/bun/api/jobs/update-store.ts b/src/bun/api/jobs/update-store.ts new file mode 100644 index 0000000..b051f07 --- /dev/null +++ b/src/bun/api/jobs/update-store.ts @@ -0,0 +1,67 @@ +import { ensureDir } from "fs-extra"; +import { IJob, JobContext } from "../task-queue"; +import { getStoreRootFolder } from "../store/services/gamesService"; +import { tmpdir } from "node:os"; +import path from "node:path"; +import z from "zod"; + +export default class UpdateStoreJob implements IJob +{ + static id = "update-store" as const; + static dataSchema = z.never(); + packageName: string; + registry: URL; + storeVersion: string; + + constructor() + { + this.packageName = process.env.STORE_PACKAGE_NAME ?? "@simeonradivoev/gameflow-store"; + this.registry = new URL(process.env.STORE_REGISTRY ?? "https://registry.npmjs.org"); + this.storeVersion = process.env.STORE_VERSION ?? "^0.1.0"; + } + + async start (context: JobContext) + { + if (process.env.CUSTOM_STORE_PATH) return; + + const tempCache = path.join(tmpdir(), "gameflow-bun-cache"); + const storeFolder = getStoreRootFolder(); + await ensureDir(storeFolder); + + console.log("Adding Store Package"); + let proc = Bun.spawn([process.execPath, "add", `${this.packageName}@${this.storeVersion}`, "--registry", this.registry.href], { + cwd: storeFolder, + stdout: 'pipe', + stderr: 'pipe', + env: { + BUN_BE_BUN: "1", + BUN_INSTALL_CACHE_DIR: tempCache + } + }); + + let stdout = await new Response(proc.stdout).text(); + console.log(stdout); + let stderr = await new Response(proc.stderr).text(); + if (stderr) + console.error(stderr); + await proc.exited; + + console.log("Updating Store Package"); + proc = Bun.spawn([process.execPath, "update", `${this.packageName}@${this.storeVersion}`, "--registry", this.registry.href], { + cwd: storeFolder, + stdout: 'pipe', + stderr: 'pipe', + env: { + BUN_BE_BUN: "1", + BUN_INSTALL_CACHE_DIR: tempCache + } + }); + + stdout = await new Response(proc.stdout).text(); + console.log(stdout); + stderr = await new Response(proc.stderr).text(); + if (stderr) + console.error(stderr); + await proc.exited; + } +} \ No newline at end of file diff --git a/src/bun/api/notifications.ts b/src/bun/api/notifications.ts index e1c135c..514ee58 100644 --- a/src/bun/api/notifications.ts +++ b/src/bun/api/notifications.ts @@ -1,5 +1,5 @@ -import { FrontendNotification } from '@simeonradivoev/gameflow-sdk/shared'; +import { FrontendNotification } from '@/shared/types'; import { events } from './app'; export default function buildNotificationsStream () diff --git a/src/bun/api/plugins/builtin/emulators/com.simeonradivoev.gameflow.cemu/cemu.ts b/src/bun/api/plugins/builtin/emulators/com.simeonradivoev.gameflow.cemu/cemu.ts index a9e6865..9fe34a4 100644 --- a/src/bun/api/plugins/builtin/emulators/com.simeonradivoev.gameflow.cemu/cemu.ts +++ b/src/bun/api/plugins/builtin/emulators/com.simeonradivoev.gameflow.cemu/cemu.ts @@ -1,4 +1,4 @@ -import { PluginLoadingContextType, PluginType } from "@simeonradivoev/gameflow-sdk"; +import { PluginLoadingContextType, PluginType } from "@/bun/types/types.schema"; import desc from './package.json'; import path from 'node:path'; import { config } from "@/bun/api/app"; diff --git a/src/bun/api/plugins/builtin/emulators/com.simeonradivoev.gameflow.dolphin/dolphin.ts b/src/bun/api/plugins/builtin/emulators/com.simeonradivoev.gameflow.dolphin/dolphin.ts index 6a44901..111b9c5 100644 --- a/src/bun/api/plugins/builtin/emulators/com.simeonradivoev.gameflow.dolphin/dolphin.ts +++ b/src/bun/api/plugins/builtin/emulators/com.simeonradivoev.gameflow.dolphin/dolphin.ts @@ -1,6 +1,6 @@ import { config } from "@/bun/api/app"; -import { PluginLoadingContextType, PluginType } from "@simeonradivoev/gameflow-sdk"; +import { PluginLoadingContextType, PluginType } from "@/bun/types/types.schema"; import path from 'node:path'; import desc from './package.json'; import { ensureDir } from "fs-extra"; diff --git a/src/bun/api/plugins/builtin/emulators/com.simeonradivoev.gameflow.pcsx2/pcsx2.ts b/src/bun/api/plugins/builtin/emulators/com.simeonradivoev.gameflow.pcsx2/pcsx2.ts index 58d61aa..23c2736 100644 --- a/src/bun/api/plugins/builtin/emulators/com.simeonradivoev.gameflow.pcsx2/pcsx2.ts +++ b/src/bun/api/plugins/builtin/emulators/com.simeonradivoev.gameflow.pcsx2/pcsx2.ts @@ -1,12 +1,12 @@ import { config } from "@/bun/api/app"; -import { PluginLoadingContextType, PluginType } from "@simeonradivoev/gameflow-sdk"; +import { PluginLoadingContextType, PluginType } from "@/bun/types/types.schema"; import defaultConfig from './PCSX2.ini' with { type: 'file' }; import path from 'node:path'; import { ensureDir } from "fs-extra"; import desc from './package.json'; import ini from 'ini'; -import { EmulatorCapabilities } from "@simeonradivoev/gameflow-sdk/shared"; +import { EmulatorCapabilities } from "@/shared/types"; export default class PCSX2Integration implements PluginType { diff --git a/src/bun/api/plugins/builtin/emulators/com.simeonradivoev.gameflow.ppsspp/ppsspp.ts b/src/bun/api/plugins/builtin/emulators/com.simeonradivoev.gameflow.ppsspp/ppsspp.ts index f69fdaf..87886dd 100644 --- a/src/bun/api/plugins/builtin/emulators/com.simeonradivoev.gameflow.ppsspp/ppsspp.ts +++ b/src/bun/api/plugins/builtin/emulators/com.simeonradivoev.gameflow.ppsspp/ppsspp.ts @@ -1,4 +1,4 @@ -import { PluginLoadingContextType, PluginType } from "@simeonradivoev/gameflow-sdk"; +import { PluginLoadingContextType, PluginType } from "@/bun/types/types.schema"; import desc from './package.json'; import { config } from "@/bun/api/app"; import configFilePathWin32 from './win32/ppsspp.ini' with { type: 'file' }; @@ -11,7 +11,7 @@ import { ensureDir } from "fs-extra"; import { homedir } from "node:os"; import ini from 'ini'; import fs from 'node:fs/promises'; -import { EmulatorCapabilities } from "@simeonradivoev/gameflow-sdk/shared"; +import { EmulatorCapabilities } from "@/shared/types"; export default class PPSSPPIntegration implements PluginType { diff --git a/src/bun/api/plugins/builtin/emulators/com.simeonradivoev.gameflow.xemu/xemu.ts b/src/bun/api/plugins/builtin/emulators/com.simeonradivoev.gameflow.xemu/xemu.ts index 57506de..ff8c3f9 100644 --- a/src/bun/api/plugins/builtin/emulators/com.simeonradivoev.gameflow.xemu/xemu.ts +++ b/src/bun/api/plugins/builtin/emulators/com.simeonradivoev.gameflow.xemu/xemu.ts @@ -1,4 +1,4 @@ -import { PluginLoadingContextType, PluginType } from "@simeonradivoev/gameflow-sdk"; +import { PluginLoadingContextType, PluginType } from "@/bun/types/types.schema"; import desc from './package.json'; import { config } from "@/bun/api/app"; import path from "node:path"; diff --git a/src/bun/api/plugins/builtin/emulators/com.simeonradivoev.gameflow.xenia/xenia.ts b/src/bun/api/plugins/builtin/emulators/com.simeonradivoev.gameflow.xenia/xenia.ts index 9d37d99..eb0715d 100644 --- a/src/bun/api/plugins/builtin/emulators/com.simeonradivoev.gameflow.xenia/xenia.ts +++ b/src/bun/api/plugins/builtin/emulators/com.simeonradivoev.gameflow.xenia/xenia.ts @@ -1,6 +1,6 @@ -import { PluginLoadingContextType, PluginType } from "@simeonradivoev/gameflow-sdk"; +import { PluginLoadingContextType, PluginType } from "@/bun/types/types.schema"; import desc from './package.json'; -import { GameflowHooks } from "@simeonradivoev/gameflow-sdk"; +import GameflowHooks from "@/bun/api/hooks/app"; import { config } from "@/bun/api/app"; import path from "node:path"; import { ensureDir } from "fs-extra"; diff --git a/src/bun/api/plugins/builtin/launchers/com.simeonradivoev.gameflow.es/es-de.ts b/src/bun/api/plugins/builtin/launchers/com.simeonradivoev.gameflow.es/es-de.ts index 77cd201..cf57e13 100644 --- a/src/bun/api/plugins/builtin/launchers/com.simeonradivoev.gameflow.es/es-de.ts +++ b/src/bun/api/plugins/builtin/launchers/com.simeonradivoev.gameflow.es/es-de.ts @@ -1,4 +1,4 @@ -import { PluginLoadingContextType, PluginType } from "@simeonradivoev/gameflow-sdk"; +import { PluginLoadingContextType, PluginType } from "@/bun/types/types.schema"; import desc from './package.json'; import { config, customEmulators, db, emulatorsDb } from "@/bun/api/app"; import * as emulatorSchema from '@schema/emulators'; @@ -13,7 +13,7 @@ import { findStoreEmulatorExec } from "@/bun/api/games/services/launchGameServic import { which } from "bun"; import os from 'node:os'; import { getLocalGameMatch } from "@/bun/api/games/services/utils"; -import { CommandEntry, EmulatorSourceEntryType } from "@simeonradivoev/gameflow-sdk/shared"; +import { CommandEntry, EmulatorSourceEntryType } from "@/shared/types"; export default class IgdbIntegration implements PluginType { diff --git a/src/bun/api/plugins/builtin/other/com.simeonradivoev.gameflow.rclone/rclone.ts b/src/bun/api/plugins/builtin/other/com.simeonradivoev.gameflow.rclone/rclone.ts index 8ab31a0..a31c94d 100644 --- a/src/bun/api/plugins/builtin/other/com.simeonradivoev.gameflow.rclone/rclone.ts +++ b/src/bun/api/plugins/builtin/other/com.simeonradivoev.gameflow.rclone/rclone.ts @@ -1,4 +1,4 @@ -import { PluginLoadingContextType, PluginType } from "@simeonradivoev/gameflow-sdk"; +import { PluginLoadingContextType, PluginType } from "@/bun/types/types.schema"; import desc from './package.json'; import { config, db, events } from "@/bun/api/app"; import path from 'node:path'; diff --git a/src/bun/api/plugins/builtin/sources/com.simeonradivoev.gameflow.igdb/igdb.ts b/src/bun/api/plugins/builtin/sources/com.simeonradivoev.gameflow.igdb/igdb.ts index c2be6d3..7c39e01 100644 --- a/src/bun/api/plugins/builtin/sources/com.simeonradivoev.gameflow.igdb/igdb.ts +++ b/src/bun/api/plugins/builtin/sources/com.simeonradivoev.gameflow.igdb/igdb.ts @@ -1,10 +1,10 @@ -import { PluginLoadingContextType, PluginType } from "@simeonradivoev/gameflow-sdk"; +import { PluginLoadingContextType, PluginType } from "@/bun/types/types.schema"; import desc from './package.json'; import secrets from "@/bun/api/secrets"; import PQueue from 'p-queue'; import * as igdb from '@phalcode/ts-igdb-client'; import { checkLoginAndRefreshTwitch } from "@/bun/api/auth"; -import { GameLookup } from "@simeonradivoev/gameflow-sdk/shared"; +import { GameLookup } from "@/shared/types"; export default class IgdbIntegration implements PluginType { diff --git a/src/bun/api/plugins/builtin/sources/com.simeonradivoev.gameflow.romm/romm.ts b/src/bun/api/plugins/builtin/sources/com.simeonradivoev.gameflow.romm/romm.ts index 2be6e68..ac9474f 100644 --- a/src/bun/api/plugins/builtin/sources/com.simeonradivoev.gameflow.romm/romm.ts +++ b/src/bun/api/plugins/builtin/sources/com.simeonradivoev.gameflow.romm/romm.ts @@ -1,12 +1,12 @@ -import { PluginLoadingContextType, PluginType } from "@simeonradivoev/gameflow-sdk"; +import { PluginLoadingContextType, PluginType } from "@/bun/types/types.schema"; import desc from './package.json'; import { DetailedRomSchema, getCollectionApiCollectionsIdGet, getCollectionsApiCollectionsGet, getCurrentUserApiUsersMeGet, getPlatformApiPlatformsIdGet, getPlatformFirmwareApiFirmwareGet, getPlatformsApiPlatformsGet, getRomApiRomsIdGet, getRomByMetadataProviderApiRomsByMetadataProviderGet, getRomContentApiRomsIdContentFileNameGet, getRomFiltersApiRomsFiltersGet, getRomsApiRomsGet, getSavesSummaryApiSavesSummaryGet, PlatformSchema, SimpleRomSchema, updateRomUserApiRomsIdPropsPut } from "@/clients/romm"; import { config, events } from "@/bun/api/app"; import path from 'node:path'; import fs from 'node:fs/promises'; -import { hashFile, isArchive, isSteamDeckGameMode } from "@/bun/utils"; +import { hashFile, isSteamDeckGameMode } from "@/bun/utils"; import { CACHE_KEYS, getOrCached } from "@/bun/api/cache"; import secrets from "@/bun/api/secrets"; import { getAuthToken } from "@/clients/romm/core/auth.gen"; @@ -14,7 +14,7 @@ import { client } from "@/clients/romm/client.gen"; import { validateGameSource } from "@/bun/api/games/services/statusService"; import z from "zod"; import { checkLoginAndRefreshRomm } from "@/bun/api/auth"; -import { DownloadFileEntry, DownloadInfo, FrontEndCollection, FrontEndGameType, FrontEndGameTypeDetailed, FrontEndGameTypeDetailedAchievement, FrontEndGameTypeWithIds, FrontEndPlatformType } from "@simeonradivoev/gameflow-sdk/shared"; +import { DownloadFileEntry, DownloadInfo, FrontEndCollection, FrontEndGameType, FrontEndGameTypeDetailed, FrontEndGameTypeDetailedAchievement, FrontEndGameTypeWithIds, FrontEndPlatformType } from "@/shared/types"; import Conf from "conf"; const SettingsSchema = z.object({ @@ -44,7 +44,7 @@ export default class RommIntegration implements PluginType async getAccessToken (config: Conf) { if (process.env.ROMM_CLIENT_TOKEN) return process.env.ROMM_CLIENT_TOKEN; - const client_token = config.get('clientApiToken'); + const client_token = await config.get('clientApiToken'); if (client_token) return client_token; return (await secrets.get({ service: 'gameflow', name: 'romm_access_token' })) ?? undefined; } @@ -254,7 +254,8 @@ export default class RommIntegration implements PluginType let path_fs = path.join(rom.fs_path, rom.fs_name); if (files.length === 1) { - if (isArchive(files[0].file_name)) + const name = files[0].file_name.toLocaleLowerCase(); + if (name.endsWith('.zip') || name.endsWith('.7z') || name.endsWith('.rar')) { extract_path = '.'; path_fs = path.join(rom.fs_path, rom.slug ?? rom.fs_name_no_ext); diff --git a/src/bun/api/plugins/builtin/sources/com.simeonradivoev.gameflow.store/package.json b/src/bun/api/plugins/builtin/sources/com.simeonradivoev.gameflow.store/package.json index 644c332..713f76f 100644 --- a/src/bun/api/plugins/builtin/sources/com.simeonradivoev.gameflow.store/package.json +++ b/src/bun/api/plugins/builtin/sources/com.simeonradivoev.gameflow.store/package.json @@ -1,8 +1,8 @@ { "name": "com.simeonradivoev.gameflow.store", - "displayName": "Gameflow Store Integration", + "displayName": "Gameflow Store", "version": "0.0.1", - "description": "The internal gameflow store integration. This is the logic of the store that uses the data only store package", + "description": "The internal gameflow store", "main": "./store.ts", "category": "sources", "canDisable": false, diff --git a/src/bun/api/plugins/builtin/sources/com.simeonradivoev.gameflow.store/services.ts b/src/bun/api/plugins/builtin/sources/com.simeonradivoev.gameflow.store/services.ts index 4935dd7..de08c46 100644 --- a/src/bun/api/plugins/builtin/sources/com.simeonradivoev.gameflow.store/services.ts +++ b/src/bun/api/plugins/builtin/sources/com.simeonradivoev.gameflow.store/services.ts @@ -1,4 +1,5 @@ import { getStoreFolder } from "@/bun/api/store/services/gamesService"; +import { EmulatorDownloadInfoSchema, EmulatorDownloadInfoType, EmulatorPackageType, StoreDownloadType, StoreGameSchema, StoreGameType } from "@/shared/constants"; import os from 'node:os'; import path from "node:path"; import * as appSchema from '@schema/app'; @@ -11,8 +12,7 @@ import { shuffleInPlace } from "@/bun/utils"; import mustache from "mustache"; import { getEmulatorDownload, getEmulatorPath } from "@/bun/api/store/services/emulatorsService"; import fs from "node:fs/promises"; -import { CommandEntry, EmulatorSourceEntryType, EmulatorSystem, FrontEndEmulator, FrontEndFilterSets, FrontEndGameType, FrontEndGameTypeDetailed, SaveFileChange, EmulatorDownloadInfoType, StoreDownloadType, StoreGameType, EmulatorPackageType, EmulatorDownloadInfoSchema, StoreGameSchema } from "@simeonradivoev/gameflow-sdk/shared"; -import { isUrl } from "@/shared/utils"; +import { CommandEntry, EmulatorSourceEntryType, EmulatorSystem, FrontEndEmulator, FrontEndFilterSets, FrontEndGameType, FrontEndGameTypeDetailed, SaveFileChange } from "@/shared/types"; export async function getStoreGames (gamesManifest: any[], filter?: { limit?: number; offset?: number; }) { @@ -40,7 +40,7 @@ export async function getStoreGame (id: string) function convertStoreMediaToPath (c: string) { - if (isUrl(c)) + if (c.startsWith('http')) { return `/api/romm/image?url=${encodeURIComponent(c)}`; } else diff --git a/src/bun/api/plugins/builtin/sources/com.simeonradivoev.gameflow.store/store.ts b/src/bun/api/plugins/builtin/sources/com.simeonradivoev.gameflow.store/store.ts index 92ce1f9..3215548 100644 --- a/src/bun/api/plugins/builtin/sources/com.simeonradivoev.gameflow.store/store.ts +++ b/src/bun/api/plugins/builtin/sources/com.simeonradivoev.gameflow.store/store.ts @@ -1,26 +1,20 @@ -import { PluginLoadingContextType, PluginType } from "@simeonradivoev/gameflow-sdk"; +import { PluginLoadingContextType, PluginType } from "@/bun/types/types.schema"; import desc from './package.json'; import path, { } from 'node:path'; import { buildStoreFrontendEmulatorSystems, getAllStoreEmulatorPackages, getStoreEmulatorPackage, getStoreFolder } from "@/bun/api/store/services/gamesService"; -import { Glob, pathToFileURL, which } from "bun"; +import { Glob, pathToFileURL } from "bun"; import { and, eq } from "drizzle-orm"; import * as emulatorSchema from '@schema/emulators'; import { config, emulatorsDb, taskQueue } from "@/bun/api/app"; import fs from "node:fs/promises"; import { getSourceGameDetailed } from "@/bun/api/games/services/utils"; -import EnsureStore from "@/bun/api/jobs/ensure-store"; +import UpdateStoreJob from "@/bun/api/jobs/update-store"; import { getEmulatorDownload, getEmulatorPath } from "@/bun/api/store/services/emulatorsService"; import { buildFilters, buildLaunchCommand, buildSaves, convertStoreEmulatorToFrontend, convertStoreToFrontend, convertStoreToFrontendDetailed, getExistingStoreEmulatorDownload, getShuffledStoreGames, getStoreGame, getValidDownloads } from "./services"; -import { DownloadInfo, FrontEndEmulatorDetailed, FrontEndGameTypeWithIds } from "@simeonradivoev/gameflow-sdk/shared"; -import { isUrl } from "@/shared/utils"; -import { Downloader } from "@/bun/utils/downloader"; -import { ensureDir, move } from "fs-extra"; -import StreamZip from "node-stream-zip"; -import { path7za } from "7zip-bin"; -import Seven from 'node-7z'; +import { DownloadInfo, FrontEndEmulatorDetailed, FrontEndGameTypeWithIds } from "@/shared/types"; -export default class StoreIntegration implements PluginType +export default class RommIntegration implements PluginType { eventsNames = [{ id: 'updateStore', title: "Update Store", description: "Update the Store Manifest", action: "Update" }]; @@ -29,7 +23,7 @@ export default class StoreIntegration implements PluginType switch (e) { case 'updateStore': - await taskQueue.enqueue(EnsureStore.id, new EnsureStore()); + await taskQueue.enqueue(UpdateStoreJob.id, new UpdateStoreJob()); return { reload: true }; } } @@ -38,7 +32,7 @@ export default class StoreIntegration implements PluginType { console.log("Store Directory is ", getStoreFolder()); ctx.setProgress(0, "Updating Store"); - await taskQueue.enqueue(EnsureStore.id, new EnsureStore()); + await taskQueue.enqueue(UpdateStoreJob.id, new UpdateStoreJob()); } async load (ctx: PluginLoadingContextType) @@ -157,8 +151,7 @@ export default class StoreIntegration implements PluginType if (!validDownload || !validDownload.bin) return; const glob = new Glob(validDownload.bin); const files = await Array.fromAsync(glob.scan({ cwd: emulatorPath })); - // es-de also searches for store executables so there might be duplicates, check first. - if (files.length > 0 && !sources.find(s => s.type === 'store')) + if (files.length > 0) { sources.push({ binPath: path.join(emulatorPath, files[0]), exists: true, rootPath: emulatorPath, type: 'store' }); } @@ -301,7 +294,7 @@ export default class StoreIntegration implements PluginType const info: DownloadInfo = { id: validDownload.id, - coverUrl: game.covers?.[0] ? isUrl(game.covers[0]) ? game.covers[0] : pathToFileURL(path.join(getStoreFolder(), game.covers[0])).href : "", + coverUrl: game.covers?.[0] ? game.covers[0].startsWith('http') ? game.covers[0] : pathToFileURL(path.join(getStoreFolder(), game.covers[0])).href : "", screenshotUrls: game.screenshots ?? [], files: [{ url: new URL(validDownload.url), @@ -331,129 +324,5 @@ export default class StoreIntegration implements PluginType return info; }); }); - - ctx.hooks.downloadFiles.tapPromise(desc.name, async ({ id, files, downloadPath, abortSignal, auth, updateProgress }) => - { - const headers: Record = {}; - if (auth) - headers['Authorization'] = auth; - const downloader = new Downloader(id, - files, - downloadPath, - { - signal: abortSignal, - headers, - onProgress: updateProgress, - }); - - const downloadedFiles = await downloader.start(); - if (downloadedFiles) - { - return { source: desc.name, files: downloadedFiles }; - } - }); - - ctx.hooks.postDownloadFiles.tapPromise(desc.name, async ({ files, extract_path, source, downloadPath, path_fs }) => - { - if (extract_path && files && source === desc.name) - { - let progress = 0; - const progressDelta = 1 / files.length; - const extractPath = path.join(downloadPath, path_fs ?? '', extract_path); - - for (const filePath of files) - { - await new Promise(async (resolve, reject) => - { - let sevenZipPath = process.env.ZIP7_PATH ?? path7za; - - if (filePath.endsWith('.rar')) - { - let newPath: string | undefined; - if (process.platform === 'win32' && await fs.exists("C:\\Program Files\\7-Zip\\7z.exe")) - { - newPath = "C:\\Program Files\\7-Zip\\7z.exe"; - } else - { - newPath = which('7z') ?? undefined; - } - - if (!newPath) - { - await fs.rm(filePath); - reject(new Error("No RAR Support")); - return; - } - - sevenZipPath = newPath; - } - - let rejected = false; - const seven = Seven.extractFull(filePath, extractPath, { $bin: sevenZipPath, $progress: true }); - seven.on('progress', p => - { - ctx.setProgress?.(progress + p.percent * progressDelta, "extract", { - speed: 0, - total: 0, - downloaded: 0 - }); - }); - seven.on('error', e => - { - reject(e); - rejected = true; - }); - seven.on('end', async () => - { - if (rejected) return; - await fs.rm(filePath); - resolve(true); - }); - }).catch(async e => - { - if (filePath.endsWith('.zip')) - { - ctx.setProgress?.(0, "extract", {}); - console.error(e); - console.warn("Could not extract", filePath, "with 7zip trying zip extractor"); - await ensureDir(extractPath); - const zip = new StreamZip.async({ file: filePath }); - let entryCount = await zip.entriesCount; - let entryCounter = entryCount; - zip.on('extract', (entry, outPath) => - { - entryCounter--; - ctx.setProgress?.(progress + (1 - (entryCounter / entryCount)) * 100 * progressDelta, "extract", {}); - }); - const count = await zip.extract(null, extractPath); - console.log(`Extracted ${count} entries`); - await zip.close(); - await fs.rm(filePath); - } else - { - throw e; - } - }); - - progress += progressDelta * 100; - } - - // check if 1 root folder we need to get rid of - const contents = await fs.readdir(extractPath); - if (contents.length === 1) - { - const stat = await fs.stat(path.join(extractPath, contents[0])); - if (stat.isDirectory()) - { - console.log("Found 1 root folder, using that instead"); - const tmpGameFolder = `${extractPath} (1)`; - await move(path.join(extractPath, contents[0]), tmpGameFolder, { overwrite: true }); - await move(tmpGameFolder, extractPath, { overwrite: true }); - } - } - - return [extractPath]; - } - }); } } \ No newline at end of file diff --git a/src/bun/api/plugins/plugin-manager.ts b/src/bun/api/plugins/plugin-manager.ts index 8b2a1b5..e3511b5 100644 --- a/src/bun/api/plugins/plugin-manager.ts +++ b/src/bun/api/plugins/plugin-manager.ts @@ -1,13 +1,10 @@ -import { GameflowHooks } from "@simeonradivoev/gameflow-sdk"; -import { PluginDescriptionType, PluginLoadingContextType, PluginType } from "@simeonradivoev/gameflow-sdk"; -import { config, events, taskQueue } from "../app"; +import GameflowHooks from "../hooks/app"; +import { PluginDescriptionType, PluginLoadingContextType, PluginType } from "../../types/types.schema"; +import { config } from "../app"; import Conf from "conf"; import projectPackage from '~/package.json'; import z from "zod"; -import { PluginSourceType, PluginUpdateCheck } from "@simeonradivoev/gameflow-sdk/shared"; -import { getUpdates } from "./services"; -import sdkPkg from '@simeonradivoev/gameflow-sdk/package.json'; -import { semver } from "bun"; +import { PluginSourceType } from "@/shared/types"; export const pluginZodRegistry = z.registry<{ requiresRestart?: boolean; @@ -24,19 +21,9 @@ export class PluginManager description: PluginDescriptionType, source: PluginSourceType; config?: Conf; - update?: PluginUpdateCheck; - incompatible?: boolean; }> = {}; - unregister (id: string) - { - if (!this.plugins[id]) return false; - delete this.plugins[id]; - console.log("Plugin", id, "unregistered"); - return true; - } - register (plugin: PluginType, description: PluginDescriptionType, source: PluginSourceType) { try @@ -81,33 +68,16 @@ export class PluginManager }; } - checkValidity (plugin: PluginDescriptionType) - { - const sdkDep = plugin.peerDependencies?.[sdkPkg.name]; - if (sdkDep) - { - return semver.satisfies(sdkPkg.version, sdkDep); - } - return true; - } - - private async reload (name: string, reloadCtx: { setProgress: (progress: number, state: string) => void; }, update: string | undefined | null) + private async reload (name: string, reloadCtx: { setProgress: (progress: number, state: string) => void; }) { const plugin = this.plugins[name]; if (plugin) { - plugin.update = update && !semver.satisfies(plugin.description.version, update) ? { current: plugin.description.version, new: update } : undefined; - const ctx: PluginLoadingContextType = { hooks: this.hooks, setProgress: reloadCtx.setProgress.bind(reloadCtx), config: plugin.config as any, - zodRegistry: pluginZodRegistry, - app: { - config, - events, - taskQueue - } + zodRegistry: pluginZodRegistry }; if (plugin.loaded) @@ -118,14 +88,7 @@ export class PluginManager try { - plugin.incompatible = !this.checkValidity(plugin.description); - if (plugin.incompatible) - { - console.error(plugin.description.name, "Incompatible sdk verison"); - return; - } - - if (plugin.enabled || plugin.description.canDisable === false || plugin.description.name === '@simeonradivoev/gameflow-store') + if (plugin.enabled || plugin.description.canDisable === false) { console.log("Loading Plugin", plugin.description.name); await plugin.plugin.load(ctx); @@ -143,13 +106,10 @@ export class PluginManager async reloadAll (ctx: { setProgress: (progress: number, state: string) => void; }) { this.hooks = new GameflowHooks(); - - const outdated = await getUpdates(); - for await (const id of Object.keys(this.plugins)) { ctx.setProgress(0, `Loading ${id}`); - await this.reload(id, ctx, outdated.find(i => i.package === id)?.update); + await this.reload(id, ctx); } } diff --git a/src/bun/api/plugins/plugins.ts b/src/bun/api/plugins/plugins.ts index ddfad06..eed9466 100644 --- a/src/bun/api/plugins/plugins.ts +++ b/src/bun/api/plugins/plugins.ts @@ -3,9 +3,7 @@ import { plugins, taskQueue } from "../app"; import z from "zod"; import { toggleElementInConfig } from "@/bun/utils"; import ReloadPluginsJob from "../jobs/reload-plugins-job"; -import { FrontendPlugin } from "@simeonradivoev/gameflow-sdk/shared"; -import { canDisable, canUninstall } from "./services"; -import PluginOperationJob from "../jobs/plugin-operation-job"; +import { FrontendPlugin } from "@/shared/types"; export default new Elysia({ prefix: '/plugins' }) .get('/', async () => @@ -19,27 +17,25 @@ export default new Elysia({ prefix: '/plugins' }) description: p.description.description, source: p.source, version: p.description.version, - canDisable: canDisable(p.description), + canDisable: p.description.canDisable ?? true, icon: p.description.icon, category: p.description.category, - hasSettings: !!p.config || !!p.plugin.eventsNames, - canUninstall: canUninstall(p.description, p.source), - update: p.update + hasSettings: !!p.config || !!p.plugin.eventsNames }; return plugin; }); }) .get('/:id', async ({ params: { id } }) => { - const plugin = plugins.plugins[decodeURIComponent(id)]; - return { ...plugin.description, update: plugin.update }; + const plugin = plugins.plugins[id]; + return plugin.description; }) .post('/:id', async ({ params: { id }, body: { enabled } }) => { - const plugin = plugins.plugins[decodeURIComponent(id)]; + const plugin = plugins.plugins[id]; if (plugin) { - if (!canDisable(plugin.description)) + if (plugin.description.canDisable === false) { return status("Forbidden"); } @@ -52,26 +48,4 @@ export default new Elysia({ prefix: '/plugins' }) } }, { body: z.object({ enabled: z.boolean() }) - }).post('/install', async ({ body: { id } }) => - { - if (taskQueue.hasActiveOfType(PluginOperationJob) || taskQueue.hasActiveOfType(ReloadPluginsJob)) return; - await taskQueue.enqueue(PluginOperationJob.id, new PluginOperationJob("add", id)); - await taskQueue.enqueue(ReloadPluginsJob.id, new ReloadPluginsJob()); - }, { - body: z.object({ id: z.string() }) - }).post('/update', async ({ body: { id } }) => - { - if (taskQueue.hasActiveOfType(PluginOperationJob) || taskQueue.hasActiveOfType(ReloadPluginsJob)) return; - await taskQueue.enqueue(PluginOperationJob.id, new PluginOperationJob("update", id)); - await taskQueue.enqueue(ReloadPluginsJob.id, new ReloadPluginsJob()); - }, { - body: z.object({ id: z.string() }) - }) - .post('/uninstall', async ({ body: { id } }) => - { - if (taskQueue.hasActiveOfType(PluginOperationJob) || taskQueue.hasActiveOfType(ReloadPluginsJob)) return; - await taskQueue.enqueue(PluginOperationJob.id, new PluginOperationJob("remove", id)); - await taskQueue.enqueue(ReloadPluginsJob.id, new ReloadPluginsJob()); - }, { - body: z.object({ id: z.string() }) }); \ No newline at end of file diff --git a/src/bun/api/plugins/register-plugins.ts b/src/bun/api/plugins/register-plugins.ts index 5746947..ead6f54 100644 --- a/src/bun/api/plugins/register-plugins.ts +++ b/src/bun/api/plugins/register-plugins.ts @@ -11,74 +11,12 @@ import igdb from './builtin/sources/com.simeonradivoev.gameflow.igdb/package.jso import store from './builtin/sources/com.simeonradivoev.gameflow.store/package.json'; import es from './builtin/launchers/com.simeonradivoev.gameflow.es/package.json'; import rclone from './builtin/other/com.simeonradivoev.gameflow.rclone/package.json'; -import { PluginDescriptionSchema, PluginDescriptionType, PluginSchema } from "@simeonradivoev/gameflow-sdk"; +import { PluginDescriptionSchema, PluginDescriptionType, PluginSchema } from "@/bun/types/types.schema"; import path from 'node:path'; import { getStoreRootFolder } from "../store/services/gamesService"; -import { getUpdates, runBunPackageCommand } from "./services"; -import { PluginSourceType } from "@simeonradivoev/gameflow-sdk/shared"; -import { taskQueue } from "../app"; -import EnsureStore from "../jobs/ensure-store"; -import { PluginRegistry } from "@/shared/constants"; -import { IsPluginAllowed } from "@/bun/utils"; type PluginEntry = PluginDescriptionType & { load: () => Promise; }; -const blacklist = new Set(['@simeonradivoev/gameflow-sdk']); - -export async function getPlugin (id: string, pluginManager: PluginManager) -{ - const pluginPath = path.join(getStoreRootFolder(), 'node_modules', id); - const pluginPackageFile = Bun.file(path.join(pluginPath, 'package.json')); - if (await pluginPackageFile.exists()) - { - const pluginPackage = await PluginDescriptionSchema.safeParseAsync(await pluginPackageFile.json()); - if (pluginPackage.success) - { - const mainPath = path.join(pluginPath, pluginPackage.data.main); - if (await Bun.file(mainPath).exists()) - { - const entry: PluginEntry = { ...pluginPackage.data, load: () => import(mainPath) }; - return entry; - } else - { - console.error("Main file for", id, "does not exist"); - } - } else - { - console.error("Invalid Package for", id, pluginPackage.error.message); - } - } else - { - console.error("Package for", id, "does not exist"); - } -} - -export async function unregisterPlugin (id: string, pluginManager: PluginManager) -{ - return pluginManager.unregister(id); -} - -export async function registerPlugin (plugin: PluginEntry, source: PluginSourceType, pluginManager: PluginManager) -{ - if (!IsPluginAllowed(plugin.name)) - { - console.log("Skipping", plugin.name, "plugin not allowed"); - return; - } - - const file = await plugin.load(); - if (file.default && typeof file.default === 'function') - { - const pluginInstance = new file.default(); - await PluginSchema.parseAsync(pluginInstance); - const description = await PluginDescriptionSchema.parseAsync(plugin); - pluginManager.register(pluginInstance, description, source); - } else - { - console.log("Skipping", plugin.name, "invalid main. Has to be class with load method"); - } -} - export default async function register (pluginManager: PluginManager) { const plugins: PluginEntry[] = [ @@ -95,59 +33,53 @@ export default async function register (pluginManager: PluginManager) { ...rclone, load: () => import('./builtin/other/com.simeonradivoev.gameflow.rclone/rclone') }, ]; - await Promise.all(plugins.map(p => registerPlugin(p, 'builtin', pluginManager))); + const storePackageFile = path.join(getStoreRootFolder(), 'package.json'); + const storePackage = await Bun.file(storePackageFile).json(); - if (IsPluginAllowed('@simeonradivoev/gameflow-store')) + if (storePackage.dependencies) { - const storePackageFilePath = path.join(getStoreRootFolder(), 'package.json'); - if (!await Bun.file(storePackageFilePath).exists()) + const storePlugins = await Promise.all(Object.keys(storePackage.dependencies).map(async p => { - console.log("Store is missing. Updating it."); - await taskQueue.enqueue(EnsureStore.id, new EnsureStore()); - console.log("Store Updated"); - } - const storePackage = await Bun.file(storePackageFilePath).json(); - - if (storePackage?.dependencies) - { - const storePlugins = await Promise.all(Object.keys(storePackage.dependencies).filter(p => !blacklist.has(p)).map(async p => + const pluginPath = path.join(getStoreRootFolder(), 'node_modules', p); + const pluginPackageFile = Bun.file(path.join(pluginPath, 'package.json')); + if (await pluginPackageFile.exists()) { - return getPlugin(p, pluginManager); - })); - - console.log("Checking for outdated packages"); - const outdated = await getUpdates(); - - const validPlugins = storePlugins.filter(p => !!p); - - if (outdated) - { - for (let i = 0; i < validPlugins.length; i++) + const pluginPackage = await PluginDescriptionSchema.safeParseAsync(await pluginPackageFile.json()); + if (pluginPackage.success) { - const plugin = validPlugins[i]; - const newVersion = outdated.find(i => i.package === plugin.name); - if (newVersion) + const mainPath = path.join(pluginPath, pluginPackage.data.main); + if (await Bun.file(mainPath).exists()) { - console.log("Plugin", plugin.name, "has update", plugin.version, "=>", newVersion.update); - - if (plugin.autoUpdate || plugin.name === '@simeonradivoev/gameflow-store') - { - console.log("Auto Updating Plugin", plugin.name); - let response = await runBunPackageCommand(["add", `${plugin.name}@${newVersion?.update}`, "--registry", PluginRegistry, '--omit', 'peer']); - console.log(response); - // Update plugin package - const newPlugin = await getPlugin(plugin.name, pluginManager); - if (newPlugin) - validPlugins[i] = newPlugin; - } + const entry: PluginEntry = { ...pluginPackage.data, load: () => import(mainPath) }; + return entry; } } } + })); - await Promise.all(validPlugins.map(p => registerPlugin(p, 'store', pluginManager))); - } - } else - { - console.log('Skipping Store Packages'); + plugins.push(...storePlugins.filter(p => !!p)); } + + await Promise.all(plugins.filter(p => + { + if (process.env.PLUGIN_WHITELIST && !process.env.PLUGIN_WHITELIST.includes(p.name)) + { + return false; + } + if (process.env.PLUGIN_BLACKLIST && process.env.PLUGIN_BLACKLIST.includes(p.name)) + { + return false; + } + return true; + }).map(async (pluginPackage) => + { + const file = await pluginPackage.load(); + if (file.default && typeof file.default === 'function') + { + const pluginInstance = new file.default(); + await PluginSchema.parseAsync(pluginInstance); + const description = await PluginDescriptionSchema.parseAsync(pluginPackage); + pluginManager.register(pluginInstance, description, 'builtin'); + } + })); } \ No newline at end of file diff --git a/src/bun/api/plugins/services.ts b/src/bun/api/plugins/services.ts deleted file mode 100644 index 8878809..0000000 --- a/src/bun/api/plugins/services.ts +++ /dev/null @@ -1,64 +0,0 @@ -import path from 'node:path'; -import os from 'node:os'; -import { getStoreRootFolder } from '../store/services/gamesService'; -import { PluginDescriptionType } from '@simeonradivoev/gameflow-sdk'; -import { existsSync } from 'node:fs'; -import { checkOutdated } from './update-check'; - -export function canDisable (description: PluginDescriptionType) -{ - if (description.name === '@simeonradivoev/gameflow-store') - { - return false; - } - return description.canDisable ?? true; -} - -export async function getUpdates () -{ - if (!existsSync(getStoreRootFolder())) return []; - const results = await checkOutdated(getStoreRootFolder()); - return results; -} - -export function canUninstall (description: PluginDescriptionType, source: string) -{ - if (description.name === '@simeonradivoev/gameflow-store') - { - return false; - } - return source !== 'builtin'; -} - -export async function runBunPackageCommand (commands: string[]) -{ - const tempCache = path.join(os.tmpdir(), "gameflow-bun-cache"); - const storeFolder = getStoreRootFolder(); - - let proc = Bun.spawn([process.execPath, ...commands, '--json'], { - cwd: storeFolder, - stdout: 'pipe', - stderr: 'pipe', - env: { - BUN_BE_BUN: "1", - BUN_INSTALL_CACHE_DIR: tempCache - } - }); - - let stdout = await new Response(proc.stdout).text(); - let stderr = await new Response(proc.stderr).text(); - if (stderr) - console.error(stderr); - await proc.exited; - return stdout; -} - -export async function hasPackage (id: string) -{ - const storeFolder = getStoreRootFolder(); - const packagePath = path.join(storeFolder, 'package.json'); - const packageFile = Bun.file(packagePath); - if (!await packageFile.exists()) return false; - const pkg = await packageFile.json(); - return !!pkg.dependencies?.[id]; -} \ No newline at end of file diff --git a/src/bun/api/plugins/update-check.ts b/src/bun/api/plugins/update-check.ts deleted file mode 100644 index 66cf381..0000000 --- a/src/bun/api/plugins/update-check.ts +++ /dev/null @@ -1,169 +0,0 @@ -import { semver } from "bun"; -import { readFile } from "fs/promises"; -import { join } from "path"; -import { getOrCached } from "../cache"; -import { PluginRegistry } from "@/shared/constants"; -import sdkPkg from '@/packages/gameflow-sdk/package.json'; - -interface UpdateInfo -{ - package: string, - current: string, - update: string | null, - latest: string, - sdkConstrained: boolean, - sdkRange: string, - note: string | null; -} - -function parseBunOutdated (cwd: string) -{ - const proc = Bun.spawnSync([process.execPath, "outdated"], { - stderr: "inherit", env: { - BUN_BE_BUN: "1", - NO_COLOR: "1", - }, cwd: cwd - }); - const output = proc.stdout.toString(); - const lines = output.split("\n").filter(Boolean); - - const headerIndex = lines.findIndex( - (l) => l.includes("Package") && l.includes("Current") - ); - if (headerIndex === -1) return []; - - return lines - .slice(headerIndex + 1) - .filter((line) => !/^[-─╌| ]+$/.test(line)) - .map((line) => - { - const [, pkg, current, , latest] = line.split("|").map((c) => c.trim()); - return pkg ? { package: pkg, current, latest } : null; - }) - .filter(p => p !== null); -} - -async function getInstalledVersion (cwd: string, pkg: string) -{ - try - { - const raw = await readFile(join(cwd, "node_modules", pkg, "package.json"), "utf8"); - return JSON.parse(raw).version ?? null; - } catch - { - return null; - } -} - -async function fetchAllVersions (pkg: string) -{ - const res = await fetch(`${PluginRegistry}/${pkg}`); - if (!res.ok) return []; - const data = await res.json(); - return Object.keys(data.versions ?? {}); -} - -async function fetchPeerDeps (pkg: string, version: string) -{ - const peerDependencies = await getOrCached(`npm-${pkg}-${version}`, async () => - { - const res = await fetch(`${PluginRegistry}/${pkg}/${version}`); - if (!res.ok) - { - throw new Error(`Error while fetching peer deps for ${pkg} ${version} ${res.status} ${res.statusText}`); - } - const data = await res.json(); - return data.peerDependencies ?? {}; - }, { - //5 days - expireMs: 1000 * 60 * 60 * 24 * 5 - }); - - - return peerDependencies; -} - -async function findBestVersion (pkg: string, allVersions: string[], sdkVersion: string) -{ - // Sort descending so we find the highest compatible version first - const sorted = [...allVersions].sort((a, b) => semver.order(b, a)); - - for (const version of sorted) - { - const peers = await fetchPeerDeps(pkg, version); - const sdkRange = peers[sdkPkg.name]; - - if (!sdkRange) - { - // No peer dep on SDK — compatible by default - return { version, sdkRange: null }; - } - - if (semver.satisfies(sdkVersion, sdkRange)) - { - return { version, sdkRange }; - } - } - - return null; -} - -export async function checkOutdated (cwd: string) -{ - const outdated = parseBunOutdated(cwd); - - if (outdated.length === 0) - { - return []; - } - - const sdkVersion = await getInstalledVersion(cwd, sdkPkg.name); - if (!sdkVersion) - { - console.error(`Could not find installed version of ${sdkPkg.name} in node_modules.`); - process.exit(1); - } - - const results = await Promise.all( - outdated.map(async ({ package: pkg, current, latest }) => - { - const allVersions = await fetchAllVersions(pkg); - - // Check if the outright latest is already SDK compatible - const latestPeers = await fetchPeerDeps(pkg, latest); - const latestSdkRange = latestPeers[sdkPkg.name]; - - const latestCompatible = - !latestSdkRange || semver.satisfies(sdkVersion, latestSdkRange); - - if (latestCompatible) - { - return { - package: pkg, - current, - update: latest, - latest, - sdkConstrained: false, - sdkRange: latestSdkRange ?? null, - note: null - } satisfies UpdateInfo as UpdateInfo; - } - - const best = await findBestVersion(pkg, allVersions, sdkVersion); - - return { - package: pkg, - current, - update: best?.version ?? null, - latest, - sdkConstrained: true, - sdkRange: best?.sdkRange ?? null, - note: best - ? `Latest (${latest}) requires incompatible SDK range; best compatible: ${best.version}` - : `No version of ${pkg} is compatible with ${sdkPkg.name}@${sdkVersion}`, - } satisfies UpdateInfo as UpdateInfo; - }) - ); - - return results; -} \ No newline at end of file diff --git a/src/bun/api/schema/app.ts b/src/bun/api/schema/app.ts index 7db68ba..a30c4fb 100644 --- a/src/bun/api/schema/app.ts +++ b/src/bun/api/schema/app.ts @@ -1,5 +1,4 @@ - -import { LocalGameMetadata } from "@simeonradivoev/gameflow-sdk/shared"; +import { LocalGameMetadata } from "@/shared/types"; import { sql, relations } from "drizzle-orm"; import { integer, text, sqliteTable, blob } from "drizzle-orm/sqlite-core"; diff --git a/src/bun/api/settings/services.ts b/src/bun/api/settings/services.ts index e0897ea..a560de6 100644 --- a/src/bun/api/settings/services.ts +++ b/src/bun/api/settings/services.ts @@ -7,7 +7,7 @@ import { cores } from '../emulatorjs/emulatorjs'; import { SERVER_URL } from '@/shared/constants'; import { host } from '@/bun/utils/host'; import { findEmulatorPluginIntegration } from '../store/services/emulatorsService'; -import { EmulatorSourceEntryType, FrontEndEmulator } from '@simeonradivoev/gameflow-sdk/shared'; +import { EmulatorSourceEntryType, FrontEndEmulator } from '@/shared/types'; /** * Get emulators based on local games. Only the ones we probably need. diff --git a/src/bun/api/settings/settings.ts b/src/bun/api/settings/settings.ts index ebd5b91..c315701 100644 --- a/src/bun/api/settings/settings.ts +++ b/src/bun/api/settings/settings.ts @@ -1,5 +1,5 @@ import z from "zod"; -import { SettingsSchema } from '@simeonradivoev/gameflow-sdk/shared'; +import { SettingsSchema } from "@shared/constants"; import Elysia, { status } from "elysia"; import { config, customEmulators, plugins, taskQueue } from "../app"; import fs from 'node:fs/promises'; @@ -10,8 +10,6 @@ import { getRelevantEmulators } from "./services"; import type { JSONSchema7 } from "json-schema"; import ReloadPluginsJob from "../jobs/reload-plugins-job"; import { pluginZodRegistry } from "../plugins/plugin-manager"; -import { TestDownloadJob } from "../jobs/test-download-job"; -import { randomUUIDv7 } from "bun"; export const settings = new Elysia({ prefix: '/api/settings' }) .get('/emulators/automatic', async () => @@ -98,31 +96,27 @@ export const settings = new Elysia({ prefix: '/api/settings' }) }) .get('/definitions/:source', async ({ params: { source } }) => { - return plugins.plugins[decodeURIComponent(source)].plugin.settingsSchema?.toJSONSchema() as JSONSchema7; + return plugins.plugins[source].plugin.settingsSchema?.toJSONSchema() as JSONSchema7; }) .get('/actions/:source', async ({ params: { source } }) => { - const plugin = plugins.plugins[decodeURIComponent(source)]?.plugin; + const plugin = plugins.plugins[source]?.plugin; if (!plugin.eventsNames) return []; return plugin.eventsNames; }) .post('/actions/:source/:id', async ({ params: { source, id } }) => { - return await plugins.plugins[decodeURIComponent(source)]?.plugin.onEvent?.(decodeURIComponent(id)); + return await plugins.plugins[source]?.plugin.onEvent?.(id); }) .get('/:source/:id', async ({ params: { source, id } }) => { - return { value: plugins.plugins[decodeURIComponent(source)].config?.get(decodeURIComponent(id)) }; - }) - .post('/test/download', async () => - { - taskQueue.enqueue(randomUUIDv7(), new TestDownloadJob()); + return { value: plugins.plugins[source].config?.get(id) }; }) .put('/:source/:id', async ({ params: { source, id }, body: { value } }) => { - const plugin = plugins.plugins[decodeURIComponent(source)]; + const plugin = plugins.plugins[source]; if (!plugin.config) return status("Not Found", "Plugin has no config"); - const settingSchema = plugin.plugin.settingsSchema?.shape[decodeURIComponent(id)] as z.ZodObject; + const settingSchema = plugin.plugin.settingsSchema?.shape[id] as z.ZodObject; if (!settingSchema) return status("Not Found", "Could not find setting"); const meta = pluginZodRegistry.get(settingSchema); diff --git a/src/bun/api/store/services/emulatorsService.ts b/src/bun/api/store/services/emulatorsService.ts index 6dfcde1..c61ed00 100644 --- a/src/bun/api/store/services/emulatorsService.ts +++ b/src/bun/api/store/services/emulatorsService.ts @@ -1,7 +1,8 @@ +import { EmulatorDownloadInfoType, EmulatorPackageType, ScoopPackageSchema } from "@/shared/constants"; import { config, plugins } from "../../app"; import { getOrCached, getOrCachedGithubRelease } from "../../cache"; import path from "node:path"; -import { EmulatorSourceEntryType, EmulatorSupport, ScoopPackageSchema, EmulatorPackageType, EmulatorDownloadInfoType } from "@simeonradivoev/gameflow-sdk/shared"; +import { EmulatorSourceEntryType, EmulatorSupport } from "@/shared/types"; export function findEmulatorPluginIntegration (name: string, validSources: (EmulatorSourceEntryType | undefined)[]): EmulatorSupport[] { diff --git a/src/bun/api/store/services/gamesService.ts b/src/bun/api/store/services/gamesService.ts index b475b89..f2149ff 100644 --- a/src/bun/api/store/services/gamesService.ts +++ b/src/bun/api/store/services/gamesService.ts @@ -1,9 +1,10 @@ +import { EmulatorPackageSchema, EmulatorPackageType } from "@/shared/constants"; import { and, eq, or } from "drizzle-orm"; import { config, emulatorsDb } from '../../app'; import path from "node:path"; import fs from 'node:fs/promises'; import * as emulatorSchema from '@schema/emulators'; -import { EmulatorSystem, EmulatorPackageType, EmulatorPackageSchema } from "@simeonradivoev/gameflow-sdk/shared"; +import { EmulatorSystem } from "@/shared/types"; export function getStoreRootFolder () { diff --git a/src/bun/api/store/store.ts b/src/bun/api/store/store.ts index 7706699..85463b3 100644 --- a/src/bun/api/store/store.ts +++ b/src/bun/api/store/store.ts @@ -3,6 +3,7 @@ import Elysia, { status } from "elysia"; import { config, db, plugins, taskQueue } from "../app"; import path from "node:path"; import fs from 'node:fs/promises'; +import { EmulatorDownloadInfoSchema } from "@/shared/constants"; import * as appSchema from '@schema/app'; import z from "zod"; import { convertLocalToFrontendDetailed, getLocalGameMatch } from "../games/services/utils"; @@ -12,17 +13,7 @@ import { getStoreFolder } from "./services/gamesService"; import { EmulatorDownloadJob } from "../jobs/emulator-download-job"; import { BiosDownloadJob } from "../jobs/bios-download-job"; import { findEmulatorPluginIntegration, getEmulatorPath } from "./services/emulatorsService"; -import { EmulatorSourceEntryType, FrontEndEmulator, FrontEndGameTypeDetailed, PluginBunDetailsSchema, PluginEntrySchema, EmulatorDownloadInfoSchema } from "@simeonradivoev/gameflow-sdk/shared"; -import PQueue from "p-queue"; -import { hasPackage, runBunPackageCommand } from "../plugins/services"; -import { semver } from "bun"; - -const npmQueue = new PQueue({ intervalCap: 60, interval: 1000 * 60, strict: true }); -const pluginsResponseSchema = z.object({ - objects: z.array(PluginEntrySchema), - total: z.number(), - time: z.coerce.date() -}); +import { EmulatorSourceEntryType, FrontEndEmulator, FrontEndGameTypeDetailed } from "@/shared/types"; export const store = new Elysia({ prefix: '/api/store' }) .get('/emulators', async ({ query }) => @@ -118,49 +109,6 @@ export const store = new Elysia({ prefix: '/api/store' }) gameCount }; }) - .get('/plugin', async ({ query: { plugin } }) => - { - const pluginsRes = await runBunPackageCommand(['info', plugin]); - const pluginData = await PluginBunDetailsSchema.parseAsync(JSON.parse(pluginsRes)); - const existingVersion = plugins.plugins[plugin]?.description.version; - - return { - ...pluginData, - installed: !!plugins.plugins[plugin] || await hasPackage(plugin), - update: existingVersion && semver.order(pluginData.version, existingVersion) > 0 ? { from: existingVersion } : undefined - }; - }, - { - query: z.object({ plugin: z.string() }) - }) - .get('/plugins', async ({ query: { search } }) => - { - //TODO: Find a better way to search keywords and a search term at the same time - const pluginsRes = await npmQueue.add(() => fetch(`https://registry.npmjs.com/-/v1/search?text=keywords:gameflow-plugin`)); - if (!pluginsRes.ok) return status(pluginsRes.status, pluginsRes.statusText); - const data: z.infer = await pluginsRes.json(); - if (search) - { - data.objects = data.objects.filter(o => - { - if (o.package.description && o.package.description.includes(search)) return true; - if (o.package.name.includes(search)) return true; - if (o.package.keywords.includes(search)) return true; - return false; - }); - data.total = data.objects.length; - } - await Promise.all(data.objects.map(async o => - { - const existingVersion = plugins.plugins[o.package.name]?.description.version; - o.installed = !!plugins.plugins[o.package.name] || await hasPackage(o.package.name); - o.update = existingVersion && semver.order(o.package.version, existingVersion) > 0 ? { from: existingVersion } : undefined; - })); - return data as any; - }, { - query: z.object({ search: z.string().optional() }), - response: pluginsResponseSchema - }) .get('/media/*', async ({ params }) => { return Bun.file(path.join(getStoreFolder(), params["*"])); @@ -188,16 +136,16 @@ export const store = new Elysia({ prefix: '/api/store' }) emulator.integrations = integrations; return emulator; }, { params: z.object({ id: z.string() }) }) - .post('/install/emulator/:id/:source', async ({ params: { source, id }, body }) => + .post('/install/emulator/:id/:source', async ({ params: { source, id }, body: { isUpdate } }) => { if (taskQueue.hasActiveOfType(EmulatorDownloadJob)) { return status("Conflict", "Installation already running"); } - const job = new EmulatorDownloadJob(id, source, body); + const job = new EmulatorDownloadJob(id, source, { isUpdate }); return taskQueue.enqueue(EmulatorDownloadJob.id, job); }, { - body: z.object({ isUpdate: z.boolean().optional() }).optional() + body: z.object({ isUpdate: z.boolean().optional() }) }) .delete('/emulator/:id', async ({ params: { id } }) => { diff --git a/src/bun/api/system.ts b/src/bun/api/system.ts index 2124144..66e7742 100644 --- a/src/bun/api/system.ts +++ b/src/bun/api/system.ts @@ -7,7 +7,7 @@ import { getAppVersion, isSteamDeck, openExternal } from "../utils"; import fs from 'node:fs/promises'; import buildNotificationsStream from "./notifications"; import path, { dirname } from "node:path"; -import { SystemInfoSchema, DirSchema, DownloadsDrive } from '@simeonradivoev/gameflow-sdk/shared'; +import { DirSchema, SystemInfoSchema } from "@/shared/constants"; import { getDevices, getDevicesCurated } from "./drives"; import getFolderSize from "get-folder-size"; import si from 'systeminformation'; @@ -16,6 +16,7 @@ import ReloadPluginsJob from "./jobs/reload-plugins-job"; import { semver } from "bun"; import { getOrCachedGithubRelease } from "./cache"; import SelfUpdateJob from "./jobs/self-update-job"; +import { DownloadsDrive } from "@/shared/types"; async function checkUpdate (force?: boolean) { @@ -86,7 +87,6 @@ export const system = new Elysia({ prefix: '/api/system' }) z.object({ type: z.literal('info'), data: SystemInfoSchema }), z.object({ type: z.literal('focus') }), z.object({ type: z.literal('loading'), progress: z.number(), state: z.string().optional() }), - z.object({ type: z.literal('activeTask'), progress: z.number().nullable() }), z.object({ type: z.literal('loaded') }), ]), async open (ws) @@ -95,8 +95,6 @@ export const system = new Elysia({ prefix: '/api/system' }) if (existingLoading) ws.send({ type: 'loading', progress: existingLoading.progress, state: existingLoading.state }); else ws.send({ type: 'loaded' }); - ws.send({ type: 'activeTask', progress: taskQueue.getActiveJobs()[0]?.progress }); - const startInfo = async () => { const battery = await si.battery(); @@ -119,8 +117,6 @@ export const system = new Elysia({ prefix: '/api/system' }) dispose.push(taskQueue.on('progress', e => { - ws.send({ type: 'activeTask', progress: e.progress }); - if (e.id === ReloadPluginsJob.id) { ws.send({ type: "loading", progress: e.progress, state: e.state }); @@ -132,8 +128,6 @@ export const system = new Elysia({ prefix: '/api/system' }) })); dispose.push(taskQueue.on('started', e => { - ws.send({ type: 'activeTask', progress: 0 }); - if (e.id === ReloadPluginsJob.id) ws.send({ type: "loading", progress: e.job.progress, state: e.job.state }); else if (e.id === SelfUpdateJob.id) @@ -141,7 +135,6 @@ export const system = new Elysia({ prefix: '/api/system' }) })); dispose.push(taskQueue.on('ended', e => { - ws.send({ type: 'activeTask', progress: null }); if (e.id !== ReloadPluginsJob.id && e.id !== SelfUpdateJob.id) return; ws.send({ type: "loaded" }); })); diff --git a/src/packages/gameflow-sdk/task-queue.ts b/src/bun/api/task-queue.ts similarity index 74% rename from src/packages/gameflow-sdk/task-queue.ts rename to src/bun/api/task-queue.ts index e86cebc..97e783d 100644 --- a/src/packages/gameflow-sdk/task-queue.ts +++ b/src/bun/api/task-queue.ts @@ -1,7 +1,6 @@ - +import { JobStatus } from '@/shared/types'; import EventEmitter from 'node:events'; import z from 'zod'; -import { JobStatus } from './shared'; export class TaskQueue { @@ -18,24 +17,14 @@ export class TaskQueue }); } - public enqueue (id: string, job: T, options?: { throwOnCancel?: boolean; }): T extends IJob + public enqueue (id: string, job: T, throwOnError?: boolean): T extends IJob ? Promise : never { this.disposeSafeguard(); if (!this.queue || !this.events) throw new Error("Queue disposed"); - if (this.activeQueue.some(j => j.id === id)) throw new Error(`Job with ID ${id} already active`); - if (this.queue.some(j => j.id === id)) throw new Error(`Job with ${id} already queued`); - const context = new JobContext(id, this.events, job, options); + const context = new JobContext(id, this.events, job); this.queue.push(context as any); - context.abortSignal.addEventListener('abort', () => - { - const queueIndex = this.queue?.findIndex(c => c === context); - if (queueIndex !== undefined && queueIndex >= 0) - { - this.queue?.splice(queueIndex, 1); - } - }); this.events?.emit('queued', { id: context.id, job: context }); this.processQueue(); return context.promise.promise as any; @@ -45,24 +34,7 @@ export class TaskQueue { if (!this.queue) return Promise.resolve(); - let activeGroupsSet = new Set(this.activeQueue.filter(j => j.job.group).map(j => j.job.group)); - const next = this.queue.filter(j => - { - if (j.job.group) - { - // Only take one task per group to be active - if (!activeGroupsSet.has(j.job.group)) - { - activeGroupsSet.add(j.job.group); - return true; - } - } else - { - return true; - } - - return false; - }).map((job, i) => ({ i, job })); + const next = this.queue.filter(j => !j.job.group || !this.activeQueue.some(a => a.job.group === j.job.group)).map((job, i) => ({ i, job })); next.reverse().forEach(({ i }) => this.queue!.splice(i, 1)); @@ -91,11 +63,6 @@ export class TaskQueue return this.activeQueue.length > 0; } - public hasQueued () - { - return this.queue && this.queue.length > 0; - } - public hasActiveOfType (type: any) { for (const entry of this.activeQueue) @@ -114,38 +81,6 @@ export class TaskQueue return job?.promise.promise ?? Promise.resolve(); } - public waitForAll () - { - return new Promise((resolve) => - { - if (!this.hasActive()) - { - resolve(true); - return; - } - - const handleEnded = () => - { - if (!this.hasActive() && !this.hasQueued()) - { - resolve(true); - this.events?.removeListener('ended', handleEnded); - this.events?.removeListener('abort', handleEnded); - } - }; - this.events?.on('ended', handleEnded); - this.events?.on('abort', handleEnded); - }); - } - - public cancelJob (id: string) - { - const job = this.queue?.find(j => j.id === id) - ?? this.activeQueue?.find(j => j.id === id); - - job?.abort('cancel'); - } - public findJob ( id: string, type: new (...args: any[]) => T @@ -163,16 +98,6 @@ export class TaskQueue return undefined as any; } - public getActiveJobs () - { - return this.activeQueue; - } - - public getQueuedJobs () - { - return this.queue; - } - public on (event: E, listener: E extends keyof EventsList ? EventsList[E] extends unknown[] ? (...args: EventsList[E]) => void : never : never): () => void { this.events?.on(event, listener); @@ -244,7 +169,6 @@ export interface CompletedEvent extends BaseEvent export interface IJob { - /** What group does the job belong to. Grouped jobs can only have 1 active job per group */ group?: string; start (context: JobContext, TData, TState>): Promise; exposeData?(): TData; @@ -285,14 +209,12 @@ export class JobContext, TData, TState extends str private events: EventEmitter; private abortController: AbortController; private m_promise: PromiseWithResolvers; - private throwOnCancel: boolean; private readonly m_job: T; - constructor(id: string, events: EventEmitter, job: T, options?: { throwOnCancel?: boolean; }) + constructor(id: string, events: EventEmitter, job: T) { this.m_id = id; this.m_job = job; - this.throwOnCancel = options?.throwOnCancel ?? false; this.abortController = new AbortController(); this.abortController.signal.addEventListener('abort', () => { @@ -324,13 +246,7 @@ export class JobContext, TData, TState extends str { if (error.target instanceof AbortSignal) { - if (this.throwOnCancel) - { - this.m_promise.reject(this.abortSignal.reason); - } else - { - this.m_promise.resolve(undefined); - } + this.m_promise.resolve(undefined); } else { console.error(error); diff --git a/src/packages/gameflow-sdk/index.ts b/src/bun/types/types.schema.ts similarity index 69% rename from src/packages/gameflow-sdk/index.ts rename to src/bun/types/types.schema.ts index c78c757..c4738fc 100644 --- a/src/packages/gameflow-sdk/index.ts +++ b/src/bun/types/types.schema.ts @@ -1,20 +1,7 @@ import z from "zod"; -import { GameflowHooks } from "./hooks/app"; -import { EmulatorDownloadInfoSchema, EmulatorPackageSchema, FrontendNotification, SettingsType } from "./shared"; -import { $ZodRegistry } from "zod/v4/core"; +import GameflowHooks from "../api/hooks/app"; import Conf from "conf"; -import { EventEmitter } from 'node:events'; -import { TaskQueue } from "./task-queue"; - -export * from "./hooks/app"; -export * from "./task-queue"; - -export interface AppEventMap -{ - exitapp: []; - notification: [FrontendNotification]; - focus: []; -} +import { $ZodRegistry } from "zod/v4/core"; export const PluginContextSchema = z.object({ hooks: z.instanceof(GameflowHooks) @@ -23,26 +10,19 @@ export const PluginContextSchema = z.object({ export const PluginLoadingContextSchema = z.object({ setProgress: z.function().input([z.number(), z.string()]).output(z.void()), config: z.instanceof(Conf).describe("Per plugin config. It will use the settings schema defined in the plugin class"), - zodRegistry: z.instanceof($ZodRegistry).describe("Used by the settings to register metadata for the UI"), - app: z.object({ - config: z.instanceof(Conf), - events: z.instanceof(EventEmitter), - taskQueue: z.instanceof(TaskQueue) - }) + zodRegistry: z.instanceof($ZodRegistry).describe("Used by the settings to register metadata for the UI") }).extend(PluginContextSchema.shape); export const PluginDescriptionSchema = z.object({ name: z.string(), - displayName: z.string().optional(), + displayName: z.string(), version: z.string(), - description: z.string().optional(), + description: z.string(), icon: z.url().optional().describe("Can be an external URL to an image or a data url"), keywords: z.array(z.string()).optional(), - peerDependencies: z.record(z.string(), z.string()).optional(), category: z.string().default("other"), main: z.string().describe("The main entry. It must export a default class implementing PluginType"), - canDisable: z.boolean().default(true).optional().describe("Can the plugin be disabled or enabled by the user"), - autoUpdate: z.boolean().optional().describe("Should the plugin auto update to latest version") + canDisable: z.boolean().default(true).optional().describe("Can the plugin be disabled or enabled by the user") }); export const PluginSchema = z.object({ @@ -62,6 +42,16 @@ export const PluginSchema = z.object({ }).or(z.record(z.string(), z.any()))).optional() }); +export type PluginType = Record> = Omit, "load" | 'settingsMigrations'> & { + load: (ctx: PluginLoadingContextType) => Promise; + settingsMigrations?: Record) => void>; +}; +export type PluginContextType = z.infer; +export type PluginLoadingContextType = Record> = z.infer & { + config: Conf; +}; +export type PluginDescriptionType = z.infer; + export const ActiveGameSchema = z.object({ process: z.any().optional(), gameId: z.object({ id: z.string(), source: z.string() }), @@ -70,24 +60,4 @@ export const ActiveGameSchema = z.object({ name: z.string(), command: z.object({ command: z.string().or(z.string().array()), startDir: z.string().optional() }) }); - -export const EmulatorPostInstallContextSchema = z.object({ - emulator: z.string(), - emulatorPackage: EmulatorPackageSchema.optional(), - path: z.string(), - update: z.boolean(), - info: EmulatorDownloadInfoSchema, -}); - -export type ActiveGameType = z.infer; -export type PluginDescriptionType = z.infer; -export type PluginContextType = z.infer; -export type PluginLoadingContextType = Record> = z.infer & { - config: Conf; -}; -export type PluginType = Record> = Omit, "load" | 'settingsMigrations'> & { - load: (ctx: PluginLoadingContextType) => Promise; - settingsMigrations?: Record) => void>; -}; -export type EmulatorPostInstallContextType = z.infer; - +export type ActiveGameType = z.infer; \ No newline at end of file diff --git a/src/bun/types/types.ts b/src/bun/types/types.ts new file mode 100644 index 0000000..6802ff9 --- /dev/null +++ b/src/bun/types/types.ts @@ -0,0 +1,18 @@ +import { EmulatorDownloadInfoType, EmulatorPackageType } from "@/shared/constants"; +import { FrontendNotification } from "@/shared/types"; + +export interface AppEventMap +{ + exitapp: []; + notification: [FrontendNotification]; + focus: []; +} + +export interface EmulatorPostInstallContext +{ + emulator: string; + emulatorPackage?: EmulatorPackageType; + path: string; + update: boolean; + info: EmulatorDownloadInfoType; +} \ No newline at end of file diff --git a/src/bun/utils.ts b/src/bun/utils.ts index 6fbc630..f03a42c 100644 --- a/src/bun/utils.ts +++ b/src/bun/utils.ts @@ -1,11 +1,10 @@ import { $, sleep } from 'bun'; import path from 'node:path'; -import { SettingsType, KeysWithValueAssignableTo } from '@simeonradivoev/gameflow-sdk/shared'; +import { SettingsType } from '@/shared/constants'; import { config } from './api/app'; import fs from 'node:fs/promises'; import packageDef from '~/package.json'; - -const archiveRegex = /.(zip|rar|7zip|7z|tar|tar.gz)$/i; +import { KeysWithValueAssignableTo } from '@/shared/types'; export function checkRunning (pid: number) { @@ -180,24 +179,4 @@ export async function moveAllFiles (srcDir: string, destDir: string) export function getAppVersion () { return process.env.VERSION_OVERRIDE ?? packageDef.version; -} - -export function isArchive (path: string) -{ - return archiveRegex.test(path); -} - -export function IsPluginAllowed (id: string) -{ - if (process.env.PLUGIN_WHITELIST && !process.env.PLUGIN_WHITELIST.includes(id)) - { - return false; - } - - if (process.env.PLUGIN_BLACKLIST && process.env.PLUGIN_BLACKLIST.includes(id)) - { - return false; - } - - return true; } \ No newline at end of file diff --git a/src/bun/utils/downloader.ts b/src/bun/utils/downloader.ts index 920e7c8..000542a 100644 --- a/src/bun/utils/downloader.ts +++ b/src/bun/utils/downloader.ts @@ -5,7 +5,12 @@ import fs from 'node:fs/promises'; import { createWriteStream } from "node:fs"; import { config, jar } from "../api/app"; import { moveAllFiles } from "../utils"; -import { DownloadFileEntry, ProgressStats } from "@simeonradivoev/gameflow-sdk/shared"; +import { DownloadFileEntry } from "@/shared/types"; + +export interface ProgressStats +{ + progress: number; +} interface TmpDownloadMetadata { @@ -27,7 +32,6 @@ export class Downloader id: string; tmpPath: string; tmpPathMeta: string; - downloadSpeed: number = 0; /** * @@ -159,7 +163,10 @@ export class Downloader }); const totalBytes = totalSize || Number(res.headers.get("content-length")) || 0; - bytesReceived += start; + if (totalSize <= 0) + bytesReceived = 0; + else + bytesReceived += start; const reader = res.body!.getReader(); @@ -174,11 +181,10 @@ export class Downloader if (totalBytes > 0 && this.onProgress) { const percent = (bytesReceived / totalBytes) * 100; - const timeDelta = Date.now() - lastUpdate; - if (timeDelta > 100) + + if (Date.now() - lastUpdate > 100) { - this.downloadSpeed = this.downloadSpeed * 0.8 + Math.round(value.length / (timeDelta / 1000)) * 0.2; - this.onProgress({ progress: percent, downloaded: bytesReceived, total: totalBytes, speed: this.downloadSpeed }); + this.onProgress({ progress: percent }); lastUpdate = Date.now(); } } @@ -188,7 +194,7 @@ export class Downloader if (this.signal.reason === 'cancel') { console.log("Canceling Download and cleaning up files"); - await fs.rm(this.tmpPath, { recursive: true, maxRetries: 3, retryDelay: 3 }); + await fs.rm(this.tmpPath, { recursive: true }); await fs.rm(this.tmpPathMeta); return; } diff --git a/src/mainview/components/AppCommunication.tsx b/src/mainview/components/AppCommunication.tsx index df727ad..bbb26c3 100644 --- a/src/mainview/components/AppCommunication.tsx +++ b/src/mainview/components/AppCommunication.tsx @@ -1,14 +1,13 @@ import { useEffect, useRef, useState } from "react"; -import { AppContext, SystemInfoContext } from "../scripts/contexts"; +import { SystemInfoContext } from "../scripts/contexts"; import { systemApi } from "../scripts/clientApi"; -import { AppInfoContext, SystemInfoType } from '@simeonradivoev/gameflow-sdk/shared'; +import { SystemInfoType } from "@/shared/constants"; import LoadingScreen from "./LoadingScreen"; import { GamepadKeyboard } from "./GamepadKeyboard"; export default function AppCommunication (data: { children: any; }) { const [systemInfo, setSystemInfo] = useState(); - const [appContext, setAppContext] = useState({} as AppInfoContext); const [loadingInfo, setLoadingInfo] = useState(undefined); const [loading, setLoading] = useState(true); const loadingProgressBarRef = useRef(null); @@ -26,9 +25,6 @@ export default function AppCommunication (data: { children: any; }) case "focus": window.focus(); break; - case "activeTask": - setAppContext(c => ({ ...c, activeTaskProgress: data.progress })); - break; case "loading": setLoadingInfo(data.state); if (loadingProgressBarRef.current) @@ -49,19 +45,17 @@ export default function AppCommunication (data: { children: any; }) }, []); return - - {loading ? - -
-
- - {loadingInfo} -
- + {loading ? + +
+
+ + {loadingInfo}
- - : data.children} - - + +
+
+ : data.children} + ; } \ No newline at end of file diff --git a/src/mainview/components/CardList.tsx b/src/mainview/components/CardList.tsx index 8511374..d05ce7b 100644 --- a/src/mainview/components/CardList.tsx +++ b/src/mainview/components/CardList.tsx @@ -6,7 +6,7 @@ import import CardElement, { GameCardParams } from "./CardElement"; import { JSX } from "react"; import { twMerge } from "tailwind-merge"; -import { GamePadButtonCode, Shortcut, useShortcuts } from "../scripts/shortcuts"; +import { GamePadButtonCode, useShortcuts } from "../scripts/shortcuts"; import { oneShot } from "../scripts/audio/audio"; export interface GameMetaExtra extends GameMeta @@ -16,7 +16,7 @@ export interface GameMetaExtra extends GameMeta focusKey: string; } -function LocalCardElement (data: { game: GameMetaExtra, i: number; onQuickAction?: (ctx: InteractParamsArgs) => void; } & FocusParams & InteractParams) +function LocalCardElement (data: { game: GameMetaExtra, i: number; } & FocusParams & InteractParams) { let preview: GameCardParams['preview'] = data.game.preview; if (!preview && data.game.previewUrls) @@ -31,28 +31,7 @@ function LocalCardElement (data: { game: GameMetaExtra, i: number; onQuickAction oneShot('click'); }; - const handleAltAction = (ctx: InteractParamsArgs) => - { - data.game.onQuickAction?.(); - data.onQuickAction?.({ event, focusKey: data.game.focusKey }); - oneShot('click'); - }; - - useShortcuts(data.game.focusKey, () => - { - const options: Shortcut[] = [{ - label: "Details", - button: GamePadButtonCode.A, - action: event => handleAction({ event, focusKey: data.game.focusKey }) - }]; - - if (data.onQuickAction || data.game.onQuickAction) - { - options.push({ label: "Play", button: GamePadButtonCode.X, action: event => handleAltAction({ event, focusKey: data.game.focusKey }) }); - } - - return options; - }, [data.onQuickAction, data.game.onQuickAction, data.game.focusKey]); + useShortcuts(data.game.focusKey, () => [{ label: "Details", button: GamePadButtonCode.A, action: event => handleAction({ event, focusKey: data.game.focusKey }) }]); return ( {data.games.map((g, i) => data.onSelectGame?.(g.id)} - i={i} - />)} + key={g.id} onFocus={data.onFocus} game={g} onAction={() => data.onSelectGame?.(g.id)} i={i} />)} {data.finalElement} diff --git a/src/mainview/components/CollectionsDetail.tsx b/src/mainview/components/CollectionsDetail.tsx index 72c391a..9d6632c 100644 --- a/src/mainview/components/CollectionsDetail.tsx +++ b/src/mainview/components/CollectionsDetail.tsx @@ -5,7 +5,7 @@ import { JSX, Suspense } from 'react'; import { FloatingShortcuts } from './Shortcuts'; import { AutoFocus } from './AutoFocus'; import { GamePadButtonCode, useShortcuts } from '../scripts/shortcuts'; -import { GameListFilterType } from '@simeonradivoev/gameflow-sdk/shared'; +import { GameListFilterType } from '@/shared/constants'; import { HandleGoBack } from '../scripts/utils'; import LoadingCardList from './LoadingCardList'; import { useQuery, useQueryClient } from '@tanstack/react-query'; diff --git a/src/mainview/components/ContextDialog.tsx b/src/mainview/components/ContextDialog.tsx index 54babea..353f429 100644 --- a/src/mainview/components/ContextDialog.tsx +++ b/src/mainview/components/ContextDialog.tsx @@ -64,7 +64,7 @@ export function OptionElement (data: DialogEntry & { onFocus?: () => void; class className={ twMerge("flex cursor-pointer sm:text-sm md:text-base group-focusable scroll-m-4")}> -
@@ -166,7 +166,7 @@ export function ContextDialog (data: { }] : [], [data.open]); return @@ -174,7 +174,7 @@ export function ContextDialog (data: {
-
    +
      {!!data.rootFocusKey && (data.showShortcuts ?? true) &&
    • } diff --git a/src/mainview/components/FrontEndGameCard.tsx b/src/mainview/components/FrontEndGameCard.tsx index 093be25..c6b8e12 100644 --- a/src/mainview/components/FrontEndGameCard.tsx +++ b/src/mainview/components/FrontEndGameCard.tsx @@ -4,7 +4,7 @@ import { FileQuestion, HardDrive, Store } from "lucide-react"; import { JSX } from "react"; import { FOCUS_KEYS } from "../scripts/types"; import { useRouter } from "@tanstack/react-router"; -import { FrontEndGameType, FrontEndId } from "@simeonradivoev/gameflow-sdk/shared"; +import { FrontEndGameType, FrontEndId } from "@/shared/types"; export default function FrontEndGameCard (data: { index: number, game: FrontEndGameType; showSource?: boolean; } & FocusParams & InteractParams) { diff --git a/src/mainview/components/GameList.tsx b/src/mainview/components/GameList.tsx index 1075a9f..67e689e 100644 --- a/src/mainview/components/GameList.tsx +++ b/src/mainview/components/GameList.tsx @@ -1,16 +1,13 @@ import { useSuspenseQuery } from "@tanstack/react-query"; import { GameMetaExtra, CardList } from "./CardList"; -import { DefaultRommStaleTime, RPC_URL } from "@shared/constants"; -import { GameListFilterType } from '@simeonradivoev/gameflow-sdk/shared'; -import { useNavigate, useRouter } from "@tanstack/react-router"; +import { DefaultRommStaleTime, GameListFilterType, RPC_URL } from "@shared/constants"; +import { useNavigate } from "@tanstack/react-router"; import { HardDrive } from "lucide-react"; import { JSX, useContext } from "react"; import { useLocalSetting } from "../scripts/utils"; import { AnimatedBackgroundContext } from "../scripts/contexts"; import { allGamesQuery } from "@queries/romm"; -import { FrontEndGameType, FrontEndId } from "@simeonradivoev/gameflow-sdk/shared"; -import { isUrl } from "@/shared/utils"; -import { FOCUS_KEYS } from "../scripts/types"; +import { FrontEndGameType, FrontEndId } from "@/shared/types"; export interface GameListParams extends FocusParams { @@ -19,7 +16,6 @@ export interface GameListParams extends FocusParams grid?: boolean, setBackground?: (url: string) => void; onGameSelect?: (id: FrontEndId, source: string | null, sourceId: string | null) => void; - onQuickAction?: (id: FrontEndId, source: string | null, sourceId: string | null) => void; focus?: string; className?: string; finalElement?: JSX.Element | JSX.Element[]; @@ -100,7 +96,7 @@ export function GameList (data: GameListParams) const previewUrls = g.path_covers.map(c => { - const url = isUrl(c) ? new URL(c) : new URL(`${RPC_URL(__HOST__)}${c}`); + const url = c.startsWith("http") ? new URL(c) : new URL(`${RPC_URL(__HOST__)}${c}`); url.searchParams.delete('ts'); return url; }); @@ -108,13 +104,13 @@ export function GameList (data: GameListParams) let platformUrl: URL | undefined = undefined; if (g.path_platform_cover) { - platformUrl = isUrl(g.path_platform_cover) ? new URL(g.path_platform_cover) : new URL(`${RPC_URL(__HOST__)}${g.path_platform_cover}`); + platformUrl = g.path_platform_cover.startsWith("http") ? new URL(g.path_platform_cover) : new URL(`${RPC_URL(__HOST__)}${g.path_platform_cover}`); platformUrl.searchParams.set('width', "64"); } return { id: `${g.id.source}@${g.id.id}`, - focusKey: FOCUS_KEYS.GAME_LIST_CARD(data.id, g.id), + focusKey: `${data.id}-${g.id.source}@${g.id.id}`, title: g.name ?? "", subtitle: (
      @@ -125,7 +121,6 @@ export function GameList (data: GameListParams) previewUrls: previewUrls, badges: badges, onSelect: () => data.onGameSelect ? data.onGameSelect(g.id, g.source, g.source_id) : handleDefaultSelect(g), - onQuickAction: data.onQuickAction ? () => data.onQuickAction?.(g.id, g.source, g.source_id) : undefined, onFocus: () => handleFocus(g.id, g.source, g.source_id) } satisfies GameMetaExtra; }, diff --git a/src/mainview/components/GamepadKeyboard.tsx b/src/mainview/components/GamepadKeyboard.tsx index 75005a1..7f3b994 100644 --- a/src/mainview/components/GamepadKeyboard.tsx +++ b/src/mainview/components/GamepadKeyboard.tsx @@ -60,7 +60,7 @@ function buildWheel (side: 0 | 1, shift: boolean, characters: boolean) const elements: JSX.Element[] = []; const refs: RefObject[] = []; const positions: { left: string; top: string; }[] = []; - const n = GetKeys(characters)[side].length, GAP = 0.028; + const W = 258, C = 129, R2 = 107, R1 = 42, n = GetKeys(characters)[side].length, GAP = 0.028; for (let i = 0; i < n; i++) { @@ -387,6 +387,10 @@ export function GamepadKeyboard () const magnitudeSqr = (x * x) + (y * y); const magnitude = Math.sqrt(magnitudeSqr); + const elementPos = keyIndex < 0 ? undefined : elements[side].positions[keyIndex]; + //const lerpX = (element?.left ?? 0); + //const lerpY = (element?.top ?? 0); + const size = 12; circle.style.left = `calc(50% + ${50 * x}% - 16px)`; circle.style.top = `calc(50% + ${50 * y}% - 16px)`; circle.style.opacity = `${1 - Math.pow(magnitude, 2)}`; diff --git a/src/mainview/components/GlobalContextDialog.tsx b/src/mainview/components/GlobalContextDialog.tsx deleted file mode 100644 index 0fcc23d..0000000 --- a/src/mainview/components/GlobalContextDialog.tsx +++ /dev/null @@ -1,28 +0,0 @@ -import { useState } from "react"; -import { GlobalDialogContext } from "../scripts/contexts"; -import { useContextDialog } from "./ContextDialog"; - -export default function GlobalContextDialog (data: { children: any; }) -{ - const [currentContext, setCurrentContext] = useState(undefined); - const [preferredChildFocusKey, setPreferredChildFocusKey] = useState(undefined); - const [onCloseCallback, setOnCloseCallback] = useState<(() => void) | undefined>(undefined); - - const { dialog, setOpen } = useContextDialog('global-context-dialog', { - content: currentContext, - onClose: onCloseCallback, - preferredChildFocusKey: preferredChildFocusKey - }); - return - {data.children} - {dialog} - ; -} \ No newline at end of file diff --git a/src/mainview/components/Header.tsx b/src/mainview/components/Header.tsx index d38ef5b..932dada 100644 --- a/src/mainview/components/Header.tsx +++ b/src/mainview/components/Header.tsx @@ -29,11 +29,10 @@ import { twMerge } from "tailwind-merge"; import { TwitchIcon } from "../scripts/brandIcons"; import { rommLoggedInQuery } from "../scripts/queries/romm"; import { twitchLoginVerificationQuery } from "../scripts/queries/settings"; -import { AppContext, SystemInfoContext } from "../scripts/contexts"; +import { SystemInfoContext } from "../scripts/contexts"; import { useNavigate, useRouter } from "@tanstack/react-router"; import { oneShot } from "../scripts/audio/audio"; import { hasUpdateQuery } from "../scripts/queries/system"; -import { GamePadButtonCode, useShortcuts } from "../scripts/shortcuts"; function HeaderAvatar (data: { id: string; @@ -74,7 +73,6 @@ export interface HeaderButton external?: boolean; action?: () => void; className?: string; - shortcutLabel?: string; } export interface HeaderAccount @@ -113,22 +111,14 @@ function NotificationStatus () function ClockStatus () { - const navigate = useNavigate(); - const app = useContext(AppContext); - const refClock = useRef(null); - const activeTaskProgress = app.activeTaskProgress; - const handleTaskClick = () => - { - navigate({ to: '/settings/tasks' }); - }; - const { ref, focusKey } = useFocusable({ focusKey: 'tasks-indicator', focusable: !!activeTaskProgress, onEnterPress: handleTaskClick }); + const ref = useRef(null); useEffect(() => { function update () { - if (refClock.current) + if (ref.current) { - refClock.current.textContent = new Date().toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' }); + ref.current.textContent = new Date().toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' }); } } @@ -152,16 +142,7 @@ function ClockStatus () return () => clearTimeout(timeout); }, []); - useShortcuts(focusKey, () => [{ - label: "Downloads", button: GamePadButtonCode.A, action (e) - { - handleTaskClick(); - }, - }]); - - return
      - - {activeTaskProgress ?
      : }
      ; + return
      ; } function BluetoothStatus () @@ -307,7 +288,6 @@ export function HeaderStatusBar (data: { buttons?: HeaderButton[]; buttonElement {data.buttonElements} {data.buttons?.map(b => {data.title} - , - id: "header-settings-btn", - action: goToSettings, - external: true, - shortcutLabel: "Settings" - } - ]} /> + , id: "header-settings-btn", action: goToSettings, external: true }]} /> diff --git a/src/mainview/components/HeaderSearchField.tsx b/src/mainview/components/HeaderSearchField.tsx index 198c552..36d0eb0 100644 --- a/src/mainview/components/HeaderSearchField.tsx +++ b/src/mainview/components/HeaderSearchField.tsx @@ -5,6 +5,7 @@ import { oneShot } from "../scripts/audio/audio"; import { Search } from "lucide-react"; import { RoundButton } from "./RoundButton"; import { useEventListener } from "usehooks-ts"; +import useActiveControl from "../scripts/gamepads"; import { twMerge } from "tailwind-merge"; function SearchInput (data: { @@ -96,10 +97,10 @@ export default function HeaderSearchField (data: { isFocusBoundary: data.compact && showInput }); - return
      + return
      {(!data.compact || showInput) && } - {data.compact && !showInput && setShowInput(true)} className="header-icon sm:size-10 md:size-14" id={`${data.id}-field`} >} + {data.compact && !showInput && setShowInput(true)} className="header-icon sm:size-10 md:size-14" id={`${data.id}-field`} >}
      ; } \ No newline at end of file diff --git a/src/mainview/components/LoadMoreButton.tsx b/src/mainview/components/LoadMoreButton.tsx index d52e4e0..d042049 100644 --- a/src/mainview/components/LoadMoreButton.tsx +++ b/src/mainview/components/LoadMoreButton.tsx @@ -1,7 +1,6 @@ import { setFocus, useFocusable } from "@noriginmedia/norigin-spatial-navigation"; import { FOCUS_KEYS } from "../scripts/types"; import { useIntersectionObserver } from "usehooks-ts"; -import { FrontEndId } from "@simeonradivoev/gameflow-sdk/shared"; export default function LoadMoreButton (data: { isFetching: boolean; hidden?: boolean, lastId?: FrontEndId; } & FocusParams & InteractParams) { diff --git a/src/mainview/components/Notifications.tsx b/src/mainview/components/Notifications.tsx index c13c4b6..4fbe03d 100644 --- a/src/mainview/components/Notifications.tsx +++ b/src/mainview/components/Notifications.tsx @@ -1,5 +1,5 @@ import { RPC_URL } from "@/shared/constants"; -import { FrontendNotification } from "@simeonradivoev/gameflow-sdk/shared"; +import { FrontendNotification } from "@/shared/types"; import { Clock, CloudUpload, Save } from "lucide-react"; import { useEffect } from "react"; import toast, { ToastOptions } from "react-hot-toast"; diff --git a/src/mainview/components/RoundButton.tsx b/src/mainview/components/RoundButton.tsx index 01f9017..386723b 100644 --- a/src/mainview/components/RoundButton.tsx +++ b/src/mainview/components/RoundButton.tsx @@ -9,11 +9,10 @@ export function RoundButton (data: { external?: boolean; style?: ButtonStyle; cssStyle?: CSSProperties; - shortcutLabel?: string; } & InteractParams & FocusParams) { return ( - diff --git a/src/mainview/components/Screenshots.tsx b/src/mainview/components/Screenshots.tsx index e65a965..42d76d3 100644 --- a/src/mainview/components/Screenshots.tsx +++ b/src/mainview/components/Screenshots.tsx @@ -8,7 +8,6 @@ import Carousel from "./Carousel"; import { ContextDialog } from "./ContextDialog"; import { GamePadButtonCode, useShortcuts } from "../scripts/shortcuts"; import { twMerge } from "tailwind-merge"; -import { isUrl } from "@/shared/utils"; function Screenshot (data: { path: string; index: number; setFocused?: (index: number) => void; } & InteractParams) { @@ -22,9 +21,8 @@ function Screenshot (data: { path: string; index: number; setFocused?: (index: n scrollIntoNearestParent(ref.current, { behavior: details.instant ? 'instant' : 'smooth' }); } }); 4096; - const url = isUrl(data.path) ? data.path : `${RPC_URL(__HOST__)}${data.path}`; return
      - focusSelf({ nativeEvent: e.nativeEvent })} src={url} loading="lazy" decoding="async" /> + focusSelf({ nativeEvent: e.nativeEvent })} src={`${RPC_URL(__HOST__)}${data.path}`} loading="lazy" decoding="async" />
      data.onAction?.({ event: e.nativeEvent, focusKey })}>
      ; } @@ -61,9 +59,8 @@ function Preview (data: { id: string; screenshots?: string[]; preview: number; s } } ], [data.preview, focusKey, data.screenshots?.length ?? 0]); - const url = isUrl(data.screenshots?.[data.preview]) ? data.screenshots?.[data.preview] : `${RPC_URL(__HOST__)}${data.screenshots?.[data.preview]}`; - return ; + return ; } export default function Screenshots (data: { screenshots?: string[]; className?: string; } & FocusParams) diff --git a/src/mainview/components/SelectMenu.tsx b/src/mainview/components/SelectMenu.tsx index 42d21c8..fa10743 100644 --- a/src/mainview/components/SelectMenu.tsx +++ b/src/mainview/components/SelectMenu.tsx @@ -2,7 +2,7 @@ import { ContextList, DialogEntry, useContextDialog } from "./ContextDialog"; import { GamePadButtonCode, useShortcuts } from "../scripts/shortcuts"; import { useMatchRoute, useNavigate, useRouter } from "@tanstack/react-router"; import { getCurrentFocusKey } from "@noriginmedia/norigin-spatial-navigation"; -import { DoorOpen, Gamepad2, Home, Puzzle, RefreshCcw, Settings, Store } from "lucide-react"; +import { DoorOpen, Gamepad2, Puzzle, RefreshCcw, Settings, Store } from "lucide-react"; import { systemApi } from "../scripts/clientApi"; import { FOCUS_KEYS } from "../scripts/types"; @@ -15,7 +15,7 @@ export default function SelectMenu (data: { rootFocusKey: string; }) const options: DialogEntry[] = [ { content: "Home", - icon: , + icon: , action (ctx) { setOpen(false); diff --git a/src/mainview/components/SideFilters.tsx b/src/mainview/components/SideFilters.tsx index 930bf2b..180030d 100644 --- a/src/mainview/components/SideFilters.tsx +++ b/src/mainview/components/SideFilters.tsx @@ -1,25 +1,25 @@ -import { DownloadsLookupFilter, DownloadsLookupFilterValues, GameListFilterType } from '@simeonradivoev/gameflow-sdk/shared'; +import { GameListFilterType } from "@/shared/constants"; import { RoundButton } from "./RoundButton"; import classNames from "classnames"; import { GamePadButtonCode, useShortcuts } from "../scripts/shortcuts"; import { useFocusable, FocusContext } from "@noriginmedia/norigin-spatial-navigation"; -import { ArrowDownAz, ClockArrowDown, CalendarArrowDown, Rocket, HardDrive, SortDesc, User, Drama, FunnelX, Store, ArrowUpDown, ArrowDown, ArrowUp } from "lucide-react"; +import { ArrowDownAz, ClockArrowDown, CalendarArrowDown, Rocket, HardDrive, SortDesc, User, Drama, FunnelX, Store } from "lucide-react"; import { sourceIconMap } from "./Constants"; -import { ContextList, DialogEntry } from "./ContextDialog"; -import { FrontEndFilterLists } from "@simeonradivoev/gameflow-sdk/shared"; -import { useContext } from 'react'; -import { GlobalDialogContext } from '../scripts/contexts'; +import { useContextDialog, ContextList, DialogEntry } from "./ContextDialog"; +import { FrontEndFilterLists } from "@/shared/types"; function FilterButton (data: { id: string, filters?: GameListFilterType, tooltip: string, icon: any; - dialog: (focNewSourceFocusKey: string) => void; + dialog: { + setToggle: (focNewSourceFocusKey?: string | undefined) => void; + }; isActive: boolean; }) { - const handleAction = () => data.dialog(data.id); + const handleAction = () => data.dialog.setToggle(data.id); useShortcuts(data.id, () => [{ label: data.tooltip, action: handleAction, button: GamePadButtonCode.A }]); return
      ; } -export function SideDownloadFilters (data: { - id: string, - filters?: DownloadsLookupFilter; - setLocalFilter: (filter: DownloadsLookupFilter) => void, - localFilter: DownloadsLookupFilter, - filterValues: DownloadsLookupFilterValues | undefined; -}) -{ - - const { ref, focusKey } = useFocusable({ focusKey: data.id }); - const globalDialog = useContext(GlobalDialogContext); - const orderByDialog = (focusKey: string) => globalDialog.openContext({ - content: ({ - content: o, - selected: data.localFilter.orderBy === o, - id: `sort-by-${o}`, - type: 'primary', - action (ctx) - { - data.setLocalFilter({ ...data.localFilter, orderBy: o }); - ctx.close(); - }, - }))} />, - preferredChildFocusKey: `sort-by-${data.localFilter.orderBy}` - }, focusKey); - - const orderDirectionDialog = (focusKey: string) => globalDialog.openContext({ - content: }, { label: 'desc', icon: }] - .map(o => ({ - content: o.label, - selected: data.localFilter.sortDirection === o.label, - icon: o.icon, - id: `sort-direction-${o.label}`, - type: 'primary', - action (ctx) - { - data.setLocalFilter({ ...data.localFilter, sortDirection: o.label as any }); - ctx.close(); - }, - })) - } />, - preferredChildFocusKey: `sort-direction-${data.localFilter.orderBy}` - }, focusKey); - - const sourceFilterDialog = (focusKey: string) => globalDialog.openContext({ - content: (o => ({ - content: o, - icon: sourceIconMap[o], - selected: data.localFilter.source === o, - id: `source-filter-${o}`, - type: 'primary', - action (ctx) - { - if (ctx.selected) data.setLocalFilter({ ...data.localFilter, source: undefined }); - else data.setLocalFilter({ ...data.localFilter, source: o }); - ctx.close(); - }, - }))} />, - preferredChildFocusKey: `source-filter-${data.localFilter.source}` - }, focusKey); - - return
      - - } /> - } /> - - {!data.filters?.source && - } /> - } - - {Object.values(data.localFilter).some(v => v !== undefined) && - <> -
      - data.setLocalFilter({})} className='p-3 drop-shadow-md!' > - - } -
      -
      ; -} - export default function SideFilters (data: { id: string, filters?: GameListFilterType; @@ -125,107 +42,96 @@ export default function SideFilters (data: { { const { ref, focusKey } = useFocusable({ focusKey: data.id }); - const globalDialog = useContext(GlobalDialogContext); - const openSourceDialog = (focusKey: string) => - { - globalDialog.openContext({ - content: (o => ({ - content: o, - icon: sourceIconMap[o], - selected: data.localFilter.source === o, - id: `source-filter-${o}`, - type: 'primary', - action (ctx) - { - if (ctx.selected) data.setLocalFilter({ ...data.localFilter, source: undefined }); - else data.setLocalFilter({ ...data.localFilter, source: o }); - ctx.close(); - }, - })).concat({ - content: "Local Only", - icon: , - selected: data.localFilter.localOnly === true, - id: `source-filter-local`, - type: 'primary', - action (ctx) - { - if (ctx.selected) data.setLocalFilter({ ...data.localFilter, localOnly: undefined }); - else data.setLocalFilter({ ...data.localFilter, localOnly: true }); - ctx.close(); - }, - })} />, preferredChildFocusKey: `source-filter-${data.localFilter.source}` - }, focusKey); - }; - - const openGenreDialog = (focusKey: string) => - { - globalDialog.openContext({ - content: ({ - content: g, - selected: data.localFilter.genres?.includes(g), - id: `genre-filter-${g}`, + const orderByDialog = useContextDialog('order-by-dialog', { + content: }, + { stat: "activity", icon: }, + { stat: "added", icon: }, + { stat: "release", icon: }, + ] satisfies { stat: GameListFilterType['orderBy'], icon?: any; }[]) + .map(o => ({ + content: o.stat, + icon: o.icon, + selected: data.localFilter.orderBy === o.stat, + id: `sort-by-${o.stat}`, type: 'primary', action (ctx) { - if (ctx.selected) data.setLocalFilter({ ...data.localFilter, genres: [...data.localFilter.genres?.filter(genre => genre !== g) ?? []] }); - else data.setLocalFilter({ ...data.localFilter, genres: [...data.localFilter.genres ?? [], g] }); + data.setLocalFilter({ ...data.localFilter, orderBy: o.stat }); ctx.close(); }, - }))} /> - }, focusKey); - }; + }))} />, + preferredChildFocusKey: `sort-by-${data.localFilter.orderBy}` + }); - const openSortingDialog = (focusKey: string) => - { - globalDialog.openContext({ - content: }, - { stat: "activity", icon: }, - { stat: "added", icon: }, - { stat: "release", icon: }, - ] satisfies { stat: GameListFilterType['orderBy'], icon?: any; }[]) - .map(o => ({ - content: o.stat, - icon: o.icon, - selected: data.localFilter.orderBy === o.stat, - id: `sort-by-${o.stat}`, - type: 'primary', - action (ctx) - { - data.setLocalFilter({ ...data.localFilter, orderBy: o.stat }); - ctx.close(); - }, - }))} />, preferredChildFocusKey: `sort-by-${data.localFilter.orderBy}` - }, focusKey); - }; - - const openAgeRatingDialog = (focusKey: string) => - { - globalDialog.openContext({ - content: ({ - content: a, - selected: data.localFilter.age_ratings?.includes(a), - id: `age-rating-filter-${a}`, + const sourceFilterDialog = useContextDialog('source-filter-dialog', { + content: (o => ({ + content: o, + icon: sourceIconMap[o], + selected: data.localFilter.source === o, + id: `source-filter-${o}`, type: 'primary', action (ctx) { - if (ctx.selected) data.setLocalFilter({ ...data.localFilter, age_ratings: [...data.localFilter.age_ratings?.filter(age => age !== a) ?? []] }); - else data.setLocalFilter({ ...data.localFilter, age_ratings: [...data.localFilter.age_ratings ?? [], a] }); + if (ctx.selected) data.setLocalFilter({ ...data.localFilter, source: undefined }); + else data.setLocalFilter({ ...data.localFilter, source: o }); ctx.close(); }, - }))} /> - }, focusKey); - }; + })).concat({ + content: "Local Only", + icon: , + selected: data.localFilter.localOnly === true, + id: `source-filter-local`, + type: 'primary', + action (ctx) + { + if (ctx.selected) data.setLocalFilter({ ...data.localFilter, localOnly: undefined }); + else data.setLocalFilter({ ...data.localFilter, localOnly: true }); + ctx.close(); + }, + })} />, + preferredChildFocusKey: `source-filter-${data.localFilter.source}` + }); + + const genreFilterDialog = useContextDialog('genre-filter-dialog', { + content: ({ + content: g, + selected: data.localFilter.genres?.includes(g), + id: `genre-filter-${g}`, + type: 'primary', + action (ctx) + { + if (ctx.selected) data.setLocalFilter({ ...data.localFilter, genres: [...data.localFilter.genres?.filter(genre => genre !== g) ?? []] }); + else data.setLocalFilter({ ...data.localFilter, genres: [...data.localFilter.genres ?? [], g] }); + ctx.close(); + }, + }))} /> + }); + + const ageRatingFilterDialog = useContextDialog('age-rating-filter-dialog', { + content: ({ + content: a, + selected: data.localFilter.age_ratings?.includes(a), + id: `age-rating-filter-${a}`, + type: 'primary', + action (ctx) + { + if (ctx.selected) data.setLocalFilter({ ...data.localFilter, age_ratings: [...data.localFilter.age_ratings?.filter(age => age !== a) ?? []] }); + else data.setLocalFilter({ ...data.localFilter, age_ratings: [...data.localFilter.age_ratings ?? [], a] }); + ctx.close(); + }, + }))} /> + }); return
      - } /> - 0} icon={} /> - 0} icon={} /> + } /> + 0} icon={} /> + 0} icon={} /> {!data.filters?.source && - } /> + } /> } {Object.values(data.localFilter).some(v => v !== undefined) && <> @@ -233,6 +139,10 @@ export default function SideFilters (data: { data.setLocalFilter({})} className='p-3 drop-shadow-md!' > } + {orderByDialog.dialog} + {sourceFilterDialog.dialog} + {genreFilterDialog.dialog} + {ageRatingFilterDialog.dialog}
      ; } \ No newline at end of file diff --git a/src/mainview/components/game/Achievements.tsx b/src/mainview/components/game/Achievements.tsx index 9fbe814..e9445cb 100644 --- a/src/mainview/components/game/Achievements.tsx +++ b/src/mainview/components/game/Achievements.tsx @@ -1,5 +1,5 @@ -import { FrontEndGameTypeDetailed, FrontEndGameTypeDetailedAchievement } from "@simeonradivoev/gameflow-sdk/shared"; +import { FrontEndGameTypeDetailed, FrontEndGameTypeDetailedAchievement } from "@/shared/types"; import { useFocusable } from "@noriginmedia/norigin-spatial-navigation"; import { Medal } from "lucide-react"; diff --git a/src/mainview/components/game/ActionButtons.tsx b/src/mainview/components/game/ActionButtons.tsx index d37ea00..02db473 100644 --- a/src/mainview/components/game/ActionButtons.tsx +++ b/src/mainview/components/game/ActionButtons.tsx @@ -10,7 +10,7 @@ import ActionButton from "./ActionButton"; import { useLocalStorage } from "usehooks-ts"; import FocusTooltip from "../FocusTooltip"; import { useBlocker, useNavigate, useRouter } from "@tanstack/react-router"; -import { FrontEndGameTypeDetailed } from "@simeonradivoev/gameflow-sdk/shared"; +import { FrontEndGameTypeDetailed } from "@/shared/types"; function AchievementsInfo (data: { game: FrontEndGameTypeDetailed; } & InteractParams) { @@ -30,11 +30,7 @@ function AchievementsInfo (data: { game: FrontEndGameTypeDetailed; } & InteractP ; } -export default function ActionButtons (data: { - game?: FrontEndGameTypeDetailed, - source: string, - id: string; -}) +export default function ActionButtons (data: { game?: FrontEndGameTypeDetailed, source: string, id: string; }) { const [, setDetailsSection] = useLocalStorage('details-section', 'screenshots'); const navigate = useNavigate(); diff --git a/src/mainview/components/game/Details.tsx b/src/mainview/components/game/Details.tsx index 99a7054..c0ac4ea 100644 --- a/src/mainview/components/game/Details.tsx +++ b/src/mainview/components/game/Details.tsx @@ -10,7 +10,7 @@ import prettyMilliseconds from 'pretty-ms'; import { useQuery } from "@tanstack/react-query"; import { validateSourceQuery } from "@/mainview/scripts/queries/romm"; import { sourceIconMap } from "../Constants"; -import { FrontEndGameTypeDetailed } from "@simeonradivoev/gameflow-sdk/shared"; +import { FrontEndGameTypeDetailed } from "@/shared/types"; export function DetailElement (data: { icon: JSX.Element; tooltip?: string | null, children?: any | any[]; }) { diff --git a/src/mainview/components/game/GameLookup.tsx b/src/mainview/components/game/GameLookup.tsx index bac4928..3b15009 100644 --- a/src/mainview/components/game/GameLookup.tsx +++ b/src/mainview/components/game/GameLookup.tsx @@ -6,7 +6,7 @@ import HeaderSearchField from "../HeaderSearchField"; import { GamePadButtonCode, useShortcuts } from "@/mainview/scripts/shortcuts"; import { scrollIntoViewHandler } from "@/mainview/scripts/utils"; import { FOCUS_KEYS } from "@/mainview/scripts/types"; -import { FrontEndId, GameLookup } from "@simeonradivoev/gameflow-sdk/shared"; +import { FrontEndId, GameLookup } from "@/shared/types"; import { gameLookupQuery } from "@/mainview/scripts/queries/romm"; import { Button } from "../options/Button"; import { useNavigate } from "@tanstack/react-router"; diff --git a/src/mainview/components/game/MainActions.tsx b/src/mainview/components/game/MainActions.tsx index 6f772af..a2caabc 100644 --- a/src/mainview/components/game/MainActions.tsx +++ b/src/mainview/components/game/MainActions.tsx @@ -1,20 +1,22 @@ import { rommApi } from "@/mainview/scripts/clientApi"; import { useMutation, useQueryClient } from "@tanstack/react-query"; -import { JSX, useContext, useEffect, useRef, useState } from "react"; +import { JSX, useEffect, useRef, useState } from "react"; import { getErrorMessage } from "react-error-boundary"; import toast from "react-hot-toast"; import { useLocalStorage } from "usehooks-ts"; -import { ContextList, DialogEntry } from "../ContextDialog"; +import { ContextList, DialogEntry, useContextDialog } from "../ContextDialog"; import { Clock, Crosshair, Download, EllipsisVertical, Import, PackageOpen, Play, TriangleAlert } from "lucide-react"; import { gameInvalidationQuery, installMutation, playMutation } from "@/mainview/scripts/queries/romm"; import ActionButton from "./ActionButton"; -import { useNavigate, UseNavigateResult, useRouter } from "@tanstack/react-router"; +import { useRouter } from "@tanstack/react-router"; +import { DownloadSourceType } from "@/shared/constants"; import { GamePadButtonCode, Shortcut, useShortcuts } from "@/mainview/scripts/shortcuts"; -import { CommandEntry, FrontEndGameTypeDetailed, DownloadSourceType } from "@simeonradivoev/gameflow-sdk/shared"; -import { GlobalDialogContext } from "@/mainview/scripts/contexts"; +import { CommandEntry, FrontEndGameTypeDetailed } from "@/shared/types"; -export function usePlayMutation (navigate: UseNavigateResult) +export default function MainActions (data: { game?: FrontEndGameTypeDetailed, source: string, id: string; }) { + const installMut = useMutation(installMutation(data.source, data.id)); + const router = useRouter(); const playMut = useMutation({ ...playMutation, onError (error) { @@ -22,36 +24,9 @@ export function usePlayMutation (navigate: UseNavigateResult) }, onSuccess (data, { source, id }, onMutateResult, context) { - navigate({ to: '/launcher/$source/$id', params: { source: source, id: id } }); + router.navigate({ to: '/launcher/$source/$id', params: { source: source, id: id } }); }, }); - - return playMut; -} - -export function playGame (source: string, id: string, cmd: CommandEntry, navigate: UseNavigateResult, playMutation: (options: { source: string, id: string, command_id: string | number; }) => void) -{ - if (cmd.emulator === 'EMULATORJS') - { - const params = new URLSearchParams(Array.isArray(cmd.command) ? cmd.command[0] : cmd.command); - navigate({ to: '/embedded/$source/$id', params: { source: source, id: id }, search: Object.fromEntries(params.entries()) }); - } else - { - playMutation({ source: source, id: id, command_id: cmd.id }); - } -} - -export default function MainActions (data: { - game?: FrontEndGameTypeDetailed, - source: string, - id: string; -}) -{ - const installMut = useMutation(installMutation(data.source, data.id)); - const router = useRouter(); - - const navigate = useNavigate(); - const globalDialog = useContext(GlobalDialogContext); const ws = useRef<{ send: (data: string) => void; }>(undefined); const [progress, setProgress] = useState(undefined); const [status, setStatus] = useState(undefined); @@ -68,7 +43,7 @@ export default function MainActions (data: { if (preferredCommand && c.id !== preferredCommand) return false; return true; }); - const playMut = usePlayMutation(navigate); + useEffect(() => { const sub = rommApi.api.romm.status({ source: data.source })({ id: data.id }).subscribe(); @@ -125,33 +100,32 @@ export default function MainActions (data: { } const showProgress = progress !== null && !!progressIcon; + useEffect(() => + { + if (showProgress) return; + showInstallOptions(false); + }, [showProgress]); - + const handlePlay = (cmd?: CommandEntry) => + { + if (!cmd) return; + if (cmd.emulator === 'EMULATORJS') + { + const params = new URLSearchParams(Array.isArray(cmd.command) ? cmd.command[0] : cmd.command); + router.navigate({ to: '/embedded/$source/$id', params: { source: data.source, id: data.id }, search: Object.fromEntries(params.entries()) }); + } else + { + playMut.mutate({ source: data.source, id: data.id, command_id: cmd.id }); + } + }; let mainButton: any | undefined = undefined; let showAllCommandsAction: ((focusKey: string) => void) | undefined; let mainAction: () => void; if (status === 'installed') { - if (validCommands.length > 1) showAllCommandsAction = (focusKey) => globalDialog.openContext({ - content: - { - const commands: DialogEntry = { - id: String(c.id), - content: c.label ?? "", - type: 'primary', - selected: preferredCommand !== undefined ? preferredCommand === c.id : i === 0, - action (ctx) - { - setPreferredCommand(c.id); - playGame(data.source, data.id, c, navigate, playMut.mutate); - }, - }; - return commands; - })} />, - preferredChildFocusKey: String(preferredCommand) - }, focusKey); - mainAction = () => validDefaultCommand ? playGame(data.source, data.id, validDefaultCommand, navigate, playMut.mutate) : undefined; + if (validCommands.length > 1) showAllCommandsAction = (focusKey) => showAllCommands(true, focusKey); + mainAction = () => handlePlay(validDefaultCommand); mainButton =
      1) { - globalDialog.openContext({ - content: ({ - content: s.name, - action (ctx) - { - installMut.mutate({ downloadId: s.id }); - ctx.close(); - }, - type: 'primary', - id: s.id - } satisfies DialogEntry)) ?? []} /> - }, 'mainAction'); + showInstallSource(true, 'mainAction'); } else { installMut.mutate({}); @@ -260,21 +223,55 @@ export default function MainActions (data: { return shortcuts; }, [showAllCommandsAction, mainAction]); + const { dialog: allCommandDialog, setOpen: showAllCommands } = useContextDialog('all-commands-dialog', { + content: + { + const commands: DialogEntry = { + id: String(c.id), + content: c.label ?? "", + type: 'primary', + selected: preferredCommand !== undefined ? preferredCommand === c.id : i === 0, + action (ctx) + { + setPreferredCommand(c.id); + handlePlay(c); + }, + }; + return commands; + })} />, + preferredChildFocusKey: String(preferredCommand) + }); + + const { dialog: installOptionsDialog, setOpen: showInstallOptions } = useContextDialog('install-options-dialog', { + content: + }); + + const { dialog: installSourcesDialog, setOpen: showInstallSource } = useContextDialog('install-source-dialog', { + content: ({ + content: s.name, + action (ctx) + { + installMut.mutate({ downloadId: s.id }); + ctx.close(); + }, + type: 'primary', + id: s.id + } satisfies DialogEntry)) ?? []} /> + }); + return
      {mainButton}
      - {showProgress && globalDialog.openContext({ - content: - }, "progress")} key="progress" square tooltip={details} type="base" id="progress" > + {showProgress && showInstallOptions(true, "progress")} key="progress" square tooltip={details} type="base" id="progress" >
      {progressIcon} @@ -282,5 +279,8 @@ export default function MainActions (data: {
      } + {installSourcesDialog} + {installOptionsDialog} + {allCommandDialog}
      ; } \ No newline at end of file diff --git a/src/mainview/components/options/Button.tsx b/src/mainview/components/options/Button.tsx index e131123..de07bdf 100644 --- a/src/mainview/components/options/Button.tsx +++ b/src/mainview/components/options/Button.tsx @@ -12,7 +12,7 @@ import { oneShot } from "@/mainview/scripts/audio/audio"; export type ButtonStyle = 'base' | 'accent' | 'primary' | 'secondary' | 'info' | 'success' | 'warning' | 'error'; const styles = { - base: 'dark:bg-base-200 light:bg-base-100 text-base-content active:not-disabled:bg-base-300! active:not-disabled:text-base-content! active:not-disabled:ring-offset-base-content', + base: 'dark:bg-base-200 light:bg-base-300 text-base-content active:not-disabled:bg-base-300! active:not-disabled:text-base-content! active:not-disabled:ring-offset-base-content', accent: "bg-accent text-accent-content active:not-disabled:bg-base-100! active:not-disabled:text-base-content! active:ring-offset-accent", primary: "bg-primary text-primary-content active:not-disabled:bg-base-100! active:not-disabled:text-base-content! active:not-disabled:ring-offset-primary", secondary: "bg-secondary text-secondary-content active:not-disabled:bg-base-100! active:not-disabled:text-base-content! active:not-disabled:ring-offset-secondary", @@ -22,17 +22,6 @@ const styles = { error: "bg-error text-error-content active:not-disabled:bg-base-100! active:not-disabled:text-base-content! active:not-disabled:ring-offset-error", }; -const externalStyles = { - base: '', - accent: "focusable-accent", - primary: "focusable-primary", - secondary: "focusable-secondary", - info: "focusable-info", - success: "focusable-success", - warning: "focusable-warning", - error: "focusable-error", -}; - export function Button (data: { id: string, children?: any, @@ -75,9 +64,9 @@ export function Button (data: { className={twMerge("flex items-center justify-center px-4 py-2 disabled:bg-base-200/40 disabled:text-base-content/40 not-disabled:cursor-pointer rounded-3xl md:text-lg not-control-mouse:focused:drop-shadow-lg border border-base-content/5 not-control-mouse:focused:bg-base-content not-control-mouse:focused:text-base-100 control-mouse:hover:not-disabled:bg-base-content control-mouse:hover:not-disabled:text-base-100 active:not-disabled:transition-none active:not-disabled:ring-offset-4", styles[data.style ?? 'base'], focused ? data.focusClassName : undefined, - data.external ? `focusable focusable-hover ${externalStyles[data.style as keyof typeof externalStyles]}` : '', classNames({ - "btn-accent": focused + "btn-accent": focused, + "focusable focusable-primary focusable-hover": data.external }, data.className))} type={data.type ?? 'button'} > diff --git a/src/mainview/components/options/DownloadDirectoryOption.tsx b/src/mainview/components/options/DownloadDirectoryOption.tsx index de902d3..9cbe29f 100644 --- a/src/mainview/components/options/DownloadDirectoryOption.tsx +++ b/src/mainview/components/options/DownloadDirectoryOption.tsx @@ -2,7 +2,8 @@ import { useState } from "react"; import { PathSettingsOptionBase, PathSettingsOptionParams } from "./PathSettingsOption"; import { useMutation, useQuery } from "@tanstack/react-query"; import { changeDownloadsMutation, getSettingQuery } from "@queries/settings"; -import { KeysWithValueAssignableTo, SettingsType } from "@simeonradivoev/gameflow-sdk/shared"; +import { SettingsType } from "@/shared/constants"; +import { KeysWithValueAssignableTo } from "@/shared/types"; export default function DownloadDirectoryOption (data: PathSettingsOptionParams & { id: KeysWithValueAssignableTo; }) { diff --git a/src/mainview/components/options/LocalOption.tsx b/src/mainview/components/options/LocalOption.tsx index 25ac7b6..d596123 100644 --- a/src/mainview/components/options/LocalOption.tsx +++ b/src/mainview/components/options/LocalOption.tsx @@ -1,5 +1,5 @@ import { JSX } from "react"; -import { LocalSettingsSchema, LocalSettingsType } from '@simeonradivoev/gameflow-sdk/shared'; +import { LocalSettingsSchema, LocalSettingsType } from "@shared/constants"; import { OptionSpace } from "./OptionSpace"; import { OptionInput } from "./OptionInput"; import { useLocalStorage } from "usehooks-ts"; diff --git a/src/mainview/components/options/PathSettingsOption.tsx b/src/mainview/components/options/PathSettingsOption.tsx index 7b2789f..2c25fb2 100644 --- a/src/mainview/components/options/PathSettingsOption.tsx +++ b/src/mainview/components/options/PathSettingsOption.tsx @@ -1,4 +1,5 @@ import { HTMLInputTypeAttribute, JSX, useEffect, useState } from "react"; +import { SettingsType } from "../../../shared/constants"; import { useMutation, useQuery } from "@tanstack/react-query"; import { OptionSpace } from "./OptionSpace"; import { OptionInput } from "./OptionInput"; @@ -8,7 +9,7 @@ import { ContextDialog } from "../ContextDialog"; import FilePicker from "../FilePicker"; import { setFocus } from "@noriginmedia/norigin-spatial-navigation"; import { getSettingQuery, setSettingMutation } from "@queries/settings"; -import { KeysWithValueAssignableTo, SettingsType } from "@simeonradivoev/gameflow-sdk/shared"; +import { KeysWithValueAssignableTo } from "@/shared/types"; export interface PathSettingsOptionParams { diff --git a/src/mainview/components/options/SettingsDropdown.tsx b/src/mainview/components/options/SettingsDropdown.tsx index 6887b52..18eabd5 100644 --- a/src/mainview/components/options/SettingsDropdown.tsx +++ b/src/mainview/components/options/SettingsDropdown.tsx @@ -1,9 +1,10 @@ import { JSX, useCallback, useEffect, useState } from "react"; +import { SettingsType } from "../../../shared/constants"; import { useMutation, useQuery } from "@tanstack/react-query"; import { OptionSpace } from "./OptionSpace"; import { getSettingQuery, setSettingMutation } from "@queries/settings"; import { OptionDropdown } from "./OptionDropdown"; -import { KeysWithValueAssignableTo, SettingsType } from "@simeonradivoev/gameflow-sdk/shared"; +import { KeysWithValueAssignableTo } from "@/shared/types"; export function SettingsDropdown (data: { label: string; diff --git a/src/mainview/components/options/SettingsOption.tsx b/src/mainview/components/options/SettingsOption.tsx index 20bcda0..55357d7 100644 --- a/src/mainview/components/options/SettingsOption.tsx +++ b/src/mainview/components/options/SettingsOption.tsx @@ -1,9 +1,10 @@ import { HTMLInputTypeAttribute, JSX, useCallback, useEffect, useState } from "react"; +import { SettingsType } from "../../../shared/constants"; import { useMutation, useQuery } from "@tanstack/react-query"; import { OptionSpace } from "./OptionSpace"; import { OptionInput } from "./OptionInput"; import { getSettingQuery, setSettingMutation } from "@queries/settings"; -import { KeysWithValueAssignableTo, SettingsType } from "@simeonradivoev/gameflow-sdk/shared"; +import { KeysWithValueAssignableTo } from "@/shared/types"; export function SettingsOption (data: { label: string; diff --git a/src/mainview/components/store/EmulatorsSection.tsx b/src/mainview/components/store/EmulatorsSection.tsx index a7712dc..eec1325 100644 --- a/src/mainview/components/store/EmulatorsSection.tsx +++ b/src/mainview/components/store/EmulatorsSection.tsx @@ -12,7 +12,7 @@ import { StoreEmulatorCard } from "./StoreEmulatorCard"; import { FOCUS_KEYS } from "@/mainview/scripts/types"; import Carousel from "../Carousel"; import { useRouter } from "@tanstack/react-router"; -import { FrontEndEmulator } from "@simeonradivoev/gameflow-sdk/shared"; +import { FrontEndEmulator } from "@/shared/types"; function SeeAllCard (data: { id: string; onAction: () => void; onFocus?: (details: { node: HTMLElement, instant?: boolean; }) => void; }) { diff --git a/src/mainview/components/store/GamesSection.tsx b/src/mainview/components/store/GamesSection.tsx index ccdd076..ff3cbbb 100644 --- a/src/mainview/components/store/GamesSection.tsx +++ b/src/mainview/components/store/GamesSection.tsx @@ -10,7 +10,7 @@ import FrontEndGameCard from "../FrontEndGameCard"; import { FOCUS_KEYS } from "@/mainview/scripts/types"; import Carousel from "../Carousel"; import { twMerge } from "tailwind-merge"; -import { FrontEndGameType, FrontEndId } from "@simeonradivoev/gameflow-sdk/shared"; +import { FrontEndGameType, FrontEndId } from "@/shared/types"; export function GamesSection (data: { games?: FrontEndGameType[]; diff --git a/src/mainview/components/store/MissingEmulatorsSection.tsx b/src/mainview/components/store/MissingEmulatorsSection.tsx index 6339dde..84f150b 100644 --- a/src/mainview/components/store/MissingEmulatorsSection.tsx +++ b/src/mainview/components/store/MissingEmulatorsSection.tsx @@ -8,7 +8,7 @@ import { GamePadButtonCode, useShortcuts } from "@/mainview/scripts/shortcuts"; import { RPC_URL } from "@/shared/constants"; import { FOCUS_KEYS } from "@/mainview/scripts/types"; import { oneShot } from "@/mainview/scripts/audio/audio"; -import { FrontEndEmulator } from "@simeonradivoev/gameflow-sdk/shared"; +import { FrontEndEmulator } from "@/shared/types"; // ── Single missing-emulator card ─────────────────────────────────────────── interface MissingCardProps diff --git a/src/mainview/components/store/StoreEmulatorCard.tsx b/src/mainview/components/store/StoreEmulatorCard.tsx index 3479579..09b3ca3 100644 --- a/src/mainview/components/store/StoreEmulatorCard.tsx +++ b/src/mainview/components/store/StoreEmulatorCard.tsx @@ -6,15 +6,11 @@ import { GamePadButtonCode, useShortcuts } from "@/mainview/scripts/shortcuts"; import { CircleFadingArrowUp, FileQuestion, IceCream2, Package, Store, WandSparkles } from "lucide-react"; import { FOCUS_KEYS } from "@/mainview/scripts/types"; import { FlatpackIcon } from "@/mainview/scripts/brandIcons"; -import { JSX, useContext } from "react"; +import { JSX } from "react"; import { oneShot } from "@/mainview/scripts/audio/audio"; import { useQuery } from "@tanstack/react-query"; import { getUpdateInfoForEmulator } from "@/mainview/scripts/queries/store"; -import { FrontEndEmulator } from "@simeonradivoev/gameflow-sdk/shared"; -import { rommApi } from "@/mainview/scripts/clientApi"; -import { useNavigate } from "@tanstack/react-router"; -import { GlobalDialogContext } from "@/mainview/scripts/contexts"; -import { ContextList, DialogEntry } from "../ContextDialog"; +import { FrontEndEmulator } from "@/shared/types"; export const emulatorStatusIcons: Record = { store: , @@ -32,7 +28,6 @@ export function StoreEmulatorCard (data: { className?: string; }) { - const navigate = useNavigate(); const handleSelect = () => { data.onSelect?.(data.emulator.name, focusKey); @@ -50,32 +45,7 @@ export function StoreEmulatorCard (data: { const { data: updateInfo } = useQuery(getUpdateInfoForEmulator(data.emulator.name)); - const globalDialogContext = useContext(GlobalDialogContext); - useShortcuts(focusKey, () => [{ - button: GamePadButtonCode.A, - label: "Details", - action: handleSelect - - }, { - button: GamePadButtonCode.Y, - label: "Launch Emulator", - action: e => - { - const entries: DialogEntry[] = data.emulator.validSources.filter(s => s.exists).map(s => ({ - content: `Launch: ${s.type}`, - type: 'primary', - icon: emulatorStatusIcons[s.type], - action (ctx) - { - if (!data.emulator) return; - rommApi.api.romm.game({ source: 'emulator' })({ id: data.emulator.name }).play.post({ command_id: s.type }); - ctx.close(); - navigate({ to: '/launcher/$source/$id', params: { source: 'emulator', id: data.emulator.name } }); - }, id: `open-${s.type}` - } satisfies DialogEntry)); - globalDialogContext.openContext({ content: }, focusKey); - } - }], [handleSelect]); + useShortcuts(focusKey, () => [{ button: GamePadButtonCode.A, label: "Details", action: handleSelect }], [handleSelect]); return (
      SettingsRouteRoute, } as any) -const SettingsTasksRoute = SettingsTasksRouteImport.update({ - id: '/tasks', - path: '/tasks', - getParentRoute: () => SettingsRouteRoute, -} as any) const SettingsPluginsRoute = SettingsPluginsRouteImport.update({ id: '/plugins', path: '/plugins', @@ -108,11 +98,6 @@ const StoreTabIndexRoute = StoreTabIndexRouteImport.update({ path: '/', getParentRoute: () => StoreTabRouteRoute, } as any) -const StoreTabPluginsRoute = StoreTabPluginsRouteImport.update({ - id: '/plugins', - path: '/plugins', - getParentRoute: () => StoreTabRouteRoute, -} as any) const StoreTabGamesRoute = StoreTabGamesRouteImport.update({ id: '/games', path: '/games', @@ -123,11 +108,6 @@ const StoreTabEmulatorsRoute = StoreTabEmulatorsRouteImport.update({ path: '/emulators', getParentRoute: () => StoreTabRouteRoute, } as any) -const StoreTabDownloadRoute = StoreTabDownloadRouteImport.update({ - id: '/download', - path: '/download', - getParentRoute: () => StoreTabRouteRoute, -} as any) const SettingsPluginSourceRoute = SettingsPluginSourceRouteImport.update({ id: '/plugin/$source', path: '/plugin/$source', @@ -158,11 +138,6 @@ const CollectionSourceIdRoute = CollectionSourceIdRouteImport.update({ path: '/collection/$source/$id', getParentRoute: () => rootRouteImport, } as any) -const StoreDetailsPluginIdRoute = StoreDetailsPluginIdRouteImport.update({ - id: '/store/details/plugin/$id', - path: '/store/details/plugin/$id', - getParentRoute: () => rootRouteImport, -} as any) const StoreDetailsEmulatorIdRoute = StoreDetailsEmulatorIdRouteImport.update({ id: '/store/details/emulator/$id', path: '/store/details/emulator/$id', @@ -173,12 +148,6 @@ const GameUpdateSourceIdRoute = GameUpdateSourceIdRouteImport.update({ path: '/game/update/$source/$id', getParentRoute: () => rootRouteImport, } as any) -const StoreDetailsDownloadSourceIdRoute = - StoreDetailsDownloadSourceIdRouteImport.update({ - id: '/store/details/download/$source/$id', - path: '/store/details/download/$source/$id', - getParentRoute: () => rootRouteImport, - } as any) export interface FileRoutesByFullPath { '/': typeof IndexRoute @@ -192,7 +161,6 @@ export interface FileRoutesByFullPath { '/settings/emulators': typeof SettingsEmulatorsRoute '/settings/interface': typeof SettingsInterfaceRoute '/settings/plugins': typeof SettingsPluginsRoute - '/settings/tasks': typeof SettingsTasksRoute '/settings/update': typeof SettingsUpdateRoute '/collection/$source/$id': typeof CollectionSourceIdRoute '/embedded/$source/$id': typeof EmbeddedSourceIdRoute @@ -200,15 +168,11 @@ export interface FileRoutesByFullPath { '/launcher/$source/$id': typeof LauncherSourceIdRoute '/platform/$source/$id': typeof PlatformSourceIdRoute '/settings/plugin/$source': typeof SettingsPluginSourceRoute - '/store/tab/download': typeof StoreTabDownloadRoute '/store/tab/emulators': typeof StoreTabEmulatorsRoute '/store/tab/games': typeof StoreTabGamesRoute - '/store/tab/plugins': typeof StoreTabPluginsRoute '/store/tab/': typeof StoreTabIndexRoute '/game/update/$source/$id': typeof GameUpdateSourceIdRoute '/store/details/emulator/$id': typeof StoreDetailsEmulatorIdRoute - '/store/details/plugin/$id': typeof StoreDetailsPluginIdRoute - '/store/details/download/$source/$id': typeof StoreDetailsDownloadSourceIdRoute } export interface FileRoutesByTo { '/': typeof IndexRoute @@ -221,7 +185,6 @@ export interface FileRoutesByTo { '/settings/emulators': typeof SettingsEmulatorsRoute '/settings/interface': typeof SettingsInterfaceRoute '/settings/plugins': typeof SettingsPluginsRoute - '/settings/tasks': typeof SettingsTasksRoute '/settings/update': typeof SettingsUpdateRoute '/collection/$source/$id': typeof CollectionSourceIdRoute '/embedded/$source/$id': typeof EmbeddedSourceIdRoute @@ -229,15 +192,11 @@ export interface FileRoutesByTo { '/launcher/$source/$id': typeof LauncherSourceIdRoute '/platform/$source/$id': typeof PlatformSourceIdRoute '/settings/plugin/$source': typeof SettingsPluginSourceRoute - '/store/tab/download': typeof StoreTabDownloadRoute '/store/tab/emulators': typeof StoreTabEmulatorsRoute '/store/tab/games': typeof StoreTabGamesRoute - '/store/tab/plugins': typeof StoreTabPluginsRoute '/store/tab': typeof StoreTabIndexRoute '/game/update/$source/$id': typeof GameUpdateSourceIdRoute '/store/details/emulator/$id': typeof StoreDetailsEmulatorIdRoute - '/store/details/plugin/$id': typeof StoreDetailsPluginIdRoute - '/store/details/download/$source/$id': typeof StoreDetailsDownloadSourceIdRoute } export interface FileRoutesById { __root__: typeof rootRouteImport @@ -252,7 +211,6 @@ export interface FileRoutesById { '/settings/emulators': typeof SettingsEmulatorsRoute '/settings/interface': typeof SettingsInterfaceRoute '/settings/plugins': typeof SettingsPluginsRoute - '/settings/tasks': typeof SettingsTasksRoute '/settings/update': typeof SettingsUpdateRoute '/collection/$source/$id': typeof CollectionSourceIdRoute '/embedded/$source/$id': typeof EmbeddedSourceIdRoute @@ -260,15 +218,11 @@ export interface FileRoutesById { '/launcher/$source/$id': typeof LauncherSourceIdRoute '/platform/$source/$id': typeof PlatformSourceIdRoute '/settings/plugin/$source': typeof SettingsPluginSourceRoute - '/store/tab/download': typeof StoreTabDownloadRoute '/store/tab/emulators': typeof StoreTabEmulatorsRoute '/store/tab/games': typeof StoreTabGamesRoute - '/store/tab/plugins': typeof StoreTabPluginsRoute '/store/tab/': typeof StoreTabIndexRoute '/game/update/$source/$id': typeof GameUpdateSourceIdRoute '/store/details/emulator/$id': typeof StoreDetailsEmulatorIdRoute - '/store/details/plugin/$id': typeof StoreDetailsPluginIdRoute - '/store/details/download/$source/$id': typeof StoreDetailsDownloadSourceIdRoute } export interface FileRouteTypes { fileRoutesByFullPath: FileRoutesByFullPath @@ -284,7 +238,6 @@ export interface FileRouteTypes { | '/settings/emulators' | '/settings/interface' | '/settings/plugins' - | '/settings/tasks' | '/settings/update' | '/collection/$source/$id' | '/embedded/$source/$id' @@ -292,15 +245,11 @@ export interface FileRouteTypes { | '/launcher/$source/$id' | '/platform/$source/$id' | '/settings/plugin/$source' - | '/store/tab/download' | '/store/tab/emulators' | '/store/tab/games' - | '/store/tab/plugins' | '/store/tab/' | '/game/update/$source/$id' | '/store/details/emulator/$id' - | '/store/details/plugin/$id' - | '/store/details/download/$source/$id' fileRoutesByTo: FileRoutesByTo to: | '/' @@ -313,7 +262,6 @@ export interface FileRouteTypes { | '/settings/emulators' | '/settings/interface' | '/settings/plugins' - | '/settings/tasks' | '/settings/update' | '/collection/$source/$id' | '/embedded/$source/$id' @@ -321,15 +269,11 @@ export interface FileRouteTypes { | '/launcher/$source/$id' | '/platform/$source/$id' | '/settings/plugin/$source' - | '/store/tab/download' | '/store/tab/emulators' | '/store/tab/games' - | '/store/tab/plugins' | '/store/tab' | '/game/update/$source/$id' | '/store/details/emulator/$id' - | '/store/details/plugin/$id' - | '/store/details/download/$source/$id' id: | '__root__' | '/' @@ -343,7 +287,6 @@ export interface FileRouteTypes { | '/settings/emulators' | '/settings/interface' | '/settings/plugins' - | '/settings/tasks' | '/settings/update' | '/collection/$source/$id' | '/embedded/$source/$id' @@ -351,15 +294,11 @@ export interface FileRouteTypes { | '/launcher/$source/$id' | '/platform/$source/$id' | '/settings/plugin/$source' - | '/store/tab/download' | '/store/tab/emulators' | '/store/tab/games' - | '/store/tab/plugins' | '/store/tab/' | '/game/update/$source/$id' | '/store/details/emulator/$id' - | '/store/details/plugin/$id' - | '/store/details/download/$source/$id' fileRoutesById: FileRoutesById } export interface RootRouteChildren { @@ -375,8 +314,6 @@ export interface RootRouteChildren { PlatformSourceIdRoute: typeof PlatformSourceIdRoute GameUpdateSourceIdRoute: typeof GameUpdateSourceIdRoute StoreDetailsEmulatorIdRoute: typeof StoreDetailsEmulatorIdRoute - StoreDetailsPluginIdRoute: typeof StoreDetailsPluginIdRoute - StoreDetailsDownloadSourceIdRoute: typeof StoreDetailsDownloadSourceIdRoute } declare module '@tanstack/react-router' { @@ -409,13 +346,6 @@ declare module '@tanstack/react-router' { preLoaderRoute: typeof SettingsUpdateRouteImport parentRoute: typeof SettingsRouteRoute } - '/settings/tasks': { - id: '/settings/tasks' - path: '/tasks' - fullPath: '/settings/tasks' - preLoaderRoute: typeof SettingsTasksRouteImport - parentRoute: typeof SettingsRouteRoute - } '/settings/plugins': { id: '/settings/plugins' path: '/plugins' @@ -479,13 +409,6 @@ declare module '@tanstack/react-router' { preLoaderRoute: typeof StoreTabIndexRouteImport parentRoute: typeof StoreTabRouteRoute } - '/store/tab/plugins': { - id: '/store/tab/plugins' - path: '/plugins' - fullPath: '/store/tab/plugins' - preLoaderRoute: typeof StoreTabPluginsRouteImport - parentRoute: typeof StoreTabRouteRoute - } '/store/tab/games': { id: '/store/tab/games' path: '/games' @@ -500,13 +423,6 @@ declare module '@tanstack/react-router' { preLoaderRoute: typeof StoreTabEmulatorsRouteImport parentRoute: typeof StoreTabRouteRoute } - '/store/tab/download': { - id: '/store/tab/download' - path: '/download' - fullPath: '/store/tab/download' - preLoaderRoute: typeof StoreTabDownloadRouteImport - parentRoute: typeof StoreTabRouteRoute - } '/settings/plugin/$source': { id: '/settings/plugin/$source' path: '/plugin/$source' @@ -549,13 +465,6 @@ declare module '@tanstack/react-router' { preLoaderRoute: typeof CollectionSourceIdRouteImport parentRoute: typeof rootRouteImport } - '/store/details/plugin/$id': { - id: '/store/details/plugin/$id' - path: '/store/details/plugin/$id' - fullPath: '/store/details/plugin/$id' - preLoaderRoute: typeof StoreDetailsPluginIdRouteImport - parentRoute: typeof rootRouteImport - } '/store/details/emulator/$id': { id: '/store/details/emulator/$id' path: '/store/details/emulator/$id' @@ -570,13 +479,6 @@ declare module '@tanstack/react-router' { preLoaderRoute: typeof GameUpdateSourceIdRouteImport parentRoute: typeof rootRouteImport } - '/store/details/download/$source/$id': { - id: '/store/details/download/$source/$id' - path: '/store/details/download/$source/$id' - fullPath: '/store/details/download/$source/$id' - preLoaderRoute: typeof StoreDetailsDownloadSourceIdRouteImport - parentRoute: typeof rootRouteImport - } } } @@ -587,7 +489,6 @@ interface SettingsRouteRouteChildren { SettingsEmulatorsRoute: typeof SettingsEmulatorsRoute SettingsInterfaceRoute: typeof SettingsInterfaceRoute SettingsPluginsRoute: typeof SettingsPluginsRoute - SettingsTasksRoute: typeof SettingsTasksRoute SettingsUpdateRoute: typeof SettingsUpdateRoute SettingsPluginSourceRoute: typeof SettingsPluginSourceRoute } @@ -599,7 +500,6 @@ const SettingsRouteRouteChildren: SettingsRouteRouteChildren = { SettingsEmulatorsRoute: SettingsEmulatorsRoute, SettingsInterfaceRoute: SettingsInterfaceRoute, SettingsPluginsRoute: SettingsPluginsRoute, - SettingsTasksRoute: SettingsTasksRoute, SettingsUpdateRoute: SettingsUpdateRoute, SettingsPluginSourceRoute: SettingsPluginSourceRoute, } @@ -609,18 +509,14 @@ const SettingsRouteRouteWithChildren = SettingsRouteRoute._addFileChildren( ) interface StoreTabRouteRouteChildren { - StoreTabDownloadRoute: typeof StoreTabDownloadRoute StoreTabEmulatorsRoute: typeof StoreTabEmulatorsRoute StoreTabGamesRoute: typeof StoreTabGamesRoute - StoreTabPluginsRoute: typeof StoreTabPluginsRoute StoreTabIndexRoute: typeof StoreTabIndexRoute } const StoreTabRouteRouteChildren: StoreTabRouteRouteChildren = { - StoreTabDownloadRoute: StoreTabDownloadRoute, StoreTabEmulatorsRoute: StoreTabEmulatorsRoute, StoreTabGamesRoute: StoreTabGamesRoute, - StoreTabPluginsRoute: StoreTabPluginsRoute, StoreTabIndexRoute: StoreTabIndexRoute, } @@ -641,8 +537,6 @@ const rootRouteChildren: RootRouteChildren = { PlatformSourceIdRoute: PlatformSourceIdRoute, GameUpdateSourceIdRoute: GameUpdateSourceIdRoute, StoreDetailsEmulatorIdRoute: StoreDetailsEmulatorIdRoute, - StoreDetailsPluginIdRoute: StoreDetailsPluginIdRoute, - StoreDetailsDownloadSourceIdRoute: StoreDetailsDownloadSourceIdRoute, } export const routeTree = rootRouteImport ._addFileChildren(rootRouteChildren) diff --git a/src/mainview/index.css b/src/mainview/index.css index 332862e..4c82b71 100644 --- a/src/mainview/index.css +++ b/src/mainview/index.css @@ -9,7 +9,6 @@ @theme { --breakpoint-sm: 0px; --breakpoint-md: 1024px; - --breakpoint-lg: 1280px; --page-scroll-bg: transparent; --animation-size: 1; diff --git a/src/mainview/index.tsx b/src/mainview/index.tsx index 166cc4f..f5639f9 100644 --- a/src/mainview/index.tsx +++ b/src/mainview/index.tsx @@ -8,7 +8,7 @@ import RouterProvider, } from "@tanstack/react-router"; import { routeTree } from "./gen/routeTree.gen"; -import { QueryClient } from "@tanstack/react-query"; +import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; import "./scripts/gamepads"; import "./scripts/windowEvents"; import "./scripts/spatialNavigation"; @@ -16,16 +16,6 @@ import NotFound from "./components/NotFound"; import Error from "./components/Error"; import serviceWorker from './scripts/serviceWorker?worker&url'; import App from "./App"; -import { PersistQueryClientProvider } from '@tanstack/react-query-persist-client'; -import { createStore, get, set, del } from "idb-keyval"; -import -{ - PersistedClient, - Persister, -} from '@tanstack/react-query-persist-client'; -import pkg from '../../package.json'; - -const idbStore = createStore("tanstack-query", "cache"); if ('serviceWorker' in navigator) { @@ -34,31 +24,7 @@ if ('serviceWorker' in navigator) const hashHistory = createHashHistory({}); -const queryClient = new QueryClient({ - defaultOptions: { - queries: { - gcTime: 1000 * 60 * 60 * 24 * 5, // 5 days - } - } -}); - -export function createIDBPersister (idbValidKey: IDBValidKey = 'reactQuery'): Persister -{ - return { - persistClient: async (client: PersistedClient) => - { - await set(idbValidKey, client, idbStore); - }, - restoreClient: async () => - { - return await get(idbValidKey, idbStore); - }, - removeClient: async () => - { - await del(idbValidKey, idbStore); - }, - } satisfies Persister; -} +const queryClient = new QueryClient(); export interface RouterContext { @@ -108,9 +74,9 @@ if (!rootElement.innerHTML) root.render( - + - + , ); diff --git a/src/mainview/query-options.ts b/src/mainview/query-options.ts index 879d632..a52c649 100644 --- a/src/mainview/query-options.ts +++ b/src/mainview/query-options.ts @@ -1,7 +1,6 @@ import { keepPreviousData, queryOptions } from "@tanstack/react-query"; import { getRomApiRomsIdGetOptions, getRomsApiRomsGetOptions } from "../clients/romm/@tanstack/react-query.gen"; -import { DefaultRommStaleTime } from "../shared/constants"; -import { GameListFilterType } from '@simeonradivoev/gameflow-sdk/shared'; +import { DefaultRommStaleTime, GameListFilterType } from "../shared/constants"; export function gamesQueryOptions (filter?: GameListFilterType) { diff --git a/src/mainview/routes/__root.tsx b/src/mainview/routes/__root.tsx index cafbab4..fbe2f26 100644 --- a/src/mainview/routes/__root.tsx +++ b/src/mainview/routes/__root.tsx @@ -8,7 +8,6 @@ import { useEffect } from "react"; import AppCommunication from "../components/AppCommunication"; import { ReactQueryDevtools } from "@tanstack/react-query-devtools"; import { TanStackRouterDevtools } from "@tanstack/react-router-devtools"; -import GlobalContextDialog from "../components/GlobalContextDialog"; export const Route = createRootRouteWithContext()({ component: RootComponent, @@ -40,11 +39,9 @@ function RootComponent () return (
      - - - - - + + + {queryDevOptions && } diff --git a/src/mainview/routes/collection.$source.$id.tsx b/src/mainview/routes/collection.$source.$id.tsx index a08c164..3b73d25 100644 --- a/src/mainview/routes/collection.$source.$id.tsx +++ b/src/mainview/routes/collection.$source.$id.tsx @@ -6,7 +6,7 @@ import { AnimatedBackgroundContext } from '../scripts/contexts'; import { getCollectionQuery } from '@queries/romm'; import { zodValidator } from '@tanstack/zod-adapter'; import z from 'zod'; -import { GameListFilterType } from '@simeonradivoev/gameflow-sdk/shared'; +import { GameListFilterType } from '@/shared/constants'; import { useLocalStorage } from 'usehooks-ts'; export const Route = createFileRoute('/collection/$source/$id')({ diff --git a/src/mainview/routes/game/$source.$id.tsx b/src/mainview/routes/game/$source.$id.tsx index 13ea8ac..064deee 100644 --- a/src/mainview/routes/game/$source.$id.tsx +++ b/src/mainview/routes/game/$source.$id.tsx @@ -24,7 +24,7 @@ import Details from "@/mainview/components/game/Details"; import { AutoFocus } from "@/mainview/components/AutoFocus"; import SelectMenu from "@/mainview/components/SelectMenu"; import { IGDBIcon } from "@/mainview/scripts/brandIcons"; -import { FrontEndGameTypeDetailed } from "@simeonradivoev/gameflow-sdk/shared"; +import { FrontEndGameTypeDetailed } from "@/shared/types"; export const Route = createFileRoute("/game/$source/$id")({ loader: async ({ params, context }) => @@ -33,9 +33,7 @@ export const Route = createFileRoute("/game/$source/$id")({ }, component: RouteComponent, errorComponent: Error, - validateSearch: zodValidator(z.object({ - focus: z.string().optional(), - })), + validateSearch: zodValidator(z.object({ focus: z.string().optional() })), staticData: { enterSound: 'openDetails', goBackSound: "returnDetails" diff --git a/src/mainview/routes/game/add.tsx b/src/mainview/routes/game/add.tsx index 6399cd0..3a6a2f8 100644 --- a/src/mainview/routes/game/add.tsx +++ b/src/mainview/routes/game/add.tsx @@ -8,18 +8,15 @@ import { PathSettingsOptionBase } from '@/mainview/components/options/PathSettin import SelectMenu from '@/mainview/components/SelectMenu'; import { FloatingShortcuts } from '@/mainview/components/Shortcuts'; import { oneShot } from '@/mainview/scripts/audio/audio'; -import { rommApi } from '@/mainview/scripts/clientApi'; import { addManualGameMutation, allGamesInvalidateQuery, gameLookupDetails, platformLookupMatchQuery } from '@/mainview/scripts/queries/romm'; import { GamePadButtonCode, useShortcuts } from '@/mainview/scripts/shortcuts'; import { HandleGoBack } from '@/mainview/scripts/utils'; -import { isUrl } from '@/shared/utils'; import { FocusContext, useFocusable } from '@noriginmedia/norigin-spatial-navigation'; import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; import { createFileRoute, useNavigate, useRouter } from '@tanstack/react-router'; import { zodValidator } from '@tanstack/zod-adapter'; -import { ArrowBigRightDash, Check, CirclePlus, CircleQuestionMark, CircleX, File, FileSearch, FolderOpen, Globe, HardDrive, Link, Save } from 'lucide-react'; +import { ArrowBigRightDash, Check, CirclePlus, CircleQuestionMark, CircleX, FileSearch, FolderOpen, HardDrive } from 'lucide-react'; import { basename } from 'pathe'; -import prettyBytes from 'pretty-bytes'; import { JSX, useState } from 'react'; import toast from 'react-hot-toast'; import { twMerge } from 'tailwind-merge'; @@ -42,7 +39,6 @@ export const Route = createFileRoute('/game/add')({ function FileSelectionField (data: { location: string | undefined, setLocation: (location: string | undefined) => void; }) { const [localLocation, setLocalLocation] = useState(data.location); - const navigate = useNavigate(); return - - ; + />; } const TAG_REGEX = /\(([^)]+)\)|\[([^\]]+)\]/g; @@ -101,17 +95,6 @@ function Overview (data: {}) const navigate = useNavigate(); const router = useRouter(); const state = Route.useSearch(); - const linkInfo = useQuery({ - enabled (query) - { - return isUrl(query.queryKey[1]); - }, - queryKey: ['dl-link-info', state.gameLocation], - queryFn: async () => - { - return rommApi.api.romm.download.file.info.get({ query: { file_url: state.gameLocation! } }); - } - }); const { data: game } = useQuery(gameLookupDetails(state.selectedGame?.source, state.selectedGame?.id)); const { data: platform } = useQuery(platformLookupMatchQuery(state.selectedGame?.source, state.platformId)); const addGame = useMutation({ @@ -122,7 +105,7 @@ function Overview (data: {}) }, async onSuccess (data, variables, onMutateResult, context) { - if (data.id === null || isUrl(state.gameLocation)) return; + if (data.id === null) return; await context.client.invalidateQueries(allGamesInvalidateQuery); navigate({ to: '/game/$source/$id', params: { @@ -153,13 +136,7 @@ function Overview (data: {})
      {platform?.match.type}
      -
      {isUrl(state.gameLocation) ? : }{state.gameLocation}
      -
      - - {linkInfo.isFetching ? : (linkInfo.data?.data?.size && prettyBytes(linkInfo.data.data.size))} - - {linkInfo.isFetching ? : (linkInfo.data?.data?.content_type && linkInfo.data.data.content_type)} -
      +
      {state.gameLocation}
      Actions
      @@ -173,11 +150,6 @@ function Overview (data: {}) gamePath: state.gameLocation, platformId: state.platformId }); - if (isUrl(state.gameLocation)) - { - navigate({ to: '/settings/tasks' }); - } - }} > Add Game
      ; } diff --git a/src/mainview/routes/game/update.$source.$id.tsx b/src/mainview/routes/game/update.$source.$id.tsx index 0a6ef83..867112a 100644 --- a/src/mainview/routes/game/update.$source.$id.tsx +++ b/src/mainview/routes/game/update.$source.$id.tsx @@ -1,15 +1,15 @@ import { AnimatedBackground } from '@/mainview/components/AnimatedBackground'; import { AutoFocus } from '@/mainview/components/AutoFocus'; import GameLookupElement from '@/mainview/components/game/GameLookup'; -import { HeaderUI } from '@/mainview/components/Header'; +import { HeaderUI, StickyHeaderUI } from '@/mainview/components/Header'; import { FloatingShortcuts } from '@/mainview/components/Shortcuts'; import { customUpdateMutation, gameInvalidationQuery, gameQuery } from '@/mainview/scripts/queries/romm'; import { GamePadButtonCode, useShortcuts } from '@/mainview/scripts/shortcuts'; import { HandleGoBack } from '@/mainview/scripts/utils'; import { FocusContext, useFocusable } from '@noriginmedia/norigin-spatial-navigation'; import { useMutation, useQuery } from '@tanstack/react-query'; -import { createFileRoute, useRouter } from '@tanstack/react-router'; -import { useEffect, useState } from 'react'; +import { createFileRoute, useNavigate, useRouter } from '@tanstack/react-router'; +import { useEffect, useRef, useState } from 'react'; import toast from 'react-hot-toast'; export const Route = createFileRoute('/game/update/$source/$id')({ diff --git a/src/mainview/routes/games.tsx b/src/mainview/routes/games.tsx index bd0fc8e..e6fd86e 100644 --- a/src/mainview/routes/games.tsx +++ b/src/mainview/routes/games.tsx @@ -2,7 +2,7 @@ import { createFileRoute, useNavigate } from '@tanstack/react-router'; import { CollectionsDetail } from '../components/CollectionsDetail'; import { zodValidator } from '@tanstack/zod-adapter'; import z from 'zod'; -import { GameListFilterType } from '@simeonradivoev/gameflow-sdk/shared'; +import { GameListFilterType } from '@/shared/constants'; import { useSessionStorage } from 'usehooks-ts'; import HeaderSearchField from '../components/HeaderSearchField'; import { useEffect } from 'react'; @@ -31,7 +31,7 @@ function RouteComponent () return + [ { navigate({ to: '/game/add' }); }} >, diff --git a/src/mainview/routes/index.tsx b/src/mainview/routes/index.tsx index 8ae562a..9505d30 100644 --- a/src/mainview/routes/index.tsx +++ b/src/mainview/routes/index.tsx @@ -14,7 +14,6 @@ import import { createFileRoute, - useNavigate, useRouter, } from "@tanstack/react-router"; import { useMutation, useQueryClient } from "@tanstack/react-query"; @@ -41,7 +40,7 @@ import z from "zod"; import CollectionList from "../components/CollectionList"; import { zodValidator } from '@tanstack/zod-adapter'; import { mobileCheck, scrollIntoViewHandler, useDragScroll } from "../scripts/utils"; -import { AnimatedBackgroundContext, GlobalDialogContext } from "../scripts/contexts"; +import { AnimatedBackgroundContext } from "../scripts/contexts"; import Carousel from "../components/Carousel"; import { closeMutation } from "@queries/system"; import { gameQuery } from "../scripts/queries/romm"; @@ -51,11 +50,7 @@ import SelectMenu from "../components/SelectMenu"; import HeaderSearchField from "../components/HeaderSearchField"; import CardElement from "../components/CardElement"; import { Router } from ".."; -import { FrontEndId } from "@simeonradivoev/gameflow-sdk/shared"; -import { playGame, usePlayMutation } from "../components/game/MainActions"; -import { rommApi } from "../scripts/clientApi"; -import { ContextList, DialogEntry } from "../components/ContextDialog"; -import { FOCUS_KEYS } from "../scripts/types"; +import { FrontEndId } from "@/shared/types"; export const Route = createFileRoute("/")({ component: ConsoleHomeUI, @@ -157,9 +152,6 @@ function HomeList (data: { focusKey: "home-list", preferredChildFocusKey: `${data.selectedFilter}-list` }); - const navigate = useNavigate(); - const playGameMut = usePlayMutation(navigate); - const globalDialog = useContext(GlobalDialogContext); const handleNodeFocus = (id: string, node: HTMLElement, details: FocusDetails) => { @@ -177,52 +169,6 @@ function HomeList (data: { router.navigate({ to: '/game/$source/$id', params: { id: String(sourceId ?? id.id), source: source ?? id.source } }); }; - async function handleGamePlay (id: FrontEndId, source: string | null, sourceId: string | null) - { - const finalSource = source ?? id.source; - const finalId = String(sourceId ?? id.id); - - const validCommands = await rommApi.api.romm.game({ source: finalSource })({ id: finalId }).commands.get(); - if (validCommands.data) - { - const preferredCommand = localStorage.getItem(`${finalSource}-${finalId}-preferred-command`); - if (preferredCommand) - { - playGame(finalSource, finalId, validCommands.data.commands[JSON.parse(preferredCommand)], navigate, playGameMut.mutate); - } else - { - if (validCommands.data.commands.length > 1) - { - globalDialog.openContext({ - content: - { - const option: DialogEntry = { - id: String(c.id), - content: c.label ?? String(c.id), - type: "primary", - action (ctx) - { - localStorage.setItem(`${finalSource}-${finalId}-preferred-command`, JSON.stringify(i)); - ctx.close(); - playGame(finalSource, finalId, validCommands.data.commands[0], navigate, playGameMut.mutate); - }, - }; - - return option; - }) - } /> - }, FOCUS_KEYS.GAME_LIST_CARD('games-list', id)); - } else if (validCommands.data.commands.length === 1) - { - playGame(finalSource, finalId, validCommands.data.commands[0], navigate, playGameMut.mutate); - } - - } - } - - } - let activeList: JSX.Element; switch (data.selectedFilter) { @@ -244,7 +190,6 @@ function HomeList (data: { activeList = <> { @@ -258,7 +203,7 @@ function HomeList (data: { setBackground={bg.setBackground} filters={{ limit: 12, orderBy: 'activity' }} finalElement={[ - , + , ]} emptyElement={[ diff --git a/src/mainview/routes/platform.$source.$id.tsx b/src/mainview/routes/platform.$source.$id.tsx index bc35faf..73d0265 100644 --- a/src/mainview/routes/platform.$source.$id.tsx +++ b/src/mainview/routes/platform.$source.$id.tsx @@ -1,17 +1,14 @@ import { createFileRoute, useRouter } from "@tanstack/react-router"; import { CollectionsDetail } from "../components/CollectionsDetail"; import { useMutation, useQuery } from "@tanstack/react-query"; -import { RPC_URL } from "../../shared/constants"; -import { GameListFilterType } from '@simeonradivoev/gameflow-sdk/shared'; +import { GameListFilterType, RPC_URL } from "../../shared/constants"; import { deletePlatformMutation, localPlatformFilter, platformQuery, updatePlatformMutation } from "@queries/romm"; import { zodValidator } from "@tanstack/zod-adapter"; import z from "zod"; import { useLocalStorage } from "usehooks-ts"; import { RefreshCcw, Settings2 } from "lucide-react"; -import { ContextList, DialogEntry } from "../components/ContextDialog"; +import { ContextList, DialogEntry, useContextDialog } from "../components/ContextDialog"; import toast from "react-hot-toast"; -import { useContext } from "react"; -import { GlobalDialogContext } from "../scripts/contexts"; export const Route = createFileRoute("/platform/$source/$id")({ component: RouteComponent, @@ -47,7 +44,6 @@ function RouteComponent () context.client.invalidateQueries(localPlatformFilter(id)); }, }); - const globalDialog = useContext(GlobalDialogContext); const deletePlatform = useMutation({ ...deletePlatformMutation(id), onError (error, variables, onMutateResult, context) @@ -80,7 +76,7 @@ function RouteComponent () if (source === 'local') { settingsOptions.push({ - id: 'delete-platform', + id: 'update-platform', type: "error", content: "Delete", icon: deletePlatform.isPending ? : , @@ -91,6 +87,10 @@ function RouteComponent () }); } + const { dialog: platformSettingsDialog, setOpen: setPlatformSettingsOpen } = useContextDialog('platform-settings-dialog', { + content: + }); + return (
      , action () { - globalDialog.openContext({ content: }, 'open-platform-settings-btn'); + setPlatformSettingsOpen(true, 'open-platform-settings-btn'); }, }]} countHint={countHint} title={} filters={{ platform_id: Number(id), platform_source: source }} /> + {platformSettingsDialog}
      ); } diff --git a/src/mainview/routes/settings/accounts.tsx b/src/mainview/routes/settings/accounts.tsx index eacd432..ce5586c 100644 --- a/src/mainview/routes/settings/accounts.tsx +++ b/src/mainview/routes/settings/accounts.tsx @@ -13,8 +13,7 @@ import useEffect, useRef, } from "react"; -import { RPC_URL } from "@shared/constants"; -import { RommLoginDataSchema } from '@simeonradivoev/gameflow-sdk/shared'; +import { RommLoginDataSchema, RPC_URL } from "@shared/constants"; import toast from "react-hot-toast"; import { OptionSpace } from "../../components/options/OptionSpace"; import { useSettingsForm, useSettingsFormContext } from "../../components/options/SettingsAppForm"; diff --git a/src/mainview/routes/settings/directories.tsx b/src/mainview/routes/settings/directories.tsx index 5adee26..4af256b 100644 --- a/src/mainview/routes/settings/directories.tsx +++ b/src/mainview/routes/settings/directories.tsx @@ -13,13 +13,10 @@ import { systemApi } from '@/mainview/scripts/clientApi'; import useActiveControl from '@/mainview/scripts/gamepads'; import { changeDownloadsMutation } from '@queries/settings'; import { downloadDrivesQuery } from '@/mainview/scripts/queries/system'; -import { DownloadsDrive } from '@simeonradivoev/gameflow-sdk/shared'; -import { zodValidator } from '@tanstack/zod-adapter'; -import z from 'zod'; +import { DownloadsDrive } from '@/shared/types'; export const Route = createFileRoute('/settings/directories')({ component: RouteComponent, - validateSearch: zodValidator(z.object({ focus: z.string().optional() })) }); function DriveComponent (data: { drive: DownloadsDrive; downloadsSize: number; refetchDrives: () => void; }) diff --git a/src/mainview/routes/settings/emulators.tsx b/src/mainview/routes/settings/emulators.tsx index 17344df..7e3f381 100644 --- a/src/mainview/routes/settings/emulators.tsx +++ b/src/mainview/routes/settings/emulators.tsx @@ -8,8 +8,7 @@ import { Check, ChevronDown, FolderSearch, HardDrive, Plug, SearchAlert, Store, import { ContextDialog, ContextList, DialogEntry, OptionElement } from '../../components/ContextDialog'; import classNames from 'classnames'; import { twMerge } from 'tailwind-merge'; -import { RPC_URL } from '../../../shared/constants'; -import { SettingsSchema } from '@simeonradivoev/gameflow-sdk/shared'; +import { RPC_URL, SettingsSchema } from '../../../shared/constants'; import emulators from '@emulators'; import { FocusContext, setFocus, useFocusable } from '@noriginmedia/norigin-spatial-navigation'; import { GamePadButtonCode, Shortcut, useShortcuts } from '@/mainview/scripts/shortcuts'; @@ -21,15 +20,11 @@ import { FOCUS_KEYS } from '@/mainview/scripts/types'; import { scrollIntoNearestParent, scrollIntoViewHandler, useDragScroll } from '@/mainview/scripts/utils'; import { SettingsOption } from '@/mainview/components/options/SettingsOption'; import { SettingsDropdown } from '@/mainview/components/options/SettingsDropdown'; -import { FrontEndEmulator } from '@simeonradivoev/gameflow-sdk/shared'; -import { zodValidator } from '@tanstack/zod-adapter'; -import z from 'zod'; -import { isUrl } from '@/shared/utils'; +import { FrontEndEmulator } from '@/shared/types'; export const Route = createFileRoute('/settings/emulators')({ component: RouteComponent, pendingComponent: EmulatorsPending, - validateSearch: zodValidator(z.object({ focus: z.string().optional() })) }); function EmulatorsPending () @@ -239,7 +234,7 @@ function EmulatorBadge (data: { let logoUrl: string | undefined = undefined; if (data.emulator.logo) { - if (isUrl(data.emulator.logo)) + if (data.emulator.logo.startsWith('http')) { logoUrl = data.emulator.logo; } else diff --git a/src/mainview/routes/settings/interface.tsx b/src/mainview/routes/settings/interface.tsx index 8ef70d4..f1a42c8 100644 --- a/src/mainview/routes/settings/interface.tsx +++ b/src/mainview/routes/settings/interface.tsx @@ -1,15 +1,11 @@ import { LocalOption } from '@/mainview/components/options/LocalOption'; -import { settingRegistry } from '@simeonradivoev/gameflow-sdk/shared'; -import { LocalSettingsSchema } from '@simeonradivoev/gameflow-sdk/shared'; +import { LocalSettingsSchema, settingRegistry } from '@/shared/constants'; import { FocusContext, useFocusable } from '@noriginmedia/norigin-spatial-navigation'; import { createFileRoute } from '@tanstack/react-router'; import { Terminal } from 'lucide-react'; -import { zodValidator } from '@tanstack/zod-adapter'; -import z from 'zod'; export const Route = createFileRoute('/settings/interface')({ component: RouteComponent, - validateSearch: zodValidator(z.object({ focus: z.string().optional() })) }); function RouteComponent () diff --git a/src/mainview/routes/settings/plugin.$source.tsx b/src/mainview/routes/settings/plugin.$source.tsx index c80b592..7263bea 100644 --- a/src/mainview/routes/settings/plugin.$source.tsx +++ b/src/mainview/routes/settings/plugin.$source.tsx @@ -5,25 +5,23 @@ import { OptionDropdown } from '@/mainview/components/options/OptionDropdown'; import { OptionInput } from '@/mainview/components/options/OptionInput'; import { OptionSpace } from '@/mainview/components/options/OptionSpace'; import { RoundButton } from '@/mainview/components/RoundButton'; -import { allPluginsFilter, getPluginDetailsQuery, updatePluginMutation } from '@/mainview/scripts/queries/plugins'; +import { getPluginDetailsQuery } from '@/mainview/scripts/queries/plugins'; import { getPluginActionsQuery, getPluginSettingQuery, getPluginSettingsDefinitionQuery, pluginActionMutation, setPluginSettingMutation } from '@/mainview/scripts/queries/settings'; import { GamePadButtonCode, useShortcuts } from '@/mainview/scripts/shortcuts'; import { scrollIntoViewHandler } from '@/mainview/scripts/utils'; import { FocusContext, useFocusable } from '@noriginmedia/norigin-spatial-navigation'; -import { PluginUpdateCheck } from '@simeonradivoev/gameflow-sdk/shared'; import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; import { createFileRoute, useNavigate } from '@tanstack/react-router'; import { JSONSchema7 } from 'json-schema'; -import { ArrowLeft, ArrowRight, CircleFadingArrowUp, CirclePlay, Settings2 } from 'lucide-react'; +import { ArrowLeft, CirclePlay, Settings2 } from 'lucide-react'; import toast from 'react-hot-toast'; export const Route = createFileRoute('/settings/plugin/$source')({ component: RouteComponent, pendingComponent: Loading, async loader (ctx) { - const source = decodeURIComponent(ctx.params.source); - const definitions = await ctx.context.queryClient.fetchQuery(getPluginSettingsDefinitionQuery(source)); - const actions = await ctx.context.queryClient.fetchQuery(getPluginActionsQuery(source)); + const definitions = await ctx.context.queryClient.fetchQuery(getPluginSettingsDefinitionQuery(ctx.params.source)); + const actions = await ctx.context.queryClient.fetchQuery(getPluginActionsQuery(ctx.params.source)); await new Promise(resolve => setTimeout(resolve, 1000)); return { definitions, actions }; }, @@ -40,8 +38,7 @@ function Loading () function PluginAction (data: { id: string, title: string | undefined, description: string | undefined; action: string; reload: () => void; }) { - const { source: sourceRaw } = Route.useParams(); - const source = decodeURIComponent(sourceRaw); + const { source } = Route.useParams(); const action = useMutation({ ...pluginActionMutation(source, data.id), onSuccess (acitonData, variables, onMutateResult, context) @@ -70,8 +67,7 @@ function PluginAction (data: { id: string, title: string | undefined, descriptio function PluginOption (data: { name: string, title?: string, prop: JSONSchema7; }) { - const { source: sourceRaw } = Route.useParams(); - const source = decodeURIComponent(sourceRaw); + const { source } = Route.useParams(); const { data: value, refetch: refetchValue } = useQuery(getPluginSettingQuery(source, data.name)); const setValue = useMutation({ ...setPluginSettingMutation(source, data.name), @@ -112,21 +108,12 @@ function PluginOption (data: { name: string, title?: string, prop: JSONSchema7; ; } -function Settings (data: { update: PluginUpdateCheck | undefined; }) +function Settings () { const { definitions, actions } = Route.useLoaderData(); - const { source: sourceRaw } = Route.useParams(); - const source = decodeURIComponent(sourceRaw); + const { source } = Route.useParams(); const queryClient = useQueryClient(); - const navigate = useNavigate(); - const update = useMutation({ - ...updatePluginMutation(source), - onSuccess (data, variables, onMutateResult, context) - { - context.client.invalidateQueries(allPluginsFilter); - navigate({ to: '/settings/plugin/$source', params: { source: encodeURIComponent(source) }, replace: true }); - }, - }); + const handleReload = () => { queryClient.refetchQueries(getPluginSettingsDefinitionQuery(source)); @@ -134,7 +121,7 @@ function Settings (data: { update: PluginUpdateCheck | undefined; }) }; const { ref, focusKey } = useFocusable({ focusKey: 'plugin-settings', - focusable: (definitions?.properties && Object.keys(definitions?.properties).length > 0) || actions.length > 0 || !!data.update + focusable: (definitions?.properties && Object.keys(definitions?.properties).length > 0) || actions.length > 0 }); return
      @@ -161,15 +148,6 @@ function Settings (data: { update: PluginUpdateCheck | undefined; }) })}
      Actions
      - {!!data.update && -
      Update
      -
      {data?.update?.current} {'>'} {data?.update?.new}
      -
      }> - - } {actions?.map(a => )}
      ; @@ -177,8 +155,7 @@ function Settings (data: { update: PluginUpdateCheck | undefined; }) function RouteComponent () { - const { source: sourceRaw } = Route.useParams(); - const source = decodeURIComponent(sourceRaw); + const { source } = Route.useParams(); const { ref, focusKey, focusSelf } = useFocusable({ focusKey: 'plugins' }); const { data } = useQuery(getPluginDetailsQuery(source)); @@ -190,17 +167,17 @@ function RouteComponent ()
      -
      +
      -
      {data?.displayName}
      -
      {data?.version}
      - {!!data?.update &&
      {data?.update.new}
      } + {data?.displayName}
        {data?.keywords?.map((k, i) =>
      • {k}
      • )}
      {data?.description}
      - + + +
      ; diff --git a/src/mainview/routes/settings/plugins.tsx b/src/mainview/routes/settings/plugins.tsx index c55fc8f..c9476ba 100644 --- a/src/mainview/routes/settings/plugins.tsx +++ b/src/mainview/routes/settings/plugins.tsx @@ -3,13 +3,13 @@ import { pluginCategoryIcons, pluginCategoryPriorities } from '@/mainview/compon import { OptionInput } from '@/mainview/components/options/OptionInput'; import { OptionSpace } from '@/mainview/components/options/OptionSpace'; import { RoundButton } from '@/mainview/components/RoundButton'; -import { enablePluginMutation, getAllPluginsQuery, uninstallPluginMutation } from '@/mainview/scripts/queries/plugins'; +import { enablePluginMutation, getAllPluginsQuery } from '@/mainview/scripts/queries/plugins'; import { GamePadButtonCode, Shortcut } from '@/mainview/scripts/shortcuts'; -import { FrontendPlugin } from '@simeonradivoev/gameflow-sdk/shared'; +import { FrontendPlugin } from '@/shared/types'; import { FocusContext, useFocusable } from '@noriginmedia/norigin-spatial-navigation'; import { useMutation, useQuery } from '@tanstack/react-query'; import { createFileRoute, useNavigate } from '@tanstack/react-router'; -import { CircleFadingArrowUp, Eye, Puzzle, Settings2, Trash } from 'lucide-react'; +import { Eye, Puzzle, Search, Settings2 } from 'lucide-react'; export const Route = createFileRoute('/settings/plugins')({ component: RouteComponent, @@ -33,9 +33,7 @@ function Plugin (data: { }, }); - const uninstall = useMutation(uninstallPluginMutation(data.plugin.name)); - const handleUninstall = () => uninstall.mutate(); - const handleDetails = () => navigate({ to: '/settings/plugin/$source', params: { source: encodeURIComponent(data.plugin.name) }, replace: true, viewTransition: { types: ['slide-up'] } }); + const handleDetails = () => navigate({ to: '/settings/plugin/$source', params: { source: data.plugin.name }, replace: true, viewTransition: { types: ['slide-up'] } }); return : }
      -
      {data.plugin.displayName ?? data.plugin.name}
      +
      {data.plugin.displayName}
      {data.plugin.name} ({data.plugin.version})
      {data.plugin.hasSettings && } - {data.plugin.update &&
      - -
      }
@@ -60,7 +55,6 @@ function Plugin (data: { >
{data.plugin.hasSettings ? : } - {data.plugin.canUninstall && {uninstall.isPending ? : }} {data.plugin.canDisable && data.setEnabled(!!v)} value={data.plugin.enabled} name={data.plugin.name} type="checkbox" />}
; diff --git a/src/mainview/routes/settings/route.tsx b/src/mainview/routes/settings/route.tsx index 625e884..fd83578 100644 --- a/src/mainview/routes/settings/route.tsx +++ b/src/mainview/routes/settings/route.tsx @@ -16,7 +16,6 @@ import classNames from "classnames"; import { ArrowBigLeft, - Cog, FingerprintPattern, HardDrive, Info, @@ -156,12 +155,6 @@ function SettingsMenu (data: {}) label="Plugins" icon={} /> - } - /> ([]); - const [queuedJobs, setQueuedJobs] = useState([]); - const wsRef = useRef<{ send: (data: any) => void; }>(null); - - useEffect(() => - { - const sub = jobsApi.api.jobs.list.subscribe(); - wsRef.current = { - send (data) - { - sub.ws.send(JSON.stringify(data)); - }, - }; - sub.on('message', e => - { - switch (e.data.type) - { - case 'allJobs': - setActiveJobs(e.data.active); - setQueuedJobs(e.data.queued); - break; - - case 'aborted': - const abortedJobId = e.data.id; - setActiveJobs(jobs => jobs.map(j => j.id === abortedJobId ? { ...j, status: 'aborted' } : j)); - setQueuedJobs(jobs => jobs.filter(j => j.id !== abortedJobId)); - break; - - case 'queued': - const queuedJob = e.data.job; - setQueuedJobs(jobs => [...jobs, queuedJob]); - break; - - case 'progress': - const progressJob = e.data.job; - setActiveJobs(jobs => jobs.map(j => j.id === progressJob.id ? progressJob : j)); - break; - - case 'started': - const newJob = e.data.job; - setActiveJobs(jobs => [newJob, ...jobs]); - setQueuedJobs(jobs => jobs.filter(j => j.id !== newJob.id)); - break; - - case 'ended': - const endedJobId = e.data.id; - setActiveJobs(jobs => jobs.filter(j => j.id !== endedJobId)); - break; - } - }); - - return () => - { - sub.close(); - wsRef.current = null; - }; - }, []); - - const handleCancel = (id: string) => - { - wsRef.current?.send({ type: 'cancel', id: id }); - }; - - return
-
Active
-
    - {activeJobs.map((job, i) =>
  • -
    -
    - {job.data.preview_url ? : } -
    -
    {job.data.name ?? job.id}
    -
    -
    -
    -
    -
    {job.state}
    -
    {job.progress.toFixed(1)}%
    -
    - -
    - {job.data.downloaded != null && job.data.total != null &&
    {prettyBytes(job.data.downloaded)}/{prettyBytes(job.data.total)}
    } - {job.data.speed != null &&
    {prettyBytes(job.data.speed)}/s
    } -
    -
    - -
    -
  • )} -
-
Queued
-
    - {queuedJobs.map((job, i) =>
  • -
    -
    -
    {job.data.name ?? job.id}
    -
    -
    -
    -
    - {job.data.total !== undefined &&
    {prettyBytes(job.data.total)}
    } -
    -
    - -
    -
  • )} -
-
; -} diff --git a/src/mainview/routes/settings/update.tsx b/src/mainview/routes/settings/update.tsx index 3f27639..905ada6 100644 --- a/src/mainview/routes/settings/update.tsx +++ b/src/mainview/routes/settings/update.tsx @@ -3,7 +3,7 @@ import DotsLoading from '@/mainview/components/backgrounds/dots'; import { Button } from '@/mainview/components/options/Button'; import { checkUpdateMutation, hasUpdateQuery, updateMutation } from '@/mainview/scripts/queries/system'; import { FocusContext, useFocusable } from '@noriginmedia/norigin-spatial-navigation'; -import { useMutation } from '@tanstack/react-query'; +import { useMutation, useQuery } from '@tanstack/react-query'; import { createFileRoute, useNavigate } from '@tanstack/react-router'; import { CircleFadingArrowUp, RefreshCcw } from 'lucide-react'; import { MarkdownAsync } from 'react-markdown'; diff --git a/src/mainview/routes/store/details.download.$source.$id.tsx b/src/mainview/routes/store/details.download.$source.$id.tsx deleted file mode 100644 index 2100442..0000000 --- a/src/mainview/routes/store/details.download.$source.$id.tsx +++ /dev/null @@ -1,129 +0,0 @@ -import { AutoFocus } from '@/mainview/components/AutoFocus'; -import DotsLoading from '@/mainview/components/backgrounds/dots'; -import { ContextList, DialogEntry } from '@/mainview/components/ContextDialog'; -import { StickyHeaderUI } from '@/mainview/components/Header'; -import { Button } from '@/mainview/components/options/Button'; -import Screenshots from '@/mainview/components/Screenshots'; -import SelectMenu from '@/mainview/components/SelectMenu'; -import { FloatingShortcuts } from '@/mainview/components/Shortcuts'; -import { GlobalDialogContext } from '@/mainview/scripts/contexts'; -import { downloadLookupQuery } from '@/mainview/scripts/queries/romm'; -import { GamePadButtonCode, useShortcuts } from '@/mainview/scripts/shortcuts'; -import { HandleGoBack } from '@/mainview/scripts/utils'; -import { FocusContext, useFocusable } from '@noriginmedia/norigin-spatial-navigation'; -import { createFileRoute, useNavigate, useRouter } from '@tanstack/react-router'; -import { Download } from 'lucide-react'; -import prettyBytes from 'pretty-bytes'; -import { useContext } from 'react'; - -export const Route = createFileRoute('/store/details/download/$source/$id')({ - component: RouteComponent, - pendingComponent: Loading, - async loader (ctx) - { - const data = await ctx.context.queryClient.fetchQuery(downloadLookupQuery(decodeURIComponent(ctx.params.source), decodeURIComponent(ctx.params.id))); - return { data }; - } -}); - -function Loading () -{ - const { ref, focusSelf } = useFocusable({ focusKey: 'download-details' }); - return <> - - - ; -} - -const imagesMap = new Set(['JPEG', 'PNG', 'Motion JPEG', 'Item Image']); -const videoFormat = new Set(['h.264']); -const downloadsBlacklist = new Set(['JPEG Thumb', 'Metadata', 'Thumbnail', 'Item Tile', 'Archive BitTorrent', ...videoFormat, ...imagesMap]); - -function Details (data: { onDownload: (focusKey: string) => void; }) -{ - const { data: download } = Route.useLoaderData(); - const screenshots = download.files.filter(f => f.format && imagesMap.has(f.format)).map(f => f.download_url); - if (screenshots.length <= 0 && download.cover_url) screenshots.push(download.cover_url); - return
- -
-
-
- {!!download.cover_url && } -
-
{download.name}
-
-
{download.date?.toDateString()}
-
-
{download.source}
-
-
-
-
- -
-
-
- {!!download.summary &&
-
-
} -
-
Downloads
-
    - {download.files.filter(f => f.format && !downloadsBlacklist.has(f.format)).map(f =>
  • - {f.id} - {!!f.size && prettyBytes(f.size)} -
  • )} -
-
- -
-
-
; -} - -function RouteComponent () -{ - const navigate = useNavigate(); - const router = useRouter(); - const { ref, focusKey, focusSelf } = useFocusable({ focusKey: 'download-details', preferredChildFocusKey: 'download-btn' }); - const { data } = Route.useLoaderData(); - const globalDialog = useContext(GlobalDialogContext); - - useShortcuts(focusKey, () => [{ - label: "Return", - action: (e) => HandleGoBack(router, e), - button: GamePadButtonCode.B - }], [router]); - - return
- - -
globalDialog.openContext({ - content: f.format && !downloadsBlacklist.has(f.format)).map(f => - { - const option: DialogEntry = { - id: f.id, - content: f.id, - type: 'primary', - action (ctx) - { - navigate({ - to: '/game/add', search: { - gameLocation: f.download_url, - search: data.name, - step: 1 - } - }); - }, - }; - - return option; - })} /> - }, focusKey)} /> - - - - -
; -} diff --git a/src/mainview/routes/store/details.emulator.$id.tsx b/src/mainview/routes/store/details.emulator.$id.tsx index d8c8372..60b3917 100644 --- a/src/mainview/routes/store/details.emulator.$id.tsx +++ b/src/mainview/routes/store/details.emulator.$id.tsx @@ -1,4 +1,4 @@ -import { useContext, useRef, useState } from "react"; +import { useRef, useState } from "react"; import { useFocusable, @@ -11,7 +11,7 @@ import { AnimatedBackground } from "@/mainview/components/AnimatedBackground"; import { rommApi, systemApi } from "@/mainview/scripts/clientApi"; import { Button } from "@/mainview/components/options/Button"; import { ChevronDown, CircleFadingArrowUp, CloudUpload, Cpu, Download, Fullscreen, Gamepad2, Info, Monitor, Puzzle, Settings, Settings2, Terminal, Trash2, TriangleAlert, WandSparkles } from "lucide-react"; -import { ContextList, DialogEntry } from "@/mainview/components/ContextDialog"; +import { ContextList, DialogEntry, useContextDialog } from "@/mainview/components/ContextDialog"; import { RPC_URL } from "@/shared/constants"; import Screenshots from "@/mainview/components/Screenshots"; import { StickyHeaderUI } from "@/mainview/components/Header"; @@ -29,8 +29,7 @@ import FocusTooltip from "@/mainview/components/FocusTooltip"; import { AutoFocus } from "@/mainview/components/AutoFocus"; import { FilterUI } from "@/mainview/components/Filters"; import Markdown from "react-markdown"; -import { FrontEndEmulatorDetailed } from "@simeonradivoev/gameflow-sdk/shared"; -import { GlobalDialogContext } from "@/mainview/scripts/contexts"; +import { FrontEndEmulatorDetailed } from "@/shared/types"; export const Route = createFileRoute('/store/details/emulator/$id')({ component: RouteComponent, @@ -66,7 +65,6 @@ function TitleArea (data: { onUpdate: (source: string) => void; }) { - const globalDialog = useContext(GlobalDialogContext); const navigation = useNavigate(); const queryClient = useQueryClient(); const deleteMutation = useMutation({ @@ -255,12 +253,14 @@ function TitleArea (data: { installButtonContent = <>Unsupported; } - const openOptionsDialog = (focusKey: string) => globalDialog.openContext({ content: }, focusKey); + const { dialog: installOptionsDialog, setOpen } = useContextDialog("install-context-menu", { + content: + }); const handleOptionsOpen = () => { if (isInstalling || !data.emulator) return false; - openOptionsDialog('install-btn'); + setOpen(true, 'install-btn'); }; return
@@ -294,10 +294,10 @@ function TitleArea (data: {
{(data.emulator?.storeDownloadInfo?.hasUpdate || !data.emulator?.storeDownloadInfo) && installedFromStore && !!updateToVersion &&
- +
} {(!data.emulator?.bios || data.emulator.bios.length <= 0) && (data.emulator?.biosRequirement === 'required') && installedFromStore &&
- +
}
+ {installOptionsDialog}
; } diff --git a/src/mainview/routes/store/details.plugin.$id.tsx b/src/mainview/routes/store/details.plugin.$id.tsx deleted file mode 100644 index 9e35cdb..0000000 --- a/src/mainview/routes/store/details.plugin.$id.tsx +++ /dev/null @@ -1,161 +0,0 @@ -import { AutoFocus } from '@/mainview/components/AutoFocus'; -import DotsLoading from '@/mainview/components/backgrounds/dots'; -import { StickyHeaderUI } from '@/mainview/components/Header'; -import LoadingScreen from '@/mainview/components/LoadingScreen'; -import { Button } from '@/mainview/components/options/Button'; -import { FloatingShortcuts } from '@/mainview/components/Shortcuts'; -import StatList, { StatEntry } from '@/mainview/components/StatList'; -import { installPluginMutation, pluginFilter, uninstallPluginMutation, updatePluginMutation } from '@/mainview/scripts/queries/plugins'; -import { pluginDetailsQuery } from '@/mainview/scripts/queries/store'; -import { GamePadButtonCode, useShortcuts } from '@/mainview/scripts/shortcuts'; -import { HandleGoBack } from '@/mainview/scripts/utils'; -import { FocusContext, useFocusable } from '@noriginmedia/norigin-spatial-navigation'; -import { QueryClient, useMutation } from '@tanstack/react-query'; -import { createFileRoute, useNavigate, useRouter } from '@tanstack/react-router'; -import { ArrowRight, CircleFadingArrowUp, Download, Settings, Trash } from 'lucide-react'; -import prettyBytes from 'pretty-bytes'; -import { Suspense } from 'react'; - -export const Route = createFileRoute('/store/details/plugin/$id')({ - component: RouteComponent, - pendingComponent: Loading, - async loader (ctx) - { - const id = decodeURIComponent(ctx.params.id); - const data = await ctx.context.queryClient.fetchQuery(pluginDetailsQuery(id)); - return { data }; - }, -}); - -function Loading () -{ - const { ref, focusSelf } = useFocusable({ focusKey: 'plugin-details' }); - return <> - - - ; -} - -function Details () -{ - const { id } = Route.useParams(); - const plugin = decodeURIComponent(id); - const { data } = Route.useLoaderData(); - const navigate = useNavigate(); - const handleRefresh = (client: QueryClient) => - { - client.invalidateQueries(pluginFilter(plugin)); - navigate({ to: '/store/details/plugin/$id', params: { id: encodeURIComponent(id) }, replace: true }); - }; - const update = useMutation({ - ...updatePluginMutation(plugin), - onSuccess (data, variables, onMutateResult, context) - { - handleRefresh(context.client); - }, - }); - const install = useMutation({ - ...installPluginMutation(plugin), - onSuccess (data, variables, onMutateResult, context) - { - handleRefresh(context.client); - }, - }); - const uninstall = useMutation({ - ...uninstallPluginMutation(plugin), - onSuccess (data, variables, onMutateResult, context) - { - handleRefresh(context.client); - }, - }); - - const stats: StatEntry[] = []; - if (data.devDependencies) - { - stats.push({ content: Object.keys(data.devDependencies), label: "Dev Dependecies" }); - } - if (data.dependencies) - { - stats.push({ content: Object.keys(data.dependencies), label: "Dependecies" }); - } - if (data.maintainers) - { - stats.push({ content: data.maintainers.map(m => m.name), label: "Maintainers" }); - } - if (data.dist) - { - stats.push({ content: prettyBytes(data.dist.unpackedSize), label: "Size" }); - } - if (data.license) - { - stats.push({ content: data.license, label: "License" }); - } - return <> - -
-
-
{data.name}
-
-
- {data.update ? <> -
{data.update.from}
- -
{data.version}
- : -
{data.version}
} - -
- by {data.author?.name ?? data._npmUser?.name}
-
-
- {data.installed && <> - {!!data.update && } - - - - } - {!data.installed && } - -
-
-
Details
-
-
{data.description}
- -
-
Keywords
-
- {data.keywords.map(k =>
  • {k}
  • )} -
    - ; -} - -function RouteComponent () -{ - const router = useRouter(); - const { ref, focusKey, focusSelf } = useFocusable({ focusKey: 'plugin-details' }); - useShortcuts(focusKey, () => [{ - label: "Return", button: GamePadButtonCode.B, action (e) - { - HandleGoBack(router, e); - }, - }]); - return
    - - - }> -
    - - - - -
    ; -} diff --git a/src/mainview/routes/store/tab/download.tsx b/src/mainview/routes/store/tab/download.tsx deleted file mode 100644 index a1f0172..0000000 --- a/src/mainview/routes/store/tab/download.tsx +++ /dev/null @@ -1,114 +0,0 @@ -import DotsLoading from '@/mainview/components/backgrounds/dots'; -import LoadMoreButton from '@/mainview/components/LoadMoreButton'; -import { Button } from '@/mainview/components/options/Button'; -import { SideDownloadFilters } from '@/mainview/components/SideFilters'; -import { downloadLookupFiltersQuery, downloadsLookupQuery } from '@/mainview/scripts/queries/romm'; -import { scrollIntoViewHandler } from '@/mainview/scripts/utils'; -import { FocusContext, useFocusable } from '@noriginmedia/norigin-spatial-navigation'; -import { DownloadLookupEntry, DownloadsLookupFilter } from '@simeonradivoev/gameflow-sdk/shared'; -import { useInfiniteQuery, useQuery } from '@tanstack/react-query'; -import { createFileRoute, useNavigate } from '@tanstack/react-router'; -import { ArrowRight, DownloadIcon, Eye, MessageCircle, Puzzle, Save, Star } from 'lucide-react'; -import prettyBytes from 'pretty-bytes'; -import { useSessionStorage } from 'usehooks-ts'; - -export const Route = createFileRoute('/store/tab/download')({ - component: RouteComponent, -}); - -function Download (data: { focusKey: string, match: DownloadLookupEntry; }) -{ - const navigate = useNavigate(); - const handleAction = () => navigate({ - to: '/store/details/download/$source/$id', params: { - source: encodeURIComponent(data.match.source), - id: encodeURIComponent(data.match.id) - } - }); - const { ref, focusKey } = useFocusable({ - focusKey: data.focusKey, - onFocus: (l, p, d) => scrollIntoViewHandler({ behavior: "smooth", block: "center", inline: "center" })(focusKey, ref.current, d), - onEnterPress: handleAction - }); - return
  • - {!!data.match.cover_url && } -
    -
    {data.match.name}
    -
    {data.match.date?.toDateString()}
    -
      - {!!data.match.size &&
    • {prettyBytes(data.match.size)}
    • } - {!!data.match.download_count &&
    • {data.match.download_count}
    • } - {!!data.match.view_count &&
    • {data.match.view_count}
    • } - {!!data.match.comment_count &&
    • {data.match.comment_count}
    • } - {!!data.match.rating &&
    • {data.match.rating}
    • } -
    -
    -
  • ; -} - -function Downloads (data: { - pages: { - data: DownloadLookupEntry[]; - totalCount: number; - hadMatchers: boolean; - nextPage: number; - }[]; - hasNextPage: boolean, - isFetchingNextPage: boolean, - isFetching: boolean, - fetchNextPage: () => void, - error: string | undefined; -}) -{ - const navigate = useNavigate(); - const { ref, focusKey } = useFocusable({ focusKey: 'downloads-list' }); - return
      - - {data.pages.flatMap((page, p) => page.data.map((match, i) => ))} - {!data.pages[0].hadMatchers &&
      } - {data.hasNextPage && data.pages[0].hadMatchers &&
      -
    ; -} - -function RouteComponent () -{ - const [search] = useSessionStorage(`${Route.to}-search`, undefined); - const [filter, setFilter] = useSessionStorage('store-download-lookup-filters', {}); - const { data, error, isPending, isFetching, isFetchingNextPage, fetchNextPage, hasNextPage } = useInfiniteQuery({ - ...downloadsLookupQuery({ ...filter, search }), - maxPages: 10, - refetchOnMount: false - }); - const { ref, focusKey } = useFocusable({ - focusKey: "main-area", - preferredChildFocusKey: "downloads-list" - }); - - const { data: lookupFilters } = useQuery(downloadLookupFiltersQuery); - - return
    - -
    - {isFetching && } - Results - {isPending ? : {data?.pages[0].totalCount}} -
    - {isPending && } - {data && } -
    - -
    - -
    -
    ; -} diff --git a/src/mainview/routes/store/tab/emulators.tsx b/src/mainview/routes/store/tab/emulators.tsx index 1fb831f..0d4ba0e 100644 --- a/src/mainview/routes/store/tab/emulators.tsx +++ b/src/mainview/routes/store/tab/emulators.tsx @@ -11,15 +11,10 @@ import { useQuery } from '@tanstack/react-query'; import { storeEmulatorsQuery } from '@queries/store'; import InvalidStoreError from '@/mainview/components/store/InvalidStoreError'; import { useSessionStorage } from 'usehooks-ts'; -import { zodValidator } from '@tanstack/zod-adapter'; -import z from 'zod'; export const Route = createFileRoute('/store/tab/emulators')({ component: RouteComponent, - errorComponent: InvalidStoreError, - validateSearch: zodValidator(z.object({ - search: z.string().optional() - })) + errorComponent: InvalidStoreError }); function RouteComponent () @@ -31,11 +26,7 @@ function RouteComponent () preferredChildFocusKey: focus }); const storeContext = useContext(StoreContext); - const { data: emulators } = useQuery({ - ...storeEmulatorsQuery({ search }), - retry: false, - throwOnError: true - }); + const { data: emulators } = useQuery({ ...storeEmulatorsQuery({ search }), retry: false, throwOnError: true }); useEffect(() => { @@ -71,7 +62,6 @@ function RouteComponent () /> )) ?? Array.from({ length: 10 }).map((_, i) =>
    )}
    - ; diff --git a/src/mainview/routes/store/tab/games.tsx b/src/mainview/routes/store/tab/games.tsx index 9176c20..c36b824 100644 --- a/src/mainview/routes/store/tab/games.tsx +++ b/src/mainview/routes/store/tab/games.tsx @@ -8,14 +8,13 @@ import LoadMoreButton from '@/mainview/components/LoadMoreButton'; import { storeGamesInfiniteQuery } from '@queries/store'; import InvalidStoreError from '@/mainview/components/store/InvalidStoreError'; import { CardList, GameMetaExtra } from '@/mainview/components/CardList'; -import { RPC_URL } from '@/shared/constants'; -import { GameListFilterType, FrontEndGameType } from '@simeonradivoev/gameflow-sdk/shared'; +import { GameListFilterType, RPC_URL } from '@/shared/constants'; import { useSessionStorage } from 'usehooks-ts'; import { zodValidator } from '@tanstack/zod-adapter'; import z from 'zod'; import SideFilters from '@/mainview/components/SideFilters'; import { gameFiltersQuery } from '@/mainview/scripts/queries/romm'; -import { isUrl } from '@/shared/utils'; +import { FrontEndGameType } from '@/shared/types'; export const Route = createFileRoute('/store/tab/games')({ component: RouteComponent, @@ -69,7 +68,7 @@ function RouteComponent () Games
    -
    +