You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
140 lines
4.5 KiB
140 lines
4.5 KiB
/**
|
|
* Plan service module for handling plan and claim data loading.
|
|
* Provides functionality to load plans with retry mechanism and error handling.
|
|
*
|
|
* @module plan
|
|
*/
|
|
|
|
import axios from "axios";
|
|
import { logger } from "../utils/logger";
|
|
|
|
/**
|
|
* Response interface for plan loading operations.
|
|
* Represents the structure of both successful and error responses.
|
|
*/
|
|
interface PlanResponse {
|
|
/** The response data payload */
|
|
data?: unknown;
|
|
/** HTTP status code of the response */
|
|
status?: number;
|
|
/** Error message in case of failure */
|
|
error?: string;
|
|
/** Response headers */
|
|
headers?: unknown;
|
|
}
|
|
|
|
/**
|
|
* Loads a plan with automatic retry mechanism.
|
|
* Attempts to load the plan multiple times in case of failure.
|
|
*
|
|
* @param handle - The unique identifier for the plan or claim
|
|
* @param retries - Number of retry attempts (default: 3)
|
|
* @returns Promise resolving to PlanResponse
|
|
*
|
|
* @remarks
|
|
* - Implements exponential backoff with 1 second delay between retries
|
|
* - Provides detailed logging of each attempt and any errors
|
|
* - Handles both plan and claim flows based on handle content
|
|
* - Logs comprehensive error information including:
|
|
* - HTTP status and headers
|
|
* - Response data
|
|
* - Request configuration
|
|
*
|
|
* @example
|
|
* ```typescript
|
|
* const response = await loadPlanWithRetry('plan-123');
|
|
* if (response.error) {
|
|
* console.error(response.error);
|
|
* } else {
|
|
* console.log(response.data);
|
|
* }
|
|
* ```
|
|
*/
|
|
export const loadPlanWithRetry = async (
|
|
handle: string,
|
|
retries = 3,
|
|
): Promise<PlanResponse> => {
|
|
try {
|
|
logger.log(`[Plan Service] Loading plan ${handle}, attempt 1/${retries}`);
|
|
logger.log(
|
|
`[Plan Service] Context: Deep link handle=${handle}, isClaimFlow=${handle.includes("claim")}`,
|
|
);
|
|
|
|
// Different endpoint if this is a claim flow
|
|
const response = await loadPlan(handle);
|
|
logger.log(`[Plan Service] Plan ${handle} loaded successfully:`, {
|
|
status: response?.status,
|
|
headers: response?.headers,
|
|
data: response?.data,
|
|
});
|
|
|
|
return response;
|
|
} catch (error: unknown) {
|
|
logger.error(`[Plan Service] Error loading plan ${handle}:`, {
|
|
message: (error as Error).message,
|
|
status: (error as { response?: { status?: number } })?.response?.status,
|
|
statusText: (error as { response?: { statusText?: string } })?.response
|
|
?.statusText,
|
|
data: (error as { response?: { data?: unknown } })?.response?.data,
|
|
headers: (error as { response?: { headers?: unknown } })?.response
|
|
?.headers,
|
|
config: {
|
|
url: (error as { config?: { url?: string } })?.config?.url,
|
|
method: (error as { config?: { method?: string } })?.config?.method,
|
|
baseURL: (error as { config?: { baseURL?: string } })?.config?.baseURL,
|
|
headers: (error as { config?: { headers?: unknown } })?.config?.headers,
|
|
},
|
|
});
|
|
|
|
if (retries > 1) {
|
|
logger.log(
|
|
`[Plan Service] Retrying plan ${handle}, ${retries - 1} attempts remaining`,
|
|
);
|
|
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
return loadPlanWithRetry(handle, retries - 1);
|
|
}
|
|
|
|
return {
|
|
error: `Failed to load plan ${handle} after ${4 - retries} attempts: ${(error as Error).message}`,
|
|
status: (error as { response?: { status?: number } })?.response?.status,
|
|
};
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Makes a single API request to load a plan or claim.
|
|
* Determines the appropriate endpoint based on the handle.
|
|
*
|
|
* @param handle - The unique identifier for the plan or claim
|
|
* @returns Promise resolving to PlanResponse
|
|
* @throws Will throw an error if the API request fails
|
|
*
|
|
* @remarks
|
|
* - Automatically detects claim vs plan endpoints based on handle
|
|
* - Uses axios for HTTP requests
|
|
* - Provides detailed error logging
|
|
* - Different endpoints:
|
|
* - Claims: /api/claims/{handle}
|
|
* - Plans: /api/plans/{handle}
|
|
*/
|
|
export const loadPlan = async (handle: string): Promise<PlanResponse> => {
|
|
logger.log(`[Plan Service] Making API request for plan ${handle}`);
|
|
|
|
const endpoint = handle.includes("claim")
|
|
? `/api/claims/${handle}`
|
|
: `/api/plans/${handle}`;
|
|
|
|
logger.log(`[Plan Service] Using endpoint: ${endpoint}`);
|
|
|
|
try {
|
|
const response = await axios.get(endpoint);
|
|
return response;
|
|
} catch (error: unknown) {
|
|
logger.error(`[Plan Service] API request failed for ${handle}:`, {
|
|
endpoint,
|
|
error: (error as Error).message,
|
|
response: (error as { response?: { data?: unknown } })?.response?.data,
|
|
});
|
|
throw error;
|
|
}
|
|
};
|
|
|