@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,64 @@
1
+ import {getStateStoreDefinitions} from './stateDefinitions.js';
2
+
3
+ function cloneValue(value) {
4
+ return value && typeof value === 'object' ? structuredClone(value) : value;
5
+ }
6
+
7
+ export function createStateStoreService() {
8
+ const state = Object.fromEntries(
9
+ getStateStoreDefinitions().map(([key, definition]) => [key, cloneValue(definition.defaultValue)]),
10
+ );
11
+ const listeners = new Set();
12
+
13
+ function notify(key, value, previousValue) {
14
+ const payload = {
15
+ key,
16
+ value: cloneValue(value),
17
+ previousValue: cloneValue(previousValue),
18
+ state: getSnapshot(),
19
+ };
20
+
21
+ for (const listener of listeners) {
22
+ listener(payload);
23
+ }
24
+ }
25
+
26
+ function get(key) {
27
+ return cloneValue(state[key]);
28
+ }
29
+
30
+ function getSnapshot() {
31
+ return Object.fromEntries(
32
+ Object.entries(state).map(([key, value]) => [key, cloneValue(value)]),
33
+ );
34
+ }
35
+
36
+ function set(key, value) {
37
+ const previousValue = state[key];
38
+ if (Object.is(previousValue, value)) {
39
+ return value;
40
+ }
41
+
42
+ state[key] = cloneValue(value);
43
+ notify(key, value, previousValue);
44
+ return value;
45
+ }
46
+
47
+ function subscribe(listener) {
48
+ if (typeof listener !== 'function') {
49
+ return () => {};
50
+ }
51
+
52
+ listeners.add(listener);
53
+ return () => {
54
+ listeners.delete(listener);
55
+ };
56
+ }
57
+
58
+ return {
59
+ get,
60
+ getSnapshot,
61
+ set,
62
+ subscribe,
63
+ };
64
+ }
@@ -0,0 +1,26 @@
1
+ function safeReadStorage(key) {
2
+ try {
3
+ return window.localStorage.getItem(key);
4
+ } catch (_error) {
5
+ return '';
6
+ }
7
+ }
8
+
9
+ function safeWriteStorage(key, value) {
10
+ try {
11
+ window.localStorage.setItem(key, value);
12
+ } catch (_error) {
13
+ // Best effort.
14
+ }
15
+ }
16
+
17
+ export function createStorageBinding(key) {
18
+ return {
19
+ read() {
20
+ return safeReadStorage(key);
21
+ },
22
+ write(value) {
23
+ safeWriteStorage(key, value);
24
+ },
25
+ };
26
+ }
@@ -0,0 +1,74 @@
1
+ import {
2
+ SUPPORTED_HANDEDNESS,
3
+ SUPPORTED_THEMES,
4
+ } from '../../preferences/constants.js';
5
+
6
+ export function normalizeString(value, fallback = '') {
7
+ const normalized = String(value ?? '').trim();
8
+ return normalized || fallback;
9
+ }
10
+
11
+ export function normalizeTheme(value) {
12
+ const normalized = String(value || '').trim().toLowerCase();
13
+ return SUPPORTED_THEMES.has(normalized) ? normalized : 'dark';
14
+ }
15
+
16
+ export function normalizeHandedness(value) {
17
+ const normalized = String(value || '').trim().toLowerCase();
18
+ return SUPPORTED_HANDEDNESS.has(normalized) ? normalized : 'right';
19
+ }
20
+
21
+ export function normalizeRemoteAutoHide(value) {
22
+ if (typeof value === 'boolean') {
23
+ return value;
24
+ }
25
+
26
+ const normalized = String(value || '').trim().toLowerCase();
27
+ if (!normalized) {
28
+ return true;
29
+ }
30
+ return !(normalized === 'false' || normalized === '0' || normalized === 'off' || normalized === 'no');
31
+ }
32
+
33
+ export function normalizeBooleanRecord(value, fallback = {}) {
34
+ if (value && typeof value === 'object' && !Array.isArray(value)) {
35
+ return Object.fromEntries(
36
+ Object.entries(value).map(([key, entryValue]) => [key, Boolean(entryValue)]),
37
+ );
38
+ }
39
+
40
+ if (!value) {
41
+ return fallback;
42
+ }
43
+
44
+ try {
45
+ const parsed = JSON.parse(value);
46
+ if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
47
+ return fallback;
48
+ }
49
+
50
+ return Object.fromEntries(
51
+ Object.entries(parsed).map(([key, entryValue]) => [key, Boolean(entryValue)]),
52
+ );
53
+ } catch (_error) {
54
+ return fallback;
55
+ }
56
+ }
57
+
58
+ export function normalizeRemoteVisibilityState(value) {
59
+ const nextState = normalizeBooleanRecord(value);
60
+ if (Object.keys(nextState).length > 0) {
61
+ return nextState;
62
+ }
63
+
64
+ const normalized = String(value || '').trim().toLowerCase();
65
+ if (normalized === 'false' || normalized === '0' || normalized === 'off') {
66
+ return {
67
+ browser: false,
68
+ samsung: false,
69
+ preview: false,
70
+ };
71
+ }
72
+
73
+ return {};
74
+ }
@@ -0,0 +1,58 @@
1
+ import {
2
+ APP_STATE_BROWSER_VISIBILITY,
3
+ APP_STATE_EFFECTIVE_BROWSER_REMOTE_VISIBLE,
4
+ APP_STATE_EFFECTIVE_KEYBOARD_REMOTE_VISIBLE,
5
+ APP_STATE_EFFECTIVE_PREVIEW_REMOTE_VISIBLE,
6
+ APP_STATE_EFFECTIVE_SAMSUNG_REMOTE_VISIBLE,
7
+ APP_STATE_EFFECTIVE_VLC_REMOTE_VISIBLE,
8
+ APP_STATE_REMOTE_VISIBILITY,
9
+ } from './appStateKeys.js';
10
+
11
+ function getConfigSection(config, section) {
12
+ return config?.[section] || {};
13
+ }
14
+
15
+ function getRecordFlag(record, key, fallback = true) {
16
+ if (record && typeof record === 'object' && Object.hasOwn(record, key)) {
17
+ return Boolean(record[key]);
18
+ }
19
+
20
+ return Boolean(fallback);
21
+ }
22
+
23
+ export function resolveEffectiveStateValue(key, {stateStore, persistStore, clientConfig}) {
24
+ const config = clientConfig.getConfig();
25
+ const remoteVisibility = persistStore.get(APP_STATE_REMOTE_VISIBILITY);
26
+ const browserVisibility = persistStore.get(APP_STATE_BROWSER_VISIBILITY);
27
+
28
+ switch (key) {
29
+ case APP_STATE_EFFECTIVE_BROWSER_REMOTE_VISIBLE:
30
+ return getConfigSection(config, 'browser').enabled !== false
31
+ && getRecordFlag(remoteVisibility, 'browser', true);
32
+
33
+ case APP_STATE_EFFECTIVE_KEYBOARD_REMOTE_VISIBLE:
34
+ return getConfigSection(config, 'keyboard').enabled !== false
35
+ && getRecordFlag(remoteVisibility, 'keyboard', true);
36
+
37
+ case APP_STATE_EFFECTIVE_VLC_REMOTE_VISIBLE:
38
+ return getConfigSection(config, 'vlc').enabled !== false
39
+ && getRecordFlag(remoteVisibility, 'vlc', true);
40
+
41
+ case APP_STATE_EFFECTIVE_SAMSUNG_REMOTE_VISIBLE:
42
+ return getRecordFlag(remoteVisibility, 'samsung', true);
43
+
44
+ case APP_STATE_EFFECTIVE_PREVIEW_REMOTE_VISIBLE:
45
+ return getConfigSection(config, 'preview').enabled !== false
46
+ && getRecordFlag(remoteVisibility, 'preview', true);
47
+
48
+ default:
49
+ if (key.startsWith('effective.browser.') && key.endsWith('.visible')) {
50
+ const browserId = key.slice('effective.browser.'.length, -'.visible'.length);
51
+ const browserConfig = getConfigSection(config, 'browser');
52
+ return browserConfig.enabled !== false
53
+ && browserConfig?.[browserId] !== false
54
+ && getRecordFlag(browserVisibility, browserId, true);
55
+ }
56
+ return undefined;
57
+ }
58
+ }
@@ -0,0 +1,107 @@
1
+ import {
2
+ BROWSER_VISIBILITY_STORAGE_KEY,
3
+ HANDEDNESS_STORAGE_KEY,
4
+ REMOTE_AUTO_HIDE_STORAGE_KEY,
5
+ REMOTE_VISIBILITY_STORAGE_KEY,
6
+ THEME_STORAGE_KEY,
7
+ } from '../../preferences/constants.js';
8
+ import {LOCALE_STORAGE_KEY} from '../../i18n/constants.js';
9
+ import {resolveLocale} from '../../i18n/core.js';
10
+ import {
11
+ APP_STATE_BROWSER_VISIBILITY,
12
+ APP_STATE_HANDEDNESS,
13
+ APP_STATE_KEYBOARD_PREVIEW_ACTIVE,
14
+ APP_STATE_LOCALE,
15
+ APP_STATE_PREVIEW_ACTIVITY_AT,
16
+ APP_STATE_REMOTE_ACCORDION_EXPANDED_PANEL,
17
+ APP_STATE_REMOTE_AUTO_HIDE,
18
+ APP_STATE_REMOTE_VISIBILITY,
19
+ APP_STATE_THEME,
20
+ } from './appStateKeys.js';
21
+ import {
22
+ normalizeBooleanRecord,
23
+ normalizeHandedness,
24
+ normalizeRemoteAutoHide,
25
+ normalizeRemoteVisibilityState,
26
+ normalizeString,
27
+ normalizeTheme,
28
+ } from './normalizers.js';
29
+
30
+ export const APP_STATE_STORE_STATE = 'state';
31
+ export const APP_STATE_STORE_PERSIST = 'persist';
32
+
33
+ export const APP_STATE_DEFINITIONS = {
34
+ [APP_STATE_PREVIEW_ACTIVITY_AT]: {
35
+ store: APP_STATE_STORE_STATE,
36
+ defaultValue: 0,
37
+ normalize: (value) => Number(value) || 0,
38
+ },
39
+ [APP_STATE_KEYBOARD_PREVIEW_ACTIVE]: {
40
+ store: APP_STATE_STORE_STATE,
41
+ defaultValue: false,
42
+ normalize: Boolean,
43
+ },
44
+ [APP_STATE_REMOTE_ACCORDION_EXPANDED_PANEL]: {
45
+ store: APP_STATE_STORE_STATE,
46
+ defaultValue: '',
47
+ normalize: (value) => normalizeString(value),
48
+ },
49
+ [APP_STATE_THEME]: {
50
+ store: APP_STATE_STORE_PERSIST,
51
+ storageKey: THEME_STORAGE_KEY,
52
+ defaultValue: 'dark',
53
+ normalize: normalizeTheme,
54
+ serialize: String,
55
+ },
56
+ [APP_STATE_LOCALE]: {
57
+ store: APP_STATE_STORE_PERSIST,
58
+ storageKey: LOCALE_STORAGE_KEY,
59
+ defaultValue: '',
60
+ normalize: (value) => resolveLocale(
61
+ value || (typeof navigator !== 'undefined' ? navigator.language : ''),
62
+ ),
63
+ serialize: String,
64
+ },
65
+ [APP_STATE_HANDEDNESS]: {
66
+ store: APP_STATE_STORE_PERSIST,
67
+ storageKey: HANDEDNESS_STORAGE_KEY,
68
+ defaultValue: 'right',
69
+ normalize: normalizeHandedness,
70
+ serialize: String,
71
+ },
72
+ [APP_STATE_REMOTE_AUTO_HIDE]: {
73
+ store: APP_STATE_STORE_PERSIST,
74
+ storageKey: REMOTE_AUTO_HIDE_STORAGE_KEY,
75
+ defaultValue: true,
76
+ normalize: normalizeRemoteAutoHide,
77
+ serialize: (value) => value ? 'true' : 'false',
78
+ },
79
+ [APP_STATE_REMOTE_VISIBILITY]: {
80
+ store: APP_STATE_STORE_PERSIST,
81
+ storageKey: REMOTE_VISIBILITY_STORAGE_KEY,
82
+ defaultValue: {},
83
+ normalize: normalizeRemoteVisibilityState,
84
+ serialize: JSON.stringify,
85
+ },
86
+ [APP_STATE_BROWSER_VISIBILITY]: {
87
+ store: APP_STATE_STORE_PERSIST,
88
+ storageKey: BROWSER_VISIBILITY_STORAGE_KEY,
89
+ defaultValue: {},
90
+ normalize: (value) => normalizeBooleanRecord(value),
91
+ serialize: JSON.stringify,
92
+ },
93
+ };
94
+
95
+ export function getAppStateDefinition(key) {
96
+ return APP_STATE_DEFINITIONS[key] || null;
97
+ }
98
+
99
+ export function getPersistStateDefinitions() {
100
+ return Object.entries(APP_STATE_DEFINITIONS)
101
+ .filter(([, definition]) => definition.store === APP_STATE_STORE_PERSIST);
102
+ }
103
+
104
+ export function getStateStoreDefinitions() {
105
+ return Object.entries(APP_STATE_DEFINITIONS)
106
+ .filter(([, definition]) => definition.store === APP_STATE_STORE_STATE);
107
+ }
@@ -0,0 +1,55 @@
1
+ export function createBackendService(services) {
2
+ async function request(path, options = {}) {
3
+ const response = await fetch(path, {
4
+ cache: 'no-store',
5
+ ...options,
6
+ });
7
+
8
+ if (!response.ok) {
9
+ throw new Error(`HTTP ${response.status}`);
10
+ }
11
+
12
+ return response;
13
+ }
14
+
15
+ async function requestJson(path, options = {}) {
16
+ const response = await request(path, options);
17
+ return response.json();
18
+ }
19
+
20
+ return {
21
+ request,
22
+ requestJson,
23
+ async getClientConfig() {
24
+ return requestJson('/api/admin/configs');
25
+ },
26
+ async createConfigSubscription(scope = 'config') {
27
+ return requestJson('/api/admin/subs/configs', {
28
+ method: 'POST',
29
+ headers: {
30
+ 'Content-Type': 'application/json',
31
+ },
32
+ body: JSON.stringify({scope}),
33
+ });
34
+ },
35
+ createEventSource(eventsUrl) {
36
+ return new EventSource(eventsUrl);
37
+ },
38
+ async deleteSubscription(id) {
39
+ const encodedId = encodeURIComponent(String(id || ''));
40
+ return fetch(`/api/admin/subs/${encodedId}`, {
41
+ method: 'DELETE',
42
+ keepalive: true,
43
+ });
44
+ },
45
+ async getAvailableRemotes() {
46
+ return requestJson('/api/admin/remotes');
47
+ },
48
+ async getAvailableBrowsers() {
49
+ return requestJson('/api/admin/remotes/browsers');
50
+ },
51
+ async getSamsungStatus() {
52
+ return requestJson('/api/remotes/samsung/status');
53
+ },
54
+ };
55
+ }
@@ -0,0 +1,45 @@
1
+ import {DEFAULT_CLIENT_CONFIG} from './defaultClientConfig.js';
2
+
3
+ export class ConfigView {
4
+ #config;
5
+
6
+ constructor(config) {
7
+ this.#config = config || {};
8
+ }
9
+
10
+ #getSection(name, fallback) {
11
+ return this.#config?.[name] || fallback;
12
+ }
13
+
14
+ getSection(name, fallback) {
15
+ return this.#getSection(name, fallback);
16
+ }
17
+
18
+ getInputConfig() {
19
+ return this.#getSection('input', DEFAULT_CLIENT_CONFIG.input);
20
+ }
21
+
22
+ getSamsungConfig() {
23
+ return this.#getSection('samsungTv', {});
24
+ }
25
+
26
+ getPreviewConfig() {
27
+ return this.#getSection('preview', DEFAULT_CLIENT_CONFIG.preview);
28
+ }
29
+
30
+ getVlcConfig() {
31
+ return this.#getSection('vlc', DEFAULT_CLIENT_CONFIG.vlc);
32
+ }
33
+
34
+ getBrowserConfig() {
35
+ return this.#getSection('browser', DEFAULT_CLIENT_CONFIG.browser);
36
+ }
37
+
38
+ getKeyboardConfig() {
39
+ return this.#getSection('keyboard', DEFAULT_CLIENT_CONFIG.keyboard);
40
+ }
41
+
42
+ getSystemConfig() {
43
+ return this.#getSection('system', DEFAULT_CLIENT_CONFIG.system);
44
+ }
45
+ }
@@ -0,0 +1,122 @@
1
+ import {setNestedValue} from '../../../utils/object.utils.js';
2
+ import {DEFAULT_CLIENT_CONFIG} from './defaultClientConfig.js';
3
+
4
+ function getConfigObjectFromEntries(entries) {
5
+ const config = {};
6
+
7
+ for (const entry of entries || []) {
8
+ if (!entry?.id) {
9
+ continue;
10
+ }
11
+
12
+ setNestedValue(config, entry.id, entry.value);
13
+ }
14
+
15
+ return config;
16
+ }
17
+
18
+ export function createClientConfigService(services) {
19
+ let configState = structuredClone(DEFAULT_CLIENT_CONFIG);
20
+ let subscriptionId = '';
21
+ let configStream = null;
22
+ let unloadBound = false;
23
+ const listeners = new Set();
24
+
25
+ function notifyListeners() {
26
+ for (const listener of listeners) {
27
+ listener(configState);
28
+ }
29
+ }
30
+
31
+ function applyConfigEntries(entries = []) {
32
+ for (const entry of entries) {
33
+ if (!entry?.path) {
34
+ continue;
35
+ }
36
+
37
+ setNestedValue(configState, entry.path, entry.value);
38
+ }
39
+
40
+ notifyListeners();
41
+ }
42
+
43
+ async function loadClientConfig() {
44
+ const payload = await services.getBackend().getClientConfig();
45
+ const loadedConfig = payload?.config || getConfigObjectFromEntries(payload?.configs);
46
+ configState = {
47
+ ...structuredClone(DEFAULT_CLIENT_CONFIG),
48
+ ...loadedConfig,
49
+ system: {
50
+ ...DEFAULT_CLIENT_CONFIG.system,
51
+ ...payload?.systemConfig,
52
+ },
53
+ };
54
+ notifyListeners();
55
+ }
56
+
57
+ async function subscribeToConfigEvents() {
58
+ if (typeof window.EventSource !== 'function') {
59
+ return;
60
+ }
61
+
62
+ const payload = await services.getBackend().createConfigSubscription('config');
63
+ subscriptionId = String(payload.id || '');
64
+ if (!subscriptionId || !payload.eventsUrl) {
65
+ return;
66
+ }
67
+
68
+ configStream?.close();
69
+ configStream = services.getBackend().createEventSource(payload.eventsUrl);
70
+ configStream.addEventListener('config.changed', (event) => {
71
+ try {
72
+ const data = JSON.parse(event.data || '{}');
73
+ applyConfigEntries(data.entries);
74
+ } catch (_error) {
75
+ }
76
+ });
77
+ }
78
+
79
+ function unsubscribeFromConfigEvents() {
80
+ if (!subscriptionId) {
81
+ return;
82
+ }
83
+
84
+ services.getBackend().deleteSubscription(subscriptionId).catch(() => {
85
+ });
86
+ configStream?.close();
87
+ configStream = null;
88
+ subscriptionId = '';
89
+ }
90
+
91
+ return {
92
+ async init() {
93
+ try {
94
+ await loadClientConfig();
95
+ } catch (_error) {
96
+ configState = structuredClone(DEFAULT_CLIENT_CONFIG);
97
+ }
98
+
99
+ await subscribeToConfigEvents();
100
+ if (!unloadBound) {
101
+ window.addEventListener('beforeunload', unsubscribeFromConfigEvents, {once: true});
102
+ unloadBound = true;
103
+ }
104
+
105
+ return this;
106
+ },
107
+ getConfig() {
108
+ return configState;
109
+ },
110
+ onChange(listener) {
111
+ if (typeof listener !== 'function') {
112
+ return () => {
113
+ };
114
+ }
115
+
116
+ listeners.add(listener);
117
+ return () => {
118
+ listeners.delete(listener);
119
+ };
120
+ },
121
+ };
122
+ }
@@ -0,0 +1,22 @@
1
+ export const DEFAULT_CLIENT_CONFIG = {
2
+ system: {
3
+ adminActionsEnabled: true,
4
+ },
5
+ input: {
6
+ touchDragHoldMs: 420,
7
+ touchDragStillDistancePx: 8,
8
+ },
9
+ browser: {
10
+ enabled: true,
11
+ },
12
+ keyboard: {
13
+ enabled: true,
14
+ },
15
+ vlc: {
16
+ enabled: false,
17
+ },
18
+ preview: {
19
+ enabled: true,
20
+ hideDelayMs: 10000,
21
+ },
22
+ };
@@ -0,0 +1,48 @@
1
+ import {createLazy} from '../../utils/createLazy.js';
2
+ import {ConfigView} from './config/ConfigView.js';
3
+ import {APP_STATE_LOCALE} from './app-state/createAppStateService.js';
4
+
5
+ export async function initializeCoreServices(services) {
6
+ await services.getClientConfig().init();
7
+ services.getAppState().init();
8
+ await services.getI18n().init(services.getAppState().get(APP_STATE_LOCALE));
9
+ services.getAppState().subscribeProperty(APP_STATE_LOCALE, ({value}) => {
10
+ services.getI18n().setLocale(value).catch(() => {});
11
+ });
12
+ return services;
13
+ }
14
+
15
+ export function initializeRealtimeServices(services) {
16
+ services.getTransport().connect();
17
+ services.getNotifications().bindTransport();
18
+ return services;
19
+ }
20
+
21
+ export function createServicesContainer({
22
+ createI18nService,
23
+ createClientConfigService,
24
+ createTransportService,
25
+ createBackendService,
26
+ createRemotesService,
27
+ createPubSubService,
28
+ createNotificationService,
29
+ createStateStoreService,
30
+ createPersistStoreService,
31
+ createAppStateService,
32
+ }) {
33
+ const container = {
34
+ getI18n: createLazy(() => createI18nService(container)),
35
+ getClientConfig: createLazy(() => createClientConfigService(container)),
36
+ getConfigView: () => new ConfigView(container.getClientConfig().getConfig()),
37
+ getTransport: createLazy(() => createTransportService(container)),
38
+ getBackend: createLazy(() => createBackendService(container)),
39
+ getRemotes: createLazy(() => createRemotesService(container)),
40
+ getPubSub: createLazy(() => createPubSubService(container)),
41
+ getNotifications: createLazy(() => createNotificationService(container)),
42
+ getStateStore: createLazy(() => createStateStoreService(container)),
43
+ getPersistStore: createLazy(() => createPersistStoreService(container)),
44
+ getAppState: createLazy(() => createAppStateService(container)),
45
+ };
46
+
47
+ return container;
48
+ }
@@ -0,0 +1,26 @@
1
+ import {createServicesContainer} from './createServicesContainer.js';
2
+ import {createI18nService} from './i18n/createI18nService.js';
3
+ import {createClientConfigService} from './config/createClientConfigService.js';
4
+ import {createSocketIoTransportService} from './transport/createSocketIoTransportService.js';
5
+ import {createBackendService} from './backend/createBackendService.js';
6
+ import {createRemotesService} from './remotes/createRemotesService.js';
7
+ import {createPubSubService} from './pubsub/createPubSubService.js';
8
+ import {createNotificationService} from './notifications/createNotificationService.js';
9
+ import {createAppStateService} from './app-state/createAppStateService.js';
10
+ import {createStateStoreService} from './app-state/createStateStoreService.js';
11
+ import {createPersistStoreService} from './app-state/createPersistStoreService.js';
12
+
13
+ export function createServicesRegistry() {
14
+ return createServicesContainer({
15
+ createI18nService,
16
+ createClientConfigService,
17
+ createTransportService: createSocketIoTransportService,
18
+ createBackendService,
19
+ createRemotesService,
20
+ createPubSubService,
21
+ createNotificationService,
22
+ createStateStoreService,
23
+ createPersistStoreService,
24
+ createAppStateService,
25
+ });
26
+ }