CRITICAL FIX: Lazy evaluate API URLs at request time, not module load time
All checks were successful
Build and Push Docker Images / docker (push) Successful in 43s
All checks were successful
Build and Push Docker Images / docker (push) Successful in 43s
ROOT CAUSE (Zen Debug Investigation): The API_BASE_URL constant was being evaluated when the module loaded, BEFORE window.env was populated by env-config.js. This caused the app to permanently use the fallback localhost:3001 instead of reading the production URL from the .env file. TIMING ISSUE: 1. Browser loads index.html 2. env-config.js loads (creates window.env) 3. main.tsx loads as ES module (DEFERRED) 4. Module imports checkoutClient → const API_BASE_URL executes 5. window.env NOT READY YET → falls back to localhost:3001 6. API_BASE_URL locked to wrong value forever THE FIX: Changed from module-level constants to request-time lazy evaluation. Now getApiBaseUrl() is called WHEN THE API REQUEST HAPPENS, not when the module loads. At that point window.env is guaranteed to exist. FILES CHANGED: - src/api/checkoutClient.ts: * Removed constant API_BASE_URL * All 3 functions now call getApiBaseUrl() at request time * Added logging to show which URL is being used - src/api/aisClient.ts: * Removed constant API_KEY * Added getApiKey() function with lazy evaluation * Same pattern for consistency and future-proofing This fixes: "FetchEvent for http://localhost:3001 resulted in network error" Now uses: https://puffinoffset.com/api (from .env file) 🔒 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
3aac87de50
commit
8d9f65868a
@ -1,13 +1,21 @@
|
|||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import type { VesselData } from '../types';
|
import type { VesselData } from '../types';
|
||||||
|
|
||||||
// Using MarineTraffic API as an example - you'll need to add your API key
|
|
||||||
const API_KEY = import.meta.env.VITE_MARINE_TRAFFIC_API_KEY;
|
|
||||||
const API_BASE_URL = 'https://services.marinetraffic.com/api/vesselmasterdata/v3';
|
const API_BASE_URL = 'https://services.marinetraffic.com/api/vesselmasterdata/v3';
|
||||||
|
|
||||||
|
// Get API key at request time to ensure window.env is populated
|
||||||
|
const getApiKey = (): string | undefined => {
|
||||||
|
if (typeof window !== 'undefined' && window.env?.MARINE_TRAFFIC_API_KEY) {
|
||||||
|
return window.env.MARINE_TRAFFIC_API_KEY;
|
||||||
|
}
|
||||||
|
return import.meta.env.VITE_MARINE_TRAFFIC_API_KEY;
|
||||||
|
};
|
||||||
|
|
||||||
export async function getVesselData(imo: string): Promise<VesselData> {
|
export async function getVesselData(imo: string): Promise<VesselData> {
|
||||||
|
const apiKey = getApiKey(); // Lazy evaluate at request time
|
||||||
|
|
||||||
// For development, return mock data if no API key is present
|
// For development, return mock data if no API key is present
|
||||||
if (!API_KEY) {
|
if (!apiKey) {
|
||||||
console.warn('No API key found - using mock data');
|
console.warn('No API key found - using mock data');
|
||||||
return getMockVesselData(imo);
|
return getMockVesselData(imo);
|
||||||
}
|
}
|
||||||
@ -16,7 +24,7 @@ export async function getVesselData(imo: string): Promise<VesselData> {
|
|||||||
const response = await axios.get(API_BASE_URL, {
|
const response = await axios.get(API_BASE_URL, {
|
||||||
params: {
|
params: {
|
||||||
imo,
|
imo,
|
||||||
apikey: API_KEY,
|
apikey: apiKey,
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -2,6 +2,8 @@ import axios from 'axios';
|
|||||||
import { logger } from '../utils/logger';
|
import { logger } from '../utils/logger';
|
||||||
|
|
||||||
// Get API base URL from runtime config (window.env) or build-time config
|
// Get API base URL from runtime config (window.env) or build-time config
|
||||||
|
// IMPORTANT: Call this function at REQUEST TIME, not at module load time,
|
||||||
|
// to ensure window.env is populated by env-config.js
|
||||||
const getApiBaseUrl = (): string => {
|
const getApiBaseUrl = (): string => {
|
||||||
// Check window.env first (runtime config from env.sh)
|
// Check window.env first (runtime config from env.sh)
|
||||||
if (typeof window !== 'undefined' && window.env?.API_BASE_URL) {
|
if (typeof window !== 'undefined' && window.env?.API_BASE_URL) {
|
||||||
@ -12,8 +14,6 @@ const getApiBaseUrl = (): string => {
|
|||||||
return import.meta.env.VITE_API_BASE_URL || 'http://localhost:3001';
|
return import.meta.env.VITE_API_BASE_URL || 'http://localhost:3001';
|
||||||
};
|
};
|
||||||
|
|
||||||
const API_BASE_URL = getApiBaseUrl();
|
|
||||||
|
|
||||||
export interface CreateCheckoutSessionParams {
|
export interface CreateCheckoutSessionParams {
|
||||||
tons: number;
|
tons: number;
|
||||||
portfolioId: number;
|
portfolioId: number;
|
||||||
@ -54,10 +54,12 @@ export async function createCheckoutSession(
|
|||||||
params: CreateCheckoutSessionParams
|
params: CreateCheckoutSessionParams
|
||||||
): Promise<CheckoutSessionResponse> {
|
): Promise<CheckoutSessionResponse> {
|
||||||
try {
|
try {
|
||||||
|
const apiBaseUrl = getApiBaseUrl(); // Lazy evaluate at request time
|
||||||
logger.info('Creating checkout session:', params);
|
logger.info('Creating checkout session:', params);
|
||||||
|
logger.info('Using API base URL:', apiBaseUrl);
|
||||||
|
|
||||||
const response = await axios.post<CheckoutSessionResponse>(
|
const response = await axios.post<CheckoutSessionResponse>(
|
||||||
`${API_BASE_URL}/api/checkout/create-session`,
|
`${apiBaseUrl}/api/checkout/create-session`,
|
||||||
params
|
params
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -79,10 +81,11 @@ export async function createCheckoutSession(
|
|||||||
*/
|
*/
|
||||||
export async function getOrderDetails(sessionId: string): Promise<OrderDetails> {
|
export async function getOrderDetails(sessionId: string): Promise<OrderDetails> {
|
||||||
try {
|
try {
|
||||||
|
const apiBaseUrl = getApiBaseUrl(); // Lazy evaluate at request time
|
||||||
logger.info('Fetching order details for session:', sessionId);
|
logger.info('Fetching order details for session:', sessionId);
|
||||||
|
|
||||||
const response = await axios.get<OrderDetails>(
|
const response = await axios.get<OrderDetails>(
|
||||||
`${API_BASE_URL}/api/checkout/session/${sessionId}`
|
`${apiBaseUrl}/api/checkout/session/${sessionId}`
|
||||||
);
|
);
|
||||||
|
|
||||||
logger.info('Order details retrieved:', response.data.order.id);
|
logger.info('Order details retrieved:', response.data.order.id);
|
||||||
@ -102,7 +105,8 @@ export async function getOrderDetails(sessionId: string): Promise<OrderDetails>
|
|||||||
*/
|
*/
|
||||||
export async function checkBackendHealth(): Promise<boolean> {
|
export async function checkBackendHealth(): Promise<boolean> {
|
||||||
try {
|
try {
|
||||||
const response = await axios.get(`${API_BASE_URL}/health`);
|
const apiBaseUrl = getApiBaseUrl(); // Lazy evaluate at request time
|
||||||
|
const response = await axios.get(`${apiBaseUrl}/health`);
|
||||||
return response.data.status === 'ok';
|
return response.data.status === 'ok';
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error('Backend health check failed:', error);
|
logger.error('Backend health check failed:', error);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user