import { TRPCError } from "@trpc/server" import { cookies } from "next/headers" import { v4 as uuidv4 } from "uuid" import { z } from "zod" import { env } from "@/env/server" import { protectedProcedure } from "@/server/trpc" import { getSasToken } from "../../getSasToken" import { SAS_REQUEST_OTP_STATE_STORAGE_COOKIE_NAME } from "../constants" import { parseSASRequestOtpError, type RequestOtpGeneralError, } from "./requestOtpError" import type { OtpState } from "../getOTPState" const inputSchema = z.object({}) const outputSchema = z.object({ status: z.string(), referenceId: z.string().uuid(), databaseUUID: z.string().uuid(), otpExpiration: z.number(), otpReceiver: z.string(), }) export const requestOtp = protectedProcedure .input(inputSchema) .output(outputSchema) .mutation(async function ({ ctx, input }) { const sasAuthToken = getSasToken() if (!sasAuthToken) { // TODO: Should we verify that the SAS token isn't expired? throw createError("AUTH_TOKEN_NOT_FOUND") } const tokenResponse = await fetchRequestOtp({ sasAuthToken }) console.log( "[SAS] requestOtp", tokenResponse.status, tokenResponse.statusText ) if (!tokenResponse.ok) { const errorBody = await tokenResponse.json() console.error("[SAS] requestOtp error", errorBody) throw createError(errorBody) } const parseResult = outputSchema.safeParse(await tokenResponse.json()) if (!parseResult.success) { throw createError(parseResult.error) } setSASOtpCookie(parseResult.data) return parseResult.data }) function createError( errorBody: | { status: string error: string errorCode: number databaseUUID: string } | Error | RequestOtpGeneralError ): TRPCError { const errorInfo = parseSASRequestOtpError(errorBody) console.error("[SAS] createError", errorInfo) return new TRPCError({ code: "BAD_REQUEST", cause: errorInfo, }) } async function fetchRequestOtp({ sasAuthToken }: { sasAuthToken: string }) { const endpoint = `${env.SAS_API_ENDPOINT}/api/scandic-partnership/customer/send-otp` console.log("[SAS]: Requesting OTP") return await fetch(endpoint, { method: "POST", headers: { "Content-Type": "application/json", "Ocp-Apim-Subscription-Key": env.SAS_OCP_APIM, Authorization: `Bearer ${sasAuthToken}`, }, body: JSON.stringify({ referenceId: uuidv4(), }), }) } function setSASOtpCookie({ referenceId, databaseUUID, }: { referenceId: string databaseUUID: string }) { cookies().set( SAS_REQUEST_OTP_STATE_STORAGE_COOKIE_NAME, JSON.stringify({ referenceId: referenceId, databaseUUID: databaseUUID, } satisfies OtpState), { httpOnly: true, maxAge: 3600, } ) }