@legioncodeinc/hive 0.1.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 (190) hide show
  1. package/LICENSE +661 -0
  2. package/README.md +262 -0
  3. package/dist/cli-commands.d.ts +41 -0
  4. package/dist/cli-commands.js +76 -0
  5. package/dist/cli-commands.js.map +1 -0
  6. package/dist/cli.d.ts +2 -0
  7. package/dist/cli.js +46 -0
  8. package/dist/cli.js.map +1 -0
  9. package/dist/daemon/dashboard/app.js +118 -0
  10. package/dist/daemon/dashboard/host.d.ts +90 -0
  11. package/dist/daemon/dashboard/host.js +172 -0
  12. package/dist/daemon/dashboard/host.js.map +1 -0
  13. package/dist/daemon/dashboard/web-assets.d.ts +88 -0
  14. package/dist/daemon/dashboard/web-assets.js +195 -0
  15. package/dist/daemon/dashboard/web-assets.js.map +1 -0
  16. package/dist/daemon/fleet-status.d.ts +15 -0
  17. package/dist/daemon/fleet-status.js +56 -0
  18. package/dist/daemon/fleet-status.js.map +1 -0
  19. package/dist/daemon/gate.d.ts +55 -0
  20. package/dist/daemon/gate.js +128 -0
  21. package/dist/daemon/gate.js.map +1 -0
  22. package/dist/daemon/proxy.d.ts +38 -0
  23. package/dist/daemon/proxy.js +126 -0
  24. package/dist/daemon/proxy.js.map +1 -0
  25. package/dist/daemon/registry.d.ts +31 -0
  26. package/dist/daemon/registry.js +120 -0
  27. package/dist/daemon/registry.js.map +1 -0
  28. package/dist/daemon/server.d.ts +41 -0
  29. package/dist/daemon/server.js +126 -0
  30. package/dist/daemon/server.js.map +1 -0
  31. package/dist/daemon/setup-auth.d.ts +37 -0
  32. package/dist/daemon/setup-auth.js +51 -0
  33. package/dist/daemon/setup-auth.js.map +1 -0
  34. package/dist/daemon/telemetry-proxy.d.ts +47 -0
  35. package/dist/daemon/telemetry-proxy.js +63 -0
  36. package/dist/daemon/telemetry-proxy.js.map +1 -0
  37. package/dist/dashboard/contracts.d.ts +235 -0
  38. package/dist/dashboard/contracts.js +43 -0
  39. package/dist/dashboard/contracts.js.map +1 -0
  40. package/dist/dashboard/web/app.d.ts +44 -0
  41. package/dist/dashboard/web/app.js +179 -0
  42. package/dist/dashboard/web/app.js.map +1 -0
  43. package/dist/dashboard/web/boot-route.d.ts +23 -0
  44. package/dist/dashboard/web/boot-route.js +29 -0
  45. package/dist/dashboard/web/boot-route.js.map +1 -0
  46. package/dist/dashboard/web/build-graph-button.d.ts +46 -0
  47. package/dist/dashboard/web/build-graph-button.js +81 -0
  48. package/dist/dashboard/web/build-graph-button.js.map +1 -0
  49. package/dist/dashboard/web/buzzing-screen.d.ts +30 -0
  50. package/dist/dashboard/web/buzzing-screen.js +135 -0
  51. package/dist/dashboard/web/buzzing-screen.js.map +1 -0
  52. package/dist/dashboard/web/folder-picker.d.ts +54 -0
  53. package/dist/dashboard/web/folder-picker.js +125 -0
  54. package/dist/dashboard/web/folder-picker.js.map +1 -0
  55. package/dist/dashboard/web/graph-layout.d.ts +101 -0
  56. package/dist/dashboard/web/graph-layout.js +0 -0
  57. package/dist/dashboard/web/graph-layout.js.map +1 -0
  58. package/dist/dashboard/web/harness-strip.d.ts +38 -0
  59. package/dist/dashboard/web/harness-strip.js +65 -0
  60. package/dist/dashboard/web/harness-strip.js.map +1 -0
  61. package/dist/dashboard/web/health-rail.d.ts +26 -0
  62. package/dist/dashboard/web/health-rail.js +61 -0
  63. package/dist/dashboard/web/health-rail.js.map +1 -0
  64. package/dist/dashboard/web/main.d.ts +22 -0
  65. package/dist/dashboard/web/main.js +51 -0
  66. package/dist/dashboard/web/main.js.map +1 -0
  67. package/dist/dashboard/web/needs-project.d.ts +51 -0
  68. package/dist/dashboard/web/needs-project.js +69 -0
  69. package/dist/dashboard/web/needs-project.js.map +1 -0
  70. package/dist/dashboard/web/page-frame.d.ts +95 -0
  71. package/dist/dashboard/web/page-frame.js +98 -0
  72. package/dist/dashboard/web/page-frame.js.map +1 -0
  73. package/dist/dashboard/web/pages/coming-soon.d.ts +23 -0
  74. package/dist/dashboard/web/pages/coming-soon.js +19 -0
  75. package/dist/dashboard/web/pages/coming-soon.js.map +1 -0
  76. package/dist/dashboard/web/pages/dashboard.d.ts +32 -0
  77. package/dist/dashboard/web/pages/dashboard.js +205 -0
  78. package/dist/dashboard/web/pages/dashboard.js.map +1 -0
  79. package/dist/dashboard/web/pages/graph.d.ts +72 -0
  80. package/dist/dashboard/web/pages/graph.js +362 -0
  81. package/dist/dashboard/web/pages/graph.js.map +1 -0
  82. package/dist/dashboard/web/pages/harnesses.d.ts +65 -0
  83. package/dist/dashboard/web/pages/harnesses.js +210 -0
  84. package/dist/dashboard/web/pages/harnesses.js.map +1 -0
  85. package/dist/dashboard/web/pages/health.d.ts +22 -0
  86. package/dist/dashboard/web/pages/health.js +91 -0
  87. package/dist/dashboard/web/pages/health.js.map +1 -0
  88. package/dist/dashboard/web/pages/lifecycle-panel.d.ts +60 -0
  89. package/dist/dashboard/web/pages/lifecycle-panel.js +187 -0
  90. package/dist/dashboard/web/pages/lifecycle-panel.js.map +1 -0
  91. package/dist/dashboard/web/pages/logs.d.ts +55 -0
  92. package/dist/dashboard/web/pages/logs.js +311 -0
  93. package/dist/dashboard/web/pages/logs.js.map +1 -0
  94. package/dist/dashboard/web/pages/memories.d.ts +35 -0
  95. package/dist/dashboard/web/pages/memories.js +439 -0
  96. package/dist/dashboard/web/pages/memories.js.map +1 -0
  97. package/dist/dashboard/web/pages/projects.d.ts +38 -0
  98. package/dist/dashboard/web/pages/projects.js +325 -0
  99. package/dist/dashboard/web/pages/projects.js.map +1 -0
  100. package/dist/dashboard/web/pages/roi-chart.d.ts +52 -0
  101. package/dist/dashboard/web/pages/roi-chart.js +133 -0
  102. package/dist/dashboard/web/pages/roi-chart.js.map +1 -0
  103. package/dist/dashboard/web/pages/roi.d.ts +93 -0
  104. package/dist/dashboard/web/pages/roi.js +375 -0
  105. package/dist/dashboard/web/pages/roi.js.map +1 -0
  106. package/dist/dashboard/web/pages/settings.d.ts +103 -0
  107. package/dist/dashboard/web/pages/settings.js +420 -0
  108. package/dist/dashboard/web/pages/settings.js.map +1 -0
  109. package/dist/dashboard/web/pages/sync.d.ts +59 -0
  110. package/dist/dashboard/web/pages/sync.js +280 -0
  111. package/dist/dashboard/web/pages/sync.js.map +1 -0
  112. package/dist/dashboard/web/panels.d.ts +178 -0
  113. package/dist/dashboard/web/panels.js +471 -0
  114. package/dist/dashboard/web/panels.js.map +1 -0
  115. package/dist/dashboard/web/primitives.d.ts +80 -0
  116. package/dist/dashboard/web/primitives.js +208 -0
  117. package/dist/dashboard/web/primitives.js.map +1 -0
  118. package/dist/dashboard/web/readiness-splash.d.ts +39 -0
  119. package/dist/dashboard/web/readiness-splash.js +201 -0
  120. package/dist/dashboard/web/readiness-splash.js.map +1 -0
  121. package/dist/dashboard/web/registry.d.ts +96 -0
  122. package/dist/dashboard/web/registry.js +99 -0
  123. package/dist/dashboard/web/registry.js.map +1 -0
  124. package/dist/dashboard/web/router.d.ts +48 -0
  125. package/dist/dashboard/web/router.js +76 -0
  126. package/dist/dashboard/web/router.js.map +1 -0
  127. package/dist/dashboard/web/scope-context.d.ts +155 -0
  128. package/dist/dashboard/web/scope-context.js +266 -0
  129. package/dist/dashboard/web/scope-context.js.map +1 -0
  130. package/dist/dashboard/web/service-icons.d.ts +33 -0
  131. package/dist/dashboard/web/service-icons.js +80 -0
  132. package/dist/dashboard/web/service-icons.js.map +1 -0
  133. package/dist/dashboard/web/setup-gate.d.ts +116 -0
  134. package/dist/dashboard/web/setup-gate.js +272 -0
  135. package/dist/dashboard/web/setup-gate.js.map +1 -0
  136. package/dist/dashboard/web/sidebar.d.ts +63 -0
  137. package/dist/dashboard/web/sidebar.js +91 -0
  138. package/dist/dashboard/web/sidebar.js.map +1 -0
  139. package/dist/dashboard/web/use-fleet-telemetry.d.ts +111 -0
  140. package/dist/dashboard/web/use-fleet-telemetry.js +278 -0
  141. package/dist/dashboard/web/use-fleet-telemetry.js.map +1 -0
  142. package/dist/dashboard/web/wire.d.ts +1937 -0
  143. package/dist/dashboard/web/wire.js +1837 -0
  144. package/dist/dashboard/web/wire.js.map +1 -0
  145. package/dist/errors.d.ts +5 -0
  146. package/dist/errors.js +11 -0
  147. package/dist/errors.js.map +1 -0
  148. package/dist/install/registry.d.ts +35 -0
  149. package/dist/install/registry.js +110 -0
  150. package/dist/install/registry.js.map +1 -0
  151. package/dist/lock.d.ts +10 -0
  152. package/dist/lock.js +87 -0
  153. package/dist/lock.js.map +1 -0
  154. package/dist/service/commands.d.ts +15 -0
  155. package/dist/service/commands.js +49 -0
  156. package/dist/service/commands.js.map +1 -0
  157. package/dist/service/index.d.ts +38 -0
  158. package/dist/service/index.js +174 -0
  159. package/dist/service/index.js.map +1 -0
  160. package/dist/service/platform.d.ts +37 -0
  161. package/dist/service/platform.js +67 -0
  162. package/dist/service/platform.js.map +1 -0
  163. package/dist/service/templates.d.ts +10 -0
  164. package/dist/service/templates.js +120 -0
  165. package/dist/service/templates.js.map +1 -0
  166. package/dist/shared/constants.d.ts +15 -0
  167. package/dist/shared/constants.js +19 -0
  168. package/dist/shared/constants.js.map +1 -0
  169. package/dist/shared/daemon-routing.d.ts +11 -0
  170. package/dist/shared/daemon-routing.js +38 -0
  171. package/dist/shared/daemon-routing.js.map +1 -0
  172. package/dist/shared/fleet-readiness.d.ts +18 -0
  173. package/dist/shared/fleet-readiness.js +9 -0
  174. package/dist/shared/fleet-readiness.js.map +1 -0
  175. package/dist/shared/fleet-telemetry.d.ts +68 -0
  176. package/dist/shared/fleet-telemetry.js +61 -0
  177. package/dist/shared/fleet-telemetry.js.map +1 -0
  178. package/dist/shared/lifecycle-flags.d.ts +34 -0
  179. package/dist/shared/lifecycle-flags.js +39 -0
  180. package/dist/shared/lifecycle-flags.js.map +1 -0
  181. package/dist/shared/memory-types.d.ts +55 -0
  182. package/dist/shared/memory-types.js +75 -0
  183. package/dist/shared/memory-types.js.map +1 -0
  184. package/dist/shared/service-status.d.ts +82 -0
  185. package/dist/shared/service-status.js +97 -0
  186. package/dist/shared/service-status.js.map +1 -0
  187. package/dist/telemetry/emit.d.ts +197 -0
  188. package/dist/telemetry/emit.js +196 -0
  189. package/dist/telemetry/emit.js.map +1 -0
  190. package/package.json +50 -0
