(sessionId: string, afterId: string | null = null, opts?: {
skipMetadata?: boolean;
})
| 631 | * per-call GET /v1/sessions/{id} when branch/status aren't needed. |
| 632 | */ |
| 633 | export async function pollRemoteSessionEvents(sessionId: string, afterId: string | null = null, opts?: { |
| 634 | skipMetadata?: boolean; |
| 635 | }): Promise<PollRemoteSessionResponse> { |
| 636 | const accessToken = getClaudeAIOAuthTokens()?.accessToken; |
| 637 | if (!accessToken) { |
| 638 | throw new Error('No access token for polling'); |
| 639 | } |
| 640 | const orgUUID = await getOrganizationUUID(); |
| 641 | if (!orgUUID) { |
| 642 | throw new Error('No org UUID for polling'); |
| 643 | } |
| 644 | const headers = { |
| 645 | ...getOAuthHeaders(accessToken), |
| 646 | 'anthropic-beta': 'ccr-byoc-2025-07-29', |
| 647 | 'x-organization-uuid': orgUUID |
| 648 | }; |
| 649 | const eventsUrl = `${getOauthConfig().BASE_API_URL}/v1/sessions/${sessionId}/events`; |
| 650 | type EventsResponse = { |
| 651 | data: unknown[]; |
| 652 | has_more: boolean; |
| 653 | first_id: string | null; |
| 654 | last_id: string | null; |
| 655 | }; |
| 656 | |
| 657 | // Cap is a safety valve against stuck cursors; steady-state is 0–1 pages. |
| 658 | const MAX_EVENT_PAGES = 50; |
| 659 | const sdkMessages: SDKMessage[] = []; |
| 660 | let cursor = afterId; |
| 661 | for (let page = 0; page < MAX_EVENT_PAGES; page++) { |
| 662 | const eventsResponse = await axios.get(eventsUrl, { |
| 663 | headers, |
| 664 | params: cursor ? { |
| 665 | after_id: cursor |
| 666 | } : undefined, |
| 667 | timeout: 30000 |
| 668 | }); |
| 669 | if (eventsResponse.status !== 200) { |
| 670 | throw new Error(`Failed to fetch session events: ${eventsResponse.statusText}`); |
| 671 | } |
| 672 | const eventsData: EventsResponse = eventsResponse.data; |
| 673 | if (!eventsData?.data || !Array.isArray(eventsData.data)) { |
| 674 | throw new Error('Invalid events response'); |
| 675 | } |
| 676 | for (const event of eventsData.data) { |
| 677 | if (event && typeof event === 'object' && 'type' in event) { |
| 678 | if (event.type === 'env_manager_log' || event.type === 'control_response') { |
| 679 | continue; |
| 680 | } |
| 681 | if ('session_id' in event) { |
| 682 | sdkMessages.push(event as SDKMessage); |
| 683 | } |
| 684 | } |
| 685 | } |
| 686 | if (!eventsData.last_id) break; |
| 687 | cursor = eventsData.last_id; |
| 688 | if (!eventsData.has_more) break; |
| 689 | } |
| 690 | if (opts?.skipMetadata) { |
no test coverage detected