/** * Better-auth client factory for the auth-only SPA (`apps/ui-server-auth`). * * Separate from the stage-ui singleton because that client is Bearer-only: * it omits cookies and injects the auth-store token on every request, which * makes no sense on the page the session cookie was just set on. This client * uses better-auth's cookie defaults (`credentials: 'include'`) instead. * * Transport seam: pass `fetchImpl` to substitute `globalThis.fetch` (wired as * `customFetchImpl`; see node_modules/better-auth/dist/client/config.mjs L+ * — the `restOfFetchOptions` spread happens after the default, so a * user-supplied value wins). Test fetches and request-scoped abort signals * both bypass memoisation so state cannot leak into the next attempt; * ordinary production callers still memoise per `apiServerUrl`. * * Removal condition: better-auth ships a hosted typed client for OIDC IdP * setups where one process is both IdP and resource server. Until then, * one factory per credential mode is the cleanest contract. */ import { steamClient } from '@proj-airi/stage-ui/libs/steam-auth-client' import { createAuthClient } from 'better-auth/vue' export interface AuthClientArgs { apiServerUrl: string /** * Optional fetch override for tests. When provided we *do not* memoise so * every test case can install its own mock without bleed-through. */ fetchImpl?: typeof fetch /** * Optional signal for one request-scoped client. Supplying it disables * memoisation so a later sign-in attempt receives a fresh signal. */ requestSignal?: AbortSignal } type AuthClient = ReturnType[] }>> const clientCache = new Map() /** * Cookie-credentialed better-auth client for the auth UI, with the Steam * plugin wired in (`linkSteam` / `signIn.steam`). Unlike the Bearer-only * stage-ui singleton, this client carries the session cookie. */ export function getAuthClient(args: AuthClientArgs): AuthClient { if (args.fetchImpl || args.requestSignal) { return createAuthClient({ baseURL: args.apiServerUrl, plugins: [steamClient()], fetchOptions: { ...(args.fetchImpl ? { customFetchImpl: args.fetchImpl } : {}), ...(args.requestSignal ? { signal: args.requestSignal } : {}), }, }) } const client = clientCache.get(args.apiServerUrl) ?? createAuthClient({ baseURL: args.apiServerUrl, plugins: [steamClient()], }) clientCache.set(args.apiServerUrl, client) return client }