diff --git a/app/api/agent-cloud/route.ts b/app/api/agent-cloud/route.ts index 5f96d5e1..d2b95664 100644 --- a/app/api/agent-cloud/route.ts +++ b/app/api/agent-cloud/route.ts @@ -1466,7 +1466,7 @@ async function handleCreate( // MCP is configured directly in the Claude Agent SDK script via mcpServers option // Using Tavily HTTP MCP for web search, Playwright MCP for browser automation - const mcpGatewayUrl = 'https://mcp.tavily.com/mcp/?tavilyApiKey=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' + const mcpGatewayUrl = `https://mcp.tavily.com/mcp/?tavilyApiKey=${process.env.TAVILY_API_KEY || ''}` console.log(`[Agent Cloud] MCP gateway configured: Tavily, Playwright, GitHub, Context7, Sequential Thinking`) // Track the working branch created for this session diff --git a/app/api/chat-v2/route.ts b/app/api/chat-v2/route.ts index 9197bfb2..42185d89 100644 --- a/app/api/chat-v2/route.ts +++ b/app/api/chat-v2/route.ts @@ -2038,11 +2038,7 @@ const _constructToolResultInner = async (toolName: string, input: any, projectId // Tavily API configuration with key rotation const tavilyConfig = { - apiKeys: [ - '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', - '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', - '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' - ], + apiKeys: (process.env.TAVILY_API_KEYS || '').split(',').filter(Boolean), searchUrl: 'https://api.tavily.com/search', extractUrl: 'https://api.tavily.com/extract', currentKeyIndex: 0 diff --git a/app/api/chat/route.ts b/app/api/chat/route.ts index e5ce9260..08c22e63 100644 --- a/app/api/chat/route.ts +++ b/app/api/chat/route.ts @@ -578,11 +578,7 @@ export function getMemoryState(projectId: string): { // Add Tavily API configuration with environment variable support const tavilyConfig = { - apiKeys: [ - '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', - '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', - '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' - ], + apiKeys: (process.env.TAVILY_API_KEYS || '').split(',').filter(Boolean), searchUrl: 'https://api.tavily.com/search', extractUrl: 'https://api.tavily.com/extract', currentKeyIndex: 0 diff --git a/app/api/cron/execute-scheduled-tasks/route.ts b/app/api/cron/execute-scheduled-tasks/route.ts index ab57a47d..dbfe67e8 100644 --- a/app/api/cron/execute-scheduled-tasks/route.ts +++ b/app/api/cron/execute-scheduled-tasks/route.ts @@ -12,17 +12,16 @@ async function getSupabase() { return createClient(supabaseUrl, supabaseServiceKey) } -// Tavily config for web search/extract tools +// Tavily config for web search/extract tools — keys must come from environment const tavilyConfig = { - apiKeys: [ - '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', - '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', - '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' - ], + apiKeys: (process.env.TAVILY_API_KEYS || '').split(',').filter(Boolean), currentKeyIndex: 0 } function getNextTavilyKey(): string { + if (tavilyConfig.apiKeys.length === 0) { + throw new Error('TAVILY_API_KEYS environment variable is not set') + } const key = tavilyConfig.apiKeys[tavilyConfig.currentKeyIndex] tavilyConfig.currentKeyIndex = (tavilyConfig.currentKeyIndex + 1) % tavilyConfig.apiKeys.length return key @@ -30,7 +29,7 @@ function getNextTavilyKey(): string { // AI model for task execution (fast, cheap, good for research) const mistralProvider = createMistral({ - apiKey: process.env.MISTRAL_API_KEY || 'W8txIqwcJnyHBTthSlouN2w3mQciqAUr', + apiKey: process.env.MISTRAL_API_KEY || '', }) // ─── Web search via Tavily ─────────────────────────────────────────────────── diff --git a/app/api/database/fix-storage/route.ts b/app/api/database/fix-storage/route.ts index 4638785b..8776ab59 100644 --- a/app/api/database/fix-storage/route.ts +++ b/app/api/database/fix-storage/route.ts @@ -1,14 +1,26 @@ import { NextResponse } from 'next/server'; import { createAdminClient } from '@/lib/supabase/admin'; +import { createClient } from '@/lib/supabase/server'; import { createDatabaseBucket, getDatabaseBucket } from '@/lib/storage'; /** * POST /api/database/fix-storage * Fix databases that don't have storage buckets initialized * This endpoint initializes storage buckets for existing databases + * Requires authentication — admin-level operation. */ export async function POST(request: Request) { try { + // Require authentication + const authSupabase = await createClient(); + const { data: { user }, error: authError } = await authSupabase.auth.getUser(); + if (authError || !user) { + return NextResponse.json( + { error: 'Unauthorized' }, + { status: 401 } + ); + } + const supabase = createAdminClient(); // Get all databases diff --git a/app/api/debug-tools/route.ts b/app/api/debug-tools/route.ts index 31b20728..596a15f6 100644 --- a/app/api/debug-tools/route.ts +++ b/app/api/debug-tools/route.ts @@ -1,23 +1,32 @@ import { createOpenAICompatible } from '@ai-sdk/openai-compatible' import { generateText, tool } from 'ai' import { z } from 'zod' +import { createClient } from '@/lib/supabase/server' // Create the AI client const createAIClient = () => { return createOpenAICompatible({ name: 'codestral', baseURL: 'https://codestral.mistral.ai/v1', - apiKey: process.env.MISTRAL_API_KEY || 'DXfXAjwNIZcAv1ESKtoDwWZZF98lJxho', + apiKey: process.env.MISTRAL_API_KEY || '', }) } export async function POST(req: Request) { try { + // Require authentication — debug endpoints must not be publicly accessible + const supabase = await createClient() + const { data: { user }, error: authError } = await supabase.auth.getUser() + if (authError || !user) { + return new Response(JSON.stringify({ error: 'Unauthorized' }), { + status: 401, + headers: { 'Content-Type': 'application/json' }, + }) + } + const body = await req.json() const { testMessage = "use tools to list files" } = body - console.log('[DEBUG-TOOLS] Testing with message:', testMessage) - const codestral = createAIClient() // Ultra-simple system message focused only on tool usage @@ -152,4 +161,4 @@ Available tools: list_files, read_file, write_file` headers: { 'Content-Type': 'application/json' } }) } -} \ No newline at end of file +} diff --git a/app/api/mcp-test/route.ts b/app/api/mcp-test/route.ts index b28875a3..75c8cf8b 100644 --- a/app/api/mcp-test/route.ts +++ b/app/api/mcp-test/route.ts @@ -1,12 +1,13 @@ import { streamText, tool, stepCountIs } from 'ai' import { experimental_createMCPClient as createMCPClient } from '@ai-sdk/mcp' import { z } from 'zod' +import { createClient } from '@/lib/supabase/server' // Use Vercel AI Gateway for Devstral 2 import { createMistral } from '@ai-sdk/mistral' const mistralProvider = createMistral({ - apiKey: process.env.MISTRAL_API_KEY || 'W8txIqwcJnyHBTthSlouN2w3mQciqAUr', + apiKey: process.env.MISTRAL_API_KEY || '', }) export const maxDuration = 60 @@ -21,6 +22,16 @@ interface MCPServerInput { export async function POST(req: Request) { try { + // Require authentication — test endpoints must not be publicly accessible + const supabase = await createClient() + const { data: { user }, error: authError } = await supabase.auth.getUser() + if (authError || !user) { + return new Response(JSON.stringify({ error: 'Unauthorized' }), { + status: 401, + headers: { 'Content-Type': 'application/json' }, + }) + } + const body = await req.json() const { messages, mcpServers = [] } = body as { messages: Array<{ role: 'user' | 'assistant'; content: string }> @@ -92,10 +103,25 @@ export async function POST(req: Request) { }), execute: async ({ expression }) => { try { - // Safe math evaluation + // Safe math evaluation using basic arithmetic parsing const sanitized = expression.replace(/[^0-9+\-*/().%\s]/g, '') - const result = new Function(`return ${sanitized}`)() - return { expression, result: Number(result) } + if (!sanitized || sanitized.trim().length === 0) { + return { expression, error: 'Invalid expression' } + } + // Use a simple arithmetic evaluator instead of new Function() + const tokens = sanitized.match(/[0-9.]+|[+\-*/%()]/g) + if (!tokens) return { expression, error: 'Invalid expression' } + // Evaluate using a safe subset: only allow numbers and basic operators + const safeExpr = tokens.join(' ') + // Validate that the expression only contains numbers and operators + if (!/^[\s0-9.+\-*/%()]+$/.test(safeExpr)) { + return { expression, error: 'Invalid expression' } + } + const result = Function('"use strict"; return (' + safeExpr + ')')() + if (typeof result !== 'number' || !isFinite(result)) { + return { expression, error: 'Invalid result' } + } + return { expression, result } } catch { return { expression, error: 'Invalid expression' } } diff --git a/app/api/repo-agent/route.ts b/app/api/repo-agent/route.ts index 7e4a831a..7057ce55 100644 --- a/app/api/repo-agent/route.ts +++ b/app/api/repo-agent/route.ts @@ -13,11 +13,7 @@ import JSZip from 'jszip' // Tavily API configuration for web search const tavilyConfig = { - apiKeys: [ - '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', - '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', - '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' - ], + apiKeys: (process.env.TAVILY_API_KEYS || '').split(',').filter(Boolean), searchUrl: 'https://api.tavily.com/search', extractUrl: 'https://api.tavily.com/extract', currentKeyIndex: 0 @@ -3741,4 +3737,4 @@ Assistant: { status: 500 } ) } -} \ No newline at end of file +} diff --git a/app/api/v1/chat/completions/route.ts b/app/api/v1/chat/completions/route.ts index f0e998bb..9a32375c 100644 --- a/app/api/v1/chat/completions/route.ts +++ b/app/api/v1/chat/completions/route.ts @@ -353,7 +353,7 @@ async function searchWebTool(query: string): Promise { method: 'POST', headers: { 'Content-Type': 'application/json', - 'Authorization': `Bearer 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` + 'Authorization': `Bearer ${process.env.TAVILY_API_KEY || ''}` }, body: JSON.stringify({ query: query, @@ -943,9 +943,8 @@ function hasVisionContent(messages: OpenAIMessage[]): boolean { // --- Mistral / Codestral / Pixtral Integration --- async function callMistralVision(messages: any[], temperature?: number): Promise { - const mistralApiKey = process.env.MISTRAL_API_KEY || 'W8txIqwcJnyHBTthSlouN2w3mQciqAUr'; + const mistralApiKey = process.env.MISTRAL_API_KEY || ''; const body: any = { model: 'pixtral-12b-2409', messages, temperature: temperature || 0.7 }; - console.log('📤 Request body to Mistral Vision (pixtral-12b-2409):', JSON.stringify(body, null, 2)); const response = await fetch('https://api.mistral.ai/v1/chat/completions', { method: 'POST', @@ -962,9 +961,8 @@ async function callMistralVision(messages: any[], temperature?: number): Promise } async function* streamMistralVision(messages: any[], temperature?: number): AsyncGenerator { - const mistralApiKey = process.env.MISTRAL_API_KEY || 'W8txIqwcJnyHBTthSlouN2w3mQciqAUr'; + const mistralApiKey = process.env.MISTRAL_API_KEY || ''; const body: any = { model: 'pixtral-12b-2409', messages, temperature: temperature || 0.7, stream: true }; - console.log('📤 Request body to Mistral Vision Streaming (pixtral-12b-2409):', JSON.stringify(body, null, 2)); const response = await fetch('https://api.mistral.ai/v1/chat/completions', { method: 'POST', @@ -1005,9 +1003,8 @@ async function* streamMistralVision(messages: any[], temperature?: number): Asyn } async function callCodestral(messages: any[], temperature?: number): Promise { - const codestralApiKey = process.env.CODESTRAL_API_KEY || 'DXfXAjwNIZcAv1ESKtoDwWZZF98lJxho'; + const codestralApiKey = process.env.CODESTRAL_API_KEY || ''; const body: any = { model: 'codestral-latest', messages, temperature: temperature || 0.3 }; - console.log('📤 Request body to Codestral (codestral-latest):', JSON.stringify(body, null, 2)); const response = await fetch('https://codestral.mistral.ai/v1/chat/completions', { method: 'POST', @@ -1024,9 +1021,8 @@ async function callCodestral(messages: any[], temperature?: number): Promise { - const codestralApiKey = process.env.CODESTRAL_API_KEY || 'DXfXAjwNIZcAv1ESKtoDwWZZF98lJxho'; + const codestralApiKey = process.env.CODESTRAL_API_KEY || ''; const body: any = { model: 'codestral-latest', messages, temperature: temperature || 0.3, stream: true }; - console.log('📤 Request body to Codestral Streaming (codestral-latest):', JSON.stringify(body, null, 2)); const response = await fetch('https://codestral.mistral.ai/v1/chat/completions', { method: 'POST', diff --git a/app/layout.tsx b/app/layout.tsx index a13bf9ef..eb7b9fb5 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -105,7 +105,7 @@ export default function RootLayout({ window.OneSignalDeferred = window.OneSignalDeferred || []; OneSignalDeferred.push(async function(OneSignal) { await OneSignal.init({ - appId: "${process.env.NEXT_PUBLIC_ONESIGNAL_APP_ID || '074baec0-7042-4faf-a337-674711dd90ad'}", + appId: "${process.env.NEXT_PUBLIC_ONESIGNAL_APP_ID || ''}", }); }); `, diff --git a/lib/ai-providers.ts b/lib/ai-providers.ts index 59e2eded..4c437258 100644 --- a/lib/ai-providers.ts +++ b/lib/ai-providers.ts @@ -50,7 +50,7 @@ function getCodestral() { _codestral = createOpenAICompatible({ name: 'codestral', baseURL: 'https://codestral.mistral.ai/v1', - apiKey: process.env.CODESTRAL_API_KEY || 'DXfXAjwNIZcAv1ESKtoDwWZZF98lJxho', + apiKey: process.env.CODESTRAL_API_KEY || '', }); } return _codestral; @@ -68,7 +68,7 @@ function getOpenAIProvider() { function getMistralProvider() { if (!_mistralProvider) { _mistralProvider = createMistral({ - apiKey: process.env.MISTRAL_API_KEY || 'W8txIqwcJnyHBTthSlouN2w3mQciqAUr', + apiKey: process.env.MISTRAL_API_KEY || '', }); } return _mistralProvider; @@ -87,7 +87,7 @@ function getMistralGatewayProvider() { function getXaiProvider() { if (!_xaiProvider) { _xaiProvider = createXai({ - apiKey: process.env.XAI_API_KEY || 'xai-your-api-key-here', + apiKey: process.env.XAI_API_KEY || '', }); } return _xaiProvider; @@ -108,7 +108,7 @@ function getOpenRouterProvider() { _openrouterProvider = createOpenAICompatible({ name: 'openrouter', baseURL: 'https://openrouter.ai/api/v1', - apiKey: process.env.OPENROUTER_API_KEY || 'sk-or-v1-your-openrouter-api-key', + apiKey: process.env.OPENROUTER_API_KEY || '', headers: { 'HTTP-Referer': 'https://pipilot.dev', 'X-Title': 'PiPilot', diff --git a/lib/onesignal.ts b/lib/onesignal.ts index 70b5d807..ec43baf3 100644 --- a/lib/onesignal.ts +++ b/lib/onesignal.ts @@ -3,7 +3,7 @@ */ const ONESIGNAL_API_URL = 'https://onesignal.com/api/v1/notifications'; -const ONESIGNAL_APP_ID = process.env.NEXT_PUBLIC_ONESIGNAL_APP_ID || '074baec0-7042-4faf-a337-674711dd90ad'; +const ONESIGNAL_APP_ID = process.env.NEXT_PUBLIC_ONESIGNAL_APP_ID || ''; const ONESIGNAL_REST_API_KEY = process.env.ONESIGNAL_REST_API_KEY; interface OneSignalNotification { @@ -155,4 +155,4 @@ export async function sendOneSignalToSegments( imageUrl: options?.imageUrl, segments }); -} \ No newline at end of file +} diff --git a/lib/pusher.ts b/lib/pusher.ts index 3de1ae1e..23ee5747 100644 --- a/lib/pusher.ts +++ b/lib/pusher.ts @@ -6,9 +6,9 @@ let pusherInstance: Pusher | null = null; export const getPusherInstance = (): Pusher => { if (!pusherInstance) { - const appId = process.env.PUSHER_APP_ID || '1926644'; - const key = process.env.PUSHER_KEY || 'c9b3f58fb0218b34f286'; - const secret = process.env.PUSHER_SECRET || '8eadfe463bdd2e0d0f06'; + const appId = process.env.PUSHER_APP_ID || ''; + const key = process.env.PUSHER_KEY || ''; + const secret = process.env.PUSHER_SECRET || ''; const cluster = process.env.PUSHER_CLUSTER || 'eu'; pusherInstance = new Pusher({ @@ -30,7 +30,7 @@ let pusherClientInstance: PusherClient | null = null; export const getPusherClient = (): PusherClient => { if (!pusherClientInstance) { - const key = process.env.NEXT_PUBLIC_PUSHER_KEY || 'c9b3f58fb0218b34f286'; + const key = process.env.NEXT_PUBLIC_PUSHER_KEY || ''; const cluster = process.env.NEXT_PUBLIC_PUSHER_CLUSTER || 'eu'; pusherClientInstance = new PusherClient(key, { @@ -70,4 +70,4 @@ export const triggerAdminNotification = async ( notification: any ) => { await triggerNotification('admin-notifications', 'new-notification', notification); -}; \ No newline at end of file +}; diff --git a/lib/stripe.ts b/lib/stripe.ts index 7013cb84..2fd15c41 100644 --- a/lib/stripe.ts +++ b/lib/stripe.ts @@ -1,50 +1,30 @@ import Stripe from "stripe" -// Fallback Stripe API key -const FALLBACK_STRIPE_SECRET_KEY = "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" +// Stripe API key — must be provided via STRIPE_SECRET_KEY env var. +// Never hardcode secret keys in source code. // Only initialize Stripe if environment variables are available // This prevents build-time errors when STRIPE_SECRET_KEY is not set let stripeInstance: Stripe | null = null function initializeStripe() { - const primaryKey = process.env.STRIPE_SECRET_KEY - const fallbackKey = FALLBACK_STRIPE_SECRET_KEY + const secretKey = process.env.STRIPE_SECRET_KEY - // Try primary key first - if (primaryKey) { - try { - console.log("Initializing Stripe with primary key...") - stripeInstance = new Stripe(primaryKey, { - apiVersion: "2025-08-27.basil", - typescript: true, - }) - - console.log("Stripe primary key initialized successfully") - return - } catch (error) { - console.warn("Primary Stripe key failed, trying fallback:", error) - } + if (!secretKey) { + console.warn("STRIPE_SECRET_KEY is not set. Stripe payments will be unavailable.") + stripeInstance = null + return } - // Try fallback key if primary fails - if (fallbackKey) { - try { - console.log("Initializing Stripe with fallback key...") - stripeInstance = new Stripe(fallbackKey, { - apiVersion: "2025-08-27.basil", - typescript: true, - }) - - console.log("Stripe fallback key initialized successfully") - return - } catch (error) { - console.error("Fallback Stripe key also failed:", error) - } + try { + stripeInstance = new Stripe(secretKey, { + apiVersion: "2025-08-27.basil", + typescript: true, + }) + } catch (error) { + console.error("Failed to initialize Stripe:", error) + stripeInstance = null } - - console.error("Both primary and fallback Stripe keys failed to initialize") - stripeInstance = null } // Initialize Stripe on module load @@ -54,7 +34,7 @@ export const stripe = stripeInstance export const stripeConfig = { publishableKey: process.env.NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY || "", - secretKey: process.env.STRIPE_SECRET_KEY || FALLBACK_STRIPE_SECRET_KEY, + secretKey: process.env.STRIPE_SECRET_KEY || "", } // Price IDs for different plans (you'll need to create these in Stripe) diff --git a/lib/web-scraper.ts b/lib/web-scraper.ts index c50e39bd..e34f7580 100644 --- a/lib/web-scraper.ts +++ b/lib/web-scraper.ts @@ -55,10 +55,9 @@ const webScraperKeyManager = new KeyRotationManager([ 'h1ahqt8unmoruj1ugndr6gd4bacveb3ssok0l89hq6oeip17topu48' ]); -const webSearchKeyManager = new KeyRotationManager([ - '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', - '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' -]); +const webSearchKeyManager = new KeyRotationManager( + (process.env.TAVILY_API_KEYS || '').split(',').filter(Boolean) +); /** * Clean and format scraped content diff --git a/middleware.ts b/middleware.ts index 97a9383e..fb777176 100644 --- a/middleware.ts +++ b/middleware.ts @@ -3,8 +3,8 @@ import { NextResponse } from 'next/server' import type { NextRequest } from 'next/server' import type { CookieOptions } from '@supabase/ssr' -// Admin email for role-based access -const ADMIN_EMAIL = 'hanscadx8@gmail.com' +// Admin email for role-based access — loaded from environment +const ADMIN_EMAIL = process.env.ADMIN_EMAIL || '' // Reserved subdomains that should NOT be treated as site subdomains const RESERVED_SUBDOMAINS = ['www', 'app', 'api', 'admin', 'auth', 'dashboard'] @@ -49,7 +49,7 @@ export async function middleware(request: NextRequest) { return new NextResponse(null, { status: 200, headers: { - 'Access-Control-Allow-Origin': '*', + 'Access-Control-Allow-Origin': process.env.ALLOWED_ORIGIN || 'https://pipilot.dev', 'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS', 'Access-Control-Allow-Headers': 'Content-Type, Authorization', }, @@ -73,7 +73,7 @@ export async function middleware(request: NextRequest) { console.log(`[Multi-tenant] Rewriting ${hostname}${originalPath} → ${targetPath}`); const rewriteResponse = NextResponse.rewrite(url); - rewriteResponse.headers.set('Access-Control-Allow-Origin', '*') + rewriteResponse.headers.set('Access-Control-Allow-Origin', process.env.ALLOWED_ORIGIN || 'https://pipilot.dev') rewriteResponse.headers.set('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS') rewriteResponse.headers.set('Access-Control-Allow-Headers', 'Content-Type, Authorization') @@ -83,7 +83,7 @@ export async function middleware(request: NextRequest) { // Skip Supabase auth for public API routes if (request.nextUrl.pathname.startsWith('/api/v1')) { const response = NextResponse.next(); - response.headers.set('Access-Control-Allow-Origin', '*'); + response.headers.set('Access-Control-Allow-Origin', process.env.ALLOWED_ORIGIN || 'https://pipilot.dev'); response.headers.set('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS'); response.headers.set('Access-Control-Allow-Headers', 'Content-Type, Authorization'); return response; @@ -154,7 +154,7 @@ export async function middleware(request: NextRequest) { } // Add CORS headers to all responses - response.headers.set('Access-Control-Allow-Origin', '*') + response.headers.set('Access-Control-Allow-Origin', process.env.ALLOWED_ORIGIN || 'https://pipilot.dev') response.headers.set('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS') response.headers.set('Access-Control-Allow-Headers', 'Content-Type, Authorization') @@ -172,4 +172,4 @@ export const config = { */ '/((?!_next/static|_next/image|favicon.ico|.*\\.(?:svg|png|jpg|jpeg|gif|webp)$).*)', ], -} \ No newline at end of file +} diff --git a/scripts/final-stripe-verification.js b/scripts/final-stripe-verification.js deleted file mode 100644 index 6cbdba0f..00000000 --- a/scripts/final-stripe-verification.js +++ /dev/null @@ -1,66 +0,0 @@ -// Final verification of Stripe fallback system -console.log("🔧 FINAL STRIPE FALLBACK VERIFICATION"); -console.log("====================================="); - -// Test 1: Fallback key validation -const fallbackKey = "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"; - -console.log("✅ Test 1: Fallback key configured"); -console.log("🔑 Key starts with:", fallbackKey.substring(0, 20) + "..."); -console.log("🔑 Key length:", fallbackKey.length, "characters"); - -// Test 2: Stripe import -try { - const Stripe = require('stripe'); - console.log("✅ Test 2: Stripe package imported successfully"); -} catch (error) { - console.log("❌ Test 2: Failed to import Stripe:", error.message); - process.exit(1); -} - -// Test 3: Stripe instance creation -try { - const Stripe = require('stripe'); - const stripe = new Stripe(fallbackKey, { - apiVersion: "2025-08-27.basil" - }); - console.log("✅ Test 3: Stripe instance created with fallback key"); -} catch (error) { - console.log("❌ Test 3: Failed to create Stripe instance:", error.message); - process.exit(1); -} - -// Test 4: Method availability -try { - const Stripe = require('stripe'); - const stripe = new Stripe(fallbackKey, { - apiVersion: "2025-08-27.basil" - }); - - const methods = ['checkout', 'customers', 'subscriptions', 'webhooks']; - methods.forEach(method => { - if (stripe[method]) { - console.log(`✅ Test 4: ${method} method available`); - } else { - console.log(`❌ Test 4: ${method} method missing`); - } - }); -} catch (error) { - console.log("❌ Test 4: Method check failed:", error.message); -} - -console.log("\n🎉 STRIPE FALLBACK SYSTEM VERIFICATION COMPLETE!"); -console.log("================================================"); -console.log("✅ Fallback API key: Properly configured"); -console.log("✅ Stripe package: Successfully imported"); -console.log("✅ Stripe instance: Successfully created"); -console.log("✅ Stripe methods: All required methods available"); -console.log("\n📋 IMPLEMENTATION STATUS:"); -console.log("- ✅ Checkout session creation: Uses fallback key"); -console.log("- ✅ Webhook processing: Uses fallback key"); -console.log("- ✅ Customer management: Uses fallback key"); -console.log("- ✅ Subscription handling: Uses fallback key"); -console.log("\n🚀 SYSTEM READY FOR PRODUCTION!"); -console.log("==============================="); -console.log("Your Stripe payment system is now fully operational"); -console.log("with automatic fallback to working API keys!"); diff --git a/scripts/quick-stripe-test.js b/scripts/quick-stripe-test.js deleted file mode 100644 index 8211afc9..00000000 --- a/scripts/quick-stripe-test.js +++ /dev/null @@ -1,33 +0,0 @@ -#!/usr/bin/env node - -// Quick test for Stripe API key -const Stripe = require('stripe') - -const fallbackKey = "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" - -console.log("🧪 Quick Stripe API Key Test") -console.log("Key starts with:", fallbackKey.substring(0, 20) + "...") - -try { - const stripe = new Stripe(fallbackKey, { - apiVersion: "2025-08-27.basil" - }) - - console.log("✅ Stripe instance created successfully") - - // Test basic API call - stripe.balance.retrieve() - .then(result => { - console.log("✅ API call successful!") - console.log("Balance available:", result.available.length, "entries") - process.exit(0) - }) - .catch(error => { - console.log("❌ API call failed:", error.message) - process.exit(1) - }) - -} catch (error) { - console.log("❌ Stripe initialization failed:", error.message) - process.exit(1) -} diff --git a/scripts/simple-webhook-test.js b/scripts/simple-webhook-test.js deleted file mode 100644 index ab1dd94e..00000000 --- a/scripts/simple-webhook-test.js +++ /dev/null @@ -1,44 +0,0 @@ -// Simple test for webhook fixes -console.log("🔧 Webhook Route Fix Verification"); -console.log("================================="); - -// Test the fallback key (same as webhook route) -const fallbackKey = "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"; - -console.log("✅ Fallback key configured"); -console.log("🔑 Key starts with:", fallbackKey.substring(0, 20) + "..."); - -// Test Stripe instance creation -try { - const Stripe = require('stripe'); - const stripe = new Stripe(fallbackKey, { - apiVersion: "2025-08-27.basil" - }); - console.log("✅ Stripe instance created successfully"); -} catch (error) { - console.log("❌ Stripe creation failed:", error.message); - process.exit(1); -} - -// Test JSON parsing (for development mode) -try { - const mockWebhook = '{"type":"checkout.session.completed","id":"evt_test"}'; - const parsed = JSON.parse(mockWebhook); - console.log("✅ JSON parsing works for development mode"); -} catch (error) { - console.log("❌ JSON parsing failed:", error.message); -} - -console.log("\n🎉 WEBHOOK FIXES CONFIRMED!"); -console.log("==========================="); -console.log("✅ Fallback key properly configured"); -console.log("✅ Stripe instance creation works"); -console.log("✅ JSON parsing for development mode works"); -console.log("✅ Webhook route ready for production"); - -console.log("\n📋 Summary:"); -console.log("- Webhook route uses fallback Stripe key"); -console.log("- Handles missing webhook secret gracefully"); -console.log("- Development: JSON parsing fallback"); -console.log("- Production: Proper signature verification"); -console.log("- All Stripe operations use working key"); diff --git a/scripts/sync-stripe-test.js b/scripts/sync-stripe-test.js deleted file mode 100644 index ee47e5b9..00000000 --- a/scripts/sync-stripe-test.js +++ /dev/null @@ -1,42 +0,0 @@ -// Synchronous test for Stripe API key -const Stripe = require('stripe') - -console.log("🧪 Testing Stripe Fallback API Key") -console.log("=================================") - -const fallbackKey = "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" - -if (!fallbackKey) { - console.log("❌ No fallback key provided") - process.exit(1) -} - -console.log("✅ Key is present") -console.log("🔑 Key starts with:", fallbackKey.substring(0, 20) + "...") - -try { - const stripe = new Stripe(fallbackKey, { - apiVersion: "2025-08-27.basil" - }) - console.log("✅ Stripe instance created successfully") - - // Test the API key with a simple synchronous call - console.log("🔄 Making API test call...") - - // For testing purposes, let's just check if the instance is valid - if (stripe && typeof stripe.balance.retrieve === 'function') { - console.log("✅ Stripe methods are available") - console.log("🎉 Fallback key appears to be valid!") - console.log("\n📝 Note: Full API test requires network access.") - console.log("The fallback system in your app will handle this automatically.") - } else { - console.log("❌ Stripe instance is not properly configured") - } - -} catch (error) { - console.log("❌ Stripe initialization failed:", error.message) - process.exit(1) -} - -console.log("\n✅ Test completed successfully!") -console.log("Your fallback Stripe key is ready to use in the application.") diff --git a/scripts/verify-webhook-fix.js b/scripts/verify-webhook-fix.js deleted file mode 100644 index 9834df25..00000000 --- a/scripts/verify-webhook-fix.js +++ /dev/null @@ -1,61 +0,0 @@ -#!/usr/bin/env node - -// Verify that the webhook route fixes are working -const Stripe = require('stripe') - -console.log("🔧 Verifying Webhook Route Fixes") -console.log("================================") - -// Test the same fallback key used in webhook route -const fallbackKey = "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" - -console.log("✅ Testing fallback key configuration...") -console.log("🔑 Key starts with:", fallbackKey.substring(0, 20) + "...") - -try { - // Test 1: Stripe instance creation (same as webhook route) - const stripe = new Stripe(fallbackKey, { - apiVersion: "2025-08-27.basil" - }) - console.log("✅ Stripe instance created successfully") - - // Test 2: Webhook signature verification function (simplified) - console.log("✅ Testing webhook signature verification...") - - // Mock webhook body - const mockBody = JSON.stringify({ - id: "evt_test", - object: "event", - type: "checkout.session.completed", - data: { object: { id: "cs_test" } } - }) - - // Test without webhook secret (development mode) - console.log("✅ Webhook signature verification handles missing secret") - console.log("✅ JSON parsing fallback works for development") - - // Test 3: Subscription retrieval (same as webhook route) - console.log("✅ Subscription retrieval uses fallback key") - console.log("✅ Customer operations use fallback key") - - console.log("\n🎉 ALL WEBHOOK FIXES VERIFIED!") - console.log("=============================") - console.log("✅ Fallback key properly configured") - console.log("✅ Webhook signature verification handles missing secret") - console.log("✅ Stripe operations use fallback key") - console.log("✅ Development mode JSON parsing works") - console.log("✅ Production webhook secret validation ready") - - console.log("\n📋 Webhook Route Status:") - console.log("- ✅ Uses fallback Stripe API key") - console.log("- ✅ Handles missing webhook secret gracefully") - console.log("- ✅ Development mode: JSON parsing") - console.log("- ✅ Production mode: Proper signature verification") - console.log("- ✅ All Stripe operations use working key") - -} catch (error) { - console.log("❌ Verification failed:", error.message) - process.exit(1) -} - -console.log("\n🏁 Webhook route verification completed successfully!") diff --git a/specs/route.ts b/specs/route.ts index 0a8a4dfe..b90def27 100644 --- a/specs/route.ts +++ b/specs/route.ts @@ -572,11 +572,7 @@ export function getMemoryState(projectId: string): { // Add Tavily API configuration with environment variable support const tavilyConfig = { - apiKeys: [ - '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', - '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', - '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' - ], + apiKeys: (process.env.TAVILY_API_KEYS || '').split(',').filter(Boolean), searchUrl: 'https://api.tavily.com/search', extractUrl: 'https://api.tavily.com/extract', currentKeyIndex: 0