Correctness fixes to the pagination pipeline. All five were reproduced against a live probe harness before being fixed, and each carries a regression test verified to fail without its fix.
Fixed
- Short first page no longer inflates the page count (#9). The page count is derived from a new
pageSizerequirement onPagedResponserather than from the first response's item count, so a page shortened by server-side filtering can no longer make the client request pages that don't exist — previously one out-of-range 404 discarded the entire load. The tailnext_pageis now adopted only from a page that actually contributed rows, so a clamped page can't trigger a full re-walk. - De-duplication can no longer be silently disabled (#10). Conformers whose
identity(of:)returns nil now take the sequential path, as the documentation always claimed. Previously they entered the parallel path with de-duplication off and could receive duplicate records. - The parallel path is now bounded (#11).
maxParallelPages(1000) mirrorsmaxSequentialPages, so a bogus servertotalcan't turn one call into thousands of requests. - A large
totalno longer crashes the process (#12).totalis range-checked before the page-count arithmetic, surfacing a decode error instead of trapping on overflow. - The pipeline genuinely runs off the main actor (#13).
streamAllPages,perform,fetch,send, andfetchAllPagesare nownonisolated. Previously the whole pipeline ran on the main actor despite the comments andPackage.swiftrationale claiming otherwise, hitching the main thread on large lists.
Upgrading
PagedResponse gains a pageSize static requirement with a default of 100. Existing conformers keep compiling, but a conformer whose real page size is smaller — or whose lists are shorter than 100 items — will fall back to the sequential walk. That is correct but slower. Declare your endpoint's actual page size to keep the parallel path.
Over-estimating pageSize is safe (the count comes out short and the remainder is walked); under-estimating is what the old code did and what #9 fixes.
Full changelog: 0.1.0...0.2.0