Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 55 additions & 0 deletions src/background/handlers/api/cosmeticHandler.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
export const handleCosmeticDataFetch = async (
message: any,

Check warning on line 2 in src/background/handlers/api/cosmeticHandler.ts

View workflow job for this annotation

GitHub Actions / lint-and-test

Unexpected any. Specify a different type
sender: any,

Check warning on line 3 in src/background/handlers/api/cosmeticHandler.ts

View workflow job for this annotation

GitHub Actions / lint-and-test

Unexpected any. Specify a different type
sendResponse: any,

Check warning on line 4 in src/background/handlers/api/cosmeticHandler.ts

View workflow job for this annotation

GitHub Actions / lint-and-test

Unexpected any. Specify a different type
) => {
const { productId, html } = message.payload;
Comment on lines +1 to +6
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

타입 미지정 및 async 불필요
any 사용과 async 키워드 문제는 다른 핸들러와 동일합니다. 함수 본문이 await 를 사용하지 않으므로 async 제거 후 return fetch(...); 권장드립니다.

🧰 Tools
🪛 GitHub Check: lint-and-test

[warning] 4-4:
Unexpected any. Specify a different type


[warning] 3-3:
Unexpected any. Specify a different type


[warning] 2-2:
Unexpected any. Specify a different type

🤖 Prompt for AI Agents
In src/background/handlers/api/cosmeticHandler.ts lines 1 to 6, the function
handleCosmeticDataFetch uses 'any' types for parameters and is marked async
without using await. Remove the async keyword from the function declaration and
replace 'any' types with appropriate specific types matching other handlers.
Also, change the function body to return the fetch call directly without
awaiting it.


fetch("https://voim.store/api/v1/cosmetic", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ productId, html }),
})
.then(async (res) => {
const json = await res.json();
return json;
})
.then((data) => {
const raw = data?.data;

if (!raw || typeof raw !== "object") {
console.warn("[voim][background] data.data 형식 이상함:", raw);
sendResponse({
type: "COSMETIC_DATA_ERROR",
error: "API 응답 형식 오류",
});
return;
}

sendResponse({
type: "COSMETIC_DATA_RESPONSE",
data: raw,
});

if (sender.tab?.id) {
chrome.tabs.sendMessage(sender.tab.id, {
type: "COSMETIC_DATA_RESPONSE",
data: raw,
});
}
})
.catch((err) => {
console.error("[voim][background] COSMETIC 요청 실패:", err);
sendResponse({
type: "COSMETIC_DATA_ERROR",
error: err.message,
});

if (sender.tab?.id) {
chrome.tabs.sendMessage(sender.tab.id, {
type: "COSMETIC_DATA_ERROR",
error: err.message,
});
}
});
};
56 changes: 56 additions & 0 deletions src/background/handlers/api/foodHandler.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
export const handleFoodDataFetch = async (
message: any,

Check warning on line 2 in src/background/handlers/api/foodHandler.ts

View workflow job for this annotation

GitHub Actions / lint-and-test

Unexpected any. Specify a different type
sender: any,

Check warning on line 3 in src/background/handlers/api/foodHandler.ts

View workflow job for this annotation

GitHub Actions / lint-and-test

Unexpected any. Specify a different type
sendResponse: any,

Check warning on line 4 in src/background/handlers/api/foodHandler.ts

View workflow job for this annotation

GitHub Actions / lint-and-test

Unexpected any. Specify a different type
) => {
chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => {
const activeTab = tabs[0];
if (!activeTab?.url) {
sendResponse({
status: 400,
error: "상품 페이지를 찾을 수 없습니다.",
});
return;
}

const productId = activeTab.url.match(/vp\/products\/(\d+)/)?.[1];
if (!productId) {
sendResponse({
status: 400,
error: "상품 ID를 찾을 수 없습니다.",
});
return;
}

const payload = {
...message.payload,
productId,
};

fetch("https://voim.store/api/v1/products/foods", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(payload),
}).then(async (res) => {
const text = await res.text();

try {
const json = JSON.parse(text);
if (res.ok) {
sendResponse({ status: 200, data: json });
} else {
sendResponse({
status: res.status,
error: json?.message ?? "에러 발생",
});
}
} catch (err) {

Check warning on line 47 in src/background/handlers/api/foodHandler.ts

View workflow job for this annotation

GitHub Actions / lint-and-test

'err' is defined but never used
console.error("[voim] JSON 파싱 실패", text);
sendResponse({
status: res.status,
error: "JSON 파싱 실패",
});
}
});
Comment on lines +30 to +54
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

네트워크 오류 미처리로 응답 누락 위험
fetch() 실패(오프라인, CORS 등) 시 .then 체인이 실행되지 않아 sendResponse 가 호출되지 않습니다.

 fetch("https://voim.store/api/v1/products/foods", { … })
     .then(async (res) => { … })
+    .catch((error) => {
+        console.error("[voim] FOOD DATA 네트워크 오류:", error);
+        sendResponse({ status: 500, error: "네트워크 오류" });
+    });

또한 catch 블록의 err 변수를 활용하도록 하거나 제거해 lint 경고를 해소하세요.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
fetch("https://voim.store/api/v1/products/foods", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(payload),
}).then(async (res) => {
const text = await res.text();
try {
const json = JSON.parse(text);
if (res.ok) {
sendResponse({ status: 200, data: json });
} else {
sendResponse({
status: res.status,
error: json?.message ?? "에러 발생",
});
}
} catch (err) {
console.error("[voim] JSON 파싱 실패", text);
sendResponse({
status: res.status,
error: "JSON 파싱 실패",
});
}
});
fetch("https://voim.store/api/v1/products/foods", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(payload),
}).then(async (res) => {
const text = await res.text();
try {
const json = JSON.parse(text);
if (res.ok) {
sendResponse({ status: 200, data: json });
} else {
sendResponse({
status: res.status,
error: json?.message ?? "에러 발생",
});
}
} catch (err) {
console.error("[voim] JSON 파싱 실패", text);
sendResponse({
status: res.status,
error: "JSON 파싱 실패",
});
}
}).catch((error) => {
console.error("[voim] FOOD DATA 네트워크 오류:", error);
sendResponse({ status: 500, error: "네트워크 오류" });
});
🧰 Tools
🪛 GitHub Check: lint-and-test

