diff --git a/postInstall.ps1 b/postInstall.ps1 index b78ed8d..55e70ef 100644 --- a/postInstall.ps1 +++ b/postInstall.ps1 @@ -1,5 +1,6 @@ # WelsonJS post-install script # Namhyeon Go , and Catswords OSS contributors. +# Updated on: 2025-12-21 # https://github.com/gnh1201/welsonjs # ================================ @@ -34,11 +35,14 @@ Write-Host $logo # SCRIPT ROOT RESOLUTION # ================================ # Ensure $ScriptRoot is available even on older PowerShell -if (-not (Get-Variable -Name PSScriptRoot -ErrorAction SilentlyContinue)) { - $ScriptRoot = Split-Path -Parent $MyInvocation.MyCommand.Path +$ScriptRoot = if ($PSScriptRoot) { + $PSScriptRoot +} +elseif ($MyInvocation.MyCommand.Path) { + Split-Path -Parent $MyInvocation.MyCommand.Path } else { - $ScriptRoot = $PSScriptRoot + (Get-Location).Path } # ================================ @@ -49,7 +53,11 @@ $urlsFilePath = Join-Path $ScriptRoot "data/DownloadUrls.psd1" if (Test-Path $urlsFilePath) { try { - $DownloadUrls = Import-PowerShellDataFile -Path $urlsFilePath + if (Get-Command Import-PowerShellDataFile -ErrorAction SilentlyContinue) { + $DownloadUrls = Import-PowerShellDataFile -Path $urlsFilePath + } else { + $DownloadUrls = Invoke-Expression (Get-Content $urlsFilePath -Raw) # Tested in Windows 8.1 + } } catch { Write-Host "[WARN] Failed to load DownloadUrls.psd1. Falling back to empty URL table." @@ -122,6 +130,12 @@ if ($TelemetryProvider -and $TelemetryProvider.ToLower() -eq "posthog") { } if ($finalDistinctId -and $finalDistinctId.Trim() -ne "") { + # Get current script file name + $scriptName = if (Get-Variable -Name PSCommandPath -ErrorAction SilentlyContinue) { + Split-Path $PSCommandPath -Leaf + } else { + Split-Path $MyInvocation.MyCommand.Path -Leaf + } # Build single event payload for PostHog /i/v0/e endpoint $body = @{ @@ -132,7 +146,7 @@ if ($TelemetryProvider -and $TelemetryProvider.ToLower() -eq "posthog") { product = "welsonjs" version = $Version os = "windows" - source = "post-install.ps1" + source = $scriptName components = $Components # Keep raw string here } timestamp = (Get-Date).ToString("o") # ISO 8601 format @@ -279,6 +293,20 @@ function Download-File { Write-Host " $Url" Write-Host " -> $DestinationPath" + # Fix TLS connectivity issues (Tested in Windows 8.1) + try { + $protocol = [Net.SecurityProtocolType]::Tls12 -bor ` + [Net.SecurityProtocolType]::Tls11 -bor ` + [Net.SecurityProtocolType]::Tls + try { + $protocol = $protocol -bor [Enum]::Parse([Net.SecurityProtocolType], 'Tls13') + } catch {} + [Net.ServicePointManager]::SecurityProtocol = $protocol + } + catch { + Write-Host "[WARN] TLS configuration failed: $($_.Exception.Message)" + } + # Ensure destination directory exists $destDir = Split-Path -Parent $DestinationPath if ($destDir -and -not (Test-Path $destDir)) { @@ -304,7 +332,60 @@ function Download-File { } if (-not $success) { - throw "Failed to download $Url after $maxRetries attempts." + Write-Host "[WARN] PowerShell download failed. Falling back to curl." + + $curlPath = Join-Path $ScriptRoot "bin\x86\curl.exe" + if (-not (Test-Path $curlPath)) { + throw "curl not found at $curlPath" + } + + $curlArgs = @( + "-L" + "--fail" + "--retry", "3" + "--retry-delay", "5" + "-o", $DestinationPath + $Url + ) + + $proc = Start-Process -FilePath $curlPath -ArgumentList $curlArgs -NoNewWindow -Wait -PassThru + if ($proc.ExitCode -ne 0 -or -not (Test-Path $DestinationPath)) { + throw "curl download failed with exit code $($proc.ExitCode)." + } + } +} + +function Invoke-7zr { + param( + [Parameter(Mandatory = $true)] + [string[]]$Arguments, + + [Parameter(Mandatory = $false)] + [string[]]$PipeToArguments + ) + + $sevenZip = Join-Path $ScriptRoot "bin\x86\7zr.exe" + if (-not (Test-Path $sevenZip)) { + throw "7zr.exe is missing: $sevenZip" + } + + Write-Host "[INFO] Using 7zr.exe:" + Write-Host " $sevenZip" + Write-Host "[DEBUG] 7zr args:" + Write-Host " $($Arguments -join ' ')" + + if ($PipeToArguments) { + Write-Host "[DEBUG] 7zr pipe-to args:" + Write-Host " $($PipeToArguments -join ' ')" + + & $sevenZip @Arguments | & $sevenZip @PipeToArguments + } + else { + & $sevenZip @Arguments + } + + if ($LASTEXITCODE -ne 0) { + throw "7zr exited with code $LASTEXITCODE." } } @@ -312,6 +393,7 @@ function Extract-CompressedFile { param( [Parameter(Mandatory = $true)] [string]$CompressedPath, + [Parameter(Mandatory = $true)] [string]$DestinationDirectory ) @@ -320,32 +402,46 @@ function Extract-CompressedFile { Write-Host " $CompressedPath" Write-Host " -> $DestinationDirectory" - # Ensure destination directory exists (clean) Ensure-EmptyDirectory -Path $DestinationDirectory - # Temporary extraction workspace $tmpExtractDir = Join-Path $DestinationDirectory "_tmp_extract" Ensure-EmptyDirectory -Path $tmpExtractDir - # Extract all - Add-Type -AssemblyName System.IO.Compression.FileSystem - [System.IO.Compression.ZipFile]::ExtractToDirectory($CompressedPath, $tmpExtractDir) + $extractedOk = $false + $zipErrorMsg = $null - # Detect source root to move from + # Try ZipFile first + try { + Add-Type -AssemblyName System.IO.Compression.FileSystem -ErrorAction Stop + [System.IO.Compression.ZipFile]::ExtractToDirectory($CompressedPath, $tmpExtractDir) + $extractedOk = $true + } + catch { + $zipErrorMsg = $_.Exception.Message + Write-Host "[WARN] ZipFile extraction failed. Falling back to 7zr.exe." + Write-Host " $zipErrorMsg" + } + + # Fallback: 7zr.exe + if (-not $extractedOk) { + Invoke-7zr -Arguments @("x", $CompressedPath, "-o$tmpExtractDir", "-y") + $extractedOk = $true + } + + # Detect root folder unwrap $entries = Get-ChildItem -Path $tmpExtractDir -Force $SourceRoot = $tmpExtractDir if ($entries.Count -eq 1 -and $entries[0].PSIsContainer) { - # ZIP contains exactly one top-level folder → unwrap that folder $SourceRoot = $entries[0].FullName - Write-Host "[*] Detected single root folder inside zip: $($entries[0].Name)" + Write-Host "[*] Detected single root folder inside archive: $($entries[0].Name)" Write-Host "[*] Unwrapping folder content..." } else { Write-Host "[*] Extracting multi-item archive (no root folder unwrapping needed)." } - # Move all items from source root to final destination + # Move items into final destination Get-ChildItem -Path $SourceRoot -Force | ForEach-Object { $targetPath = Join-Path $DestinationDirectory $_.Name @@ -355,7 +451,6 @@ function Extract-CompressedFile { Move-Item -Path $_.FullName -Destination $targetPath } - # Cleanup Remove-Item -Path $tmpExtractDir -Recurse -Force } @@ -363,6 +458,7 @@ function Extract-TarGzArchive { param( [Parameter(Mandatory = $true)] [string]$ArchivePath, + [Parameter(Mandatory = $true)] [string]$DestinationDirectory ) @@ -373,27 +469,27 @@ function Extract-TarGzArchive { Ensure-EmptyDirectory -Path $DestinationDirectory - # Validate tar availability + # Try tar first $tarCommand = Get-Command tar -ErrorAction SilentlyContinue - if (-not $tarCommand) { - Write-Host "[ERROR] 'tar' command not found." - throw "tar not available on this system." - } + if ($tarCommand) { + Write-Host "[DEBUG] tar command:" + Write-Host " tar -xzf `"$ArchivePath`" -C `"$DestinationDirectory`"" - Write-Host "[DEBUG] tar command:" - Write-Host " tar -xzf `"$ArchivePath`" -C `"$DestinationDirectory`"" - - try { & tar -xzf "$ArchivePath" -C "$DestinationDirectory" if ($LASTEXITCODE -ne 0) { throw "tar exited with code $LASTEXITCODE." } + return } - catch { - throw "Failed to extract TAR.GZ archive: $($_.Exception.Message)" - } + + Write-Host "[WARN] 'tar' not found. Falling back to 7zr.exe." + + Invoke-7zr ` + -Arguments @("x", $ArchivePath, "-so") ` + -PipeToArguments @("x", "-ttar", "-si", "-o$DestinationDirectory", "-y") } + # ================================ # COMPRESSED / INSTALLER PATHS # ================================ diff --git a/setup.iss b/setup.iss index 96eb725..c466dc2 100644 --- a/setup.iss +++ b/setup.iss @@ -1,5 +1,5 @@ ; @created_on 2020-06-26 -; @updated_on 2025-12-01 +; @updated_on 2025-12-20 ; @author Namhyeon Go and Catswords OSS contributors. [Setup] @@ -49,7 +49,7 @@ Root: HKCR; Subkey: "{cm:AppName}.Script"; ValueType: string; ValueData: "{cm:Ap Root: HKCR; Subkey: "{cm:AppName}.Script\DefaultIcon"; ValueType: string; ValueData: "{app}\app\favicon.ico,0"; Flags: uninsdeletekey Root: HKCR; Subkey: "{cm:AppName}.Script\shell"; ValueType: string; ValueData: "open"; Components: artifacts; Flags: uninsdeletevalue Root: HKCR; Subkey: "{cm:AppName}.Script\shell\open"; ValueType: string; ValueData: "Run with {cm:AppName}"; Components: artifacts; Flags: uninsdeletevalue -Root: HKCR; Subkey: "{cm:AppName}.Script\shell\open\command"; ValueType: string; ValueData: """{userappdata}\{cm:AppName}\bin\WelsonJS.Launcher.exe"" --file ""%1"""; Components: artifacts; Flags: uninsdeletevalue +Root: HKCR; Subkey: "{cm:AppName}.Script\shell\open\command"; ValueType: string; ValueData: """{app}\bin\x86\WelsonJS.Launcher.exe"" --file ""%1"""; Components: artifacts; Flags: uninsdeletevalue Root: HKCR; Subkey: "{cm:AppName}.Script\ScriptEngine"; ValueType: string; ValueData: "JScript"; Flags: uninsdeletevalue Root: HKCR; Subkey: "{cm:AppName}.Script\ScriptHostEncode"; ValueType: string; ValueData: "{{85131630-480C-11D2-B1F9-00C04F86C324}}"; Flags: uninsdeletevalue Root: HKCR; Subkey: ".js"; ValueType: string; ValueData: "{cm:AppName}.Script"; Components: fileassoc; Flags: uninsdeletevalue; @@ -75,6 +75,11 @@ Source: "helloworld.*"; DestDir: "{app}"; Source: "app\*"; DestDir: "{app}/app"; Flags: ignoreversion recursesubdirs; Source: "lib\*"; DestDir: "{app}/lib"; Flags: ignoreversion recursesubdirs; ; Source: "bin\*"; Excludes: "installer\*"; DestDir: "{app}/bin"; Flags: ignoreversion recursesubdirs; +Source: "bin\x86\7zr.exe"; DestDir: "{app}/bin/x86"; Flags: ignoreversion recursesubdirs; +Source: "bin\x86\curl.exe"; DestDir: "{app}/bin/x86"; Flags: ignoreversion recursesubdirs; +Source: "bin\x86\curl-ca-bundle.crt"; DestDir: "{app}/bin/x86"; Flags: ignoreversion recursesubdirs; +Source: "bin\x86\WelsonJS.Launcher.exe"; DestDir: "{app}/bin/x86"; Flags: ignoreversion recursesubdirs; +Source: "bin\x86\WelsonJS.Launcher.exe.config"; DestDir: "{app}/bin/x86"; Flags: ignoreversion recursesubdirs; Source: "data\*"; Excludes: "*-apikey.txt"; DestDir: "{app}/data"; Flags: ignoreversion recursesubdirs; ; Source: "node_modules\*"; DestDir: "{app}/node_modules"; Flags: ignoreversion recursesubdirs; ; Source: "bower_components\*"; DestDir: "{app}/node_modules"; Flags: ignoreversion recursesubdirs; @@ -87,14 +92,14 @@ Name: "{app}\tmp"; ; Type: files; Name: "{app}\defaultService.js" [Icons] -Name: "{group}\Start {cm:AppName} Launcher"; Filename: "{userappdata}\{cm:AppName}\bin\WelsonJS.Launcher.exe"; Components: artifacts; AfterInstall: SetElevationBit('{group}\Start {cm:AppName} Launcher.lnk'); +Name: "{group}\Start {cm:AppName} Launcher"; Filename: "{app}\bin\x86\WelsonJS.Launcher.exe"; Components: artifacts; AfterInstall: SetElevationBit('{group}\Start {cm:AppName} Launcher.lnk'); Name: "{group}\Test {cm:AppName}"; Filename: "{app}\bootstrap.bat"; AfterInstall: SetElevationBit('{group}\Test {cm:AppName}.lnk'); Name: "{group}\Uninstall {cm:AppName}"; Filename: "{uninstallexe}"; AfterInstall: SetElevationBit('{group}\Uninstall {cm:AppName}.lnk'); [Run] Filename: "powershell.exe"; Parameters: "-ExecutionPolicy Bypass -NoProfile -File ""{app}\postInstall.ps1"" -TelemetryProvider posthog -TelemetryApiKey ""{cm:PostHogApiKey}"" -Version ""{cm:AppVersion}"" -DistinctId ""{computername}"" -Components ""{code:GetSelectedComponents}"""; WorkingDir: "{app}"; Flags: waituntilterminated -Filename: {app}\installService.bat; Components: artifacts; Flags: nowait -Filename: "{userappdata}\{cm:AppName}\bin\WelsonJS.Launcher.exe"; Components: artifacts; Flags: nowait +Filename: "{app}\installService.bat"; Components: artifacts; Flags: nowait +Filename: "{app}\bin\x86\WelsonJS.Launcher.exe"; Components: artifacts; Flags: nowait [UninstallRun] Filename: {app}\uninstallService.bat; Components: artifacts; Flags: waituntilterminated