@velor/remote-mouse 6.4.8

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.
Files changed (316) hide show
  1. package/.artifacts/screenshots/remote-mobile-config.png +0 -0
  2. package/.artifacts/screenshots/remote-mobile-home.png +0 -0
  3. package/.artifacts/screenshots/remote-mobile-preferences.png +0 -0
  4. package/.artifacts/screenshots/remote-mobile-server-info.png +0 -0
  5. package/.artifacts/screenshots/remote-mobile-vlc.png +0 -0
  6. package/.env.example +93 -0
  7. package/README.md +370 -0
  8. package/bin/remote-mouse.js +19 -0
  9. package/client/core/dom.js +148 -0
  10. package/client/core/init-socket-io.js +117 -0
  11. package/client/core/socket-emit.js +6 -0
  12. package/client/core/window-events.js +23 -0
  13. package/client/i18n/apply-page-translations.js +18 -0
  14. package/client/i18n/constants.js +3 -0
  15. package/client/i18n/core.js +40 -0
  16. package/client/i18n/locale-registry.js +77 -0
  17. package/client/i18n/locales/de.js +227 -0
  18. package/client/i18n/locales/en.js +389 -0
  19. package/client/i18n/locales/es.js +228 -0
  20. package/client/i18n/locales/fr.js +389 -0
  21. package/client/i18n/locales/it.js +227 -0
  22. package/client/i18n/locales/ja.js +227 -0
  23. package/client/i18n/locales/pt.js +227 -0
  24. package/client/i18n/locales/ru.js +240 -0
  25. package/client/i18n/locales/zh.js +227 -0
  26. package/client/preferences/constants.js +15 -0
  27. package/client/preferences/effects.js +24 -0
  28. package/client/preferences/load.js +19 -0
  29. package/client/preferences/render.js +26 -0
  30. package/client/preferences/rows.js +78 -0
  31. package/client/preferences/state.js +29 -0
  32. package/client/preview/create-preview-frame-receiver.js +13 -0
  33. package/client/preview/draw.js +77 -0
  34. package/client/preview/parse-preview-frame.js +39 -0
  35. package/client/preview/preview-stream.js +152 -0
  36. package/client/services/app-state/appStateKeys.js +30 -0
  37. package/client/services/app-state/createAppStateService.js +216 -0
  38. package/client/services/app-state/createPersistStoreService.js +122 -0
  39. package/client/services/app-state/createStateStoreService.js +64 -0
  40. package/client/services/app-state/localStorageBinding.js +26 -0
  41. package/client/services/app-state/normalizers.js +74 -0
  42. package/client/services/app-state/resolveEffectiveStateValue.js +58 -0
  43. package/client/services/app-state/stateDefinitions.js +107 -0
  44. package/client/services/backend/createBackendService.js +55 -0
  45. package/client/services/config/ConfigView.js +45 -0
  46. package/client/services/config/createClientConfigService.js +122 -0
  47. package/client/services/config/defaultClientConfig.js +22 -0
  48. package/client/services/createServicesContainer.js +48 -0
  49. package/client/services/createServicesRegistry.js +26 -0
  50. package/client/services/i18n/createI18nService.js +86 -0
  51. package/client/services/notifications/createNotificationService.js +56 -0
  52. package/client/services/pubsub/createPubSubService.js +20 -0
  53. package/client/services/remotes/createRemotesService.js +20 -0
  54. package/client/services/transport/createSocketIoTransportService.js +50 -0
  55. package/client/touch/bindTouchPassthrough.js +94 -0
  56. package/client/touch/createTouchList.js +18 -0
  57. package/client/touch/dispatchSyntheticTouch.js +20 -0
  58. package/client/touch/gesture-zone.js +28 -0
  59. package/client/touch/throttle.js +46 -0
  60. package/client/touch/touch-handlers.js +193 -0
  61. package/client/touch/touchpad.js +231 -0
  62. package/client/ui/config/page.js +840 -0
  63. package/client/ui/main/applyRemoteVisibilityState.js +60 -0
  64. package/client/ui/main/bind-client-notifications.js +3 -0
  65. package/client/ui/main/bindings/bindAccordion.js +121 -0
  66. package/client/ui/main/bindings/bindActionButtons.js +13 -0
  67. package/client/ui/main/bindings/bindAdminDrawer.js +137 -0
  68. package/client/ui/main/bindings/bindAdminRemoteButtons.js +77 -0
  69. package/client/ui/main/bindings/bindAdminVersion.js +27 -0
  70. package/client/ui/main/bindings/bindBrowserRemoteButtons.js +119 -0
  71. package/client/ui/main/bindings/bindRemoteAccordion.js +23 -0
  72. package/client/ui/main/bindings/bindSamsungRemoteButtons.js +320 -0
  73. package/client/ui/main/bindings/bindSystemRemoteButtons.js +41 -0
  74. package/client/ui/main/bindings/bindVlcRemoteButtons.js +64 -0
  75. package/client/ui/main/canvas-ui.js +33 -0
  76. package/client/ui/main/connection-overlay.js +57 -0
  77. package/client/ui/main/init-ui.js +54 -0
  78. package/client/ui/main/keyboard-panel.js +271 -0
  79. package/client/ui/main/mouse-buttons.js +94 -0
  80. package/client/ui/main/page.js +21 -0
  81. package/client/ui/notifications/show-toast.js +48 -0
  82. package/client/ui/preferences/bindPreferenceSwitchers.js +49 -0
  83. package/client/ui/preferences/page.js +61 -0
  84. package/client/ui/preferences/switchers.js +200 -0
  85. package/index.js +9 -0
  86. package/package.json +41 -0
  87. package/public/admin-config.css +447 -0
  88. package/public/admin-config.html +63 -0
  89. package/public/apple-touch-icon.png +0 -0
  90. package/public/brave-icon.svg +13 -0
  91. package/public/favicon.svg +30 -0
  92. package/public/icon-192.png +0 -0
  93. package/public/icon-512.png +0 -0
  94. package/public/index.html +246 -0
  95. package/public/manifest.webmanifest +45 -0
  96. package/public/preferences.html +55 -0
  97. package/public/server-info.html +574 -0
  98. package/public/styles.css +1042 -0
  99. package/public/sw.js +103 -0
  100. package/scripts/codex-commit.sh +112 -0
  101. package/scripts/generate-mobile-screenshots.mjs +244 -0
  102. package/scripts/install-linux.sh +633 -0
  103. package/scripts/install-windows.ps1 +369 -0
  104. package/server/application/createApplicationLifecycle.js +15 -0
  105. package/server/application/logger.js +216 -0
  106. package/server/application/shutdown.js +81 -0
  107. package/server/application/start.js +95 -0
  108. package/server/application/state.js +19 -0
  109. package/server/connection/api/admin-actions.router.js +65 -0
  110. package/server/connection/api/admin-configs.router.js +165 -0
  111. package/server/connection/api/admin-remotes.router.js +61 -0
  112. package/server/connection/api/admin-subs.router.js +49 -0
  113. package/server/connection/api/client.router.js +15 -0
  114. package/server/connection/api/configs.js +96 -0
  115. package/server/connection/api/qr-page.handler.js +17 -0
  116. package/server/connection/api/remotes.router.js +30 -0
  117. package/server/connection/api/server-info.router.js +149 -0
  118. package/server/connection/api/session.middleware.js +93 -0
  119. package/server/connection/api/unauthorized-response.js +73 -0
  120. package/server/connection/socket/createConnectionRegistrar.js +23 -0
  121. package/server/connection/socket/createSocketSessionAuthMiddleware.js +49 -0
  122. package/server/connection/socket/socket-action-responder.js +12 -0
  123. package/server/connection/socket/socket.timestamp-middleware.js +51 -0
  124. package/server/index.js +12 -0
  125. package/server/init/bootstrapApi.js +87 -0
  126. package/server/init/bootstrapSocket.js +79 -0
  127. package/server/init/createAdminApiRouter.js +22 -0
  128. package/server/init/createAdminUiRouter.js +21 -0
  129. package/server/init/createSocketActionRegistrars.js +52 -0
  130. package/server/init/observers/startConfigObserver.js +51 -0
  131. package/server/init/observers/startDisplaySizeObserver.js +55 -0
  132. package/server/init/observers/startNotificationObserver.js +49 -0
  133. package/server/init/observers/startQrOverlayHoverObserver.js +89 -0
  134. package/server/init/observers/startQrOverlayRefreshObserver.js +53 -0
  135. package/server/os/darwin/app.js +45 -0
  136. package/server/os/darwin/applescript.js +51 -0
  137. package/server/os/darwin/cliSocket.js +53 -0
  138. package/server/os/darwin/url.js +9 -0
  139. package/server/os/darwin/window.js +10 -0
  140. package/server/os/linux/app.js +120 -0
  141. package/server/os/linux/cliSocket.js +53 -0
  142. package/server/os/linux/process.js +69 -0
  143. package/server/os/linux/screen.js +58 -0
  144. package/server/os/linux/systemd.js +139 -0
  145. package/server/os/linux/url.js +17 -0
  146. package/server/os/linux/windows.js +144 -0
  147. package/server/os/win32/app.js +66 -0
  148. package/server/os/win32/cliSocket.js +15 -0
  149. package/server/os/win32/powershell.js +70 -0
  150. package/server/os/win32/process.js +20 -0
  151. package/server/os/win32/service.js +95 -0
  152. package/server/os/win32/url.js +9 -0
  153. package/server/os/win32/window.js +10 -0
  154. package/server/remotes/admin/createAdminEventGuardMiddleware.js +29 -0
  155. package/server/remotes/admin/createForceUpdateCheckAction.js +39 -0
  156. package/server/remotes/admin/createInstallUpdateAction.js +64 -0
  157. package/server/remotes/admin/createOpenQrBrowserAction.js +63 -0
  158. package/server/remotes/admin/createOpenServerInfoBrowserAction.js +58 -0
  159. package/server/remotes/admin/createRestartServiceAction.js +20 -0
  160. package/server/remotes/admin/createRotateEntryTokenAction.js +43 -0
  161. package/server/remotes/admin/createToggleQrOverlayAction.js +38 -0
  162. package/server/remotes/admin/index.js +32 -0
  163. package/server/remotes/admin/notifyIfRestarted.js +102 -0
  164. package/server/remotes/admin/registrar.js +94 -0
  165. package/server/remotes/browser/actions/createFocusOrLaunchBrowserAction.js +22 -0
  166. package/server/remotes/browser/actions/openUrlOnHost.js +3 -0
  167. package/server/remotes/browser/browserCatalog.js +70 -0
  168. package/server/remotes/browser/index.js +15 -0
  169. package/server/remotes/browser/listBrowsersOnHost.js +23 -0
  170. package/server/remotes/browser/registrar.js +29 -0
  171. package/server/remotes/browser/spec.js +18 -0
  172. package/server/remotes/browser/state.js +5 -0
  173. package/server/remotes/input/registrar.js +39 -0
  174. package/server/remotes/preview/bgraToRgbaBuffer.js +20 -0
  175. package/server/remotes/preview/captureAroundCursor.js +19 -0
  176. package/server/remotes/preview/createPreviewStreamer.js +85 -0
  177. package/server/remotes/preview/registrar.js +34 -0
  178. package/server/remotes/samsung/createSamsungCommandService.js +203 -0
  179. package/server/remotes/samsung/createSamsungRemote.js +26 -0
  180. package/server/remotes/samsung/createSamsungRemoteGetter.js +46 -0
  181. package/server/remotes/samsung/createSamsungTvGetter.js +102 -0
  182. package/server/remotes/samsung/device-config.js +122 -0
  183. package/server/remotes/samsung/registrar.js +59 -0
  184. package/server/remotes/samsung/utils.js +56 -0
  185. package/server/remotes/vlc/index.js +39 -0
  186. package/server/remotes/vlc/registrar.js +94 -0
  187. package/server/remotes/vlc/spec.js +15 -0
  188. package/server/remotes/vlc/state.js +5 -0
  189. package/server/remotes/window/index.js +6 -0
  190. package/server/remotes/window/registrar.js +28 -0
  191. package/server/services/application/createApplicationDaemonService.js +144 -0
  192. package/server/services/application/getDaemonServiceAdapter.js +56 -0
  193. package/server/services/application/utils.js +29 -0
  194. package/server/services/config/bootstrapConfig.js +38 -0
  195. package/server/services/config/configPaths.js +42 -0
  196. package/server/services/config/configSchema.js +297 -0
  197. package/server/services/config/configService.js +89 -0
  198. package/server/services/config/defaultConfig.js +137 -0
  199. package/server/services/config/envConfig.js +49 -0
  200. package/server/services/config/index.js +9 -0
  201. package/server/services/config/logConfig.js +54 -0
  202. package/server/services/config/system-config.js +44 -0
  203. package/server/services/createServicesContainer.js +94 -0
  204. package/server/services/createServicesRegistry.js +48 -0
  205. package/server/services/input/createInputController.js +17 -0
  206. package/server/services/input/createKeyboardController.js +146 -0
  207. package/server/services/input/createMouseController.js +182 -0
  208. package/server/services/notifier/createClientNotifier.js +23 -0
  209. package/server/services/notifier/createHostNotifier.js +41 -0
  210. package/server/services/notifier/createNotifier.js +13 -0
  211. package/server/services/notifier/createNotifierComposite.js +122 -0
  212. package/server/services/notifier/handleOpenQrBrowserEvent.js +40 -0
  213. package/server/services/notifier/handleOpenServerInfoBrowserEvent.js +40 -0
  214. package/server/services/notifier/handleRestartServiceEvent.js +37 -0
  215. package/server/services/notifier/handleRotateEntryTokenEvent.js +42 -0
  216. package/server/services/notifier/handleSessionEvent.js +24 -0
  217. package/server/services/notifier/handleToggleQrOverlayEvent.js +21 -0
  218. package/server/services/notifier/host-notifier/createLinuxHostNotifier.js +23 -0
  219. package/server/services/notifier/host-notifier/createNodeNotifierHostNotifier.js +24 -0
  220. package/server/services/notifier/host-notifier/index.js +11 -0
  221. package/server/services/notifier/mapper/handleForceUpdateCheckEvent.js +24 -0
  222. package/server/services/notifier/mapper/handleInstallUpdateEvent.js +53 -0
  223. package/server/services/notifier/mapper/handleSocketEvent.js +40 -0
  224. package/server/services/notifier/mapper/handleUpdateManagerEvent.js +24 -0
  225. package/server/services/notifier/mapper/notify.js +7 -0
  226. package/server/services/os/index.js +23 -0
  227. package/server/services/os/platforms/createFallbackAdapter.js +31 -0
  228. package/server/services/os/platforms/darwin/app.js +6 -0
  229. package/server/services/os/platforms/darwin/index.js +21 -0
  230. package/server/services/os/platforms/darwin/scripts.js +4 -0
  231. package/server/services/os/platforms/darwin/url.js +1 -0
  232. package/server/services/os/platforms/darwin/window.js +4 -0
  233. package/server/services/os/platforms/linux/app.js +6 -0
  234. package/server/services/os/platforms/linux/index.js +33 -0
  235. package/server/services/os/platforms/linux/url.js +1 -0
  236. package/server/services/os/platforms/linux/windows.js +11 -0
  237. package/server/services/os/platforms/win32/app.js +6 -0
  238. package/server/services/os/platforms/win32/index.js +21 -0
  239. package/server/services/os/platforms/win32/overlay.js +6 -0
  240. package/server/services/os/platforms/win32/powershell.js +4 -0
  241. package/server/services/os/platforms/win32/url.js +1 -0
  242. package/server/services/os/platforms/win32/window.js +4 -0
  243. package/server/services/os/shared.js +2 -0
  244. package/server/services/overlay/createNoopOverlay.js +13 -0
  245. package/server/services/overlay/createQrOverlay.js +27 -0
  246. package/server/services/overlay/createQrOverlayWin32.js +158 -0
  247. package/server/services/overlay/createQrOverlayYad.js +178 -0
  248. package/server/services/overlay/renderQrPage.js +82 -0
  249. package/server/services/persistence/createConfigDao.js +106 -0
  250. package/server/services/persistence/createDatabaseProvider.js +23 -0
  251. package/server/services/persistence/createEntryTokenDao.js +140 -0
  252. package/server/services/persistence/createRestartLogDao.js +210 -0
  253. package/server/services/persistence/index.js +19 -0
  254. package/server/services/pubsub/createEventStore.js +54 -0
  255. package/server/services/pubsub/createPubSub.js +89 -0
  256. package/server/services/pubsub/createServiceEvents.js +29 -0
  257. package/server/services/pubsub/serviceEventConstants.js +39 -0
  258. package/server/services/remotes/createRemotes.js +25 -0
  259. package/server/services/server/createHttpsServer.js +12 -0
  260. package/server/services/server/createServer.js +66 -0
  261. package/server/services/sse/createSseService.js +96 -0
  262. package/server/services/sse/utils.js +7 -0
  263. package/server/services/system/createSystemService.js +170 -0
  264. package/server/services/system/getNetworkInfo.js +18 -0
  265. package/server/services/system/getScreenInfo.js +32 -0
  266. package/server/services/system/listNetworkInterfaces.js +27 -0
  267. package/server/services/task-manager/createTaskManager.js +68 -0
  268. package/server/services/task-runner/createTaskRunner.js +114 -0
  269. package/server/services/token-manager/createTokenManager.js +244 -0
  270. package/server/services/token-manager/token-format.js +7 -0
  271. package/server/services/token-manager/token-store-utils.js +8 -0
  272. package/server/services/update-manager/CommandUpdateSource.js +70 -0
  273. package/server/services/update-manager/NpmUpdateSource.js +34 -0
  274. package/server/services/update-manager/buildNpmGlobalUpdateCommand.js +15 -0
  275. package/server/services/update-manager/chooseUpdateCheckSource.js +20 -0
  276. package/server/services/update-manager/chooseUpdateInstallSource.js +5 -0
  277. package/server/services/update-manager/createUpdateManager.js +109 -0
  278. package/server/services/update-manager/resolveInstallUpdateCommand.js +42 -0
  279. package/server/term/cli/executeLocalServiceCommand.js +42 -0
  280. package/server/term/cli/getCliSocketPath.js +5 -0
  281. package/server/term/cli/parseCliArgs.js +110 -0
  282. package/server/term/cli/printCliResult.js +18 -0
  283. package/server/term/cli/runCliCmd.js +50 -0
  284. package/server/term/cli/sendCliCommand.js +76 -0
  285. package/server/term/cliSocket.js +29 -0
  286. package/server/term/srv/commands/configCommand.js +84 -0
  287. package/server/term/srv/commands/helpCommand.js +6 -0
  288. package/server/term/srv/commands/infoCommand.js +7 -0
  289. package/server/term/srv/commands/openQrCommand.js +7 -0
  290. package/server/term/srv/commands/samsungDetectCommand.js +52 -0
  291. package/server/term/srv/commands/serviceCommand.js +25 -0
  292. package/server/term/srv/commands/systemConfigCommand.js +7 -0
  293. package/server/term/srv/commands/tasksCommand.js +24 -0
  294. package/server/term/srv/commands/tokensCommand.js +15 -0
  295. package/server/term/srv/executeCliCommand.js +44 -0
  296. package/server/term/srv/executeCliRequest.js +38 -0
  297. package/server/term/srv/startCliServer.js +140 -0
  298. package/server/utils/createRandomToken.js +11 -0
  299. package/server/utils/env.js +155 -0
  300. package/server/utils/git.js +13 -0
  301. package/server/utils/http.js +7 -0
  302. package/server/utils/network.js +45 -0
  303. package/server/utils/paths.js +10 -0
  304. package/server/utils/process.js +57 -0
  305. package/server/utils/robot.js +11 -0
  306. package/server/utils/semver.js +33 -0
  307. package/server/utils/truncateText.js +7 -0
  308. package/utils/createLazy.js +13 -0
  309. package/utils/functional.js +48 -0
  310. package/utils/math.js +26 -0
  311. package/utils/notificationSettings.js +61 -0
  312. package/utils/object.utils.js +79 -0
  313. package/utils/predicates.js +17 -0
  314. package/utils/remoteCommands.js +40 -0
  315. package/utils/sync.js +3 -0
  316. package/velor-remote-mouse-6.4.8.tgz +0 -0
