@uniai-fe/util-api 0.1.9 → 0.1.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +40 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.mjs +38 -1
- package/dist/index.mjs.map +1 -1
- package/dist/response/index.cjs +40 -0
- package/dist/response/index.cjs.map +1 -1
- package/dist/response/index.d.cts +30 -1
- package/dist/response/index.d.ts +30 -1
- package/dist/response/index.mjs +38 -1
- package/dist/response/index.mjs.map +1 -1
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -3,6 +3,21 @@
|
|
|
3
3
|
var utilFunctions = require('@uniai-fe/util-functions');
|
|
4
4
|
|
|
5
5
|
// src/response/module.ts
|
|
6
|
+
var API_IDLE_STATUS = "idle";
|
|
7
|
+
var isApiErrorItem = (errorValue) => {
|
|
8
|
+
if (!errorValue || typeof errorValue !== "object") {
|
|
9
|
+
return false;
|
|
10
|
+
}
|
|
11
|
+
const nextError = errorValue;
|
|
12
|
+
return typeof nextError.field_name === "string" && typeof nextError.message === "string";
|
|
13
|
+
};
|
|
14
|
+
var isApiBaseResponse = (payload) => {
|
|
15
|
+
if (!payload || typeof payload !== "object") {
|
|
16
|
+
return false;
|
|
17
|
+
}
|
|
18
|
+
const nextPayload = payload;
|
|
19
|
+
return typeof nextPayload.status === "string" && Array.isArray(nextPayload.errors) && nextPayload.errors.every(isApiErrorItem);
|
|
20
|
+
};
|
|
6
21
|
var setAlternateResponse = (errorMessage, data) => ({
|
|
7
22
|
status: "fail",
|
|
8
23
|
errors: [
|
|
@@ -10,6 +25,28 @@ var setAlternateResponse = (errorMessage, data) => ({
|
|
|
10
25
|
],
|
|
11
26
|
data
|
|
12
27
|
});
|
|
28
|
+
var getApiErrorState = (payload) => isApiBaseResponse(payload) ? payload.status : void 0;
|
|
29
|
+
var getApiErrorMessages = (payload) => {
|
|
30
|
+
if (!isApiBaseResponse(payload)) {
|
|
31
|
+
return [];
|
|
32
|
+
}
|
|
33
|
+
return payload.errors.map((errorItem) => errorItem.message.trim()).filter(Boolean);
|
|
34
|
+
};
|
|
35
|
+
var getApiError = (response, payload) => {
|
|
36
|
+
const state = getApiErrorState(payload);
|
|
37
|
+
const messages = getApiErrorMessages(payload);
|
|
38
|
+
const hasFailedStatusCode = response.status !== 200;
|
|
39
|
+
const hasFailedState = typeof state === "string" && !["success", API_IDLE_STATUS].includes(state);
|
|
40
|
+
const hasFailedMessage = messages.length > 0;
|
|
41
|
+
if (!hasFailedStatusCode && !hasFailedState && !hasFailedMessage) {
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
return {
|
|
45
|
+
code: response.status,
|
|
46
|
+
state,
|
|
47
|
+
message: messages.join(" | ") || response.statusText || void 0
|
|
48
|
+
};
|
|
49
|
+
};
|
|
13
50
|
var getQueryString = (searchParams) => {
|
|
14
51
|
const serialized = utilFunctions.convertObjectToSearchParams(searchParams, {
|
|
15
52
|
function: "getQueryString"
|
|
@@ -146,6 +183,9 @@ var fetchWithBody = async ({
|
|
|
146
183
|
|
|
147
184
|
exports.fetchWithBody = fetchWithBody;
|
|
148
185
|
exports.generateQueryUrl = generateQueryUrl;
|
|
186
|
+
exports.getApiError = getApiError;
|
|
187
|
+
exports.getApiErrorMessages = getApiErrorMessages;
|
|
188
|
+
exports.getApiErrorState = getApiErrorState;
|
|
149
189
|
exports.getFetchOptions = getFetchOptions;
|
|
150
190
|
exports.getQueryString = getQueryString;
|
|
151
191
|
exports.getRouteUrl = getRouteUrl;
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/response/module.ts","../src/request/module.ts"],"names":["convertObjectToSearchParams"],"mappings":"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","file":"index.cjs","sourcesContent":["import type { API_Res_Base } from \"./types\";\n\nexport const setAlternateResponse = <ResponseDataType>(\n errorMessage: string,\n data: ResponseDataType,\n): API_Res_Base<ResponseDataType> => ({\n status: \"fail\",\n errors: [\n { field_name: \"\", message: errorMessage || \"데이터 조회에 실패했습니다.\" },\n ],\n data,\n});\n","import { convertObjectToSearchParams } from \"@uniai-fe/util-functions\";\nimport type {\n API_FetchWithBodyParams,\n API_GetFetchOptionsParams,\n API_GenerateQueryUrlParams,\n} from \"./types\";\n\n/**\n * API Request Utils; 쿼리스트링 생성\n * @param {unknown} [searchParams] 쿼리스트링 변환 대상\n * @returns {string} 직렬화된 쿼리스트링\n * @example\n * const query = getQueryString({ farm_id: 1 });\n */\nexport const getQueryString = (searchParams?: unknown): string => {\n // 변경: util-functions 공통 유틸을 재사용해 query 변환 규칙을 단일화한다.\n const serialized = convertObjectToSearchParams(searchParams, {\n function: \"getQueryString\",\n }).toString();\n return serialized ? `?${serialized}` : \"\";\n};\n\n/**\n * API Request Utils; Next.js route 디버깅 로그 출력\n * @param {string} method HTTP method 문자열\n * @param {string} routeUrl frontend route URL\n * @param {string} [queryUrl] backend query URL\n * @param {unknown[]} messages 로그 메시지\n */\nexport const nextAPILog = (\n method: string,\n routeUrl: string,\n queryUrl?: string,\n ...messages: unknown[]\n) => {\n // 2026-03-19: 배포 환경에서의 모니터링 및 디버깅을 위한 서버 로그 확인을 위해 주석처리함\n // if (process.env.NODE_ENV === \"production\") {\n // return;\n // }\n\n // 변경: util-api 단독 동작을 위해 날짜 포맷 의존성을 내부 계산으로 대체한다.\n const date = new Date();\n const dateText = date.toISOString().split(\"T\")[0] ?? \"\";\n const timeText = `${date.toLocaleTimeString(\"en-US\", { hour12: false })}.${date.getMilliseconds()}`;\n const requestMethod = method.split(\"-\")[0]?.toUpperCase() || \"-\";\n const responseMethod = method.split(\"-\")[1]?.toUpperCase() || requestMethod;\n\n return console.log(\n `\\n`,\n `[Next Server API] ⏱ ${dateText} ( ${timeText} )`,\n `\\n λ [${requestMethod}] FE route`,\n `\\n ${routeUrl}`,\n ...(queryUrl\n ? [`\\n ═⏵ Ω [${responseMethod}] BE url`, `\\n ${queryUrl}`, `\\n`]\n : []),\n ...(messages?.[0] ? [` ◇-`, ...messages] : []),\n `\\n`,\n );\n};\n\n/**\n * API Request Utils; 클라이언트 요청 URL 생성\n * @param {string} routeUrl next.js API URL 또는 요청 경로\n * @param {URLSearchParams | object} [searchParams] 쿼리스트링 원본\n */\nexport const getRouteUrl = (\n routeUrl: string,\n searchParams?: URLSearchParams | object,\n) => `${routeUrl}${getQueryString(searchParams)}`;\n\n/**\n * API Request Utils; GET API 요청 URL 생성\n * @param {API_GenerateQueryUrlParams} params URL 생성 파라미터\n * @property {string} [params.method] fetch HTTP method\n * @property {string} params.domain API 도메인\n * @property {string} params.routeUrl frontend route URL\n * @property {string} params.queryUrl backend query URL\n * @property {URLSearchParams | object} [params.searchParams] 쿼리스트링 원본\n * @property {object} [params.log] 디버깅 로그 객체\n * @property {boolean} [params.logDisabled] 로그 비활성화 여부\n * @returns {string} 완성된 요청 URL\n * @example\n * const url = generateQueryUrl({ domain, routeUrl, queryUrl });\n */\nexport const generateQueryUrl = ({\n method = \"GET\",\n domain,\n routeUrl,\n queryUrl,\n searchParams,\n log,\n logDisabled,\n}: API_GenerateQueryUrlParams): string => {\n const url = `${domain}${queryUrl}${getQueryString(searchParams)}`;\n\n if (!logDisabled) {\n nextAPILog(method, routeUrl, url, {\n ...(log ?? {}),\n ...(searchParams ?? {}),\n });\n }\n\n return url;\n};\n\n/**\n * API Request Utils; fetch 요청 옵션 생성\n * @param {API_GetFetchOptionsParams} params 요청 옵션 파라미터\n * @property {string} params.method HTTP method 문자열\n * @property {HeadersInit} [params.headers] 요청 헤더\n * @property {BodyInit | null} [params.body] 요청 body\n * @returns {RequestInit} fetch 요청 옵션 객체\n * @example\n * const option = getFetchOptions({\n * method: \"POST\",\n * headers: { \"Content-Type\": \"application/json\" },\n * body: JSON.stringify({ farm_id: 1 }),\n * });\n */\nexport const getFetchOptions = ({\n method,\n headers,\n body,\n}: API_GetFetchOptionsParams): RequestInit => ({\n method,\n // 변경: Headers 인스턴스는 Object.keys로 비어 보일 수 있어 정의 여부만으로 유지한다.\n ...(typeof headers === \"undefined\" ? {} : { headers }),\n ...(typeof body === \"undefined\" ? {} : { body }),\n});\n\n/**\n * API Request Utils; body 기반 fetch 요청\n * @template BodyDataType\n * @template ResponseType\n * @param {API_FetchWithBodyParams<BodyDataType, ResponseType>} params 요청 파라미터\n * @property {string} params.domain API 도메인\n * @property {string} params.method HTTP method 문자열\n * @property {string} params.routeUrl frontend route URL\n * @property {string} params.queryUrl backend query URL\n * @property {ResponseType} params.alternateResponse 실패 시 대체 응답\n * @property {URLSearchParams | object} [params.searchParams] 쿼리스트링 원본\n * @property {HeadersInit} [params.headers] fetch headers\n * @property {BodyInit | null} [params.body] fetch body\n * @property {BodyDataType} [params.bodyData] body 데이터\n * @property {boolean} [params.isRawResponse] raw response 반환 여부\n * @property {object} [params.debug] 디버그 로그 객체\n * @property {boolean} [params.disabled] fetch 비활성화 여부\n * @property {boolean} [params.disabledLog] 로그 비활성화 여부\n * @returns {Promise<ResponseType>} 응답 데이터 또는 alternateResponse\n * @example\n * const response = await fetchWithBody({ domain, method: \"POST\", routeUrl, queryUrl, alternateResponse });\n */\nexport const fetchWithBody = async <\n BodyDataType = object,\n ResponseType extends object | Response = Response,\n>({\n domain,\n method,\n routeUrl,\n queryUrl,\n searchParams,\n headers,\n body,\n bodyData,\n isRawResponse,\n alternateResponse,\n debug,\n disabled,\n disabledLog,\n}: API_FetchWithBodyParams<\n BodyDataType,\n ResponseType\n>): Promise<ResponseType> => {\n const url = `${domain}${queryUrl}${getQueryString(searchParams)}`;\n const option = getFetchOptions({ method, headers, body });\n\n if (!body && typeof bodyData !== \"undefined\") {\n // 변경: util-functions 공통 유틸을 재사용해 body 직렬화 규칙을 단일화한다.\n const bodyParams = convertObjectToSearchParams(bodyData, {\n function: \"fetchWithBody\",\n method,\n domain,\n routeUrl,\n queryUrl,\n searchParams,\n }).toString();\n if (bodyParams === \"\") {\n nextAPILog(method.toLowerCase(), routeUrl, url, {\n state: \"ERROR (BODY - DATA)\",\n error: \"데이터가 유효하지 않습니다.\",\n bodyData,\n ...(debug ?? {}),\n });\n return alternateResponse;\n }\n option.body = bodyData as BodyInit;\n }\n\n if (!disabledLog) {\n nextAPILog(method.toLowerCase(), routeUrl, url, {\n state: \"READY\",\n ...option,\n ...(debug ?? {}),\n });\n }\n\n if (disabled) {\n nextAPILog(method.toLowerCase(), routeUrl, url, {\n state: \"FETCH DISABLED\",\n message: \"API 요청제한 활성화됨.\",\n });\n return alternateResponse;\n }\n\n try {\n const responseRaw = await fetch(url, option);\n const responseCode = responseRaw.status;\n\n if (!disabledLog) {\n nextAPILog(method.toLowerCase(), routeUrl, url, {\n state: responseCode === 200 ? \"SUCCESS\" : \"FAIL\",\n code: responseCode,\n });\n }\n\n if (isRawResponse) {\n return responseRaw as ResponseType;\n }\n return (await responseRaw.json()) as ResponseType;\n } catch (error: unknown) {\n if (!disabledLog) {\n nextAPILog(method.toLowerCase(), routeUrl, url, {\n state: \"ERROR (RESPONSE)\",\n error,\n ...(debug ?? {}),\n });\n }\n return alternateResponse;\n }\n};\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/response/module.ts","../src/request/module.ts"],"names":["convertObjectToSearchParams"],"mappings":"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","file":"index.cjs","sourcesContent":["import type { API_Res_Base, API_Res_Error } from \"./types\";\n\nconst API_IDLE_STATUS = \"idle\";\n\n/**\n * API Response Utility; 에러 item 판별\n * @param {unknown} errorValue 검사 대상 값\n * @returns {boolean} API error item 여부\n * @example\n * const isApiError = isApiErrorItem({ field_name: \"email\", message: \"필수값\" });\n */\nconst isApiErrorItem = (errorValue: unknown): errorValue is API_Res_Error => {\n if (!errorValue || typeof errorValue !== \"object\") {\n return false;\n }\n\n const nextError = errorValue as Partial<API_Res_Error>;\n\n return (\n typeof nextError.field_name === \"string\" &&\n typeof nextError.message === \"string\"\n );\n};\n\n/**\n * API Response Utility; Base 응답 판별\n * @param {unknown} payload 검사 대상 payload\n * @returns {boolean} API_Res_Base 형태 여부\n * @example\n * const isApiBase = isApiBaseResponse(payload);\n */\nconst isApiBaseResponse = (\n payload: unknown,\n): payload is API_Res_Base<unknown> => {\n if (!payload || typeof payload !== \"object\") {\n return false;\n }\n\n const nextPayload = payload as Partial<API_Res_Base<unknown>>;\n\n return (\n typeof nextPayload.status === \"string\" &&\n Array.isArray(nextPayload.errors) &&\n nextPayload.errors.every(isApiErrorItem)\n );\n};\n\nexport const setAlternateResponse = <ResponseDataType>(\n errorMessage: string,\n data: ResponseDataType,\n): API_Res_Base<ResponseDataType> => ({\n status: \"fail\",\n errors: [\n { field_name: \"\", message: errorMessage || \"데이터 조회에 실패했습니다.\" },\n ],\n data,\n});\n\n/**\n * API Response Utility; 응답 status 추출\n * @param {unknown} payload 응답 payload\n * @returns {string | undefined} API layer status\n * @example\n * const status = getApiErrorState(payload);\n */\nexport const getApiErrorState = (payload: unknown): string | undefined =>\n isApiBaseResponse(payload) ? payload.status : undefined;\n\n/**\n * API Response Utility; 응답 에러 메시지 목록 추출\n * @param {unknown} payload 응답 payload\n * @returns {string[]} 비어 있지 않은 에러 메시지 목록\n * @example\n * const messages = getApiErrorMessages(payload);\n */\nexport const getApiErrorMessages = (payload: unknown): string[] => {\n if (!isApiBaseResponse(payload)) {\n return [];\n }\n\n return payload.errors\n .map(errorItem => errorItem.message.trim())\n .filter(Boolean);\n};\n\n/**\n * API Response Utility; 응답 오류 요약 추출\n * @param {Response} response fetch 응답 객체\n * @param {unknown} payload 응답 payload\n * @returns {{ code: number; state?: string; message?: string } | null} 수집 대상 오류 요약\n * @example\n * const apiError = getApiError(response, payload);\n */\nexport const getApiError = (\n response: Response,\n payload: unknown,\n): {\n code: number;\n state?: string;\n message?: string;\n} | null => {\n const state = getApiErrorState(payload);\n const messages = getApiErrorMessages(payload);\n const hasFailedStatusCode = response.status !== 200;\n const hasFailedState =\n typeof state === \"string\" && ![\"success\", API_IDLE_STATUS].includes(state);\n const hasFailedMessage = messages.length > 0;\n\n if (!hasFailedStatusCode && !hasFailedState && !hasFailedMessage) {\n return null;\n }\n\n return {\n code: response.status,\n state,\n message: messages.join(\" | \") || response.statusText || undefined,\n };\n};\n","import { convertObjectToSearchParams } from \"@uniai-fe/util-functions\";\nimport type {\n API_FetchWithBodyParams,\n API_GetFetchOptionsParams,\n API_GenerateQueryUrlParams,\n} from \"./types\";\n\n/**\n * API Request Utils; 쿼리스트링 생성\n * @param {unknown} [searchParams] 쿼리스트링 변환 대상\n * @returns {string} 직렬화된 쿼리스트링\n * @example\n * const query = getQueryString({ farm_id: 1 });\n */\nexport const getQueryString = (searchParams?: unknown): string => {\n // 변경: util-functions 공통 유틸을 재사용해 query 변환 규칙을 단일화한다.\n const serialized = convertObjectToSearchParams(searchParams, {\n function: \"getQueryString\",\n }).toString();\n return serialized ? `?${serialized}` : \"\";\n};\n\n/**\n * API Request Utils; Next.js route 디버깅 로그 출력\n * @param {string} method HTTP method 문자열\n * @param {string} routeUrl frontend route URL\n * @param {string} [queryUrl] backend query URL\n * @param {unknown[]} messages 로그 메시지\n */\nexport const nextAPILog = (\n method: string,\n routeUrl: string,\n queryUrl?: string,\n ...messages: unknown[]\n) => {\n // 2026-03-19: 배포 환경에서의 모니터링 및 디버깅을 위한 서버 로그 확인을 위해 주석처리함\n // if (process.env.NODE_ENV === \"production\") {\n // return;\n // }\n\n // 변경: util-api 단독 동작을 위해 날짜 포맷 의존성을 내부 계산으로 대체한다.\n const date = new Date();\n const dateText = date.toISOString().split(\"T\")[0] ?? \"\";\n const timeText = `${date.toLocaleTimeString(\"en-US\", { hour12: false })}.${date.getMilliseconds()}`;\n const requestMethod = method.split(\"-\")[0]?.toUpperCase() || \"-\";\n const responseMethod = method.split(\"-\")[1]?.toUpperCase() || requestMethod;\n\n return console.log(\n `\\n`,\n `[Next Server API] ⏱ ${dateText} ( ${timeText} )`,\n `\\n λ [${requestMethod}] FE route`,\n `\\n ${routeUrl}`,\n ...(queryUrl\n ? [`\\n ═⏵ Ω [${responseMethod}] BE url`, `\\n ${queryUrl}`, `\\n`]\n : []),\n ...(messages?.[0] ? [` ◇-`, ...messages] : []),\n `\\n`,\n );\n};\n\n/**\n * API Request Utils; 클라이언트 요청 URL 생성\n * @param {string} routeUrl next.js API URL 또는 요청 경로\n * @param {URLSearchParams | object} [searchParams] 쿼리스트링 원본\n */\nexport const getRouteUrl = (\n routeUrl: string,\n searchParams?: URLSearchParams | object,\n) => `${routeUrl}${getQueryString(searchParams)}`;\n\n/**\n * API Request Utils; GET API 요청 URL 생성\n * @param {API_GenerateQueryUrlParams} params URL 생성 파라미터\n * @property {string} [params.method] fetch HTTP method\n * @property {string} params.domain API 도메인\n * @property {string} params.routeUrl frontend route URL\n * @property {string} params.queryUrl backend query URL\n * @property {URLSearchParams | object} [params.searchParams] 쿼리스트링 원본\n * @property {object} [params.log] 디버깅 로그 객체\n * @property {boolean} [params.logDisabled] 로그 비활성화 여부\n * @returns {string} 완성된 요청 URL\n * @example\n * const url = generateQueryUrl({ domain, routeUrl, queryUrl });\n */\nexport const generateQueryUrl = ({\n method = \"GET\",\n domain,\n routeUrl,\n queryUrl,\n searchParams,\n log,\n logDisabled,\n}: API_GenerateQueryUrlParams): string => {\n const url = `${domain}${queryUrl}${getQueryString(searchParams)}`;\n\n if (!logDisabled) {\n nextAPILog(method, routeUrl, url, {\n ...(log ?? {}),\n ...(searchParams ?? {}),\n });\n }\n\n return url;\n};\n\n/**\n * API Request Utils; fetch 요청 옵션 생성\n * @param {API_GetFetchOptionsParams} params 요청 옵션 파라미터\n * @property {string} params.method HTTP method 문자열\n * @property {HeadersInit} [params.headers] 요청 헤더\n * @property {BodyInit | null} [params.body] 요청 body\n * @returns {RequestInit} fetch 요청 옵션 객체\n * @example\n * const option = getFetchOptions({\n * method: \"POST\",\n * headers: { \"Content-Type\": \"application/json\" },\n * body: JSON.stringify({ farm_id: 1 }),\n * });\n */\nexport const getFetchOptions = ({\n method,\n headers,\n body,\n}: API_GetFetchOptionsParams): RequestInit => ({\n method,\n // 변경: Headers 인스턴스는 Object.keys로 비어 보일 수 있어 정의 여부만으로 유지한다.\n ...(typeof headers === \"undefined\" ? {} : { headers }),\n ...(typeof body === \"undefined\" ? {} : { body }),\n});\n\n/**\n * API Request Utils; body 기반 fetch 요청\n * @template BodyDataType\n * @template ResponseType\n * @param {API_FetchWithBodyParams<BodyDataType, ResponseType>} params 요청 파라미터\n * @property {string} params.domain API 도메인\n * @property {string} params.method HTTP method 문자열\n * @property {string} params.routeUrl frontend route URL\n * @property {string} params.queryUrl backend query URL\n * @property {ResponseType} params.alternateResponse 실패 시 대체 응답\n * @property {URLSearchParams | object} [params.searchParams] 쿼리스트링 원본\n * @property {HeadersInit} [params.headers] fetch headers\n * @property {BodyInit | null} [params.body] fetch body\n * @property {BodyDataType} [params.bodyData] body 데이터\n * @property {boolean} [params.isRawResponse] raw response 반환 여부\n * @property {object} [params.debug] 디버그 로그 객체\n * @property {boolean} [params.disabled] fetch 비활성화 여부\n * @property {boolean} [params.disabledLog] 로그 비활성화 여부\n * @returns {Promise<ResponseType>} 응답 데이터 또는 alternateResponse\n * @example\n * const response = await fetchWithBody({ domain, method: \"POST\", routeUrl, queryUrl, alternateResponse });\n */\nexport const fetchWithBody = async <\n BodyDataType = object,\n ResponseType extends object | Response = Response,\n>({\n domain,\n method,\n routeUrl,\n queryUrl,\n searchParams,\n headers,\n body,\n bodyData,\n isRawResponse,\n alternateResponse,\n debug,\n disabled,\n disabledLog,\n}: API_FetchWithBodyParams<\n BodyDataType,\n ResponseType\n>): Promise<ResponseType> => {\n const url = `${domain}${queryUrl}${getQueryString(searchParams)}`;\n const option = getFetchOptions({ method, headers, body });\n\n if (!body && typeof bodyData !== \"undefined\") {\n // 변경: util-functions 공통 유틸을 재사용해 body 직렬화 규칙을 단일화한다.\n const bodyParams = convertObjectToSearchParams(bodyData, {\n function: \"fetchWithBody\",\n method,\n domain,\n routeUrl,\n queryUrl,\n searchParams,\n }).toString();\n if (bodyParams === \"\") {\n nextAPILog(method.toLowerCase(), routeUrl, url, {\n state: \"ERROR (BODY - DATA)\",\n error: \"데이터가 유효하지 않습니다.\",\n bodyData,\n ...(debug ?? {}),\n });\n return alternateResponse;\n }\n option.body = bodyData as BodyInit;\n }\n\n if (!disabledLog) {\n nextAPILog(method.toLowerCase(), routeUrl, url, {\n state: \"READY\",\n ...option,\n ...(debug ?? {}),\n });\n }\n\n if (disabled) {\n nextAPILog(method.toLowerCase(), routeUrl, url, {\n state: \"FETCH DISABLED\",\n message: \"API 요청제한 활성화됨.\",\n });\n return alternateResponse;\n }\n\n try {\n const responseRaw = await fetch(url, option);\n const responseCode = responseRaw.status;\n\n if (!disabledLog) {\n nextAPILog(method.toLowerCase(), routeUrl, url, {\n state: responseCode === 200 ? \"SUCCESS\" : \"FAIL\",\n code: responseCode,\n });\n }\n\n if (isRawResponse) {\n return responseRaw as ResponseType;\n }\n return (await responseRaw.json()) as ResponseType;\n } catch (error: unknown) {\n if (!disabledLog) {\n nextAPILog(method.toLowerCase(), routeUrl, url, {\n state: \"ERROR (RESPONSE)\",\n error,\n ...(debug ?? {}),\n });\n }\n return alternateResponse;\n }\n};\n"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export { setAlternateResponse } from './response/index.cjs';
|
|
1
|
+
export { getApiError, getApiErrorMessages, getApiErrorState, setAlternateResponse } from './response/index.cjs';
|
|
2
2
|
export { A as API_Res_Base, a as API_Res_Error, b as API_Res_Pagination, c as API_Res_Status } from './types-Djyp4Jr-.cjs';
|
|
3
3
|
export { API_FetchWithBodyParams, API_FetchWithBodyResponseFallback, API_GenerateQueryUrlParams, API_GetFetchOptionsParams, fetchWithBody, generateQueryUrl, getFetchOptions, getQueryString, getRouteUrl, nextAPILog } from './request/index.cjs';
|
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export { setAlternateResponse } from './response/index.js';
|
|
1
|
+
export { getApiError, getApiErrorMessages, getApiErrorState, setAlternateResponse } from './response/index.js';
|
|
2
2
|
export { A as API_Res_Base, a as API_Res_Error, b as API_Res_Pagination, c as API_Res_Status } from './types-Djyp4Jr-.js';
|
|
3
3
|
export { API_FetchWithBodyParams, API_FetchWithBodyResponseFallback, API_GenerateQueryUrlParams, API_GetFetchOptionsParams, fetchWithBody, generateQueryUrl, getFetchOptions, getQueryString, getRouteUrl, nextAPILog } from './request/index.js';
|
package/dist/index.mjs
CHANGED
|
@@ -1,6 +1,21 @@
|
|
|
1
1
|
import { convertObjectToSearchParams } from '@uniai-fe/util-functions';
|
|
2
2
|
|
|
3
3
|
// src/response/module.ts
|
|
4
|
+
var API_IDLE_STATUS = "idle";
|
|
5
|
+
var isApiErrorItem = (errorValue) => {
|
|
6
|
+
if (!errorValue || typeof errorValue !== "object") {
|
|
7
|
+
return false;
|
|
8
|
+
}
|
|
9
|
+
const nextError = errorValue;
|
|
10
|
+
return typeof nextError.field_name === "string" && typeof nextError.message === "string";
|
|
11
|
+
};
|
|
12
|
+
var isApiBaseResponse = (payload) => {
|
|
13
|
+
if (!payload || typeof payload !== "object") {
|
|
14
|
+
return false;
|
|
15
|
+
}
|
|
16
|
+
const nextPayload = payload;
|
|
17
|
+
return typeof nextPayload.status === "string" && Array.isArray(nextPayload.errors) && nextPayload.errors.every(isApiErrorItem);
|
|
18
|
+
};
|
|
4
19
|
var setAlternateResponse = (errorMessage, data) => ({
|
|
5
20
|
status: "fail",
|
|
6
21
|
errors: [
|
|
@@ -8,6 +23,28 @@ var setAlternateResponse = (errorMessage, data) => ({
|
|
|
8
23
|
],
|
|
9
24
|
data
|
|
10
25
|
});
|
|
26
|
+
var getApiErrorState = (payload) => isApiBaseResponse(payload) ? payload.status : void 0;
|
|
27
|
+
var getApiErrorMessages = (payload) => {
|
|
28
|
+
if (!isApiBaseResponse(payload)) {
|
|
29
|
+
return [];
|
|
30
|
+
}
|
|
31
|
+
return payload.errors.map((errorItem) => errorItem.message.trim()).filter(Boolean);
|
|
32
|
+
};
|
|
33
|
+
var getApiError = (response, payload) => {
|
|
34
|
+
const state = getApiErrorState(payload);
|
|
35
|
+
const messages = getApiErrorMessages(payload);
|
|
36
|
+
const hasFailedStatusCode = response.status !== 200;
|
|
37
|
+
const hasFailedState = typeof state === "string" && !["success", API_IDLE_STATUS].includes(state);
|
|
38
|
+
const hasFailedMessage = messages.length > 0;
|
|
39
|
+
if (!hasFailedStatusCode && !hasFailedState && !hasFailedMessage) {
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
return {
|
|
43
|
+
code: response.status,
|
|
44
|
+
state,
|
|
45
|
+
message: messages.join(" | ") || response.statusText || void 0
|
|
46
|
+
};
|
|
47
|
+
};
|
|
11
48
|
var getQueryString = (searchParams) => {
|
|
12
49
|
const serialized = convertObjectToSearchParams(searchParams, {
|
|
13
50
|
function: "getQueryString"
|
|
@@ -142,6 +179,6 @@ var fetchWithBody = async ({
|
|
|
142
179
|
}
|
|
143
180
|
};
|
|
144
181
|
|
|
145
|
-
export { fetchWithBody, generateQueryUrl, getFetchOptions, getQueryString, getRouteUrl, nextAPILog, setAlternateResponse };
|
|
182
|
+
export { fetchWithBody, generateQueryUrl, getApiError, getApiErrorMessages, getApiErrorState, getFetchOptions, getQueryString, getRouteUrl, nextAPILog, setAlternateResponse };
|
|
146
183
|
//# sourceMappingURL=index.mjs.map
|
|
147
184
|
//# sourceMappingURL=index.mjs.map
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/response/module.ts","../src/request/module.ts"],"names":[],"mappings":"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","file":"index.mjs","sourcesContent":["import type { API_Res_Base } from \"./types\";\n\nexport const setAlternateResponse = <ResponseDataType>(\n errorMessage: string,\n data: ResponseDataType,\n): API_Res_Base<ResponseDataType> => ({\n status: \"fail\",\n errors: [\n { field_name: \"\", message: errorMessage || \"데이터 조회에 실패했습니다.\" },\n ],\n data,\n});\n","import { convertObjectToSearchParams } from \"@uniai-fe/util-functions\";\nimport type {\n API_FetchWithBodyParams,\n API_GetFetchOptionsParams,\n API_GenerateQueryUrlParams,\n} from \"./types\";\n\n/**\n * API Request Utils; 쿼리스트링 생성\n * @param {unknown} [searchParams] 쿼리스트링 변환 대상\n * @returns {string} 직렬화된 쿼리스트링\n * @example\n * const query = getQueryString({ farm_id: 1 });\n */\nexport const getQueryString = (searchParams?: unknown): string => {\n // 변경: util-functions 공통 유틸을 재사용해 query 변환 규칙을 단일화한다.\n const serialized = convertObjectToSearchParams(searchParams, {\n function: \"getQueryString\",\n }).toString();\n return serialized ? `?${serialized}` : \"\";\n};\n\n/**\n * API Request Utils; Next.js route 디버깅 로그 출력\n * @param {string} method HTTP method 문자열\n * @param {string} routeUrl frontend route URL\n * @param {string} [queryUrl] backend query URL\n * @param {unknown[]} messages 로그 메시지\n */\nexport const nextAPILog = (\n method: string,\n routeUrl: string,\n queryUrl?: string,\n ...messages: unknown[]\n) => {\n // 2026-03-19: 배포 환경에서의 모니터링 및 디버깅을 위한 서버 로그 확인을 위해 주석처리함\n // if (process.env.NODE_ENV === \"production\") {\n // return;\n // }\n\n // 변경: util-api 단독 동작을 위해 날짜 포맷 의존성을 내부 계산으로 대체한다.\n const date = new Date();\n const dateText = date.toISOString().split(\"T\")[0] ?? \"\";\n const timeText = `${date.toLocaleTimeString(\"en-US\", { hour12: false })}.${date.getMilliseconds()}`;\n const requestMethod = method.split(\"-\")[0]?.toUpperCase() || \"-\";\n const responseMethod = method.split(\"-\")[1]?.toUpperCase() || requestMethod;\n\n return console.log(\n `\\n`,\n `[Next Server API] ⏱ ${dateText} ( ${timeText} )`,\n `\\n λ [${requestMethod}] FE route`,\n `\\n ${routeUrl}`,\n ...(queryUrl\n ? [`\\n ═⏵ Ω [${responseMethod}] BE url`, `\\n ${queryUrl}`, `\\n`]\n : []),\n ...(messages?.[0] ? [` ◇-`, ...messages] : []),\n `\\n`,\n );\n};\n\n/**\n * API Request Utils; 클라이언트 요청 URL 생성\n * @param {string} routeUrl next.js API URL 또는 요청 경로\n * @param {URLSearchParams | object} [searchParams] 쿼리스트링 원본\n */\nexport const getRouteUrl = (\n routeUrl: string,\n searchParams?: URLSearchParams | object,\n) => `${routeUrl}${getQueryString(searchParams)}`;\n\n/**\n * API Request Utils; GET API 요청 URL 생성\n * @param {API_GenerateQueryUrlParams} params URL 생성 파라미터\n * @property {string} [params.method] fetch HTTP method\n * @property {string} params.domain API 도메인\n * @property {string} params.routeUrl frontend route URL\n * @property {string} params.queryUrl backend query URL\n * @property {URLSearchParams | object} [params.searchParams] 쿼리스트링 원본\n * @property {object} [params.log] 디버깅 로그 객체\n * @property {boolean} [params.logDisabled] 로그 비활성화 여부\n * @returns {string} 완성된 요청 URL\n * @example\n * const url = generateQueryUrl({ domain, routeUrl, queryUrl });\n */\nexport const generateQueryUrl = ({\n method = \"GET\",\n domain,\n routeUrl,\n queryUrl,\n searchParams,\n log,\n logDisabled,\n}: API_GenerateQueryUrlParams): string => {\n const url = `${domain}${queryUrl}${getQueryString(searchParams)}`;\n\n if (!logDisabled) {\n nextAPILog(method, routeUrl, url, {\n ...(log ?? {}),\n ...(searchParams ?? {}),\n });\n }\n\n return url;\n};\n\n/**\n * API Request Utils; fetch 요청 옵션 생성\n * @param {API_GetFetchOptionsParams} params 요청 옵션 파라미터\n * @property {string} params.method HTTP method 문자열\n * @property {HeadersInit} [params.headers] 요청 헤더\n * @property {BodyInit | null} [params.body] 요청 body\n * @returns {RequestInit} fetch 요청 옵션 객체\n * @example\n * const option = getFetchOptions({\n * method: \"POST\",\n * headers: { \"Content-Type\": \"application/json\" },\n * body: JSON.stringify({ farm_id: 1 }),\n * });\n */\nexport const getFetchOptions = ({\n method,\n headers,\n body,\n}: API_GetFetchOptionsParams): RequestInit => ({\n method,\n // 변경: Headers 인스턴스는 Object.keys로 비어 보일 수 있어 정의 여부만으로 유지한다.\n ...(typeof headers === \"undefined\" ? {} : { headers }),\n ...(typeof body === \"undefined\" ? {} : { body }),\n});\n\n/**\n * API Request Utils; body 기반 fetch 요청\n * @template BodyDataType\n * @template ResponseType\n * @param {API_FetchWithBodyParams<BodyDataType, ResponseType>} params 요청 파라미터\n * @property {string} params.domain API 도메인\n * @property {string} params.method HTTP method 문자열\n * @property {string} params.routeUrl frontend route URL\n * @property {string} params.queryUrl backend query URL\n * @property {ResponseType} params.alternateResponse 실패 시 대체 응답\n * @property {URLSearchParams | object} [params.searchParams] 쿼리스트링 원본\n * @property {HeadersInit} [params.headers] fetch headers\n * @property {BodyInit | null} [params.body] fetch body\n * @property {BodyDataType} [params.bodyData] body 데이터\n * @property {boolean} [params.isRawResponse] raw response 반환 여부\n * @property {object} [params.debug] 디버그 로그 객체\n * @property {boolean} [params.disabled] fetch 비활성화 여부\n * @property {boolean} [params.disabledLog] 로그 비활성화 여부\n * @returns {Promise<ResponseType>} 응답 데이터 또는 alternateResponse\n * @example\n * const response = await fetchWithBody({ domain, method: \"POST\", routeUrl, queryUrl, alternateResponse });\n */\nexport const fetchWithBody = async <\n BodyDataType = object,\n ResponseType extends object | Response = Response,\n>({\n domain,\n method,\n routeUrl,\n queryUrl,\n searchParams,\n headers,\n body,\n bodyData,\n isRawResponse,\n alternateResponse,\n debug,\n disabled,\n disabledLog,\n}: API_FetchWithBodyParams<\n BodyDataType,\n ResponseType\n>): Promise<ResponseType> => {\n const url = `${domain}${queryUrl}${getQueryString(searchParams)}`;\n const option = getFetchOptions({ method, headers, body });\n\n if (!body && typeof bodyData !== \"undefined\") {\n // 변경: util-functions 공통 유틸을 재사용해 body 직렬화 규칙을 단일화한다.\n const bodyParams = convertObjectToSearchParams(bodyData, {\n function: \"fetchWithBody\",\n method,\n domain,\n routeUrl,\n queryUrl,\n searchParams,\n }).toString();\n if (bodyParams === \"\") {\n nextAPILog(method.toLowerCase(), routeUrl, url, {\n state: \"ERROR (BODY - DATA)\",\n error: \"데이터가 유효하지 않습니다.\",\n bodyData,\n ...(debug ?? {}),\n });\n return alternateResponse;\n }\n option.body = bodyData as BodyInit;\n }\n\n if (!disabledLog) {\n nextAPILog(method.toLowerCase(), routeUrl, url, {\n state: \"READY\",\n ...option,\n ...(debug ?? {}),\n });\n }\n\n if (disabled) {\n nextAPILog(method.toLowerCase(), routeUrl, url, {\n state: \"FETCH DISABLED\",\n message: \"API 요청제한 활성화됨.\",\n });\n return alternateResponse;\n }\n\n try {\n const responseRaw = await fetch(url, option);\n const responseCode = responseRaw.status;\n\n if (!disabledLog) {\n nextAPILog(method.toLowerCase(), routeUrl, url, {\n state: responseCode === 200 ? \"SUCCESS\" : \"FAIL\",\n code: responseCode,\n });\n }\n\n if (isRawResponse) {\n return responseRaw as ResponseType;\n }\n return (await responseRaw.json()) as ResponseType;\n } catch (error: unknown) {\n if (!disabledLog) {\n nextAPILog(method.toLowerCase(), routeUrl, url, {\n state: \"ERROR (RESPONSE)\",\n error,\n ...(debug ?? {}),\n });\n }\n return alternateResponse;\n }\n};\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/response/module.ts","../src/request/module.ts"],"names":[],"mappings":"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","file":"index.mjs","sourcesContent":["import type { API_Res_Base, API_Res_Error } from \"./types\";\n\nconst API_IDLE_STATUS = \"idle\";\n\n/**\n * API Response Utility; 에러 item 판별\n * @param {unknown} errorValue 검사 대상 값\n * @returns {boolean} API error item 여부\n * @example\n * const isApiError = isApiErrorItem({ field_name: \"email\", message: \"필수값\" });\n */\nconst isApiErrorItem = (errorValue: unknown): errorValue is API_Res_Error => {\n if (!errorValue || typeof errorValue !== \"object\") {\n return false;\n }\n\n const nextError = errorValue as Partial<API_Res_Error>;\n\n return (\n typeof nextError.field_name === \"string\" &&\n typeof nextError.message === \"string\"\n );\n};\n\n/**\n * API Response Utility; Base 응답 판별\n * @param {unknown} payload 검사 대상 payload\n * @returns {boolean} API_Res_Base 형태 여부\n * @example\n * const isApiBase = isApiBaseResponse(payload);\n */\nconst isApiBaseResponse = (\n payload: unknown,\n): payload is API_Res_Base<unknown> => {\n if (!payload || typeof payload !== \"object\") {\n return false;\n }\n\n const nextPayload = payload as Partial<API_Res_Base<unknown>>;\n\n return (\n typeof nextPayload.status === \"string\" &&\n Array.isArray(nextPayload.errors) &&\n nextPayload.errors.every(isApiErrorItem)\n );\n};\n\nexport const setAlternateResponse = <ResponseDataType>(\n errorMessage: string,\n data: ResponseDataType,\n): API_Res_Base<ResponseDataType> => ({\n status: \"fail\",\n errors: [\n { field_name: \"\", message: errorMessage || \"데이터 조회에 실패했습니다.\" },\n ],\n data,\n});\n\n/**\n * API Response Utility; 응답 status 추출\n * @param {unknown} payload 응답 payload\n * @returns {string | undefined} API layer status\n * @example\n * const status = getApiErrorState(payload);\n */\nexport const getApiErrorState = (payload: unknown): string | undefined =>\n isApiBaseResponse(payload) ? payload.status : undefined;\n\n/**\n * API Response Utility; 응답 에러 메시지 목록 추출\n * @param {unknown} payload 응답 payload\n * @returns {string[]} 비어 있지 않은 에러 메시지 목록\n * @example\n * const messages = getApiErrorMessages(payload);\n */\nexport const getApiErrorMessages = (payload: unknown): string[] => {\n if (!isApiBaseResponse(payload)) {\n return [];\n }\n\n return payload.errors\n .map(errorItem => errorItem.message.trim())\n .filter(Boolean);\n};\n\n/**\n * API Response Utility; 응답 오류 요약 추출\n * @param {Response} response fetch 응답 객체\n * @param {unknown} payload 응답 payload\n * @returns {{ code: number; state?: string; message?: string } | null} 수집 대상 오류 요약\n * @example\n * const apiError = getApiError(response, payload);\n */\nexport const getApiError = (\n response: Response,\n payload: unknown,\n): {\n code: number;\n state?: string;\n message?: string;\n} | null => {\n const state = getApiErrorState(payload);\n const messages = getApiErrorMessages(payload);\n const hasFailedStatusCode = response.status !== 200;\n const hasFailedState =\n typeof state === \"string\" && ![\"success\", API_IDLE_STATUS].includes(state);\n const hasFailedMessage = messages.length > 0;\n\n if (!hasFailedStatusCode && !hasFailedState && !hasFailedMessage) {\n return null;\n }\n\n return {\n code: response.status,\n state,\n message: messages.join(\" | \") || response.statusText || undefined,\n };\n};\n","import { convertObjectToSearchParams } from \"@uniai-fe/util-functions\";\nimport type {\n API_FetchWithBodyParams,\n API_GetFetchOptionsParams,\n API_GenerateQueryUrlParams,\n} from \"./types\";\n\n/**\n * API Request Utils; 쿼리스트링 생성\n * @param {unknown} [searchParams] 쿼리스트링 변환 대상\n * @returns {string} 직렬화된 쿼리스트링\n * @example\n * const query = getQueryString({ farm_id: 1 });\n */\nexport const getQueryString = (searchParams?: unknown): string => {\n // 변경: util-functions 공통 유틸을 재사용해 query 변환 규칙을 단일화한다.\n const serialized = convertObjectToSearchParams(searchParams, {\n function: \"getQueryString\",\n }).toString();\n return serialized ? `?${serialized}` : \"\";\n};\n\n/**\n * API Request Utils; Next.js route 디버깅 로그 출력\n * @param {string} method HTTP method 문자열\n * @param {string} routeUrl frontend route URL\n * @param {string} [queryUrl] backend query URL\n * @param {unknown[]} messages 로그 메시지\n */\nexport const nextAPILog = (\n method: string,\n routeUrl: string,\n queryUrl?: string,\n ...messages: unknown[]\n) => {\n // 2026-03-19: 배포 환경에서의 모니터링 및 디버깅을 위한 서버 로그 확인을 위해 주석처리함\n // if (process.env.NODE_ENV === \"production\") {\n // return;\n // }\n\n // 변경: util-api 단독 동작을 위해 날짜 포맷 의존성을 내부 계산으로 대체한다.\n const date = new Date();\n const dateText = date.toISOString().split(\"T\")[0] ?? \"\";\n const timeText = `${date.toLocaleTimeString(\"en-US\", { hour12: false })}.${date.getMilliseconds()}`;\n const requestMethod = method.split(\"-\")[0]?.toUpperCase() || \"-\";\n const responseMethod = method.split(\"-\")[1]?.toUpperCase() || requestMethod;\n\n return console.log(\n `\\n`,\n `[Next Server API] ⏱ ${dateText} ( ${timeText} )`,\n `\\n λ [${requestMethod}] FE route`,\n `\\n ${routeUrl}`,\n ...(queryUrl\n ? [`\\n ═⏵ Ω [${responseMethod}] BE url`, `\\n ${queryUrl}`, `\\n`]\n : []),\n ...(messages?.[0] ? [` ◇-`, ...messages] : []),\n `\\n`,\n );\n};\n\n/**\n * API Request Utils; 클라이언트 요청 URL 생성\n * @param {string} routeUrl next.js API URL 또는 요청 경로\n * @param {URLSearchParams | object} [searchParams] 쿼리스트링 원본\n */\nexport const getRouteUrl = (\n routeUrl: string,\n searchParams?: URLSearchParams | object,\n) => `${routeUrl}${getQueryString(searchParams)}`;\n\n/**\n * API Request Utils; GET API 요청 URL 생성\n * @param {API_GenerateQueryUrlParams} params URL 생성 파라미터\n * @property {string} [params.method] fetch HTTP method\n * @property {string} params.domain API 도메인\n * @property {string} params.routeUrl frontend route URL\n * @property {string} params.queryUrl backend query URL\n * @property {URLSearchParams | object} [params.searchParams] 쿼리스트링 원본\n * @property {object} [params.log] 디버깅 로그 객체\n * @property {boolean} [params.logDisabled] 로그 비활성화 여부\n * @returns {string} 완성된 요청 URL\n * @example\n * const url = generateQueryUrl({ domain, routeUrl, queryUrl });\n */\nexport const generateQueryUrl = ({\n method = \"GET\",\n domain,\n routeUrl,\n queryUrl,\n searchParams,\n log,\n logDisabled,\n}: API_GenerateQueryUrlParams): string => {\n const url = `${domain}${queryUrl}${getQueryString(searchParams)}`;\n\n if (!logDisabled) {\n nextAPILog(method, routeUrl, url, {\n ...(log ?? {}),\n ...(searchParams ?? {}),\n });\n }\n\n return url;\n};\n\n/**\n * API Request Utils; fetch 요청 옵션 생성\n * @param {API_GetFetchOptionsParams} params 요청 옵션 파라미터\n * @property {string} params.method HTTP method 문자열\n * @property {HeadersInit} [params.headers] 요청 헤더\n * @property {BodyInit | null} [params.body] 요청 body\n * @returns {RequestInit} fetch 요청 옵션 객체\n * @example\n * const option = getFetchOptions({\n * method: \"POST\",\n * headers: { \"Content-Type\": \"application/json\" },\n * body: JSON.stringify({ farm_id: 1 }),\n * });\n */\nexport const getFetchOptions = ({\n method,\n headers,\n body,\n}: API_GetFetchOptionsParams): RequestInit => ({\n method,\n // 변경: Headers 인스턴스는 Object.keys로 비어 보일 수 있어 정의 여부만으로 유지한다.\n ...(typeof headers === \"undefined\" ? {} : { headers }),\n ...(typeof body === \"undefined\" ? {} : { body }),\n});\n\n/**\n * API Request Utils; body 기반 fetch 요청\n * @template BodyDataType\n * @template ResponseType\n * @param {API_FetchWithBodyParams<BodyDataType, ResponseType>} params 요청 파라미터\n * @property {string} params.domain API 도메인\n * @property {string} params.method HTTP method 문자열\n * @property {string} params.routeUrl frontend route URL\n * @property {string} params.queryUrl backend query URL\n * @property {ResponseType} params.alternateResponse 실패 시 대체 응답\n * @property {URLSearchParams | object} [params.searchParams] 쿼리스트링 원본\n * @property {HeadersInit} [params.headers] fetch headers\n * @property {BodyInit | null} [params.body] fetch body\n * @property {BodyDataType} [params.bodyData] body 데이터\n * @property {boolean} [params.isRawResponse] raw response 반환 여부\n * @property {object} [params.debug] 디버그 로그 객체\n * @property {boolean} [params.disabled] fetch 비활성화 여부\n * @property {boolean} [params.disabledLog] 로그 비활성화 여부\n * @returns {Promise<ResponseType>} 응답 데이터 또는 alternateResponse\n * @example\n * const response = await fetchWithBody({ domain, method: \"POST\", routeUrl, queryUrl, alternateResponse });\n */\nexport const fetchWithBody = async <\n BodyDataType = object,\n ResponseType extends object | Response = Response,\n>({\n domain,\n method,\n routeUrl,\n queryUrl,\n searchParams,\n headers,\n body,\n bodyData,\n isRawResponse,\n alternateResponse,\n debug,\n disabled,\n disabledLog,\n}: API_FetchWithBodyParams<\n BodyDataType,\n ResponseType\n>): Promise<ResponseType> => {\n const url = `${domain}${queryUrl}${getQueryString(searchParams)}`;\n const option = getFetchOptions({ method, headers, body });\n\n if (!body && typeof bodyData !== \"undefined\") {\n // 변경: util-functions 공통 유틸을 재사용해 body 직렬화 규칙을 단일화한다.\n const bodyParams = convertObjectToSearchParams(bodyData, {\n function: \"fetchWithBody\",\n method,\n domain,\n routeUrl,\n queryUrl,\n searchParams,\n }).toString();\n if (bodyParams === \"\") {\n nextAPILog(method.toLowerCase(), routeUrl, url, {\n state: \"ERROR (BODY - DATA)\",\n error: \"데이터가 유효하지 않습니다.\",\n bodyData,\n ...(debug ?? {}),\n });\n return alternateResponse;\n }\n option.body = bodyData as BodyInit;\n }\n\n if (!disabledLog) {\n nextAPILog(method.toLowerCase(), routeUrl, url, {\n state: \"READY\",\n ...option,\n ...(debug ?? {}),\n });\n }\n\n if (disabled) {\n nextAPILog(method.toLowerCase(), routeUrl, url, {\n state: \"FETCH DISABLED\",\n message: \"API 요청제한 활성화됨.\",\n });\n return alternateResponse;\n }\n\n try {\n const responseRaw = await fetch(url, option);\n const responseCode = responseRaw.status;\n\n if (!disabledLog) {\n nextAPILog(method.toLowerCase(), routeUrl, url, {\n state: responseCode === 200 ? \"SUCCESS\" : \"FAIL\",\n code: responseCode,\n });\n }\n\n if (isRawResponse) {\n return responseRaw as ResponseType;\n }\n return (await responseRaw.json()) as ResponseType;\n } catch (error: unknown) {\n if (!disabledLog) {\n nextAPILog(method.toLowerCase(), routeUrl, url, {\n state: \"ERROR (RESPONSE)\",\n error,\n ...(debug ?? {}),\n });\n }\n return alternateResponse;\n }\n};\n"]}
|
package/dist/response/index.cjs
CHANGED
|
@@ -1,6 +1,21 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
// src/response/module.ts
|
|
4
|
+
var API_IDLE_STATUS = "idle";
|
|
5
|
+
var isApiErrorItem = (errorValue) => {
|
|
6
|
+
if (!errorValue || typeof errorValue !== "object") {
|
|
7
|
+
return false;
|
|
8
|
+
}
|
|
9
|
+
const nextError = errorValue;
|
|
10
|
+
return typeof nextError.field_name === "string" && typeof nextError.message === "string";
|
|
11
|
+
};
|
|
12
|
+
var isApiBaseResponse = (payload) => {
|
|
13
|
+
if (!payload || typeof payload !== "object") {
|
|
14
|
+
return false;
|
|
15
|
+
}
|
|
16
|
+
const nextPayload = payload;
|
|
17
|
+
return typeof nextPayload.status === "string" && Array.isArray(nextPayload.errors) && nextPayload.errors.every(isApiErrorItem);
|
|
18
|
+
};
|
|
4
19
|
var setAlternateResponse = (errorMessage, data) => ({
|
|
5
20
|
status: "fail",
|
|
6
21
|
errors: [
|
|
@@ -8,7 +23,32 @@ var setAlternateResponse = (errorMessage, data) => ({
|
|
|
8
23
|
],
|
|
9
24
|
data
|
|
10
25
|
});
|
|
26
|
+
var getApiErrorState = (payload) => isApiBaseResponse(payload) ? payload.status : void 0;
|
|
27
|
+
var getApiErrorMessages = (payload) => {
|
|
28
|
+
if (!isApiBaseResponse(payload)) {
|
|
29
|
+
return [];
|
|
30
|
+
}
|
|
31
|
+
return payload.errors.map((errorItem) => errorItem.message.trim()).filter(Boolean);
|
|
32
|
+
};
|
|
33
|
+
var getApiError = (response, payload) => {
|
|
34
|
+
const state = getApiErrorState(payload);
|
|
35
|
+
const messages = getApiErrorMessages(payload);
|
|
36
|
+
const hasFailedStatusCode = response.status !== 200;
|
|
37
|
+
const hasFailedState = typeof state === "string" && !["success", API_IDLE_STATUS].includes(state);
|
|
38
|
+
const hasFailedMessage = messages.length > 0;
|
|
39
|
+
if (!hasFailedStatusCode && !hasFailedState && !hasFailedMessage) {
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
return {
|
|
43
|
+
code: response.status,
|
|
44
|
+
state,
|
|
45
|
+
message: messages.join(" | ") || response.statusText || void 0
|
|
46
|
+
};
|
|
47
|
+
};
|
|
11
48
|
|
|
49
|
+
exports.getApiError = getApiError;
|
|
50
|
+
exports.getApiErrorMessages = getApiErrorMessages;
|
|
51
|
+
exports.getApiErrorState = getApiErrorState;
|
|
12
52
|
exports.setAlternateResponse = setAlternateResponse;
|
|
13
53
|
//# sourceMappingURL=index.cjs.map
|
|
14
54
|
//# sourceMappingURL=index.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/response/module.ts"],"names":[],"mappings":";;;AAEO,IAAM,oBAAA,GAAuB,CAClC,YAAA,EACA,IAAA,MACoC;AAAA,EACpC,MAAA,EAAQ,MAAA;AAAA,EACR,MAAA,EAAQ;AAAA,IACN,EAAE,UAAA,EAAY,EAAA,EAAI,OAAA,EAAS,gBAAgB,6EAAA;AAAkB,GAC/D;AAAA,EACA;AACF,CAAA","file":"index.cjs","sourcesContent":["import type { API_Res_Base } from \"./types\";\n\nexport const setAlternateResponse = <ResponseDataType>(\n errorMessage: string,\n data: ResponseDataType,\n): API_Res_Base<ResponseDataType> => ({\n status: \"fail\",\n errors: [\n { field_name: \"\", message: errorMessage || \"데이터 조회에 실패했습니다.\" },\n ],\n data,\n});\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/response/module.ts"],"names":[],"mappings":";;;AAEA,IAAM,eAAA,GAAkB,MAAA;AASxB,IAAM,cAAA,GAAiB,CAAC,UAAA,KAAqD;AAC3E,EAAA,IAAI,CAAC,UAAA,IAAc,OAAO,UAAA,KAAe,QAAA,EAAU;AACjD,IAAA,OAAO,KAAA;AAAA,EACT;AAEA,EAAA,MAAM,SAAA,GAAY,UAAA;AAElB,EAAA,OACE,OAAO,SAAA,CAAU,UAAA,KAAe,QAAA,IAChC,OAAO,UAAU,OAAA,KAAY,QAAA;AAEjC,CAAA;AASA,IAAM,iBAAA,GAAoB,CACxB,OAAA,KACqC;AACrC,EAAA,IAAI,CAAC,OAAA,IAAW,OAAO,OAAA,KAAY,QAAA,EAAU;AAC3C,IAAA,OAAO,KAAA;AAAA,EACT;AAEA,EAAA,MAAM,WAAA,GAAc,OAAA;AAEpB,EAAA,OACE,OAAO,WAAA,CAAY,MAAA,KAAW,QAAA,IAC9B,KAAA,CAAM,OAAA,CAAQ,WAAA,CAAY,MAAM,CAAA,IAChC,WAAA,CAAY,MAAA,CAAO,KAAA,CAAM,cAAc,CAAA;AAE3C,CAAA;AAEO,IAAM,oBAAA,GAAuB,CAClC,YAAA,EACA,IAAA,MACoC;AAAA,EACpC,MAAA,EAAQ,MAAA;AAAA,EACR,MAAA,EAAQ;AAAA,IACN,EAAE,UAAA,EAAY,EAAA,EAAI,OAAA,EAAS,gBAAgB,6EAAA;AAAkB,GAC/D;AAAA,EACA;AACF,CAAA;AASO,IAAM,mBAAmB,CAAC,OAAA,KAC/B,kBAAkB,OAAO,CAAA,GAAI,QAAQ,MAAA,GAAS;AASzC,IAAM,mBAAA,GAAsB,CAAC,OAAA,KAA+B;AACjE,EAAA,IAAI,CAAC,iBAAA,CAAkB,OAAO,CAAA,EAAG;AAC/B,IAAA,OAAO,EAAC;AAAA,EACV;AAEA,EAAA,OAAO,OAAA,CAAQ,MAAA,CACZ,GAAA,CAAI,CAAA,SAAA,KAAa,SAAA,CAAU,QAAQ,IAAA,EAAM,CAAA,CACzC,MAAA,CAAO,OAAO,CAAA;AACnB;AAUO,IAAM,WAAA,GAAc,CACzB,QAAA,EACA,OAAA,KAKU;AACV,EAAA,MAAM,KAAA,GAAQ,iBAAiB,OAAO,CAAA;AACtC,EAAA,MAAM,QAAA,GAAW,oBAAoB,OAAO,CAAA;AAC5C,EAAA,MAAM,mBAAA,GAAsB,SAAS,MAAA,KAAW,GAAA;AAChD,EAAA,MAAM,cAAA,GACJ,OAAO,KAAA,KAAU,QAAA,IAAY,CAAC,CAAC,SAAA,EAAW,eAAe,CAAA,CAAE,QAAA,CAAS,KAAK,CAAA;AAC3E,EAAA,MAAM,gBAAA,GAAmB,SAAS,MAAA,GAAS,CAAA;AAE3C,EAAA,IAAI,CAAC,mBAAA,IAAuB,CAAC,cAAA,IAAkB,CAAC,gBAAA,EAAkB;AAChE,IAAA,OAAO,IAAA;AAAA,EACT;AAEA,EAAA,OAAO;AAAA,IACL,MAAM,QAAA,CAAS,MAAA;AAAA,IACf,KAAA;AAAA,IACA,SAAS,QAAA,CAAS,IAAA,CAAK,KAAK,CAAA,IAAK,SAAS,UAAA,IAAc;AAAA,GAC1D;AACF","file":"index.cjs","sourcesContent":["import type { API_Res_Base, API_Res_Error } from \"./types\";\n\nconst API_IDLE_STATUS = \"idle\";\n\n/**\n * API Response Utility; 에러 item 판별\n * @param {unknown} errorValue 검사 대상 값\n * @returns {boolean} API error item 여부\n * @example\n * const isApiError = isApiErrorItem({ field_name: \"email\", message: \"필수값\" });\n */\nconst isApiErrorItem = (errorValue: unknown): errorValue is API_Res_Error => {\n if (!errorValue || typeof errorValue !== \"object\") {\n return false;\n }\n\n const nextError = errorValue as Partial<API_Res_Error>;\n\n return (\n typeof nextError.field_name === \"string\" &&\n typeof nextError.message === \"string\"\n );\n};\n\n/**\n * API Response Utility; Base 응답 판별\n * @param {unknown} payload 검사 대상 payload\n * @returns {boolean} API_Res_Base 형태 여부\n * @example\n * const isApiBase = isApiBaseResponse(payload);\n */\nconst isApiBaseResponse = (\n payload: unknown,\n): payload is API_Res_Base<unknown> => {\n if (!payload || typeof payload !== \"object\") {\n return false;\n }\n\n const nextPayload = payload as Partial<API_Res_Base<unknown>>;\n\n return (\n typeof nextPayload.status === \"string\" &&\n Array.isArray(nextPayload.errors) &&\n nextPayload.errors.every(isApiErrorItem)\n );\n};\n\nexport const setAlternateResponse = <ResponseDataType>(\n errorMessage: string,\n data: ResponseDataType,\n): API_Res_Base<ResponseDataType> => ({\n status: \"fail\",\n errors: [\n { field_name: \"\", message: errorMessage || \"데이터 조회에 실패했습니다.\" },\n ],\n data,\n});\n\n/**\n * API Response Utility; 응답 status 추출\n * @param {unknown} payload 응답 payload\n * @returns {string | undefined} API layer status\n * @example\n * const status = getApiErrorState(payload);\n */\nexport const getApiErrorState = (payload: unknown): string | undefined =>\n isApiBaseResponse(payload) ? payload.status : undefined;\n\n/**\n * API Response Utility; 응답 에러 메시지 목록 추출\n * @param {unknown} payload 응답 payload\n * @returns {string[]} 비어 있지 않은 에러 메시지 목록\n * @example\n * const messages = getApiErrorMessages(payload);\n */\nexport const getApiErrorMessages = (payload: unknown): string[] => {\n if (!isApiBaseResponse(payload)) {\n return [];\n }\n\n return payload.errors\n .map(errorItem => errorItem.message.trim())\n .filter(Boolean);\n};\n\n/**\n * API Response Utility; 응답 오류 요약 추출\n * @param {Response} response fetch 응답 객체\n * @param {unknown} payload 응답 payload\n * @returns {{ code: number; state?: string; message?: string } | null} 수집 대상 오류 요약\n * @example\n * const apiError = getApiError(response, payload);\n */\nexport const getApiError = (\n response: Response,\n payload: unknown,\n): {\n code: number;\n state?: string;\n message?: string;\n} | null => {\n const state = getApiErrorState(payload);\n const messages = getApiErrorMessages(payload);\n const hasFailedStatusCode = response.status !== 200;\n const hasFailedState =\n typeof state === \"string\" && ![\"success\", API_IDLE_STATUS].includes(state);\n const hasFailedMessage = messages.length > 0;\n\n if (!hasFailedStatusCode && !hasFailedState && !hasFailedMessage) {\n return null;\n }\n\n return {\n code: response.status,\n state,\n message: messages.join(\" | \") || response.statusText || undefined,\n };\n};\n"]}
|
|
@@ -2,5 +2,34 @@ import { A as API_Res_Base } from '../types-Djyp4Jr-.cjs';
|
|
|
2
2
|
export { a as API_Res_Error, b as API_Res_Pagination, c as API_Res_Status } from '../types-Djyp4Jr-.cjs';
|
|
3
3
|
|
|
4
4
|
declare const setAlternateResponse: <ResponseDataType>(errorMessage: string, data: ResponseDataType) => API_Res_Base<ResponseDataType>;
|
|
5
|
+
/**
|
|
6
|
+
* API Response Utility; 응답 status 추출
|
|
7
|
+
* @param {unknown} payload 응답 payload
|
|
8
|
+
* @returns {string | undefined} API layer status
|
|
9
|
+
* @example
|
|
10
|
+
* const status = getApiErrorState(payload);
|
|
11
|
+
*/
|
|
12
|
+
declare const getApiErrorState: (payload: unknown) => string | undefined;
|
|
13
|
+
/**
|
|
14
|
+
* API Response Utility; 응답 에러 메시지 목록 추출
|
|
15
|
+
* @param {unknown} payload 응답 payload
|
|
16
|
+
* @returns {string[]} 비어 있지 않은 에러 메시지 목록
|
|
17
|
+
* @example
|
|
18
|
+
* const messages = getApiErrorMessages(payload);
|
|
19
|
+
*/
|
|
20
|
+
declare const getApiErrorMessages: (payload: unknown) => string[];
|
|
21
|
+
/**
|
|
22
|
+
* API Response Utility; 응답 오류 요약 추출
|
|
23
|
+
* @param {Response} response fetch 응답 객체
|
|
24
|
+
* @param {unknown} payload 응답 payload
|
|
25
|
+
* @returns {{ code: number; state?: string; message?: string } | null} 수집 대상 오류 요약
|
|
26
|
+
* @example
|
|
27
|
+
* const apiError = getApiError(response, payload);
|
|
28
|
+
*/
|
|
29
|
+
declare const getApiError: (response: Response, payload: unknown) => {
|
|
30
|
+
code: number;
|
|
31
|
+
state?: string;
|
|
32
|
+
message?: string;
|
|
33
|
+
} | null;
|
|
5
34
|
|
|
6
|
-
export { API_Res_Base, setAlternateResponse };
|
|
35
|
+
export { API_Res_Base, getApiError, getApiErrorMessages, getApiErrorState, setAlternateResponse };
|
package/dist/response/index.d.ts
CHANGED
|
@@ -2,5 +2,34 @@ import { A as API_Res_Base } from '../types-Djyp4Jr-.js';
|
|
|
2
2
|
export { a as API_Res_Error, b as API_Res_Pagination, c as API_Res_Status } from '../types-Djyp4Jr-.js';
|
|
3
3
|
|
|
4
4
|
declare const setAlternateResponse: <ResponseDataType>(errorMessage: string, data: ResponseDataType) => API_Res_Base<ResponseDataType>;
|
|
5
|
+
/**
|
|
6
|
+
* API Response Utility; 응답 status 추출
|
|
7
|
+
* @param {unknown} payload 응답 payload
|
|
8
|
+
* @returns {string | undefined} API layer status
|
|
9
|
+
* @example
|
|
10
|
+
* const status = getApiErrorState(payload);
|
|
11
|
+
*/
|
|
12
|
+
declare const getApiErrorState: (payload: unknown) => string | undefined;
|
|
13
|
+
/**
|
|
14
|
+
* API Response Utility; 응답 에러 메시지 목록 추출
|
|
15
|
+
* @param {unknown} payload 응답 payload
|
|
16
|
+
* @returns {string[]} 비어 있지 않은 에러 메시지 목록
|
|
17
|
+
* @example
|
|
18
|
+
* const messages = getApiErrorMessages(payload);
|
|
19
|
+
*/
|
|
20
|
+
declare const getApiErrorMessages: (payload: unknown) => string[];
|
|
21
|
+
/**
|
|
22
|
+
* API Response Utility; 응답 오류 요약 추출
|
|
23
|
+
* @param {Response} response fetch 응답 객체
|
|
24
|
+
* @param {unknown} payload 응답 payload
|
|
25
|
+
* @returns {{ code: number; state?: string; message?: string } | null} 수집 대상 오류 요약
|
|
26
|
+
* @example
|
|
27
|
+
* const apiError = getApiError(response, payload);
|
|
28
|
+
*/
|
|
29
|
+
declare const getApiError: (response: Response, payload: unknown) => {
|
|
30
|
+
code: number;
|
|
31
|
+
state?: string;
|
|
32
|
+
message?: string;
|
|
33
|
+
} | null;
|
|
5
34
|
|
|
6
|
-
export { API_Res_Base, setAlternateResponse };
|
|
35
|
+
export { API_Res_Base, getApiError, getApiErrorMessages, getApiErrorState, setAlternateResponse };
|
package/dist/response/index.mjs
CHANGED
|
@@ -1,4 +1,19 @@
|
|
|
1
1
|
// src/response/module.ts
|
|
2
|
+
var API_IDLE_STATUS = "idle";
|
|
3
|
+
var isApiErrorItem = (errorValue) => {
|
|
4
|
+
if (!errorValue || typeof errorValue !== "object") {
|
|
5
|
+
return false;
|
|
6
|
+
}
|
|
7
|
+
const nextError = errorValue;
|
|
8
|
+
return typeof nextError.field_name === "string" && typeof nextError.message === "string";
|
|
9
|
+
};
|
|
10
|
+
var isApiBaseResponse = (payload) => {
|
|
11
|
+
if (!payload || typeof payload !== "object") {
|
|
12
|
+
return false;
|
|
13
|
+
}
|
|
14
|
+
const nextPayload = payload;
|
|
15
|
+
return typeof nextPayload.status === "string" && Array.isArray(nextPayload.errors) && nextPayload.errors.every(isApiErrorItem);
|
|
16
|
+
};
|
|
2
17
|
var setAlternateResponse = (errorMessage, data) => ({
|
|
3
18
|
status: "fail",
|
|
4
19
|
errors: [
|
|
@@ -6,7 +21,29 @@ var setAlternateResponse = (errorMessage, data) => ({
|
|
|
6
21
|
],
|
|
7
22
|
data
|
|
8
23
|
});
|
|
24
|
+
var getApiErrorState = (payload) => isApiBaseResponse(payload) ? payload.status : void 0;
|
|
25
|
+
var getApiErrorMessages = (payload) => {
|
|
26
|
+
if (!isApiBaseResponse(payload)) {
|
|
27
|
+
return [];
|
|
28
|
+
}
|
|
29
|
+
return payload.errors.map((errorItem) => errorItem.message.trim()).filter(Boolean);
|
|
30
|
+
};
|
|
31
|
+
var getApiError = (response, payload) => {
|
|
32
|
+
const state = getApiErrorState(payload);
|
|
33
|
+
const messages = getApiErrorMessages(payload);
|
|
34
|
+
const hasFailedStatusCode = response.status !== 200;
|
|
35
|
+
const hasFailedState = typeof state === "string" && !["success", API_IDLE_STATUS].includes(state);
|
|
36
|
+
const hasFailedMessage = messages.length > 0;
|
|
37
|
+
if (!hasFailedStatusCode && !hasFailedState && !hasFailedMessage) {
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
return {
|
|
41
|
+
code: response.status,
|
|
42
|
+
state,
|
|
43
|
+
message: messages.join(" | ") || response.statusText || void 0
|
|
44
|
+
};
|
|
45
|
+
};
|
|
9
46
|
|
|
10
|
-
export { setAlternateResponse };
|
|
47
|
+
export { getApiError, getApiErrorMessages, getApiErrorState, setAlternateResponse };
|
|
11
48
|
//# sourceMappingURL=index.mjs.map
|
|
12
49
|
//# sourceMappingURL=index.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/response/module.ts"],"names":[],"mappings":";AAEO,IAAM,oBAAA,GAAuB,CAClC,YAAA,EACA,IAAA,MACoC;AAAA,EACpC,MAAA,EAAQ,MAAA;AAAA,EACR,MAAA,EAAQ;AAAA,IACN,EAAE,UAAA,EAAY,EAAA,EAAI,OAAA,EAAS,gBAAgB,6EAAA;AAAkB,GAC/D;AAAA,EACA;AACF,CAAA","file":"index.mjs","sourcesContent":["import type { API_Res_Base } from \"./types\";\n\nexport const setAlternateResponse = <ResponseDataType>(\n errorMessage: string,\n data: ResponseDataType,\n): API_Res_Base<ResponseDataType> => ({\n status: \"fail\",\n errors: [\n { field_name: \"\", message: errorMessage || \"데이터 조회에 실패했습니다.\" },\n ],\n data,\n});\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/response/module.ts"],"names":[],"mappings":";AAEA,IAAM,eAAA,GAAkB,MAAA;AASxB,IAAM,cAAA,GAAiB,CAAC,UAAA,KAAqD;AAC3E,EAAA,IAAI,CAAC,UAAA,IAAc,OAAO,UAAA,KAAe,QAAA,EAAU;AACjD,IAAA,OAAO,KAAA;AAAA,EACT;AAEA,EAAA,MAAM,SAAA,GAAY,UAAA;AAElB,EAAA,OACE,OAAO,SAAA,CAAU,UAAA,KAAe,QAAA,IAChC,OAAO,UAAU,OAAA,KAAY,QAAA;AAEjC,CAAA;AASA,IAAM,iBAAA,GAAoB,CACxB,OAAA,KACqC;AACrC,EAAA,IAAI,CAAC,OAAA,IAAW,OAAO,OAAA,KAAY,QAAA,EAAU;AAC3C,IAAA,OAAO,KAAA;AAAA,EACT;AAEA,EAAA,MAAM,WAAA,GAAc,OAAA;AAEpB,EAAA,OACE,OAAO,WAAA,CAAY,MAAA,KAAW,QAAA,IAC9B,KAAA,CAAM,OAAA,CAAQ,WAAA,CAAY,MAAM,CAAA,IAChC,WAAA,CAAY,MAAA,CAAO,KAAA,CAAM,cAAc,CAAA;AAE3C,CAAA;AAEO,IAAM,oBAAA,GAAuB,CAClC,YAAA,EACA,IAAA,MACoC;AAAA,EACpC,MAAA,EAAQ,MAAA;AAAA,EACR,MAAA,EAAQ;AAAA,IACN,EAAE,UAAA,EAAY,EAAA,EAAI,OAAA,EAAS,gBAAgB,6EAAA;AAAkB,GAC/D;AAAA,EACA;AACF,CAAA;AASO,IAAM,mBAAmB,CAAC,OAAA,KAC/B,kBAAkB,OAAO,CAAA,GAAI,QAAQ,MAAA,GAAS;AASzC,IAAM,mBAAA,GAAsB,CAAC,OAAA,KAA+B;AACjE,EAAA,IAAI,CAAC,iBAAA,CAAkB,OAAO,CAAA,EAAG;AAC/B,IAAA,OAAO,EAAC;AAAA,EACV;AAEA,EAAA,OAAO,OAAA,CAAQ,MAAA,CACZ,GAAA,CAAI,CAAA,SAAA,KAAa,SAAA,CAAU,QAAQ,IAAA,EAAM,CAAA,CACzC,MAAA,CAAO,OAAO,CAAA;AACnB;AAUO,IAAM,WAAA,GAAc,CACzB,QAAA,EACA,OAAA,KAKU;AACV,EAAA,MAAM,KAAA,GAAQ,iBAAiB,OAAO,CAAA;AACtC,EAAA,MAAM,QAAA,GAAW,oBAAoB,OAAO,CAAA;AAC5C,EAAA,MAAM,mBAAA,GAAsB,SAAS,MAAA,KAAW,GAAA;AAChD,EAAA,MAAM,cAAA,GACJ,OAAO,KAAA,KAAU,QAAA,IAAY,CAAC,CAAC,SAAA,EAAW,eAAe,CAAA,CAAE,QAAA,CAAS,KAAK,CAAA;AAC3E,EAAA,MAAM,gBAAA,GAAmB,SAAS,MAAA,GAAS,CAAA;AAE3C,EAAA,IAAI,CAAC,mBAAA,IAAuB,CAAC,cAAA,IAAkB,CAAC,gBAAA,EAAkB;AAChE,IAAA,OAAO,IAAA;AAAA,EACT;AAEA,EAAA,OAAO;AAAA,IACL,MAAM,QAAA,CAAS,MAAA;AAAA,IACf,KAAA;AAAA,IACA,SAAS,QAAA,CAAS,IAAA,CAAK,KAAK,CAAA,IAAK,SAAS,UAAA,IAAc;AAAA,GAC1D;AACF","file":"index.mjs","sourcesContent":["import type { API_Res_Base, API_Res_Error } from \"./types\";\n\nconst API_IDLE_STATUS = \"idle\";\n\n/**\n * API Response Utility; 에러 item 판별\n * @param {unknown} errorValue 검사 대상 값\n * @returns {boolean} API error item 여부\n * @example\n * const isApiError = isApiErrorItem({ field_name: \"email\", message: \"필수값\" });\n */\nconst isApiErrorItem = (errorValue: unknown): errorValue is API_Res_Error => {\n if (!errorValue || typeof errorValue !== \"object\") {\n return false;\n }\n\n const nextError = errorValue as Partial<API_Res_Error>;\n\n return (\n typeof nextError.field_name === \"string\" &&\n typeof nextError.message === \"string\"\n );\n};\n\n/**\n * API Response Utility; Base 응답 판별\n * @param {unknown} payload 검사 대상 payload\n * @returns {boolean} API_Res_Base 형태 여부\n * @example\n * const isApiBase = isApiBaseResponse(payload);\n */\nconst isApiBaseResponse = (\n payload: unknown,\n): payload is API_Res_Base<unknown> => {\n if (!payload || typeof payload !== \"object\") {\n return false;\n }\n\n const nextPayload = payload as Partial<API_Res_Base<unknown>>;\n\n return (\n typeof nextPayload.status === \"string\" &&\n Array.isArray(nextPayload.errors) &&\n nextPayload.errors.every(isApiErrorItem)\n );\n};\n\nexport const setAlternateResponse = <ResponseDataType>(\n errorMessage: string,\n data: ResponseDataType,\n): API_Res_Base<ResponseDataType> => ({\n status: \"fail\",\n errors: [\n { field_name: \"\", message: errorMessage || \"데이터 조회에 실패했습니다.\" },\n ],\n data,\n});\n\n/**\n * API Response Utility; 응답 status 추출\n * @param {unknown} payload 응답 payload\n * @returns {string | undefined} API layer status\n * @example\n * const status = getApiErrorState(payload);\n */\nexport const getApiErrorState = (payload: unknown): string | undefined =>\n isApiBaseResponse(payload) ? payload.status : undefined;\n\n/**\n * API Response Utility; 응답 에러 메시지 목록 추출\n * @param {unknown} payload 응답 payload\n * @returns {string[]} 비어 있지 않은 에러 메시지 목록\n * @example\n * const messages = getApiErrorMessages(payload);\n */\nexport const getApiErrorMessages = (payload: unknown): string[] => {\n if (!isApiBaseResponse(payload)) {\n return [];\n }\n\n return payload.errors\n .map(errorItem => errorItem.message.trim())\n .filter(Boolean);\n};\n\n/**\n * API Response Utility; 응답 오류 요약 추출\n * @param {Response} response fetch 응답 객체\n * @param {unknown} payload 응답 payload\n * @returns {{ code: number; state?: string; message?: string } | null} 수집 대상 오류 요약\n * @example\n * const apiError = getApiError(response, payload);\n */\nexport const getApiError = (\n response: Response,\n payload: unknown,\n): {\n code: number;\n state?: string;\n message?: string;\n} | null => {\n const state = getApiErrorState(payload);\n const messages = getApiErrorMessages(payload);\n const hasFailedStatusCode = response.status !== 200;\n const hasFailedState =\n typeof state === \"string\" && ![\"success\", API_IDLE_STATUS].includes(state);\n const hasFailedMessage = messages.length > 0;\n\n if (!hasFailedStatusCode && !hasFailedState && !hasFailedMessage) {\n return null;\n }\n\n return {\n code: response.status,\n state,\n message: messages.join(\" | \") || response.statusText || undefined,\n };\n};\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@uniai-fe/util-api",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.10",
|
|
4
4
|
"description": "API contract types and framework-agnostic utilities for UNIAI FE projects",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"private": false,
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
"publishConfig": {
|
|
11
11
|
"access": "public"
|
|
12
12
|
},
|
|
13
|
-
"packageManager": "pnpm@10.
|
|
13
|
+
"packageManager": "pnpm@10.33.0",
|
|
14
14
|
"engines": {
|
|
15
15
|
"node": ">=24",
|
|
16
16
|
"pnpm": ">=10"
|