import { setUserMetadata, superTokensFunctionMiddleware, getSessionContext } from "@/utils/supertokens"; import { createServerFn } from "@tanstack/react-start"; import { Player, playerInputSchema, playerUpdateSchema, PlayerStats } from "@/features/players/types"; import { Match } from "@/features/matches/types"; import { pbAdmin } from "@/lib/pocketbase/client"; import { z } from "zod"; import { logger } from "."; import { getRequest } from "@tanstack/react-start/server"; import { toServerResult } from "@/lib/tanstack-query/utils/to-server-result"; import { serverFnLoggingMiddleware } from "@/utils/activities"; export const fetchMe = createServerFn() .handler(async () => toServerResult(async () => { const request = getRequest(); try { const context = await getSessionContext(request); await pbAdmin.authPromise; const result = await pbAdmin.getPlayerByAuthId(context.userAuthId); return { user: result || undefined, roles: context.roles, metadata: context.metadata, phone: context.phone }; } catch (error: any) { logger.info("FetchMe: Error caught", { message: error?.message, isResponse: error instanceof Response, status: error instanceof Response ? error.status : error?.response?.status }); if (error instanceof Response) { const status = error.status; if (status === 440) { logger.info("FetchMe: Session refresh required (440)"); throw error; } } if (error?.response?.status === 440 || error?.response?.status === 401) { const errorData = error?.response?.data; if (errorData?.error === "SESSION_REFRESH_REQUIRED") { logger.info("FetchMe: Session refresh required (legacy)"); throw error; } } if (error?.message === "Unauthenticated") { logger.info("FetchMe: No authenticated user (expected when not logged in)"); return { user: undefined, roles: [], metadata: {}, phone: undefined }; } logger.warn("FetchMe: Unexpected error, returning default", error); return { user: undefined, roles: [], metadata: {}, phone: undefined }; } }) ); export const getPlayer = createServerFn() .inputValidator(z.string()) .middleware([superTokensFunctionMiddleware]) .handler(async ({ data }) => toServerResult(async () => await pbAdmin.getPlayer(data)) ); export const updatePlayer = createServerFn() .inputValidator(playerUpdateSchema) .middleware([superTokensFunctionMiddleware, serverFnLoggingMiddleware]) .handler(async ({ context, data }) => toServerResult(async () => { const userAuthId = context.userAuthId; if (!userAuthId) return; const existing = await pbAdmin.getPlayerByAuthId(userAuthId); if (!existing) return; const updatedPlayer = await pbAdmin.updatePlayer( existing.id!, { first_name: data.first_name, last_name: data.last_name } ); logger.info('Updated player name', updatedPlayer); await setUserMetadata({ data: { first_name: data.first_name, last_name: data.last_name } }); return updatedPlayer; }) ); export const createPlayer = createServerFn() .inputValidator(playerInputSchema) .middleware([superTokensFunctionMiddleware]) .handler(async ({ context, data }) => toServerResult(async () => { const userAuthId = context.userAuthId; if (!userAuthId) return; const existing = await pbAdmin.getPlayerByAuthId(userAuthId); if (existing) return; logger.info('Creating player', data, userAuthId); const newPlayer = await pbAdmin.createPlayer({ auth_id: userAuthId, first_name: data.first_name, last_name: data.last_name }); await setUserMetadata({ data: { first_name: data.first_name, last_name: data.last_name, player_id: newPlayer?.id?.toString() } }); logger.info('Created player', newPlayer); return newPlayer; }) ); export const associatePlayer = createServerFn() .inputValidator(z.string()) .middleware([superTokensFunctionMiddleware, serverFnLoggingMiddleware]) .handler(async ({ context, data }) => toServerResult(async () => { const userAuthId = context.userAuthId; if (!userAuthId) return; const p = await pbAdmin.getPlayer(data); await pbAdmin.updatePlayer(data, { auth_id: userAuthId }); await setUserMetadata({ data: { player_id: data, first_name: p?.first_name, last_name: p?.last_name }}); const player = await pbAdmin.getPlayer(data); logger.info('Associated player', player); return player; }) ); export const listPlayers = createServerFn() .middleware([superTokensFunctionMiddleware]) .handler(async () => toServerResult(pbAdmin.listPlayers) ); export const getUnassociatedPlayers = createServerFn() .middleware([superTokensFunctionMiddleware]) .handler(async () => toServerResult(pbAdmin.getUnassociatedPlayers) ); export const getPlayerStats = createServerFn() .inputValidator(z.object({ playerId: z.string(), viewType: z.enum(['all', 'mainline', 'regional']).optional() })) .middleware([superTokensFunctionMiddleware]) .handler(async ({ data }) => toServerResult(async () => await pbAdmin.getPlayerStats(data.playerId, data.viewType)) ); export const getAllPlayerStats = createServerFn() .inputValidator(z.enum(['all', 'mainline', 'regional']).optional()) .middleware([superTokensFunctionMiddleware]) .handler(async ({ data }) => toServerResult(async () => await pbAdmin.getAllPlayerStats(data)) ); export const getPlayerMatches = createServerFn() .inputValidator(z.string()) .middleware([superTokensFunctionMiddleware]) .handler(async ({ data }) => toServerResult(async () => await pbAdmin.getPlayerMatches(data)) ); export const getUnenrolledPlayers = createServerFn() .inputValidator(z.string()) .middleware([superTokensFunctionMiddleware]) .handler(async ({ data: tournamentId }) => toServerResult(async () => await pbAdmin.getUnenrolledPlayers(tournamentId)) ); export const getPlayersActivity = createServerFn() .middleware([superTokensFunctionMiddleware]) .handler(async () => toServerResult(async () => await pbAdmin.getPlayersActivity()) );