Private/ConfigManager.ps1

$script:ConfigDirName  = '.onepam'
$script:ConfigFileName = 'config.json'
$script:DefaultAPIBase = 'https://onepam.com'

function Get-OpConfigDir {
    [OutputType([string])]
    param()
    $homeDir = if ($IsWindows -or $env:OS -eq 'Windows_NT') { $env:USERPROFILE } else { $env:HOME }
    Join-Path $homeDir $script:ConfigDirName
}

function Confirm-OpConfigDir {
    $dir = Get-OpConfigDir
    if (-not (Test-Path $dir)) {
        New-Item -ItemType Directory -Path $dir -Force | Out-Null
        if (-not $IsWindows -and -not ($env:OS -eq 'Windows_NT')) {
            chmod 700 $dir 2>$null
        }
    }
    $dir
}

function Get-OpConfig {
    [OutputType([PSCustomObject])]
    param()

    $path = Join-Path (Get-OpConfigDir) $script:ConfigFileName

    $default = [PSCustomObject]@{
        api_base = $script:DefaultAPIBase
        org_uuid = ''
    }

    if (-not (Test-Path $path)) { return $default }

    try {
        $json = Get-Content -Path $path -Raw -ErrorAction Stop | ConvertFrom-Json
        if (-not $json.api_base) { $json | Add-Member -NotePropertyName 'api_base' -NotePropertyValue $script:DefaultAPIBase -Force }
        if ($null -eq $json.org_uuid) { $json | Add-Member -NotePropertyName 'org_uuid' -NotePropertyValue '' -Force }
        $json
    }
    catch {
        $default
    }
}

$script:SafePathSegmentPattern = '^[a-zA-Z0-9._-]+$'

function Assert-OpValidApiBase {
    param(
        [Parameter(Mandatory)]
        [string]$Url
    )
    $trimmed = $Url.TrimEnd('/')
    try {
        $parsed = [Uri]::new($trimmed)
        if ($parsed.Scheme -notin @('https', 'http')) {
            throw "API base must use https:// or http:// scheme, got '$($parsed.Scheme)://'."
        }
        if (-not $parsed.Host) {
            throw "API base URL has no host: '$trimmed'."
        }
    }
    catch [System.UriFormatException] {
        throw "Invalid API base URL: '$trimmed'."
    }
}

function Assert-OpSafePathSegment {
    param(
        [Parameter(Mandatory)]
        [string]$Value,
        [string]$Label = 'identifier'
    )
    if (-not $Value) {
        throw "$Label is required."
    }
    if ($Value -notmatch $script:SafePathSegmentPattern) {
        throw "Invalid ${Label}: '$Value'"
    }
}

function Save-OpConfig {
    param(
        [Parameter(Mandatory)]
        [PSCustomObject]$Config
    )

    $dir = Confirm-OpConfigDir
    $path = Join-Path $dir $script:ConfigFileName
    $Config | ConvertTo-Json -Depth 4 | Set-Content -Path $path -Encoding UTF8 -Force
    if (-not $IsWindows -and -not ($env:OS -eq 'Windows_NT')) {
        chmod 600 $path 2>$null
    }
}