StateModel/Support/Eigenverft.Manifested.Sandbox.Shared.Npm.ps1
|
<#
Eigenverft.Manifested.Sandbox.Shared.Npm #> function Get-ManagedNodeNpmGlobalConfigPath { <# .SYNOPSIS Builds the managed npm global config path for a Node runtime home. .DESCRIPTION Returns the npm global config path used by sandbox-managed Node runtimes. .PARAMETER NodeHome The managed Node runtime home directory. #> [CmdletBinding()] param( [Parameter(Mandatory = $true)] [string]$NodeHome ) return (Join-Path $NodeHome 'etc\npmrc') } function Test-ManifestedManagedNpmCommand { <# .SYNOPSIS Checks whether an npm command belongs to the managed sandbox runtime. .DESCRIPTION Verifies that the supplied npm command path lives under the sandbox-managed Node tools root for the current local layout. .PARAMETER NpmCmd The npm command path to test. .PARAMETER LocalRoot The sandbox local root used to resolve the managed Node tools root. #> [CmdletBinding()] param( [Parameter(Mandatory = $true)] [string]$NpmCmd, [string]$LocalRoot = (Get-ManifestedLocalRoot) ) $layout = Get-ManifestedLayout -LocalRoot $LocalRoot return (Test-ManifestedPathIsUnderRoot -Path $NpmCmd -RootPath $layout.NodeToolsRoot) } function Get-ManifestedNpmGlobalConfigPath { <# .SYNOPSIS Returns the managed npm global config path for an npm command. .DESCRIPTION Resolves the managed npm global config path when the npm command belongs to the sandbox-managed runtime, otherwise returns `$null`. .PARAMETER NpmCmd The npm command path to inspect. .PARAMETER LocalRoot The sandbox local root used to resolve the managed runtime layout. #> [CmdletBinding()] param( [Parameter(Mandatory = $true)] [string]$NpmCmd, [string]$LocalRoot = (Get-ManifestedLocalRoot) ) if (-not (Test-ManifestedManagedNpmCommand -NpmCmd $NpmCmd -LocalRoot $LocalRoot)) { return $null } $nodeHome = Split-Path -Parent $NpmCmd return (Get-ManagedNodeNpmGlobalConfigPath -NodeHome $nodeHome) } function Get-ManifestedManagedNpmCommandArguments { <# .SYNOPSIS Builds extra npm arguments for managed runtimes. .DESCRIPTION Returns the managed global config path and the command-line arguments needed to force npm to use that config file when the runtime is sandbox-managed. .PARAMETER NpmCmd The npm command path to inspect. .PARAMETER LocalRoot The sandbox local root used to resolve the managed runtime layout. #> [CmdletBinding()] param( [Parameter(Mandatory = $true)] [string]$NpmCmd, [string]$LocalRoot = (Get-ManifestedLocalRoot) ) $globalConfigPath = Get-ManifestedNpmGlobalConfigPath -NpmCmd $NpmCmd -LocalRoot $LocalRoot $commandArguments = @() if (-not [string]::IsNullOrWhiteSpace($globalConfigPath)) { $commandArguments += @('--globalconfig', $globalConfigPath) } [pscustomobject]@{ IsManagedNpm = (-not [string]::IsNullOrWhiteSpace($globalConfigPath)) GlobalConfigPath = $globalConfigPath CommandArguments = @($commandArguments) } } function Get-ManifestedNpmRegistryUri { <# .SYNOPSIS Resolves the active npm registry URI. .DESCRIPTION Reads the npm registry configuration and returns a normalized URI, falling back to the public npm registry when the configured value is missing or invalid. .PARAMETER NpmCmd The npm command used to query the registry configuration. #> [CmdletBinding()] param( [Parameter(Mandatory = $true)] [string]$NpmCmd ) $defaultRegistryUri = [uri]'https://registry.npmjs.org/' $registryValue = $null try { $registryOutput = & $NpmCmd config get registry 2>$null if ($LASTEXITCODE -eq 0 -and $null -ne $registryOutput) { $registryValue = ($registryOutput | Select-Object -First 1).ToString().Trim() } } catch { $registryValue = $null } if ([string]::IsNullOrWhiteSpace($registryValue) -or $registryValue -in @('undefined', 'null')) { return $defaultRegistryUri } try { return [uri]$registryValue } catch { return $defaultRegistryUri } } function Resolve-ManifestedNpmProxyRoute { <# .SYNOPSIS Detects whether npm registry access uses a system proxy. .DESCRIPTION Queries the system web proxy for the target npm registry URI and reports whether access is direct or proxied, including the resolved proxy URI when one is required. .PARAMETER RegistryUri The npm registry URI to evaluate. #> [CmdletBinding()] param( [Parameter(Mandatory = $true)] [uri]$RegistryUri ) $proxyUri = $null try { $systemProxy = [System.Net.WebRequest]::GetSystemWebProxy() if ($null -ne $systemProxy) { $systemProxy.Credentials = [System.Net.CredentialCache]::DefaultCredentials if (-not $systemProxy.IsBypassed($RegistryUri)) { $candidateProxyUri = $systemProxy.GetProxy($RegistryUri) if ($null -ne $candidateProxyUri -and $candidateProxyUri.AbsoluteUri -ne $RegistryUri.AbsoluteUri) { $proxyUri = $candidateProxyUri } } } } catch { $proxyUri = $null } [pscustomobject]@{ RegistryUri = $RegistryUri.AbsoluteUri RegistryHost = $RegistryUri.Host ProxyUri = if ($proxyUri) { $proxyUri.AbsoluteUri } else { $null } ProxyRequired = ($null -ne $proxyUri) Route = if ($proxyUri) { 'Proxy' } else { 'Direct' } } } function Get-ManifestedNpmConfigValue { <# .SYNOPSIS Reads a single npm config value. .DESCRIPTION Runs `npm config get` for the requested key and returns the normalized value, or `$null` when the setting is absent, false-like, or could not be read. .PARAMETER NpmCmd The npm command used to query configuration. .PARAMETER Key The npm configuration key to read. .PARAMETER GlobalConfigPath An optional managed global config path to query explicitly. #> [CmdletBinding()] param( [Parameter(Mandatory = $true)] [string]$NpmCmd, [Parameter(Mandatory = $true)] [string]$Key, [string]$GlobalConfigPath ) $arguments = @('config', 'get', $Key) if (-not [string]::IsNullOrWhiteSpace($GlobalConfigPath)) { $arguments += @('--location=global', '--globalconfig', $GlobalConfigPath) } try { $valueOutput = & $NpmCmd @arguments 2>$null if ($LASTEXITCODE -ne 0 -or $null -eq $valueOutput) { return $null } $valueText = ($valueOutput | Select-Object -First 1).ToString().Trim() if ([string]::IsNullOrWhiteSpace($valueText) -or $valueText -in @('undefined', 'null', 'false')) { return $null } return $valueText } catch { return $null } } function Get-ManifestedNpmProxyConfigurationStatus { <# .SYNOPSIS Reports the npm proxy configuration state. .DESCRIPTION Combines registry resolution, proxy route detection, and current managed npm proxy settings to decide whether the sandbox-owned npm config needs changes. .PARAMETER NpmCmd The npm command to inspect. .PARAMETER LocalRoot The sandbox local root used to resolve the managed runtime layout. #> [CmdletBinding()] param( [Parameter(Mandatory = $true)] [string]$NpmCmd, [string]$LocalRoot = (Get-ManifestedLocalRoot) ) $registryUri = Get-ManifestedNpmRegistryUri -NpmCmd $NpmCmd $proxyRoute = Resolve-ManifestedNpmProxyRoute -RegistryUri $registryUri $globalConfigPath = Get-ManifestedNpmGlobalConfigPath -NpmCmd $NpmCmd -LocalRoot $LocalRoot $currentProxy = $null $currentHttpsProxy = $null if (-not [string]::IsNullOrWhiteSpace($globalConfigPath)) { $currentProxy = Get-ManifestedNpmConfigValue -NpmCmd $NpmCmd -Key 'proxy' -GlobalConfigPath $globalConfigPath $currentHttpsProxy = Get-ManifestedNpmConfigValue -NpmCmd $NpmCmd -Key 'https-proxy' -GlobalConfigPath $globalConfigPath } if ([string]::IsNullOrWhiteSpace($globalConfigPath)) { $action = 'SkippedExternalNpm' } elseif ($proxyRoute.Route -eq 'Direct') { $action = 'DirectNoChange' } elseif ($currentProxy -eq $proxyRoute.ProxyUri -and $currentHttpsProxy -eq $proxyRoute.ProxyUri) { $action = 'ReusedManagedGlobalProxy' } else { $action = 'NeedsManagedGlobalProxy' } [pscustomobject]@{ NpmCmd = $NpmCmd RegistryUri = $proxyRoute.RegistryUri RegistryHost = $proxyRoute.RegistryHost ProxyUri = $proxyRoute.ProxyUri ProxyRequired = $proxyRoute.ProxyRequired Route = $proxyRoute.Route Action = $action GlobalConfigPath = $globalConfigPath CurrentProxy = $currentProxy CurrentHttpsProxy = $currentHttpsProxy } } function Sync-ManifestedNpmProxyConfiguration { <# .SYNOPSIS Applies the managed npm proxy configuration when required. .DESCRIPTION Uses the computed proxy status to write sandbox-owned npm proxy settings into the managed global config file when the registry route requires a proxy. .PARAMETER NpmCmd The npm command used to write configuration. .PARAMETER Status An optional precomputed proxy status object. .PARAMETER LocalRoot The sandbox local root used to resolve the managed runtime layout. #> [CmdletBinding()] param( [Parameter(Mandatory = $true)] [string]$NpmCmd, [pscustomobject]$Status, [string]$LocalRoot = (Get-ManifestedLocalRoot) ) if (-not $Status) { $Status = Get-ManifestedNpmProxyConfigurationStatus -NpmCmd $NpmCmd -LocalRoot $LocalRoot } if ($Status.Action -ne 'NeedsManagedGlobalProxy') { return $Status } New-ManifestedDirectory -Path (Split-Path -Parent $Status.GlobalConfigPath) | Out-Null & $NpmCmd config set ("proxy=" + $Status.ProxyUri) ("https-proxy=" + $Status.ProxyUri) --location=global --globalconfig $Status.GlobalConfigPath if ($LASTEXITCODE -ne 0) { throw "npm config set for proxy exited with code $LASTEXITCODE." } [pscustomobject]@{ NpmCmd = $Status.NpmCmd RegistryUri = $Status.RegistryUri RegistryHost = $Status.RegistryHost ProxyUri = $Status.ProxyUri ProxyRequired = $Status.ProxyRequired Route = $Status.Route Action = 'ConfiguredManagedGlobalProxy' GlobalConfigPath = $Status.GlobalConfigPath CurrentProxy = $Status.ProxyUri CurrentHttpsProxy = $Status.ProxyUri } } |