prismcast 1.13.0 → 1.14.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 (218) hide show
  1. package/dist/app.d.ts +88 -6
  2. package/dist/app.js +287 -154
  3. package/dist/app.js.map +1 -1
  4. package/dist/browser/cdp.d.ts +6 -17
  5. package/dist/browser/cdp.js +6 -57
  6. package/dist/browser/cdp.js.map +1 -1
  7. package/dist/browser/index.d.ts +106 -23
  8. package/dist/browser/index.js +292 -225
  9. package/dist/browser/index.js.map +1 -1
  10. package/dist/browser/precaching.d.ts +25 -11
  11. package/dist/browser/precaching.js +245 -97
  12. package/dist/browser/precaching.js.map +1 -1
  13. package/dist/browser/tabCapture.js +3 -10
  14. package/dist/browser/tabCapture.js.map +1 -1
  15. package/dist/browser/tuning/comcastPolymer.js +13 -14
  16. package/dist/browser/tuning/comcastPolymer.js.map +1 -1
  17. package/dist/browser/tuning/hbo.js +34 -17
  18. package/dist/browser/tuning/hbo.js.map +1 -1
  19. package/dist/browser/video.d.ts +1 -1
  20. package/dist/browser/video.js +3 -3
  21. package/dist/channels/index.js +5 -5
  22. package/dist/channels/index.js.map +1 -1
  23. package/dist/cliHelp.d.ts +11 -0
  24. package/dist/cliHelp.js +148 -0
  25. package/dist/cliHelp.js.map +1 -0
  26. package/dist/config/channelForm.js +5 -4
  27. package/dist/config/channelForm.js.map +1 -1
  28. package/dist/config/consistencyProbe.d.ts +2 -4
  29. package/dist/config/consistencyProbe.js +8 -51
  30. package/dist/config/consistencyProbe.js.map +1 -1
  31. package/dist/config/index.d.ts +107 -55
  32. package/dist/config/index.js +499 -267
  33. package/dist/config/index.js.map +1 -1
  34. package/dist/config/paths.d.ts +13 -8
  35. package/dist/config/paths.js +21 -25
  36. package/dist/config/paths.js.map +1 -1
  37. package/dist/config/persistence.d.ts +57 -11
  38. package/dist/config/persistence.js +127 -44
  39. package/dist/config/persistence.js.map +1 -1
  40. package/dist/config/reactivity.d.ts +60 -36
  41. package/dist/config/reactivity.js +89 -116
  42. package/dist/config/reactivity.js.map +1 -1
  43. package/dist/config/services.d.ts +61 -26
  44. package/dist/config/services.js +137 -68
  45. package/dist/config/services.js.map +1 -1
  46. package/dist/config/streamSettings.d.ts +24 -0
  47. package/dist/config/streamSettings.js +17 -0
  48. package/dist/config/streamSettings.js.map +1 -0
  49. package/dist/config/userChannels.d.ts +60 -52
  50. package/dist/config/userChannels.js +138 -188
  51. package/dist/config/userChannels.js.map +1 -1
  52. package/dist/config/userConfig.d.ts +224 -61
  53. package/dist/config/userConfig.js +351 -134
  54. package/dist/config/userConfig.js.map +1 -1
  55. package/dist/hdhr/discover.d.ts +7 -1
  56. package/dist/hdhr/discover.js +12 -6
  57. package/dist/hdhr/discover.js.map +1 -1
  58. package/dist/hdhr/index.d.ts +51 -10
  59. package/dist/hdhr/index.js +108 -112
  60. package/dist/hdhr/index.js.map +1 -1
  61. package/dist/hdhr/udp.d.ts +11 -4
  62. package/dist/hdhr/udp.js +25 -20
  63. package/dist/hdhr/udp.js.map +1 -1
  64. package/dist/index.js +16 -143
  65. package/dist/index.js.map +1 -1
  66. package/dist/native/index.d.ts +1 -1
  67. package/dist/native/index.js +4 -3
  68. package/dist/native/index.js.map +1 -1
  69. package/dist/native/proxy.d.ts +1 -1
  70. package/dist/native/proxy.js +36 -28
  71. package/dist/native/proxy.js.map +1 -1
  72. package/dist/routes/cdp.d.ts +7 -6
  73. package/dist/routes/cdp.js +9 -8
  74. package/dist/routes/cdp.js.map +1 -1
  75. package/dist/routes/components.d.ts +23 -5
  76. package/dist/routes/components.js +21 -4
  77. package/dist/routes/components.js.map +1 -1
  78. package/dist/routes/config/channels/endpoints/browse.js +39 -29
  79. package/dist/routes/config/channels/endpoints/browse.js.map +1 -1
  80. package/dist/routes/config/channels/endpoints/bulk.js +2 -6
  81. package/dist/routes/config/channels/endpoints/bulk.js.map +1 -1
  82. package/dist/routes/config/channels/endpoints/predefined.js +5 -15
  83. package/dist/routes/config/channels/endpoints/predefined.js.map +1 -1
  84. package/dist/routes/config/channels/endpoints/prefs.js +7 -6
  85. package/dist/routes/config/channels/endpoints/prefs.js.map +1 -1
  86. package/dist/routes/config/channels/endpoints/service.js +6 -5
  87. package/dist/routes/config/channels/endpoints/service.js.map +1 -1
  88. package/dist/routes/config/channels/endpoints/tags.js +4 -16
  89. package/dist/routes/config/channels/endpoints/tags.js.map +1 -1
  90. package/dist/routes/config/channels/table.d.ts +2 -1
  91. package/dist/routes/config/channels/table.js +11 -13
  92. package/dist/routes/config/channels/table.js.map +1 -1
  93. package/dist/routes/config/http/envelope.d.ts +6 -3
  94. package/dist/routes/config/http/envelope.js +18 -5
  95. package/dist/routes/config/http/envelope.js.map +1 -1
  96. package/dist/routes/config/index.d.ts +21 -13
  97. package/dist/routes/config/index.js +47 -34
  98. package/dist/routes/config/index.js.map +1 -1
  99. package/dist/routes/config/settings.d.ts +43 -6
  100. package/dist/routes/config/settings.js +225 -125
  101. package/dist/routes/config/settings.js.map +1 -1
  102. package/dist/routes/config/vocabulary.d.ts +24 -0
  103. package/dist/routes/config/vocabulary.js +33 -0
  104. package/dist/routes/config/vocabulary.js.map +1 -0
  105. package/dist/routes/debug.js +28 -13
  106. package/dist/routes/debug.js.map +1 -1
  107. package/dist/routes/root/content.js +33 -26
  108. package/dist/routes/root/content.js.map +1 -1
  109. package/dist/routes/root/scripts/channels.js +23 -11
  110. package/dist/routes/root/scripts/channels.js.map +1 -1
  111. package/dist/routes/root/scripts/config.d.ts +1 -1
  112. package/dist/routes/root/scripts/config.js +127 -79
  113. package/dist/routes/root/scripts/config.js.map +1 -1
  114. package/dist/routes/root/scripts/shared.js +34 -23
  115. package/dist/routes/root/scripts/shared.js.map +1 -1
  116. package/dist/routes/root/scripts/status.handlers.d.ts +8 -13
  117. package/dist/routes/root/scripts/status.handlers.js +35 -21
  118. package/dist/routes/root/scripts/status.handlers.js.map +1 -1
  119. package/dist/routes/root/styles.js +13 -16
  120. package/dist/routes/root/styles.js.map +1 -1
  121. package/dist/routes/services.js +12 -16
  122. package/dist/routes/services.js.map +1 -1
  123. package/dist/routes/theme.js +12 -12
  124. package/dist/routes/theme.js.map +1 -1
  125. package/dist/routes/ui.d.ts +4 -3
  126. package/dist/routes/ui.js +17 -13
  127. package/dist/routes/ui.js.map +1 -1
  128. package/dist/service/generators.js +12 -9
  129. package/dist/service/generators.js.map +1 -1
  130. package/dist/streaming/captureSession.d.ts +4 -4
  131. package/dist/streaming/captureSession.js +6 -7
  132. package/dist/streaming/captureSession.js.map +1 -1
  133. package/dist/streaming/codec.d.ts +12 -2
  134. package/dist/streaming/codec.js +40 -28
  135. package/dist/streaming/codec.js.map +1 -1
  136. package/dist/streaming/fmp4Segmenter.d.ts +14 -4
  137. package/dist/streaming/fmp4Segmenter.js +99 -79
  138. package/dist/streaming/fmp4Segmenter.js.map +1 -1
  139. package/dist/streaming/hls.d.ts +21 -14
  140. package/dist/streaming/hls.js +148 -122
  141. package/dist/streaming/hls.js.map +1 -1
  142. package/dist/streaming/hlsResume.d.ts +36 -13
  143. package/dist/streaming/hlsResume.js +68 -37
  144. package/dist/streaming/hlsResume.js.map +1 -1
  145. package/dist/streaming/monitor.d.ts +5 -3
  146. package/dist/streaming/monitor.js +47 -37
  147. package/dist/streaming/monitor.js.map +1 -1
  148. package/dist/streaming/mp4Parser.d.ts +29 -4
  149. package/dist/streaming/mp4Parser.js +49 -7
  150. package/dist/streaming/mp4Parser.js.map +1 -1
  151. package/dist/streaming/playlistBuilder.d.ts +1 -2
  152. package/dist/streaming/playlistBuilder.js +2 -3
  153. package/dist/streaming/playlistBuilder.js.map +1 -1
  154. package/dist/streaming/preroll.d.ts +43 -16
  155. package/dist/streaming/preroll.js +112 -62
  156. package/dist/streaming/preroll.js.map +1 -1
  157. package/dist/streaming/pretune.d.ts +2 -2
  158. package/dist/streaming/pretune.js +11 -7
  159. package/dist/streaming/pretune.js.map +1 -1
  160. package/dist/streaming/recovery.d.ts +29 -2
  161. package/dist/streaming/recovery.js +43 -4
  162. package/dist/streaming/recovery.js.map +1 -1
  163. package/dist/streaming/registry.d.ts +13 -10
  164. package/dist/streaming/registry.js +6 -5
  165. package/dist/streaming/registry.js.map +1 -1
  166. package/dist/streaming/setup.d.ts +29 -20
  167. package/dist/streaming/setup.js +181 -170
  168. package/dist/streaming/setup.js.map +1 -1
  169. package/dist/streaming/showInfo.d.ts +24 -12
  170. package/dist/streaming/showInfo.js +120 -113
  171. package/dist/streaming/showInfo.js.map +1 -1
  172. package/dist/streaming/statusEmitter.d.ts +15 -10
  173. package/dist/streaming/statusEmitter.js +24 -20
  174. package/dist/streaming/statusEmitter.js.map +1 -1
  175. package/dist/types/config.d.ts +24 -13
  176. package/dist/types/config.js +5 -1
  177. package/dist/types/config.js.map +1 -1
  178. package/dist/types/index.d.ts +3 -2
  179. package/dist/types/index.js +2 -1
  180. package/dist/types/index.js.map +1 -1
  181. package/dist/types/profiles.d.ts +2 -2
  182. package/dist/types/selection.d.ts +12 -10
  183. package/dist/types/streaming.d.ts +12 -5
  184. package/dist/types/streaming.js +12 -5
  185. package/dist/types/streaming.js.map +1 -1
  186. package/dist/utils/debugFilter.d.ts +3 -2
  187. package/dist/utils/debugFilter.js +7 -5
  188. package/dist/utils/debugFilter.js.map +1 -1
  189. package/dist/{hdhr → utils}/deviceId.d.ts +1 -1
  190. package/dist/{hdhr → utils}/deviceId.js +11 -29
  191. package/dist/utils/deviceId.js.map +1 -0
  192. package/dist/utils/errors.d.ts +7 -0
  193. package/dist/utils/errors.js +12 -3
  194. package/dist/utils/errors.js.map +1 -1
  195. package/dist/utils/fileLogger.d.ts +23 -12
  196. package/dist/utils/fileLogger.js +73 -41
  197. package/dist/utils/fileLogger.js.map +1 -1
  198. package/dist/utils/httpErrors.d.ts +13 -0
  199. package/dist/utils/httpErrors.js +22 -0
  200. package/dist/utils/httpErrors.js.map +1 -0
  201. package/dist/utils/index.d.ts +3 -0
  202. package/dist/utils/index.js +3 -0
  203. package/dist/utils/index.js.map +1 -1
  204. package/dist/utils/logger.d.ts +9 -8
  205. package/dist/utils/logger.js +64 -20
  206. package/dist/utils/logger.js.map +1 -1
  207. package/dist/utils/markup.js +8 -3
  208. package/dist/utils/markup.js.map +1 -1
  209. package/dist/utils/plainObject.d.ts +6 -0
  210. package/dist/utils/plainObject.js +18 -0
  211. package/dist/utils/plainObject.js.map +1 -0
  212. package/dist/utils/runtimeIdentity.context.js +1 -29
  213. package/dist/utils/runtimeIdentity.context.js.map +1 -1
  214. package/dist/utils/runtimeIdentity.d.ts +17 -6
  215. package/dist/utils/runtimeIdentity.js +50 -17
  216. package/dist/utils/runtimeIdentity.js.map +1 -1
  217. package/package.json +5 -5
  218. package/dist/hdhr/deviceId.js.map +0 -1
