prismcast 1.9.0 → 1.10.0

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 (360) hide show
  1. package/dist/app.d.ts +1 -1
  2. package/dist/app.js +27 -9
  3. package/dist/app.js.map +1 -1
  4. package/dist/browser/cdp.js +7 -7
  5. package/dist/browser/cdp.js.map +1 -1
  6. package/dist/browser/channelSelection.d.ts +41 -11
  7. package/dist/browser/channelSelection.js +75 -24
  8. package/dist/browser/channelSelection.js.map +1 -1
  9. package/dist/browser/display.d.ts +1 -1
  10. package/dist/browser/index.d.ts +8 -8
  11. package/dist/browser/index.js +42 -43
  12. package/dist/browser/index.js.map +1 -1
  13. package/dist/browser/login.d.ts +2 -2
  14. package/dist/browser/login.js +1 -1
  15. package/dist/browser/manifestInterceptor.d.ts +77 -0
  16. package/dist/browser/manifestInterceptor.js +323 -0
  17. package/dist/browser/manifestInterceptor.js.map +1 -0
  18. package/dist/browser/precaching.js +4 -4
  19. package/dist/browser/tuning/comcastPolymer.d.ts +1 -1
  20. package/dist/browser/tuning/cox.d.ts +1 -1
  21. package/dist/browser/tuning/directv.d.ts +1 -1
  22. package/dist/browser/tuning/directv.js +61 -62
  23. package/dist/browser/tuning/directv.js.map +1 -1
  24. package/dist/browser/tuning/fox.d.ts +1 -1
  25. package/dist/browser/tuning/fox.js +171 -14
  26. package/dist/browser/tuning/fox.js.map +1 -1
  27. package/dist/browser/tuning/hbo.d.ts +1 -1
  28. package/dist/browser/tuning/hbo.js +6 -6
  29. package/dist/browser/tuning/hbo.js.map +1 -1
  30. package/dist/browser/tuning/hulu.d.ts +1 -1
  31. package/dist/browser/tuning/hulu.js +117 -110
  32. package/dist/browser/tuning/hulu.js.map +1 -1
  33. package/dist/browser/tuning/shared.d.ts +3 -3
  34. package/dist/browser/tuning/shared.js +5 -5
  35. package/dist/browser/tuning/sling.d.ts +1 -1
  36. package/dist/browser/tuning/sling.js +28 -28
  37. package/dist/browser/tuning/sling.js.map +1 -1
  38. package/dist/browser/tuning/spectrum.d.ts +1 -1
  39. package/dist/browser/tuning/spectrum.js +21 -22
  40. package/dist/browser/tuning/spectrum.js.map +1 -1
  41. package/dist/browser/tuning/thumbnailRow.d.ts +1 -1
  42. package/dist/browser/tuning/thumbnailRow.js +1 -1
  43. package/dist/browser/tuning/tileClick.d.ts +1 -1
  44. package/dist/browser/tuning/tileClick.js +5 -5
  45. package/dist/browser/tuning/xfinity.d.ts +1 -1
  46. package/dist/browser/tuning/youtubeTv.d.ts +1 -1
  47. package/dist/browser/tuning/youtubeTv.js +17 -18
  48. package/dist/browser/tuning/youtubeTv.js.map +1 -1
  49. package/dist/browser/video.d.ts +20 -6
  50. package/dist/browser/video.js +30 -38
  51. package/dist/browser/video.js.map +1 -1
  52. package/dist/channels/index.d.ts +1 -2
  53. package/dist/channels/index.js +73 -40
  54. package/dist/channels/index.js.map +1 -1
  55. package/dist/config/channelForm.d.ts +58 -0
  56. package/dist/config/channelForm.js +129 -0
  57. package/dist/config/channelForm.js.map +1 -0
  58. package/dist/config/consistencyProbe.d.ts +7 -0
  59. package/dist/config/consistencyProbe.js +143 -0
  60. package/dist/config/consistencyProbe.js.map +1 -0
  61. package/dist/config/health.d.ts +4 -3
  62. package/dist/config/health.js +75 -62
  63. package/dist/config/health.js.map +1 -1
  64. package/dist/config/index.d.ts +1 -1
  65. package/dist/config/index.js +19 -12
  66. package/dist/config/index.js.map +1 -1
  67. package/dist/config/paths.d.ts +9 -3
  68. package/dist/config/paths.js +12 -4
  69. package/dist/config/paths.js.map +1 -1
  70. package/dist/config/persistence.context.d.ts +8 -0
  71. package/dist/config/persistence.context.js +30 -0
  72. package/dist/config/persistence.context.js.map +1 -0
  73. package/dist/config/persistence.d.ts +110 -12
  74. package/dist/config/persistence.js +351 -32
  75. package/dist/config/persistence.js.map +1 -1
  76. package/dist/config/presets.d.ts +14 -4
  77. package/dist/config/presets.js +84 -75
  78. package/dist/config/presets.js.map +1 -1
  79. package/dist/config/profiles.d.ts +2 -2
  80. package/dist/config/profiles.js +7 -9
  81. package/dist/config/profiles.js.map +1 -1
  82. package/dist/config/servicePacks.d.ts +2 -2
  83. package/dist/config/servicePacks.js +28 -28
  84. package/dist/config/servicePacks.js.map +1 -1
  85. package/dist/config/services.d.ts +62 -36
  86. package/dist/config/services.js +150 -136
  87. package/dist/config/services.js.map +1 -1
  88. package/dist/config/sites.d.ts +3 -3
  89. package/dist/config/sites.js +16 -16
  90. package/dist/config/sites.js.map +1 -1
  91. package/dist/config/userChannels.d.ts +500 -41
  92. package/dist/config/userChannels.js +1201 -312
  93. package/dist/config/userChannels.js.map +1 -1
  94. package/dist/config/userConfig.d.ts +103 -10
  95. package/dist/config/userConfig.js +277 -117
  96. package/dist/config/userConfig.js.map +1 -1
  97. package/dist/config/userProfiles.d.ts +4 -2
  98. package/dist/config/userProfiles.js +72 -26
  99. package/dist/config/userProfiles.js.map +1 -1
  100. package/dist/hdhr/channelMap.js +8 -11
  101. package/dist/hdhr/channelMap.js.map +1 -1
  102. package/dist/hdhr/deviceId.js +10 -9
  103. package/dist/hdhr/deviceId.js.map +1 -1
  104. package/dist/hdhr/discover.js +4 -5
  105. package/dist/hdhr/discover.js.map +1 -1
  106. package/dist/hdhr/index.js +6 -10
  107. package/dist/hdhr/index.js.map +1 -1
  108. package/dist/index.js +12 -12
  109. package/dist/index.js.map +1 -1
  110. package/dist/native/codecInference.d.ts +44 -0
  111. package/dist/native/codecInference.js +327 -0
  112. package/dist/native/codecInference.js.map +1 -0
  113. package/dist/native/decrypt.d.ts +1 -1
  114. package/dist/native/index.d.ts +5 -5
  115. package/dist/native/index.js +42 -64
  116. package/dist/native/index.js.map +1 -1
  117. package/dist/native/probe.d.ts +27 -9
  118. package/dist/native/probe.js +158 -67
  119. package/dist/native/probe.js.map +1 -1
  120. package/dist/native/proxy.d.ts +4 -2
  121. package/dist/native/proxy.js +52 -49
  122. package/dist/native/proxy.js.map +1 -1
  123. package/dist/native/tokenExpiry.d.ts +22 -0
  124. package/dist/native/tokenExpiry.js +153 -0
  125. package/dist/native/tokenExpiry.js.map +1 -0
  126. package/dist/routes/auth.js +6 -10
  127. package/dist/routes/auth.js.map +1 -1
  128. package/dist/routes/components.js +2 -2
  129. package/dist/routes/components.js.map +1 -1
  130. package/dist/routes/config/channels/endpoints/browse.d.ts +6 -0
  131. package/dist/routes/config/channels/endpoints/browse.js +195 -0
  132. package/dist/routes/config/channels/endpoints/browse.js.map +1 -0
  133. package/dist/routes/config/channels/endpoints/bulk.d.ts +6 -0
  134. package/dist/routes/config/channels/endpoints/bulk.js +128 -0
  135. package/dist/routes/config/channels/endpoints/bulk.js.map +1 -0
  136. package/dist/routes/config/channels/endpoints/crud.d.ts +6 -0
  137. package/dist/routes/config/channels/endpoints/crud.js +504 -0
  138. package/dist/routes/config/channels/endpoints/crud.js.map +1 -0
  139. package/dist/routes/config/channels/endpoints/importExport.d.ts +6 -0
  140. package/dist/routes/config/channels/endpoints/importExport.js +131 -0
  141. package/dist/routes/config/channels/endpoints/importExport.js.map +1 -0
  142. package/dist/routes/config/channels/endpoints/predefined.d.ts +6 -0
  143. package/dist/routes/config/channels/endpoints/predefined.js +78 -0
  144. package/dist/routes/config/channels/endpoints/predefined.js.map +1 -0
  145. package/dist/routes/config/channels/endpoints/prefs.d.ts +6 -0
  146. package/dist/routes/config/channels/endpoints/prefs.js +58 -0
  147. package/dist/routes/config/channels/endpoints/prefs.js.map +1 -0
  148. package/dist/routes/config/channels/endpoints/service.d.ts +6 -0
  149. package/dist/routes/config/channels/endpoints/service.js +149 -0
  150. package/dist/routes/config/channels/endpoints/service.js.map +1 -0
  151. package/dist/routes/config/channels/endpoints/tags.d.ts +6 -0
  152. package/dist/routes/config/channels/endpoints/tags.js +185 -0
  153. package/dist/routes/config/channels/endpoints/tags.js.map +1 -0
  154. package/dist/routes/config/channels/http/handler.d.ts +10 -0
  155. package/dist/routes/config/channels/http/handler.js +20 -0
  156. package/dist/routes/config/channels/http/handler.js.map +1 -0
  157. package/dist/routes/config/channels/http/playlistHint.d.ts +25 -0
  158. package/dist/routes/config/channels/http/playlistHint.js +40 -0
  159. package/dist/routes/config/channels/http/playlistHint.js.map +1 -0
  160. package/dist/routes/config/channels/http/serviceWarning.d.ts +10 -0
  161. package/dist/routes/config/channels/http/serviceWarning.js +28 -0
  162. package/dist/routes/config/channels/http/serviceWarning.js.map +1 -0
  163. package/dist/routes/config/channels/index.d.ts +3 -3
  164. package/dist/routes/config/channels/index.js +1 -1
  165. package/dist/routes/config/channels/index.js.map +1 -1
  166. package/dist/routes/config/channels/{routes.d.ts → setup.d.ts} +1 -1
  167. package/dist/routes/config/channels/setup.js +23 -0
  168. package/dist/routes/config/channels/setup.js.map +1 -0
  169. package/dist/routes/config/channels/table.d.ts +9 -9
  170. package/dist/routes/config/channels/table.js +124 -76
  171. package/dist/routes/config/channels/table.js.map +1 -1
  172. package/dist/routes/config/http/envelope.d.ts +111 -0
  173. package/dist/routes/config/http/envelope.js +103 -0
  174. package/dist/routes/config/http/envelope.js.map +1 -0
  175. package/dist/routes/config/index.d.ts +9 -9
  176. package/dist/routes/config/index.js +2 -2
  177. package/dist/routes/config/index.js.map +1 -1
  178. package/dist/routes/config/services.js +69 -68
  179. package/dist/routes/config/services.js.map +1 -1
  180. package/dist/routes/config/settings.d.ts +1 -1
  181. package/dist/routes/config/settings.js +45 -38
  182. package/dist/routes/config/settings.js.map +1 -1
  183. package/dist/routes/debug.js +12 -11
  184. package/dist/routes/debug.js.map +1 -1
  185. package/dist/routes/icons.js +2 -2
  186. package/dist/routes/icons.js.map +1 -1
  187. package/dist/routes/logs.js +19 -30
  188. package/dist/routes/logs.js.map +1 -1
  189. package/dist/routes/mpegts.js +1 -1
  190. package/dist/routes/playlist.d.ts +1 -1
  191. package/dist/routes/playlist.js +37 -26
  192. package/dist/routes/playlist.js.map +1 -1
  193. package/dist/routes/root/content.js +27 -6
  194. package/dist/routes/root/content.js.map +1 -1
  195. package/dist/routes/root/index.js +2 -5
  196. package/dist/routes/root/index.js.map +1 -1
  197. package/dist/routes/root/scripts/channels.js +16 -16
  198. package/dist/routes/root/scripts/channels.js.map +1 -1
  199. package/dist/routes/root/scripts/config.js +59 -59
  200. package/dist/routes/root/scripts/config.js.map +1 -1
  201. package/dist/routes/root/scripts/index.d.ts +4 -4
  202. package/dist/routes/root/scripts/shared.js +24 -10
  203. package/dist/routes/root/scripts/shared.js.map +1 -1
  204. package/dist/routes/root/scripts/status.d.ts +4 -0
  205. package/dist/routes/root/scripts/status.handlers.d.ts +182 -0
  206. package/dist/routes/root/scripts/status.handlers.js +713 -0
  207. package/dist/routes/root/scripts/status.handlers.js.map +1 -0
  208. package/dist/routes/root/scripts/status.js +86 -488
  209. package/dist/routes/root/scripts/status.js.map +1 -1
  210. package/dist/routes/root/styles.js +5 -5
  211. package/dist/routes/services.js +18 -15
  212. package/dist/routes/services.js.map +1 -1
  213. package/dist/routes/sse.d.ts +16 -0
  214. package/dist/routes/sse.js +29 -0
  215. package/dist/routes/sse.js.map +1 -0
  216. package/dist/routes/streams.js +10 -23
  217. package/dist/routes/streams.js.map +1 -1
  218. package/dist/routes/ui.d.ts +2 -2
  219. package/dist/routes/upgrade.js +6 -7
  220. package/dist/routes/upgrade.js.map +1 -1
  221. package/dist/service/commands.context.d.ts +6 -0
  222. package/dist/service/commands.context.js +47 -0
  223. package/dist/service/commands.context.js.map +1 -0
  224. package/dist/service/commands.d.ts +53 -8
  225. package/dist/service/commands.js +171 -188
  226. package/dist/service/commands.js.map +1 -1
  227. package/dist/service/generators.context.d.ts +6 -0
  228. package/dist/service/generators.context.js +45 -0
  229. package/dist/service/generators.context.js.map +1 -0
  230. package/dist/service/generators.d.ts +56 -16
  231. package/dist/service/generators.js +499 -383
  232. package/dist/service/generators.js.map +1 -1
  233. package/dist/service/index.d.ts +2 -2
  234. package/dist/streaming/clients.d.ts +2 -2
  235. package/dist/streaming/clients.js +2 -2
  236. package/dist/streaming/codec.d.ts +2 -2
  237. package/dist/streaming/codec.js +0 -1
  238. package/dist/streaming/codec.js.map +1 -1
  239. package/dist/streaming/fmp4Segmenter.d.ts +2 -2
  240. package/dist/streaming/fmp4Segmenter.js +12 -12
  241. package/dist/streaming/hls.d.ts +3 -3
  242. package/dist/streaming/hls.js +81 -70
  243. package/dist/streaming/hls.js.map +1 -1
  244. package/dist/streaming/hlsResume.d.ts +3 -3
  245. package/dist/streaming/hlsResume.js +5 -5
  246. package/dist/streaming/hlsSegments.d.ts +5 -2
  247. package/dist/streaming/hlsSegments.js +14 -9
  248. package/dist/streaming/hlsSegments.js.map +1 -1
  249. package/dist/streaming/monitor.d.ts +12 -12
  250. package/dist/streaming/monitor.js +80 -54
  251. package/dist/streaming/monitor.js.map +1 -1
  252. package/dist/streaming/mp4Parser.d.ts +34 -4
  253. package/dist/streaming/mp4Parser.js +111 -29
  254. package/dist/streaming/mp4Parser.js.map +1 -1
  255. package/dist/streaming/mpegts.d.ts +1 -1
  256. package/dist/streaming/mpegts.js +13 -10
  257. package/dist/streaming/mpegts.js.map +1 -1
  258. package/dist/streaming/playlistBuilder.d.ts +1 -1
  259. package/dist/streaming/playlistBuilder.js +2 -2
  260. package/dist/streaming/preroll.d.ts +9 -9
  261. package/dist/streaming/preroll.js +39 -41
  262. package/dist/streaming/preroll.js.map +1 -1
  263. package/dist/streaming/pretune.js +4 -4
  264. package/dist/streaming/pretune.js.map +1 -1
  265. package/dist/streaming/recovery.d.ts +3 -3
  266. package/dist/streaming/recovery.js +4 -4
  267. package/dist/streaming/registry.d.ts +6 -6
  268. package/dist/streaming/setup.d.ts +9 -8
  269. package/dist/streaming/setup.js +97 -49
  270. package/dist/streaming/setup.js.map +1 -1
  271. package/dist/streaming/showInfo.d.ts +9 -3
  272. package/dist/streaming/showInfo.js +26 -18
  273. package/dist/streaming/showInfo.js.map +1 -1
  274. package/dist/streaming/statusEmitter.d.ts +4 -4
  275. package/dist/streaming/statusEmitter.js +2 -2
  276. package/dist/types/channels.d.ts +133 -34
  277. package/dist/types/channels.js +39 -1
  278. package/dist/types/channels.js.map +1 -1
  279. package/dist/types/config.d.ts +20 -1
  280. package/dist/types/index.d.ts +9 -8
  281. package/dist/types/index.js +1 -0
  282. package/dist/types/index.js.map +1 -1
  283. package/dist/types/profiles.d.ts +5 -4
  284. package/dist/types/selection.d.ts +48 -4
  285. package/dist/types/streaming.d.ts +1 -1
  286. package/dist/upgrade/commands.context.d.ts +6 -0
  287. package/dist/upgrade/commands.context.js +29 -0
  288. package/dist/upgrade/commands.context.js.map +1 -0
  289. package/dist/upgrade/commands.d.ts +29 -2
  290. package/dist/upgrade/commands.js +87 -134
  291. package/dist/upgrade/commands.js.map +1 -1
  292. package/dist/upgrade/detection.context.d.ts +6 -0
  293. package/dist/upgrade/detection.context.js +24 -0
  294. package/dist/upgrade/detection.context.js.map +1 -0
  295. package/dist/upgrade/detection.d.ts +140 -10
  296. package/dist/upgrade/detection.js +153 -66
  297. package/dist/upgrade/detection.js.map +1 -1
  298. package/dist/upgrade/index.d.ts +2 -2
  299. package/dist/utils/chromeFetch.d.ts +1 -1
  300. package/dist/utils/chromeFetch.js +1 -1
  301. package/dist/utils/clock.d.ts +14 -0
  302. package/dist/utils/clock.js +28 -0
  303. package/dist/utils/clock.js.map +1 -0
  304. package/dist/utils/debugFilter.d.ts +1 -1
  305. package/dist/utils/debugFilter.js +6 -4
  306. package/dist/utils/debugFilter.js.map +1 -1
  307. package/dist/utils/delay.d.ts +2 -3
  308. package/dist/utils/delay.js +10 -16
  309. package/dist/utils/delay.js.map +1 -1
  310. package/dist/utils/evaluate.js +12 -14
  311. package/dist/utils/evaluate.js.map +1 -1
  312. package/dist/utils/ffmpeg.context.d.ts +6 -0
  313. package/dist/utils/ffmpeg.context.js +31 -0
  314. package/dist/utils/ffmpeg.context.js.map +1 -0
  315. package/dist/utils/ffmpeg.d.ts +85 -29
  316. package/dist/utils/ffmpeg.js +126 -129
  317. package/dist/utils/ffmpeg.js.map +1 -1
  318. package/dist/utils/fileLogger.d.ts +18 -2
  319. package/dist/utils/fileLogger.js +58 -30
  320. package/dist/utils/fileLogger.js.map +1 -1
  321. package/dist/utils/format.d.ts +1 -1
  322. package/dist/utils/format.js +2 -2
  323. package/dist/utils/format.js.map +1 -1
  324. package/dist/utils/html.js +1 -3
  325. package/dist/utils/html.js.map +1 -1
  326. package/dist/utils/index.d.ts +21 -20
  327. package/dist/utils/index.js +1 -0
  328. package/dist/utils/index.js.map +1 -1
  329. package/dist/utils/logger.js +16 -20
  330. package/dist/utils/logger.js.map +1 -1
  331. package/dist/utils/m3u.d.ts +18 -3
  332. package/dist/utils/m3u.js +28 -14
  333. package/dist/utils/m3u.js.map +1 -1
  334. package/dist/utils/memo.d.ts +19 -0
  335. package/dist/utils/memo.js +53 -0
  336. package/dist/utils/memo.js.map +1 -0
  337. package/dist/utils/morganStream.js +2 -2
  338. package/dist/utils/morganStream.js.map +1 -1
  339. package/dist/utils/pid.d.ts +2 -2
  340. package/dist/utils/pid.js +2 -2
  341. package/dist/utils/platform.d.ts +1 -1
  342. package/dist/utils/platform.js +3 -3
  343. package/dist/utils/platform.js.map +1 -1
  344. package/dist/utils/retry.d.ts +2 -0
  345. package/dist/utils/retry.js +9 -7
  346. package/dist/utils/retry.js.map +1 -1
  347. package/dist/utils/sanitize.d.ts +2 -2
  348. package/dist/utils/sanitize.js +4 -4
  349. package/dist/utils/timing.d.ts +6 -3
  350. package/dist/utils/timing.js +10 -6
  351. package/dist/utils/timing.js.map +1 -1
  352. package/dist/utils/version.d.ts +3 -2
  353. package/dist/utils/version.js +14 -27
  354. package/dist/utils/version.js.map +1 -1
  355. package/package.json +13 -7
  356. package/dist/native/intercept.d.ts +0 -35
  357. package/dist/native/intercept.js +0 -181
  358. package/dist/native/intercept.js.map +0 -1
  359. package/dist/routes/config/channels/routes.js +0 -1505
  360. package/dist/routes/config/channels/routes.js.map +0 -1
