Spaces:
Build error
Build error
File size: 2,079 Bytes
5816640 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 | import type { Router } from 'express';
import { supabase, tableMissing } from '../supabase.js';
interface RevenueStreamRecord {
amount: number;
status: string;
metadata: Record<string, any> | null;
}
export function registerRiverRoutes(router: Router) {
router.get('/river/tools', async (_req, res, next) => {
try {
const { data, error } = await supabase
.from('river_tools')
.select('*')
.order('created_at', { ascending: false });
if (error && !tableMissing(error)) throw error;
res.json({ tools: data ?? [] });
} catch (error) {
next(error);
}
});
router.get('/river/analytics/:toolId', async (req, res, next) => {
const { toolId } = req.params;
try {
const { data, error } = await supabase
.from('river_tool_metrics')
.select('*')
.eq('tool_id', toolId)
.order('recorded_at', { ascending: false })
.limit(1)
.single();
if (!error && data) {
return res.json({ toolId, ...data });
}
if (error && !tableMissing(error)) {
throw error;
}
// Fallback to aggregate revenue streams
const { data: revenueData, error: revenueError } = await supabase
.from('revenue_streams')
.select('amount,status,metadata');
if (revenueError && !tableMissing(revenueError)) throw revenueError;
const streams = (revenueData ?? []) as RevenueStreamRecord[];
const relevant = streams.filter(stream => {
const meta = stream.metadata || {};
return meta.tool_id === toolId || meta.toolId === toolId;
});
const revenue = relevant.reduce((sum, stream) => sum + (stream.status === 'confirmed' ? stream.amount : 0), 0);
const conversions = relevant.length;
res.json({
toolId,
revenue,
conversions,
subscribers: conversions, // placeholder until distinct subscribers tracked
mrr: revenue,
timestamp: new Date().toISOString(),
});
} catch (error) {
next(error);
}
});
}
|