Skip to content
6 changes: 3 additions & 3 deletions backend/src/controllers/stream.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -258,7 +258,7 @@ export const listStreams = async (req: Request, res: Response) => {
typeof limit === 'string' ? (Number.parseInt(limit, 10) || DEFAULT_STREAM_PAGE_SIZE) : DEFAULT_STREAM_PAGE_SIZE,
MAX_STREAM_PAGE_SIZE
);
const parsedOffset = typeof offset === 'string' ? (Number.parseInt(offset, 10) || 0) : 0;
const parsedOffset = typeof offset === 'string' ? Math.max(0, Number.parseInt(offset, 10) || 0) : 0;

// Validate sort field
const validSortFields = ['createdAt', 'startTime', 'lastUpdateTime', 'depositedAmount', 'endTime'];
Expand Down Expand Up @@ -375,7 +375,7 @@ export const getStreamEvents = async (req: Request, res: Response) => {

let offset = 0;
if (rawOffset && typeof rawOffset === 'string') {
offset = Number.parseInt(rawOffset, 10) || 0;
offset = Math.max(0, Number.parseInt(rawOffset, 10) || 0);
} else if (rawPage && typeof rawPage === 'string' && !cursor) {
const page = Number.parseInt(rawPage, 10) || 1;
offset = Math.max(0, (page - 1) * limit);
Expand Down Expand Up @@ -655,7 +655,7 @@ export const topUpStreamHandler = async (req: Request, res: Response) => {
return res.status(200).json({ streamId, txHash, depositedAmount: newDeposited });
} catch (error: any) {
logger.error(`[topUp] stream=${streamId} error:`, error);
return res.status(500).json({ error: error.message ?? 'Internal server error' });
return res.status(400).json({ error: 'Failed to top up stream on chain', message: error.message ?? 'Unknown error' });
}
};

Expand Down
2 changes: 1 addition & 1 deletion backend/src/controllers/user.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ export const getUserEvents = async (req: Request, res: Response, next: NextFunct
rawLimit && typeof rawLimit === 'string' ? (Number.parseInt(rawLimit, 10) || DEFAULT_EVENTS_PAGE_SIZE) : DEFAULT_EVENTS_PAGE_SIZE,
MAX_EVENTS_PAGE_SIZE
);
const offset = rawOffset && typeof rawOffset === 'string' ? (Number.parseInt(rawOffset, 10) || 0) : 0;
const offset = rawOffset && typeof rawOffset === 'string' ? Math.max(0, Number.parseInt(rawOffset, 10) || 0) : 0;

const whereClause = {
stream: {
Expand Down
8 changes: 0 additions & 8 deletions backend/src/routes/v1/streams/index.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,8 @@
import { Router } from 'express';
import { requireAuth } from '../../../middleware/auth.js';
import { withdrawHandler } from './withdraw.js';
import oldStreamRoutes from '../stream.routes.js';

const router = Router();

// Mount the old routes first
router.use('/', oldStreamRoutes);

/**
* Override/Add POST /api/v1/streams/:streamId/withdraw
*/
router.post('/:streamId/withdraw', requireAuth, withdrawHandler as any);

export default router;
2 changes: 2 additions & 0 deletions frontend/src/components/dashboard/dashboard-view.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,8 @@ const SIDEBAR_ITEMS: SidebarItem[] = [
/** Shimmer card used as a placeholder while data loads */
function SkeletonCard({ className = "" }: { className?: string }) {
return (
<div className={`relative overflow-hidden rounded-2xl ${className}`}>
<Skeleton className="absolute inset-0" aria-hidden="true" />
<div
className={`animate-pulse bg-gray-200 dark:bg-gray-700 rounded-2xl relative overflow-hidden ${className}`}
aria-hidden="true"
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/hooks/useIncomingStreams.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ export function useWithdrawIncomingStream(

return { previousStreams, expectedWithdrawn };
},
onSuccess: async (result, stream, _variables, context) => {
onSuccess: async (result, stream, context) => {
if (publicKey) {
const ctx = context as {
previousStreams?: IncomingStreamRecord[];
Expand Down
Loading