@@ -0,0 +1,278 @@
1
+ /**
2
+ * The SHARED fleet-telemetry view-model hook — hive PRD-004/PRD-005. One hook, consumed by
3
+ * `/buzzing` (PRD-004a), the health rail (PRD-005a), and the `/health` page (PRD-005b/PRD-005c),
4
+ * so the SSE-first/REST-fallback wiring, the registered-name enumeration, and the bounded log
5
+ * ring buffer are each written exactly once (per the implementation brief), not duplicated per
6
+ * consumer.
7
+ *
8
+ * Sourcing precedence (bz-AC-4/bz-AC-5/bz-AC-6, hr-AC-3/hr-AC-4/hr-AC-5):
9
+ * 1. `EventSource("/api/telemetry/stream")` — the same-origin relay of doctor's real SSE
10
+ * stream (`telemetry-proxy.ts`). Live, near-real-time. `EventSource` auto-reconnects on its
11
+ * own after a drop (the browser's built-in behavior), so "resumes without a manual refresh"
12
+ * falls out of the platform rather than hand-rolled reconnect logic.
13
+ * 2. `GET /api/fleet-status` (PRD-002a), polled — the fail-soft fallback the whole time SSE is
14
+ * unavailable/erroring. Coarser (no metrics/Deep Lake/lastSeen), but keeps every tile/pill
15
+ * rendering rather than blanking.
16
+ *
17
+ * Every state-mutating step below is a PURE, exported function (`applyRegisteredNames`,
18
+ * `applySseEvent`, `applyRestFallback`, `appendLogs`, `deriveServiceViews`) so the derivation and
19
+ * bookkeeping are unit-testable without a real `EventSource` (jsdom has none — the hook itself
20
+ * degrades to the REST path in that environment, exactly like `wire.ts`'s `logsStream`).
21
+ *
22
+ * Memory-bounded (parent index constraint, lg-AC-6): `logs` is a capped ring buffer
23
+ * ({@link LOG_RING_BUFFER_CAP}), oldest-dropped; `services` holds only CURRENT per-service state,
24
+ * never a history series (hr-AC-7).
25
+ */
26
+ import React from "react";
27
+ import { FLEET_TELEMETRY_EVENT_NAME, parseFleetTelemetryEvent, } from "../../shared/fleet-telemetry.js";
28
+ import { deriveServiceState, fromFleetDaemonStatus, fromFleetServiceModel, nextFirstActiveAt, } from "../../shared/service-status.js";
29
+ // ─────────────────────────────────────────────────────────────────────────────
30
+ // Endpoints (same-origin only — hr-AC-6/sd-AC-6: the browser never reaches doctor directly).
31
+ // ─────────────────────────────────────────────────────────────────────────────
32
+ const REGISTERED_SERVICES_ENDPOINT = "/api/registered-services";
33
+ const TELEMETRY_STREAM_ENDPOINT = "/api/telemetry/stream";
34
+ const FLEET_STATUS_ENDPOINT = "/api/fleet-status";
35
+ /** How often the REST fallback polls while the SSE stream is unavailable (ms). */
36
+ const DEFAULT_REST_POLL_MS = 2000;
37
+ /** The bounded log ring-buffer cap (lg-AC-6/lg-AC-8): older lines drop rather than accumulate. */
38
+ export const LOG_RING_BUFFER_CAP = 500;
39
+ export const EMPTY_FLEET_TELEMETRY_VIEW = { services: [], logs: [], source: "none", asOf: null };
40
+ /** The initial, empty state before any registration/telemetry has arrived. */
41
+ export function createInitialTelemetryState(registeredNames = []) {
42
+ return { registeredNames, services: new Map(), logs: [], source: "none", asOf: null };
43
+ }
44
+ /** Union a freshly-observed name into the tracked registered set, preserving first-seen order. */
45
+ function withKnownName(names, name) {
46
+ return names.includes(name) ? names : [...names, name];
47
+ }
48
+ /**
49
+ * Merge the full registered-name enumeration (`GET /api/registered-services`) into state
50
+ * (bz-AC-1/bz-AC-2, hr-AC-1). Never drops a name already tracked from telemetry that this
51
+ * enumeration happens not to list (defense against a stale/partial registry read).
52
+ */
53
+ export function applyRegisteredNames(state, names) {
54
+ let next = state.registeredNames;
55
+ for (const name of names)
56
+ next = withKnownName(next, name);
57
+ return next === state.registeredNames ? state : { ...state, registeredNames: next };
58
+ }
59
+ /** Append new log lines, capped at {@link LOG_RING_BUFFER_CAP} with the OLDEST dropped first (lg-AC-6/lg-AC-8). */
60
+ export function appendLogs(existing, incoming) {
61
+ if (incoming.length === 0)
62
+ return existing;
63
+ const merged = [...existing, ...incoming];
64
+ return merged.length > LOG_RING_BUFFER_CAP ? merged.slice(merged.length - LOG_RING_BUFFER_CAP) : merged;
65
+ }
66
+ /** Apply one live `fleet-telemetry` SSE event (bz-AC-4, hr-AC-3, sd-AC-8/sd-AC-9 per-service isolation). */
67
+ export function applySseEvent(state, event, now) {
68
+ let names = state.registeredNames;
69
+ const services = new Map(state.services);
70
+ for (const model of event.services) {
71
+ names = withKnownName(names, model.name);
72
+ const signal = fromFleetServiceModel(model);
73
+ const previous = services.get(model.name);
74
+ services.set(model.name, {
75
+ signal,
76
+ metrics: model.metrics,
77
+ deeplake: model.deeplake,
78
+ firstActiveAt: nextFirstActiveAt(model.health, previous?.firstActiveAt ?? null, now),
79
+ });
80
+ }
81
+ return {
82
+ registeredNames: names,
83
+ services,
84
+ logs: appendLogs(state.logs, event.logs),
85
+ source: "sse",
86
+ asOf: event.asOf,
87
+ };
88
+ }
89
+ /**
90
+ * Apply one `GET /api/fleet-status` fail-soft projection (bz-AC-5, hr-AC-4). The coarse
91
+ * projection carries no metrics/Deep Lake/lastSeen, so existing per-service metrics/Deep Lake
92
+ * readings are RETAINED (hm-AC-10's "last known metrics") — only the derived health-driving
93
+ * signal is refreshed.
94
+ *
95
+ * The response is a SNAPSHOT, not a patch: `services` is rebuilt from `status.daemons` alone, so
96
+ * a daemon missing from a later response loses its stale `signal`/`firstActiveAt` and falls back
97
+ * to the registered-but-silent derivation (`starting`) instead of staying `active`/`degraded`
98
+ * forever. Its NAME is still retained via `registeredNames`, so the row never disappears.
99
+ */
100
+ export function applyRestFallback(state, status, now) {
101
+ if (status.supervisor !== "reachable") {
102
+ // Supervisor itself unreachable: no per-service signal to apply, but the source flips so
103
+ // consumers can show a "telemetry unavailable" fail-soft state rather than a stale "sse" label.
104
+ return { ...state, source: "rest" };
105
+ }
106
+ let names = state.registeredNames;
107
+ const services = new Map();
108
+ for (const daemon of status.daemons) {
109
+ names = withKnownName(names, daemon.name);
110
+ const signal = fromFleetDaemonStatus(daemon);
111
+ const previous = state.services.get(daemon.name);
112
+ services.set(daemon.name, {
113
+ signal,
114
+ metrics: previous?.metrics ?? {},
115
+ deeplake: previous?.deeplake ?? null,
116
+ firstActiveAt: nextFirstActiveAt(daemon.health, previous?.firstActiveAt ?? null, now),
117
+ });
118
+ }
119
+ return { registeredNames: names, services, logs: state.logs, source: "rest", asOf: status.asOf };
120
+ }
121
+ /** Build the rendered per-service views for every KNOWN name, in first-seen order (never omitted, sd-AC-2/bz-AC-2). */
122
+ export function deriveServiceViews(state, now) {
123
+ return state.registeredNames.map((name) => {
124
+ const runtime = state.services.get(name);
125
+ const derived = deriveServiceState({
126
+ signal: runtime?.signal ?? null,
127
+ now,
128
+ firstActiveAt: runtime?.firstActiveAt ?? null,
129
+ });
130
+ return {
131
+ name,
132
+ state: derived,
133
+ health: runtime?.signal.health ?? null,
134
+ lastSeen: runtime?.signal.lastSeen ?? null,
135
+ metrics: runtime?.metrics ?? {},
136
+ deeplake: runtime?.deeplake ?? null,
137
+ telemetryFault: runtime?.signal.telemetryFault ?? null,
138
+ };
139
+ });
140
+ }
141
+ /** Project internal {@link TelemetryState} into the public {@link FleetTelemetryView}. */
142
+ export function toFleetTelemetryView(state, now) {
143
+ return { services: deriveServiceViews(state, now), logs: state.logs, source: state.source, asOf: state.asOf };
144
+ }
145
+ /**
146
+ * The shared fleet-telemetry hook (see module doc for the sourcing precedence). Every consumer
147
+ * mounts its own instance; the underlying SSE/REST wiring is identical code shared via this one
148
+ * function rather than re-implemented per screen.
149
+ */
150
+ export function useFleetTelemetry(options = {}) {
151
+ const restPollMs = options.restPollMs ?? DEFAULT_REST_POLL_MS;
152
+ const [state, setState] = React.useState(() => createInitialTelemetryState());
153
+ const [now, setNow] = React.useState(() => Date.now());
154
+ // `deriveServiceState` is time-dependent (the warming grace window, the stale-`lastSeen`
155
+ // override), so the view must recompute on a clock tick too, not only on incoming data:
156
+ // a quiet-but-open SSE stream would otherwise freeze a service in `warming`, or never age a
157
+ // stale `lastSeen` into `error`, until some unrelated state update happened to re-render.
158
+ React.useEffect(() => {
159
+ const id = setInterval(() => setNow(Date.now()), 1000);
160
+ return () => clearInterval(id);
161
+ }, []);
162
+ // bz-AC-1/bz-AC-2/hr-AC-1: enumerate the FULL registered-service set once on mount, so a tile
163
+ // exists for a registered-but-silent service even before its first telemetry tick.
164
+ React.useEffect(() => {
165
+ let alive = true;
166
+ void (async () => {
167
+ try {
168
+ const response = await fetch(REGISTERED_SERVICES_ENDPOINT);
169
+ if (!response.ok)
170
+ return;
171
+ const body = (await response.json());
172
+ if (!alive || !Array.isArray(body.names))
173
+ return;
174
+ const names = body.names.filter((n) => typeof n === "string");
175
+ if (names.length > 0)
176
+ setState((current) => applyRegisteredNames(current, names));
177
+ }
178
+ catch {
179
+ // Fail soft: no enumeration; tiles simply populate as telemetry/fallback rows arrive.
180
+ }
181
+ })();
182
+ return () => {
183
+ alive = false;
184
+ };
185
+ }, []);
186
+ // The SSE-first / REST-fallback data path.
187
+ React.useEffect(() => {
188
+ let alive = true;
189
+ let restIntervalId = null;
190
+ function stopRestFallback() {
191
+ if (restIntervalId !== null) {
192
+ clearInterval(restIntervalId);
193
+ restIntervalId = null;
194
+ }
195
+ }
196
+ function startRestFallback() {
197
+ if (restIntervalId !== null)
198
+ return;
199
+ const tick = async () => {
200
+ try {
201
+ const response = await fetch(FLEET_STATUS_ENDPOINT);
202
+ const body = (await response.json());
203
+ if (!alive)
204
+ return;
205
+ setState((current) => applyRestFallback(current, body, Date.now()));
206
+ }
207
+ catch {
208
+ // Keep the last-known view; the next tick retries (bz-AC-5/hr-AC-4 fail-soft).
209
+ }
210
+ };
211
+ void tick();
212
+ restIntervalId = setInterval(() => void tick(), restPollMs);
213
+ }
214
+ // jsdom (this repo's test environment) has no `EventSource`; degrading straight to the REST
215
+ // path here mirrors `wire.ts`'s `logsStream` guard and keeps this hook exercisable in tests.
216
+ const EventSourceCtor = globalThis.EventSource;
217
+ if (EventSourceCtor === undefined) {
218
+ startRestFallback();
219
+ return () => {
220
+ alive = false;
221
+ stopRestFallback();
222
+ };
223
+ }
224
+ let source = null;
225
+ const onTelemetry = (event) => {
226
+ if (!alive)
227
+ return;
228
+ const data = typeof event.data === "string" ? event.data : String(event.data);
229
+ const parsed = parseFleetTelemetryEvent(data);
230
+ if (parsed === null)
231
+ return;
232
+ // A good frame means the stream is up; stop the fallback poll (bz-AC-6/hr-AC-5: resumed
233
+ // live updates without a manual refresh).
234
+ stopRestFallback();
235
+ setState((current) => applySseEvent(current, parsed, Date.now()));
236
+ };
237
+ // bz-AC-5/hr-AC-4: any stream error (including a drop) falls back to polling REST while
238
+ // `EventSource`'s own built-in reconnect keeps retrying the stream in the background.
239
+ const onError = () => startRestFallback();
240
+ try {
241
+ source = new EventSourceCtor(TELEMETRY_STREAM_ENDPOINT);
242
+ source.addEventListener(FLEET_TELEMETRY_EVENT_NAME, onTelemetry);
243
+ source.addEventListener("error", onError);
244
+ }
245
+ catch {
246
+ startRestFallback();
247
+ }
248
+ return () => {
249
+ alive = false;
250
+ stopRestFallback();
251
+ try {
252
+ source?.removeEventListener(FLEET_TELEMETRY_EVENT_NAME, onTelemetry);
253
+ source?.removeEventListener("error", onError);
254
+ source?.close();
255
+ }
256
+ catch {
257
+ // Closing an already-closed/errored source must never throw into unmount.
258
+ }
259
+ };
260
+ }, [restPollMs]);
261
+ return React.useMemo(() => toFleetTelemetryView(state, now), [state, now]);
262
+ }
263
+ // ─────────────────────────────────────────────────────────────────────────────
264
+ // PRD-005c: log verbosity filtering over the SAME bounded buffer (no second stream, no re-fetch).
265
+ // ─────────────────────────────────────────────────────────────────────────────
266
+ /** The four selectable verbosity levels (lg-AC-4), ordered least→most severe. */
267
+ export const LOG_LEVELS = ["debug", "info", "warn", "error"];
268
+ /** Rank an arbitrary (free-form, per doctor's schema) log level string; an unrecognized level defaults to `info`'s rank. */
269
+ function logLevelRank(level) {
270
+ const idx = LOG_LEVELS.indexOf(level.trim().toLowerCase());
271
+ return idx === -1 ? LOG_LEVELS.indexOf("info") : idx;
272
+ }
273
+ /** Filter a log buffer to lines AT OR ABOVE `minLevel` (lg-AC-4/lg-AC-5) — a view filter, never a re-fetch. */
274
+ export function filterLogsByVerbosity(logs, minLevel) {
275
+ const minRank = LOG_LEVELS.indexOf(minLevel);
276
+ return logs.filter((entry) => logLevelRank(entry.level) >= minRank);
277
+ }
278
+ //# sourceMappingURL=use-fleet-telemetry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-fleet-telemetry.js","sourceRoot":"","sources":["../../../src/dashboard/web/use-fleet-telemetry.ts"],"names":[],"mappings":"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"}