@www.hyperlinks.space/program-kit 1.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +53 -0
- package/api/ai.ts +111 -0
- package/api/base.ts +117 -0
- package/api/blockchain.ts +58 -0
- package/api/bot.ts +19 -0
- package/api/ping.ts +41 -0
- package/api/releases.ts +162 -0
- package/api/telegram.ts +65 -0
- package/api/tsconfig.json +17 -0
- package/app/_layout.tsx +135 -0
- package/app/ai.tsx +39 -0
- package/app/components/GlobalBottomBar.tsx +447 -0
- package/app/components/GlobalBottomBarWeb.tsx +362 -0
- package/app/components/GlobalLogoBar.tsx +108 -0
- package/app/components/GlobalLogoBarFallback.tsx +66 -0
- package/app/components/GlobalLogoBarWithFallback.tsx +24 -0
- package/app/components/HyperlinksSpaceLogo.tsx +29 -0
- package/app/components/Telegram.tsx +648 -0
- package/app/components/telegramWebApp.ts +359 -0
- package/app/fonts.ts +12 -0
- package/app/index.tsx +102 -0
- package/app/theme.ts +117 -0
- package/app.json +60 -0
- package/assets/icon.ico +0 -0
- package/assets/images/favicon.png +0 -0
- package/blockchain/coffee.ts +217 -0
- package/blockchain/router.ts +44 -0
- package/bot/format.ts +143 -0
- package/bot/grammy.ts +52 -0
- package/bot/responder.ts +620 -0
- package/bot/webhook.ts +262 -0
- package/database/messages.ts +128 -0
- package/database/start.ts +133 -0
- package/database/users.ts +46 -0
- package/docs/ai_and_search_bar_input.md +94 -0
- package/docs/ai_bot_messages.md +124 -0
- package/docs/backlogs/medium_term_backlog.md +26 -0
- package/docs/backlogs/short_term_backlog.md +39 -0
- package/docs/blue_bar_tackling.md +143 -0
- package/docs/bot_async_streaming.md +174 -0
- package/docs/build_and_install.md +129 -0
- package/docs/database_messages.md +34 -0
- package/docs/fonts.md +18 -0
- package/docs/releases.md +201 -0
- package/docs/releases_github_actions.md +188 -0
- package/docs/scalability.md +34 -0
- package/docs/security_plan_raw.md +244 -0
- package/docs/security_raw.md +345 -0
- package/docs/timing_raw.md +63 -0
- package/docs/tma_logo_bar_jump_investigation.md +69 -0
- package/docs/update.md +205 -0
- package/docs/wallets_hosting_architecture.md +257 -0
- package/eas.json +47 -0
- package/eslint.config.js +10 -0
- package/fullREADME.md +159 -0
- package/global.css +67 -0
- package/npmReadMe.md +53 -0
- package/package.json +214 -0
- package/scripts/load-env.ts +17 -0
- package/scripts/migrate-db.ts +16 -0
- package/scripts/program-kit-init.cjs +58 -0
- package/scripts/run-bot-local.ts +30 -0
- package/scripts/set-webhook.ts +67 -0
- package/scripts/test-api-base.ts +12 -0
- package/telegram/post.ts +328 -0
- package/tsconfig.json +17 -0
- package/vercel.json +7 -0
- package/windows/after-sign-windows-icon.cjs +13 -0
- package/windows/build-layout.cjs +72 -0
- package/windows/build-with-progress.cjs +88 -0
- package/windows/build.cjs +2247 -0
- package/windows/cleanup-legacy-appdata-installs.ps1 +91 -0
- package/windows/cleanup-legacy-windows-shortcuts.ps1 +46 -0
- package/windows/cleanup.cjs +200 -0
- package/windows/embed-windows-exe-icon.cjs +55 -0
- package/windows/extractAppPackage.nsh +150 -0
- package/windows/forge/README.md +41 -0
- package/windows/forge/forge.config.js +138 -0
- package/windows/forge/make-with-stamp.cjs +65 -0
- package/windows/forge-cleanup.cjs +255 -0
- package/windows/hsp-app-process.ps1 +63 -0
- package/windows/installer-hooks.nsi +373 -0
- package/windows/product-brand.cjs +42 -0
- package/windows/remove-orphan-uninstall-registry.ps1 +67 -0
- package/windows/run-installed-with-icon-debug.cmd +20 -0
- package/windows/run-win-electron-builder.cjs +46 -0
- package/windows/updater-dialog.html +143 -0
|
@@ -0,0 +1,373 @@
|
|
|
1
|
+
; Installer hooks for debug-friendly installs:
|
|
2
|
+
; - real-time DetailPrint + mirrored log file in %TEMP%
|
|
3
|
+
; - finish page shows full log in selectable read-only text area
|
|
4
|
+
;
|
|
5
|
+
; InstFiles page: the one-line status above the list is separate from the details list. SetDetailsPrint
|
|
6
|
+
; both duplicates DetailPrint into both; we use textonly for HspInstallStepStatus, then listonly so
|
|
7
|
+
; HspInstallDetailPrint lines only appear in the list (not repeated on the status line).
|
|
8
|
+
; Steps 1–N: see !define HSP_INSTALL_STEP_TOTAL and !insertmacro HspInstallStepStatus in HspInstFilesShow,
|
|
9
|
+
; customCheckAppRunning, extractAppPackage (decompress), customInstall.
|
|
10
|
+
;
|
|
11
|
+
; HSP_INSTALLER_AUTO_FINISH — two finish-page setups (see commits 4f25a5c vs 160595ef):
|
|
12
|
+
; • Defined → auto-dismiss wizard after install (4f25a5c: no MUI_FINISHPAGE_NOAUTOCLOSE, Finish
|
|
13
|
+
; button, then WM_CLOSE / Quit in HspFinishPage*).
|
|
14
|
+
; • Commented → installer stays open for logs (160595ef: MUI_FINISHPAGE_NOAUTOCLOSE, no forced close).
|
|
15
|
+
; Uncomment the next line to enable auto-close:
|
|
16
|
+
!define HSP_INSTALLER_AUTO_FINISH
|
|
17
|
+
|
|
18
|
+
; Extra exe name for older builds (do not use APP_EXECUTABLE_FILENAME here — not always defined by NSIS / CI).
|
|
19
|
+
; Legacy main exe from older "Hyperlinks Space App" installs (taskkill / relaunch).
|
|
20
|
+
!define HSP_ALT_MAIN_EXE "Hyperlinks Space App.exe"
|
|
21
|
+
; Hiding the bar: MUI2 only allows MUI_INSTFILESPAGE_PROGRESSBAR = "" | colored | smooth — "disable" is invalid and breaks InstProgressFlags (NSIS 3 CI). Hide msctls_progress32 at runtime in HspInstFilesShow instead.
|
|
22
|
+
|
|
23
|
+
!include "FileFunc.nsh"
|
|
24
|
+
!include "WinMessages.nsh"
|
|
25
|
+
|
|
26
|
+
!define HSP_INSTALL_STEP_TOTAL 6
|
|
27
|
+
; Status line only (textonly). Keep in sync with step inserts in customCheckAppRunning, extractAppPackage, customInstall.
|
|
28
|
+
!macro HspInstallStepStatus STEP
|
|
29
|
+
!ifndef BUILD_UNINSTALLER
|
|
30
|
+
SetDetailsView show
|
|
31
|
+
SetDetailsPrint textonly
|
|
32
|
+
DetailPrint "Installation: Step ${STEP} of ${HSP_INSTALL_STEP_TOTAL}"
|
|
33
|
+
SetDetailsPrint listonly
|
|
34
|
+
!endif
|
|
35
|
+
!macroend
|
|
36
|
+
|
|
37
|
+
!ifdef BUILD_UNINSTALLER
|
|
38
|
+
!macro HspAppendInstallerLog TEXT
|
|
39
|
+
!macroend
|
|
40
|
+
!macro HspInstallDetailPrint MSG
|
|
41
|
+
!macroend
|
|
42
|
+
!endif
|
|
43
|
+
|
|
44
|
+
!ifndef BUILD_UNINSTALLER
|
|
45
|
+
Var HspLogFile
|
|
46
|
+
Var HspLogHandle
|
|
47
|
+
Var HspFinishLogEdit
|
|
48
|
+
Var HspDidLaunchApp
|
|
49
|
+
|
|
50
|
+
Function HspEnsureInstallerLogPath
|
|
51
|
+
StrCmp $HspLogFile "" hspSetLogPath hspLogPathDone
|
|
52
|
+
hspSetLogPath:
|
|
53
|
+
StrCpy $HspLogFile "$TEMP\HyperlinksSpaceInstall.log"
|
|
54
|
+
Delete "$HspLogFile"
|
|
55
|
+
hspLogPathDone:
|
|
56
|
+
FunctionEnd
|
|
57
|
+
|
|
58
|
+
!macro HspAppendInstallerLog TEXT
|
|
59
|
+
Call HspEnsureInstallerLogPath
|
|
60
|
+
${GetTime} "" "L" $R0 $R1 $R2 $R3 $R4 $R5 $R6
|
|
61
|
+
StrCpy $R7 "[$R2-$R1-$R0 $R4:$R5:$R6] "
|
|
62
|
+
FileOpen $HspLogHandle "$HspLogFile" a
|
|
63
|
+
FileWrite $HspLogHandle $R7
|
|
64
|
+
FileWrite $HspLogHandle "${TEXT}"
|
|
65
|
+
FileWrite $HspLogHandle "$\r$\n"
|
|
66
|
+
FileClose $HspLogHandle
|
|
67
|
+
!macroend
|
|
68
|
+
|
|
69
|
+
!macro HspInstallDetailPrint MSG
|
|
70
|
+
SetDetailsView show
|
|
71
|
+
SetDetailsPrint listonly
|
|
72
|
+
DetailPrint "${MSG}"
|
|
73
|
+
!insertmacro HspAppendInstallerLog "${MSG}"
|
|
74
|
+
!macroend
|
|
75
|
+
|
|
76
|
+
Function .onInstSuccess
|
|
77
|
+
; Primary launch trigger for all installer modes (including one-click/silent paths).
|
|
78
|
+
; Use one-shot guard so Finish-page fallback does not launch twice.
|
|
79
|
+
StrCmp $HspDidLaunchApp "1" hspInstSuccessAfterLaunch
|
|
80
|
+
StrCpy $HspDidLaunchApp "1"
|
|
81
|
+
Sleep 500
|
|
82
|
+
Call HspLaunchInstalledApp
|
|
83
|
+
hspInstSuccessAfterLaunch:
|
|
84
|
+
!insertmacro HspAppendInstallerLog "INSTALL_SUCCESS"
|
|
85
|
+
FunctionEnd
|
|
86
|
+
|
|
87
|
+
Function HspLaunchInstalledApp
|
|
88
|
+
; Keep Forge/electron-builder compatibility: avoid $launchLink (not always defined).
|
|
89
|
+
IfFileExists "$INSTDIR\current\${PRODUCT_FILENAME}.exe" hspLaunchCurrent hspLaunchLegacy
|
|
90
|
+
hspLaunchCurrent:
|
|
91
|
+
ExecShell "open" "$INSTDIR\current\${PRODUCT_FILENAME}.exe"
|
|
92
|
+
!insertmacro HspAppendInstallerLog "APP_LAUNCH_TRIGGERED(current)"
|
|
93
|
+
Return
|
|
94
|
+
hspLaunchLegacy:
|
|
95
|
+
IfFileExists "$INSTDIR\${PRODUCT_FILENAME}.exe" hspLaunchLegacyDo hspLaunchFailed
|
|
96
|
+
hspLaunchLegacyDo:
|
|
97
|
+
ExecShell "open" "$INSTDIR\${PRODUCT_FILENAME}.exe"
|
|
98
|
+
!insertmacro HspAppendInstallerLog "APP_LAUNCH_TRIGGERED"
|
|
99
|
+
Return
|
|
100
|
+
hspLaunchFailed:
|
|
101
|
+
!insertmacro HspAppendInstallerLog "APP_LAUNCH_FAILED"
|
|
102
|
+
FunctionEnd
|
|
103
|
+
|
|
104
|
+
Function .onInstFailed
|
|
105
|
+
!insertmacro HspAppendInstallerLog "INSTALL_FAILED"
|
|
106
|
+
FunctionEnd
|
|
107
|
+
|
|
108
|
+
Function HspInstFilesShow
|
|
109
|
+
!insertmacro HspInstallStepStatus 1
|
|
110
|
+
FindWindow $0 "#32770" "" $HWNDPARENT
|
|
111
|
+
FindWindow $1 "msctls_progress32" "" $0
|
|
112
|
+
IntCmp $1 0 hspInstFilesBarDone
|
|
113
|
+
ShowWindow $1 ${SW_HIDE}
|
|
114
|
+
hspInstFilesBarDone:
|
|
115
|
+
FunctionEnd
|
|
116
|
+
|
|
117
|
+
; $0 = 1 if any known packaged exe is still running (see hsp-app-process.ps1 -Action Test).
|
|
118
|
+
Function HspResolvePowerShellExe
|
|
119
|
+
IfFileExists "$WINDIR\Sysnative\WindowsPowerShell\v1.0\powershell.exe" 0 hspPsSys32
|
|
120
|
+
StrCpy $R5 "$WINDIR\Sysnative\WindowsPowerShell\v1.0\powershell.exe"
|
|
121
|
+
Return
|
|
122
|
+
hspPsSys32:
|
|
123
|
+
StrCpy $R5 "$WINDIR\System32\WindowsPowerShell\v1.0\powershell.exe"
|
|
124
|
+
FunctionEnd
|
|
125
|
+
|
|
126
|
+
Function HspSetEnvInstDir
|
|
127
|
+
System::Call 'kernel32::SetEnvironmentVariable(t, t) ("HSP_INSTDIR", "$INSTDIR")'
|
|
128
|
+
FunctionEnd
|
|
129
|
+
|
|
130
|
+
Function HspClearEnvInstDir
|
|
131
|
+
System::Call 'kernel32::SetEnvironmentVariable(t, i) ("HSP_INSTDIR", 0)'
|
|
132
|
+
FunctionEnd
|
|
133
|
+
|
|
134
|
+
; PowerShell: use nsExec::Exec (not ExecWait). ExecWait always attaches a console to powershell.exe,
|
|
135
|
+
; which flashes on screen even with -WindowStyle Hidden; nsExec runs the process with no console window.
|
|
136
|
+
Function HspAnyPackagedExeRunning
|
|
137
|
+
Call HspResolvePowerShellExe
|
|
138
|
+
Call HspSetEnvInstDir
|
|
139
|
+
IfFileExists "$PLUGINSDIR\hsp-app-process.ps1" 0 hspAnyExeNoScript
|
|
140
|
+
nsExec::Exec `"$R5" -NoProfile -NonInteractive -ExecutionPolicy Bypass -File "$PLUGINSDIR\hsp-app-process.ps1" -Action Test`
|
|
141
|
+
Pop $R4
|
|
142
|
+
Call HspClearEnvInstDir
|
|
143
|
+
StrCmp $R4 "error" hspAnyExeNsFail
|
|
144
|
+
StrCmp $R4 "timeout" hspAnyExeNsFail
|
|
145
|
+
IntCmp $R4 0 hspAnyExeYes
|
|
146
|
+
StrCpy $0 0
|
|
147
|
+
Return
|
|
148
|
+
hspAnyExeNsFail:
|
|
149
|
+
StrCpy $0 0
|
|
150
|
+
Return
|
|
151
|
+
hspAnyExeNoScript:
|
|
152
|
+
Call HspClearEnvInstDir
|
|
153
|
+
StrCpy $0 0
|
|
154
|
+
Return
|
|
155
|
+
hspAnyExeYes:
|
|
156
|
+
StrCpy $0 1
|
|
157
|
+
Return
|
|
158
|
+
FunctionEnd
|
|
159
|
+
|
|
160
|
+
Function HspWaitUntilPackagedProcessesGone
|
|
161
|
+
StrCpy $R8 0
|
|
162
|
+
hspWaitPackagedPoll:
|
|
163
|
+
Call HspAnyPackagedExeRunning
|
|
164
|
+
IntCmp $0 0 hspWaitPackagedDone
|
|
165
|
+
IntOp $R8 $R8 + 1
|
|
166
|
+
IntCmp $R8 600 0 0 hspWaitPackagedDone
|
|
167
|
+
Sleep 50
|
|
168
|
+
Goto hspWaitPackagedPoll
|
|
169
|
+
hspWaitPackagedDone:
|
|
170
|
+
; Extra settle after Test script reports processes gone (handles on DLLs).
|
|
171
|
+
Sleep 500
|
|
172
|
+
FunctionEnd
|
|
173
|
+
|
|
174
|
+
Function HspKillPackagedAppProcesses
|
|
175
|
+
Call HspResolvePowerShellExe
|
|
176
|
+
Call HspSetEnvInstDir
|
|
177
|
+
IfFileExists "$PLUGINSDIR\hsp-app-process.ps1" 0 hspKillNoScript
|
|
178
|
+
nsExec::Exec `"$R5" -NoProfile -NonInteractive -ExecutionPolicy Bypass -File "$PLUGINSDIR\hsp-app-process.ps1" -Action Kill`
|
|
179
|
+
Pop $R4
|
|
180
|
+
hspKillNoScript:
|
|
181
|
+
Call HspClearEnvInstDir
|
|
182
|
+
FunctionEnd
|
|
183
|
+
|
|
184
|
+
; Called from windows/extractAppPackage.nsh before each CopyFiles (and each retry).
|
|
185
|
+
Function HspKillBeforeCopy
|
|
186
|
+
SetDetailsView show
|
|
187
|
+
SetDetailsPrint listonly
|
|
188
|
+
DetailPrint "[installer] unlock install dir before copy (attempt $R1)"
|
|
189
|
+
Call HspKillPackagedAppProcesses
|
|
190
|
+
Call HspWaitUntilPackagedProcessesGone
|
|
191
|
+
; Second pass: elevation can miss user processes on first taskkill; retry once.
|
|
192
|
+
Call HspKillPackagedAppProcesses
|
|
193
|
+
Call HspWaitUntilPackagedProcessesGone
|
|
194
|
+
; Clear read-only on existing tree (helps overwrite in Program Files).
|
|
195
|
+
IfFileExists "$INSTDIR" 0 hspKillBeforeCopyNoAttrib
|
|
196
|
+
nsExec::Exec `%COMSPEC% /c attrib -R "$INSTDIR\*.*" /S /D`
|
|
197
|
+
Pop $R9
|
|
198
|
+
hspKillBeforeCopyNoAttrib:
|
|
199
|
+
FunctionEnd
|
|
200
|
+
|
|
201
|
+
Function HspFinishPageShow
|
|
202
|
+
!ifndef HSP_INSTALLER_AUTO_FINISH
|
|
203
|
+
SetAutoClose false
|
|
204
|
+
!endif
|
|
205
|
+
Call HspEnsureInstallerLogPath
|
|
206
|
+
; Launch app automatically when install reaches finish page; keep installer open for logs.
|
|
207
|
+
StrCmp $HspDidLaunchApp "1" hspSkipAutoLaunch
|
|
208
|
+
StrCpy $HspDidLaunchApp "1"
|
|
209
|
+
Call HspLaunchInstalledApp
|
|
210
|
+
hspSkipAutoLaunch:
|
|
211
|
+
StrCpy $HspFinishLogEdit ""
|
|
212
|
+
System::Call "user32::CreateWindowExW(i 0, w \"Edit\", w \"\", i 0x50201844, i 128, i 128, i 360, i 220, i $HWNDPARENT, i 0, i 0, i 0) i.r0"
|
|
213
|
+
IntCmp $0 0 hspFinishShowDone
|
|
214
|
+
StrCpy $HspFinishLogEdit $0
|
|
215
|
+
StrCpy $9 $0
|
|
216
|
+
System::Call "user32::SendMessageW(i r9, i 0xC5, i 16777216, i 0)"
|
|
217
|
+
IfFileExists "$HspLogFile" hspFinishFillFile
|
|
218
|
+
System::Call "user32::SetWindowTextW(i r9, w \"No installation log file was found.\")"
|
|
219
|
+
Goto hspFinishShowDone
|
|
220
|
+
hspFinishFillFile:
|
|
221
|
+
FileOpen $R0 "$HspLogFile" r
|
|
222
|
+
hspFinishReadLoop:
|
|
223
|
+
FileRead $R0 $1
|
|
224
|
+
IfErrors hspFinishFileDone
|
|
225
|
+
System::Call "user32::SendMessageW(i r9, i 0x000E, i 0, i 0) i.r4"
|
|
226
|
+
System::Call "user32::SendMessageW(i r9, i 0xB1, i r4, i r4)"
|
|
227
|
+
StrCpy $2 "$1$\r$\n"
|
|
228
|
+
System::Call "user32::SendMessageW(i r9, i 0xC2, i 1, w r2)"
|
|
229
|
+
Goto hspFinishReadLoop
|
|
230
|
+
hspFinishFileDone:
|
|
231
|
+
FileClose $R0
|
|
232
|
+
hspFinishShowDone:
|
|
233
|
+
!ifdef HSP_INSTALLER_AUTO_FINISH
|
|
234
|
+
; Quit in SHOW alone is unreliable (runs before nsDialogs::Show message loop).
|
|
235
|
+
SendMessage $HWNDPARENT ${WM_CLOSE} 0 0
|
|
236
|
+
System::Call "user32::PostQuitMessage(i 0)"
|
|
237
|
+
!endif
|
|
238
|
+
FunctionEnd
|
|
239
|
+
|
|
240
|
+
Function HspFinishPageLeave
|
|
241
|
+
StrCmp $HspFinishLogEdit "" +3
|
|
242
|
+
StrCpy $0 $HspFinishLogEdit
|
|
243
|
+
System::Call "user32::DestroyWindow(i r0)"
|
|
244
|
+
StrCpy $HspFinishLogEdit ""
|
|
245
|
+
!ifdef HSP_INSTALLER_AUTO_FINISH
|
|
246
|
+
Quit
|
|
247
|
+
!endif
|
|
248
|
+
FunctionEnd
|
|
249
|
+
!endif
|
|
250
|
+
|
|
251
|
+
!macro customHeader
|
|
252
|
+
Caption "${PRODUCT_NAME}"
|
|
253
|
+
ShowInstDetails show
|
|
254
|
+
!ifdef BUILD_UNINSTALLER
|
|
255
|
+
ShowUninstDetails show
|
|
256
|
+
!endif
|
|
257
|
+
!macroend
|
|
258
|
+
|
|
259
|
+
!macro customPageAfterChangeDir
|
|
260
|
+
ShowInstDetails show
|
|
261
|
+
!define MUI_PAGE_CUSTOMFUNCTION_SHOW HspInstFilesShow
|
|
262
|
+
!macroend
|
|
263
|
+
|
|
264
|
+
!macro customInstallMode
|
|
265
|
+
; Leave install mode to electron-builder (perMachine in package.json → Program Files).
|
|
266
|
+
; Forcing $isForceCurrentInstall breaks INSTALL_MODE_PER_ALL_USERS_REQUIRED / per-machine builds.
|
|
267
|
+
!macroend
|
|
268
|
+
|
|
269
|
+
; Installer only. Uninstaller defines BUILD_UNINSTALLER — Call must use un.* there; use stock _CHECK_APP_RUNNING.
|
|
270
|
+
!ifndef BUILD_UNINSTALLER
|
|
271
|
+
!macro customCheckAppRunning
|
|
272
|
+
!insertmacro HspInstallDetailPrint "[installer] stop running app processes (tree kill + wait, all exe names)"
|
|
273
|
+
Call HspKillPackagedAppProcesses
|
|
274
|
+
Call HspWaitUntilPackagedProcessesGone
|
|
275
|
+
!insertmacro HspInstallStepStatus 2
|
|
276
|
+
!macroend
|
|
277
|
+
!endif
|
|
278
|
+
|
|
279
|
+
!macro customInit
|
|
280
|
+
!insertmacro HspInstallDetailPrint "[installer] customInit start"
|
|
281
|
+
; Remove stale Start Menu / Desktop shortcuts from older "Hyperlinks Space App" installs (new product: ${PRODUCT_NAME}).
|
|
282
|
+
Delete "$SMPROGRAMS\Hyperlinks Space App.lnk"
|
|
283
|
+
Delete "$COMMONPROGRAMS\Hyperlinks Space App.lnk"
|
|
284
|
+
Delete "$DESKTOP\Hyperlinks Space App.lnk"
|
|
285
|
+
Delete "$COMMONDESKTOP\Hyperlinks Space App.lnk"
|
|
286
|
+
RMDir /r /REBOOTOK "$SMPROGRAMS\Hyperlinks Space App"
|
|
287
|
+
RMDir /r /REBOOTOK "$COMMONPROGRAMS\Hyperlinks Space App"
|
|
288
|
+
; Old per-user installs (AppData\Local\Programs\...) when current build uses perMachine → Program Files.
|
|
289
|
+
ReadEnvStr $R8 "LOCALAPPDATA"
|
|
290
|
+
RMDir /r /REBOOTOK "$R8\Programs\Hyperlinks Space App"
|
|
291
|
+
RMDir /r /REBOOTOK "$R8\Programs\HyperlinksSpaceApp"
|
|
292
|
+
!insertmacro HspInstallDetailPrint "[installer] removed legacy Hyperlinks Space App shortcuts (if present)"
|
|
293
|
+
; Do NOT delete UninstallString / QuietUninstallString here — that breaks Windows Settings "Uninstall"
|
|
294
|
+
; for this product and can leave a grayed-out Apps entry with no uninstall command.
|
|
295
|
+
!insertmacro HspInstallDetailPrint "[installer] customInit complete"
|
|
296
|
+
!macroend
|
|
297
|
+
|
|
298
|
+
!macro customInstall
|
|
299
|
+
!insertmacro HspInstallStepStatus 5
|
|
300
|
+
!insertmacro HspInstallDetailPrint "[installer] customInstall start"
|
|
301
|
+
!insertmacro HspInstallDetailPrint "[installer] files copied, waiting for Finish page"
|
|
302
|
+
; Trigger launch as soon as install work is complete.
|
|
303
|
+
StrCmp $HspDidLaunchApp "1" hspCustomInstallAfterLaunch
|
|
304
|
+
StrCpy $HspDidLaunchApp "1"
|
|
305
|
+
Call HspLaunchInstalledApp
|
|
306
|
+
hspCustomInstallAfterLaunch:
|
|
307
|
+
!insertmacro HspInstallDetailPrint "[installer] customInstall complete"
|
|
308
|
+
!insertmacro HspInstallStepStatus 6
|
|
309
|
+
!macroend
|
|
310
|
+
|
|
311
|
+
!macro customFinishPage
|
|
312
|
+
!ifndef BUILD_UNINSTALLER
|
|
313
|
+
!ifdef HSP_INSTALLER_AUTO_FINISH
|
|
314
|
+
; 4f25a5c: omit NOAUTOCLOSE (single-step to Finish; then we force-close in HspFinishPageShow/Leave).
|
|
315
|
+
!define MUI_FINISHPAGE_BUTTON "Finish"
|
|
316
|
+
!define MUI_PAGE_CUSTOMFUNCTION_SHOW HspFinishPageShow
|
|
317
|
+
!define MUI_PAGE_CUSTOMFUNCTION_LEAVE HspFinishPageLeave
|
|
318
|
+
!insertmacro MUI_PAGE_FINISH
|
|
319
|
+
!else
|
|
320
|
+
; 160595ef: NOAUTOCLOSE keeps the wizard open until the user is done (log copy / manual close).
|
|
321
|
+
!define MUI_FINISHPAGE_NOAUTOCLOSE
|
|
322
|
+
!define MUI_PAGE_CUSTOMFUNCTION_SHOW HspFinishPageShow
|
|
323
|
+
!define MUI_PAGE_CUSTOMFUNCTION_LEAVE HspFinishPageLeave
|
|
324
|
+
!insertmacro MUI_PAGE_FINISH
|
|
325
|
+
!endif
|
|
326
|
+
!endif
|
|
327
|
+
!macroend
|
|
328
|
+
|
|
329
|
+
!macro customUnInstall
|
|
330
|
+
!insertmacro HspAppendInstallerLog "[uninstaller] start"
|
|
331
|
+
; Per-machine installs only remove SHELL_CONTEXT=HKLM keys. Legacy per-user installs also wrote
|
|
332
|
+
; HKCU Uninstall + Software\{APP_GUID}; that leaves a duplicate "Installed apps" row. Clean HKCU when
|
|
333
|
+
; uninstalling for all users. (Do not remove HKCU InstallLocation when uninstalling per-user —
|
|
334
|
+
; InstFiles still reads MenuDirectory from HKCU in that mode.)
|
|
335
|
+
DetailPrint "[uninstaller] legacy HKCU registry cleanup (if any)"
|
|
336
|
+
DeleteRegKey HKCU "${UNINSTALL_REGISTRY_KEY}"
|
|
337
|
+
!ifdef UNINSTALL_REGISTRY_KEY_2
|
|
338
|
+
DeleteRegKey HKCU "${UNINSTALL_REGISTRY_KEY_2}"
|
|
339
|
+
!endif
|
|
340
|
+
${if} $installMode == "all"
|
|
341
|
+
DeleteRegKey HKCU "${INSTALL_REGISTRY_KEY}"
|
|
342
|
+
${endif}
|
|
343
|
+
|
|
344
|
+
; Defensive cleanup for older 32-bit-view uninstall entries (WOW6432Node) that can remain visible
|
|
345
|
+
; in Windows "Installed apps" if an old uninstall executable was removed manually.
|
|
346
|
+
DetailPrint "[uninstaller] legacy WOW6432Node uninstall key cleanup (if any)"
|
|
347
|
+
DeleteRegKey HKLM "Software\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\${UNINSTALL_APP_KEY}"
|
|
348
|
+
DeleteRegKey HKLM "Software\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\${APP_GUID}"
|
|
349
|
+
|
|
350
|
+
; Remove legacy all-users install folders only (do not target current PRODUCT folder here).
|
|
351
|
+
; Try immediate delete first; schedule reboot cleanup only if path is locked.
|
|
352
|
+
ClearErrors
|
|
353
|
+
RMDir /r "$PROGRAMFILES\Hyperlinks Space App"
|
|
354
|
+
IfErrors 0 +2
|
|
355
|
+
RMDir /r /REBOOTOK "$PROGRAMFILES\Hyperlinks Space App"
|
|
356
|
+
|
|
357
|
+
ClearErrors
|
|
358
|
+
RMDir /r "$PROGRAMFILES64\Hyperlinks Space App"
|
|
359
|
+
IfErrors 0 +2
|
|
360
|
+
RMDir /r /REBOOTOK "$PROGRAMFILES64\Hyperlinks Space App"
|
|
361
|
+
|
|
362
|
+
!insertmacro HspAppendInstallerLog "[uninstaller] complete"
|
|
363
|
+
!macroend
|
|
364
|
+
|
|
365
|
+
; Runs before Section install (electron-builder prepends this include). Drops helper script for nsExec::Exec -File.
|
|
366
|
+
; Use BUILD_RESOURCES_DIR so makensis finds the script when cwd is the NSIS cache dir (Forge/CI).
|
|
367
|
+
!ifndef BUILD_UNINSTALLER
|
|
368
|
+
Section "-hsp_app_process_ps1"
|
|
369
|
+
InitPluginsDir
|
|
370
|
+
SetOutPath $PLUGINSDIR
|
|
371
|
+
File "${BUILD_RESOURCES_DIR}\hsp-app-process.ps1"
|
|
372
|
+
SectionEnd
|
|
373
|
+
!endif
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Single source of truth for Windows/Electron product naming.
|
|
3
|
+
* Display name and artifact slug come from app/package.json → build.productName.
|
|
4
|
+
*/
|
|
5
|
+
const fs = require("fs");
|
|
6
|
+
const path = require("path");
|
|
7
|
+
|
|
8
|
+
const pkgPath = path.join(__dirname, "..", "package.json");
|
|
9
|
+
const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf8"));
|
|
10
|
+
const productDisplayName = pkg.build?.productName ?? "Hyperlinks Space Program";
|
|
11
|
+
/** No spaces; matches electron-builder artifactName patterns (e.g. HyperlinksSpaceProgram_1.0.0.zip). */
|
|
12
|
+
const productSlug = productDisplayName.replace(/\s+/g, "");
|
|
13
|
+
|
|
14
|
+
/** Previous public name — keep for updater zip matching, staged layouts, and NSIS taskkill of old installs. */
|
|
15
|
+
const legacyDisplayNames = ["Hyperlinks Space App"];
|
|
16
|
+
const legacySlugs = ["HyperlinksSpaceApp"];
|
|
17
|
+
|
|
18
|
+
function allKnownExeBaseNames() {
|
|
19
|
+
const set = new Set();
|
|
20
|
+
set.add(`${productDisplayName}.exe`);
|
|
21
|
+
set.add(`${productSlug}.exe`);
|
|
22
|
+
for (const d of legacyDisplayNames) set.add(`${d}.exe`);
|
|
23
|
+
for (const s of legacySlugs) set.add(`${s}.exe`);
|
|
24
|
+
return [...set];
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/** Regex: release zip assets starting with current or legacy slug (e.g. HyperlinksSpaceProgram_ or HyperlinksSpaceApp_). */
|
|
28
|
+
function portableZipAssetPattern() {
|
|
29
|
+
const slugs = [productSlug, ...legacySlugs].join("|");
|
|
30
|
+
return new RegExp(`^(?:${slugs})[_-]`, "i");
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
module.exports = {
|
|
34
|
+
productDisplayName,
|
|
35
|
+
productSlug,
|
|
36
|
+
/** Same as build.win.artifactName portable zip prefix `${slug}_`. */
|
|
37
|
+
portableZipPrefix: `${productSlug}_`,
|
|
38
|
+
legacyDisplayNames,
|
|
39
|
+
legacySlugs,
|
|
40
|
+
allKnownExeBaseNames,
|
|
41
|
+
portableZipAssetPattern,
|
|
42
|
+
};
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# Remove broken "Hyperlinks Space App" entries from Uninstall registry so Settings no longer shows a ghost app
|
|
2
|
+
# with grayed-out Uninstall (usually UninstallString missing or points to deleted files).
|
|
3
|
+
#
|
|
4
|
+
# Run from elevated PowerShell if HKLM keys need removal: Right-click PowerShell -> Run as administrator
|
|
5
|
+
#
|
|
6
|
+
# Usage:
|
|
7
|
+
# powershell -ExecutionPolicy Bypass -File .\windows\remove-orphan-uninstall-registry.ps1 # list only
|
|
8
|
+
# powershell -ExecutionPolicy Bypass -File .\windows\remove-orphan-uninstall-registry.ps1 -Remove # delete matching keys
|
|
9
|
+
#
|
|
10
|
+
param(
|
|
11
|
+
[switch]$Remove
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
$ErrorActionPreference = "Continue"
|
|
15
|
+
$matchDisplay = "Hyperlinks Space App"
|
|
16
|
+
|
|
17
|
+
$roots = @(
|
|
18
|
+
"HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall"
|
|
19
|
+
"HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall"
|
|
20
|
+
"HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall"
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
$found = @()
|
|
24
|
+
foreach ($root in $roots) {
|
|
25
|
+
if (-not (Test-Path -LiteralPath $root)) { continue }
|
|
26
|
+
Get-ChildItem -LiteralPath $root -ErrorAction SilentlyContinue | ForEach-Object {
|
|
27
|
+
try {
|
|
28
|
+
$p = Get-ItemProperty -LiteralPath $_.PSPath -ErrorAction Stop
|
|
29
|
+
$name = $p.DisplayName
|
|
30
|
+
if (-not $name) { return }
|
|
31
|
+
if ($name -notlike "*$matchDisplay*") { return }
|
|
32
|
+
$un = $p.UninstallString
|
|
33
|
+
$quiet = $p.QuietUninstallString
|
|
34
|
+
$found += [pscustomobject]@{
|
|
35
|
+
PsPath = $_.PSPath
|
|
36
|
+
DisplayName = $name
|
|
37
|
+
UninstallString = $un
|
|
38
|
+
QuietUninstall = $quiet
|
|
39
|
+
}
|
|
40
|
+
} catch {}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if ($found.Count -eq 0) {
|
|
45
|
+
Write-Host "No Uninstall registry entries with DisplayName matching '$matchDisplay' were found."
|
|
46
|
+
exit 0
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
Write-Host "Matching registry keys:"
|
|
50
|
+
$found | Select-Object DisplayName, UninstallString, QuietUninstall, PsPath | Format-List
|
|
51
|
+
|
|
52
|
+
if (-not $Remove) {
|
|
53
|
+
Write-Host ""
|
|
54
|
+
Write-Host "To remove these keys (so the ghost app disappears from Settings), re-run with -Remove"
|
|
55
|
+
exit 0
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
foreach ($row in $found) {
|
|
59
|
+
try {
|
|
60
|
+
Remove-Item -LiteralPath $row.PsPath -Recurse -Force
|
|
61
|
+
Write-Host "Removed: $($row.PsPath)"
|
|
62
|
+
} catch {
|
|
63
|
+
Write-Warning "Could not remove $($row.PsPath) (try Administrator PowerShell for HKLM): $_"
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
Write-Host "Done. If Settings still shows the app, restart it or sign out and back in."
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
@echo off
|
|
2
|
+
setlocal EnableExtensions
|
|
3
|
+
rem Launches the per-machine NSIS install with HSP_DEBUG_ICON=1 so main.log gets [icon:debug] lines.
|
|
4
|
+
rem Log file: %%APPDATA%%\expo-template-default\main.log (see package.json "name").
|
|
5
|
+
set "HSP_DEBUG_ICON=1"
|
|
6
|
+
set "ROOT=%ProgramFiles%\Hyperlinks Space Program"
|
|
7
|
+
if not exist "%ROOT%\" (
|
|
8
|
+
echo [run-installed-with-icon-debug] Not found: "%ROOT%"
|
|
9
|
+
exit /b 1
|
|
10
|
+
)
|
|
11
|
+
for %%N in ("Hyperlinks Space Program.exe" "Hyperlinks-Space-Program.exe" "HyperlinksSpaceProgram.exe") do (
|
|
12
|
+
if exist "%ROOT%\%%~N" (
|
|
13
|
+
echo [run-installed-with-icon-debug] Starting "%ROOT%\%%~N"
|
|
14
|
+
start "" "%ROOT%\%%~N"
|
|
15
|
+
exit /b 0
|
|
16
|
+
)
|
|
17
|
+
)
|
|
18
|
+
echo [run-installed-with-icon-debug] No known exe in "%ROOT%":
|
|
19
|
+
dir /b "%ROOT%\*.exe" 2>nul
|
|
20
|
+
exit /b 1
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Runs electron-builder --win with BUILD_STAMP, per-build output under releases/builder/<id>/eb-output/,
|
|
3
|
+
* then cleanup.cjs in the same process env (so HSP_EB_OUTPUT is not lost between shells).
|
|
4
|
+
*/
|
|
5
|
+
const { spawnSync } = require("child_process");
|
|
6
|
+
const path = require("path");
|
|
7
|
+
const { RELEASE_BUILD_DEV_DIRNAME, resolveBuildLayout, ensureCleanEbOutput } = require("./build-layout.cjs");
|
|
8
|
+
|
|
9
|
+
const appDir = path.join(__dirname, "..");
|
|
10
|
+
const ebCli = require.resolve("electron-builder/cli.js");
|
|
11
|
+
|
|
12
|
+
function relForConfig(p) {
|
|
13
|
+
return path.relative(appDir, p).split(path.sep).join("/");
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const layout = resolveBuildLayout(appDir);
|
|
17
|
+
ensureCleanEbOutput(layout.ebOutputDir);
|
|
18
|
+
|
|
19
|
+
const outArg = `--config.directories.output=${relForConfig(layout.ebOutputDir)}`;
|
|
20
|
+
const env = {
|
|
21
|
+
...process.env,
|
|
22
|
+
BUILD_STAMP: layout.buildStamp,
|
|
23
|
+
RELEASE_BUILD_ID: layout.buildName,
|
|
24
|
+
HSP_EB_OUTPUT: relForConfig(layout.ebOutputDir),
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
console.log(`[win-eb] build=${layout.buildName} stamp=${layout.buildStamp}`);
|
|
28
|
+
console.log(`[win-eb] staging → ${relForConfig(layout.ebOutputDir)} (removed after cleanup)`);
|
|
29
|
+
console.log(`[win-eb] final → releases/builder/${layout.buildName}/<installer>.exe + ${RELEASE_BUILD_DEV_DIRNAME}/`);
|
|
30
|
+
|
|
31
|
+
const r = spawnSync(process.execPath, [ebCli, "--win", "--publish", "never", outArg], {
|
|
32
|
+
cwd: appDir,
|
|
33
|
+
env,
|
|
34
|
+
stdio: "inherit",
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
if (r.status !== 0) {
|
|
38
|
+
process.exit(r.status === null ? 1 : r.status);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const c = spawnSync(process.execPath, [path.join(__dirname, "cleanup.cjs")], {
|
|
42
|
+
cwd: appDir,
|
|
43
|
+
env,
|
|
44
|
+
stdio: "inherit",
|
|
45
|
+
});
|
|
46
|
+
process.exit(c.status === null ? 1 : c.status);
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8" />
|
|
5
|
+
<title>Updater</title>
|
|
6
|
+
<style>
|
|
7
|
+
#log {
|
|
8
|
+
scrollbar-width: thin;
|
|
9
|
+
scrollbar-color: #3d3d3d #141414;
|
|
10
|
+
}
|
|
11
|
+
#log::-webkit-scrollbar {
|
|
12
|
+
width: 8px;
|
|
13
|
+
height: 8px;
|
|
14
|
+
}
|
|
15
|
+
#log::-webkit-scrollbar-track {
|
|
16
|
+
background: #141414;
|
|
17
|
+
border-radius: 4px;
|
|
18
|
+
}
|
|
19
|
+
#log::-webkit-scrollbar-thumb {
|
|
20
|
+
background: #3d3d3d;
|
|
21
|
+
border-radius: 4px;
|
|
22
|
+
border: 1px solid #1f1f1f;
|
|
23
|
+
}
|
|
24
|
+
#log::-webkit-scrollbar-thumb:hover {
|
|
25
|
+
background: #505050;
|
|
26
|
+
}
|
|
27
|
+
#log::-webkit-scrollbar-corner {
|
|
28
|
+
background: #0d0d0d;
|
|
29
|
+
}
|
|
30
|
+
#install:disabled {
|
|
31
|
+
opacity: 0.45;
|
|
32
|
+
cursor: not-allowed;
|
|
33
|
+
}
|
|
34
|
+
</style>
|
|
35
|
+
</head>
|
|
36
|
+
<body
|
|
37
|
+
style="
|
|
38
|
+
font-family: Segoe UI, Arial, sans-serif;
|
|
39
|
+
box-sizing: border-box;
|
|
40
|
+
padding: 12px 14px 10px;
|
|
41
|
+
background: #111;
|
|
42
|
+
color: #eee;
|
|
43
|
+
margin: 0;
|
|
44
|
+
"
|
|
45
|
+
>
|
|
46
|
+
<div id="cv" style="font-size: 12px; color: #aaa; margin-bottom: 6px"></div>
|
|
47
|
+
<div id="t" style="font-size: 14px; margin-bottom: 8px; line-height: 1.35">Checking for updates...</div>
|
|
48
|
+
<div id="progressWrap" style="display: none; margin-bottom: 8px">
|
|
49
|
+
<div style="height: 14px; background: #333; border-radius: 7px; overflow: hidden">
|
|
50
|
+
<div
|
|
51
|
+
id="b"
|
|
52
|
+
style="height: 100%; width: 0%; min-width: 0; background: #2ea043; transition: width 0.12s ease-out"
|
|
53
|
+
></div>
|
|
54
|
+
</div>
|
|
55
|
+
</div>
|
|
56
|
+
<div id="logWrap" style="margin-bottom: 8px">
|
|
57
|
+
<div style="font-size: 10px; color: #888; margin-bottom: 4px">Activity log</div>
|
|
58
|
+
<pre
|
|
59
|
+
id="log"
|
|
60
|
+
style="
|
|
61
|
+
margin: 0;
|
|
62
|
+
max-height: 90px;
|
|
63
|
+
overflow-y: auto;
|
|
64
|
+
overflow-x: auto;
|
|
65
|
+
background: #0d0d0d;
|
|
66
|
+
border: 1px solid #333;
|
|
67
|
+
border-radius: 4px;
|
|
68
|
+
padding: 6px 8px;
|
|
69
|
+
font: 11px/1.35 Consolas, 'Cascadia Mono', monospace;
|
|
70
|
+
color: #c9d1d9;
|
|
71
|
+
white-space: pre-wrap;
|
|
72
|
+
word-break: break-all;
|
|
73
|
+
"
|
|
74
|
+
></pre>
|
|
75
|
+
</div>
|
|
76
|
+
<div id="actionsWrap" style="display: none; flex-direction: row; justify-content: flex-end">
|
|
77
|
+
<button id="install" disabled style="padding: 5px 10px">Update with reload</button>
|
|
78
|
+
</div>
|
|
79
|
+
<script>
|
|
80
|
+
(function () {
|
|
81
|
+
try {
|
|
82
|
+
const { ipcRenderer } = require("electron");
|
|
83
|
+
function applyUpdaterUi(data) {
|
|
84
|
+
const t = document.getElementById("t");
|
|
85
|
+
const progressWrap = document.getElementById("progressWrap");
|
|
86
|
+
const actionsWrap = document.getElementById("actionsWrap");
|
|
87
|
+
const b = document.getElementById("b");
|
|
88
|
+
const i = document.getElementById("install");
|
|
89
|
+
if (t) t.textContent = data.text;
|
|
90
|
+
if (progressWrap) progressWrap.style.display = data.showProgress ? "block" : "none";
|
|
91
|
+
if (actionsWrap) actionsWrap.style.display = data.showActions ? "flex" : "none";
|
|
92
|
+
if (b) {
|
|
93
|
+
const w = Math.max(0, Math.min(100, Math.round(Number(data.percent) || 0)));
|
|
94
|
+
b.style.width = w + "%";
|
|
95
|
+
b.style.minWidth = w > 0 ? "2px" : "0";
|
|
96
|
+
}
|
|
97
|
+
if (i) i.disabled = !data.installEnabled;
|
|
98
|
+
}
|
|
99
|
+
function appendLogLine(line) {
|
|
100
|
+
const el = document.getElementById("log");
|
|
101
|
+
if (!el) return;
|
|
102
|
+
el.textContent += (el.textContent ? "\n" : "") + line;
|
|
103
|
+
const parts = el.textContent.split("\n");
|
|
104
|
+
if (parts.length > 220) el.textContent = parts.slice(-220).join("\n");
|
|
105
|
+
el.scrollTop = el.scrollHeight;
|
|
106
|
+
}
|
|
107
|
+
ipcRenderer.on("updater-ui", (_e, data) => applyUpdaterUi(data));
|
|
108
|
+
ipcRenderer.on("updater-log-init", (_e, lines) => {
|
|
109
|
+
const el = document.getElementById("log");
|
|
110
|
+
if (!el) return;
|
|
111
|
+
el.textContent = Array.isArray(lines) ? lines.join("\n") : "";
|
|
112
|
+
el.scrollTop = el.scrollHeight;
|
|
113
|
+
});
|
|
114
|
+
ipcRenderer.on("updater-log", (_e, line) =>
|
|
115
|
+
appendLogLine(typeof line === "string" ? line : String(line)),
|
|
116
|
+
);
|
|
117
|
+
const installBtn = document.getElementById("install");
|
|
118
|
+
if (installBtn) {
|
|
119
|
+
installBtn.addEventListener("click", async () => {
|
|
120
|
+
appendLogLine("[ui] Update with reload clicked — sending to main process…");
|
|
121
|
+
try {
|
|
122
|
+
const r = await ipcRenderer.invoke("updater-install-now");
|
|
123
|
+
if (r && r.ok === false) {
|
|
124
|
+
appendLogLine("[ui] Main refused: " + (r.err || "unknown"));
|
|
125
|
+
}
|
|
126
|
+
} catch (e) {
|
|
127
|
+
const msg = e && e.message ? e.message : String(e);
|
|
128
|
+
appendLogLine("[ui] IPC invoke failed: " + msg + " (trying legacy send)");
|
|
129
|
+
ipcRenderer.send("updater-install-click");
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
} else {
|
|
133
|
+
ipcRenderer.send("updater-renderer-error", "install button #install missing");
|
|
134
|
+
}
|
|
135
|
+
} catch (err) {
|
|
136
|
+
try {
|
|
137
|
+
require("electron").ipcRenderer.send("updater-renderer-error", String(err && err.message ? err.message : err));
|
|
138
|
+
} catch (_) {}
|
|
139
|
+
}
|
|
140
|
+
})();
|
|
141
|
+
</script>
|
|
142
|
+
</body>
|
|
143
|
+
</html>
|