Skip to content
Open
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
8 changes: 8 additions & 0 deletions src/lib/pagination.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,18 @@ describe('validatePaginationFlags', () => {
expect(() => validatePaginationFlags({ pageSize: Number.NaN })).toThrow(ApiError);
});

it('rejects fractional pageSize values', () => {
expect(() => validatePaginationFlags({ pageSize: 1.5 })).toThrow(ApiError);
});

it('rejects maxItems=0', () => {
expect(() => validatePaginationFlags({ maxItems: 0 })).toThrow(ApiError);
});

it('rejects fractional maxItems values', () => {
expect(() => validatePaginationFlags({ maxItems: 2.5 })).toThrow(ApiError);
});

it('accepts pageSize=100 (the hard cap)', () => {
expect(() => validatePaginationFlags({ pageSize: 100 })).not.toThrow();
});
Expand Down
10 changes: 5 additions & 5 deletions src/lib/pagination.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,9 @@ const DEFAULT_PAGE_SIZE = 25;
* Validates and normalizes pagination flags. Per the CLI OpenAPI spec
* §components.parameters.PageSize the hard cap is 100. Values above the
* cap are now rejected with exit 5 rather than silently clamped, giving
* callers fast feedback that their flag value is out of range. Sub-1 /
* NaN values also throw. `maxItems` is validated but not capped (it is a
* client-side cursor, not a server parameter).
* callers fast feedback that their flag value is out of range. Fractional,
* sub-1, and NaN values also throw. `maxItems` is validated but not capped
* (it is a client-side cursor, not a server parameter).
*
* NOTE: `runResultHistory` previously did its own silent clamp via
* `Math.min(Math.max(1, n), 100)` — that was unified to this path by the
Expand All @@ -38,7 +38,7 @@ const DEFAULT_PAGE_SIZE = 25;
export function validatePaginationFlags(flags: PaginationFlags): PaginationFlags {
const out: PaginationFlags = { ...flags };
if (out.pageSize !== undefined) {
if (!Number.isFinite(out.pageSize) || out.pageSize < 1) {
if (!Number.isFinite(out.pageSize) || !Number.isInteger(out.pageSize) || out.pageSize < 1) {
throw localValidationError(
'page-size',
`must be a positive integer between 1 and ${HARD_PAGE_SIZE_CAP}`,
Expand All @@ -52,7 +52,7 @@ export function validatePaginationFlags(flags: PaginationFlags): PaginationFlags
}
}
if (out.maxItems !== undefined) {
if (!Number.isFinite(out.maxItems) || out.maxItems < 1) {
if (!Number.isFinite(out.maxItems) || !Number.isInteger(out.maxItems) || out.maxItems < 1) {
throw localValidationError('maxItems', 'must be a positive integer');
}
}
Expand Down