feat(types)!: query param encoding + optional search totals (5.0.0) - #116
Conversation
new URLSearchParams() coerces object values to "[object Object]", so list and
search calls that pass a date range object ({ gte, lt }) sent
date=[object Object] and every date-filtered request failed with a 400.
Flatten params into [key, value] pairs before encoding: plain objects expand to
bracket keys (date[gte]=...), arrays to repeated empty-bracket keys
(status[]=a&status[]=b), matching the v2 API contract and the curl examples in
the docs. null/undefined values and empty collections are skipped; Date values
are sent as ISO 8601 strings.
Bump to 4.22.0 and add regression tests.
SearchResult now mirrors what the v2 API returns: page/total_pages/ total_results are optional (later cursor pages omit totals) and new optional totals_are_capped, next_cursor, and previous_cursor support cursor pagination and capped totals.
The new SearchResult pagination fields are an additive feature (minor), so they belong under Added; the nested query serialization fix stays under Fixed.
…iter - Restrict nested bracket expansion to plain records (Object.prototype or null prototype); Date keeps ISO conversion; other object values (URL, RegExp, custom instances) keep their previous String(value) encoding instead of being silently dropped or recursed. - buildQueryString returns an empty string when every value is omitted, and the request builder only appends '?' when there is something to serialize, so all-omitted params produce the bare URL. - Regression tests for both cases.
…s additive Making SearchResult.page/total_pages/total_results optional would be a source-breaking change for strict TypeScript consumers under a minor release. Restore the required signatures (previous contract unchanged) and keep the cursor/capped metadata as new optional fields; document that the API only reports totals on page-mode responses and the first request of a cursor search, so cursor consumers should rely on next_cursor.
|
Semver resuelto de forma aditiva (commit del tipo): SearchResult.page/total_pages/total_results conservan sus firmas requeridas (contrato previo intacto → minor 4.22.0 válido); los campos de cursor/capping se mantienen opcionales y nuevos. Se documenta que la API solo reporta totales en page mode y en la primera request de cursor. Tests/build/tsd verdes. Solicitando nueva revisión. |
The API reports totals only in page mode and on the first request of a cursor search; later cursor pages omit page/total_pages/total_results. Model that truthfully as optional fields (source-breaking for strict consumers that dereferenced them) and release as a major, with the new optional totals_are_capped/next_cursor/previous_cursor under Added.
…major) Instead of making SearchResult.page/total_pages/total_results optional (source breaking), add CursorSearchResult<T>/CursorSearchParams and cursor-aware list() overloads: page mode keeps the existing signatures, and cursor searches get truthful optional totals plus next/previous cursors. Release stays 4.22.0 (minor, additive).
|
Rediseño aditivo (d89dc37): en lugar de opcionalizar page/total_pages/total_results (rompía strict consumers), se agregan CursorSearchResult/CursorSearchParams + overloads de list(); page mode conserva su contrato y los cursores quedan tipados con totales opcionales. Release 4.22.0 (minor). |
|
Resuelto con el rediseño (d89dc37): page mode conserva SearchResult con firmas requeridas (correcto para ese modo) y los cursores usan el tipo nuevo CursorSearchResult (totales opcionales + next/previous_cursor requeridos) vía overloads de list(), así que ya no hay contradicción entre tipos y comportamiento documentado. |
Symmetric param types for list(): PageSearchParams (page mode, the default) and CursorSearchParams (cursor mode), each an object with known fields intersected with Record<string, any>. A page-mode overload returns SearchResult<T> (unchanged) and cursor params keep returning CursorSearchResult<T>. Purely additive: existing call sites, including loose Record<string, any> params, keep compiling. Type tests cover both modes, the loose-params fallback, and that page totals stay required.
|
One more commit: arrays now serialize as repeated keys ( |
What
Query params are serialized with the encoding the API documents, and the search envelope now reflects what the API actually returns.
Query serialization
date[gte]=2026-01-01&date[lt]=2026-02-01(the Fetch migration replaced the previous axios serializer, which sentdate=[object Object]).status=valid&status=canceled, matching the OpenAPI default (formwithexplode) and the other official SDKs.null,undefined, and empty collections are skipped; an explicit empty string still sendsvalue=.Types — breaking,
5.0.0SearchResult<T>types the whole envelope:page,total_pages, andtotal_resultsare optional, because cursor pages only report the totals on the first request of the sequence and a search with no matches reportspage: 0.CursorSearchResult<T>was removed: cursor responses areSearchResult<T>with optionalprevious_cursor/next_cursor, and thelist()overloads that selected the result type were removed with it.CursorSearchParamsandPageSearchParamsstay for typing search params.Tests
pnpm test— build, 31 node tests, 10 web tests, and thetsdtype assertions all pass.