[warning] 47-47:
'err' is defined but never used

🤖 Prompt for AI Agents
In src/background/handlers/api/foodHandler.ts around lines 30 to 54, the fetch
call lacks a catch block to handle network errors, which can cause sendResponse
to never be called on failures like offline or CORS issues. Add a .catch block
after the .then chain to catch fetch errors and call sendResponse with an
appropriate error status and message. Also, update the existing catch block
inside .then to use the err parameter for logging or remove it if unused to fix
lint warnings.

});
};
41 changes: 41 additions & 0 deletions src/background/handlers/api/healthDataHandler.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
export const handleHealthDataFetch = async (
message: any,

Check warning on line 2 in src/background/handlers/api/healthDataHandler.ts

View workflow job for this annotation

GitHub Actions / lint-and-test

Unexpected any. Specify a different type
sender: any,

Check warning on line 3 in src/background/handlers/api/healthDataHandler.ts

View workflow job for this annotation

GitHub Actions / lint-and-test

Unexpected any. Specify a different type
sendResponse: any,

Check warning on line 4 in src/background/handlers/api/healthDataHandler.ts

View workflow job for this annotation

GitHub Actions / lint-and-test

Unexpected any. Specify a different type
) => {
const { productId, title, html, birthYear, gender, allergies } =
message.payload;

fetch("https://voim.store/api/v1/health-food/keywords", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
productId,
title,
html,
birthYear,
gender,
allergies,
}),
})
.then((res) => res.json())
.then((data) => {
if (sender.tab?.id) {
chrome.tabs.sendMessage(sender.tab.id, {
type: "HEALTH_DATA_RESPONSE",
data: data.data,
});
}
sendResponse({ type: "HEALTH_DATA_RESPONSE", data: data.data });
})
.catch((err) => {
console.error("HEALTH 요청 실패:", err);
if (sender.tab?.id) {
chrome.tabs.sendMessage(sender.tab.id, {
type: "HEALTH_DATA_ERROR",
error: err.message,
});
}
sendResponse({ type: "HEALTH_DATA_ERROR", error: err.message });
});
};
42 changes: 42 additions & 0 deletions src/background/handlers/api/imageAnalysisHandler.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { logger } from "@src/utils/logger";

