Modules/businessdev.ALbuild.Containers/Private/Invoke-BcCaptureEngine.ps1
|
function Invoke-BcCaptureEngine { <# .SYNOPSIS Runs capture.js over a job and returns its events, with the password kept out of the command line. .DESCRIPTION The transport between PowerShell and the browser: * the job goes out as a FILE (its path is the only argument), * the password goes out as an ENVIRONMENT VARIABLE, because a command line is readable by every process on the host, * the results come back as NDJSON on stdout - one complete JSON object per line, so a long run can be streamed rather than buffered, * the PNGs never travel through here at all; the engine writes them and reports paths. PLAYWRIGHT_BROWSERS_PATH is set for the child and restored afterwards, so a long-lived session (the MCP server) is not left with a global pointing at one version's browser store. .PARAMETER Job The job as a hashtable; it is serialised to a temporary file. .PARAMETER Credential The container credentials. The password is read out of them here and handed to the child through the environment - it is never logged and never placed in an argument. .PARAMETER Browser The Get-BcCaptureBrowser result identifying node, the install and the browser store. .PARAMETER OnEvent Optional scriptblock invoked with each parsed event as it is read - the streaming hook for a caller that wants progress rather than a verdict. .OUTPUTS PSCustomObject with Events, Done, Errors, Captures and ExitCode. #> [CmdletBinding()] [OutputType([PSCustomObject])] param( [Parameter(Mandatory)] [hashtable] $Job, [Parameter(Mandatory)] [PSCredential] $Credential, [Parameter(Mandatory)] [PSCustomObject] $Browser, [scriptblock] $OnEvent ) $resource = Get-BcCaptureResource $engine = Join-Path -Path $resource.Folder -ChildPath 'capture.js' if (-not (Test-Path -LiteralPath $engine)) { throw "The capture engine is missing from the module ('$engine'). Reinstall businessdev.ALbuild." } $jobFile = Join-Path -Path ([System.IO.Path]::GetTempPath()) -ChildPath ("albuild-capture-$([guid]::NewGuid().ToString('N')).json") $Job | ConvertTo-Json -Depth 12 | Set-Content -LiteralPath $jobFile -Encoding UTF8 $previousPassword = $env:ALBUILD_CAPTURE_PASSWORD $previousBrowsers = $env:PLAYWRIGHT_BROWSERS_PATH try { $env:ALBUILD_CAPTURE_PASSWORD = $Credential.GetNetworkCredential().Password $env:PLAYWRIGHT_BROWSERS_PATH = $Browser.BrowsersPath # Exit 1 means "some target failed", which is a result to read, not a launch failure - so it # is a success exit code here and the events decide. $result = Invoke-ALbuildProcess -FilePath $Browser.NodePath -Arguments @($engine, $jobFile) ` -PassThru -SuccessExitCodes @(0, 1) } finally { $env:ALBUILD_CAPTURE_PASSWORD = $previousPassword $env:PLAYWRIGHT_BROWSERS_PATH = $previousBrowsers Remove-Item -LiteralPath $jobFile -Force -ErrorAction SilentlyContinue } $events = [System.Collections.Generic.List[object]]::new() foreach ($line in ("$($result.StdOut)" -split "`r?`n")) { if (-not $line.Trim()) { continue } try { $parsed = $line | ConvertFrom-Json } catch { continue } $events.Add($parsed) if ($OnEvent) { & $OnEvent $parsed } } # Nothing on stdout at all means node never got as far as the engine. Say that, with whatever it # wrote to stderr, instead of reporting "no captures" about a run that never started. if ($events.Count -eq 0) { $stderr = Format-BcRedactedText -Text "$($result.StdErr)" throw "CAPTURE_FAILED: the capture engine produced no output [exit $($result.ExitCode)]. $stderr" } [PSCustomObject]@{ ExitCode = $result.ExitCode Events = @($events) Done = @($events | Where-Object { $_.type -eq 'done' })[0] Errors = @($events | Where-Object { $_.type -eq 'error' }) Captures = @($events | Where-Object { $_.type -eq 'capture' }) } } |