---
summary: "Cursor paging on journal/funder works lists, faster failure on a request-timeout deadline"
breaking: false
security: false
---

# 0.3.2 — 2026-08-06

## Added

- **`works_cursor`** input and **`nextWorksCursor`** enrichment on `crossref_search_journals` and `crossref_search_funders` — pages the journal works / funded-works list past the 10,000-record `works_offset` ceiling with no ceiling of its own. Pass `works_cursor="*"` to start a walk at the newest work, then chain the token from each response.
- **`works_cursor_offset_conflict`** error reason on both tools — rejects `works_cursor` paired with a nonzero `works_offset` rather than silently preferring one.

## Changed

- `works_offset_too_large`'s recovery and the works-list ceiling `notice` on both tools now point at `works_cursor="*"` instead of redirecting to `crossref_search_works` with an `issn:`/`funder:` filter — that filter answers a narrower question on funders, since `/funders/{id}/works` also counts the funder's registry descendants.
- A blank `works_cursor` (`""`) is normalized to absent and falls back to offset paging, instead of selecting the cursor path with nothing to send upstream.
- `CrossrefService`'s `SubResourceWorksOptions` gains `cursor`; a shared `setSubResourcePage` helper writes cursor-or-offset onto the journal/funder works sub-resource requests, cursor taking precedence.

## Fixed

- A request that hits `CROSSREF_TIMEOUT_MS` no longer retries — `transportError` now throws `retryable: false` on a deadline expiry, so the call fails after one `CROSSREF_TIMEOUT_MS` window (~10s at the default) instead of the full four-attempt budget (~47s). `upstreamError` takes a `retryable` override for this. HTTP 408 and 504 are unaffected and keep the full retry budget — they arrive at upstream speed, not this server's own clock.

`tests/services/crossref/crossref-service.test.ts` is rebuilt against `createFetchMock` in place of module-wide `vi.mock` stubs of `withRetry` and `httpErrorFromResponse`, which had put the real retry loop and status-mapping table out of reach of every case in the file. 218 → 240 tests; `bun run devcheck` clean.
