mirror of
https://github.com/pacnpal/thrilltrack-explorer.git
synced 2025-12-22 10:51:12 -05:00
Migrate Phase 3 Webhook and Utilities
Extend createEdgeFunction usage to novu-webhook, seed-test-data, and sitemap by removing manual boilerplate (CORS, auth, tracking, error handling) and replacing logging with span-based tracing; wire in EdgeFunctionContext for supabase, user, span, and requestId; preserve core logic including webhook validation, data seeding utilities, and sitemap caching.
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import { createClient } from 'https://esm.sh/@supabase/supabase-js@2.57.4';
|
||||
import { edgeLogger } from '../_shared/logger.ts';
|
||||
import { serve } from "https://deno.land/std@0.168.0/http/server.ts";
|
||||
import { createEdgeFunction, type EdgeFunctionContext } from '../_shared/edgeFunctionWrapper.ts';
|
||||
import { addSpanEvent } from '../_shared/logger.ts';
|
||||
import { formatEdgeError } from '../_shared/errorFormatter.ts';
|
||||
|
||||
const BASE_URL = 'https://dev.thrillwiki.com';
|
||||
@@ -131,7 +132,7 @@ function generateSitemapXml(urls: SitemapUrl[]): string {
|
||||
// SITEMAP GENERATION
|
||||
// ============================================================================
|
||||
|
||||
async function generateSitemap(requestId: string): Promise<{
|
||||
async function generateSitemap(requestId: string, span: any): Promise<{
|
||||
xml: string;
|
||||
stats: SitemapStats;
|
||||
}> {
|
||||
@@ -150,10 +151,12 @@ async function generateSitemap(requestId: string): Promise<{
|
||||
generation_time_ms: 0,
|
||||
};
|
||||
|
||||
const supabase = createClient(
|
||||
Deno.env.get('SUPABASE_URL') ?? '',
|
||||
Deno.env.get('SUPABASE_ANON_KEY') ?? ''
|
||||
);
|
||||
const supabaseUrl = Deno.env.get('SUPABASE_URL') ?? '';
|
||||
const supabaseAnonKey = Deno.env.get('SUPABASE_ANON_KEY') ?? '';
|
||||
|
||||
// Dynamic import to avoid circular dependency issues
|
||||
const { createClient } = await import('https://esm.sh/@supabase/supabase-js@2.57.4');
|
||||
const supabase = createClient(supabaseUrl, supabaseAnonKey);
|
||||
|
||||
// Static pages
|
||||
const now = new Date().toISOString();
|
||||
@@ -265,8 +268,7 @@ async function generateSitemap(requestId: string): Promise<{
|
||||
|
||||
const xml = generateSitemapXml(urls);
|
||||
|
||||
edgeLogger.info('Sitemap generated', {
|
||||
requestId,
|
||||
addSpanEvent(span, 'sitemap_generated', {
|
||||
stats,
|
||||
sizeKB: (xml.length / 1024).toFixed(2),
|
||||
});
|
||||
@@ -293,76 +295,51 @@ function generateFallbackSitemap(): string {
|
||||
// MAIN HANDLER
|
||||
// ============================================================================
|
||||
|
||||
Deno.serve(async (req) => {
|
||||
const requestId = crypto.randomUUID();
|
||||
serve(createEdgeFunction({
|
||||
name: 'sitemap',
|
||||
requireAuth: false, // Public endpoint
|
||||
corsHeaders: {},
|
||||
}, async (req, { span, requestId }: EdgeFunctionContext) => {
|
||||
const startTime = Date.now();
|
||||
|
||||
try {
|
||||
// Return cached version if valid
|
||||
if (isCacheValid()) {
|
||||
const duration = Date.now() - startTime;
|
||||
edgeLogger.info('Sitemap cache hit', {
|
||||
requestId,
|
||||
cacheAge: Date.now() - cacheTimestamp,
|
||||
duration,
|
||||
});
|
||||
|
||||
return new Response(cachedSitemap, {
|
||||
headers: {
|
||||
'Content-Type': 'application/xml; charset=utf-8',
|
||||
'X-Request-ID': requestId,
|
||||
'X-Cache': 'HIT',
|
||||
'X-Generation-Time': `${duration}ms`,
|
||||
...cacheHeaders,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
// Generate fresh sitemap
|
||||
const sitemap = await generateSitemap(requestId);
|
||||
|
||||
// Update cache
|
||||
cachedSitemap = sitemap.xml;
|
||||
cacheTimestamp = Date.now();
|
||||
|
||||
// Return cached version if valid
|
||||
if (isCacheValid()) {
|
||||
const duration = Date.now() - startTime;
|
||||
|
||||
edgeLogger.info('Sitemap cache miss - generated', {
|
||||
requestId,
|
||||
addSpanEvent(span, 'sitemap_cache_hit', {
|
||||
cacheAge: Date.now() - cacheTimestamp,
|
||||
duration,
|
||||
stats: sitemap.stats,
|
||||
});
|
||||
|
||||
return new Response(sitemap.xml, {
|
||||
return new Response(cachedSitemap, {
|
||||
headers: {
|
||||
'Content-Type': 'application/xml; charset=utf-8',
|
||||
'X-Request-ID': requestId,
|
||||
'X-Cache': 'MISS',
|
||||
'X-Cache': 'HIT',
|
||||
'X-Generation-Time': `${duration}ms`,
|
||||
...cacheHeaders,
|
||||
},
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
const duration = Date.now() - startTime;
|
||||
|
||||
edgeLogger.error('Sitemap generation failed', {
|
||||
requestId,
|
||||
error: formatEdgeError(error),
|
||||
duration,
|
||||
});
|
||||
|
||||
// Return minimal valid sitemap on error (graceful degradation)
|
||||
const fallbackSitemap = generateFallbackSitemap();
|
||||
|
||||
return new Response(fallbackSitemap, {
|
||||
status: 200, // Still return 200 for SEO
|
||||
headers: {
|
||||
'Content-Type': 'application/xml; charset=utf-8',
|
||||
'X-Request-ID': requestId,
|
||||
'X-Error': 'true',
|
||||
'Cache-Control': 'public, max-age=300', // Cache errors for 5min only
|
||||
},
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Generate fresh sitemap
|
||||
const sitemap = await generateSitemap(requestId, span);
|
||||
|
||||
// Update cache
|
||||
cachedSitemap = sitemap.xml;
|
||||
cacheTimestamp = Date.now();
|
||||
|
||||
const duration = Date.now() - startTime;
|
||||
|
||||
addSpanEvent(span, 'sitemap_cache_miss', {
|
||||
duration,
|
||||
stats: sitemap.stats,
|
||||
});
|
||||
|
||||
return new Response(sitemap.xml, {
|
||||
headers: {
|
||||
'Content-Type': 'application/xml; charset=utf-8',
|
||||
'X-Cache': 'MISS',
|
||||
'X-Generation-Time': `${duration}ms`,
|
||||
...cacheHeaders,
|
||||
},
|
||||
});
|
||||
}));
|
||||
|
||||
Reference in New Issue
Block a user