diff --git a/.cargo/config.toml b/.cargo/config.toml index 7115f0015..085f3158f 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -2,5 +2,8 @@ [target.'cfg(windows)'] rustflags = ["-C", "link-args=/STACK:16777220", "--cfg", "tokio_unstable"] +[target.x86_64-pc-windows-msvc] +linker = "rust-lld" + [build] rustflags = ["--cfg", "tokio_unstable"] diff --git a/.github/workflows/daedalus-docker.yml b/.github/workflows/daedalus-docker.yml index 0dda82541..b0f72c964 100644 --- a/.github/workflows/daedalus-docker.yml +++ b/.github/workflows/daedalus-docker.yml @@ -22,23 +22,26 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v4 + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v2 - name: Fetch docker metadata id: docker_meta - uses: docker/metadata-action@v3 + uses: docker/metadata-action@v5 with: images: ghcr.io/modrinth/daedalus - name: Login to GitHub Images - uses: docker/login-action@v1 + uses: docker/login-action@v3 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - name: Build and push - id: docker_build - uses: docker/build-push-action@v2 + uses: docker/build-push-action@v6 with: file: ./apps/daedalus_client/Dockerfile push: ${{ github.event_name != 'pull_request' }} tags: ${{ steps.docker_meta.outputs.tags }} labels: ${{ steps.docker_meta.outputs.labels }} + cache-from: type=registry,ref=ghcr.io/modrinth/daedalus:main + cache-to: type=inline diff --git a/.github/workflows/labrinth-docker.yml b/.github/workflows/labrinth-docker.yml index 114c8ee48..43577e662 100644 --- a/.github/workflows/labrinth-docker.yml +++ b/.github/workflows/labrinth-docker.yml @@ -20,23 +20,26 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v4 + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v2 - name: Fetch docker metadata id: docker_meta - uses: docker/metadata-action@v3 + uses: docker/metadata-action@v5 with: images: ghcr.io/modrinth/labrinth - name: Login to GitHub Images - uses: docker/login-action@v1 + uses: docker/login-action@v3 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - name: Build and push - id: docker_build - uses: docker/build-push-action@v2 + uses: docker/build-push-action@v6 with: file: ./apps/labrinth/Dockerfile push: ${{ github.event_name != 'pull_request' }} tags: ${{ steps.docker_meta.outputs.tags }} labels: ${{ steps.docker_meta.outputs.labels }} + cache-from: type=registry,ref=ghcr.io/modrinth/labrinth:main + cache-to: type=inline diff --git a/.github/workflows/theseus-build.yml b/.github/workflows/theseus-build.yml index 76ae5f900..64ae2b334 100644 --- a/.github/workflows/theseus-build.yml +++ b/.github/workflows/theseus-build.yml @@ -75,7 +75,7 @@ jobs: rename-to: ${{ startsWith(matrix.platform, 'windows') && 'dasel.exe' || 'dasel' }} chmod: 0755 - - name: โš™๏ธ Set application version + - name: โš™๏ธ Set application version and environment shell: bash run: | APP_VERSION="$(git describe --tags --always | sed -E 's/-([0-9]+)-(g[0-9a-fA-F]+)$/-canary+\1.\2/')" @@ -84,6 +84,8 @@ jobs: dasel put -f packages/app-lib/Cargo.toml -t string -v "${APP_VERSION#v}" 'package.version' dasel put -f apps/app-frontend/package.json -t string -v "${APP_VERSION#v}" 'version' + cp packages/app-lib/.env.prod packages/app-lib/.env + - name: ๐Ÿ’จ Setup Turbo cache uses: rharkor/caching-for-turbo@v1.8 diff --git a/.github/workflows/turbo-ci.yml b/.github/workflows/turbo-ci.yml index 6f82db1b2..fda114e5e 100644 --- a/.github/workflows/turbo-ci.yml +++ b/.github/workflows/turbo-ci.yml @@ -52,7 +52,7 @@ jobs: # cargo-binstall does not have pre-built binaries for sqlx-cli, so we fall # back to a cached cargo install - name: ๐Ÿงฐ Setup cargo-sqlx - uses: AlexTMjugador/cache-cargo-install-action@feat/features-support + uses: taiki-e/cache-cargo-install-action@v2 with: tool: sqlx-cli locked: false @@ -74,10 +74,14 @@ jobs: cp .env.local .env sqlx database setup + - name: โš™๏ธ Set app environment + working-directory: packages/app-lib + run: cp .env.staging .env + - name: ๐Ÿ” Lint and test run: pnpm run ci - name: ๐Ÿ” Verify intl:extract has been run run: | pnpm intl:extract - git diff --exit-code */*/src/locales/en-US/index.json + git diff --exit-code --color */*/src/locales/en-US/index.json diff --git a/Cargo.lock b/Cargo.lock index f6519c3b1..66073b932 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5731,6 +5731,17 @@ dependencies = [ "phf_shared 0.11.3", ] +[[package]] +name = "phf" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "913273894cec178f401a31ec4b656318d95473527be05c0752cc41cdc32be8b7" +dependencies = [ + "phf_macros 0.12.1", + "phf_shared 0.12.1", + "serde", +] + [[package]] name = "phf_codegen" version = "0.8.0" @@ -5781,6 +5792,16 @@ dependencies = [ "rand 0.8.5", ] +[[package]] +name = "phf_generator" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2cbb1126afed61dd6368748dae63b1ee7dc480191c6262a3b4ff1e29d86a6c5b" +dependencies = [ + "fastrand 2.3.0", + "phf_shared 0.12.1", +] + [[package]] name = "phf_macros" version = "0.10.0" @@ -5808,6 +5829,19 @@ dependencies = [ "syn 2.0.101", ] +[[package]] +name = "phf_macros" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d713258393a82f091ead52047ca779d37e5766226d009de21696c4e667044368" +dependencies = [ + "phf_generator 0.12.1", + "phf_shared 0.12.1", + "proc-macro2", + "quote", + "syn 2.0.101", +] + [[package]] name = "phf_shared" version = "0.8.0" @@ -5835,6 +5869,15 @@ dependencies = [ "siphasher 1.0.1", ] +[[package]] +name = "phf_shared" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06005508882fb681fd97892ecff4b7fd0fee13ef1aa569f8695dae7ab9099981" +dependencies = [ + "siphasher 1.0.1", +] + [[package]] name = "pin-project" version = "1.1.10" @@ -8930,6 +8973,7 @@ dependencies = [ "data-url", "dirs", "discord-rich-presence", + "dotenvy", "dunce", "either", "encoding_rs", @@ -8945,6 +8989,7 @@ dependencies = [ "notify-debouncer-mini", "p256", "paste", + "phf 0.12.1", "png", "quartz_nbt", "quick-xml 0.37.5", @@ -8984,6 +9029,8 @@ dependencies = [ "dashmap", "either", "enumset", + "hyper 1.6.0", + "hyper-util", "native-dialog", "paste", "serde", diff --git a/Cargo.toml b/Cargo.toml index d95e9b601..b3c0bfa71 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -67,6 +67,7 @@ heck = "0.5.0" hex = "0.4.3" hickory-resolver = "0.25.2" hmac = "0.12.1" +hyper = "1.6.0" hyper-rustls = { version = "0.27.7", default-features = false, features = [ "http1", "native-tokio", @@ -98,6 +99,7 @@ notify = { version = "8.0.0", default-features = false } notify-debouncer-mini = { version = "0.6.0", default-features = false } p256 = "0.13.2" paste = "1.0.15" +phf = { version = "0.12.1", features = ["macros"] } png = "0.17.16" prometheus = "0.14.0" quartz_nbt = "0.2.9" diff --git a/apps/app-frontend/src/App.vue b/apps/app-frontend/src/App.vue index 1bc25942c..abfabdf52 100644 --- a/apps/app-frontend/src/App.vue +++ b/apps/app-frontend/src/App.vue @@ -61,9 +61,10 @@ import { renderString } from '@modrinth/utils' import { useFetch } from '@/helpers/fetch.js' import { check } from '@tauri-apps/plugin-updater' import NavButton from '@/components/ui/NavButton.vue' -import { get as getCreds, login, logout } from '@/helpers/mr_auth.js' +import { cancelLogin, get as getCreds, login, logout } from '@/helpers/mr_auth.js' import { get_user } from '@/helpers/cache.js' import AppSettingsModal from '@/components/ui/modal/AppSettingsModal.vue' +import AuthGrantFlowWaitModal from '@/components/ui/modal/AuthGrantFlowWaitModal.vue' import PromotionWrapper from '@/components/ui/PromotionWrapper.vue' import { hide_ads_window, init_ads_window } from '@/helpers/ads.js' import FriendsList from '@/components/ui/friends/FriendsList.vue' @@ -263,6 +264,8 @@ const incompatibilityWarningModal = ref() const credentials = ref() +const modrinthLoginFlowWaitModal = ref() + async function fetchCredentials() { const creds = await getCreds().catch(handleError) if (creds && creds.user_id) { @@ -272,8 +275,24 @@ async function fetchCredentials() { } async function signIn() { - await login().catch(handleError) - await fetchCredentials() + modrinthLoginFlowWaitModal.value.show() + + try { + await login() + await fetchCredentials() + } catch (error) { + if ( + typeof error === 'object' && + typeof error['message'] === 'string' && + error.message.includes('Login canceled') + ) { + // Not really an error due to being a result of user interaction, show nothing + } else { + handleError(error) + } + } finally { + modrinthLoginFlowWaitModal.value.hide() + } } async function logOut() { @@ -402,6 +421,9 @@ function handleAuxClick(e) { + + + diff --git a/apps/app-frontend/src/components/ui/InstanceCreationModal.vue b/apps/app-frontend/src/components/ui/InstanceCreationModal.vue index c09255a7c..ee6328ff0 100644 --- a/apps/app-frontend/src/components/ui/InstanceCreationModal.vue +++ b/apps/app-frontend/src/components/ui/InstanceCreationModal.vue @@ -305,12 +305,16 @@ const [ get_game_versions().then(shallowRef).catch(handleError), get_loaders() .then((value) => - value - .filter((item) => item.supported_project_types.includes('modpack')) - .map((item) => item.name.toLowerCase()), + ref( + value + .filter((item) => item.supported_project_types.includes('modpack')) + .map((item) => item.name.toLowerCase()), + ), ) - .then(ref) - .catch(handleError), + .catch((err) => { + handleError(err) + return ref([]) + }), ]) loaders.value.unshift('vanilla') diff --git a/apps/app-frontend/src/components/ui/modal/AuthGrantFlowWaitModal.vue b/apps/app-frontend/src/components/ui/modal/AuthGrantFlowWaitModal.vue new file mode 100644 index 000000000..3f169faff --- /dev/null +++ b/apps/app-frontend/src/components/ui/modal/AuthGrantFlowWaitModal.vue @@ -0,0 +1,42 @@ + + diff --git a/apps/app-frontend/src/components/ui/skin/EditSkinModal.vue b/apps/app-frontend/src/components/ui/skin/EditSkinModal.vue index de0ae7132..06b45fd1d 100644 --- a/apps/app-frontend/src/components/ui/skin/EditSkinModal.vue +++ b/apps/app-frontend/src/components/ui/skin/EditSkinModal.vue @@ -118,6 +118,7 @@ import { type Cape, type SkinModel, get_normalized_skin_texture, + determineModelType, } from '@/helpers/skins.ts' import { handleError } from '@/store/notifications' import { @@ -253,7 +254,7 @@ async function showNew(e: MouseEvent, skinTextureUrl: string) { mode.value = 'new' currentSkin.value = null uploadedTextureUrl.value = skinTextureUrl - variant.value = 'CLASSIC' + variant.value = await determineModelType(skinTextureUrl) selectedCape.value = undefined visibleCapeList.value = [] initVisibleCapeList() diff --git a/apps/app-frontend/src/components/ui/world/RecentWorldsList.vue b/apps/app-frontend/src/components/ui/world/RecentWorldsList.vue index a960f805f..5f80a194f 100644 --- a/apps/app-frontend/src/components/ui/world/RecentWorldsList.vue +++ b/apps/app-frontend/src/components/ui/world/RecentWorldsList.vue @@ -1,5 +1,6 @@ diff --git a/apps/app/src/api/oauth_utils/mod.rs b/apps/app/src/api/oauth_utils/mod.rs new file mode 100644 index 000000000..4182cfb6c --- /dev/null +++ b/apps/app/src/api/oauth_utils/mod.rs @@ -0,0 +1,3 @@ +//! Assorted utilities for OAuth 2.0 authorization flows. + +pub mod auth_code_reply; diff --git a/apps/app/src/api/worlds.rs b/apps/app/src/api/worlds.rs index 544ce05d6..103ecdf38 100644 --- a/apps/app/src/api/worlds.rs +++ b/apps/app/src/api/worlds.rs @@ -5,8 +5,8 @@ use tauri::{AppHandle, Manager, Runtime}; use theseus::prelude::ProcessMetadata; use theseus::profile::{QuickPlayType, get_full_path}; use theseus::worlds::{ - DisplayStatus, ServerPackStatus, ServerStatus, World, WorldType, - WorldWithProfile, + DisplayStatus, ProtocolVersion, ServerPackStatus, ServerStatus, World, + WorldType, WorldWithProfile, }; use theseus::{profile, worlds}; @@ -183,14 +183,16 @@ pub async fn remove_server_from_profile( } #[tauri::command] -pub async fn get_profile_protocol_version(path: &str) -> Result> { +pub async fn get_profile_protocol_version( + path: &str, +) -> Result> { Ok(worlds::get_profile_protocol_version(path).await?) } #[tauri::command] pub async fn get_server_status( address: &str, - protocol_version: Option, + protocol_version: Option, ) -> Result { Ok(worlds::get_server_status(address, protocol_version).await?) } diff --git a/apps/app/tauri.conf.json b/apps/app/tauri.conf.json index 724e536d8..8667de5c6 100644 --- a/apps/app/tauri.conf.json +++ b/apps/app/tauri.conf.json @@ -63,6 +63,7 @@ "height": 800, "resizable": true, "title": "Modrinth App", + "label": "main", "width": 1280, "minHeight": 700, "minWidth": 1100, diff --git a/apps/daedalus_client/Dockerfile b/apps/daedalus_client/Dockerfile index 9ea70f9ca..271c829aa 100644 --- a/apps/daedalus_client/Dockerfile +++ b/apps/daedalus_client/Dockerfile @@ -1,9 +1,19 @@ +# syntax=docker/dockerfile:1 + FROM rust:1.88.0 AS build WORKDIR /usr/src/daedalus COPY . . -RUN cargo build --release --package daedalus_client +RUN --mount=type=cache,target=/usr/src/daedalus/target \ + --mount=type=cache,target=/usr/local/cargo/git/db \ + --mount=type=cache,target=/usr/local/cargo/registry \ + cargo build --release --package daedalus_client +FROM build AS artifacts + +RUN --mount=type=cache,target=/usr/src/daedalus/target \ + mkdir /daedalus \ + && cp /usr/src/daedalus/target/release/daedalus_client /daedalus/daedalus_client FROM debian:bookworm-slim @@ -11,7 +21,7 @@ RUN apt-get update \ && apt-get install -y --no-install-recommends ca-certificates openssl \ && rm -rf /var/lib/apt/lists/* -COPY --from=build /usr/src/daedalus/target/release/daedalus_client /daedalus/daedalus_client -WORKDIR /daedalus_client +COPY --from=artifacts /daedalus /daedalus -CMD /daedalus/daedalus_client +WORKDIR /daedalus_client +CMD ["/daedalus/daedalus_client"] diff --git a/apps/frontend/package.json b/apps/frontend/package.json index 7cded8314..011eafb64 100644 --- a/apps/frontend/package.json +++ b/apps/frontend/package.json @@ -59,10 +59,12 @@ "markdown-it": "14.1.0", "pathe": "^1.1.2", "pinia": "^2.1.7", + "pinia-plugin-persistedstate": "^4.4.1", "prettier": "^3.6.2", "qrcode.vue": "^3.4.0", "semver": "^7.5.4", "three": "^0.172.0", + "vue-confetti-explosion": "^1.0.2", "vue-multiselect": "3.0.0-alpha.2", "vue-typed-virtual-list": "^1.0.10", "vue3-ace-editor": "^2.2.4", diff --git a/apps/frontend/src/components/ui/ModerationChecklist.vue b/apps/frontend/src/components/ui/ModerationChecklist.vue deleted file mode 100644 index b21fd9954..000000000 --- a/apps/frontend/src/components/ui/ModerationChecklist.vue +++ /dev/null @@ -1,1133 +0,0 @@ - - - - - diff --git a/apps/frontend/src/components/ui/NewsletterButton.vue b/apps/frontend/src/components/ui/NewsletterButton.vue index 61778eaa0..43d59b76a 100644 --- a/apps/frontend/src/components/ui/NewsletterButton.vue +++ b/apps/frontend/src/components/ui/NewsletterButton.vue @@ -1,29 +1,28 @@ diff --git a/apps/frontend/src/pages/moderation/technical-review-mockup.vue b/apps/frontend/src/pages/moderation/technical-review-mockup.vue new file mode 100644 index 000000000..f18897fc6 --- /dev/null +++ b/apps/frontend/src/pages/moderation/technical-review-mockup.vue @@ -0,0 +1,386 @@ + + + diff --git a/apps/frontend/src/pages/moderation/technical-review.vue b/apps/frontend/src/pages/moderation/technical-review.vue new file mode 100644 index 000000000..40f28feca --- /dev/null +++ b/apps/frontend/src/pages/moderation/technical-review.vue @@ -0,0 +1,3 @@ + diff --git a/apps/frontend/src/pages/servers/index.vue b/apps/frontend/src/pages/servers/index.vue index 60495d150..2ac52cbe8 100644 --- a/apps/frontend/src/pages/servers/index.vue +++ b/apps/frontend/src/pages/servers/index.vue @@ -45,8 +45,9 @@

