@thead-vantage/react 2.10.0 → 2.12.0

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/README.md CHANGED
@@ -31,7 +31,7 @@ The TheAd Vantage integration supports multiple modes of operation to accommodat
31
31
  **Use Case**: Platform developers using the component in production deployments.
32
32
 
33
33
  **Behavior**:
34
- - Connects to `https://thead-vantage.com/api/ads`
34
+ - Connects to `https://www.thead-vantage.com/api/ads` (uses www to avoid 308 redirects)
35
35
  - Full tracking enabled (impressions and clicks are recorded)
36
36
  - No configuration required
37
37
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@thead-vantage/react",
3
- "version": "2.10.0",
3
+ "version": "2.12.0",
4
4
  "description": "React components and utilities for TheAd Vantage ad platform integration",
5
5
  "main": "./src/index.ts",
6
6
  "module": "./src/index.ts",
@@ -83,7 +83,19 @@ export function AdBanner({
83
83
  }
84
84
  } catch (err) {
85
85
  console.error('[AdBanner] Error fetching ad:', err);
86
- setError(err instanceof Error ? err.message : 'Failed to fetch ad');
86
+
87
+ // For CORS errors, show user-friendly message but log technical details
88
+ if (err instanceof Error && err.message.includes('CORS error')) {
89
+ console.error('[AdBanner] CORS Error Details:', {
90
+ message: err.message,
91
+ note: 'This is a server-side configuration issue. The thead-vantage.com server needs to handle OPTIONS requests without redirecting. See CORS_CONFIGURATION.md for implementation details.',
92
+ });
93
+ // Show generic message to end users
94
+ setError('Ad unavailable');
95
+ } else {
96
+ // For other errors, show the error message
97
+ setError(err instanceof Error ? err.message : 'Failed to fetch ad');
98
+ }
87
99
  } finally {
88
100
  setLoading(false);
89
101
  }
package/src/lib/ads.ts CHANGED
@@ -168,16 +168,26 @@ export async function fetchAdBanner(params: FetchAdBannerParams): Promise<AdBann
168
168
  });
169
169
 
170
170
  // Handle redirects manually (if any)
171
+ // Note: 308 redirects at Vercel edge level will still break CORS preflight
172
+ // This handles redirects for the actual GET request, but preflight redirects are blocked by browser
171
173
  if (response.type === 'opaqueredirect' || (response.status >= 300 && response.status < 400)) {
172
174
  const location = response.headers.get('location');
173
175
  if (location) {
174
- // Follow the redirect for the actual request (not preflight)
176
+ // Extract the redirect URL
175
177
  const redirectUrl = location.startsWith('http')
176
178
  ? location
177
179
  : new URL(location, normalizedUrl).toString();
178
- console.warn('[AdBanner] Server redirected request, following redirect:', redirectUrl.replace(new RegExp(`api_key=${params.apiKey}`, 'g'), 'api_key=***'));
180
+
181
+ console.warn('[AdBanner] Server redirected request (status:', response.status, '), following redirect:', redirectUrl.replace(new RegExp(`api_key=${params.apiKey}`, 'g'), 'api_key=***'));
182
+ console.warn('[AdBanner] Note: If this is a 308 redirect, it may break CORS preflight. Consider using the canonical domain directly.');
183
+
179
184
  // Recursively call with the redirect URL
180
- return await fetchAdBanner({ ...params, apiUrl: redirectUrl });
185
+ // Limit recursion to prevent infinite loops
186
+ const redirectCount = (params as any).__redirectCount || 0;
187
+ if (redirectCount >= 3) {
188
+ throw new Error('Too many redirects. The server may be misconfigured.');
189
+ }
190
+ return await fetchAdBanner({ ...params, apiUrl: redirectUrl, __redirectCount: redirectCount + 1 } as any);
181
191
  }
182
192
  }
183
193
 
@@ -303,9 +313,22 @@ export async function fetchAdBanner(params: FetchAdBannerParams): Promise<AdBann
303
313
  } catch (error) {
304
314
  // Handle CORS errors specifically
305
315
  if (error instanceof TypeError && (error.message.includes('CORS') || error.message.includes('Failed to fetch'))) {
306
- console.error('[AdBanner] CORS error detected. This usually means the server is redirecting preflight requests.');
307
- console.error('[AdBanner] The server at thead-vantage.com needs to handle OPTIONS requests directly without redirecting.');
308
- throw new Error('CORS error: The ad server is redirecting preflight requests. This needs to be fixed server-side. See CORS_CONFIGURATION.md for details.');
316
+ // Check if this might be a 308 redirect issue
317
+ // Vercel redirects thead-vantage.com www.thead-vantage.com at edge level
318
+ // This breaks CORS preflight because browsers don't allow redirects on OPTIONS requests
319
+ const isRedirectIssue = normalizedUrl.includes('thead-vantage.com') && !normalizedUrl.includes('www.');
320
+
321
+ if (isRedirectIssue) {
322
+ console.error('[AdBanner] CORS error detected. This appears to be a 308 redirect issue.');
323
+ console.error('[AdBanner] The domain thead-vantage.com redirects to www.thead-vantage.com at Vercel edge level.');
324
+ console.error('[AdBanner] This breaks CORS preflight requests because browsers block redirects on OPTIONS requests.');
325
+ console.error('[AdBanner] Solution: Use www.thead-vantage.com directly (library has been updated to do this).');
326
+ throw new Error('CORS error: 308 redirect detected. The server redirects thead-vantage.com → www.thead-vantage.com, which breaks CORS preflight. The library now uses www.thead-vantage.com by default. If you see this error, check your API URL configuration.');
327
+ } else {
328
+ console.error('[AdBanner] CORS error detected. This usually means the server is redirecting preflight requests.');
329
+ console.error('[AdBanner] The server needs to handle OPTIONS requests directly without redirecting.');
330
+ throw new Error('CORS error: The ad server is redirecting preflight requests. This needs to be fixed server-side. See CORS_CONFIGURATION.md for details.');
331
+ }
309
332
  }
310
333
 
311
334
  console.error('[AdBanner] Error fetching ad:', error);
@@ -85,16 +85,19 @@ export function getApiBaseUrl(explicitApiUrl?: string): string {
85
85
 
86
86
  // Priority 4: Localhost development (platform developers on localhost)
87
87
  // Use production API but will add dev flags to prevent tracking
88
+ // Use www.thead-vantage.com to avoid 308 redirects
88
89
  if (!selectedUrl && isLocalhost()) {
89
- selectedUrl = 'https://thead-vantage.com/api/ads';
90
- reason = 'localhost detection (production API with dev flags)';
90
+ selectedUrl = 'https://www.thead-vantage.com/api/ads';
91
+ reason = 'localhost detection (production API with dev flags - using www to avoid redirects)';
91
92
  }
92
93
 
93
94
  // Priority 5: Production mode (default)
94
95
  // Platform developers use this by default in production
96
+ // IMPORTANT: Use www.thead-vantage.com to avoid 308 redirects at Vercel edge
97
+ // Vercel redirects thead-vantage.com → www.thead-vantage.com, which breaks CORS preflight
95
98
  if (!selectedUrl) {
96
- selectedUrl = 'https://thead-vantage.com/api/ads';
97
- reason = 'production mode (default)';
99
+ selectedUrl = 'https://www.thead-vantage.com/api/ads';
100
+ reason = 'production mode (default - using www to avoid redirects)';
98
101
  }
99
102
 
100
103
  // Normalize the URL to avoid redirects that cause CORS preflight issues