fix(planner): bound /api/sessions listing (default 50, max 200)
Addresses planner-audit #8. `listSessions()` had no LIMIT — every call to `GET /api/sessions` returned every non-closed session and did a full table scan ordered by last_activity. On a long-running planner host that's both a memory cliff and a query-plan footgun. Now: defaults to 50 rows, clamps to [1, 200], accepts `?limit=` for pagination-light scenarios. `sessions_last_activity_idx` (added in #438) backs the ORDER BY + LIMIT efficiently.
This commit is contained in:
parent
11edcbccb3
commit
6f18ce8099
2 changed files with 16 additions and 4 deletions
|
|
@ -106,12 +106,19 @@ export function initializeSessionWithNoGoAreas(
|
|||
});
|
||||
}
|
||||
|
||||
export async function listSessions(): Promise<SessionMetadata[]> {
|
||||
// Default page size for the listing API. Hard cap so an unbounded
|
||||
// caller can't request thousands of rows (or trigger a full scan).
|
||||
const DEFAULT_LIST_LIMIT = 50;
|
||||
const MAX_LIST_LIMIT = 200;
|
||||
|
||||
export async function listSessions(limit: number = DEFAULT_LIST_LIMIT): Promise<SessionMetadata[]> {
|
||||
const bounded = Math.min(Math.max(1, limit), MAX_LIST_LIMIT);
|
||||
return getDb()
|
||||
.select()
|
||||
.from(sessions)
|
||||
.where(eq(sessions.closed, false))
|
||||
.orderBy(desc(sessions.lastActivity));
|
||||
.orderBy(desc(sessions.lastActivity))
|
||||
.limit(bounded);
|
||||
}
|
||||
|
||||
export async function expireSessions(maxAgeDays: number = 7): Promise<number> {
|
||||
|
|
|
|||
|
|
@ -42,9 +42,14 @@ export async function action({ request }: Route.ActionArgs) {
|
|||
});
|
||||
}
|
||||
|
||||
export async function loader(_args: Route.LoaderArgs) {
|
||||
export async function loader({ request }: Route.LoaderArgs) {
|
||||
return withDb(async () => {
|
||||
const sessions = await listSessions();
|
||||
const url = new URL(request.url);
|
||||
// Accept an explicit `?limit=` but rely on listSessions to clamp
|
||||
// it to a sane upper bound.
|
||||
const limitParam = Number(url.searchParams.get("limit"));
|
||||
const limit = Number.isFinite(limitParam) && limitParam > 0 ? limitParam : undefined;
|
||||
const sessions = await listSessions(limit);
|
||||
return data({ sessions });
|
||||
});
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue