param( [string]$Workspace = "D:\workspace\vignette", [int]$ApiPort = 8001, [string]$Cloudflared = "$env:LOCALAPPDATA\Microsoft\WinGet\Links\cloudflared.exe", [string]$CloudflaredConfig = "$env:USERPROFILE\.cloudflared\vignette-config.yml", [switch]$SkipCloudflaredRestart ) $ErrorActionPreference = "Stop" $ApiDir = Join-Path $Workspace "apps\api" $Python = Join-Path $env:LOCALAPPDATA "Programs\Python\Python311\python.exe" $OutLog = Join-Path $ApiDir "api.public.out.log" $ErrLog = Join-Path $ApiDir "api.public.err.log" if (!(Test-Path $Python)) { throw "Python 3.11 not found at $Python" } if (!(Test-Path $ApiDir)) { throw "API directory not found at $ApiDir" } Get-CimInstance Win32_Process | Where-Object { $_.CommandLine -like "*uvicorn app.main:app*--port $ApiPort*" } | ForEach-Object { Stop-Process -Id $_.ProcessId -Force } $env:ENVIRONMENT = "prod" $env:AUTH_DEV_LOGIN_ENABLED = "false" $env:AUTO_SEED_PERSONAS = "false" $env:ALLOW_SEED_PERSONA_FALLBACK = "false" $env:FRONTEND_BASE_URL = "https://vignette.chanpaca.net" $env:CORS_ORIGINS = '["https://vignette.chanpaca.net","https://vignette-b1q.pages.dev"]' $proc = Start-Process -WindowStyle Hidden -FilePath $Python ` -ArgumentList @("-m", "uvicorn", "app.main:app", "--host", "127.0.0.1", "--port", "$ApiPort") ` -WorkingDirectory $ApiDir ` -RedirectStandardOutput $OutLog ` -RedirectStandardError $ErrLog ` -PassThru Start-Sleep -Seconds 3 $health = Invoke-RestMethod -Uri "http://127.0.0.1:$ApiPort/health" -TimeoutSec 20 if ($health.environment -ne "prod" -or -not $health.db -or -not $health.engine) { throw "Public API health is not production-safe: $($health | ConvertTo-Json -Compress)" } if (!$SkipCloudflaredRestart) { if (!(Test-Path $Cloudflared)) { throw "cloudflared not found at $Cloudflared" } if (!(Test-Path $CloudflaredConfig)) { throw "cloudflared config not found at $CloudflaredConfig" } $lines = Get-Content $CloudflaredConfig $insideApiIngress = $false $updated = $false $nextLines = foreach ($line in $lines) { if ($line -match "hostname:\s*api-vignette\.chanpaca\.net") { $insideApiIngress = $true $line continue } if ($insideApiIngress -and $line -match "^\s*service:\s*http://127\.0\.0\.1:\d+\s*$") { $updated = $true $insideApiIngress = $false " service: http://127.0.0.1:$ApiPort" continue } if ($insideApiIngress -and $line -match "^\s*-\s+") { $insideApiIngress = $false } $line } if (!$updated) { throw "Could not find api-vignette.chanpaca.net localhost service in $CloudflaredConfig" } Set-Content -Encoding UTF8 -Path $CloudflaredConfig -Value $nextLines Get-CimInstance Win32_Process | Where-Object { $_.Name -eq "cloudflared.exe" -and $_.CommandLine -like "*vignette-config.yml*" } | ForEach-Object { Stop-Process -Id $_.ProcessId -Force } Start-Sleep -Seconds 2 Start-Process -WindowStyle Hidden -FilePath $Cloudflared ` -ArgumentList @("tunnel", "--config", $CloudflaredConfig, "run") ` -RedirectStandardOutput (Join-Path $Workspace "cloudflared.public.out.log") ` -RedirectStandardError (Join-Path $Workspace "cloudflared.public.err.log") ` -PassThru | Out-Null } Write-Output "Public API running on http://127.0.0.1:$ApiPort with PID $($proc.Id)" Write-Output "Health: $($health | ConvertTo-Json -Compress)"