updated fetchers
This commit is contained in:
parent
f8184246d9
commit
a8ff968962
|
|
@ -0,0 +1,38 @@
|
||||||
|
import { ApiResponse, CookieObject } from "./types";
|
||||||
|
import NextCrypto from "next-crypto";
|
||||||
|
|
||||||
|
const tokenSecretEnv = process.env.TOKENSECRET_90;
|
||||||
|
const tokenSecret = tokenSecretEnv || "e781d1b0-9418-40b3-9940-385abf81a0b7";
|
||||||
|
const nextCrypto = new NextCrypto(tokenSecret);
|
||||||
|
|
||||||
|
const cookieObject: CookieObject = {
|
||||||
|
httpOnly: true,
|
||||||
|
path: "/",
|
||||||
|
sameSite: "none",
|
||||||
|
secure: true,
|
||||||
|
maxAge: 3600,
|
||||||
|
priority: "high",
|
||||||
|
};
|
||||||
|
|
||||||
|
const DEFAULT_TIMEOUT: number = 10000; // 10 seconds
|
||||||
|
const defaultHeaders: Record<string, string> = {
|
||||||
|
accept: "application/json",
|
||||||
|
language: "tr",
|
||||||
|
domain: "evyos.com.tr",
|
||||||
|
tz: "GMT+3",
|
||||||
|
"Content-type": "application/json",
|
||||||
|
};
|
||||||
|
const DEFAULT_RESPONSE: ApiResponse = {
|
||||||
|
error: "Hata tipi belirtilmedi",
|
||||||
|
status: 500,
|
||||||
|
data: {},
|
||||||
|
};
|
||||||
|
|
||||||
|
export {
|
||||||
|
DEFAULT_TIMEOUT,
|
||||||
|
DEFAULT_RESPONSE,
|
||||||
|
defaultHeaders,
|
||||||
|
tokenSecret,
|
||||||
|
cookieObject,
|
||||||
|
nextCrypto,
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,127 @@
|
||||||
|
"use server";
|
||||||
|
import { DEFAULT_RESPONSE, defaultHeaders, DEFAULT_TIMEOUT } from "./base";
|
||||||
|
import { FetchOptions, HttpMethod, ApiResponse } from "./types";
|
||||||
|
import { retrieveAccessToken } from "./mutual/cookies/token";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 };
|
||||||
|
|
@ -0,0 +1,36 @@
|
||||||
|
import { formatServiceUrl } from "./utils";
|
||||||
|
|
||||||
|
const baseUrlAuth = formatServiceUrl(
|
||||||
|
process.env.NEXT_PUBLIC_AUTH_SERVICE_URL || "auth_service:8001"
|
||||||
|
);
|
||||||
|
const baseUrlRestriction = formatServiceUrl(
|
||||||
|
process.env.NEXT_PUBLIC_RESTRICTION_SERVICE_URL || "restriction_service:8002"
|
||||||
|
);
|
||||||
|
const baseUrlApplication = formatServiceUrl(
|
||||||
|
process.env.NEXT_PUBLIC_MANAGEMENT_SERVICE_URL || "management_service:8003"
|
||||||
|
);
|
||||||
|
const baseUrlAccount = formatServiceUrl(
|
||||||
|
process.env.NEXT_PUBLIC_ACCOUNT_SERVICE_URL || "account_service:8004"
|
||||||
|
);
|
||||||
|
const baseUrlBuilding = formatServiceUrl(
|
||||||
|
process.env.NEXT_PUBLIC_BUILDING_SERVICE_URL || "building_service:8006"
|
||||||
|
);
|
||||||
|
const baseUrlPeople = formatServiceUrl(
|
||||||
|
process.env.NEXT_PUBLIC_VALIDATION_SERVICE_URL || "validation_service:8009"
|
||||||
|
);
|
||||||
|
|
||||||
|
const urlCheckToken = `${baseUrlAuth}/authentication/token/check`;
|
||||||
|
const urlPageValid = `${baseUrlRestriction}/restrictions/page/valid`;
|
||||||
|
const urlSiteUrls = `${baseUrlRestriction}/restrictions/sites/list`;
|
||||||
|
|
||||||
|
export {
|
||||||
|
baseUrlAuth,
|
||||||
|
baseUrlPeople,
|
||||||
|
baseUrlApplication,
|
||||||
|
baseUrlAccount,
|
||||||
|
baseUrlBuilding,
|
||||||
|
baseUrlRestriction,
|
||||||
|
urlCheckToken,
|
||||||
|
urlPageValid,
|
||||||
|
urlSiteUrls,
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
'use server';
|
||||||
|
import { cookies } from "next/headers";
|
||||||
|
import { cookieObject } from "@/fetchers/base";
|
||||||
|
import { ResponseCookie } from "next/dist/compiled/@edge-runtime/cookies";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Server action to delete all access cookies at once
|
||||||
|
* This is a direct server action that can be called from server components
|
||||||
|
*/
|
||||||
|
export async function deleteAllCookies() {
|
||||||
|
try {
|
||||||
|
const cookieStore = await cookies();
|
||||||
|
if (cookieStore.has("eys-zzz")) { cookieStore.delete({ name: "eys-zzz", ...cookieObject } as ResponseCookie); }
|
||||||
|
if (cookieStore.has("eys-yyy")) { cookieStore.delete({ name: "eys-yyy", ...cookieObject } as ResponseCookie); }
|
||||||
|
if (cookieStore.has("eys-sel")) { cookieStore.delete({ name: "eys-sel", ...cookieObject } as ResponseCookie); }
|
||||||
|
return true;
|
||||||
|
} catch (error) { console.error("Error in deleteAllCookies:", error); return false }
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,49 @@
|
||||||
|
import { cookies } from "next/headers";
|
||||||
|
import { fetchDataWithToken } from "@/fetchers/fecther";
|
||||||
|
import { urlCheckToken, urlPageValid, urlSiteUrls } from "@/fetchers/index";
|
||||||
|
import { nextCrypto } from "@/fetchers/base";
|
||||||
|
import { AuthError } from "@/validations/mutual/context/validations";
|
||||||
|
import { fetchResponseStatus } from "@/fetchers/utils";
|
||||||
|
|
||||||
|
async function checkAccessTokenIsValid() {
|
||||||
|
try {
|
||||||
|
const response = await fetchDataWithToken(urlCheckToken, {}, "GET", false);
|
||||||
|
return fetchResponseStatus(response);
|
||||||
|
} catch (error) { throw new AuthError("No access token found") }
|
||||||
|
}
|
||||||
|
|
||||||
|
async function retrievePageList() {
|
||||||
|
const response: any = await fetchDataWithToken(urlSiteUrls, {}, "GET", false);
|
||||||
|
return fetchResponseStatus(response) ? response.data?.sites : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function retrieveApplicationbyUrl(pageUrl: string) {
|
||||||
|
const response: any = await fetchDataWithToken(urlPageValid, { page_url: pageUrl }, "POST", false);
|
||||||
|
return fetchResponseStatus(response) ? response.data?.application : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function retrieveAccessToken() {
|
||||||
|
const cookieStore = await cookies();
|
||||||
|
try {
|
||||||
|
const encrpytAccessToken = cookieStore.get("eys-zzz")?.value || "";
|
||||||
|
return await nextCrypto.decrypt(encrpytAccessToken) || "";
|
||||||
|
}
|
||||||
|
catch (error) { throw new AuthError("No access token found") }
|
||||||
|
}
|
||||||
|
|
||||||
|
async function retrieveAccessObjects() {
|
||||||
|
const cookieStore = await cookies();
|
||||||
|
try {
|
||||||
|
const encrpytAccessObject = cookieStore.get("eys-yyy")?.value || "";
|
||||||
|
return await nextCrypto.decrypt(encrpytAccessObject) || "";
|
||||||
|
}
|
||||||
|
catch (error) { throw new AuthError("No access objects found") }
|
||||||
|
}
|
||||||
|
|
||||||
|
export {
|
||||||
|
checkAccessTokenIsValid,
|
||||||
|
retrieveAccessToken,
|
||||||
|
retrieveAccessObjects,
|
||||||
|
retrieveApplicationbyUrl,
|
||||||
|
retrievePageList,
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
type HttpMethod = "GET" | "POST" | "PUT" | "DELETE" | "PATCH";
|
||||||
|
|
||||||
|
interface ApiResponse<T = any> {
|
||||||
|
status: number;
|
||||||
|
data: T;
|
||||||
|
error?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface FetchOptions {
|
||||||
|
method?: HttpMethod;
|
||||||
|
cache?: boolean;
|
||||||
|
timeout?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface CookieObject {
|
||||||
|
httpOnly: boolean;
|
||||||
|
path: string;
|
||||||
|
sameSite: string;
|
||||||
|
secure: boolean;
|
||||||
|
maxAge: number;
|
||||||
|
priority: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type { HttpMethod, ApiResponse, FetchOptions, CookieObject };
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
const formatServiceUrl = (url: string) => {
|
||||||
|
if (!url) return "";
|
||||||
|
return url.startsWith("http") ? url : `http://${url}`;
|
||||||
|
};
|
||||||
|
|
||||||
|
function fetchResponseStatus(response: any) {
|
||||||
|
return 199 < response?.status && response?.status < 300;
|
||||||
|
}
|
||||||
|
|
||||||
|
export { formatServiceUrl, fetchResponseStatus };
|
||||||
|
|
@ -0,0 +1,193 @@
|
||||||
|
// From Redis objects
|
||||||
|
export class AuthError extends Error {
|
||||||
|
constructor(message: string) {
|
||||||
|
super(message);
|
||||||
|
this.name = 'AuthError';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ClientOnline {
|
||||||
|
lastLogin: Date;
|
||||||
|
lastLogout: Date;
|
||||||
|
lastAction: Date;
|
||||||
|
lastPage: string;
|
||||||
|
userType: string;
|
||||||
|
lang: string;
|
||||||
|
timezone: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ClientPageConfig {
|
||||||
|
mode: string;
|
||||||
|
textFont: number;
|
||||||
|
theme: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ClientHeader {
|
||||||
|
header: any[];
|
||||||
|
activeDomain: string;
|
||||||
|
listOfDomains: string[];
|
||||||
|
connections: any[];
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ClientMenu {
|
||||||
|
selectionList: string[];
|
||||||
|
activeSelection: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ClientSelection {
|
||||||
|
selectionList: any[];
|
||||||
|
activeSelection: Record<string, any>;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ClientUser {
|
||||||
|
uuid: string;
|
||||||
|
avatar: string;
|
||||||
|
email: string;
|
||||||
|
phone_number: string;
|
||||||
|
user_tag: string;
|
||||||
|
password_expiry_begins: string;
|
||||||
|
person: {
|
||||||
|
uuid: string;
|
||||||
|
firstname: string;
|
||||||
|
surname: string;
|
||||||
|
middle_name: string;
|
||||||
|
sex_code: string;
|
||||||
|
person_tag: string;
|
||||||
|
country_code: string;
|
||||||
|
birth_date: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ClientSettings {
|
||||||
|
lastOnline: Date;
|
||||||
|
token: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface LinkList {
|
||||||
|
linkList: any[];
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ClientRedisToken {
|
||||||
|
online: ClientOnline;
|
||||||
|
pageConfig: ClientPageConfig;
|
||||||
|
menu: ClientMenu;
|
||||||
|
header: ClientHeader;
|
||||||
|
selection: ClientSelection;
|
||||||
|
user: ClientUser;
|
||||||
|
settings: ClientSettings;
|
||||||
|
chatRoom: LinkList;
|
||||||
|
notifications: LinkList;
|
||||||
|
messages: LinkList;
|
||||||
|
}
|
||||||
|
|
||||||
|
const defaultClientOnline: ClientOnline = {
|
||||||
|
lastLogin: new Date(),
|
||||||
|
lastLogout: new Date(),
|
||||||
|
lastAction: new Date(),
|
||||||
|
lastPage: "/dashboard",
|
||||||
|
userType: "employee",
|
||||||
|
lang: "tr",
|
||||||
|
timezone: "GMT+3",
|
||||||
|
};
|
||||||
|
|
||||||
|
const defaultClientPageConfig: ClientPageConfig = {
|
||||||
|
mode: "light",
|
||||||
|
textFont: 14,
|
||||||
|
theme: "default",
|
||||||
|
};
|
||||||
|
|
||||||
|
const defaultClientMenu: ClientMenu = {
|
||||||
|
selectionList: [],
|
||||||
|
activeSelection: "/dashboard",
|
||||||
|
};
|
||||||
|
|
||||||
|
const defaultClientHeader: ClientHeader = {
|
||||||
|
header: [],
|
||||||
|
activeDomain: "",
|
||||||
|
listOfDomains: [],
|
||||||
|
connections: [],
|
||||||
|
};
|
||||||
|
|
||||||
|
const defaultClientSelection: ClientSelection = {
|
||||||
|
selectionList: [],
|
||||||
|
activeSelection: {},
|
||||||
|
};
|
||||||
|
|
||||||
|
const defaultClientUser: ClientUser = {
|
||||||
|
uuid: "",
|
||||||
|
avatar: "",
|
||||||
|
email: "",
|
||||||
|
phone_number: "",
|
||||||
|
user_tag: "",
|
||||||
|
password_expiry_begins: new Date().toISOString(),
|
||||||
|
person: {
|
||||||
|
uuid: "",
|
||||||
|
firstname: "",
|
||||||
|
surname: "",
|
||||||
|
middle_name: "",
|
||||||
|
sex_code: "",
|
||||||
|
person_tag: "",
|
||||||
|
country_code: "",
|
||||||
|
birth_date: "",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const defaultClientSettings: ClientSettings = {
|
||||||
|
lastOnline: new Date(),
|
||||||
|
token: "",
|
||||||
|
};
|
||||||
|
|
||||||
|
const defaultLinkList: LinkList = {
|
||||||
|
linkList: [],
|
||||||
|
};
|
||||||
|
|
||||||
|
const defaultClientRedisToken: ClientRedisToken = {
|
||||||
|
online: defaultClientOnline,
|
||||||
|
pageConfig: defaultClientPageConfig,
|
||||||
|
menu: defaultClientMenu,
|
||||||
|
header: defaultClientHeader,
|
||||||
|
selection: defaultClientSelection,
|
||||||
|
user: defaultClientUser,
|
||||||
|
settings: defaultClientSettings,
|
||||||
|
chatRoom: defaultLinkList,
|
||||||
|
notifications: defaultLinkList,
|
||||||
|
messages: defaultLinkList,
|
||||||
|
};
|
||||||
|
|
||||||
|
const generateRedisKey = (userType: string, uuId: string) => {
|
||||||
|
const userTypeToUpper = userType.toUpperCase();
|
||||||
|
if (!userTypeToUpper || !uuId) throw new Error("Invalid user type or uuId");
|
||||||
|
return `CLIENT:${userTypeToUpper}:${uuId}`;
|
||||||
|
};
|
||||||
|
|
||||||
|
const readRedisKey = (redisKey: string) => {
|
||||||
|
if (redisKey.split(":").length !== 2) throw new Error("Invalid redis key");
|
||||||
|
const userTypeToUpper = redisKey.split(":")[1];
|
||||||
|
const uuId = redisKey.split(":")[2];
|
||||||
|
if (!userTypeToUpper || !uuId) throw new Error("Invalid user type or uuId");
|
||||||
|
return { userType: userTypeToUpper.toLowerCase(), uuId };
|
||||||
|
};
|
||||||
|
|
||||||
|
export {
|
||||||
|
defaultClientOnline,
|
||||||
|
defaultClientPageConfig,
|
||||||
|
defaultClientMenu,
|
||||||
|
defaultClientHeader,
|
||||||
|
defaultClientSelection,
|
||||||
|
defaultClientUser,
|
||||||
|
defaultClientSettings,
|
||||||
|
defaultLinkList,
|
||||||
|
defaultClientRedisToken,
|
||||||
|
};
|
||||||
|
export type {
|
||||||
|
ClientOnline,
|
||||||
|
ClientPageConfig,
|
||||||
|
ClientMenu,
|
||||||
|
ClientHeader,
|
||||||
|
ClientSelection,
|
||||||
|
ClientUser,
|
||||||
|
ClientSettings,
|
||||||
|
LinkList,
|
||||||
|
ClientRedisToken,
|
||||||
|
};
|
||||||
|
export { generateRedisKey, readRedisKey };
|
||||||
|
|
@ -0,0 +1,44 @@
|
||||||
|
interface FetcherRequest {
|
||||||
|
url: string;
|
||||||
|
isNoCache: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface PostFetcherRequest<T> extends FetcherRequest {
|
||||||
|
body: Record<string, T>;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface GetFetcherRequest extends FetcherRequest {
|
||||||
|
url: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface DeleteFetcherRequest extends GetFetcherRequest {}
|
||||||
|
interface PutFetcherRequest<T> extends PostFetcherRequest<T> {}
|
||||||
|
interface PatchFetcherRequest<T> extends PostFetcherRequest<T> {}
|
||||||
|
|
||||||
|
interface FetcherRespose {
|
||||||
|
success: boolean;
|
||||||
|
}
|
||||||
|
interface PaginationResponse {
|
||||||
|
onPage: number;
|
||||||
|
onPageCount: number;
|
||||||
|
totalPage: number;
|
||||||
|
totalCount: number;
|
||||||
|
next: boolean;
|
||||||
|
back: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface FetcherDataResponse<T> extends FetcherRespose {
|
||||||
|
data: Record<string, T> | null;
|
||||||
|
pagination?: PaginationResponse;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type {
|
||||||
|
FetcherRequest,
|
||||||
|
PostFetcherRequest,
|
||||||
|
GetFetcherRequest,
|
||||||
|
DeleteFetcherRequest,
|
||||||
|
PutFetcherRequest,
|
||||||
|
PatchFetcherRequest,
|
||||||
|
FetcherRespose,
|
||||||
|
FetcherDataResponse,
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,38 @@
|
||||||
|
import { ApiResponse, CookieObject } from "./types";
|
||||||
|
import NextCrypto from "next-crypto";
|
||||||
|
|
||||||
|
const tokenSecretEnv = process.env.TOKENSECRET_90;
|
||||||
|
const tokenSecret = tokenSecretEnv || "e781d1b0-9418-40b3-9940-385abf81a0b7";
|
||||||
|
const nextCrypto = new NextCrypto(tokenSecret);
|
||||||
|
|
||||||
|
const cookieObject: CookieObject = {
|
||||||
|
httpOnly: true,
|
||||||
|
path: "/",
|
||||||
|
sameSite: "none",
|
||||||
|
secure: true,
|
||||||
|
maxAge: 3600,
|
||||||
|
priority: "high",
|
||||||
|
};
|
||||||
|
|
||||||
|
const DEFAULT_TIMEOUT: number = 10000; // 10 seconds
|
||||||
|
const defaultHeaders: Record<string, string> = {
|
||||||
|
accept: "application/json",
|
||||||
|
language: "tr",
|
||||||
|
domain: "evyos.com.tr",
|
||||||
|
tz: "GMT+3",
|
||||||
|
"Content-type": "application/json",
|
||||||
|
};
|
||||||
|
const DEFAULT_RESPONSE: ApiResponse = {
|
||||||
|
error: "Hata tipi belirtilmedi",
|
||||||
|
status: 500,
|
||||||
|
data: {},
|
||||||
|
};
|
||||||
|
|
||||||
|
export {
|
||||||
|
DEFAULT_TIMEOUT,
|
||||||
|
DEFAULT_RESPONSE,
|
||||||
|
defaultHeaders,
|
||||||
|
tokenSecret,
|
||||||
|
cookieObject,
|
||||||
|
nextCrypto,
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,127 @@
|
||||||
|
"use server";
|
||||||
|
import { DEFAULT_RESPONSE, defaultHeaders, DEFAULT_TIMEOUT } from "./base";
|
||||||
|
import { FetchOptions, HttpMethod, ApiResponse } from "./types";
|
||||||
|
import { retrieveAccessToken } from "./mutual/cookies/token";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 };
|
||||||
|
|
@ -0,0 +1,36 @@
|
||||||
|
import { formatServiceUrl } from "./utils";
|
||||||
|
|
||||||
|
const baseUrlAuth = formatServiceUrl(
|
||||||
|
process.env.NEXT_PUBLIC_AUTH_SERVICE_URL || "auth_service:8001"
|
||||||
|
);
|
||||||
|
const baseUrlRestriction = formatServiceUrl(
|
||||||
|
process.env.NEXT_PUBLIC_RESTRICTION_SERVICE_URL || "restriction_service:8002"
|
||||||
|
);
|
||||||
|
const baseUrlApplication = formatServiceUrl(
|
||||||
|
process.env.NEXT_PUBLIC_MANAGEMENT_SERVICE_URL || "management_service:8003"
|
||||||
|
);
|
||||||
|
const baseUrlAccount = formatServiceUrl(
|
||||||
|
process.env.NEXT_PUBLIC_ACCOUNT_SERVICE_URL || "account_service:8004"
|
||||||
|
);
|
||||||
|
const baseUrlBuilding = formatServiceUrl(
|
||||||
|
process.env.NEXT_PUBLIC_BUILDING_SERVICE_URL || "building_service:8006"
|
||||||
|
);
|
||||||
|
const baseUrlPeople = formatServiceUrl(
|
||||||
|
process.env.NEXT_PUBLIC_VALIDATION_SERVICE_URL || "validation_service:8009"
|
||||||
|
);
|
||||||
|
|
||||||
|
const urlCheckToken = `${baseUrlAuth}/authentication/token/check`;
|
||||||
|
const urlPageValid = `${baseUrlRestriction}/restrictions/page/valid`;
|
||||||
|
const urlSiteUrls = `${baseUrlRestriction}/restrictions/sites/list`;
|
||||||
|
|
||||||
|
export {
|
||||||
|
baseUrlAuth,
|
||||||
|
baseUrlPeople,
|
||||||
|
baseUrlApplication,
|
||||||
|
baseUrlAccount,
|
||||||
|
baseUrlBuilding,
|
||||||
|
baseUrlRestriction,
|
||||||
|
urlCheckToken,
|
||||||
|
urlPageValid,
|
||||||
|
urlSiteUrls,
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
'use server';
|
||||||
|
import { cookies } from "next/headers";
|
||||||
|
import { cookieObject } from "@/fetchers/base";
|
||||||
|
import { ResponseCookie } from "next/dist/compiled/@edge-runtime/cookies";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Server action to delete all access cookies at once
|
||||||
|
* This is a direct server action that can be called from server components
|
||||||
|
*/
|
||||||
|
export async function deleteAllCookies() {
|
||||||
|
try {
|
||||||
|
const cookieStore = await cookies();
|
||||||
|
if (cookieStore.has("eys-zzz")) { cookieStore.delete({ name: "eys-zzz", ...cookieObject } as ResponseCookie); }
|
||||||
|
if (cookieStore.has("eys-yyy")) { cookieStore.delete({ name: "eys-yyy", ...cookieObject } as ResponseCookie); }
|
||||||
|
if (cookieStore.has("eys-sel")) { cookieStore.delete({ name: "eys-sel", ...cookieObject } as ResponseCookie); }
|
||||||
|
return true;
|
||||||
|
} catch (error) { console.error("Error in deleteAllCookies:", error); return false }
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,49 @@
|
||||||
|
import { cookies } from "next/headers";
|
||||||
|
import { fetchDataWithToken } from "@/fetchers/fecther";
|
||||||
|
import { urlCheckToken, urlPageValid, urlSiteUrls } from "@/fetchers/index";
|
||||||
|
import { nextCrypto } from "@/fetchers/base";
|
||||||
|
import { AuthError } from "@/validations/mutual/context/validations";
|
||||||
|
import { fetchResponseStatus } from "@/fetchers/utils";
|
||||||
|
|
||||||
|
async function checkAccessTokenIsValid() {
|
||||||
|
try {
|
||||||
|
const response = await fetchDataWithToken(urlCheckToken, {}, "GET", false);
|
||||||
|
return fetchResponseStatus(response);
|
||||||
|
} catch (error) { throw new AuthError("No access token found") }
|
||||||
|
}
|
||||||
|
|
||||||
|
async function retrievePageList() {
|
||||||
|
const response: any = await fetchDataWithToken(urlSiteUrls, {}, "GET", false);
|
||||||
|
return fetchResponseStatus(response) ? response.data?.sites : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function retrieveApplicationbyUrl(pageUrl: string) {
|
||||||
|
const response: any = await fetchDataWithToken(urlPageValid, { page_url: pageUrl }, "POST", false);
|
||||||
|
return fetchResponseStatus(response) ? response.data?.application : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function retrieveAccessToken() {
|
||||||
|
const cookieStore = await cookies();
|
||||||
|
try {
|
||||||
|
const encrpytAccessToken = cookieStore.get("eys-zzz")?.value || "";
|
||||||
|
return await nextCrypto.decrypt(encrpytAccessToken) || "";
|
||||||
|
}
|
||||||
|
catch (error) { throw new AuthError("No access token found") }
|
||||||
|
}
|
||||||
|
|
||||||
|
async function retrieveAccessObjects() {
|
||||||
|
const cookieStore = await cookies();
|
||||||
|
try {
|
||||||
|
const encrpytAccessObject = cookieStore.get("eys-yyy")?.value || "";
|
||||||
|
return await nextCrypto.decrypt(encrpytAccessObject) || "";
|
||||||
|
}
|
||||||
|
catch (error) { throw new AuthError("No access objects found") }
|
||||||
|
}
|
||||||
|
|
||||||
|
export {
|
||||||
|
checkAccessTokenIsValid,
|
||||||
|
retrieveAccessToken,
|
||||||
|
retrieveAccessObjects,
|
||||||
|
retrieveApplicationbyUrl,
|
||||||
|
retrievePageList,
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
type HttpMethod = "GET" | "POST" | "PUT" | "DELETE" | "PATCH";
|
||||||
|
|
||||||
|
interface ApiResponse<T = any> {
|
||||||
|
status: number;
|
||||||
|
data: T;
|
||||||
|
error?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface FetchOptions {
|
||||||
|
method?: HttpMethod;
|
||||||
|
cache?: boolean;
|
||||||
|
timeout?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface CookieObject {
|
||||||
|
httpOnly: boolean;
|
||||||
|
path: string;
|
||||||
|
sameSite: string;
|
||||||
|
secure: boolean;
|
||||||
|
maxAge: number;
|
||||||
|
priority: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type { HttpMethod, ApiResponse, FetchOptions, CookieObject };
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
const formatServiceUrl = (url: string) => {
|
||||||
|
if (!url) return "";
|
||||||
|
return url.startsWith("http") ? url : `http://${url}`;
|
||||||
|
};
|
||||||
|
|
||||||
|
function fetchResponseStatus(response: any) {
|
||||||
|
return 199 < response?.status && response?.status < 300;
|
||||||
|
}
|
||||||
|
|
||||||
|
export { formatServiceUrl, fetchResponseStatus };
|
||||||
|
|
@ -2,11 +2,11 @@
|
||||||
|
|
||||||
## Contexts
|
## Contexts
|
||||||
|
|
||||||
- [Component Contexts](./docs/contexts/component_contexts.md)
|
- [Component Contexts](./contexts/component_contexts.md)
|
||||||
- [Component Menu](./docs/contexts/component_menu.md)
|
- [Component Menu](./contexts/component_menu.md)
|
||||||
- [Component User](./docs/contexts/component_user.md)
|
- [Component User](./contexts/component_user.md)
|
||||||
- [Component Online](./docs/contexts/component_online.md)
|
- [Component Online](./contexts/component_online.md)
|
||||||
- [Component Selection](./docs/contexts/component_selection.md)
|
- [Component Selection](./contexts/component_selection.md)
|
||||||
|
|
||||||
## Language Selection
|
## Language Selection
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue