fix(cli): reject negative and fractional count/pagination flags in Danish portal CLIs (#191)

Bare z.coerce.number() accepted negative and fractional values for count/pagination flags, and slice(0, limit) with a negative limit silently dropped trailing results instead of erroring. Tightens the schemas to .int().min(1) across all four Danish portal CLIs (including jobnet occupations --per-page) with network-free validation tests.

By @ayobamiseun.
This commit is contained in:
Ayobami Adegoke
2026-07-19 19:38:48 +02:00
committed by GitHub
parent 3a184bc115
commit 70e0eb43ce
13 changed files with 228 additions and 13 deletions
@@ -22,7 +22,7 @@ export const autocomplete = defineCommand({
query: option(z.string().optional(), {
description: "Search text to autocomplete (required)",
}),
limit: option(z.coerce.number().optional(), {
limit: option(z.coerce.number().int().min(1).optional(), {
description: "Cap total suggestions returned",
}),
format: option(z.enum(["json", "table", "plain"]).default("json"), {
@@ -13,7 +13,7 @@ export const categories = defineCommand({
name: "categories",
description: "List all job categories with live counts",
options: {
limit: option(z.coerce.number().optional(), {
limit: option(z.coerce.number().int().min(1).optional(), {
description: "Cap number of categories returned",
}),
format: option(z.enum(["json", "table", "plain"]).default("json"), {
@@ -22,7 +22,7 @@ export const locations = defineCommand({
query: option(z.string().optional(), {
description: "Location text to search (city, zip code, region) (required)",
}),
limit: option(z.coerce.number().optional(), {
limit: option(z.coerce.number().int().min(1).optional(), {
description: "Cap total suggestions returned",
}),
format: option(z.enum(["json", "table", "plain"]).default("json"), {
@@ -105,10 +105,10 @@ export const search = defineCommand({
"job-type": option(z.string().optional(), {
description: "Comma-separated job types: fuldtid,deltid,fleksjob,elev,studiejob,praktik",
}),
page: option(z.coerce.number().default(1), {
page: option(z.coerce.number().int().min(1).default(1), {
description: "Page number (30 items per page, server-enforced)",
}),
limit: option(z.coerce.number().optional(), {
limit: option(z.coerce.number().int().min(1).optional(), {
description: "Cap total results returned by CLI (client-side)",
}),
format: option(z.enum(["json", "table", "plain"]).default("json"), {