From aebebecf1b97cd3593622fff0f10040fb574043b Mon Sep 17 00:00:00 2001 From: Christian Vidal Wolf Date: Sat, 21 Feb 2026 00:25:04 +0100 Subject: [PATCH] Fix Vercel function limit - remove unused API endpoints - Removed fetch-forecast.ts (not used) - Removed fetch-vendor-stock.ts (not used) - Removed migrate-experiments.ts (manual SQL migration is sufficient) - Kept 10 essential API functions (limit is 12 on Hobby plan) Co-authored-by: Qwen-Coder --- api/fetch-forecast.ts | 49 ----------------- api/fetch-vendor-stock.ts | 49 ----------------- api/migrate-experiments.ts | 106 ------------------------------------- 3 files changed, 204 deletions(-) delete mode 100644 api/fetch-forecast.ts delete mode 100644 api/fetch-vendor-stock.ts delete mode 100644 api/migrate-experiments.ts diff --git a/api/fetch-forecast.ts b/api/fetch-forecast.ts deleted file mode 100644 index ca60504..0000000 --- a/api/fetch-forecast.ts +++ /dev/null @@ -1,49 +0,0 @@ - -import type { VercelRequest, VercelResponse } from '@vercel/node'; -import fs from 'fs'; -import path from 'path'; - -export default async function handler(req: VercelRequest, res: VercelResponse) { - // CORS headers - res.setHeader('Access-Control-Allow-Origin', '*'); - res.setHeader('Access-Control-Allow-Methods', 'GET, OPTIONS'); - res.setHeader('Access-Control-Allow-Headers', 'Content-Type'); - - if (req.method === 'OPTIONS') { - return res.status(200).end(); - } - - try { - console.log('[fetch-forecast] Reading Forecast file from local storage...'); - // Try multiple possible paths to be robust - const pathsToTry = [ - path.join(process.cwd(), 'fc 26.xlsx'), - path.join(process.cwd(), 'public', 'fc 26.xlsx'), - path.join('/Users/christianvidalwolf/github/CrazeAnalytix', 'fc 26.xlsx') // Direct path as fallback for this environment - ]; - - let buffer = null; - let foundPath = ''; - - for (const p of pathsToTry) { - console.log(`[fetch-forecast] Checking path: ${p}`); - if (fs.existsSync(p)) { - buffer = fs.readFileSync(p); - foundPath = p; - break; - } - } - - if (!buffer) { - throw new Error(`Forecast file 'fc 26.xlsx' not found in any of: ${pathsToTry.join(', ')}`); - } - - console.log(`[fetch-forecast] Successfully read Forecast Excel from ${foundPath}, size: ${buffer.byteLength}`); - - res.setHeader('Content-Type', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'); - res.status(200).send(buffer); - } catch (error: any) { - console.error('[fetch-forecast] Error:', error); - res.status(500).json({ error: error.message }); - } -} diff --git a/api/fetch-vendor-stock.ts b/api/fetch-vendor-stock.ts deleted file mode 100644 index 94d3cf4..0000000 --- a/api/fetch-vendor-stock.ts +++ /dev/null @@ -1,49 +0,0 @@ - -import type { VercelRequest, VercelResponse } from '@vercel/node'; -import fs from 'fs'; -import path from 'path'; - -export default async function handler(req: VercelRequest, res: VercelResponse) { - // CORS headers - res.setHeader('Access-Control-Allow-Origin', '*'); - res.setHeader('Access-Control-Allow-Methods', 'GET, OPTIONS'); - res.setHeader('Access-Control-Allow-Headers', 'Content-Type'); - - if (req.method === 'OPTIONS') { - return res.status(200).end(); - } - - try { - console.log('[fetch-vendor-stock] Reading Vendor Stock file from local storage...'); - // Try multiple possible paths to be robust - const pathsToTry = [ - path.join(process.cwd(), 'Vendor Stock.xlsx'), - path.join(process.cwd(), 'public', 'Vendor Stock.xlsx'), - path.join('/Users/christianvidalwolf/github/CrazeAnalytix', 'Vendor Stock.xlsx') - ]; - - let buffer = null; - let foundPath = ''; - - for (const p of pathsToTry) { - console.log(`[fetch-vendor-stock] Checking path: ${p}`); - if (fs.existsSync(p)) { - buffer = fs.readFileSync(p); - foundPath = p; - break; - } - } - - if (!buffer) { - throw new Error(`Vendor Stock file 'Vendor Stock.xlsx' not found in any of: ${pathsToTry.join(', ')}`); - } - - console.log(`[fetch-vendor-stock] Successfully read Vendor Stock Excel from ${foundPath}, size: ${buffer.byteLength}`); - - res.setHeader('Content-Type', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'); - res.status(200).send(buffer); - } catch (error: any) { - console.error('[fetch-vendor-stock] Error:', error); - res.status(500).json({ error: error.message }); - } -} diff --git a/api/migrate-experiments.ts b/api/migrate-experiments.ts deleted file mode 100644 index bf73b28..0000000 --- a/api/migrate-experiments.ts +++ /dev/null @@ -1,106 +0,0 @@ -import type { VercelRequest, VercelResponse } from '@vercel/node'; -import { createClient } from '@supabase/supabase-js'; - -export default async function handler(req: VercelRequest, res: VercelResponse) { - res.setHeader('Access-Control-Allow-Origin', '*'); - res.setHeader('Access-Control-Allow-Methods', 'POST, OPTIONS'); - res.setHeader('Access-Control-Allow-Headers', 'Content-Type'); - - if (req.method === 'OPTIONS') return res.status(200).end(); - if (req.method !== 'POST') return res.status(405).json({ error: 'Method not allowed' }); - - const supabaseUrl = process.env.SUPABASE_URL; - const supabaseServiceKey = process.env.SUPABASE_SERVICE_KEY; - - if (!supabaseUrl || !supabaseServiceKey) { - return res.status(500).json({ error: 'Supabase credentials not configured' }); - } - - const supabase = createClient(supabaseUrl, supabaseServiceKey); - - const sql = ` - CREATE TABLE IF NOT EXISTS experiments ( - id UUID PRIMARY KEY DEFAULT gen_random_uuid(), - name TEXT NOT NULL, - description TEXT, - type TEXT NOT NULL CHECK (type IN ('pricing', 'advertising', 'content', 'promotion')), - status TEXT NOT NULL DEFAULT 'planned' CHECK (status IN ('planned', 'active', 'completed', 'paused')), - - asins TEXT[] NOT NULL DEFAULT '{}', - marketplace TEXT NOT NULL, - - start_date DATE NOT NULL, - end_date DATE, - created_at TIMESTAMPTZ DEFAULT NOW(), - updated_at TIMESTAMPTZ DEFAULT NOW(), - - hypothesis TEXT, - primary_metric TEXT NOT NULL DEFAULT 'units', - target_lift_percent NUMERIC, - - baseline_units NUMERIC, - baseline_revenue NUMERIC, - experiment_units NUMERIC, - experiment_revenue NUMERIC, - actual_lift_percent NUMERIC, - statistical_significance NUMERIC, - - learnings TEXT, - owner TEXT - ); - - CREATE INDEX IF NOT EXISTS idx_experiments_status ON experiments(status); - CREATE INDEX IF NOT EXISTS idx_experiments_marketplace ON experiments(marketplace); - CREATE INDEX IF NOT EXISTS idx_experiments_type ON experiments(type); - CREATE INDEX IF NOT EXISTS idx_experiments_dates ON experiments(start_date, end_date); - CREATE INDEX IF NOT EXISTS idx_experiments_asins ON experiments USING GIN(asins); - - -- Create updated_at trigger function if not exists - CREATE OR REPLACE FUNCTION update_updated_at_column() - RETURNS TRIGGER AS $$ - BEGIN - NEW.updated_at = NOW(); - RETURN NEW; - END; - $$ LANGUAGE plpgsql; - - -- Create trigger - DROP TRIGGER IF EXISTS update_experiments_updated_at ON experiments; - CREATE TRIGGER update_experiments_updated_at - BEFORE UPDATE ON experiments - FOR EACH ROW - EXECUTE FUNCTION update_updated_at_column(); - `; - - try { - // Execute SQL via Supabase RPC or direct connection - // Since we can't run raw SQL via JS client, we'll create the table using the query builder - - // First check if table exists - const { error: checkError } = await supabase.from('experiments').select('id').limit(1); - - if (checkError && checkError.message.includes('relation') && checkError.message.includes('does not exist')) { - // Table doesn't exist - we need to create it via SQL - // Unfortunately the JS client can't run CREATE TABLE directly - // We'll return instructions - return res.status(200).json({ - message: 'Table needs to be created via SQL Editor', - instructions: 'Please go to Supabase Dashboard → SQL Editor and run the migration SQL', - sql: sql - }); - } - - // Table exists, create indexes - await supabase.rpc('create_experiment_indexes'); - - return res.status(200).json({ - success: true, - message: 'Experiments table is ready' - }); - } catch (error: any) { - return res.status(500).json({ - error: error.message, - instructions: 'Please go to Supabase Dashboard → SQL Editor and run the migration SQL manually' - }); - } -}