diff --git a/sentry-api-client/Public/Get-SentryReplayRecordingSegments.ps1 b/sentry-api-client/Public/Get-SentryReplayRecordingSegments.ps1 new file mode 100644 index 0000000..4033557 --- /dev/null +++ b/sentry-api-client/Public/Get-SentryReplayRecordingSegments.ps1 @@ -0,0 +1,42 @@ +function Get-SentryReplayRecordingSegments { + <# + .SYNOPSIS + Retrieves the recording segments of a session replay from Sentry. + + .DESCRIPTION + Fetches the rrweb recording data of a Sentry session replay by its ID. + The response is a JSON array with one entry per segment; each entry is the + segment's list of rrweb events (video metadata, breadcrumbs, etc.). + Automatically removes hyphens from GUID-formatted replay IDs. + + .PARAMETER ReplayId + The unique identifier of the replay. Can be provided with or without hyphens. + + .EXAMPLE + Get-SentryReplayRecordingSegments -ReplayId "7acc9c0d4a2e0a85187fe9b75e6b05ac" + # Retrieves the rrweb events of all recording segments of the given replay + #> + [CmdletBinding()] + param( + [Parameter(Mandatory = $true)] + [string]$ReplayId + ) + + # Remove hyphens from GUID-formatted replay IDs + $ReplayId = $ReplayId -replace '-', '' + + $Uri = Get-SentryProjectUrl -Resource "replays/$ReplayId/recording-segments/" -QueryString "download=true" + + # The endpoint returns an array with one entry per segment. Wrapping the + # call in `@(...)` collects an empty response into an empty array rather + # than `$null`. Pipeline enumeration collapses a single-segment response + # into its inner rrweb event list on the way here, so detect that case + # (elements are event dictionaries rather than segment lists) and re-wrap + # it. The comma operator prevents the same unwrapping on return. + $Segments = @(Invoke-SentryApiRequest -Uri $Uri -Method 'GET') + if ($Segments.Count -gt 0 -and $Segments[0] -is [System.Collections.IDictionary]) { + $Segments = , $Segments + } + + return , $Segments +} diff --git a/sentry-api-client/SentryApiClient.psd1 b/sentry-api-client/SentryApiClient.psd1 index a3aa9a7..d4f0261 100644 --- a/sentry-api-client/SentryApiClient.psd1 +++ b/sentry-api-client/SentryApiClient.psd1 @@ -41,6 +41,7 @@ 'Get-SentryMetrics', 'Get-SentryMetricsByAttribute', 'Get-SentryReplay', + 'Get-SentryReplayRecordingSegments', 'Get-SentrySpans', 'Invoke-SentryCLI' ) diff --git a/utils/Integration.TestUtils.psm1 b/utils/Integration.TestUtils.psm1 index 588b790..c4fa5f1 100644 --- a/utils/Integration.TestUtils.psm1 +++ b/utils/Integration.TestUtils.psm1 @@ -563,5 +563,56 @@ function Get-SentryTestReplay { throw "Replay $ReplayId not found in Sentry within $TimeoutSeconds seconds: $lastError" } +function Get-SentryTestReplayRecordingSegments { + [CmdletBinding()] + param( + [Parameter(Mandatory = $true)] + [string]$ReplayId, + + [Parameter()] + [int]$TimeoutSeconds = 300 + ) + + Write-Host "Fetching Sentry replay recording segments for replay: $ReplayId" -ForegroundColor Yellow + $progressActivity = "Waiting for Sentry replay recording segments of $ReplayId" + + $startTime = Get-Date + $endTime = $startTime.AddSeconds($TimeoutSeconds) + $lastError = $null + $elapsedSeconds = 0 + + try { + do { + $segments = $null + $elapsedSeconds = [int]((Get-Date) - $startTime).TotalSeconds + $percentComplete = [math]::Min(100, ($elapsedSeconds / $TimeoutSeconds) * 100) + + Write-Progress -Activity $progressActivity -Status "Elapsed: $elapsedSeconds/$TimeoutSeconds seconds" -PercentComplete $percentComplete + + try { + $segments = Get-SentryReplayRecordingSegments -ReplayId $ReplayId + } catch { + $lastError = $_.Exception.Message + Write-Debug "Recording segments for replay $ReplayId not found yet: $lastError" + } + + if ($segments -and @($segments).Count -gt 0) { + Write-Host "Recording segments for replay $ReplayId fetched from Sentry" -ForegroundColor Green + # Pass as -InputObject so a single-segment array is not enumerated away + ConvertTo-Json -InputObject $segments -Depth 10 | Out-File -FilePath (Get-OutputFilePath "replay-recording-$ReplayId.json") + # Use comma operator to ensure array is preserved (prevents PowerShell unwrapping single item) + return , @($segments) + } + + Start-Sleep -Milliseconds 500 + $currentTime = Get-Date + } while ($currentTime -lt $endTime) + } finally { + Write-Progress -Activity $progressActivity -Completed + } + + throw "Recording segments for replay $ReplayId not found in Sentry within $TimeoutSeconds seconds: $lastError" +} + # Export module functions -Export-ModuleMember -Function Invoke-CMakeConfigure, Invoke-CMakeBuild, Set-OutputDir, Get-OutputFilePath, Get-EventIds, Get-SentryTestEvent, Get-SentryTestEventAttachments, Get-SentryTestLog, Get-SentryTestMetric, Get-SentryTestTransaction, Get-SentryTestReplay, Get-PackageAumid +Export-ModuleMember -Function Invoke-CMakeConfigure, Invoke-CMakeBuild, Set-OutputDir, Get-OutputFilePath, Get-EventIds, Get-SentryTestEvent, Get-SentryTestEventAttachments, Get-SentryTestLog, Get-SentryTestMetric, Get-SentryTestTransaction, Get-SentryTestReplay, Get-SentryTestReplayRecordingSegments, Get-PackageAumid