Skip to content

Commit d9284eb

Browse files
Standardize pagination with next cursor (#27)
Co-authored-by: unknown <> Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
1 parent f136cb8 commit d9284eb

10 files changed

Lines changed: 60 additions & 31 deletions

File tree

docs/cli-reference.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -73,8 +73,8 @@ opensea search accounts <query> [--limit <n>]
7373
## Tokens
7474

7575
```bash
76-
opensea tokens trending [--chains <chains>] [--limit <n>] [--cursor <cursor>]
77-
opensea tokens top [--chains <chains>] [--limit <n>] [--cursor <cursor>]
76+
opensea tokens trending [--chains <chains>] [--limit <n>] [--next <cursor>]
77+
opensea tokens top [--chains <chains>] [--limit <n>] [--next <cursor>]
7878
opensea tokens get <chain> <address>
7979
```
8080

@@ -90,4 +90,4 @@ opensea swaps quote --from-chain <chain> --from-address <address> --to-chain <ch
9090
opensea accounts get <address>
9191
```
9292

93-
> All list commands support cursor-based pagination. See [pagination.md](pagination.md) for details.
93+
> REST list commands support cursor-based pagination. Search commands return a flat list with no cursor. See [pagination.md](pagination.md) for details.

docs/pagination.md

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ The OpenSea API uses cursor-based pagination. Paginated responses include a `nex
44

55
## CLI
66

7-
Most list commands support `--next <cursor>` (or `--cursor <cursor>` for tokens):
7+
All paginated commands use `--next <cursor>`:
88

99
```bash
1010
# First page
@@ -13,16 +13,17 @@ opensea collections list --limit 5
1313
# The response includes a "next" cursor — pass it to get the next page
1414
opensea collections list --limit 5 --next "LXBrPTEwMDA..."
1515

16-
# Tokens use --cursor instead of --next
16+
# Tokens also use --next
1717
opensea tokens trending --limit 5
18-
opensea tokens trending --limit 5 --cursor "abc123..."
18+
opensea tokens trending --limit 5 --next "abc123..."
1919
```
2020

2121
### Commands that support pagination
2222

2323
| Command | Cursor flag |
2424
|---|---|
2525
| `collections list` | `--next` |
26+
2627
| `nfts list-by-collection` | `--next` |
2728
| `nfts list-by-contract` | `--next` |
2829
| `nfts list-by-account` | `--next` |
@@ -35,8 +36,10 @@ opensea tokens trending --limit 5 --cursor "abc123..."
3536
| `events by-account` | `--next` |
3637
| `events by-collection` | `--next` |
3738
| `events by-nft` | `--next` |
38-
| `tokens trending` | `--cursor` |
39-
| `tokens top` | `--cursor` |
39+
| `tokens trending` | `--next` |
40+
| `tokens top` | `--next` |
41+
42+
> **Note:** Search commands (`search collections`, `search nfts`, `search tokens`, `search accounts`) do not support cursor-based pagination. The underlying GraphQL API returns a flat list with no `next` cursor.
4043
4144
## SDK
4245

docs/sdk.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ const account = await client.accounts.get("0x123...")
129129
const { tokens, next } = await client.tokens.trending({
130130
chains: ["base", "ethereum"],
131131
limit: 10,
132-
cursor: "cursor_string",
132+
next: "cursor_string",
133133
})
134134

135135
const { tokens, next } = await client.tokens.top({
@@ -142,7 +142,7 @@ const tokenDetails = await client.tokens.get("base", "0x123...")
142142

143143
## Search
144144

145-
Search methods use GraphQL and return different result shapes than the REST API.
145+
Search methods use GraphQL and return different result shapes than the REST API. Search endpoints do not currently expose a `next` cursor for pagination; use `limit` to control result count.
146146

147147
```typescript
148148
const collections = await client.search.collections("mfers", {

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@opensea/cli",
3-
"version": "0.2.1",
3+
"version": "0.3.0",
44
"type": "module",
55
"description": "OpenSea CLI - Query the OpenSea API from the command line or programmatically",
66
"main": "dist/index.js",

src/commands/tokens.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,16 +16,16 @@ export function tokensCommand(
1616
.description("Get trending tokens based on OpenSea's trending score")
1717
.option("--chains <chains>", "Comma-separated list of chains to filter by")
1818
.option("--limit <limit>", "Number of results (max 100)", "20")
19-
.option("--cursor <cursor>", "Pagination cursor")
19+
.option("--next <cursor>", "Pagination cursor")
2020
.action(
21-
async (options: { chains?: string; limit: string; cursor?: string }) => {
21+
async (options: { chains?: string; limit: string; next?: string }) => {
2222
const client = getClient()
2323
const result = await client.get<{ tokens: Token[]; next?: string }>(
2424
"/api/v2/tokens/trending",
2525
{
2626
chains: options.chains,
2727
limit: Number.parseInt(options.limit, 10),
28-
cursor: options.cursor,
28+
cursor: options.next,
2929
},
3030
)
3131
console.log(formatOutput(result, getFormat()))
@@ -37,16 +37,16 @@ export function tokensCommand(
3737
.description("Get top tokens ranked by 24-hour trading volume")
3838
.option("--chains <chains>", "Comma-separated list of chains to filter by")
3939
.option("--limit <limit>", "Number of results (max 100)", "20")
40-
.option("--cursor <cursor>", "Pagination cursor")
40+
.option("--next <cursor>", "Pagination cursor")
4141
.action(
42-
async (options: { chains?: string; limit: string; cursor?: string }) => {
42+
async (options: { chains?: string; limit: string; next?: string }) => {
4343
const client = getClient()
4444
const result = await client.get<{ tokens: Token[]; next?: string }>(
4545
"/api/v2/tokens/top",
4646
{
4747
chains: options.chains,
4848
limit: Number.parseInt(options.limit, 10),
49-
cursor: options.cursor,
49+
cursor: options.next,
5050
},
5151
)
5252
console.log(formatOutput(result, getFormat()))

src/sdk.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -317,24 +317,24 @@ class TokensAPI {
317317
async trending(options?: {
318318
limit?: number
319319
chains?: string[]
320-
cursor?: string
320+
next?: string
321321
}): Promise<{ tokens: Token[]; next?: string }> {
322322
return this.client.get("/api/v2/tokens/trending", {
323323
limit: options?.limit,
324324
chains: options?.chains?.join(","),
325-
cursor: options?.cursor,
325+
cursor: options?.next,
326326
})
327327
}
328328

329329
async top(options?: {
330330
limit?: number
331331
chains?: string[]
332-
cursor?: string
332+
next?: string
333333
}): Promise<{ tokens: Token[]; next?: string }> {
334334
return this.client.get("/api/v2/tokens/top", {
335335
limit: options?.limit,
336336
chains: options?.chains?.join(","),
337-
cursor: options?.cursor,
337+
cursor: options?.next,
338338
})
339339
}
340340

src/types/api.ts

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -250,11 +250,6 @@ export interface GetTraitsResponse {
250250
counts: { [traitType: string]: TraitCounts }
251251
}
252252

253-
export interface PaginatedResponse<T> {
254-
next?: string
255-
results: T[]
256-
}
257-
258253
export interface Token {
259254
address: string
260255
chain: string

test/commands/tokens.test.ts

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,15 @@ describe("tokensCommand", () => {
2727

2828
const cmd = tokensCommand(ctx.getClient, ctx.getFormat)
2929
await cmd.parseAsync(
30-
["trending", "--chains", "ethereum,base", "--limit", "10"],
30+
[
31+
"trending",
32+
"--chains",
33+
"ethereum,base",
34+
"--limit",
35+
"10",
36+
"--next",
37+
"abc123",
38+
],
3139
{ from: "user" },
3240
)
3341

@@ -36,6 +44,7 @@ describe("tokensCommand", () => {
3644
expect.objectContaining({
3745
chains: "ethereum,base",
3846
limit: 10,
47+
cursor: "abc123",
3948
}),
4049
)
4150
})
@@ -44,11 +53,13 @@ describe("tokensCommand", () => {
4453
ctx.mockClient.get.mockResolvedValue({ tokens: [] })
4554

4655
const cmd = tokensCommand(ctx.getClient, ctx.getFormat)
47-
await cmd.parseAsync(["top", "--limit", "5"], { from: "user" })
56+
await cmd.parseAsync(["top", "--limit", "5", "--next", "cursor1"], {
57+
from: "user",
58+
})
4859

4960
expect(ctx.mockClient.get).toHaveBeenCalledWith(
5061
"/api/v2/tokens/top",
51-
expect.objectContaining({ limit: 5 }),
62+
expect.objectContaining({ limit: 5, cursor: "cursor1" }),
5263
)
5364
})
5465

test/sdk.test.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -294,6 +294,16 @@ describe("OpenSeaCLI", () => {
294294
})
295295
})
296296

297+
it("trending maps next option to cursor param", async () => {
298+
mockGet.mockResolvedValue({ tokens: [] })
299+
await sdk.tokens.trending({ next: "cursor1" })
300+
expect(mockGet).toHaveBeenCalledWith("/api/v2/tokens/trending", {
301+
limit: undefined,
302+
chains: undefined,
303+
cursor: "cursor1",
304+
})
305+
})
306+
297307
it("trending with no options", async () => {
298308
mockGet.mockResolvedValue({ tokens: [] })
299309
await sdk.tokens.trending()
@@ -304,6 +314,16 @@ describe("OpenSeaCLI", () => {
304314
})
305315
})
306316

317+
it("top maps next option to cursor param", async () => {
318+
mockGet.mockResolvedValue({ tokens: [] })
319+
await sdk.tokens.top({ limit: 5, next: "cursor2" })
320+
expect(mockGet).toHaveBeenCalledWith("/api/v2/tokens/top", {
321+
limit: 5,
322+
chains: undefined,
323+
cursor: "cursor2",
324+
})
325+
})
326+
307327
it("top calls correct endpoint", async () => {
308328
mockGet.mockResolvedValue({ tokens: [] })
309329
await sdk.tokens.top({ limit: 5 })

0 commit comments

Comments
 (0)