- Modrinth Servers is the easiest way to host your own Minecraft server. Seamlessly install - and play your favorite mods and modpacks, all within the Modrinth platform. + Modrinth Servers is the easiest way to host your own Minecraft: Java Edition server. + Seamlessly install and play your favorite mods and modpacks, all within the Modrinth + platform.

- Yes. All Modrinth Servers come with DDoS protection powered by - OVHcloudยฎ Anti-DDoS infrastructure - which has over 17Tbps capacity. Your server is safe on Modrinth. + Yes. All Modrinth Servers come with DDoS protection, with up to 17Tbps capacity in + some locations.

@@ -443,8 +441,9 @@ Where are Modrinth Servers located? Can I choose a region?

- We have servers in both North America in Vint Hill, Virginia, and Europe in Limburg, - Germany. More regions to come in the future! + We have servers available in North America and Europe at the moment that you can + choose upon purchase. More regions to come in the future! If you'd like to switch + your region, please contact support.

@@ -461,7 +460,7 @@

-
+
@@ -482,7 +481,7 @@

-
+
@@ -493,6 +492,24 @@ All prices are listed in United States Dollars (USD).

+ +
+ + + + + What Minecraft versions and loaders can be used? + +

+ Modrinth Servers can run any version of Minecraft: Java Edition going all the way + back to version 1.2.5, including snapshot versions. +

+

+ We also support a wide range of mod and plugin loaders, including Fabric, Quilt, + Forge, and NeoForge for mods, as well as Paper and Purpur for plugins. Availability + depends on whether the mod or plugin loader supports the selected Minecraft version. +

+
diff --git a/apps/frontend/src/pages/servers/manage/[id]/options/startup.vue b/apps/frontend/src/pages/servers/manage/[id]/options/startup.vue index bd9a7edd4..7080f0e1c 100644 --- a/apps/frontend/src/pages/servers/manage/[id]/options/startup.vue +++ b/apps/frontend/src/pages/servers/manage/[id]/options/startup.vue @@ -42,7 +42,7 @@