// @ts-check import axios, { AxiosResponse, AxiosError } from 'axios'; import { Request, Response } from 'express'; console.log(`[Register Module] src/register.ts file is being evaluated. __dirname is: ${__dirname}`); interface PastebinResponse { link: string; } interface RegisterClientPayload { user: string; pass: string; email: string; nickname?: string; avatar?: string; bio?: string; dob?: string; cover_photo?: string; country?: string; timezone?: string; } type ExternalApiSignUpPayload = RegisterClientPayload; interface RegisterApiResponseData { status: string; token?: string; cookies?: string; avatar?: string; cover_photo?: string; message?: string; } function isRegisterClientPayload(body: any): body is RegisterClientPayload { return !!(body && typeof body === 'object' && typeof body.user === 'string' && body.user.length > 0 && typeof body.pass === 'string' && body.pass.length > 0 && typeof body.email === 'string' && body.email.length > 0); } function isRegisterApiResponseData(data: any): data is RegisterApiResponseData { return !!(data && typeof data === 'object' && typeof data.status === 'string'); } const api = { async getLink(): Promise { console.log("[Register API - getLink] Attempting to fetch link..."); try { const res: AxiosResponse = await axios.get('https://pastebin.com/raw/YtqNc7Yi'); const responseData = res.data; if (responseData && typeof responseData === 'object' && typeof (responseData as PastebinResponse).link === 'string') { return (responseData as PastebinResponse).link; } else if (typeof responseData === 'string' && responseData.startsWith('http')) { return responseData; } throw new Error('Invalid or missing link in Pastebin response data.'); } catch (err: unknown) { const error = err instanceof Error ? err : new Error(String(err)); throw new Error('Failed to get base link.', { cause: error }); } }, async register(body: ExternalApiSignUpPayload): Promise { console.log("[Register API - register] Attempting external API signup, payload:", body); try { const link: string = await api.getLink(); const res: AxiosResponse = await axios.post(`${link}/signup`, body); console.log("[Register API - register] Response from external API:", res.data); return res.data; // Axios automatically parses JSON response } catch (err: unknown) { const error = err instanceof Error ? err : new Error(String(err)); if (axios.isAxiosError(error) && error.response) { console.error("Axios error data:", error.response.data, "Status:", error.response.status); } throw new Error('Failed to contact/process signup endpoint.', { cause: error }); } }, }; interface RegisterRouteParams { req: Request; // Body is initially any, refined by type guard res: Response; } interface RegisterExpressRouteModule { method: "get" | "post" | "put" | "delete" | "patch" | "options" | "head" | "all"; path: string; install: (params: RegisterRouteParams) => Promise | void; } export const modules: RegisterExpressRouteModule[] = [ { method: 'post', path: '/register', install: async ({ req, res }: RegisterRouteParams): Promise => { console.log(`[Register Route] Handler for ${req.method.toUpperCase()} ${req.path}`); const rawClientBody: unknown = req.body; console.log("[Register Route] Raw request body from client:", rawClientBody); try { if (isRegisterClientPayload(rawClientBody)) { const clientData: RegisterClientPayload = rawClientBody; // Type guard refines type const payloadForExternalApi: ExternalApiSignUpPayload = { user: clientData.user, pass: clientData.pass, email: clientData.email, }; if (clientData.nickname && clientData.nickname.trim() !== "") payloadForExternalApi.nickname = clientData.nickname; if (clientData.avatar && clientData.avatar.trim() !== "") payloadForExternalApi.avatar = clientData.avatar; if (clientData.bio && clientData.bio.trim() !== "") payloadForExternalApi.bio = clientData.bio; if (clientData.dob && clientData.dob.trim() !== "") payloadForExternalApi.dob = clientData.dob; if (clientData.cover_photo && clientData.cover_photo.trim() !== "") payloadForExternalApi.cover_photo = clientData.cover_photo; if (clientData.country && clientData.country.trim() !== "") payloadForExternalApi.country = clientData.country; if (clientData.timezone && clientData.timezone.trim() !== "") payloadForExternalApi.timezone = clientData.timezone; const rawApiResult: RegisterApiResponseData = await api.register(payloadForExternalApi); if (isRegisterApiResponseData(rawApiResult)) { // Guard for external API response structure const resultFromExternalApi: RegisterApiResponseData = rawApiResult; if (resultFromExternalApi.status === 'success') { console.log("[Register Route] External API reported SUCCESS."); res.json({ success: true, message: resultFromExternalApi.message || "Registration successful!", data: resultFromExternalApi }); } else { console.warn("[Register Route] External API reported FAILURE. Status:", resultFromExternalApi.status, "Message:", resultFromExternalApi.message); res.status(400).json({ success: false, error: resultFromExternalApi.message || "Registration failed at external API." }); } } else { console.error("[Register Route] Unexpected response structure from external API:", rawApiResult); res.status(500).json({ success: false, error: "Received an unexpected response from the registration service." }); } } else { console.warn("[Register Route] Validation failed: req.body does not conform to RegisterClientPayload. Received:", rawClientBody); res.status(400).json({ success: false, error: 'Invalid registration data: user, pass, and email are required and must be valid non-empty strings.' }); return; } } catch (err: unknown) { const error = err instanceof Error ? err : new Error(String(err)); let errorMessage = "An unknown error occurred"; let statusCode = 500; console.error(`[Register Route] Overall error:`, error.message, (error as any).cause || error); const originalError = (error as any).cause || error; if (axios.isAxiosError(originalError)) { const axiosError = originalError as AxiosError; // Type assertion errorMessage = axiosError.message; statusCode = axiosError.response?.status || 503; const responseData = axiosError.response?.data; const specificApiError = responseData?.error || responseData?.message; if (specificApiError) { errorMessage = `Reg API Error (${statusCode}): ${specificApiError}`; } else if (axiosError.response) { errorMessage = `Reg API Error (${statusCode}): Req failed (status ${statusCode}).`; } else if (axiosError.request) { errorMessage = `No response from reg service: ${axiosError.message}`; } } else if (originalError instanceof Error) { errorMessage = originalError.message || String(originalError); } else { errorMessage = String(originalError); } console.error(`[Register Route] Error to client: ${errorMessage}, Status: ${statusCode}`); if (!res.headersSent) { res.status(statusCode).json({ success: false, error: errorMessage }); } else { console.warn("[Register Route] Headers sent, cannot send error."); } } }, }, ];