forked from Lilly-Protocol/lily-sdk
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathpagination.ts
More file actions
73 lines (68 loc) · 2.06 KB
/
Copy pathpagination.ts
File metadata and controls
73 lines (68 loc) · 2.06 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
import type { PaginationQuery } from './models/common';
export interface CursorPage<T> {
readonly items: readonly T[];
readonly nextCursor: string | null;
readonly hasMore: boolean;
}
/**
* Extracts pagination metadata from an HTTP response.
* Works with cursor-based list endpoints that return items at the top level
* and a cursor in the response headers or body.
*/
export function parseCursorPage<T>(
items: readonly T[],
cursor: string | null | undefined,
): CursorPage<T> {
return {
items,
nextCursor: cursor ?? null,
hasMore: cursor != null && cursor !== '',
};
}
/**
* Builds a PaginationQuery from a cursor string.
* Returns an empty object when the cursor is null/empty.
*/
export function buildPaginationQuery(cursor: string | null | undefined): PaginationQuery {
if (!cursor) {
return {};
}
return { cursor };
}
/**
* Async iterator helper that auto-paginates through a cursor-based list endpoint.
*
* @example
* for await (const agent of paginate(client.agents.list.bind(client.agents))) {
* console.log(agent.id);
* }
*/
export async function* paginate<T>(
fetchPage: (query?: PaginationQuery) => Promise<readonly T[]>,
options?: { limit?: number; maxPages?: number },
): AsyncGenerator<T, void, unknown> {
const maxPages = options?.maxPages ?? 100;
let pageCount = 0;
while (pageCount < maxPages) {
const query: PaginationQuery = options?.limit ? { limit: options.limit } : {};
const items = await fetchPage(query);
for (const item of items) {
yield item;
}
// Without a cursor mechanism from the response, we stop after one page
// since we can't know if there are more items.
pageCount += 1;
// If we got fewer items than the limit, we're done
if (options?.limit && items.length < options.limit) {
break;
}
// Without response headers exposing next cursor, we stop to avoid infinite loop
if (items.length === 0) {
break;
}
// If no limit specified, we do one page (can't know if there are more)
if (!options?.limit) {
break;
}
}
}