export const handleImageAnalysisFetch = async (
message: any,
sender: any,
sendResponse: any,
) => {
Comment on lines +3 to +7
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

타입 선언 및 async 키워드 사용이 부자연스럽습니다
message, sender, sendResponse를 모두 any로 두면 TypeScript의 장점을 잃습니다. 또한 함수에 async를 붙였지만 내부에서 await를 쓰지 않고 fetch(...).then() 체인을 반환하지 않아 Promise<void>가 아닌 undefined를 즉시 반환하게 됩니다.

-export const handleImageAnalysisFetch = async (
-    message: any,
-    sender: any,
-    sendResponse: any,
-) => {
+interface ImageAnalysisMessage { payload: { url?: string } }
+export const handleImageAnalysisFetch = (
+    message: ImageAnalysisMessage,
+    sender: chrome.runtime.MessageSender,
+    sendResponse: (response: unknown) => void,
+) => {

async 를 제거하고 마지막에 return fetch(...); 를 추가해 리스너에서 true 를 반환하지 않아도 런타임이 응답 대기를 인지하도록 하는 편이 명확합니다.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export const handleImageAnalysisFetch = async (
message: any,
sender: any,
sendResponse: any,
) => {
interface ImageAnalysisMessage { payload: { url?: string } }
export const handleImageAnalysisFetch = (
message: ImageAnalysisMessage,
sender: chrome.runtime.MessageSender,
sendResponse: (response: unknown) => void,
) => {
🤖 Prompt for AI Agents
In src/background/handlers/api/imageAnalysisHandler.ts around lines 3 to 7, the
parameters message, sender, and sendResponse are all typed as any, which loses
TypeScript's type safety benefits. Also, the function is marked async but does
not use await or return a Promise properly, causing it to return undefined
immediately. To fix this, remove the async keyword from the function
declaration, replace the any types with appropriate specific types for message,
sender, and sendResponse, and ensure the function returns the fetch call
directly by adding return before fetch(...). This will make the function return
a Promise and allow the runtime to recognize the asynchronous response
correctly.

const imageUrl = message.payload?.url;

fetch("https://voim.store/api/v1/image-analysis", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ url: imageUrl }),
})
Comment on lines +8 to +14
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

imageUrl 유효성 검증 누락
message.payload?.urlundefined 인 경우 그대로 API 호출이 이뤄집니다. 빈 URL 전송은 서버 400을 유발할 수 있으므로 검사 후 즉시 에러 응답을 보내는 것이 안전합니다.

🤖 Prompt for AI Agents
In src/background/handlers/api/imageAnalysisHandler.ts around lines 8 to 14, the
code assigns imageUrl from message.payload?.url without validating it, which can
cause an API call with an undefined or empty URL leading to server 400 errors.
Add a check after extracting imageUrl to verify it is defined and non-empty; if
not, immediately return or throw an error response instead of proceeding with
the fetch call.

.then((res) => res.json())
Comment on lines +10 to +15
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

res.ok 확인이 필요합니다
HTTP 오류 상태(4xx/5xx)에서도 res.json()을 시도하면 추가 오류가 발생할 수 있습니다. if (!res.ok) throw new Error(...) 패턴으로 처리하세요.

🤖 Prompt for AI Agents
In src/background/handlers/api/imageAnalysisHandler.ts around lines 10 to 15,
the fetch response is parsed to JSON without checking if the HTTP response
status is OK. To fix this, add a check for res.ok after receiving the response;
if it is false, throw an error with an appropriate message before calling
res.json(). This prevents attempting to parse error responses as JSON and avoids
additional errors.

.then((data) => {
logger.debug("이미지 분석 API 응답:", data);
if (sender.tab?.id) {
chrome.tabs.sendMessage(sender.tab.id, {
type: "IMAGE_ANALYSIS_RESPONSE",
data: data.data,
});
}
sendResponse({
type: "IMAGE_ANALYSIS_RESPONSE",
data: data.data,
});
})
.catch((err) => {
console.error("이미지 분석 에러:", err);
if (sender.tab?.id) {
chrome.tabs.sendMessage(sender.tab.id, {
type: "IMAGE_ANALYSIS_ERROR",
error: err.message,
});
}
sendResponse({
type: "IMAGE_ANALYSIS_ERROR",
error: err.message,
});
});
};
6 changes: 6 additions & 0 deletions src/background/handlers/api/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export { handleFoodDataFetch } from "./foodHandler";
export { handleImageAnalysisFetch } from "./imageAnalysisHandler";
export { handleOutlineInfoFetch } from "./outlineInfoHandler";
export { handleCosmeticDataFetch } from "./cosmeticHandler";
export { handleReviewSummaryFetch } from "./reviewSummaryHandler";
export { handleHealthDataFetch } from "./healthDataHandler";
59 changes: 59 additions & 0 deletions src/background/handlers/api/outlineInfoHandler.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
export const handleOutlineInfoFetch = async (
message: any,
sender: any,
sendResponse: any,
) => {
const { outline, html } = message.payload;
Comment on lines +1 to +6
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

타입 및 async/콜백 혼용
함수에 async 가 있지만 내부 로직은 전부 콜백 기반(chrome.tabs.query)입니다. async 제거 후 Promise 체인 반환이 명확합니다. 또한 message, sender 타입 구체화를 권장합니다.

🤖 Prompt for AI Agents
In src/background/handlers/api/outlineInfoHandler.ts lines 1 to 6, the function
is marked async but uses only callback-based chrome.tabs.query internally, so
remove the async keyword and refactor to return a Promise chain clearly. Also,
replace the any types for message and sender with more specific types to improve
type safety and clarity.


chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => {
const activeTab = tabs[0];
if (!activeTab?.url) {
sendResponse({
type: "OUTLINE_INFO_ERROR",
error: "상품 페이지를 찾을 수 없습니다.",
});
return;
}

const productId = activeTab.url.match(/vp\/products\/(\d+)/)?.[1];
if (!productId) {
sendResponse({
type: "OUTLINE_INFO_ERROR",
error: "상품 ID를 찾을 수 없습니다.",
});
return;
}

fetch(`https://voim.store/api/v1/product-detail/${outline}`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ html, productId }),
})
.then((res) => res.json())
.then((data) => {
Comment on lines +27 to +33
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

res.ok 체크 누락 및 예외 처리
다른 핸들러와 동일하게 HTTP 오류 상태에 대한 처리가 없습니다.

🤖 Prompt for AI Agents
In src/background/handlers/api/outlineInfoHandler.ts around lines 27 to 33, the
fetch response does not check res.ok to handle HTTP error statuses. Add a check
for res.ok after receiving the response, and if false, throw an error or handle
it appropriately to ensure HTTP errors are caught and managed consistently with
other handlers.

if (sender.tab?.id) {
chrome.tabs.sendMessage(sender.tab.id, {
type: "OUTLINE_INFO_RESPONSE",
data: data.data,
});
}
sendResponse({
type: "OUTLINE_INFO_RESPONSE",
data: data.data,
});
})
.catch((err) => {
console.error("OUTLINE INFO 오류:", err);
if (sender.tab?.id) {
chrome.tabs.sendMessage(sender.tab.id, {
type: "OUTLINE_INFO_ERROR",
error: err.message,
});
}
sendResponse({
type: "OUTLINE_INFO_ERROR",
error: err.message,
});
});
});
};
54 changes: 54 additions & 0 deletions src/background/handlers/api/reviewSummaryHandler.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
export const handleReviewSummaryFetch = async (
message: any,
sender: any,
sendResponse: any,
) => {
const { productId, reviewRating, reviews } = message.payload;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

message.payload 존재 여부 확인 필요
message.payloadundefined 이면 구조 분해 단계에서 런타임 오류가 발생합니다.
호출부 신뢰가 불확실하므로 if (!message?.payload) { … } 가드 코드를 추가해주세요.

🤖 Prompt for AI Agents
In src/background/handlers/api/reviewSummaryHandler.ts at line 6, the code
destructures properties from message.payload without checking if payload exists,
which can cause a runtime error if payload is undefined. Add a guard clause
before destructuring to check if message.payload is present, for example using
if (!message?.payload) { return or handle error }, to prevent runtime
exceptions.


fetch("https://voim.store/api/v1/review/summary", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ productId, reviewRating, reviews }),
})
.then(async (res) => {
if (!res.ok) {
const errorData = await res.json().catch(() => ({}));
throw new Error(
errorData.message || `HTTP error! status: ${res.status}`,
);
}
return res.json();
})
.then((data) => {
if (!data.data) {
throw new Error("서버 응답에 데이터가 없습니다.");
}

if (sender.tab?.id) {
chrome.tabs.sendMessage(sender.tab.id, {
type: "REVIEW_SUMMARY_RESPONSE",
data: data.data,
});
}
sendResponse({
type: "REVIEW_SUMMARY_RESPONSE",
data: data.data,
});
})
.catch((err) => {
console.error("[voim] REVIEW SUMMARY 오류:", err);
const errorMessage =
err.message || "리뷰 요약 처리 중 오류가 발생했습니다";

if (sender.tab?.id) {
chrome.tabs.sendMessage(sender.tab.id, {
type: "REVIEW_SUMMARY_ERROR",
error: errorMessage,
});
}
sendResponse({
type: "REVIEW_SUMMARY_ERROR",
error: errorMessage,
});
});
};
Loading
Loading