@oneuptime/common 11.5.10 → 11.5.12

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 (65) hide show
  1. package/Models/AnalyticsModels/NetworkFlow.ts +12 -1
  2. package/Server/API/StatusPageAPI.ts +14 -1
  3. package/Server/Services/IncidentService.ts +62 -67
  4. package/Server/Services/MonitorGroupService.ts +15 -2
  5. package/Server/Services/MonitorService.ts +91 -3
  6. package/Server/Services/MonitorStatusTimelineService.ts +285 -100
  7. package/Server/Services/StatusPageService.ts +59 -34
  8. package/Server/Utils/Monitor/MonitorResource.ts +43 -14
  9. package/Server/Utils/Monitor/MonitorStatusTimeline.ts +32 -7
  10. package/Server/Utils/Monitor/MonitorStatusTimelineReconciler.ts +362 -0
  11. package/Tests/Server/Services/MonitorStatusTimelineService.test.ts +235 -0
  12. package/Tests/Server/Utils/Monitor/MonitorStatusTimelineReconciler.test.ts +555 -0
  13. package/Tests/Types/Database/CompareOperatorWireSerialization.test.ts +216 -0
  14. package/Tests/Types/Database/GreaterThan.test.ts +5 -1
  15. package/Tests/Types/Database/GreaterThanOrEqual.test.ts +5 -1
  16. package/Tests/Types/Database/GreaterThanOrNull.test.ts +24 -1
  17. package/Tests/Types/Database/LessThan.test.ts +5 -1
  18. package/Tests/Types/Database/LessThanOrEqual.test.ts +24 -1
  19. package/Tests/Types/Database/LessThanOrNull.test.ts +5 -1
  20. package/Tests/Utils/Uptime/UptimeUtil.test.ts +726 -0
  21. package/Types/BaseDatabase/GreaterThan.ts +8 -1
  22. package/Types/BaseDatabase/GreaterThanOrEqual.ts +8 -1
  23. package/Types/BaseDatabase/GreaterThanOrNull.ts +9 -1
  24. package/Types/BaseDatabase/LessThan.ts +8 -1
  25. package/Types/BaseDatabase/LessThanOrEqual.ts +9 -1
  26. package/Types/BaseDatabase/LessThanOrNull.ts +8 -1
  27. package/Utils/StatusPage/ResourceUptime.ts +11 -1
  28. package/Utils/Uptime/UptimeUtil.ts +142 -36
  29. package/build/dist/Models/AnalyticsModels/NetworkFlow.js +12 -1
  30. package/build/dist/Models/AnalyticsModels/NetworkFlow.js.map +1 -1
  31. package/build/dist/Server/API/StatusPageAPI.js +12 -2
  32. package/build/dist/Server/API/StatusPageAPI.js.map +1 -1
  33. package/build/dist/Server/Services/IncidentService.js +47 -56
  34. package/build/dist/Server/Services/IncidentService.js.map +1 -1
  35. package/build/dist/Server/Services/MonitorGroupService.js +15 -2
  36. package/build/dist/Server/Services/MonitorGroupService.js.map +1 -1
  37. package/build/dist/Server/Services/MonitorService.js +66 -3
  38. package/build/dist/Server/Services/MonitorService.js.map +1 -1
  39. package/build/dist/Server/Services/MonitorStatusTimelineService.js +244 -102
  40. package/build/dist/Server/Services/MonitorStatusTimelineService.js.map +1 -1
  41. package/build/dist/Server/Services/StatusPageService.js +57 -33
  42. package/build/dist/Server/Services/StatusPageService.js.map +1 -1
  43. package/build/dist/Server/Utils/Monitor/MonitorResource.js +34 -12
  44. package/build/dist/Server/Utils/Monitor/MonitorResource.js.map +1 -1
  45. package/build/dist/Server/Utils/Monitor/MonitorStatusTimeline.js +25 -8
  46. package/build/dist/Server/Utils/Monitor/MonitorStatusTimeline.js.map +1 -1
  47. package/build/dist/Server/Utils/Monitor/MonitorStatusTimelineReconciler.js +268 -0
  48. package/build/dist/Server/Utils/Monitor/MonitorStatusTimelineReconciler.js.map +1 -0
  49. package/build/dist/Types/BaseDatabase/GreaterThan.js +8 -1
  50. package/build/dist/Types/BaseDatabase/GreaterThan.js.map +1 -1
  51. package/build/dist/Types/BaseDatabase/GreaterThanOrEqual.js +8 -1
  52. package/build/dist/Types/BaseDatabase/GreaterThanOrEqual.js.map +1 -1
  53. package/build/dist/Types/BaseDatabase/GreaterThanOrNull.js +9 -1
  54. package/build/dist/Types/BaseDatabase/GreaterThanOrNull.js.map +1 -1
  55. package/build/dist/Types/BaseDatabase/LessThan.js +8 -1
  56. package/build/dist/Types/BaseDatabase/LessThan.js.map +1 -1
  57. package/build/dist/Types/BaseDatabase/LessThanOrEqual.js +9 -1
  58. package/build/dist/Types/BaseDatabase/LessThanOrEqual.js.map +1 -1
  59. package/build/dist/Types/BaseDatabase/LessThanOrNull.js +8 -1
  60. package/build/dist/Types/BaseDatabase/LessThanOrNull.js.map +1 -1
  61. package/build/dist/Utils/StatusPage/ResourceUptime.js +4 -1
  62. package/build/dist/Utils/StatusPage/ResourceUptime.js.map +1 -1
  63. package/build/dist/Utils/Uptime/UptimeUtil.js +86 -33
  64. package/build/dist/Utils/Uptime/UptimeUtil.js.map +1 -1
  65. package/package.json +3 -2
