Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions src/app/api/chat/messages/pagination.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
const DEFAULT_LIMIT = 50;
const MAX_LIMIT = 100;
const DEFAULT_OFFSET = 0;

export function normalizeMessagePagination(searchParams) {
return {
limit: readInteger(searchParams.get('limit'), {
fallback: DEFAULT_LIMIT,
min: 1,
max: MAX_LIMIT
}),
offset: readInteger(searchParams.get('offset'), {
fallback: DEFAULT_OFFSET,
min: 0
})
};
}

function readInteger(value, { fallback, min, max }) {
if (value == null || value === '') return fallback;

const parsed = Number(value);
if (!Number.isInteger(parsed) || parsed < min) return fallback;

return typeof max === 'number' ? Math.min(parsed, max) : parsed;
}
32 changes: 32 additions & 0 deletions src/app/api/chat/messages/pagination.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { describe, expect, it } from 'vitest';
import { normalizeMessagePagination } from './pagination.js';

describe('normalizeMessagePagination', () => {
it('uses default pagination when query params are missing', () => {
expect(normalizeMessagePagination(new URLSearchParams())).toEqual({
limit: 50,
offset: 0
});
});

it('accepts valid integer limit and offset params', () => {
expect(normalizeMessagePagination(new URLSearchParams('limit=25&offset=10'))).toEqual({
limit: 25,
offset: 10
});
});

it('falls back for malformed or negative pagination params', () => {
expect(normalizeMessagePagination(new URLSearchParams('limit=1abc&offset=-5'))).toEqual({
limit: 50,
offset: 0
});
});

it('caps oversized limits before building the database range', () => {
expect(normalizeMessagePagination(new URLSearchParams('limit=1000&offset=2'))).toEqual({
limit: 100,
offset: 2
});
});
});
6 changes: 3 additions & 3 deletions src/app/api/chat/messages/route.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import { NextResponse } from 'next/server';
import { createServiceRoleClient } from '@/lib/supabase/service-role.js';
import { createClient } from '@supabase/supabase-js';
import { normalizeMessagePagination } from './pagination.js';
// Lazy service role client creation
let supabaseServiceRole = null;
function getServiceRoleClient() {
Expand Down Expand Up @@ -277,8 +278,7 @@ export async function GET(request) {
console.log('🔐 [API] ✅ Internal user ID:', userId);

const conversationId = url.searchParams.get('conversation_id');
const limit = parseInt(url.searchParams.get('limit') || '50');
const offset = parseInt(url.searchParams.get('offset') || '0');
const { limit, offset } = normalizeMessagePagination(url.searchParams);

if (!conversationId) {
return NextResponse.json({ error: 'Missing conversation_id parameter' }, { status: 400 });
Expand Down Expand Up @@ -492,4 +492,4 @@ export async function PATCH(request, { params } = {}) {
console.error('Error in PATCH /api/chat/messages/:id/read:', error);
return NextResponse.json({ error: 'Internal server error' }, { status: 500 });
}
}
}
Loading