/** * TikTok Business API pagination. * * TikTok uses cursor-based pagination with `cursor` + `has_more`: * - Request: `cursor` (integer, default 0 or current timestamp) * - Response: `{ data: [...], cursor: number, has_more: boolean }` * * This differs from Meta's `paging.cursors.after` / `paging.next` pattern. */ export interface TikTokPaginatedResponse { cursor: number; has_more: boolean; [key: string]: unknown; } export interface TikTokCursorOptions { /** Function that makes the API call with given cursor. */ fetcher: (cursor?: number) => Promise & Record>; /** Function to extract the data array from the response. */ extractData: (response: TikTokPaginatedResponse & Record) => T[]; } /** * Async-iterable cursor for TikTok paginated endpoints. * Works with any endpoint that returns `{ cursor, has_more, ...data }`. */ export class TikTokCursor implements AsyncIterable { private readonly fetcher: TikTokCursorOptions["fetcher"]; private readonly extractData: TikTokCursorOptions["extractData"]; private nextCursor: number | undefined; private hasMore = true; private started = false; constructor(opts: TikTokCursorOptions) { this.fetcher = opts.fetcher; this.extractData = opts.extractData; } /** Fetch the next page. */ async next(): Promise<{ data: T[]; hasNext: boolean }> { if (!this.hasMore && this.started) return { data: [], hasNext: false }; this.started = true; const response = await this.fetcher(this.nextCursor); const data = this.extractData(response); this.nextCursor = response.cursor; this.hasMore = response.has_more; return { data, hasNext: this.hasMore }; } async *[Symbol.asyncIterator](): AsyncIterator { while (true) { const page = await this.next(); yield* page.data; if (!page.hasNext) break; } } /** Collect all items across all pages. */ async toArray(): Promise { const result: T[] = []; for await (const item of this) result.push(item); return result; } /** Collect up to N items. */ async take(n: number): Promise { const result: T[] = []; for await (const item of this) { result.push(item); if (result.length >= n) break; } return result; } }