# @suaveplan/pagination - Universal pagination primitives: cursor, offset, keyset strategies with adapters, iterators, and type-safe request/response shapes. ## Summary Universal pagination primitives for cursor-based, offset-based, and keyset-based (seek) pagination strategies. The package covers the full pagination surface: request normalisation, response envelope construction, opaque cursor and page-token encoding, async iterators that drain pages automatically, a pluggable adapter interface for any data source, and optional OpenTelemetry instrumentation. All three strategies share the same error hierarchy and Zod schemas so they compose cleanly in multi-strategy APIs. ## Documentation tree - [adapters](./src/adapters/database-adapter.md) — _(no submodules)_ - [database-adapter](./src/adapters/database-adapter.md) — _(no submodules)_ - [cursor](./src/cursor/cursor.md) — _(no submodules)_ - [cursor-pagination](./src/cursor/cursor-pagination.md) — The `cursor-pagination` module provides base64url cursor encoding/decoding and adapter-backed forward/backward fetch op… - [cursor](./src/cursor/cursor.md) — _(no submodules)_ - [codes](./src/errors/codes.md) — Defines and registers all stable error codes for the `@suaveplan/pagination` package using `defineCodes` from `@suavepl… - [pagination-error](./src/errors/pagination-error.md) — `PaginationError` is the structured error base class for all failures originating within `@suaveplan/pagination`. It ex… - [helpers](./src/helpers/helpers.md) — _(no submodules)_ - [helpers](./src/helpers/helpers.md) — _(no submodules)_ - [keyset](./src/keyset/keyset-pagination.md) — _(no submodules)_ - [keyset-pagination](./src/keyset/keyset-pagination.md) — _(no submodules)_ - [offset](./src/offset/offset.md) — _(no submodules)_ - [offset](./src/offset/offset.md) — _(no submodules)_ - [otel](./src/otel/pagination-otel.md) — _(no submodules)_ - [pagination-otel](./src/otel/pagination-otel.md) — _(no submodules)_ - [tokens](./src/tokens/page-tokens.md) — _(no submodules)_ - [page-tokens](./src/tokens/page-tokens.md) — _(no submodules)_ - [database-adapter](./src/adapters/database-adapter.md) — _(no submodules)_- [cursor](./src/cursor/cursor.md) — _(no submodules)_- [cursor-pagination](./src/cursor/cursor-pagination.md) — The `cursor-pagination` module provides base64url cursor encoding/decoding and adapter-backed forward/backward fetch op… - [cursor](./src/cursor/cursor.md) — _(no submodules)_- [codes](./src/errors/codes.md) — Defines and registers all stable error codes for the `@suaveplan/pagination` package using `defineCodes` from `@suavepl… - [pagination-error](./src/errors/pagination-error.md) — `PaginationError` is the structured error base class for all failures originating within `@suaveplan/pagination`. It ex… - [helpers](./src/helpers/helpers.md) — _(no submodules)_- [helpers](./src/helpers/helpers.md) — _(no submodules)_- [keyset](./src/keyset/keyset-pagination.md) — _(no submodules)_- [keyset-pagination](./src/keyset/keyset-pagination.md) — _(no submodules)_- [offset](./src/offset/offset.md) — _(no submodules)_- [offset](./src/offset/offset.md) — _(no submodules)_- [otel](./src/otel/pagination-otel.md) — _(no submodules)_- [pagination-otel](./src/otel/pagination-otel.md) — _(no submodules)_- [tokens](./src/tokens/page-tokens.md) — _(no submodules)_- [page-tokens](./src/tokens/page-tokens.md) — _(no submodules)_- [database-adapter](./src/adapters/database-adapter.md) — _(no submodules)_- [cursor](./src/cursor/cursor.md) — _(no submodules)_- [cursor-pagination](./src/cursor/cursor-pagination.md) — The `cursor-pagination` module provides base64url cursor encoding/decoding and adapter-backed forward/backward fetch op… - [cursor](./src/cursor/cursor.md) — _(no submodules)_- [codes](./src/errors/codes.md) — Defines and registers all stable error codes for the `@suaveplan/pagination` package using `defineCodes` from `@suavepl… - [pagination-error](./src/errors/pagination-error.md) — `PaginationError` is the structured error base class for all failures originating within `@suaveplan/pagination`. It ex… - [helpers](./src/helpers/helpers.md) — _(no submodules)_- [helpers](./src/helpers/helpers.md) — _(no submodules)_- [keyset](./src/keyset/keyset-pagination.md) — _(no submodules)_- [keyset-pagination](./src/keyset/keyset-pagination.md) — _(no submodules)_- [offset](./src/offset/offset.md) — _(no submodules)_- [offset](./src/offset/offset.md) — _(no submodules)_- [otel](./src/otel/pagination-otel.md) — _(no submodules)_- [pagination-otel](./src/otel/pagination-otel.md) — _(no submodules)_- [tokens](./src/tokens/page-tokens.md) — _(no submodules)_- [page-tokens](./src/tokens/page-tokens.md) — _(no submodules)_- [database-adapter](./src/adapters/database-adapter.md) — _(no submodules)_- [cursor](./src/cursor/cursor.md) — _(no submodules)_- [cursor-pagination](./src/cursor/cursor-pagination.md) — The `cursor-pagination` module provides base64url cursor encoding/decoding and adapter-backed forward/backward fetch op… - [cursor](./src/cursor/cursor.md) — _(no submodules)_- [codes](./src/errors/codes.md) — Defines and registers all stable error codes for the `@suaveplan/pagination` package using `defineCodes` from `@suavepl… - [pagination-error](./src/errors/pagination-error.md) — `PaginationError` is the structured error base class for all failures originating within `@suaveplan/pagination`. It ex… - [helpers](./src/helpers/helpers.md) — _(no submodules)_- [helpers](./src/helpers/helpers.md) — _(no submodules)_- [keyset](./src/keyset/keyset-pagination.md) — _(no submodules)_- [keyset-pagination](./src/keyset/keyset-pagination.md) — _(no submodules)_- [offset](./src/offset/offset.md) — _(no submodules)_- [offset](./src/offset/offset.md) — _(no submodules)_- [otel](./src/otel/pagination-otel.md) — _(no submodules)_- [pagination-otel](./src/otel/pagination-otel.md) — _(no submodules)_- [tokens](./src/tokens/page-tokens.md) — _(no submodules)_- [page-tokens](./src/tokens/page-tokens.md) — _(no submodules)_- [database-adapter](./src/adapters/database-adapter.md) — _(no submodules)_- [cursor](./src/cursor/cursor.md) — _(no submodules)_ - [cursor-pagination](./src/cursor/cursor-pagination.md) — The `cursor-pagination` module provides base64url cursor encoding/decoding and adapter-backed forward/backward fetch op… - [cursor](./src/cursor/cursor.md) — _(no submodules)_- [codes](./src/errors/codes.md) — Defines and registers all stable error codes for the `@suaveplan/pagination` package using `defineCodes` from `@suavepl… - [pagination-error](./src/errors/pagination-error.md) — `PaginationError` is the structured error base class for all failures originating within `@suaveplan/pagination`. It ex… - [helpers](./src/helpers/helpers.md) — _(no submodules)_ - [helpers](./src/helpers/helpers.md) — _(no submodules)_- [keyset](./src/keyset/keyset-pagination.md) — _(no submodules)_ - [keyset-pagination](./src/keyset/keyset-pagination.md) — _(no submodules)_- [offset](./src/offset/offset.md) — _(no submodules)_ - [offset](./src/offset/offset.md) — _(no submodules)_- [otel](./src/otel/pagination-otel.md) — _(no submodules)_ - [pagination-otel](./src/otel/pagination-otel.md) — _(no submodules)_- [tokens](./src/tokens/page-tokens.md) — _(no submodules)_ - [page-tokens](./src/tokens/page-tokens.md) — _(no submodules)_ ## Install ```bash bun add @suaveplan/pagination ``` ## Quick start ```ts import { paginateArray } from "@suaveplan/pagination/offset"; import { cursorPaginateArray } from "@suaveplan/pagination/cursor"; import { createOffsetIterator, collectAll } from "@suaveplan/pagination/helpers"; // Offset: slice page 2, 10 items per page const items = Array.from({ length: 50 }, (_, i) => ({ id: i + 1 })); const page2 = paginateArray(items, 2, 10); // page2.data → items 11–20 // page2.meta.totalPages → 5, page2.meta.hasNext → true // Cursor: paginate an in-memory array by item.id const users = [{ id: "a" }, { id: "b" }, { id: "c" }, { id: "d" }]; const first = cursorPaginateArray(users, { limit: 2 }, (u) => u.id); // first.meta.endCursor → "b", first.meta.hasNextPage → true const second = cursorPaginateArray( users, { cursor: first.meta.endCursor ?? undefined, limit: 2 }, (u) => u.id ); // second.data → [{ id: "c" }, { id: "d" }] // Helpers: drain all pages into a flat array const iter = createOffsetIterator( (page, limit) => Promise.resolve(paginateArray(items, page, limit)), { limit: 10 } ); const all = await collectAll(iter); // → all 50 items ``` ## Modules | Module | Description | |--------|-------------| | [src/cursor/cursor.md](src/cursor/cursor.md) | In-memory cursor pagination building blocks: `cursorPaginateArray`, `createEdges`, `createConnection`, `calculateCursorMeta`, `normalizeCursorRequest` | | [src/cursor/cursor-pagination.md](src/cursor/cursor-pagination.md) | Adapter-backed cursor pagination: `encodeCursor`, `decodeCursor`, `validateCursor`, `fetchAfter`, `fetchBefore` | | [src/offset/offset.md](src/offset/offset.md) | Offset/page-number pagination: `paginateArray`, `normalizeOffsetRequest`, `calculateOffsetMeta`, `pageToOffset`, `offsetToPage`, `getPageRange`, `estimateTotalCount` | | [src/keyset/keyset-pagination.md](src/keyset/keyset-pagination.md) | Seek-based keyset pagination: `keysetPaginate`, `fetchKeysetPage`, `encodeKeysetCursor`, `decodeKeysetCursor`, `extractSortKeys` | | [src/helpers/helpers.md](src/helpers/helpers.md) | Higher-order iteration utilities: `createOffsetIterator`, `createCursorIterator`, `collectAll`, `collectUpTo`, `mapPaginated`, `mergeOffsetResponses` | | [src/adapters/database-adapter.md](src/adapters/database-adapter.md) | `PaginationAdapter` interface, `MemoryPaginationAdapter`, and `createMemoryAdapter` factory | | [src/tokens/page-tokens.md](src/tokens/page-tokens.md) | Opaque page tokens with sort and filter metadata: `createCursorToken`, `createOffsetToken`, `encodePageToken`, `decodePageToken`, `hashFilters`, `validateTokenFilter` | | [src/otel/pagination-otel.md](src/otel/pagination-otel.md) | OTel instrumentation: `getPaginationInstruments` with request counter, page-size histogram, and encode/decode histogram; graceful no-op fallback | | [src/errors/pagination-error.md](src/errors/pagination-error.md) | `PaginationError` — structured error class extending `SuaveplanError` with `PAGINATION.*` codes | | [src/errors/codes.md](src/errors/codes.md) | `PAGINATION_CODES` constant and `PaginationCode` union type |