* Performs a single ListObjectsV2 page request and returns the parsed result.
( ctx: S3Context, prefix: string, continuationToken: string | undefined, retryOptions?: Parameters<typeof secureFetchWithRetry>[2], maxKeys: number = LIST_MAX_KEYS )
| 459 | * Performs a single ListObjectsV2 page request and returns the parsed result. |
| 460 | */ |
| 461 | async function listObjectsPage( |
| 462 | ctx: S3Context, |
| 463 | prefix: string, |
| 464 | continuationToken: string | undefined, |
| 465 | retryOptions?: Parameters<typeof secureFetchWithRetry>[2], |
| 466 | maxKeys: number = LIST_MAX_KEYS |
| 467 | ): Promise<{ objects: S3ObjectEntry[]; isTruncated: boolean; nextContinuationToken?: string }> { |
| 468 | const queryParams: Record<string, string> = { |
| 469 | 'list-type': '2', |
| 470 | 'encoding-type': 'url', |
| 471 | 'max-keys': String(maxKeys), |
| 472 | } |
| 473 | if (prefix) queryParams.prefix = prefix |
| 474 | if (continuationToken) queryParams['continuation-token'] = continuationToken |
| 475 | |
| 476 | const canonicalQueryString = buildListQueryString(queryParams) |
| 477 | const bucketPath = buildBucketPath(ctx) |
| 478 | const headers = buildSignedHeaders(ctx, 'GET', bucketPath, canonicalQueryString) |
| 479 | |
| 480 | const url = buildUrl(ctx, bucketPath, canonicalQueryString) |
| 481 | |
| 482 | const response = await secureFetchWithRetry(url, { method: 'GET', headers }, retryOptions) |
| 483 | |
| 484 | if (!response.ok) { |
| 485 | const errorText = await response.text() |
| 486 | throw new Error(`S3 ListObjectsV2 failed: ${response.status} ${errorText}`) |
| 487 | } |
| 488 | |
| 489 | const xml = await response.text() |
| 490 | return parseListResponse(xml) |
| 491 | } |
| 492 | |
| 493 | export const s3Connector: ConnectorConfig = { |
| 494 | ...s3ConnectorMeta, |
no test coverage detected