@@ -7,46 +7,19 @@
7
7
  *
8
8
  * - Variant entries with a canonicalKey (in channels.json) reference a canonical that exists in PREDEFINED_CHANNELS or the user's stored channels.
9
9
  * - User domain mappings (in profiles.json) reference profiles that exist as builtin or user-defined.
10
- * - The service tag filter (in config.json's channels.enabledServices) contains only recognized service tags.
11
10
  *
12
- * Each issue is logged loudly and, when an auto-fix is provided, applied immediately. Auto-fixes that need to mutate persistent state go through the same
13
- * mutate* functions as user code so the integrity validators and snapshot machinery cover them too.
11
+ * The probe reports what an operator must act on and changes nothing: each issue is logged, because the right repair depends on what the operator intended. A
12
+ * rule the running process can enforce on its own belongs where the process applies it - an unknown service tag never reaches the running filter because the
13
+ * services module restricts the filter itself - rather than here.
14
14
  *
15
15
  * Adding a new check is a single function returning ConsistencyIssue[]; collectConsistencyIssues calls each registered check function and aggregates the
16
16
  * results into one array.
17
17
  */
18
- import { LOG, formatError } from "../utils/index.js";
19
- import { getAllServiceTags, mutateEnabledServices } from "./services.js";
20
18
  import { getUserDomains, getUserProfiles } from "./userProfiles.js";
21
- import { CONFIG } from "./index.js";
19
+ import { LOG } from "../utils/index.js";
22
20
  import { PREDEFINED_CHANNELS } from "../channels/index.js";
23
21
  import { getBuiltinProfile } from "./sites.js";
24
22
  import { getStoredUserChannels } from "./userChannels.js";
25
- /**
26
- * Validates that every service tag in CONFIG.channels.enabledServices is recognized, and when unknown tags remain its auto-fix persists the cleaned list through
27
- * mutateEnabledServices. In practice initializeUserChannels already strips unrecognized tags from the in-memory CONFIG.channels.enabledServices before the probe
28
- * runs - a memory-only cleanup that does not rewrite config.json - so the probe usually sees a clean list and the persisting auto-fix does not fire.
29
- */
30
- function checkServiceTagFilter() {
31
- if (CONFIG.channels.enabledServices.length === 0) {
32
- return [];
33
- }
34
- const knownTags = new Set(getAllServiceTags().map((tag) => tag.tag));
35
- const enabledSet = new Set(CONFIG.channels.enabledServices);
36
- const invalid = [...enabledSet.difference(knownTags)];
37
- if (invalid.length === 0) {
38
- return [];
39
- }
40
- return [{
41
- autoFix: async () => {
42
- // mutateEnabledServices persists the cleaned list to config.json and updates the in-memory cache atomically.
43
- await mutateEnabledServices([...enabledSet.intersection(knownTags)]);
44
- },
45
- category: "unknown-service-tag",
46
- description: "Service filter contains unrecognized tag(s): " + invalid.join(", "),
47
- severity: "warning"
48
- }];
49
- }
50
23
  /**
51
24
  * Validates that every variant entry's canonicalKey points at a channel that exists either in the predefined catalog or the user's stored channels. Dangling
52
25
  * canonical references usually mean the user deleted the canonical without cleaning the variants up; we surface for operator action rather than auto-fixing
@@ -101,16 +74,13 @@ function checkDomainProfiles() {
101
74
  */
102
75
  function collectConsistencyIssues() {
103
76
  return [
104
- ...checkServiceTagFilter(),
105
77
  ...checkVariantCanonicals(),
106
78
  ...checkDomainProfiles()
107
79
  ];
108
80
  }
109
81
  /**
110
- * Runs the consistency probe at startup. Logs every issue, runs auto-fixes for warnings, and surfaces errors for operator review. Errors do not block startup
111
- * - a consistency error is recoverable runtime state, not an unbootable system. Operators see them in the log and can act before the next restart.
112
- *
113
- * Auto-fix failures are themselves logged but do not propagate. The probe is best-effort hygiene; a failure here must not bring down the server.
82
+ * Runs the consistency probe at startup. Logs every issue at its severity and changes nothing, so an operator sees in the log what needs their action before the
83
+ * next restart. Errors do not block startup - a consistency error is recoverable runtime state, not an unbootable system.
114
84
  */
115
85
  export async function runConsistencyProbeAtStartup() {
116
86
  const issues = collectConsistencyIssues();
@@ -119,8 +89,7 @@ export async function runConsistencyProbeAtStartup() {
119
89
  }
120
90
  for (const issue of issues) {
121
91
  const message = "Consistency probe (" + issue.category + ", " + issue.severity + "): " + issue.description;
122
- // Defensive: no current checker emits severity:"error" - every check returns "warning" issues. The branch exists so a future check that needs operator
123
- // attention rather than auto-cleanup can mark itself error and surface accordingly. Add a test to assert this behavior once an error-severity check exists.
92
+ // An error-severity issue is logged at error, so a check whose issue needs the operator before the next restart surfaces accordingly.
124
93
  if (issue.severity === "error") {
125
94
  LOG.error(message);
126
95
  }
@@ -128,19 +97,7 @@ export async function runConsistencyProbeAtStartup() {
128
97
  LOG.warn(message);
129
98
  }
130
99
  }
131
- // Run auto-fixes in parallel via Promise.allSettled - each fix is independent and a failure on one must not block the others. We iterate the eligible issues
132
- // and look up each settlement by index (length-paired by construction; Promise.allSettled preserves input order and arity), logging rejected reasons as
133
- // warnings while leaving successful fixes intact.
134
- const eligible = issues.filter((issue) => (issue.severity === "warning") && issue.autoFix);
135
- const results = await Promise.allSettled(eligible.map(async (issue) => issue.autoFix?.()));
136
- for (const [index, issue] of eligible.entries()) {
137
- const result = results[index];
138
- if (result?.status === "rejected") {
139
- LOG.warn("Consistency probe auto-fix failed for %s: %s.", issue.category, formatError(result.reason));
140
- }
141
- }
142
- // Defensive: paired with the per-issue severity dispatch above. No checker currently emits severity:"error", so this aggregate report is unreachable today;
143
- // it remains in place so a future error-severity check produces the operator-visible summary line without any further wiring.
100
+ // Paired with the per-issue severity dispatch above: any error-severity issue also produces one operator-visible summary line counting them.
144
101
  const errors = issues.filter((issue) => issue.severity === "error").length;
145
102
  if (errors > 0) {
146
103
  LOG.error("Consistency probe found %d error(s) requiring operator review.", errors);
@@ -1 +1 @@
1
- {"version":3,"file":"consistencyProbe.js","sourceRoot":"","sources":["../../src/config/consistencyProbe.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AACH,OAAO,EAAE,GAAG,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,EAAE,iBAAiB,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AACzE,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpE,OAAO,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAEpC,OAAO,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAC/C,OAAO,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAC;AAqB1D;;;;GAIG;AACH,SAAS,qBAAqB;IAE5B,IAAG,MAAM,CAAC,QAAQ,CAAC,eAAe,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAEhD,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC,iBAAiB,EAAE,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;IACrE,MAAM,UAAU,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,eAAe,CAAC,CAAC;IAC5D,MAAM,OAAO,GAAG,CAAC,GAAG,UAAU,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC;IAEtD,IAAG,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAExB,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,OAAO,CAAC;YAEN,OAAO,EAAE,KAAK,IAAmB,EAAE;gBAEjC,6GAA6G;gBAC7G,MAAM,qBAAqB,CAAC,CAAC,GAAG,UAAU,CAAC,YAAY,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;YACvE,CAAC;YACD,QAAQ,EAAE,qBAAqB;YAC/B,WAAW,EAAE,+CAA+C,GAAG,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC;YACjF,QAAQ,EAAE,SAAS;SACpB,CAAC,CAAC;AACL,CAAC;AAED;;;;GAIG;AACH,SAAS,sBAAsB;IAE7B,MAAM,MAAM,GAAuB,EAAE,CAAC;IACtC,MAAM,MAAM,GAAG,qBAAqB,EAAE,CAAC;IAEvC,KAAI,MAAM,CAAE,GAAG,EAAE,KAAK,CAAE,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QAEnD,MAAM,YAAY,GAAI,KAAiB,CAAC,YAAY,CAAC;QAErD,IAAG,CAAC,YAAY,EAAE,CAAC;YAEjB,SAAS;QACX,CAAC;QAED,IAAG,mBAAmB,CAAC,YAAY,CAAC,IAAI,MAAM,CAAC,YAAY,CAAC,EAAE,CAAC;YAE7D,SAAS;QACX,CAAC;QAED,MAAM,CAAC,IAAI,CAAC;YAEV,QAAQ,EAAE,4BAA4B;YACtC,WAAW,EAAE,WAAW,GAAG,GAAG,GAAG,kCAAkC,GAAG,YAAY,GAAG,IAAI;YACzF,QAAQ,EAAE,SAAS;SACpB,CAAC,CAAC;IACL,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;GAEG;AACH,SAAS,mBAAmB;IAE1B,MAAM,MAAM,GAAuB,EAAE,CAAC;IACtC,MAAM,WAAW,GAAG,cAAc,EAAE,CAAC;IACrC,MAAM,YAAY,GAAG,eAAe,EAAE,CAAC;IAEvC,KAAI,MAAM,CAAE,MAAM,EAAE,MAAM,CAAE,IAAI,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,CAAC;QAE5D,MAAM,UAAU,GAAG,MAAM,CAAC,OAAO,CAAC;QAElC,IAAG,CAAC,UAAU,EAAE,CAAC;YAEf,SAAS;QACX,CAAC;QAED,0JAA0J;QAC1J,+IAA+I;QAC/I,IAAG,iBAAiB,CAAC,UAAU,CAAC,IAAI,YAAY,CAAC,UAAU,CAAC,EAAE,CAAC;YAE7D,SAAS;QACX,CAAC;QAED,MAAM,CAAC,IAAI,CAAC;YAEV,QAAQ,EAAE,yBAAyB;YACnC,WAAW,EAAE,UAAU,GAAG,MAAM,GAAG,gCAAgC,GAAG,UAAU,GAAG,IAAI;YACvF,QAAQ,EAAE,SAAS;SACpB,CAAC,CAAC;IACL,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;GAEG;AACH,SAAS,wBAAwB;IAE/B,OAAO;QAEL,GAAG,qBAAqB,EAAE;QAC1B,GAAG,sBAAsB,EAAE;QAC3B,GAAG,mBAAmB,EAAE;KACzB,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,4BAA4B;IAEhD,MAAM,MAAM,GAAG,wBAAwB,EAAE,CAAC;IAE1C,IAAG,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAEvB,OAAO;IACT,CAAC;IAED,KAAI,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAE1B,MAAM,OAAO,GAAG,qBAAqB,GAAG,KAAK,CAAC,QAAQ,GAAG,IAAI,GAAG,KAAK,CAAC,QAAQ,GAAG,KAAK,GAAG,KAAK,CAAC,WAAW,CAAC;QAE3G,uJAAuJ;QACvJ,4JAA4J;QAC5J,IAAG,KAAK,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;YAE9B,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QACrB,CAAC;aAAM,CAAC;YAEN,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACpB,CAAC;IACH,CAAC;IAED,6JAA6J;IAC7J,wJAAwJ;IACxJ,kDAAkD;IAClD,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,QAAQ,KAAK,SAAS,CAAC,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC;IAC3F,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,UAAU,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC;IAE3F,KAAI,MAAM,CAAE,KAAK,EAAE,KAAK,CAAE,IAAI,QAAQ,CAAC,OAAO,EAAE,EAAE,CAAC;QAEjD,MAAM,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC;QAE9B,IAAG,MAAM,EAAE,MAAM,KAAK,UAAU,EAAE,CAAC;YAEjC,GAAG,CAAC,IAAI,CAAC,+CAA+C,EAAE,KAAK,CAAC,QAAQ,EAAE,WAAW,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC;QACxG,CAAC;IACH,CAAC;IAED,4JAA4J;IAC5J,8HAA8H;IAC9H,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,MAAM,CAAC;IAE3E,IAAG,MAAM,GAAG,CAAC,EAAE,CAAC;QAEd,GAAG,CAAC,KAAK,CAAC,gEAAgE,EAAE,MAAM,CAAC,CAAC;IACtF,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"consistencyProbe.js","sourceRoot":"","sources":["../../src/config/consistencyProbe.ts"],"names":[],"mappings":"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"}
@@ -1,16 +1,25 @@
1
- import type { ApplyResult, ChangeOutcome, ConfigChange } from "./reactivity.ts";
1
+ import type { ApplyResult, ChangeRejection, ConfigChange, ConfigChangePartition } from "./reactivity.ts";
2
+ import { mutateConfigThen, readConfig } from "./userConfig.ts";
3
+ import type { ProcessFieldPath, UserConfig } from "./userConfig.ts";
2
4
  import type { Config, Nullable } from "../types/index.ts";
3
- import { mutateConfig, readConfig } from "./userConfig.ts";
4
5
  /**
5
6
  * CLI override map. Keys are dot-separated CONFIG_METADATA paths (e.g., "server.port", "paths.chromeDataDir"). Values are the parsed CLI flag values. Applied as the
6
7
  * highest-priority merge pass in mergeConfiguration().
7
8
  */
8
9
  export type CliOverrides = Record<string, unknown>;
9
10
  export interface ConfigStore {
10
- readonly mutateConfig: typeof mutateConfig;
11
+ readonly mutateConfigThen: typeof mutateConfigThen;
11
12
  readonly readConfig: typeof readConfig;
12
13
  }
13
14
  export declare let CONFIG: Config;
15
+ /**
16
+ * The error a save throws when the configuration it would write fails validation. The store writes nothing when its mutation throws, so the file, the running
17
+ * configuration and the loaded snapshot all stay as they were. Its message is the validation reason alone, complete sentences an operator can act on, so a
18
+ * route answers it as the validation error it is.
19
+ */
20
+ export declare class ConfigurationRejectedError extends Error {
21
+ name: string;
22
+ }
14
23
  /**
15
24
  * Indicates whether a user config file parse error occurred during initialization. The web UI displays a warning when this is true.
16
25
  */
@@ -21,69 +30,121 @@ export declare let configParseError: boolean;
21
30
  export declare let configParseErrorMessage: string | undefined;
22
31
  /**
23
32
  * Initializes the configuration by loading the user config file, merging with defaults, applying environment variable overrides, and applying CLI overrides. This
24
- * must be called at startup before any code accesses CONFIG. After initialization, the CONFIG object contains the final merged values.
33
+ * must be called at startup before any code accesses CONFIG. After initialization, the CONFIG object contains the final merged values. A file whose stored
34
+ * capture values need a correction, or whose HDHomeRun DeviceID the boot corrected, is written once through the store, the one write storing every correction
35
+ * the file needs, unless the store could not read the file or the configuration carries a hard error.
25
36
  * @param cliOverrides - Optional CLI flag overrides, applied at the highest priority level.
37
+ * @param io - The config store the boot reads from and makes its one correcting write through.
26
38
  */
27
39
  export declare function initializeConfiguration(cliOverrides?: CliOverrides, io?: ConfigStore): Promise<void>;
28
40
  /**
29
- * Re-reads the user config file, re-merges with the original CLI overrides, applies post-merge normalizations, commits the result to the in-memory CONFIG
30
- * binding, and dispatches the resulting diff to registered config-change handlers. This is the single entry point for "config changed - tell subsystems"; both
31
- * the /config save handler and /config/import handler call it after writing to disk. The returned ApplyResult partitions the diff into changes that were
32
- * applied live, deferred (requiring restart), or rejected (refused by a handler). Callers use the deferred count to decide whether to schedule a restart.
33
- *
34
- * Atomicity contract: failures during the read, merge, or normalize steps leave CONFIG completely untouched - the function builds the new shape in isolation
35
- * and only reassigns the live binding after all of those steps succeed. Failures DURING handler dispatch, however, occur after the CONFIG reassignment: CONFIG
36
- * already reflects the new on-disk state, but the handler chain may have run partway. The conservative answer is that handlers must not throw; they should
37
- * report outcomes (including "rejected") instead. That atomicity-on-read behavior is exercised by index.reload.test.ts.
41
+ * Returns the loaded snapshot: the configuration file as last loaded, merged and normalized exactly as the next boot would read it. Where it differs from CONFIG,
42
+ * the running process does not yet reflect the file. The settings form renders from it, so a page loaded after a save shows what is saved rather than what is
43
+ * running, and submitting that page cannot post the running value back over a change waiting for a restart.
44
+ * @returns The loaded snapshot. Callers read it and never mutate it.
45
+ */
46
+ export declare function getLoadedConfiguration(): Readonly<Config>;
47
+ /**
48
+ * Answers which saved settings the running process does not yet reflect: the gap between CONFIG and the loaded snapshot, partitioned by reactivity class. Its
49
+ * held members are the settings pending a restart, and its live and next-stream members are the settings a handler could not realize. The view covers the
50
+ * settings surface alone, the paths CONFIG_METADATA declares, because a leaf the process wrote and the loaded snapshot does not hold, which only a process
51
+ * write the file refused leaves, is the process ahead of the file rather than a save the user is waiting on. Derived on every call from CONFIG and the loaded
52
+ * snapshot, so it holds no state of its own. A reconcile publishes the snapshot only once it has committed what its handlers realized, so a caller that does
53
+ * not wait on the store's queue reads CONFIG and the snapshot as the last completed reconcile left them, and a change a save introduces is never listed as
54
+ * unrealized while its handlers are still running.
55
+ * @returns The settings-surface gap, partitioned into held, live, and next-stream changes, each carrying the running value as previous and the saved value as
56
+ * current.
57
+ */
58
+ export declare function getConfigurationGap(): ConfigChangePartition;
59
+ /**
60
+ * The one entry for a write to the settings surface - the settings save, the import, and the debug page all go through it. Inside the store's own mutation it
61
+ * applies the caller's mutator to the current file, builds the candidate exactly as the next boot would read that file, and refuses an invalid candidate by
62
+ * throwing ConfigurationRejectedError with the validation reason, so the store writes nothing. A file the store cannot parse or cannot read refuses the
63
+ * mutation inside the store the same way. Once the file is written, the save reconciles that candidate as the write's follow-up and answers with its result.
38
64
  *
39
- * Validation contract: before committing, the merged shape is re-checked against the same hard-error and capture-coercion checks the startup path enforces.
40
- * A configuration that carries a hard error (out-of-range numeric, non-absolute path, conflicting HDHR port) or would need a capture coercion (native mode, a
41
- * captureCodecs list missing the h264 baseline) is rejected rather than silently coerced: CONFIG stays on the previous valid state and every diffed change is
42
- * reported as rejected so the operator sees why nothing took effect. This closes the window where a live save could commit an un-normalized capture
43
- * configuration into the live binding without passing through validateConfiguration. The reject-on-invalid path is exercised by index.reload.test.ts.
65
+ * One queue: the store's chain serializes each write's read-modify-write together with its follow-up, a save's reconcile or a process write's commit, which
66
+ * runs while the store's queue is held, so no write reads the file while another write's reconcile or commit is running, and overlapping saves commit in the
67
+ * order their writes landed. A config-change handler never writes the configuration, because the reconcile or the process write's commit it runs inside holds
68
+ * the store's queue, and a write it awaited would wait on that queue and never settle.
69
+ * @param mutator - Applies the caller's change to the current file in place. A throw inside it writes nothing.
70
+ * @param io - The config store the save writes through.
71
+ * @returns What the reconcile realized, the restart-class changes this save holds for a restart, and the changes of this save a handler refused.
72
+ * @throws ConfigurationRejectedError when the candidate fails validation, and the store's own error when the file cannot be parsed, read, or written.
73
+ */
74
+ export declare function saveConfiguration(mutator: (current: UserConfig) => void, io?: ConfigStore): Promise<ApplyResult>;
75
+ /**
76
+ * The leaves a process write answers, keyed by the dot path of a field the process owns, so a path PROCESS_FIELDS does not declare as a state field is a
77
+ * compile error.
78
+ */
79
+ export type ProcessFieldValues = Readonly<Partial<Record<ProcessFieldPath, unknown>>>;
80
+ /**
81
+ * What a process write answers: whether the file took the write. The running configuration holds the leaves whatever the file did, so persisted false means
82
+ * the change is in effect but reverts when the process restarts, which a caller acting for the user reports to them.
83
+ */
84
+ export interface ProcessWriteResult {
85
+ readonly persisted: boolean;
86
+ }
87
+ /**
88
+ * The operation for every field the process owns, the leaves the settings form never writes: the setup flag, the disabled predefined channels, the display
89
+ * preferences, the service list, and the discovered DVR host. Inside the store's own mutation it answers the leaves from the file the store just read and sets
90
+ * each on that file, and once the write has landed its follow-up commits exactly those leaves: their handlers are dispatched whatever CONFIG held before, and
91
+ * each leaf is set on CONFIG and then on the loaded snapshot. It builds no candidate and validates nothing beyond the store's own write normalization, because
92
+ * the process already holds the values it writes, and every other difference between CONFIG and the file, a hand edit or a refused setting among them, stays
93
+ * for the next settings save to reconcile and report.
44
94
  *
45
- * Serialization contract: calls are serialized on a module-level queue, so overlapping reloads read and commit in call order and the last reload to run always
46
- * reads a snapshot at least as fresh as every write that preceded its call. A failed reload rejects to its own caller without breaking the chain for later
47
- * ones. This extends the handler contract: a registered config-change handler must never call reloadConfiguration, because a queued reload awaiting a nested
48
- * reload would deadlock the chain.
49
- * @returns The aggregate result of dispatching the diff.
50
- */
51
- export declare function reloadConfiguration(io?: ConfigStore): Promise<ApplyResult>;
52
- /**
53
- * Live-applies the "logging." subset of a config diff. The debug filter is applied live by commitDebugFilter during reloadConfiguration - the runtime filter is
54
- * updated right after CONFIG is committed and before the diff dispatches - so it reports applied with no restart, which is what lets a debug-filter change take
55
- * effect immediately instead of waiting for one. The remaining logging fields (httpLogLevel, maxSize) are consumed when the logger and HTTP middleware are wired
56
- * at startup, so they defer to a restart.
95
+ * When the store refuses the write - it could not read or parse the file, or the callback, the write, or its readback failed - the leaves are answered again
96
+ * from the running configuration, one warning names them with the store's error, and they are committed to CONFIG alone; the operation resolves with persisted
97
+ * false, because the process owns the value and the file is only its record. The warning comes before the commit so a commit that throws propagates with the
98
+ * store's error already on record. A readback that fails is such a refusal though the file may hold the leaves, and the loaded snapshot takes them at the
99
+ * next settings save that lands. A rejection that arrives once the follow-up has begun is rethrown instead, because that write has landed: committing and
100
+ * dispatching the leaves a second time would log a refusal the file never made.
57
101
  *
58
- * Exported so tests can invoke the dispatch directly with a synthetic diff. Registered with the reactivity primitive at module load (side effect below).
59
- * @param changes - The subset of the diff whose path begins with "logging.".
60
- * @returns Per-change outcomes.
102
+ * A caller's fields answers from its argument alone and changes nothing it reaches, because it may run twice, once on the file the store read and once on the
103
+ * clone of CONFIG the refused path hands it, and Readonly holds only its argument's top level. A handler for a process field never writes the configuration,
104
+ * because the commit it runs inside holds the store's queue; a handler that refuses a process leaf leaves it committed regardless.
105
+ * @param fields - Answers the leaves to write, keyed by path, from the stored configuration it is handed.
106
+ * @param io - The config store the write goes through.
107
+ * @returns Whether the file took the write: persisted is true once the write has landed and false when the store refused it.
108
+ * @throws Whatever a follow-up that has begun rejects with, such as the class resolver's error for a leaf no setting or state entry classifies, and whatever
109
+ * the refused path's commit throws once its warning is logged.
61
110
  */
62
- export declare function applyLoggingConfigChanges(changes: readonly ConfigChange[]): Promise<readonly ChangeOutcome[]>;
111
+ export declare function writeProcessFields(fields: (stored: Readonly<UserConfig>) => ProcessFieldValues, io?: ConfigStore): Promise<ProcessWriteResult>;
112
+ /**
113
+ * Realizes a change to the persisted debug filter: the candidate's filter becomes the runtime filter unless an env or CLI source owns it. Applying a filter
114
+ * cannot fail, so the handler refuses nothing. It is exported, as every module-registered handler is, so a suite that resets the registry re-registers it.
115
+ * @param _changes - The change under the handler's path; the candidate carries the filter, so the handler reads it there instead.
116
+ * @param next - The candidate running configuration.
117
+ * @returns No rejections.
118
+ */
119
+ export declare function applyDebugFilterChange(_changes: readonly ConfigChange[], next: Readonly<Config>): Promise<readonly ChangeRejection[]>;
63
120
  /**
64
121
  * Returns a deep copy of the default configuration. Used by the web UI to display default values and handle reset operations.
65
122
  * @returns A copy of the default configuration.
66
123
  */
67
124
  export declare function getDefaults(): Config;
68
125
  /**
69
- * Validates that a configuration value is a positive integer within an optional range. This helper performs the common validation pattern of checking for valid
70
- * integers and enforcing minimum/maximum bounds. It returns an error message if validation fails, allowing the caller to collect all errors before reporting them.
71
- * @param name - The configuration name for error messages, typically the environment variable name.
72
- * @param value - The value to validate, typically parsed from an environment variable.
73
- * @param min - Optional minimum allowed value (inclusive).
126
+ * Validates that a configuration value is an integer at or above its floor and at or below an optional ceiling. The floor is the minimum the setting's metadata
127
+ * declares, and 1 when none is declared, so a setting whose metadata allows zero accepts it and an integer setting with no declared minimum stays positive. It
128
+ * returns an error message rather than throwing, so the caller can collect every error before reporting them. Every message is a complete sentence naming the
129
+ * value it refused, and a value below the floor draws a message naming the floor it applied, because a save joins the messages into the reason it answers with.
130
+ * @param name - The configuration name for error messages, typically the environment variable name or the setting's label.
131
+ * @param value - The value to validate.
132
+ * @param min - The declared minimum (inclusive). When it is omitted, the floor is 1.
74
133
  * @param max - Optional maximum allowed value (inclusive).
75
134
  * @returns Error message if invalid, null if valid.
76
135
  */
77
- export declare function validatePositiveInt(name: string, value: number, min?: number, max?: number): Nullable<string>;
136
+ export declare function validateInteger(name: string, value: number, min?: number, max?: number): Nullable<string>;
78
137
  /**
79
- * Validates that a configuration value is a positive number (including floats) within an optional range.
138
+ * Validates that a configuration value is a number, fractional or whole, at or above its floor and at or below an optional ceiling. The floor is the minimum the
139
+ * setting's metadata declares, and when none is declared the value must be positive, so zero is accepted only where the metadata says it is. Every message is a
140
+ * complete sentence naming the value it refused and, for a value below the floor, the floor it applied.
80
141
  * @param name - The configuration name for error messages.
81
142
  * @param value - The value to validate.
82
- * @param min - Optional minimum allowed value (inclusive).
143
+ * @param min - The declared minimum (inclusive). When it is omitted, the value must be greater than zero.
83
144
  * @param max - Optional maximum allowed value (inclusive).
84
145
  * @returns Error message if invalid, null if valid.
85
146
  */
86
- export declare function validatePositiveNumber(name: string, value: number, min?: number, max?: number): Nullable<string>;
147
+ export declare function validateNumber(name: string, value: number, min?: number, max?: number): Nullable<string>;
87
148
  /** The settings whose value the server refuses to start with out of range. Each entry is a CONFIG_METADATA path, and the floor, the ceiling, and the name the
88
149
  * error reports all come from that path's metadata - the same metadata the settings form validates a save against. One declaration of a bound means a value
89
150
  * the form accepts is a value the boot accepts, and there is no second copy to fall out of step with the first.
@@ -97,21 +158,12 @@ export declare function validatePositiveNumber(name: string, value: number, min?
97
158
  */
98
159
  export declare const STARTUP_BOUNDED_SETTINGS: readonly string[];
99
160
  /**
100
- * Validates all configuration values and throws an error if any are invalid. This function runs at startup after configuration initialization. It first applies
101
- * the capture coercions in place (filtering captureCodecs, forcing FFmpeg mode, with the same operator-visible warning as before), then collects every hard
102
- * error against the coerced CONFIG and throws once with the complete list. Splitting the pure collectors (collectCoercions, collectHardErrors) from the in-place
103
- * application lets reloadConfiguration reuse the same hard-error and capture-coercion checks without silently coercing a live save.
161
+ * Validates the running configuration and throws if it carries any hard error. It runs at startup once the configuration is initialized, collects every hard
162
+ * error, and throws once with the complete list, so the operator can fix every issue in one pass. A correctable value never reaches here uncorrected, because
163
+ * the configuration is corrected as it is built.
104
164
  * @throws If any configuration value is invalid. The error message lists all invalid values.
105
165
  */
106
166
  export declare function validateConfiguration(): void;
107
- /**
108
- * Persists the capture configuration that validateConfiguration coerced at startup back to disk so the on-disk state matches the live CONFIG. A no-op unless a
109
- * coercion actually occurred. Without this, a config file holding an unsupported capture value (native mode, or a captureCodecs list missing the h264 baseline)
110
- * stays divergent from the coerced live CONFIG forever, and the reload-validation path would then reject every later save on the resulting phantom capture diff.
111
- * filterDefaults strips any value equal to its default on write, so a config coerced back to the FFmpeg/h264 defaults leaves a clean file with no capture override.
112
- * Failures degrade gracefully: the live CONFIG is already coerced, so a write failure only means the divergence persists until the next successful save or boot.
113
- */
114
- export declare function persistCoercedConfig(io?: ConfigStore): Promise<void>;
115
167
  /**
116
168
  * Displays the active configuration at startup. This helps operators verify their settings and diagnose connection issues. We log only the most commonly adjusted
117
169
  * values to keep output concise while providing useful debugging information.