@@ -258,7 +258,7 @@ export function generateLandingPageStyles() {
258
258
  ".channel-table tr.user-channel:hover { background: var(--user-channel-tint-hover); }",
259
259
  // Predefined channel override indicator. Left-border accent + blue dot on the first cell matches the settings form's .form-group.modified treatment
260
260
  // (border + dot = "modified from defaults"). The border targets td:first-child because border-collapse: separate prevents borders on <tr> elements. The
261
- // dot is a ::before pseudo-element on the same cell so it's always the first visual element in the row, right next to the border. No background tint — the
261
+ // dot is a ::before pseudo-element on the same cell so it's always the first visual element in the row, right next to the border. No background tint - the
262
262
  // border and dot are the sole differentiators, exactly like modified settings.
263
263
  ".channel-table tr.channel-override td:first-child { border-left: 3px solid var(--interactive-primary); }",
264
264
  ".channel-table tr.channel-override td:first-child::before { content: ''; display: inline-block; width: 8px; height: 8px; " +
@@ -273,7 +273,7 @@ export function generateLandingPageStyles() {
273
273
  ".channel-table tr.channel-unavailable td { color: var(--text-tertiary); }",
274
274
  ".channel-table tr.channel-unavailable.channel-disabled { opacity: 0.5; }",
275
275
  ".channel-table.hide-disabled tr.channel-unavailable { display: none; }",
276
- // Tag pills — rounded labels for tag display in the channel table, tag manager modal, and edit form. The pill shape provides clear visual identity and
276
+ // Tag pills - rounded labels for tag display in the channel table, tag manager modal, and edit form. The pill shape provides clear visual identity and
277
277
  // scannability across all surfaces where tags appear.
278
278
  ".tag-badge { display: inline-block; padding: 1px 7px; margin: 1px 2px; font-size: 11px; border-radius: 10px; " +
279
279
  "background: var(--surface-elevated); border: 1px solid var(--border-default); color: var(--text-secondary); font-weight: 500; }",
@@ -283,7 +283,7 @@ export function generateLandingPageStyles() {
283
283
  ".tag-checkbox-label { cursor: pointer; display: inline-flex; align-items: center; gap: 3px; }",
284
284
  ".tag-checkbox-label input { margin: 0; }",
285
285
  ".tag-checkbox-label .tag-badge { cursor: pointer; }",
286
- // Inline tag edit portal — shared dropdown portaled to <body> via JS. The td has the dropdown class so the document click handler recognizes it as a dropdown
286
+ // Inline tag edit portal - shared dropdown portaled to <body> via JS. The td has the dropdown class so the document click handler recognizes it as a dropdown
287
287
  // context. The display override preserves table-cell layout (the .dropdown class defaults to display: inline-block for div-based dropdowns).
288
288
  "td.dropdown { display: table-cell; }",
289
289
  ".inline-tag-menu { min-width: 140px; }",
@@ -291,7 +291,7 @@ export function generateLandingPageStyles() {
291
291
  ".tag-editable:hover { background: var(--surface-hover); }",
292
292
  ".tag-rename-input { font-size: 11px; padding: 1px 4px; border: 1px solid var(--interactive-primary); border-radius: 10px; " +
293
293
  "outline: none; width: 120px; }",
294
- // Tag manager modal — list of tags with add/delete/restore actions. Hint and error styling use shared wizard classes.
294
+ // Tag manager modal - list of tags with add/delete/restore actions. Hint and error styling use shared wizard classes.
295
295
  ".tag-manager-add { display: flex; gap: 8px; margin-bottom: 8px; }",
296
296
  ".tag-manager-add input { flex: 1; padding: 4px 8px; font-size: 13px; border: 1px solid var(--form-input-border); border-radius: 4px; }",
297
297
  ".tag-manager-list { display: flex; flex-direction: column; gap: 4px; }",
@@ -363,7 +363,7 @@ export function generateLandingPageStyles() {
363
363
  // Health indicator colors. The login icon only uses health-success (provider verified). The health icon uses both (channel last-tune result).
364
364
  ".health-success { color: var(--interactive-success); }",
365
365
  ".health-failed { color: var(--interactive-delete); }",
366
- // Health icon is non-interactive — no hover effect, default cursor. The .user-channel override needs matching specificity (0-3-0) to prevent the
366
+ // Health icon is non-interactive - no hover effect, default cursor. The .user-channel override needs matching specificity (0-3-0) to prevent the
367
367
  // tinted hover background from making the health icon look clickable on user-defined channel rows.
368
368
  ".btn-icon-health { cursor: default; }",
369
369
  ".btn-icon-health:hover { background: transparent; color: var(--text-secondary); }",
@@ -2,11 +2,12 @@ import { getChannelListing, getChannelLogo, isPredefinedChannel } from "../confi
2
2
  import { getChannelServiceLabel, getResolvedChannel, getServiceGroup, getServiceTagForChannel, isServiceTagEnabled, resolveServiceKey } from "../config/services.js";
3
3
  import { getCurrentBrowser, minimizeBrowserWindow, registerManagedPage, unregisterManagedPage } from "../browser/index.js";
4
4
  import { getProviderBySlug, normalizeChannelName } from "../browser/channelSelection.js";
5
+ import { sendError, sendNotFoundError } from "./config/http/envelope.js";
5
6
  import { CONFIG } from "../config/index.js";
6
7
  import { LOG } from "../utils/index.js";
7
8
  /* The services endpoint exposes channel discovery for each registered service. A GET request to /services/:slug/channels creates a temporary browser page,
8
9
  * navigates to the service's guide, runs the service's discoverChannels implementation, and returns a sorted JSON array of discovered channels. The temporary
9
- * page is always closed in a finally block to prevent resource leaks. Concurrent requests for the same service are coalesced — only one discovery walk runs at a
10
+ * page is always closed in a finally block to prevent resource leaks. Concurrent requests for the same service are coalesced - only one discovery walk runs at a
10
11
  * time, and subsequent requests piggyback on the in-flight result. A refresh=true request aborts any in-flight discovery and starts fresh.
11
12
  */
12
13
  // Sentinel error used to identify aborted discoveries in the retry loop. Distinguishes abort rejections from genuine discovery failures so the loop only retries
@@ -26,8 +27,10 @@ const inflight = new Map();
26
27
  */
27
28
  function sendDiscoveryError(res, label, error) {
28
29
  const message = (error instanceof Error) ? error.message : String(error);
30
+ // Channel discovery failures are warnings rather than errors because they typically reflect provider DOM drift, network blips, or transient site outages
31
+ // (recoverable by retry) rather than server-side faults. The envelope helper normalizes the response shape; the LOG.warn level is preserved deliberately.
29
32
  LOG.warn("Channel discovery failed for %s: %s.", label, message);
30
- res.status(500).json({ error: "Channel discovery failed: " + message + "." });
33
+ sendError(res, 500, { error: "Channel discovery failed: " + message + "." });
31
34
  }
32
35
  /**
33
36
  * Runs service channel discovery in a temporary browser page. Opens a new page, navigates to the service's guide URL, runs the discovery function, and returns
@@ -40,7 +43,7 @@ function sendDiscoveryError(res, label, error) {
40
43
  async function runDiscovery(provider, signal) {
41
44
  let page = null;
42
45
  // Close the page when the abort signal fires. This causes any in-progress Puppeteer operations to throw, propagating the cancellation through the discovery
43
- // function without requiring explicit signal checking in each provider's implementation. The finally block also closes the page unconditionally — the
46
+ // function without requiring explicit signal checking in each provider's implementation. The finally block also closes the page unconditionally - the
44
47
  // redundant close is idempotent (caught by try/catch).
45
48
  const onAbort = () => {
46
49
  if (page) {
@@ -99,16 +102,16 @@ async function runDiscovery(provider, signal) {
99
102
  * (predefined keys are hand-crafted and may not match generateChannelKey output).
100
103
  *
101
104
  * For each canonical in the listing, we check for a variant matching the browsed service (via getServiceGroup) and extract its channelSelector via
102
- * getResolvedChannel. This builds a channelSelector → lineup state map that the discovered channels are matched against.
105
+ * getResolvedChannel. This builds a channelSelector -> lineup state map that the discovered channels are matched against.
103
106
  *
104
107
  * @param channels - The raw discovered channels from the service.
105
108
  * @param serviceSlug - The slug of the service being browsed (e.g., "spectrum", "hulu").
106
109
  * @returns Annotated channels with lineup state where applicable.
107
110
  */
108
111
  function annotateWithLineupState(channels, serviceSlug) {
109
- // Build a channelSelector → lineup state mapping for the browsed service. For each canonical entry in the listing, we find the variant that corresponds
112
+ // Build a channelSelector -> lineup state mapping for the browsed service. For each canonical entry in the listing, we find the variant that corresponds
110
113
  // to this service (if one exists) and index by that variant's channelSelector. This ensures matching works even when predefined keys don't match the
111
- // normalized channel name (e.g., "axstv" vs generateChannelKey("AXS TV") → "axs-tv").
114
+ // normalized channel name (e.g., "axstv" vs generateChannelKey("AXS TV") -> "axs-tv").
112
115
  //
113
116
  // When two canonicals share the same channelSelector for a service (East/Pacific pairs like "Disney Channel"), the map stores an array of states. The
114
117
  // annotation step then uses the discovery entry's stationId to disambiguate which canonical to assign.
@@ -184,11 +187,11 @@ function annotateWithLineupState(channels, serviceSlug) {
184
187
  if (!states || (states.length === 0)) {
185
188
  return ch;
186
189
  }
187
- // Single match — no disambiguation needed.
190
+ // Single match - no disambiguation needed.
188
191
  if (states.length === 1) {
189
192
  return { ...ch, lineup: states[0] };
190
193
  }
191
- // Multiple matches — use stationId to pick the right canonical. Fall back to the first match if stationId doesn't disambiguate.
194
+ // Multiple matches - use stationId to pick the right canonical. Fall back to the first match if stationId doesn't disambiguate.
192
195
  const match = states.find((s) => s.stationId === ch.stationId) ?? states[0];
193
196
  return { ...ch, lineup: match };
194
197
  });
@@ -199,18 +202,18 @@ function annotateWithLineupState(channels, serviceSlug) {
199
202
  */
200
203
  export function setupServicesEndpoint(app) {
201
204
  app.get("/services/:slug/channels", async (req, res) => {
202
- const slug = req.params.slug;
205
+ const slug = req.params["slug"];
203
206
  const provider = getProviderBySlug(slug);
204
207
  if (!provider) {
205
- res.status(404).json({ error: "Unknown service: " + slug + "." });
208
+ sendNotFoundError(res, "Unknown service: " + slug + ".");
206
209
  return;
207
210
  }
208
211
  // When refresh=true is requested, clear the service's caches (unified channel cache, row caches, fully-enumerated flags, etc.) so the discovery walk runs
209
- // against fresh data. This also resets warm tuning state (watch URLs, GUIDs), but the discovery walk repopulates the unified cache before returning — any
210
- // subsequent tune resolves from the freshly populated cache as normal. If a discovery is already in flight, abort it first — clearing the cache while a
212
+ // against fresh data. This also resets warm tuning state (watch URLs, GUIDs), but the discovery walk repopulates the unified cache before returning - any
213
+ // subsequent tune resolves from the freshly populated cache as normal. If a discovery is already in flight, abort it first - clearing the cache while a
211
214
  // discovery is progressively populating it would corrupt its state.
212
- const lineup = req.query.lineup === "true";
213
- const refresh = req.query.refresh === "true";
215
+ const lineup = req.query["lineup"] === "true";
216
+ const refresh = req.query["refresh"] === "true";
214
217
  if (refresh) {
215
218
  const existing = inflight.get(slug);
216
219
  if (existing) {
@@ -243,7 +246,7 @@ export function setupServicesEndpoint(app) {
243
246
  entry = { controller, promise };
244
247
  inflight.set(slug, entry);
245
248
  }
246
- // Await the in-flight discovery. If it was aborted by a refresh=true request, a new discovery should now be in the map — retry against that one. The caller
249
+ // Await the in-flight discovery. If it was aborted by a refresh=true request, a new discovery should now be in the map - retry against that one. The caller
247
250
  // doesn't know or care about the abort; they just want channels. Only DiscoveryAbortError triggers a retry; genuine failures are reported immediately.
248
251
  for (;;) {
249
252
  try {
@@ -1 +1 @@
1
- {"version":3,"file":"services.js","sourceRoot":"","sources":["../../src/routes/services.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"services.js","sourceRoot":"","sources":["../../src/routes/services.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ import type { Response } from "express";
2
+ /**
3
+ * SSE transport handle returned by installSseStream. Callers use sendEvent to push events with JSON payloads (eventType=null for an unnamed data event), and
4
+ * call close() during request teardown to clear the heartbeat timer.
5
+ */
6
+ export interface SseStream {
7
+ close: () => void;
8
+ sendEvent: (eventType: string | null, data: unknown) => void;
9
+ }
10
+ /**
11
+ * Sets the SSE response headers, flushes them so the connection opens immediately, and starts the heartbeat. Returns helpers the caller uses to push events
12
+ * and to clean up the heartbeat timer when the connection closes.
13
+ * @param res - The Express response object.
14
+ * @returns An SseStream handle for sending events and tearing down.
15
+ */
16
+ export declare function installSseStream(res: Response): SseStream;
@@ -0,0 +1,29 @@
1
+ // Heartbeat cadence in milliseconds. Sent as a named heartbeat event to keep the connection alive through proxies and let clients detect staleness.
2
+ const HEARTBEAT_INTERVAL_MS = 30_000;
3
+ /**
4
+ * Sets the SSE response headers, flushes them so the connection opens immediately, and starts the heartbeat. Returns helpers the caller uses to push events
5
+ * and to clean up the heartbeat timer when the connection closes.
6
+ * @param res - The Express response object.
7
+ * @returns An SseStream handle for sending events and tearing down.
8
+ */
9
+ export function installSseStream(res) {
10
+ // Cache-Control prevents proxies from buffering the stream; Connection: keep-alive ensures the connection stays open; Content-Type: text/event-stream is
11
+ // the SSE protocol marker the browser EventSource needs to recognize the response.
12
+ res.setHeader("Cache-Control", "no-cache");
13
+ res.setHeader("Connection", "keep-alive");
14
+ res.setHeader("Content-Type", "text/event-stream");
15
+ // Flush headers immediately so the EventSource handshake completes before the first event arrives.
16
+ res.flushHeaders();
17
+ // Send a named heartbeat event every HEARTBEAT_INTERVAL_MS to keep the connection alive through proxies and allow clients to detect staleness.
18
+ const heartbeat = setInterval(() => res.write("event: heartbeat\ndata: \n\n"), HEARTBEAT_INTERVAL_MS);
19
+ return {
20
+ close: () => { clearInterval(heartbeat); },
21
+ sendEvent: (eventType, data) => {
22
+ if (eventType !== null) {
23
+ res.write("event: " + eventType + "\n");
24
+ }
25
+ res.write("data: " + JSON.stringify(data) + "\n\n");
26
+ }
27
+ };
28
+ }
29
+ //# sourceMappingURL=sse.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sse.js","sourceRoot":"","sources":["../../src/routes/sse.ts"],"names":[],"mappings":"AAOA,oJAAoJ;AACpJ,MAAM,qBAAqB,GAAG,MAAM,CAAC;AAYrC;;;;;GAKG;AACH,MAAM,UAAU,gBAAgB,CAAC,GAAa;IAE5C,yJAAyJ;IACzJ,mFAAmF;IACnF,GAAG,CAAC,SAAS,CAAC,eAAe,EAAE,UAAU,CAAC,CAAC;IAC3C,GAAG,CAAC,SAAS,CAAC,YAAY,EAAE,YAAY,CAAC,CAAC;IAC1C,GAAG,CAAC,SAAS,CAAC,cAAc,EAAE,mBAAmB,CAAC,CAAC;IAEnD,mGAAmG;IACnG,GAAG,CAAC,YAAY,EAAE,CAAC;IAEnB,+IAA+I;IAC/I,MAAM,SAAS,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,8BAA8B,CAAC,EAAE,qBAAqB,CAAC,CAAC;IAEtG,OAAO;QAEL,KAAK,EAAE,GAAS,EAAE,GAAG,aAAa,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;QAChD,SAAS,EAAE,CAAC,SAAwB,EAAE,IAAa,EAAQ,EAAE;YAE3D,IAAG,SAAS,KAAK,IAAI,EAAE,CAAC;gBAEtB,GAAG,CAAC,KAAK,CAAC,SAAS,GAAG,SAAS,GAAG,IAAI,CAAC,CAAC;YAC1C,CAAC;YAED,GAAG,CAAC,KAAK,CAAC,QAAQ,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,CAAC;QACtD,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -1,7 +1,9 @@
1
1
  import { getAllStreams, getStream, getStreamCount, getStreamMemoryUsage } from "../streaming/registry.js";
2
2
  import { getStatusSnapshot, getStreamStatus, subscribeToStatus } from "../streaming/statusEmitter.js";
3
+ import { sendNotFoundError, sendSuccess, sendValidationError } from "./config/http/envelope.js";
3
4
  import { CONFIG } from "../config/index.js";
4
5
  import { emitCurrentSystemStatus } from "../browser/index.js";
6
+ import { installSseStream } from "./sse.js";
5
7
  import { terminateStream } from "../streaming/lifecycle.js";
6
8
  /* The streams endpoint provides visibility into active streams and allows operators to terminate streams via the API. This is useful for debugging and for
7
9
  * integrations that need to manage stream lifecycle.
@@ -43,44 +45,29 @@ export function setupStreamsEndpoint(app) {
43
45
  app.delete("/streams/:id", (req, res) => {
44
46
  const streamIdParam = parseInt(req.params.id);
45
47
  if (isNaN(streamIdParam)) {
46
- res.status(400).json({ error: "Invalid stream ID." });
48
+ sendValidationError(res, "Invalid stream ID.");
47
49
  return;
48
50
  }
49
51
  const streamInfo = getStream(streamIdParam);
50
52
  if (!streamInfo) {
51
- res.status(404).json({ error: "Stream not found." });
53
+ sendNotFoundError(res, "Stream not found.");
52
54
  return;
53
55
  }
54
56
  terminateStream(streamIdParam, streamInfo.info.storeKey, "API request");
55
57
  void emitCurrentSystemStatus();
56
- res.json({ message: "Stream terminated.", streamId: streamIdParam });
58
+ sendSuccess(res, { data: { streamId: streamIdParam }, message: "Stream terminated." });
57
59
  });
58
60
  /* The /streams/status endpoint provides real-time stream and system status via Server-Sent Events. Connected clients receive an initial snapshot of all streams
59
61
  * and the system state, then receive updates as streams are added, removed, or their health changes.
60
62
  */
61
63
  app.get("/streams/status", (req, res) => {
62
- // Set SSE headers. The Content-Type must be text/event-stream for the browser to recognize this as an SSE connection.
63
- res.setHeader("Cache-Control", "no-cache");
64
- res.setHeader("Connection", "keep-alive");
65
- res.setHeader("Content-Type", "text/event-stream");
66
- // Disable response buffering to ensure events are sent immediately.
67
- res.flushHeaders();
64
+ const sse = installSseStream(res);
68
65
  // Send the initial snapshot so clients have current state.
69
- const snapshot = getStatusSnapshot();
70
- res.write("event: snapshot\n");
71
- res.write("data: " + JSON.stringify(snapshot) + "\n\n");
72
- // Subscribe to status events and forward them to the client.
73
- const unsubscribe = subscribeToStatus((eventType, data) => {
74
- res.write("event: " + eventType + "\n");
75
- res.write("data: " + JSON.stringify(data) + "\n\n");
76
- });
77
- // Send a named heartbeat event every 30 seconds to keep the connection alive through proxies and allow clients to detect staleness.
78
- const heartbeatInterval = setInterval(() => {
79
- res.write("event: heartbeat\ndata: \n\n");
80
- }, 30000);
81
- // Clean up when the client disconnects.
66
+ sse.sendEvent("snapshot", getStatusSnapshot());
67
+ // Subscribe to status events and forward them to the client; the heartbeat is owned by installSseStream.
68
+ const unsubscribe = subscribeToStatus((eventType, data) => { sse.sendEvent(eventType, data); });
82
69
  req.on("close", () => {
83
- clearInterval(heartbeatInterval);
70
+ sse.close();
84
71
  unsubscribe();
85
72
  });
86
73
  });
@@ -1 +1 @@
1
- {"version":3,"file":"streams.js","sourceRoot":"","sources":["../../src/routes/streams.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"streams.js","sourceRoot":"","sources":["../../src/routes/streams.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,5 @@
1
- export { generateAlert, generateBadge, generateButton, generatePanelHeader, generateSection, generateSelect, generateSimpleAlert, generateStatusIndicator, generateTextInput } from "./components.js";
2
- export type { AlertType, BadgeVariant, ButtonOptions, ButtonSize, ButtonVariant, SelectOption, SelectOptions, TextInputOptions } from "./components.js";
1
+ export { generateAlert, generateBadge, generateButton, generatePanelHeader, generateSection, generateSelect, generateSimpleAlert, generateStatusIndicator, generateTextInput } from "./components.ts";
2
+ export type { AlertType, BadgeVariant, ButtonOptions, ButtonSize, ButtonVariant, SelectOption, SelectOptions, TextInputOptions } from "./components.ts";
3
3
  /**
4
4
  * Options for configuring the tab script behavior.
5
5
  */
@@ -1,4 +1,5 @@
1
- import { LOG, fetchLatestVersion, formatError, getPackageVersion, isRunningAsService, isVersionLessThan, normalizeVersion } from "../utils/index.js";
1
+ import { LOG, fetchLatestVersion, getPackageVersion, isRunningAsService, isVersionLessThan, normalizeVersion } from "../utils/index.js";
2
+ import { sendErrorResponse, sendSuccess, sendValidationError } from "./config/http/envelope.js";
2
3
  import { closeBrowser } from "../browser/index.js";
3
4
  import { detectInstallMethod } from "../upgrade/detection.js";
4
5
  import { exec as execCallback } from "node:child_process";
@@ -29,8 +30,7 @@ export function setupUpgradeEndpoint(app) {
29
30
  });
30
31
  }
31
32
  catch (error) {
32
- LOG.error("Failed to get upgrade info: %s.", formatError(error));
33
- res.status(500).json({ message: "Failed to get upgrade info: " + formatError(error), success: false });
33
+ sendErrorResponse(res, error, "get upgrade info");
34
34
  }
35
35
  });
36
36
  // POST /upgrade - Executes the upgrade command for the detected installation method. Uses async exec so the event loop stays free during the upgrade command,
@@ -39,7 +39,7 @@ export function setupUpgradeEndpoint(app) {
39
39
  try {
40
40
  const info = detectInstallMethod();
41
41
  if (!info.upgradeable) {
42
- res.json({ message: "This installation method does not support in-place upgrades.", success: false, willRestart: false });
42
+ sendValidationError(res, "This installation method does not support in-place upgrades.");
43
43
  return;
44
44
  }
45
45
  // Execute the upgrade command asynchronously to avoid blocking the event loop.
@@ -50,7 +50,7 @@ export function setupUpgradeEndpoint(app) {
50
50
  LOG.info("Executing upgrade via web UI: %s.", info.upgradeCommand);
51
51
  await exec(info.upgradeCommand, options);
52
52
  const willRestart = isRunningAsService();
53
- res.json({ message: "Upgrade complete.", success: true, willRestart });
53
+ sendSuccess(res, { data: { willRestart }, message: "Upgrade complete." });
54
54
  // If running as a service, exit after a short delay so the service manager restarts us with the new version.
55
55
  if (willRestart) {
56
56
  setTimeout(() => {
@@ -60,8 +60,7 @@ export function setupUpgradeEndpoint(app) {
60
60
  }
61
61
  }
62
62
  catch (error) {
63
- LOG.error("Upgrade failed: %s.", formatError(error));
64
- res.status(500).json({ message: "Upgrade failed: " + formatError(error), success: false, willRestart: false });
63
+ sendErrorResponse(res, error, "upgrade");
65
64
  }
66
65
  });
67
66
  }
@@ -1 +1 @@
1
- {"version":3,"file":"upgrade.js","sourceRoot":"","sources":["../../src/routes/upgrade.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"upgrade.js","sourceRoot":"","sources":["../../src/routes/upgrade.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ import type { ServiceContext } from "./commands.ts";
2
+ /**
3
+ * Builds the default ServiceContext from real runtime I/O.
4
+ * @returns A ServiceContext populated from the live process.
5
+ */
6
+ export declare function createDefaultServiceContext(): ServiceContext;
@@ -0,0 +1,47 @@
1
+ /* Copyright(C) 2024-2026, HJD (https://github.com/hjdhjd). All rights reserved.
2
+ *
3
+ * commands.context.ts: The default adapter that produces a ServiceContext from real runtime I/O. The handlers in commands.ts are pure orchestrators over a
4
+ * ServiceContext; this file is the only place in the service-commands module that calls execFile, fetches HTTP, reads the filesystem, or queries process.platform.
5
+ * Tests bypass this file entirely by constructing ServiceContext literals inline.
6
+ */
7
+ import { DEFAULTS, readConfig } from "../config/userConfig.js";
8
+ import { getNodeExecutablePath, getPlatform, getPrismCastEntryPoint, getServiceFilePath } from "../utils/platform.js";
9
+ import { buildServiceDefinition, detectStalePaths, getServiceGenerator, getServicePaths } from "./generators.js";
10
+ import { print, printError } from "../utils/cliOutput.js";
11
+ import { getDataDir } from "../config/paths.js";
12
+ /**
13
+ * Builds the default ServiceContext from real runtime I/O.
14
+ * @returns A ServiceContext populated from the live process.
15
+ */
16
+ export function createDefaultServiceContext() {
17
+ return {
18
+ buildServiceDefinition,
19
+ detectStalePaths,
20
+ fetchActiveStreams: async (port) => {
21
+ try {
22
+ const response = await fetch("http://127.0.0.1:" + String(port) + "/streams", { signal: AbortSignal.timeout(3000) });
23
+ if (!response.ok) {
24
+ return null;
25
+ }
26
+ return await response.json();
27
+ }
28
+ catch {
29
+ return null;
30
+ }
31
+ },
32
+ getDataDir,
33
+ getEntryPoint: getPrismCastEntryPoint,
34
+ getGenerator: getServiceGenerator,
35
+ getNodePath: getNodeExecutablePath,
36
+ getPlatform: () => getPlatform(),
37
+ getServerPort: async () => {
38
+ const result = await readConfig();
39
+ return result.config.server?.port ?? DEFAULTS.server.port;
40
+ },
41
+ getServiceFilePath,
42
+ getServicePaths,
43
+ stderr: printError,
44
+ stdout: print
45
+ };
46
+ }
47
+ //# sourceMappingURL=commands.context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"commands.context.js","sourceRoot":"","sources":["../../src/service/commands.context.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAC/D,OAAO,EAAiB,qBAAqB,EAAE,WAAW,EAAE,sBAAsB,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAErI,OAAO,EAAE,sBAAsB,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AACjH,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAC1D,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAEhD;;;GAGG;AACH,MAAM,UAAU,2BAA2B;IAEzC,OAAO;QAEL,sBAAsB;QACtB,gBAAgB;QAChB,kBAAkB,EAAE,KAAK,EAAE,IAAY,EAAmC,EAAE;YAE1E,IAAI,CAAC;gBAEH,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,mBAAmB,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,UAAU,EAAE,EAAE,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;gBAErH,IAAG,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;oBAEhB,OAAO,IAAI,CAAC;gBACd,CAAC;gBAED,OAAO,MAAM,QAAQ,CAAC,IAAI,EAAqB,CAAC;YAClD,CAAC;YAAC,MAAM,CAAC;gBAEP,OAAO,IAAI,CAAC;YACd,CAAC;QACH,CAAC;QACD,UAAU;QACV,aAAa,EAAE,sBAAsB;QACrC,YAAY,EAAE,mBAAmB;QACjC,WAAW,EAAE,qBAAqB;QAClC,WAAW,EAAE,GAAa,EAAE,CAAC,WAAW,EAAE;QAC1C,aAAa,EAAE,KAAK,IAAqB,EAAE;YAEzC,MAAM,MAAM,GAAG,MAAM,UAAU,EAAE,CAAC;YAElC,OAAO,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,IAAI,IAAI,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC;QAC5D,CAAC;QACD,kBAAkB;QAClB,eAAe;QACf,MAAM,EAAE,UAAU;QAClB,MAAM,EAAE,KAAK;KACd,CAAC;AACJ,CAAC"}
@@ -1,43 +1,88 @@
1
+ import { type Platform } from "../utils/platform.ts";
2
+ import type { ServiceDefinition, ServiceGenerator, ServicePaths, StalePathResult } from "./generators.ts";
3
+ import type { Nullable } from "../types/index.ts";
4
+ /**
5
+ * Response from the /streams endpoint.
6
+ */
7
+ export interface StreamsResponse {
8
+ count: number;
9
+ limit: number;
10
+ streams: {
11
+ channel: Nullable<string>;
12
+ duration: number;
13
+ id: number;
14
+ showName: string;
15
+ url: string;
16
+ }[];
17
+ }
18
+ /**
19
+ * The runtime context the service handlers consume. Each field models one capability the handlers need - generator selection, path/platform queries, server probe,
20
+ * stale-path detection, service-definition build, and stdout/stderr output. Decision logic is a pure function of this shape; production wires it through
21
+ * createDefaultServiceContext (in commands.context.ts), tests pass a context literal.
22
+ */
23
+ export interface ServiceContext {
24
+ readonly buildServiceDefinition: () => ServiceDefinition;
25
+ readonly detectStalePaths: () => Nullable<StalePathResult>;
26
+ readonly fetchActiveStreams: (port: number) => Promise<Nullable<StreamsResponse>>;
27
+ readonly getDataDir: () => string;
28
+ readonly getEntryPoint: () => string;
29
+ readonly getGenerator: () => Nullable<ServiceGenerator>;
30
+ readonly getNodePath: () => string;
31
+ readonly getPlatform: () => Platform;
32
+ readonly getServerPort: () => Promise<number>;
33
+ readonly getServiceFilePath: () => string;
34
+ readonly getServicePaths: () => Nullable<ServicePaths>;
35
+ readonly stderr: (line: string) => void;
36
+ readonly stdout: (line: string) => void;
37
+ }
1
38
  /**
2
39
  * Prints usage information for the service subcommand.
40
+ * @param ctx - The service context. Defaults to createDefaultServiceContext().
3
41
  */
4
- export declare function printServiceUsage(): void;
42
+ export declare function printServiceUsage(ctx?: ServiceContext): void;
5
43
  /**
6
44
  * Handles the `service install` command. Generates and installs a service file for the current platform, then starts the service.
7
45
  * @param force - If true, reinstall even if already installed.
46
+ * @param ctx - The service context. Defaults to createDefaultServiceContext().
8
47
  * @returns Exit code (0 for success, 1 for error).
9
48
  */
10
- export declare function handleInstall(force: boolean): Promise<number>;
49
+ export declare function handleInstall(force: boolean, ctx?: ServiceContext): Promise<number>;
11
50
  /**
12
51
  * Handles the `service uninstall` command. Stops and removes the service.
52
+ * @param ctx - The service context. Defaults to createDefaultServiceContext().
13
53
  * @returns Exit code (0 for success, 1 for error).
14
54
  */
15
- export declare function handleUninstall(): Promise<number>;
55
+ export declare function handleUninstall(ctx?: ServiceContext): Promise<number>;
16
56
  /**
17
57
  * Handles the `service start` command. Starts the service if it is installed but not running. If the service file contains stale paths (e.g., after a Homebrew
18
58
  * upgrade), they are fixed automatically before starting.
59
+ * @param ctx - The service context. Defaults to createDefaultServiceContext().
19
60
  * @returns Exit code (0 for success, 1 for error).
20
61
  */
21
- export declare function handleStart(): Promise<number>;
62
+ export declare function handleStart(ctx?: ServiceContext): Promise<number>;
22
63
  /**
23
64
  * Handles the `service stop` command. Always attempts to stop the service regardless of whether it appears to be running, ensuring that loaded-but-not-running
24
65
  * state (common on launchd after a crash) is properly cleared.
66
+ * @param ctx - The service context. Defaults to createDefaultServiceContext().
25
67
  * @returns Exit code (0 for success, 1 for error).
26
68
  */
27
- export declare function handleStop(): Promise<number>;
69
+ export declare function handleStop(ctx?: ServiceContext): Promise<number>;
28
70
  /**
29
71
  * Handles the `service restart` command. Stops the service, then compares paths and regenerates the service file if needed before starting.
72
+ * @param ctx - The service context. Defaults to createDefaultServiceContext().
30
73
  * @returns Exit code (0 for success, 1 for error).
31
74
  */
32
- export declare function handleRestart(): Promise<number>;
75
+ export declare function handleRestart(ctx?: ServiceContext): Promise<number>;
33
76
  /**
34
77
  * Handles the `service status` command. Shows the current service installation and running status.
78
+ * @param ctx - The service context. Defaults to createDefaultServiceContext().
35
79
  * @returns Exit code (0 for success).
36
80
  */
37
- export declare function handleStatus(): Promise<number>;
81
+ export declare function handleStatus(ctx?: ServiceContext): Promise<number>;
38
82
  /**
39
83
  * Main handler for the `service` subcommand. Parses arguments and delegates to the appropriate handler.
40
84
  * @param args - Arguments after 'service' (e.g., ['install', '--force']).
85
+ * @param ctx - The service context. Defaults to createDefaultServiceContext().
41
86
  * @returns Exit code (0 for success, 1 for error).
42
87
  */
43
- export declare function handleServiceCommand(args: string[]): Promise<number>;
88
+ export declare function handleServiceCommand(args: string[], ctx?: ServiceContext): Promise<number>;