203 lines
5.1 KiB
TypeScript
203 lines
5.1 KiB
TypeScript
"use server";
|
|
import {
|
|
DEFAULT_RESPONSE,
|
|
defaultHeaders,
|
|
DEFAULT_TIMEOUT,
|
|
nextCrypto,
|
|
} from "./base";
|
|
import { FetchOptions, HttpMethod, ApiResponse } from "./types";
|
|
import { retrieveAccessToken } from "./mutual/cookies/token";
|
|
import { cookies } from "next/headers";
|
|
import { cookieObject } from "@/fetchers/base";
|
|
|
|
/**
|
|
* Retrieves user selection from cookies with graceful fallback
|
|
* @returns User selection object or default selection if not found
|
|
*/
|
|
const functionRetrieveUserSelection = async () => {
|
|
try {
|
|
const cookieStore = await cookies();
|
|
const encrpytUserSelection = cookieStore.get("eys-sel")?.value || "";
|
|
if (!encrpytUserSelection) {
|
|
return {
|
|
redisKey: "default",
|
|
uuid: "",
|
|
timestamp: new Date().toISOString(),
|
|
};
|
|
}
|
|
try {
|
|
const decrpytUserSelection = await nextCrypto.decrypt(
|
|
encrpytUserSelection
|
|
);
|
|
if (!decrpytUserSelection) {
|
|
return {
|
|
redisKey: "default",
|
|
uuid: "",
|
|
timestamp: new Date().toISOString(),
|
|
};
|
|
}
|
|
return JSON.parse(decrpytUserSelection);
|
|
} catch (decryptError) {
|
|
return {
|
|
redisKey: "default",
|
|
uuid: "",
|
|
timestamp: new Date().toISOString(),
|
|
};
|
|
}
|
|
} catch (error) {
|
|
return {
|
|
redisKey: "default",
|
|
uuid: "",
|
|
timestamp: new Date().toISOString(),
|
|
};
|
|
}
|
|
};
|
|
|
|
const functionSetUserSelection = async (userSelection: any) => {
|
|
const cookieStore = await cookies();
|
|
const encrpytUserSelection = await nextCrypto.encrypt(
|
|
JSON.stringify(userSelection)
|
|
);
|
|
if (!encrpytUserSelection) throw new Error("No user selection found");
|
|
cookieStore.set({
|
|
name: "eys-sel",
|
|
value: encrpytUserSelection,
|
|
...cookieObject,
|
|
} as any);
|
|
};
|
|
|
|
const functionRemoveUserSelection = async () => {
|
|
const cookieStore = await cookies();
|
|
cookieStore.delete("eys-sel");
|
|
};
|
|
|
|
/**
|
|
* Creates a promise that rejects after a specified timeout
|
|
* @param ms Timeout in milliseconds
|
|
* @param controller AbortController to abort the fetch request
|
|
* @returns A promise that rejects after the timeout
|
|
*/
|
|
const createTimeoutPromise = (
|
|
ms: number,
|
|
controller: AbortController
|
|
): Promise<never> => {
|
|
return new Promise((_, reject) => {
|
|
setTimeout(() => {
|
|
controller.abort();
|
|
reject(new Error(`Request timed out after ${ms}ms`));
|
|
}, ms);
|
|
});
|
|
};
|
|
|
|
/**
|
|
* Core fetch function with timeout and error handling
|
|
* @param url The URL to fetch
|
|
* @param options Fetch options
|
|
* @param headers Request headers
|
|
* @param payload Request payload
|
|
* @returns API response
|
|
*/
|
|
async function coreFetch<T>(
|
|
url: string,
|
|
options: FetchOptions = {},
|
|
headers: Record<string, string> = defaultHeaders,
|
|
payload?: any
|
|
): Promise<ApiResponse<T>> {
|
|
const { method = "POST", cache = false, timeout = DEFAULT_TIMEOUT } = options;
|
|
|
|
try {
|
|
const controller = new AbortController();
|
|
const fetchOptions: RequestInit = {
|
|
method,
|
|
headers,
|
|
cache: cache ? "force-cache" : "no-cache",
|
|
signal: controller.signal,
|
|
};
|
|
|
|
if (method !== "GET" && payload) {
|
|
fetchOptions.body = JSON.stringify(
|
|
payload.payload ? payload.payload : payload
|
|
);
|
|
}
|
|
const timeoutPromise = createTimeoutPromise(timeout, controller);
|
|
const response = await Promise.race([
|
|
fetch(url, fetchOptions),
|
|
timeoutPromise,
|
|
]);
|
|
const responseData = await response.json();
|
|
return {
|
|
status: response.status,
|
|
data: responseData || ({} as T),
|
|
};
|
|
} catch (error) {
|
|
console.error(`API Error (${url}):`, error);
|
|
return {
|
|
...DEFAULT_RESPONSE,
|
|
error: error instanceof Error ? error.message : "Network error",
|
|
} as ApiResponse<T>;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Fetch data without authentication
|
|
*/
|
|
async function fetchData<T>(
|
|
endpoint: string,
|
|
payload?: any,
|
|
method: HttpMethod = "POST",
|
|
cache: boolean = false,
|
|
timeout: number = DEFAULT_TIMEOUT
|
|
): Promise<ApiResponse<T>> {
|
|
return coreFetch<T>(
|
|
endpoint,
|
|
{ method, cache, timeout },
|
|
defaultHeaders,
|
|
payload
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Fetch data with authentication token
|
|
*/
|
|
async function fetchDataWithToken<T>(
|
|
endpoint: string,
|
|
payload?: any,
|
|
method: HttpMethod = "POST",
|
|
cache: boolean = false,
|
|
timeout: number = DEFAULT_TIMEOUT
|
|
): Promise<ApiResponse<T>> {
|
|
const accessToken = await retrieveAccessToken();
|
|
const headers = { ...defaultHeaders, "eys-acs-tkn": accessToken };
|
|
return coreFetch<T>(endpoint, { method, cache, timeout }, headers, payload);
|
|
}
|
|
|
|
/**
|
|
* Update data with authentication token and UUID
|
|
*/
|
|
async function updateDataWithToken<T>(
|
|
endpoint: string,
|
|
uuid: string,
|
|
payload?: any,
|
|
method: HttpMethod = "POST",
|
|
cache: boolean = false,
|
|
timeout: number = DEFAULT_TIMEOUT
|
|
): Promise<ApiResponse<T>> {
|
|
const accessToken = await retrieveAccessToken();
|
|
const headers = { ...defaultHeaders, "eys-acs-tkn": accessToken };
|
|
return coreFetch<T>(
|
|
`${endpoint}/${uuid}`,
|
|
{ method, cache, timeout },
|
|
headers,
|
|
payload
|
|
);
|
|
}
|
|
|
|
export {
|
|
fetchData,
|
|
fetchDataWithToken,
|
|
updateDataWithToken,
|
|
functionRetrieveUserSelection,
|
|
functionSetUserSelection,
|
|
functionRemoveUserSelection,
|
|
};
|