@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,210 @@
1
+ const RESTART_LOG_TABLE = 'application_restart_log';
2
+
3
+ const DEFAULT_RESTART_CAUSE = 'user';
4
+ const DEFAULT_EVENT_TYPE = 'restart';
5
+
6
+ function normalizeRestartCause(value) {
7
+ const normalized = String(value || '').trim().toLowerCase();
8
+ if (normalized === 'user' || normalized === 'reboot' || normalized === 'unexpected') {
9
+ return normalized;
10
+ }
11
+ return DEFAULT_RESTART_CAUSE;
12
+ }
13
+
14
+ function normalizeEventType(value) {
15
+ const normalized = String(value || '').trim().toLowerCase();
16
+ if (normalized === 'start' || normalized === 'stop' || normalized === 'restart') {
17
+ return normalized;
18
+ }
19
+ return DEFAULT_EVENT_TYPE;
20
+ }
21
+
22
+ function normalizeRecord(row) {
23
+ if (!row) {
24
+ return null;
25
+ }
26
+
27
+ let details = {};
28
+ try {
29
+ details = JSON.parse(String(row.details_json || '{}'));
30
+ } catch (_error) {
31
+ details = {};
32
+ }
33
+
34
+ return {
35
+ id: Number(row.id),
36
+ requestedAt: Number(row.requested_at),
37
+ detectedAt: Number(row.detected_at || 0) || null,
38
+ eventType: normalizeEventType(row.event_type),
39
+ cause: normalizeRestartCause(row.restart_cause),
40
+ source: String(row.source || ''),
41
+ status: String(row.status || ''),
42
+ details,
43
+ };
44
+ }
45
+
46
+ export function createRestartLogDao({getDatabase}) {
47
+ let bootstrapped = false;
48
+
49
+ function bootstrapRestartLogTable() {
50
+ if (bootstrapped) {
51
+ return;
52
+ }
53
+
54
+ const db = getDatabase();
55
+ db.exec(`
56
+ CREATE TABLE IF NOT EXISTS ${RESTART_LOG_TABLE} (
57
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
58
+ requested_at INTEGER NOT NULL,
59
+ detected_at INTEGER,
60
+ event_type TEXT NOT NULL DEFAULT '${DEFAULT_EVENT_TYPE}',
61
+ restart_cause TEXT NOT NULL DEFAULT '${DEFAULT_RESTART_CAUSE}',
62
+ source TEXT NOT NULL DEFAULT '',
63
+ status TEXT NOT NULL DEFAULT 'requested',
64
+ details_json TEXT NOT NULL DEFAULT '{}'
65
+ )
66
+ `);
67
+
68
+ const columns = db.prepare(`PRAGMA table_info(${RESTART_LOG_TABLE})`).all();
69
+ const hasRestartCause = columns.some((column) => String(column?.name || '') === 'restart_cause');
70
+ const hasEventType = columns.some((column) => String(column?.name || '') === 'event_type');
71
+ if (!hasEventType) {
72
+ db.exec(`
73
+ ALTER TABLE ${RESTART_LOG_TABLE}
74
+ ADD COLUMN event_type TEXT NOT NULL DEFAULT '${DEFAULT_EVENT_TYPE}'
75
+ `);
76
+ }
77
+
78
+ if (!hasRestartCause) {
79
+ db.exec(`
80
+ ALTER TABLE ${RESTART_LOG_TABLE}
81
+ ADD COLUMN restart_cause TEXT NOT NULL DEFAULT '${DEFAULT_RESTART_CAUSE}'
82
+ `);
83
+ }
84
+
85
+ bootstrapped = true;
86
+ }
87
+
88
+ function createRestartRequest({
89
+ requestedAt = Date.now(),
90
+ detectedAt = null,
91
+ cause = DEFAULT_RESTART_CAUSE,
92
+ source = 'unknown',
93
+ status = 'requested',
94
+ details = {},
95
+ } = {}) {
96
+ bootstrapRestartLogTable();
97
+ const db = getDatabase();
98
+ const result = db.prepare(`
99
+ INSERT INTO ${RESTART_LOG_TABLE} (requested_at, detected_at, event_type, restart_cause, source, status, details_json)
100
+ VALUES (?, ?, ?, ?, ?, ?, ?)
101
+ `).run(
102
+ Math.floor(Number(requestedAt) || Date.now()),
103
+ detectedAt == null ? null : Math.floor(Number(detectedAt) || Date.now()),
104
+ DEFAULT_EVENT_TYPE,
105
+ normalizeRestartCause(cause),
106
+ String(source || 'unknown'),
107
+ String(status || 'requested'),
108
+ JSON.stringify(details || {}),
109
+ );
110
+ return Number(result.lastInsertRowid);
111
+ }
112
+
113
+ function createLifecycleEvent({
114
+ eventAt = Date.now(),
115
+ eventType,
116
+ cause = DEFAULT_RESTART_CAUSE,
117
+ source = 'unknown',
118
+ status = 'completed',
119
+ details = {},
120
+ } = {}) {
121
+ bootstrapRestartLogTable();
122
+ const db = getDatabase();
123
+ const timestamp = Math.floor(Number(eventAt) || Date.now());
124
+ const result = db.prepare(`
125
+ INSERT INTO ${RESTART_LOG_TABLE} (requested_at, detected_at, event_type, restart_cause, source, status, details_json)
126
+ VALUES (?, ?, ?, ?, ?, ?, ?)
127
+ `).run(
128
+ timestamp,
129
+ timestamp,
130
+ normalizeEventType(eventType),
131
+ normalizeRestartCause(cause),
132
+ String(source || 'unknown'),
133
+ String(status || 'completed'),
134
+ JSON.stringify(details || {}),
135
+ );
136
+ return Number(result.lastInsertRowid);
137
+ }
138
+
139
+ function updateRestartStatus(id, {
140
+ detectedAt,
141
+ status,
142
+ details,
143
+ } = {}) {
144
+ bootstrapRestartLogTable();
145
+ if (!Number.isFinite(Number(id))) {
146
+ return false;
147
+ }
148
+
149
+ const db = getDatabase();
150
+ const current = normalizeRecord(db.prepare(`
151
+ SELECT *
152
+ FROM ${RESTART_LOG_TABLE}
153
+ WHERE id = ?
154
+ LIMIT 1
155
+ `).get(Number(id)));
156
+
157
+ if (!current) {
158
+ return false;
159
+ }
160
+
161
+ const nextDetails = details === undefined
162
+ ? current.details
163
+ : {...current.details, ...(details || {})};
164
+
165
+ db.prepare(`
166
+ UPDATE ${RESTART_LOG_TABLE}
167
+ SET detected_at = ?,
168
+ status = ?,
169
+ details_json = ?
170
+ WHERE id = ?
171
+ `).run(
172
+ detectedAt == null ? current.detectedAt : Math.floor(Number(detectedAt)),
173
+ String(status || current.status),
174
+ JSON.stringify(nextDetails || {}),
175
+ Number(id),
176
+ );
177
+
178
+ return true;
179
+ }
180
+
181
+ function listRecentRestartRecords(limit = 20) {
182
+ bootstrapRestartLogTable();
183
+ const db = getDatabase();
184
+ return db.prepare(`
185
+ SELECT *
186
+ FROM ${RESTART_LOG_TABLE}
187
+ ORDER BY requested_at DESC, id DESC
188
+ LIMIT ?
189
+ `).all(Math.max(1, Number(limit) || 20)).map(normalizeRecord);
190
+ }
191
+
192
+ function getLastLifecycleEvent() {
193
+ bootstrapRestartLogTable();
194
+ const db = getDatabase();
195
+ return normalizeRecord(db.prepare(`
196
+ SELECT *
197
+ FROM ${RESTART_LOG_TABLE}
198
+ ORDER BY requested_at DESC, id DESC
199
+ LIMIT 1
200
+ `).get());
201
+ }
202
+
203
+ return {
204
+ createRestartRequest,
205
+ createLifecycleEvent,
206
+ updateRestartStatus,
207
+ getLastLifecycleEvent,
208
+ listRecentRestartRecords,
209
+ };
210
+ }
@@ -0,0 +1,19 @@
1
+ import {createConfigDao} from './createConfigDao.js';
2
+ import {createEntryTokenDao} from './createEntryTokenDao.js';
3
+ import {createDatabaseProvider} from './createDatabaseProvider.js';
4
+ import {createRestartLogDao} from './createRestartLogDao.js';
5
+
6
+ export function createPersistence(services) {
7
+ const getDatabase = createDatabaseProvider({
8
+ getDatabasePath: () => services.getSystemConfig().persistence.dbPath,
9
+ });
10
+
11
+ return {
12
+ getDatabase,
13
+ configDao: createConfigDao({
14
+ getDatabase,
15
+ }),
16
+ entryTokenDao: createEntryTokenDao({getDatabase}),
17
+ restartLogDao: createRestartLogDao({getDatabase}),
18
+ };
19
+ }
@@ -0,0 +1,54 @@
1
+ function normalizeServiceName(service) {
2
+ const value = String(service || '').trim();
3
+ return value || 'unknown';
4
+ }
5
+
6
+ function cloneEvent(event) {
7
+ return {
8
+ sequence: event.sequence,
9
+ service: event.service,
10
+ type: event.type,
11
+ at: event.at,
12
+ payload: event.payload,
13
+ snapshot: event.snapshot,
14
+ };
15
+ }
16
+
17
+ export function createEventStore(services) {
18
+ const latestByService = new Map();
19
+ const history = [];
20
+ const bus = services.getPubSub();
21
+
22
+ bus.subscribe((event) => {
23
+ if (event.snapshot) {
24
+ latestByService.set(event.service, cloneEvent(event));
25
+ }
26
+
27
+ history.push(cloneEvent(event));
28
+ if (history.length > 500) {
29
+ history.splice(0, history.length - 500);
30
+ }
31
+ });
32
+
33
+ function getLatestSnapshot() {
34
+ return Array.from(latestByService.values(), (event) => cloneEvent(event));
35
+ }
36
+
37
+ function getHistory(limit = 100) {
38
+ const safeLimit = Math.max(0, Math.floor(Number(limit) || 0));
39
+ const source = safeLimit > 0 ? history.slice(-safeLimit) : history;
40
+ return source.map((event) => cloneEvent(event));
41
+ }
42
+
43
+ function getLatestEvent(service) {
44
+ const event = latestByService.get(normalizeServiceName(service));
45
+ return event ? cloneEvent(event) : null;
46
+ }
47
+
48
+ return {
49
+ getLatestSnapshot,
50
+ getHistory,
51
+ getLatestEvent,
52
+ getServiceState: getLatestEvent,
53
+ };
54
+ }
@@ -0,0 +1,89 @@
1
+ import {createExactMatchPredicate} from '../../../utils/predicates.js';
2
+
3
+ function normalizeServiceName(service) {
4
+ const value = String(service || '').trim();
5
+ return value || 'unknown';
6
+ }
7
+
8
+ function cloneEvent(event) {
9
+ return {
10
+ sequence: event.sequence,
11
+ service: event.service,
12
+ type: event.type,
13
+ at: event.at,
14
+ payload: event.payload,
15
+ snapshot: event.snapshot,
16
+ };
17
+ }
18
+
19
+ function createListenerEntry(listener, predicateOrObject) {
20
+ if (typeof listener !== 'function') {
21
+ return null;
22
+ }
23
+
24
+ let predicate = null;
25
+ if (typeof predicateOrObject === 'function') {
26
+ predicate = predicateOrObject;
27
+ } else if (predicateOrObject && typeof predicateOrObject === 'object') {
28
+ const normalizedFilters = {...predicateOrObject};
29
+ if (normalizedFilters.service !== undefined) {
30
+ normalizedFilters.service = normalizeServiceName(normalizedFilters.service);
31
+ }
32
+ predicate = Object.keys(normalizedFilters).length
33
+ ? createExactMatchPredicate(normalizedFilters)
34
+ : null;
35
+ }
36
+
37
+ return {
38
+ notify(event) {
39
+ if (predicate && !predicate(event)) {
40
+ return;
41
+ }
42
+
43
+ listener(event);
44
+ },
45
+ };
46
+ }
47
+
48
+ export function createPubSub() {
49
+ const listeners = new Set();
50
+ let nextSequence = 1;
51
+
52
+ function publish(service, payload, options = {}) {
53
+ const event = {
54
+ sequence: nextSequence++,
55
+ service: normalizeServiceName(service),
56
+ type: String(options.type || 'event').trim() || 'event',
57
+ at: new Date().toISOString(),
58
+ payload,
59
+ snapshot: options.snapshot !== false,
60
+ };
61
+
62
+ for (const listener of listeners) {
63
+ try {
64
+ listener.notify(cloneEvent(event));
65
+ } catch (_error) {
66
+ // Best effort: keep the bus alive even if one subscriber fails.
67
+ }
68
+ }
69
+
70
+ return cloneEvent(event);
71
+ }
72
+
73
+ function subscribe(listener, predicateOrObject) {
74
+ const entry = createListenerEntry(listener, predicateOrObject);
75
+ if (!entry) {
76
+ return () => {};
77
+ }
78
+
79
+ listeners.add(entry);
80
+ return () => {
81
+ listeners.delete(entry);
82
+ };
83
+ }
84
+
85
+ return {
86
+ publish,
87
+ subscribe,
88
+ };
89
+ }
@@ -0,0 +1,29 @@
1
+ import {PUBSUB_EVENT_STATE_CHANGED} from './serviceEventConstants.js';
2
+
3
+ export function createServiceEvents(services) {
4
+ function publish(service, payload, options = {}) {
5
+ return services.getPubSub().publish(service, payload, options);
6
+ }
7
+
8
+ function publishState(service, state, options = {}) {
9
+ return publish(service, state, {
10
+ type: String(options.type || PUBSUB_EVENT_STATE_CHANGED).trim() || PUBSUB_EVENT_STATE_CHANGED,
11
+ ...options,
12
+ snapshot: options.snapshot ?? true,
13
+ });
14
+ }
15
+
16
+ function publishEvent(service, type, payload, options = {}) {
17
+ return publish(service, payload, {
18
+ ...options,
19
+ type: String(type || 'event').trim() || 'event',
20
+ snapshot: options.snapshot ?? false,
21
+ });
22
+ }
23
+
24
+ return {
25
+ publish,
26
+ publishState,
27
+ publishEvent,
28
+ };
29
+ }
@@ -0,0 +1,39 @@
1
+ export const PUBSUB_SERVICE_SOCKET = 'socket';
2
+ export const PUBSUB_SERVICE_SESSION = 'session';
3
+ export const PUBSUB_SERVICE_TASK_MANAGER = 'task-manager';
4
+ export const PUBSUB_SERVICE_TOKEN_MANAGER = 'token-manager';
5
+ export const PUBSUB_SERVICE_UPDATE_MANAGER = 'update-manager';
6
+ export const PUBSUB_SERVICE_CONFIG = 'config';
7
+ export const PUBSUB_SERVICE_ADMIN_FORCE_UPDATE_CHECK = 'admin:force-update-check';
8
+ export const PUBSUB_SERVICE_ADMIN_INSTALL_UPDATE = 'admin:install-update';
9
+ export const PUBSUB_SERVICE_ADMIN_OPEN_QR_BROWSER = 'admin:open-qr-browser';
10
+ export const PUBSUB_SERVICE_ADMIN_OPEN_SERVER_INFO_BROWSER = 'admin:open-server-info-browser';
11
+ export const PUBSUB_SERVICE_ADMIN_RESTART_SERVICE = 'admin:restart-service';
12
+ export const PUBSUB_SERVICE_ADMIN_TOGGLE_QR_OVERLAY = 'admin:toggle-qr-overlay';
13
+ export const PUBSUB_SERVICE_ADMIN_ROTATE_ENTRY_TOKEN = 'admin:rotate-entry-token';
14
+
15
+ export const PUBSUB_EVENT_STATE_CHANGED = 'state.changed';
16
+
17
+ export const PUBSUB_EVENT_SOCKET_CLIENT_CONNECTED = 'client.connected';
18
+ export const PUBSUB_EVENT_SOCKET_CLIENT_DISCONNECTED = 'client.disconnected';
19
+ export const PUBSUB_EVENT_SESSION_CREATED = 'session.created';
20
+
21
+ export const PUBSUB_EVENT_UPDATE_CHECK = 'update.check';
22
+ export const PUBSUB_EVENT_UPDATE_AVAILABLE = 'update.available';
23
+ export const PUBSUB_EVENT_UPDATE_ERROR = 'update.error';
24
+ export const PUBSUB_EVENT_TOKEN_CHANGED = 'token.changed';
25
+ export const PUBSUB_EVENT_CONFIG_UPDATED = 'config.updated';
26
+ export const PUBSUB_EVENT_CONFIG_DELETED = 'config.deleted';
27
+
28
+ export const PUBSUB_EVENT_ADMIN_COMPLETED = 'completed';
29
+ export const PUBSUB_EVENT_ADMIN_STARTED = 'started';
30
+ export const PUBSUB_EVENT_ADMIN_FAILED = 'failed';
31
+ export const PUBSUB_EVENT_ADMIN_REJECTED_NO_COMMAND = 'rejected.no-command';
32
+ export const PUBSUB_EVENT_ADMIN_REJECTED_DISABLED = 'rejected.disabled';
33
+ export const PUBSUB_EVENT_ADMIN_UNCHANGED = 'unchanged';
34
+ export const PUBSUB_EVENT_ADMIN_ROTATED = 'rotated';
35
+ export const PUBSUB_EVENT_ADMIN_TOGGLED = 'toggled';
36
+ export const PUBSUB_EVENT_ADMIN_CLIENT_OPENED = 'client.opened';
37
+ export const PUBSUB_EVENT_ADMIN_SERVER_OPEN_FAILED = 'server.open.failed';
38
+ export const PUBSUB_EVENT_ADMIN_SERVER_OPENED = 'server.opened';
39
+ export const PUBSUB_EVENT_ADMIN_RESTART_DETECTED = 'restart.detected';
@@ -0,0 +1,25 @@
1
+ import {createBrowser} from "../../remotes/browser/index.js";
2
+ import {createSamsungRemote} from "../../remotes/samsung/createSamsungRemote.js";
3
+ import {createPreviewStreamer} from "../../remotes/preview/createPreviewStreamer.js";
4
+ import {createAdminActions} from "../../remotes/admin/index.js";
5
+ import {createVlc} from "../../remotes/vlc/index.js";
6
+ import {createWindowActions} from "../../remotes/window/index.js";
7
+
8
+ export function createRemotes(services) {
9
+ const osService = services.getOs();
10
+ const browser = createBrowser(osService);
11
+ const samsung = createSamsungRemote(services);
12
+ const preview = createPreviewStreamer(services);
13
+ const adminActions = createAdminActions(services);
14
+ const vlc = createVlc(services);
15
+ const windowActions = createWindowActions(osService);
16
+
17
+ return {
18
+ browser,
19
+ samsung,
20
+ preview,
21
+ adminActions,
22
+ vlc,
23
+ windowActions,
24
+ };
25
+ }
@@ -0,0 +1,12 @@
1
+ import fs from "node:fs";
2
+ import https from "node:https";
3
+
4
+ export function createHttpsServer(app, config) {
5
+ if (!config.https.sslKeyPath || !config.https.sslCertPath) {
6
+ throw new Error('HTTPS=true exige SSL_KEY_PATH et SSL_CERT_PATH.');
7
+ }
8
+
9
+ const key = fs.readFileSync(config.https.sslKeyPath, 'utf8');
10
+ const cert = fs.readFileSync(config.https.sslCertPath, 'utf8');
11
+ return https.createServer({key, cert}, app);
12
+ }
@@ -0,0 +1,66 @@
1
+ import http from 'node:http';
2
+ import express from 'express';
3
+ import {Server} from 'socket.io';
4
+ import {getPublicUrl} from '../../utils/network.js';
5
+ import cookieParser from "cookie-parser";
6
+ import {createHttpsServer} from "./createHttpsServer.js";
7
+ import {createLogger} from '../../application/logger.js';
8
+
9
+ export function createServer(services) {
10
+ const log = createLogger('server:create');
11
+ const {
12
+ getSystemConfig
13
+ } = services;
14
+
15
+ const config = getSystemConfig();
16
+ const serverStartedAt = Date.now();
17
+ const app = express();
18
+ const cookies = cookieParser(config.session.cookieSecret);
19
+
20
+ const server = config.https.enabled
21
+ ? createHttpsServer(app, config)
22
+ : http.createServer(app);
23
+ const sockets = new Set();
24
+
25
+ const io = new Server(server, {});
26
+ log.debug({
27
+ protocol: config.protocol,
28
+ port: config.port,
29
+ httpsEnabled: Boolean(config.https.enabled),
30
+ }, 'Serveur HTTP initialise');
31
+
32
+ server.on('connection', (socket) => {
33
+ sockets.add(socket);
34
+ log.trace({socketCount: sockets.size}, 'Connexion HTTP ouverte');
35
+ socket.on('close', () => {
36
+ sockets.delete(socket);
37
+ log.trace({socketCount: sockets.size}, 'Connexion HTTP fermee');
38
+ });
39
+ });
40
+
41
+ const basePublicUrl = getPublicUrl(
42
+ config.port,
43
+ config.protocol,
44
+ config.serverHost);
45
+
46
+ return {
47
+ server,
48
+ io,
49
+ app,
50
+ basePublicUrl,
51
+ serverStartedAt,
52
+ cookieParser: cookies,
53
+ closeIdleConnections: () => {
54
+ log.debug('Fermeture connexions HTTP inactives');
55
+ server.closeIdleConnections?.();
56
+ },
57
+ destroyConnections: () => {
58
+ log.debug({socketCount: sockets.size}, 'Destruction connexions HTTP restantes');
59
+ for (const socket of sockets) {
60
+ socket.destroy();
61
+ }
62
+ sockets.clear();
63
+ }
64
+ };
65
+ }
66
+
@@ -0,0 +1,96 @@
1
+ import {
2
+ createExactMatchPredicate,
3
+ formatSseMessage
4
+ } from "./utils.js";
5
+
6
+ export function createSseService() {
7
+ const subscriptions = new Map();
8
+ let nextId = 1;
9
+
10
+ function createSubscription({filters} = {}) {
11
+ const id = `sub-${nextId++}`;
12
+ subscriptions.set(id, {
13
+ id,
14
+ predicate: createExactMatchPredicate(filters || {}),
15
+ pendingEvents: [],
16
+ response: null,
17
+ });
18
+ return id;
19
+ }
20
+
21
+ function emit(event) {
22
+ for (const subscription of subscriptions.values()) {
23
+ if (!subscription.predicate(event)) {
24
+ continue;
25
+ }
26
+
27
+ if (subscription.response) {
28
+ subscription.response.write(formatSseMessage(event));
29
+ continue;
30
+ }
31
+
32
+ subscription.pendingEvents.push(event);
33
+ if (subscription.pendingEvents.length > 50) {
34
+ subscription.pendingEvents.shift();
35
+ }
36
+ }
37
+ }
38
+
39
+ function connect(id, req, res) {
40
+ const subscription = subscriptions.get(id);
41
+ if (!subscription) {
42
+ return false;
43
+ }
44
+
45
+ if (subscription.response && subscription.response !== res) {
46
+ subscription.response.end();
47
+ }
48
+
49
+ subscription.response = res;
50
+ res.setHeader('Content-Type', 'text/event-stream; charset=utf-8');
51
+ res.setHeader('Cache-Control', 'no-cache, no-transform');
52
+ res.setHeader('Connection', 'keep-alive');
53
+ res.flushHeaders?.();
54
+ res.write('retry: 3000\n\n');
55
+
56
+ for (const event of subscription.pendingEvents) {
57
+ res.write(formatSseMessage(event));
58
+ }
59
+ subscription.pendingEvents = [];
60
+
61
+ req.on('close', () => {
62
+ if (subscription.response === res) {
63
+ subscription.response = null;
64
+ }
65
+ res.end();
66
+ });
67
+
68
+ return true;
69
+ }
70
+
71
+ function deleteSubscription(id) {
72
+ const subscription = subscriptions.get(id);
73
+ if (!subscription) {
74
+ return false;
75
+ }
76
+
77
+ subscription.response?.end();
78
+ subscriptions.delete(id);
79
+ return true;
80
+ }
81
+
82
+ function closeAll() {
83
+ for (const [id, subscription] of subscriptions.entries()) {
84
+ subscription.response?.end();
85
+ subscriptions.delete(id);
86
+ }
87
+ }
88
+
89
+ return {
90
+ createSubscription,
91
+ connect,
92
+ deleteSubscription,
93
+ emit,
94
+ closeAll,
95
+ };
96
+ }
@@ -0,0 +1,7 @@
1
+ export {createExactMatchPredicate} from '../../../utils/predicates.js';
2
+
3
+ export function formatSseMessage(event = {}) {
4
+ const eventName = String(event.name || event.type || 'message').trim() || 'message';
5
+ const payload = event.payload === undefined ? {} : event.payload;
6
+ return `event: ${eventName}\ndata: ${JSON.stringify(payload)}\n\n`;
7
+ }