Release v2.2.6 - #27
Merged
Merged
Conversation
Cursor-mode getMany rejected requests with no ?sort= even when the route declared a single-field @crud({ query: { sort } }) default, because the guard validated only client-parsed sort before the offset composer's client-then-default fallback ever ran. Add a shared resolveCursorSort helper in @nestjs-crud/core/cursor that mirrors the offset resolution order (client sort, then route default, then neither) and wire it into TypeOrmCrudService.doGetManyCursor ahead of every other cursor guard. Multi-field defaults and no-sort-anywhere still 400, with messages naming the responsible origin instead of a bare field count. Adds a fixture route and an integration cell proving a defaulted sort reaches a live 200 with a cursor that decodes to the declared field.
Unit specs for the cursor default-sort fallback helper — client sort, route-default fallback (single and multi-field), no-sort-anywhere, empty-array-as-absent on both sides, and the locked error-message prefix with no legacy count-suffix wording. No database dependency; 100% branch coverage on the helper.
Adds the remaining cursor 400-path integration cells: a multi-field route default with no ?sort= still 400s naming the route default as the origin; no sort anywhere (neither client nor route) 400s naming both remedies with no legacy count-suffix wording; and a mismatch-guard regression replaying a defaulted-sort cursor against an explicit differing ?sort=. The two pre-existing 400 cells (multi-field client sort, missing limit) are untouched.
doGetManyCursor now calls the shared resolveCursorSort helper (client ?sort= first, else the route's @crud({ query: { sort } }) default) instead of validating only the client-parsed sort before the single-sort-field guard. A route declaring a single-field default now returns a live keyset page with no ?sort= on the request; a multi-field default and the no-sort-anywhere case still 400 with origin-naming messages instead of the old misleading "got: 0" count. Adds two fixture routes (users-cursor-default-sort, users-cursor-multi-sort) and three integration cells to packages/drizzle/test/cursor.spec.ts; all 15 pre-existing cells pass unchanged.
doGetManyCursor now calls the shared resolveCursorSort helper (client ?sort= first, else the route's @crud({ query: { sort } }) default) instead of validating only the client-parsed sort before the single-sort-field guard. A route declaring a single-field default now returns a live keyset page with no ?sort= on the request; a multi-field default and the no-sort-anywhere case still 400 with origin-naming messages instead of the old misleading "got: 0" count. The fresh per-call EntityManager access pattern is untouched. Adds two fixture routes (users-cursor-default-sort, users-cursor-multi-sort) and three integration cells to packages/mikro-orm/test/cursor.spec.ts; all 15 pre-existing cells pass unchanged under the ESM test runner.
PrismaQueryComposer.applyCursor returned early when no cursor was decoded, so a route-declared default sort on cursor mode's first page never reached ORDER BY and rows came back in arbitrary database order. The sort-field allowlist check also only ran on non-first pages. Restructure applyCursor so the allowlist check and the ORDER BY assignment (with primary-key tie-breaker) run on every cursor request, including the first page. Only the keyset WHERE composition stays gated on a decoded cursor, since there is no prior page position to resume from on a first page.
PrismaCrudService.doGetManyCursor validated only the client-parsed sort array, so cursor-mode requests with no ?sort= against a route declaring a @crud({ query: { sort } }) default always 400'd — even when a single-field default existed to fall back to. Offset mode already resolves this fallback; cursor mode did not. Wire the shared resolveCursorSort helper (introduced for TypeORM in a prior commit) into doGetManyCursor before every other cursor guard, replacing the inline client-only check. A route-declared single-field default is now honored the same way a client-supplied sort is; a multi-field default or no sort anywhere still 400s with a message naming the origin instead of the previous misleading count. Add two fixture routes (/users-cursor-default-sort, /users-cursor-multi-sort) and four integration cells covering the 200 default-sort path, first-page ordering, the multi-field-default 400, and the no-sort-anywhere 400.
Add a Sort resolution section to the cursor pagination wiki page, placed right after Setup. Covers the client-then-route-default resolution order, the two multi-field 400 cases, the no-sort 400 case, and a table mapping each condition to its exact message text.
… and CLAUDE.md Add an Unreleased/Fixed entry to the root CHANGELOG and every adapter package CHANGELOG (core, typeorm, drizzle, mikro-orm, prisma) describing the cursor sort-resolution fix, plus a second Prisma-specific entry for the first-cursor-page ORDER BY fix. Rewrite the cursor bullet in CLAUDE.md's Key patterns list to state the resolution order instead of stale 400-condition wording.
…8, typeorm 0.3.31, Prisma 7.9.1, tooling)
…zzle and MikroORM DrizzleQueryComposer.applyCursor and MikroOrmQueryComposer.applyCursor skipped the sort-field allowlist check and the ORDER BY assignment (sort field + primary-key tie-breaker) whenever no cursor was decoded, i.e. on every cursor-mode first page. A tie-prone sort field could then return rows in unspecified order on that first page, letting later keyset pages silently skip or duplicate rows. Ports the same restructuring already applied to PrismaQueryComposer.applyCursor this phase: the allowlist check and ORDER BY now run unconditionally, and only the keyset WHERE stays gated on a decoded cursor. Adds a first-page ordering regression cell to each adapter's cursor spec that asserts the ORDER BY SQL fragment received by the driver connection, not just response row order — the latter false-passes because small LIMIT-bounded unordered scans often incidentally return primary-key order anyway.
Closes 39 open advisories against the root yarn.lock via a dedupe-first fix ladder: yarn dedupe + yarn up -R for every package whose parent range already admits the patched version, and a resolutions entry only where a parent hard-pins an exact version outside every declared range (lerna's js-yaml). Ten packages moved purely via re-resolution; nine hono/ @hono/node-server alerts closed because the package left the tree entirely (a stale @prisma/dev-era transitive), which also let two dead resolutions entries get deleted. The existing resolutions block was audited in place: three stale floors bumped (tar, plus two lerna-scoped tar entries), one dead global tar entry removed, one dead hono entry and one dead @hono/node-server entry removed, and the fast-uri floor raised to the current patched version. No new resolutions forced a version outside its declaring parent's own range, and no direct dependency range or peerDependencies changed.
Bump every demo dependency to a current caret range (no exact pins), staying inside each package's declared peer cap, and regenerate the lockfile. Closes all 17 demo-lockfile dependabot advisories, including the critical node-tar decompression chain and the long-standing uuid advisory (now satisfied by typeorm's refreshed uuid dependency). typescript stays on the 5.x line after 6.x/7.x both failed to compile/install cleanly; @types/node capped at the 24.x line to match CI's Node version, with the README's Prerequisites floor raised to match.
Closes 56 open dependabot alerts accumulated since 2.2.5, all via dependency and lockfile updates with zero dismissals. No advisory reached the installed dependency closure of a published package; the one residual concern (typeorm's wide peer range) carries forward as existing peer-floor work already planned for the next minor.
|
Packages with version v2.2.6 have been released |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
A patch release. It fixes cursor-mode pagination's handling of a route's default sort and closes every security advisory reported since 2.2.5.
Fixed
getManynow falls back to a route's@Crud({ query: { sort } })default when a request omits?sort=, matching how offset mode has always resolved sort. Applies to@nestjs-crud/typeorm,@nestjs-crud/drizzle,@nestjs-crud/mikro-orm, and@nestjs-crud/prisma. A route default that declares two or more sort fields still returns400, now with a message naming the field count and noting it came from the route configuration. A request with no sort anywhere still returns400, with a message describing both failure cases instead of reporting a bare field count of zero.@nestjs-crud/drizzle,@nestjs-crud/mikro-orm, and@nestjs-crud/prisma, the first cursor page now always orders by the sort field plus a primary-key tie-breaker. Before this fix, the first page could return ties in unspecified order, risking skipped or duplicated rows once pagination continued.Security
This release closes every dependabot advisory reported since 2.2.5: 56 advisories, all closed through dependency and lockfile updates, none through dismissal.
@nestjs-crud/typeormpeer range ontypeormstill admits older releases for consumers who pin low. Tightening that range is planned peer-floor work for the next minor.