From 4224ef45b33f6b489a9aa9d911fe5ec923968f07 Mon Sep 17 00:00:00 2001 From: Truman Gao <106889354+tdgao@users.noreply.github.com> Date: Tue, 31 Mar 2026 10:15:35 -0700 Subject: [PATCH] feat: add shared UI package auth DI (#5720) * feat: add shared UI package auth DI * use refs instead of reactive * pnpm prepr * move app auth provider setup to src/providers/setup --- apps/app-frontend/src/App.vue | 5 ++++ apps/app-frontend/src/providers/setup/auth.ts | 29 +++++++++++++++++++ apps/frontend/src/providers/setup.ts | 2 ++ apps/frontend/src/providers/setup/auth.ts | 29 +++++++++++++++++++ packages/ui/src/providers/auth.ts | 12 ++++++++ packages/ui/src/providers/index.ts | 1 + 6 files changed, 78 insertions(+) create mode 100644 apps/app-frontend/src/providers/setup/auth.ts create mode 100644 apps/frontend/src/providers/setup/auth.ts create mode 100644 packages/ui/src/providers/auth.ts diff --git a/apps/app-frontend/src/App.vue b/apps/app-frontend/src/App.vue index 63fbe35ed..6b1b964a1 100644 --- a/apps/app-frontend/src/App.vue +++ b/apps/app-frontend/src/App.vue @@ -106,6 +106,7 @@ import { } from '@/providers/download-progress.ts' import { createServerInstall, provideServerInstall } from '@/providers/server-install' import { setupProviders } from '@/providers/setup' +import { setupAuthProvider } from '@/providers/setup/auth' import { useError } from '@/store/error.js' import { useLoading, useTheming } from '@/store/state' @@ -454,6 +455,10 @@ const credentials = ref() const modrinthLoginFlowWaitModal = ref() +setupAuthProvider(credentials, async (_redirectPath) => { + await signIn() +}) + async function fetchCredentials() { const creds = await getCreds().catch(handleError) if (creds && creds.user_id) { diff --git a/apps/app-frontend/src/providers/setup/auth.ts b/apps/app-frontend/src/providers/setup/auth.ts new file mode 100644 index 000000000..bf522c59a --- /dev/null +++ b/apps/app-frontend/src/providers/setup/auth.ts @@ -0,0 +1,29 @@ +import type { Labrinth } from '@modrinth/api-client' +import { type AuthProvider, provideAuth } from '@modrinth/ui' +import { type Ref, ref, watchEffect } from 'vue' + +type AppCredentials = { + session?: string | null + user?: Labrinth.Users.v2.User | null +} + +export function setupAuthProvider( + credentials: Ref, + requestSignIn: (redirectPath: string) => void | Promise, +) { + const sessionToken = ref(null) + const user = ref(null) + + const authProvider: AuthProvider = { + session_token: sessionToken, + user, + requestSignIn, + } + + watchEffect(() => { + sessionToken.value = credentials.value?.session ?? null + user.value = credentials.value?.user ?? null + }) + + provideAuth(authProvider) +} diff --git a/apps/frontend/src/providers/setup.ts b/apps/frontend/src/providers/setup.ts index c558dc4c7..9b68c64e9 100644 --- a/apps/frontend/src/providers/setup.ts +++ b/apps/frontend/src/providers/setup.ts @@ -1,6 +1,7 @@ import { provideNotificationManager } from '@modrinth/ui' import { FrontendNotificationManager } from './frontend-notifications' +import { setupAuthProvider } from './setup/auth' import { setupFilePickerProvider } from './setup/file-picker' import { setupModrinthClientProvider } from './setup/modrinth-client' import { setupPageContextProvider } from './setup/page-context' @@ -9,6 +10,7 @@ import { setupTagsProvider } from './setup/tags' export function setupProviders(auth: Awaited>) { provideNotificationManager(new FrontendNotificationManager()) + setupAuthProvider(auth) setupModrinthClientProvider(auth) setupTagsProvider() setupFilePickerProvider() diff --git a/apps/frontend/src/providers/setup/auth.ts b/apps/frontend/src/providers/setup/auth.ts new file mode 100644 index 000000000..ae717324b --- /dev/null +++ b/apps/frontend/src/providers/setup/auth.ts @@ -0,0 +1,29 @@ +import type { Labrinth } from '@modrinth/api-client' +import { type AuthProvider, provideAuth } from '@modrinth/ui' +import { ref, watchEffect } from 'vue' + +export function setupAuthProvider(auth: Awaited>) { + const router = useRouter() + const sessionToken = ref(null) + const user = ref(null) + + const authProvider: AuthProvider = { + session_token: sessionToken, + user, + requestSignIn: async (redirectPath: string) => { + await router.push({ + path: '/auth/sign-in', + query: { + redirect: redirectPath, + }, + }) + }, + } + + watchEffect(() => { + sessionToken.value = auth.value.token || null + user.value = (auth.value.user as Labrinth.Users.v2.User | null) ?? null + }) + + provideAuth(authProvider) +} diff --git a/packages/ui/src/providers/auth.ts b/packages/ui/src/providers/auth.ts new file mode 100644 index 000000000..b5f68437a --- /dev/null +++ b/packages/ui/src/providers/auth.ts @@ -0,0 +1,12 @@ +import type { Labrinth } from '@modrinth/api-client/src/modules/labrinth/types' +import type { Ref } from 'vue' + +import { createContext } from './create-context' + +export interface AuthProvider { + session_token: Ref + user: Ref + requestSignIn: (redirectPath: string) => void | Promise +} + +export const [injectAuth, provideAuth] = createContext('root', 'auth') diff --git a/packages/ui/src/providers/index.ts b/packages/ui/src/providers/index.ts index 3eac3d13f..2c45450ba 100644 --- a/packages/ui/src/providers/index.ts +++ b/packages/ui/src/providers/index.ts @@ -1,5 +1,6 @@ export * from './api-client' export * from './app-backup' +export * from './auth' export * from './content-manager' export { createContext } from './create-context' export * from './file-picker'