ADR-026: Client-Side Logging + linting fixes
Some checks failed
Deploy to Test Environment / deploy-to-test (push) Has been cancelled

This commit is contained in:
2026-01-09 17:58:21 -08:00
parent 9ffcc9d65d
commit 25d6b76f6d
24 changed files with 242 additions and 195 deletions

View File

@@ -94,8 +94,7 @@ export const apiFetch = async (
// unless the path is already a full URL. This works for both browser and Node.js.
const fullUrl = url.startsWith('http') ? url : joinUrl(API_BASE_URL, url);
logger.debug(`apiFetch: ${options.method || 'GET'} ${fullUrl}`);
console.error(`[apiClient] apiFetch Request: ${options.method || 'GET'} ${fullUrl}`);
logger.debug({ method: options.method || 'GET', url: fullUrl }, 'apiFetch: Request');
// Create a new headers object to avoid mutating the original options.
const headers = new Headers(options.headers || {});
@@ -150,7 +149,8 @@ export const apiFetch = async (
// --- DEBUG LOGGING for failed requests ---
if (!response.ok) {
const responseText = await response.clone().text();
logger.error({ url: fullUrl, status: response.status, body: responseText },
logger.error(
{ url: fullUrl, status: response.status, body: responseText },
'apiFetch: Request failed',
);
}
@@ -181,7 +181,11 @@ export const authedGet = (endpoint: string, options: ApiOptions = {}): Promise<R
};
/** Helper for authenticated POST requests with a JSON body */
export const authedPost = <T>(endpoint: string, body: T, options: ApiOptions = {}): Promise<Response> => {
export const authedPost = <T>(
endpoint: string,
body: T,
options: ApiOptions = {},
): Promise<Response> => {
return apiFetch(
endpoint,
{ method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(body) },
@@ -204,7 +208,11 @@ export const authedPostForm = (
};
/** Helper for authenticated PUT requests with a JSON body */
export const authedPut = <T>(endpoint: string, body: T, options: ApiOptions = {}): Promise<Response> => {
export const authedPut = <T>(
endpoint: string,
body: T,
options: ApiOptions = {},
): Promise<Response> => {
return apiFetch(
endpoint,
{ method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(body) },
@@ -406,7 +414,8 @@ export const addWatchedItem = (
itemName: string,
category: string,
tokenOverride?: string,
): Promise<Response> => authedPost('/users/watched-items', { itemName, category }, { tokenOverride });
): Promise<Response> =>
authedPost('/users/watched-items', { itemName, category }, { tokenOverride });
export const removeWatchedItem = (
masterItemId: number,
@@ -426,10 +435,8 @@ export const fetchBestSalePrices = (tokenOverride?: string): Promise<Response> =
export const fetchShoppingLists = (tokenOverride?: string): Promise<Response> =>
authedGet('/users/shopping-lists', { tokenOverride });
export const fetchShoppingListById = (
listId: number,
tokenOverride?: string,
): Promise<Response> => authedGet(`/users/shopping-lists/${listId}`, { tokenOverride });
export const fetchShoppingListById = (listId: number, tokenOverride?: string): Promise<Response> =>
authedGet(`/users/shopping-lists/${listId}`, { tokenOverride });
export const createShoppingList = (name: string, tokenOverride?: string): Promise<Response> =>
authedPost('/users/shopping-lists', { name }, { tokenOverride });
@@ -451,10 +458,8 @@ export const updateShoppingListItem = (
): Promise<Response> =>
authedPut(`/users/shopping-lists/items/${itemId}`, updates, { tokenOverride });
export const removeShoppingListItem = (
itemId: number,
tokenOverride?: string,
): Promise<Response> => authedDelete(`/users/shopping-lists/items/${itemId}`, { tokenOverride });
export const removeShoppingListItem = (itemId: number, tokenOverride?: string): Promise<Response> =>
authedDelete(`/users/shopping-lists/items/${itemId}`, { tokenOverride });
/**
* Fetches the full profile for the currently authenticated user.
@@ -483,10 +488,7 @@ export async function loginUser(
* @param receiptImage The image file of the receipt.
* @returns A promise that resolves with the backend's response, including the newly created receipt record.
*/
export const uploadReceipt = (
receiptImage: File,
tokenOverride?: string,
): Promise<Response> => {
export const uploadReceipt = (receiptImage: File, tokenOverride?: string): Promise<Response> => {
const formData = new FormData();
formData.append('receiptImage', receiptImage);
return authedPostForm('/receipts/upload', formData, { tokenOverride });
@@ -580,18 +582,14 @@ export const getUserFeed = (
tokenOverride?: string,
): Promise<Response> => authedGet(`/users/feed?limit=${limit}&offset=${offset}`, { tokenOverride });
export const forkRecipe = (
originalRecipeId: number,
tokenOverride?: string,
): Promise<Response> => authedPostEmpty(`/recipes/${originalRecipeId}/fork`, { tokenOverride });
export const forkRecipe = (originalRecipeId: number, tokenOverride?: string): Promise<Response> =>
authedPostEmpty(`/recipes/${originalRecipeId}/fork`, { tokenOverride });
export const followUser = (userIdToFollow: string, tokenOverride?: string): Promise<Response> =>
authedPostEmpty(`/users/${userIdToFollow}/follow`, { tokenOverride });
export const unfollowUser = (
userIdToUnfollow: string,
tokenOverride?: string,
): Promise<Response> => authedDelete(`/users/${userIdToUnfollow}/follow`, { tokenOverride });
export const unfollowUser = (userIdToUnfollow: string, tokenOverride?: string): Promise<Response> =>
authedDelete(`/users/${userIdToUnfollow}/follow`, { tokenOverride });
// --- Activity Log API Function ---
@@ -618,15 +616,11 @@ export const fetchActivityLog = (
export const getUserFavoriteRecipes = (tokenOverride?: string): Promise<Response> =>
authedGet('/users/me/favorite-recipes', { tokenOverride });
export const addFavoriteRecipe = (
recipeId: number,
tokenOverride?: string,
): Promise<Response> => authedPost('/users/me/favorite-recipes', { recipeId }, { tokenOverride });
export const addFavoriteRecipe = (recipeId: number, tokenOverride?: string): Promise<Response> =>
authedPost('/users/me/favorite-recipes', { recipeId }, { tokenOverride });
export const removeFavoriteRecipe = (
recipeId: number,
tokenOverride?: string,
): Promise<Response> => authedDelete(`/users/me/favorite-recipes/${recipeId}`, { tokenOverride });
export const removeFavoriteRecipe = (recipeId: number, tokenOverride?: string): Promise<Response> =>
authedDelete(`/users/me/favorite-recipes/${recipeId}`, { tokenOverride });
// --- Recipe Comments API Functions ---
@@ -655,10 +649,7 @@ export const addRecipeComment = (
* @param tokenOverride Optional token for testing.
* @returns A promise that resolves to the API response containing the suggestion.
*/
export const suggestRecipe = (
ingredients: string[],
tokenOverride?: string,
): Promise<Response> => {
export const suggestRecipe = (ingredients: string[], tokenOverride?: string): Promise<Response> => {
// This is a protected endpoint, so we use authedPost.
return authedPost('/recipes/suggest', { ingredients }, { tokenOverride });
};
@@ -687,7 +678,8 @@ export const updateRecipeCommentStatus = (
commentId: number,
status: 'visible' | 'hidden' | 'reported',
tokenOverride?: string,
): Promise<Response> => authedPut(`/admin/comments/${commentId}/status`, { status }, { tokenOverride });
): Promise<Response> =>
authedPut(`/admin/comments/${commentId}/status`, { status }, { tokenOverride });
/**
* Fetches all brands from the backend. Requires admin privileges.
@@ -737,12 +729,11 @@ export const getFlyersForReview = (tokenOverride?: string): Promise<Response> =>
export const approveCorrection = (
correctionId: number,
tokenOverride?: string,
): Promise<Response> => authedPostEmpty(`/admin/corrections/${correctionId}/approve`, { tokenOverride });
): Promise<Response> =>
authedPostEmpty(`/admin/corrections/${correctionId}/approve`, { tokenOverride });
export const rejectCorrection = (
correctionId: number,
tokenOverride?: string,
): Promise<Response> => authedPostEmpty(`/admin/corrections/${correctionId}/reject`, { tokenOverride });
export const rejectCorrection = (correctionId: number, tokenOverride?: string): Promise<Response> =>
authedPostEmpty(`/admin/corrections/${correctionId}/reject`, { tokenOverride });
export const updateSuggestedCorrection = (
correctionId: number,
@@ -1032,7 +1023,9 @@ export const getSpendingAnalysis = (
endDate: string,
tokenOverride?: string,
): Promise<Response> =>
authedGet(`/budgets/spending-analysis?startDate=${startDate}&endDate=${endDate}`, { tokenOverride });
authedGet(`/budgets/spending-analysis?startDate=${startDate}&endDate=${endDate}`, {
tokenOverride,
});
// --- Gamification API Functions ---