@@ -11,7 +11,14 @@ export default class GreaterThan<T extends CompareType> extends CompareBase<T> {
11
11
  public override toJSON(): JSONObject {
12
12
  return {
13
13
  _type: ObjectType.GreaterThan,
14
- value: (this as GreaterThan<T>).toString(),
14
+ /*
15
+ * The RAW value is serialized (like InBetween), not toString():
16
+ * toString() collapses a Date to a local-timezone date-only string
17
+ * (asDateForDatabaseQuery), shifting Date bounds sent from the browser
18
+ * by up to a day. JSON.stringify emits a raw Date as its full ISO
19
+ * timestamp, which the server binds at full precision.
20
+ */
21
+ value: (this as GreaterThan<T>).value,
15
22
  };
16
23
  }
17
24
 
@@ -13,7 +13,14 @@ export default class GreaterThanOrEqual<
13
13
  public override toJSON(): JSONObject {
14
14
  return {
15
15
  _type: ObjectType.GreaterThanOrEqual,
16
- value: (this as GreaterThanOrEqual<T>).toString(),
16
+ /*
17
+ * The RAW value is serialized (like InBetween), not toString():
18
+ * toString() collapses a Date to a local-timezone date-only string
19
+ * (asDateForDatabaseQuery), shifting Date bounds sent from the browser
20
+ * by up to a day. JSON.stringify emits a raw Date as its full ISO
21
+ * timestamp, which the server binds at full precision.
22
+ */
23
+ value: (this as GreaterThanOrEqual<T>).value,
17
24
  };
18
25
  }
19
26
 
@@ -10,10 +10,18 @@ export default class GreaterThanOrNull<
10
10
  super(value);
11
11
  }
12
12
 