@@ -0,0 +1,369 @@
1
+ [CmdletBinding()]
2
+ param(
3
+ [Alias('y')]
4
+ [switch]$Yes,
5
+
6
+ [string]$PackageName = $env:REMOTE_MOUSE_NPM_PACKAGE,
7
+
8
+ [string]$ConfigDir = $env:REMOTE_MOUSE_CONFIG_DIR,
9
+
10
+ [int]$Port = $(if ($env:REMOTE_MOUSE_PORT) { [int]$env:REMOTE_MOUSE_PORT } else { 3000 }),
11
+
12
+ [switch]$Https,
13
+
14
+ [switch]$NoHttps,
15
+
16
+ [switch]$GenerateCert,
17
+
18
+ [switch]$NoGenerateCert,
19
+
20
+ [string]$SslKeyPath = $env:REMOTE_MOUSE_SSL_KEY_PATH,
21
+
22
+ [string]$SslCertPath = $env:REMOTE_MOUSE_SSL_CERT_PATH,
23
+
24
+ [switch]$InstallService,
25
+
26
+ [switch]$NoService
27
+ )
28
+
29
+ $ErrorActionPreference = 'Stop'
30
+
31
+ function Get-DefaultPackageName {
32
+ $fallback = '@velor/remote-mouse'
33
+ if ([string]::IsNullOrWhiteSpace($PSCommandPath)) {
34
+ return $fallback
35
+ }
36
+
37
+ $scriptDir = Split-Path -Parent $PSCommandPath
38
+ $projectRoot = Split-Path -Parent $scriptDir
39
+ $packageJsonPath = Join-Path $projectRoot 'package.json'
40
+
41
+ if (Test-Path -LiteralPath $packageJsonPath) {
42
+ try {
43
+ $packageJson = Get-Content -LiteralPath $packageJsonPath -Raw | ConvertFrom-Json
44
+ if ($packageJson.name) {
45
+ return [string]$packageJson.name
46
+ }
47
+ } catch {
48
+ return $fallback
49
+ }
50
+ }
51
+
52
+ return $fallback
53
+ }
54
+
55
+ if ([string]::IsNullOrWhiteSpace($PackageName)) {
56
+ $PackageName = Get-DefaultPackageName
57
+ }
58
+
59
+ if ([string]::IsNullOrWhiteSpace($ConfigDir)) {
60
+ $ConfigDir = Join-Path $env:APPDATA 'remote-mouse'
61
+ }
62
+
63
+ function Write-Step {
64
+ param([string]$Message)
65
+ Write-Host ''
66
+ Write-Host $Message
67
+ }
68
+
69
+ function Confirm-Step {
70
+ param([string]$Prompt)
71
+
72
+ if ($Yes) {
73
+ Write-Host "$Prompt [Y/n] y"
74
+ return $true
75
+ }
76
+
77
+ $answer = Read-Host "$Prompt [y/N]"
78
+ return $answer -match '^(y|yes)$'
79
+ }
80
+
81
+ function Read-Value {
82
+ param(
83
+ [string]$Prompt,
84
+ [string]$DefaultValue = ''
85
+ )
86
+
87
+ if ($Yes) {
88
+ Write-Host "$Prompt [$DefaultValue] $DefaultValue"
89
+ return $DefaultValue
90
+ }
91
+
92
+ if ($DefaultValue) {
93
+ $value = Read-Host "$Prompt [$DefaultValue]"
94
+ if ([string]::IsNullOrWhiteSpace($value)) {
95
+ return $DefaultValue
96
+ }
97
+ return $value
98
+ }
99
+
100
+ return Read-Host $Prompt
101
+ }
102
+
103
+ function Test-Command {
104
+ param([string]$Name)
105
+ return [bool](Get-Command $Name -ErrorAction SilentlyContinue)
106
+ }
107
+
108
+ function Install-WithWinget {
109
+ param(
110
+ [string]$PackageId,
111
+ [string]$Label
112
+ )
113
+
114
+ if (-not (Test-Command 'winget')) {
115
+ throw "Missing $Label and winget is not available. Install $Label manually, then rerun this script."
116
+ }
117
+
118
+ if (Confirm-Step "Install $Label with winget?") {
119
+ winget install --id $PackageId --exact --accept-package-agreements --accept-source-agreements
120
+ } else {
121
+ throw "Cannot continue without $Label."
122
+ }
123
+ }
124
+
125
+ function Ensure-Node {
126
+ $missingNode = -not (Test-Command 'node')
127
+ $missingNpm = -not (Test-Command 'npm')
128
+
129
+ if (-not $missingNode -and -not $missingNpm) {
130
+ Write-Step "Node: $(node --version)"
131
+ Write-Step "npm: $(npm --version)"
132
+ return
133
+ }
134
+
135
+ if ($missingNode) {
136
+ Write-Warning 'node was not found in PATH.'
137
+ }
138
+ if ($missingNpm) {
139
+ Write-Warning 'npm was not found in PATH.'
140
+ }
141
+
142
+ Install-WithWinget -PackageId 'OpenJS.NodeJS.LTS' -Label 'Node.js LTS'
143
+
144
+ if (-not (Test-Command 'node') -or -not (Test-Command 'npm')) {
145
+ throw 'Node.js was installed, but node/npm are still not available in this terminal. Open a new terminal and rerun this script.'
146
+ }
147
+ }
148
+
149
+ function Ensure-BuildTools {
150
+ if (Test-Command 'cl') {
151
+ return
152
+ }
153
+
154
+ Write-Warning 'Microsoft C++ build tools were not found in PATH.'
155
+ if (Test-Command 'winget') {
156
+ if (Confirm-Step 'Install Microsoft Visual Studio Build Tools with winget?') {
157
+ winget install --id Microsoft.VisualStudio.2022.BuildTools --exact --accept-package-agreements --accept-source-agreements --override '--quiet --wait --add Microsoft.VisualStudio.Workload.VCTools --includeRecommended'
158
+ return
159
+ }
160
+ }
161
+
162
+ Write-Warning 'Native npm modules may require Microsoft C++ Build Tools. Install them manually if npm install fails.'
163
+ }
164
+
165
+ function Ensure-Python {
166
+ if (Test-Command 'python') {
167
+ return
168
+ }
169
+
170
+ if (Test-Command 'py') {
171
+ return
172
+ }
173
+
174
+ Write-Warning 'Python was not found in PATH.'
175
+ if (Test-Command 'winget') {
176
+ if (Confirm-Step 'Install Python with winget?') {
177
+ winget install --id Python.Python.3.12 --exact --accept-package-agreements --accept-source-agreements
178
+ return
179
+ }
180
+ }
181
+
182
+ Write-Warning 'Native npm modules may require Python. Install it manually if npm install fails.'
183
+ }
184
+
185
+ function Ensure-PowerShell {
186
+ if ($PSVersionTable.PSVersion.Major -lt 5) {
187
+ throw 'PowerShell 5 or newer is required.'
188
+ }
189
+ }
190
+
191
+ function Install-NpmPackage {
192
+ Write-Step "Installing npm package: $PackageName"
193
+ npm install -g $PackageName
194
+
195
+ if (-not (Test-Command 'remote-mouse')) {
196
+ throw 'remote-mouse CLI was not found in PATH after npm installation. Open a new terminal or check npm global bin path with: npm prefix -g'
197
+ }
198
+ }
199
+
200
+ function New-CookieSecret {
201
+ $bytes = New-Object byte[] 32
202
+ $rng = [System.Security.Cryptography.RandomNumberGenerator]::Create()
203
+ try {
204
+ $rng.GetBytes($bytes)
205
+ return -join ($bytes | ForEach-Object { $_.ToString('x2') })
206
+ } finally {
207
+ $rng.Dispose()
208
+ }
209
+ }
210
+
211
+ function Configure-Https {
212
+ $config = @{
213
+ Https = 'false'
214
+ KeyPath = ''
215
+ CertPath = ''
216
+ }
217
+
218
+ if ($NoHttps) {
219
+ return $config
220
+ }
221
+
222
+ if (-not $Https -and -not (Confirm-Step 'Serve Remote Mouse over HTTPS?')) {
223
+ return $config
224
+ }
225
+
226
+ $config.Https = 'true'
227
+ $certDir = Join-Path $ConfigDir 'certs'
228
+
229
+ if ($GenerateCert -or (-not $NoGenerateCert -and (Confirm-Step 'Generate a local self-signed certificate?'))) {
230
+ New-Item -ItemType Directory -Force -Path $certDir | Out-Null
231
+ $cert = New-SelfSignedCertificate `
232
+ -DnsName @('localhost', 'remote-mouse.local') `
233
+ -CertStoreLocation 'Cert:\CurrentUser\My' `
234
+ -KeyAlgorithm RSA `
235
+ -KeyLength 2048 `
236
+ -KeyExportPolicy Exportable `
237
+ -NotAfter (Get-Date).AddYears(1)
238
+
239
+ $pfxPath = Join-Path $certDir 'remote-mouse.pfx'
240
+ $password = ConvertTo-SecureString -String (New-CookieSecret) -AsPlainText -Force
241
+ Export-PfxCertificate -Cert $cert -FilePath $pfxPath -Password $password | Out-Null
242
+
243
+ if (-not (Test-Command 'openssl')) {
244
+ Install-WithWinget -PackageId 'ShiningLight.OpenSSL' -Label 'OpenSSL'
245
+ }
246
+
247
+ $keyPath = Join-Path $certDir 'remote-mouse.key'
248
+ $certPath = Join-Path $certDir 'remote-mouse.crt'
249
+ $plainPassword = (New-Object System.Net.NetworkCredential('', $password)).Password
250
+ openssl pkcs12 -in $pfxPath -nocerts -nodes -out $keyPath -passin "pass:$plainPassword"
251
+ openssl pkcs12 -in $pfxPath -clcerts -nokeys -out $certPath -passin "pass:$plainPassword"
252
+
253
+ $config.KeyPath = $keyPath
254
+ $config.CertPath = $certPath
255
+ return $config
256
+ }
257
+
258
+ $keyPathInput = $SslKeyPath
259
+ if ([string]::IsNullOrWhiteSpace($keyPathInput)) {
260
+ $keyPathInput = Read-Value 'Path to the existing PEM private key'
261
+ }
262
+
263
+ $certPathInput = $SslCertPath
264
+ if ([string]::IsNullOrWhiteSpace($certPathInput)) {
265
+ $certPathInput = Read-Value 'Path to the existing PEM certificate'
266
+ }
267
+
268
+ if (-not (Test-Path -LiteralPath $keyPathInput)) {
269
+ throw "Private key not found: $keyPathInput"
270
+ }
271
+ if (-not (Test-Path -LiteralPath $certPathInput)) {
272
+ throw "Certificate not found: $certPathInput"
273
+ }
274
+
275
+ $config.KeyPath = $keyPathInput
276
+ $config.CertPath = $certPathInput
277
+ return $config
278
+ }
279
+
280
+ function Write-EnvFile {
281
+ param([hashtable]$HttpsConfig)
282
+
283
+ New-Item -ItemType Directory -Force -Path $ConfigDir | Out-Null
284
+ $envFile = Join-Path $ConfigDir '.env'
285
+
286
+ if (Test-Path -LiteralPath $envFile) {
287
+ if (-not (Confirm-Step "Overwrite existing $envFile?")) {
288
+ Write-Step "Keeping existing $envFile."
289
+ return
290
+ }
291
+ }
292
+
293
+ $cookieSecret = New-CookieSecret
294
+ $dbPath = Join-Path $ConfigDir 'remote-mouse.sqlite3'
295
+ $content = @"
296
+ PORT=$Port
297
+ SERVER_HOST=
298
+ CONFIG_DIR=$ConfigDir
299
+ PERSISTENCE_DB_PATH=$dbPath
300
+ ENV_FILE_PATH=$envFile
301
+
302
+ HTTPS=$($HttpsConfig.Https)
303
+ SSL_KEY_PATH=$($HttpsConfig.KeyPath)
304
+ SSL_CERT_PATH=$($HttpsConfig.CertPath)
305
+
306
+ ENTRY_PATH_ENABLED=true
307
+ ENTRY_PATH_FIXED=
308
+ ENTRY_PATH_TOKEN_LENGTH=24
309
+ ENTRY_PATH_ROTATE_INTERVAL_MIN=60
310
+ ENTRY_PATH_GRACE_MIN=120
311
+
312
+ SESSION_COOKIE_NAME=remote_mouse_session
313
+ SESSION_COOKIE_SECRET=$cookieSecret
314
+ SESSION_COOKIE_MAX_AGE_DAYS=7
315
+ SOCKET_EVENT_MAX_AGE_MS=1200
316
+
317
+ LOG_LEVEL=info
318
+ LOG_FORMAT=json
319
+ ADMIN_ACTIONS_ENABLED=true
320
+ SERVICE_NAME=remote-mouse
321
+ SERVICE_RESTART_COMMAND=
322
+ "@
323
+
324
+ Set-Content -LiteralPath $envFile -Value $content -Encoding UTF8
325
+ Write-Step "Wrote $envFile"
326
+ }
327
+
328
+ function Install-Service {
329
+ if ($NoService) {
330
+ return $false
331
+ }
332
+
333
+ if (-not $InstallService -and -not (Confirm-Step 'Install the user service?')) {
334
+ return $false
335
+ }
336
+
337
+ remote-mouse service install
338
+ remote-mouse service restart
339
+ return $true
340
+ }
341
+
342
+ function Main {
343
+ Write-Step 'Remote Mouse Windows installer'
344
+ Write-Step "Package: $PackageName"
345
+ Write-Step "Config directory: $ConfigDir"
346
+
347
+ Ensure-PowerShell
348
+ Ensure-Node
349
+ Ensure-BuildTools
350
+ Ensure-Python
351
+ Install-NpmPackage
352
+ $httpsConfig = Configure-Https
353
+ Write-EnvFile -HttpsConfig $httpsConfig
354
+ $serviceInstalled = Install-Service
355
+
356
+ Write-Step 'Installation complete.'
357
+ if ($serviceInstalled) {
358
+ Write-Host 'Service installed. Use Task Scheduler or remote-mouse service restart to manage it.'
359
+ } else {
360
+ Write-Host 'Start Remote Mouse with: remote-mouse'
361
+ }
362
+
363
+ if ($httpsConfig.Https -eq 'true') {
364
+ Write-Host 'Browsers will warn about the self-signed certificate until it is trusted locally.'
365
+ Write-Host 'Use the browser advanced/details option to continue to the site.'
366
+ }
367
+ }
368
+
369
+ Main
@@ -0,0 +1,15 @@
1
+ import {createApplicationStart} from './start.js';
2
+ import {createApplicationShutdown} from './shutdown.js';
3
+ import {ensureApplicationLifecycleState} from './state.js';
4
+
5
+ export function createApplicationLifecycle(services) {
6
+ const state = ensureApplicationLifecycleState(services);
7
+ const shutdown = createApplicationShutdown(services);
8
+ state.shutdown = shutdown;
9
+ const start = createApplicationStart(services);
10
+
11
+ return {
12
+ start,
13
+ shutdown,
14
+ };
15
+ }
@@ -0,0 +1,216 @@
1
+ import pino from 'pino';
2
+ import {Writable} from 'node:stream';
3
+ import {getSystemConfig} from "../services/config/index.js";
4
+
5
+ const maxStoredLogs = 400;
6
+ const maxStoredMessageLength = 2_000;
7
+ const maxStoredDataLength = 8_000;
8
+ const recentLogs = [];
9
+ const cliLogSubscribers = new Set();
10
+ let rootLogger = null;
11
+ let temporaryLogLevel = '';
12
+
13
+ const levels = {
14
+ trace: 10,
15
+ debug: 20,
16
+ info: 30,
17
+ warn: 40,
18
+ error: 50,
19
+ fatal: 60,
20
+ };
21
+
22
+ const levelNamesByValue = Object.fromEntries(
23
+ Object.entries(levels).map(([name, value]) => [value, name]),
24
+ );
25
+
26
+ function getLevelValue(level) {
27
+ return levels[String(level || '').trim()] ?? levels.info;
28
+ }
29
+
30
+ function safeClone(value) {
31
+ if (value === undefined) {
32
+ return undefined;
33
+ }
34
+ try {
35
+ const serialized = JSON.stringify(value);
36
+ if (typeof serialized !== 'string') {
37
+ return undefined;
38
+ }
39
+ if (serialized.length <= maxStoredDataLength) {
40
+ return JSON.parse(serialized);
41
+ }
42
+
43
+ return {
44
+ truncated: true,
45
+ preview: `${serialized.slice(0, maxStoredDataLength)}...`,
46
+ };
47
+ } catch (_error) {
48
+ const text = String(value);
49
+ return text.length <= maxStoredDataLength
50
+ ? text
51
+ : `${text.slice(0, maxStoredDataLength)}...`;
52
+ }
53
+ }
54
+
55
+ function mapPinoRecord(record) {
56
+ const {time, level, scope, msg, pid: _pid, hostname: _hostname, ...data} = record || {};
57
+ const levelName = levelNamesByValue[level] || String(level || 'info');
58
+ return {
59
+ at: typeof time === 'string' ? time : new Date(time || Date.now()).toISOString(),
60
+ scope: String(scope || 'app'),
61
+ level: levelName,
62
+ message: String(msg || '').slice(0, maxStoredMessageLength),
63
+ data: Object.keys(data).length > 0 ? safeClone(data) : undefined,
64
+ };
65
+ }
66
+
67
+ function publishCliLog(entry) {
68
+ for (const subscriber of cliLogSubscribers) {
69
+ if (getLevelValue(entry.level) < subscriber.minLevel) {
70
+ continue;
71
+ }
72
+
73
+ subscriber.write(entry);
74
+ }
75
+ }
76
+
77
+ function parseLogLines(buffer, chunk, onRecord) {
78
+ const lines = `${buffer}${String(chunk || '')}`.split('\n');
79
+ const nextBuffer = lines.pop() || '';
80
+
81
+ for (const line of lines) {
82
+ const trimmed = line.trim();
83
+ if (!trimmed) {
84
+ continue;
85
+ }
86
+
87
+ try {
88
+ onRecord(JSON.parse(trimmed));
89
+ } catch (_error) {
90
+ // Non-JSON transport output is intentionally ignored by structured transports.
91
+ }
92
+ }
93
+
94
+ return nextBuffer;
95
+ }
96
+
97
+ function createRecentLogTransport() {
98
+ let buffer = '';
99
+
100
+ return new Writable({
101
+ write(chunk, _encoding, callback) {
102
+ buffer = parseLogLines(buffer, chunk, (record) => {
103
+ const entry = mapPinoRecord(record);
104
+ recentLogs.push(entry);
105
+ if (recentLogs.length > maxStoredLogs) {
106
+ recentLogs.splice(0, recentLogs.length - maxStoredLogs);
107
+ }
108
+ });
109
+ callback();
110
+ },
111
+ });
112
+ }
113
+
114
+ function createCliLogTransport() {
115
+ let buffer = '';
116
+
117
+ return new Writable({
118
+ write(chunk, _encoding, callback) {
119
+ buffer = parseLogLines(buffer, chunk, (record) => {
120
+ publishCliLog(mapPinoRecord(record));
121
+ });
122
+ callback();
123
+ },
124
+ });
125
+ }
126
+
127
+ function createDestination(logFormat) {
128
+ if (logFormat === 'flat' || logFormat === 'pretty') {
129
+ return pino.transport({
130
+ target: 'pino-pretty',
131
+ options: {
132
+ colorize: false,
133
+ singleLine: true,
134
+ translateTime: 'SYS:standard',
135
+ ignore: 'pid,hostname',
136
+ },
137
+ });
138
+ }
139
+
140
+ return undefined;
141
+ }
142
+
143
+ function syncLoggerConfig(logger) {
144
+ const nextLevel = temporaryLogLevel || getSystemConfig()?.logging?.level;
145
+ if (nextLevel && logger.level !== nextLevel) {
146
+ logger.level = nextLevel;
147
+ }
148
+ }
149
+
150
+ function buildRootLogger() {
151
+ const systemConfig = getSystemConfig();
152
+ const systemLogLevel = systemConfig?.logging?.level || 'info';
153
+ const systemLogFormat = systemConfig?.logging?.format || 'json';
154
+ const systemDestination = createDestination(systemLogFormat) || process.stdout;
155
+ const logger = pino({
156
+ level: systemLogLevel,
157
+ timestamp: pino.stdTimeFunctions.isoTime,
158
+ }, pino.multistream([
159
+ {level: systemLogLevel, stream: systemDestination},
160
+ {level: 'trace', stream: createRecentLogTransport()},
161
+ {level: 'trace', stream: createCliLogTransport()},
162
+ ]));
163
+
164
+ return logger;
165
+ }
166
+
167
+ export function bootstrapLogger() {
168
+ if (!rootLogger) {
169
+ rootLogger = buildRootLogger();
170
+ } else {
171
+ syncLoggerConfig(rootLogger);
172
+ }
173
+ return rootLogger;
174
+ }
175
+
176
+ export function createLogger(scope) {
177
+ const logger = bootstrapLogger();
178
+ syncLoggerConfig(logger);
179
+ return logger.child({ scope });
180
+ }
181
+
182
+ export function getRecentLogs(limit = 200) {
183
+ const safeLimit = Math.max(1, Math.min(1000, Math.round(Number(limit) || 200)));
184
+ return recentLogs.slice(-safeLimit);
185
+ }
186
+
187
+ export async function withTemporaryLoggerLevel(level, callback) {
188
+ const logger = bootstrapLogger();
189
+ const previousTemporaryLogLevel = temporaryLogLevel;
190
+ const previousLevel = logger.level;
191
+ temporaryLogLevel = String(level || '').trim();
192
+ if (temporaryLogLevel) {
193
+ logger.level = temporaryLogLevel;
194
+ }
195
+
196
+ try {
197
+ return await callback();
198
+ } finally {
199
+ temporaryLogLevel = previousTemporaryLogLevel;
200
+ logger.level = previousTemporaryLogLevel || previousLevel;
201
+ }
202
+ }
203
+
204
+ export async function withCliLogStream(level, onLog, callback) {
205
+ const subscriber = {
206
+ minLevel: getLevelValue(level),
207
+ write: typeof onLog === 'function' ? onLog : () => {},
208
+ };
209
+ cliLogSubscribers.add(subscriber);
210
+
211
+ try {
212
+ return await withTemporaryLoggerLevel(level, callback);
213
+ } finally {
214
+ cliLogSubscribers.delete(subscriber);
215
+ }
216
+ }
@@ -0,0 +1,81 @@
1
+ import {ensureApplicationLifecycleState} from './state.js';
2
+ import {createLogger} from './logger.js';
3
+
4
+ export function createApplicationShutdown(services) {
5
+ const log = createLogger('server');
6
+
7
+ async function runShutdownStep(label, action) {
8
+ try {
9
+ await action();
10
+ } catch (error) {
11
+ log.error({err: error}, label);
12
+ }
13
+ }
14
+
15
+ return async function shutdown(signal) {
16
+ const state = ensureApplicationLifecycleState(services);
17
+ const serverBundle = services.getServer();
18
+ const httpServer = serverBundle.server;
19
+ const io = serverBundle.io;
20
+ const taskManager = services.getTaskManager();
21
+ const qrOverlay = services.getQrOverlay();
22
+ const sseService = services.getSseService();
23
+
24
+ if (state.shuttingDown) {
25
+ return;
26
+ }
27
+
28
+ state.shuttingDown = true;
29
+ log.info({signal}, 'Arret du serveur');
30
+ services.getPersistence().restartLogDao?.createLifecycleEvent({
31
+ eventAt: Date.now(),
32
+ eventType: 'stop',
33
+ cause: 'user',
34
+ source: signal ? `signal:${signal}` : 'shutdown',
35
+ status: 'completed',
36
+ details: {
37
+ signal: signal || null,
38
+ graceful: true,
39
+ processUptimeSec: Math.floor(process.uptime()),
40
+ },
41
+ });
42
+
43
+ await Promise.allSettled([
44
+ runShutdownStep('Erreur a l arret du task manager', () => taskManager.stop()),
45
+ runShutdownStep('Erreur a l arret de l observateur de configuration', () => state.stopConfigObserver()),
46
+ runShutdownStep('Erreur a l arret de l observateur de notifications', () => state.stopNotificationObserver()),
47
+ runShutdownStep('Erreur a l arret de l observateur de resolution ecran', () => state.stopDisplaySizeObserver()),
48
+ runShutdownStep('Erreur a l arret de l observateur du QR overlay', () => state.stopQrOverlayRefreshObserver()),
49
+ runShutdownStep('Erreur a l arret de l observateur du survol QR overlay', () => state.stopQrOverlayHoverObserver()),
50
+ runShutdownStep('Erreur a la fermeture du socket CLI', () => state.cliServer?.close()),
51
+ runShutdownStep('Erreur a la fermeture du QR overlay', () => qrOverlay.close()),
52
+ runShutdownStep('Erreur a la fermeture des connexions SSE', () => sseService?.closeAll?.()),
53
+ runShutdownStep('Erreur a la fermeture de Socket.IO', () => new Promise((resolve) => {
54
+ io?.close?.(() => resolve());
55
+ })),
56
+ ]);
57
+
58
+ try {
59
+ serverBundle.closeIdleConnections?.();
60
+ } catch (error) {
61
+ log.error({err: error}, 'Erreur a la fermeture des connexions HTTP inactives');
62
+ }
63
+
64
+ await new Promise((resolve) => {
65
+ const forceShutdownTimer = setTimeout(() => {
66
+ try {
67
+ serverBundle.destroyConnections?.();
68
+ } catch (error) {
69
+ log.error({err: error}, 'Erreur a la destruction forcee des connexions HTTP');
70
+ }
71
+ }, 1_500);
72
+
73
+ httpServer.close(() => {
74
+ clearTimeout(forceShutdownTimer);
75
+ resolve();
76
+ });
77
+ });
78
+
79
+ process.exit(0);
80
+ };
81
+ }