hAPI_face2 / src /routes /river.ts
deploy's picture
Deploy hAPI-face2 mediator 2025-10-07T05:24:34Z
5816640
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);
}
});
}