13
+ /*
14
+ * Serializes the RAW value (like InBetween does), not toString(): toString()
15
+ * collapses a Date to a date-only string in the LOCAL timezone
16
+ * (asDateForDatabaseQuery), so a Date bound would arrive at the server as
17
+ * midnight of the browser's calendar date and shift the query bound by up to
18
+ * a day. JSON.stringify turns a raw Date into its full ISO timestamp, which
19
+ * the server binds at full precision.
20
+ */
13
21
  public override toJSON(): JSONObject {
14
22
  return {
15
23
  _type: ObjectType.GreaterThanOrNull,
16
- value: (this as GreaterThanOrNull<T>).toString(),
24
+ value: (this as GreaterThanOrNull<T>).value,
17
25
  };
18
26
  }
19
27
 
@@ -11,7 +11,14 @@ export default class LessThan<T extends CompareType> extends CompareBase<T> {
11
11
  public override toJSON(): JSONObject {
12
12
  return {
13
13
  _type: ObjectType.LessThan,
14
- value: (this as LessThan<T>).toString(),
14
+ /*
15
+ * The RAW value is serialized (like InBetween), not toString():
16
+ * toString() collapses a Date to a local-timezone date-only string
17
+ * (asDateForDatabaseQuery), shifting Date bounds sent from the browser
18
+ * by up to a day. JSON.stringify emits a raw Date as its full ISO
19
+ * timestamp, which the server binds at full precision.
20
+ */
21
+ value: (this as LessThan<T>).value,
15
22
  };
16
23
  }
17
24
 
@@ -10,10 +10,18 @@ export default class LessThanOrEqual<
10
10
  super(value);
11
11
  }
12
12
 
13
+ /*
14
+ * Serializes the RAW value (like InBetween does), not toString(): toString()
15
+ * collapses a Date to a date-only string in the LOCAL timezone
16
+ * (asDateForDatabaseQuery), so a bound of "now" would arrive at the server as
17
+ * midnight of the browser's calendar date and silently exclude every row from
18
+ * today. JSON.stringify turns a raw Date into its full ISO timestamp, which
19
+ * the server binds at full precision.
20
+ */
13
21
  public override toJSON(): JSONObject {
14
22
  return {
15
23
  _type: ObjectType.LessThanOrEqual,
16
- value: (this as LessThanOrEqual<T>).toString(),
24
+ value: (this as LessThanOrEqual<T>).value,
17
25
  };
18
26
  }
19
27
 
@@ -13,7 +13,14 @@ export default class LessThanOrNull<
13
13
  public override toJSON(): JSONObject {
14
14
  return {
15
15
  _type: ObjectType.LessThanOrNull,
16
- value: (this as LessThanOrNull<T>).toString(),
16
+ /*
17
+ * The RAW value is serialized (like InBetween), not toString():
18
+ * toString() collapses a Date to a local-timezone date-only string
19
+ * (asDateForDatabaseQuery), shifting Date bounds sent from the browser
20
+ * by up to a day. JSON.stringify emits a raw Date as its full ISO
21
+ * timestamp, which the server binds at full precision.
22
+ */
23
+ value: (this as LessThanOrNull<T>).value,
17
24
  };
18
25
  }
19
26
 
@@ -6,7 +6,7 @@ import StatusPageResource from "../../Models/DatabaseModels/StatusPageResource";
6
6
  import Dictionary from "../../Types/Dictionary";
7
7
  import UptimePrecision from "../../Types/StatusPage/UptimePrecision";
8
8
  import StatusPageGroup from "../../Models/DatabaseModels/StatusPageGroup";
9
- import UptimeUtil from "../Uptime/UptimeUtil";
9
+ import UptimeUtil, { UptimeWindow } from "../Uptime/UptimeUtil";
10
10
 
