90 lines
2.1 KiB
TypeScript
90 lines
2.1 KiB
TypeScript
|
|
// classes.listcursor.ts
|
||
|
|
|
||
|
|
import * as plugins from './plugins.js';
|
||
|
|
import type { Bucket } from './classes.bucket.js';
|
||
|
|
|
||
|
|
export interface IListCursorOptions {
|
||
|
|
pageSize?: number;
|
||
|
|
}
|
||
|
|
|
||
|
|
export interface IListCursorResult {
|
||
|
|
keys: string[];
|
||
|
|
done: boolean;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* ListCursor provides explicit pagination control for listing objects in a bucket.
|
||
|
|
* Useful for UI pagination, resumable operations, and manual batch processing.
|
||
|
|
*/
|
||
|
|
export class ListCursor {
|
||
|
|
private continuationToken?: string;
|
||
|
|
private exhausted = false;
|
||
|
|
private pageSize: number;
|
||
|
|
|
||
|
|
constructor(
|
||
|
|
private bucket: Bucket,
|
||
|
|
private prefix: string,
|
||
|
|
options: IListCursorOptions = {}
|
||
|
|
) {
|
||
|
|
this.pageSize = options.pageSize || 1000;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Fetch the next page of object keys
|
||
|
|
* @returns Object with keys array and done flag
|
||
|
|
*/
|
||
|
|
public async next(): Promise<IListCursorResult> {
|
||
|
|
if (this.exhausted) {
|
||
|
|
return { keys: [], done: true };
|
||
|
|
}
|
||
|
|
|
||
|
|
const command = new plugins.s3.ListObjectsV2Command({
|
||
|
|
Bucket: this.bucket.name,
|
||
|
|
Prefix: this.prefix,
|
||
|
|
MaxKeys: this.pageSize,
|
||
|
|
ContinuationToken: this.continuationToken,
|
||
|
|
});
|
||
|
|
|
||
|
|
const response = await this.bucket.smartbucketRef.s3Client.send(command);
|
||
|
|
|
||
|
|
const keys = (response.Contents || [])
|
||
|
|
.map((obj) => obj.Key)
|
||
|
|
.filter((key): key is string => !!key);
|
||
|
|
|
||
|
|
this.continuationToken = response.NextContinuationToken;
|
||
|
|
this.exhausted = !this.continuationToken;
|
||
|
|
|
||
|
|
return { keys, done: this.exhausted };
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Check if there are more pages to fetch
|
||
|
|
*/
|
||
|
|
public hasMore(): boolean {
|
||
|
|
return !this.exhausted;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Reset the cursor to start from the beginning
|
||
|
|
*/
|
||
|
|
public reset(): void {
|
||
|
|
this.continuationToken = undefined;
|
||
|
|
this.exhausted = false;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Get the current continuation token (for saving/restoring state)
|
||
|
|
*/
|
||
|
|
public getToken(): string | undefined {
|
||
|
|
return this.continuationToken;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Set the continuation token (for resuming from a saved state)
|
||
|
|
*/
|
||
|
|
public setToken(token: string | undefined): void {
|
||
|
|
this.continuationToken = token;
|
||
|
|
this.exhausted = !token;
|
||
|
|
}
|
||
|
|
}
|