11
11
  export default class StatusPageResourceUptimeUtil {
12
12
  public static getWorstMonitorStatus(data: {
@@ -137,6 +137,8 @@ export default class StatusPageResourceUptimeUtil {
137
137
  precision: UptimePrecision;
138
138
  downtimeMonitorStatuses: Array<MonitorStatus>;
139
139
  monitorsInGroup: Dictionary<Array<ObjectID>>;
140
+ // if supplied, uptime is measured over this window instead of "first event -> now".
141
+ uptimeWindow?: UptimeWindow | undefined;
140
142
  }): number | null {
141
143
  if (!data.statusPageResource.showUptimePercent) {
142
144
  return null;
@@ -156,6 +158,7 @@ export default class StatusPageResourceUptimeUtil {
156
158
  monitorStatusTimelines,
157
159
  data.precision,
158
160
  downtimeMonitorStatuses,
161
+ data.uptimeWindow,
159
162
  );
160
163
 
161
164
  return uptimePercent;
@@ -168,6 +171,8 @@ export default class StatusPageResourceUptimeUtil {
168
171
  downtimeMonitorStatuses: Array<MonitorStatus>;
169
172
  statusPageResources: Array<StatusPageResource>;
170
173
  monitorsInGroup: Dictionary<Array<ObjectID>>;
174
+ // if supplied, uptime is measured over this window instead of "first event -> now".
175
+ uptimeWindow?: UptimeWindow | undefined;
171
176
  }): number | null {
172
177
  if (!data.statusPageGroup.showUptimePercent) {
173
178
  return null;
@@ -193,6 +198,7 @@ export default class StatusPageResourceUptimeUtil {
193
198
  precision: data.precision,
194
199
  downtimeMonitorStatuses: data.downtimeMonitorStatuses,
195
200
  monitorsInGroup: data.monitorsInGroup,
201
+ uptimeWindow: data.uptimeWindow,
196
202
  });
197
203
 
198
204
  if (calculateUptimePercentOfResource !== null) {
@@ -252,6 +258,8 @@ export default class StatusPageResourceUptimeUtil {
252
258
  statusPageResources: Array<StatusPageResource>;
253
259
  resourceGroups: Array<StatusPageGroup>;
254
260
  monitorsInGroup: Dictionary<Array<ObjectID>>;
261
+ // if supplied, uptime is measured over this window instead of "first event -> now".
262
+ uptimeWindow?: UptimeWindow | undefined;
255
263
  }): number | null {
256
264
  const showUptimePercentage: boolean = Boolean(
257
265
  data.statusPageResources.find((item: StatusPageResource) => {
@@ -276,6 +284,7 @@ export default class StatusPageResourceUptimeUtil {
276
284
  downtimeMonitorStatuses: data.downtimeMonitorStatuses,
277
285
  statusPageResources: data.statusPageResources,
278
286
  monitorsInGroup: data.monitorsInGroup,
287
+ uptimeWindow: data.uptimeWindow,
279
288
  });
280
289
 
281
290
  if (calculateAvgUptimePercentOfStatusPageGroup !== null) {
@@ -298,6 +307,7 @@ export default class StatusPageResourceUptimeUtil {
298
307
  precision: data.precision,
299
308
  downtimeMonitorStatuses: data.downtimeMonitorStatuses,
300
309
  monitorsInGroup: data.monitorsInGroup,
310
+ uptimeWindow: data.uptimeWindow,
301
311
  });
302
312
 
303
313
  if (calculateUptimePercentOfResource !== null) {
@@ -7,15 +7,30 @@ import MonitorStatus from "../../Models/DatabaseModels/MonitorStatus";
7
7
  import MonitorStatusTimeline from "../../Models/DatabaseModels/MonitorStatusTimeline";
8
8
  import UptimePrecision from "../../Types/StatusPage/UptimePrecision";
9
9
 
10
+ /**
11
+ * The time period an uptime calculation is reported over. When this is supplied, events are
12
+ * clipped to it and the denominator of the uptime percentage is the window itself - clipped to
13
+ * now, and starting no earlier than the first recorded event (so a monitor younger than the
14
+ * window is measured from its first event, not diluted by time it did not exist). Without it,
15
+ * events run to the start of the next event (or now) and the denominator is "first event -> now",
16
+ * which lets an open (endsAt = null) row from months ago leak into an unrelated report.
17
+ */
18
+ export interface UptimeWindow {
19
+ startDate: Date;
20
+ endDate: Date;
21
+ }
22
+
10
23
  export default class UptimeUtil {
11
24
  /**
12
25
  * This function, `getMonitorEventsForId`, takes a `monitorId` as an argument and returns an array of `MonitorEvent` objects.
13
26
  * @param {ObjectID} monitorId - The ID of the monitor for which events are to be fetched.
27
+ * @param {UptimeWindow | undefined} window - If supplied, events are clipped to this window and events outside it are dropped.
14
28
  * @returns {Array<MonitorEvent>} - An array of `MonitorEvent` objects.
15
29
  */
16
30
  public static getMonitorEventsForId(
17
31
  monitorId: ObjectID,
18
32
  statusTimelineItems: Array<MonitorStatusTimeline>,
33
+ window?: UptimeWindow | undefined,
19
34
  ): Array<MonitorEvent> {
20
35
  // Initialize an empty array to store the monitor events.
21
36
 
@@ -65,15 +80,54 @@ export default class UptimeUtil {
65
80
  // check if there's next event, if there is, set the end date to the start date of the next event.
66
81
  if (i < monitorEvents.length - 1) {
67
82
  endDate = monitorEvents[i + 1]!.startsAt;
68
- } else {
83
+ }
84
+
85
+ // if this is the last event, or the next event has no start date, then this event is still open and runs until now.
86
+ if (!endDate) {
69
87
  endDate = OneUptimeDate.getCurrentDate();
70
88
  }
71
89
  }
72
90
 
91
+ let eventStartDate: Date = startDate;
92
+ let eventEndDate: Date = endDate;
93
+
94
+ if (window) {
95
+ /*
96
+ * Clip the event to the reporting window. Without this an open (endsAt = null) row that
97
+ * started months before the window contributes its entire life to the report.
98
+ *
99
+ * The end is also capped at "now", to match the denominator in
100
+ * getTotalDowntimeInSeconds, which measures the window only up to the
101
+ * current time (min(window.endDate, now)). If the numerator were allowed
102
+ * to run to a future window.endDate while the denominator stopped at now,
103
+ * a closed row ending in the future could make downtime exceed the elapsed
104
+ * period and drive the raw percentage negative.
105
+ */
106
+ eventStartDate = OneUptimeDate.getGreaterDate(
107
+ eventStartDate,
108
+ window.startDate,
109
+ );
110
+ eventEndDate = OneUptimeDate.getLesserDate(
111
+ eventEndDate,
112
+ OneUptimeDate.getLesserDate(
113
+ window.endDate,
114
+ OneUptimeDate.getCurrentDate(),
115
+ ),
116
+ );
117
+
118
+ // if the event does not overlap the window at all, then drop it.
119
+ if (
120
+ OneUptimeDate.getSecondsBetweenDates(eventStartDate, eventEndDate) <=
121
+ 0
122
+ ) {
123
+ continue;
124
+ }
125
+ }
126
+
73
127
  // Push a new MonitorEvent object to the eventList array with properties from the current item and calculated dates.
74
128
  eventList.push({
75
- startDate: startDate,
76
- endDate: endDate!,
129
+ startDate: eventStartDate,
130
+ endDate: eventEndDate,
77
131
  label: monitorEvents[i]?.monitorStatus?.name || "Operational",
78
132
  priority: monitorEvents[i]?.monitorStatus?.priority || 0,
79
133
  color: monitorEvents[i]?.monitorStatus?.color || Green,
@@ -88,8 +142,12 @@ export default class UptimeUtil {
88
142
 
89
143
  public static getNonOverlappingMonitorEvents(
90
144
  items: Array<MonitorStatusTimeline>,
145
+ window?: UptimeWindow | undefined,
91
146
  ): Array<Event> {
92
- const monitorEventList: Array<MonitorEvent> = this.getMonitorEvents(items);
147
+ const monitorEventList: Array<MonitorEvent> = this.getMonitorEvents(
148
+ items,
149
+ window,
150
+ );
93
151
 
94
152
  const eventList: Array<Event> = [];
95
153
 
@@ -98,20 +156,6 @@ export default class UptimeUtil {
98
156
 
99
157
  const monitorEvent: MonitorEvent = monitorEventList[i]!;
100
158
 
101
- if (!monitorEvent.endDate) {
102
- // if this is the last event then set endDate to current date.
103
-
104
- // otherwise set it to start date of next event.
105
-
106
- if (i === monitorEventList.length - 1) {
107
- monitorEvent.endDate = OneUptimeDate.getCurrentDate();
108
- } else {
109
- monitorEvent.endDate =
110
- monitorEventList[i + 1]!.startDate ||
111
- OneUptimeDate.getCurrentDate();
112
- }
113
- }
114
-
115
159
  if (
116
160
  eventList.length === 0 ||
117
161
  OneUptimeDate.isAfter(
@@ -188,6 +232,7 @@ export default class UptimeUtil {
188
232
 
189
233
  public static getMonitorEvents(
190
234
  items: Array<MonitorStatusTimeline>,
235
+ window?: UptimeWindow | undefined,
191
236
  ): Array<MonitorEvent> {
192
237
  // get all distinct monitor ids.
193
238
  const monitorIds: Array<ObjectID> = [];
@@ -219,6 +264,7 @@ export default class UptimeUtil {
219
264
  const monitorEvents: Array<MonitorEvent> = this.getMonitorEventsForId(
220
265
  monitorId,
221
266
  items,
267
+ window,
222
268
  );
223
269
  eventList.push(...monitorEvents);
224
270
  }
@@ -242,12 +288,14 @@ export default class UptimeUtil {
242
288
  public static getTotalDowntimeInSeconds(
243
289
  monitorStatusTimelines: Array<MonitorStatusTimeline>,
244
290
  downtimeMonitorStatuses: Array<MonitorStatus>,
291
+ window?: UptimeWindow | undefined,
245
292
  ): {
246
293
  totalDowntimeInSeconds: number;
247
294
  totalSecondsInTimePeriod: number;
248
295
  } {
249
296
  const monitorEvents: Array<Event> = this.getNonOverlappingMonitorEvents(
250
297
  monitorStatusTimelines,
298
+ window,
251
299
  );
252
300
 
253
301
  // sort these by start date,
@@ -263,33 +311,83 @@ export default class UptimeUtil {
263
311
  return 0;
264
312
  });
265
313
 
314
+ /*
315
+ * If a window is supplied then the time period is the window itself, and not "first event -> now".
316
+ * Two clamps apply to the window:
317
+ *
318
+ * - The window end is clipped to now, so a window that reaches into the future does not
319
+ * inflate the denominator (which is what made the reported percentage drift upwards
320
+ * every day).
321
+ *
322
+ * - The window start is clamped forward to the first event's start, so time from before
323
+ * the monitor's first recorded event does not count as uptime. Events are already
324
+ * clipped to the window, so this only moves the start when the monitor has NO data for
325
+ * the head of the window - i.e. it is younger than the window. Without this a monitor
326
+ * created a day ago and Offline ever since would report ~98.9% uptime over a 90 day
327
+ * window; with it, it reports 0% - the same answer the windowless
328
+ * "first event -> now" denominator always gave.
329
+ *
330
+ * When there are no events at all there is nothing to clamp to and the denominator is the
331
+ * full (now-clipped) window.
332
+ */
333
+ let windowSecondsInTimePeriod: number | null = null;
334
+
335
+ if (window) {
336
+ const windowEndDate: Date = OneUptimeDate.getLesserDate(
337
+ window.endDate,
338
+ OneUptimeDate.getCurrentDate(),
339
+ );
340
+
341
+ const windowStartDate: Date =
342
+ monitorEvents.length > 0
343
+ ? OneUptimeDate.getGreaterDate(
344
+ window.startDate,
345
+ monitorEvents[0]!.startDate,
346
+ )
347
+ : window.startDate;
348
+
349
+ windowSecondsInTimePeriod = OneUptimeDate.getSecondsBetweenDates(
350
+ windowStartDate,
351
+ windowEndDate,
352
+ );
353
+
354
+ // never let the denominator be zero or negative.
355
+ if (!windowSecondsInTimePeriod || windowSecondsInTimePeriod < 0) {
356
+ windowSecondsInTimePeriod = 1;
357
+ }
358
+ }
359
+
266
360
  // calculate number of seconds between start of first event to date time now.
267
361
  let totalSecondsInTimePeriod: number = 0;
268
362
 
269
363
  if (monitorEvents.length === 0) {
270
364
  return {
271
365
  totalDowntimeInSeconds: 0,
272
- totalSecondsInTimePeriod: 1,
366
+ totalSecondsInTimePeriod: windowSecondsInTimePeriod ?? 1,
273
367
  };
274
368
  }
275
369
 
276
- if (
277
- OneUptimeDate.isAfter(
278
- monitorEvents[0]!.startDate,
279
- OneUptimeDate.getCurrentDate(),
280
- )
281
- ) {
282
- return {
283
- totalDowntimeInSeconds: 0,
284
- totalSecondsInTimePeriod: 1,
285
- };
286
- }
370
+ if (windowSecondsInTimePeriod !== null) {
371
+ totalSecondsInTimePeriod = windowSecondsInTimePeriod;
372
+ } else {
373
+ if (
374
+ OneUptimeDate.isAfter(
375
+ monitorEvents[0]!.startDate,
376
+ OneUptimeDate.getCurrentDate(),
377
+ )
378
+ ) {
379
+ return {
380
+ totalDowntimeInSeconds: 0,
381
+ totalSecondsInTimePeriod: 1,
382
+ };
383
+ }
287
384
 
288
- totalSecondsInTimePeriod =
289
- OneUptimeDate.getSecondsBetweenDates(
290
- monitorEvents[0]!.startDate,
291
- OneUptimeDate.getCurrentDate(),
292
- ) || 1;
385
+ totalSecondsInTimePeriod =
386
+ OneUptimeDate.getSecondsBetweenDates(
387
+ monitorEvents[0]!.startDate,
388
+ OneUptimeDate.getCurrentDate(),
389
+ ) || 1;
390
+ }
293
391
 
294
392
  // get order of operational state.
295
393
 
@@ -347,6 +445,7 @@ export default class UptimeUtil {
347
445
  monitorStatusTimelines: Array<MonitorStatusTimeline>,
348
446
  precision: UptimePrecision,
349
447
  downtimeMonitorStatuses: Array<MonitorStatus>,
448
+ window?: UptimeWindow | undefined,
350
449
  ): number {
351
450
  // calculate percentage.
352
451
 
@@ -354,6 +453,7 @@ export default class UptimeUtil {
354
453
  this.getTotalDowntimeInSeconds(
355
454
  monitorStatusTimelines,
356
455
  downtimeMonitorStatuses,
456
+ window,
357
457
  );
358
458
 
359
459
  if (totalSecondsInTimePeriod === 0) {
@@ -369,8 +469,14 @@ export default class UptimeUtil {
369
469
  totalSecondsInTimePeriod) *
370
470
  100;
371
471
 
472
+ /*
473
+ * clamp before rounding. roundToPrecision floors, so an out of range value would otherwise
474
+ * escape as is (for example -13.5 stays -13.5 and never becomes 0).
475
+ */
476
+ const clampedPercentage: number = Math.min(100, Math.max(0, percentage));
477
+
372
478
  return this.roundToPrecision({
373
- number: percentage,
479
+ number: clampedPercentage,
374
480
  precision,
375
481
  });
376
482
  }
@@ -264,8 +264,19 @@ export default class NetworkFlow extends AnalyticsBaseModel {
264
264
  * (a retentionDate column computed at ingest, like Log/Metric) is
265
265
  * the phase-2 follow-up. Keyed on server-assigned ingestedAt so a
266
266
  * device with a wrong clock cannot make rows expire early.
267
+ *
268
+ * toDateTime() is NOT redundant: ingestedAt is DateTime64(9), so
269
+ * `ingestedAt + INTERVAL 30 DAY` stays DateTime64(9), and a TTL
270
+ * expression must evaluate to Date or DateTime. ClickHouse only began
271
+ * accepting DateTime64 there in 25.x; on 24.x it fails the CREATE with
272
+ * BAD_TTL_EXPRESSION, which aborts the whole boot schema-sync (it has
273
+ * no per-table error handling) and takes every table registered after
274
+ * this one down with it. The Helm chart ships `tag: latest` but tells
275
+ * operators to pin for production, so older servers are supported and
276
+ * this must stay version-portable. Narrowing to second precision is
277
+ * lossless for a 30-day retention window.
267
278
  */
268
- ttlExpression: "ingestedAt + INTERVAL 30 DAY DELETE",
279
+ ttlExpression: "toDateTime(ingestedAt) + INTERVAL 30 DAY DELETE",
269
280
  defaultSortColumn: "flowStartAt",
270
281
  });
271
282
  }
@@ -1 +1 @@
1
- {"version":3,"file":"NetworkFlow.js","sourceRoot":"","sources":["../../../../Models/AnalyticsModels/NetworkFlow.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"NetworkFlow.js","sourceRoot":"","sources":["../../../../Models/AnalyticsModels/NetworkFlow.ts"],"names":[],"mappings":"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"}
@@ -879,6 +879,16 @@ export default class StatusPageAPI extends BaseAPI {
879
879
  endDateForMonitorTimeline: endDate,
880
880
  });
881
881
  const downtimeMonitorStatuses = statusPage.downtimeMonitorStatuses || [];
882
+ /*
883
+ * this endpoint reports uptime over an explicit [startDate, endDate] range, so events
884
+ * have to be clipped to it and the denominator has to be the range itself. Without
885
+ * this an open (endsAt = null) row that started before the range contributes its
886
+ * entire duration to the downtime total.
887
+ */
888
+ const uptimeWindow = {
889
+ startDate: startDate,
890
+ endDate: endDate,
891
+ };
882
892
  const getUptimeByStatusPageGroup = (data) => {
883
893
  var _a, _b, _c, _d, _e;
884
894
  const groupUptime = {
@@ -936,7 +946,7 @@ export default class StatusPageAPI extends BaseAPI {
936
946
  monitorsInGroup: monitorsInGroup,
937
947
  });
938
948
  if (resource.showUptimePercent) {
939
- const uptimePercent = UptimeUtil.calculateUptimePercentage(resourceStatusTimelines, precision, downtimeMonitorStatuses);
949
+ const uptimePercent = UptimeUtil.calculateUptimePercentage(resourceStatusTimelines, precision, downtimeMonitorStatuses, uptimeWindow);
940
950
  resourceUptime.uptimePercent = uptimePercent;
941
951
  }
942
952
  groupUptime.statusPageResourceUptimes.push(resourceUptime);
@@ -966,7 +976,7 @@ export default class StatusPageAPI extends BaseAPI {
966
976
  monitorStatusTimelines: monitorStatusTimelines,
967
977
  monitorsInGroup: monitorsInGroup,
968
978
  });
969
- const uptimePercent = UptimeUtil.calculateUptimePercentage(resourceStatusTimelines, precision, downtimeMonitorStatuses);
979
+ const uptimePercent = UptimeUtil.calculateUptimePercentage(resourceStatusTimelines, precision, downtimeMonitorStatuses, uptimeWindow);
970
980
  resourceUptime.uptimePercent = uptimePercent;
971
981
  }
972
982
  groupUptime.statusPageResourceUptimes.push(resourceUptime);