busroot-sdk 0.0.8-dev.2920350130 → 0.0.8-dev.2920950808

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 (2) hide show
  1. package/build/index.js +63 -29
  2. package/package.json +1 -1
package/build/index.js CHANGED
@@ -38,6 +38,7 @@ var require_time = __commonJS({
38
38
  exports2.Crons = exports2.TimeIntervals = exports2.TimeRange = void 0;
39
39
  exports2.getTimeIntervalFromString = getTimeIntervalFromString;
40
40
  exports2.getTimeIntervalKeyFromMs = getTimeIntervalKeyFromMs;
41
+ exports2.nominalDurationMs = nominalDurationMs;
41
42
  exports2.millisToSec = millisToSec;
42
43
  var zod_1 = require("zod");
43
44
  exports2.TimeRange = zod_1.z.object({
@@ -95,6 +96,15 @@ var require_time = __commonJS({
95
96
  }
96
97
  return void 0;
97
98
  }
99
+ var MAX_CLOCK_CHANGE_MS = exports2.TimeIntervals["1h"].ms;
100
+ function nominalDurationMs(durationMs) {
101
+ const dayMs = exports2.TimeIntervals["1d"].ms;
102
+ const wholeDays = Math.round(durationMs / dayMs);
103
+ if (wholeDays >= 1 && Math.abs(durationMs - wholeDays * dayMs) <= MAX_CLOCK_CHANGE_MS) {
104
+ return wholeDays * dayMs;
105
+ }
106
+ return durationMs;
107
+ }
98
108
  function millisToSec(millis) {
99
109
  return millis / 1e3;
100
110
  }
@@ -554,6 +564,7 @@ var require_times = __commonJS({
554
564
  exports2.fromSpecificHourString = fromSpecificHourString;
555
565
  exports2.plantWeekNumber = plantWeekNumber;
556
566
  exports2.plantWeekStart = plantWeekStart;
567
+ exports2.addPlantDays = addPlantDays;
557
568
  exports2.getTimeRangeFromRangeCode = getTimeRangeFromRangeCode;
558
569
  exports2.getCoverage = getCoverage;
559
570
  exports2.getWindowAtTime = getWindowAtTime;
@@ -568,6 +579,7 @@ var require_times = __commonJS({
568
579
  exports2.getDayRangeCode = getDayRangeCode;
569
580
  exports2.getCurrentWeekRangeCode = getCurrentWeekRangeCode;
570
581
  exports2.generateTimeWindows = generateTimeWindows;
582
+ exports2.generatePlantDayWindows = generatePlantDayWindows;
571
583
  exports2.BusrootDateTimeParse = BusrootDateTimeParse;
572
584
  exports2.decimalHoursToTime = decimalHoursToTime;
573
585
  var moment_timezone_1 = __importStar(require("moment-timezone"));
@@ -744,7 +756,8 @@ var require_times = __commonJS({
744
756
  }
745
757
  ];
746
758
  function getAllowedAggregationWindowsForDuration(durationMs) {
747
- const allowedAggregationWindows = AllowedAggregationWindows.find((a) => durationMs <= a.durationMs)?.allowedAggregationWindows;
759
+ const nominalMs = (0, time_1.nominalDurationMs)(durationMs);
760
+ const allowedAggregationWindows = AllowedAggregationWindows.find((a) => nominalMs <= a.durationMs)?.allowedAggregationWindows;
748
761
  return allowedAggregationWindows;
749
762
  }
750
763
  function getTimestampFromString(timeString) {
@@ -978,6 +991,15 @@ var require_times = __commonJS({
978
991
  }
979
992
  return start;
980
993
  }
994
+ var DAYS_PER_WEEK = 7;
995
+ function plantDayRange(date, days, dayStartHour) {
996
+ const from = date.clone().add(dayStartHour, "hour").valueOf();
997
+ const to = date.clone().add(days, "days").add(dayStartHour, "hour").valueOf();
998
+ return timestampsToTimeRange({ from, to });
999
+ }
1000
+ function addPlantDays(instant, days, timezone) {
1001
+ return (0, moment_timezone_1.default)(instant).tz(timezone).add(days, "days").valueOf();
1002
+ }
981
1003
  function floorToPlantWeekStart(instant, plant) {
982
1004
  const weekStartDay = plant.weekStartDay ?? 0;
983
1005
  return (0, moment_timezone_1.default)(instant).tz(plant.timezone).subtract(weekStartDay, "days").subtract(plant.dayStartHour, "hours").startOf("isoWeek").add(weekStartDay, "days").add(plant.dayStartHour, "hours").valueOf();
@@ -1037,36 +1059,33 @@ var require_times = __commonJS({
1037
1059
  day.utc();
1038
1060
  return timestampsToTimeRange({ from: day.valueOf(), to: day.add(1, "hours").valueOf() });
1039
1061
  },
1062
+ // Every range below ends where the next one of its kind starts, built on the plant's local calendar
1063
+ // (add whole days/months, then dayStartHour) and only then read as UTC. Adding a fixed n×24h instead
1064
+ // would make a range that contains a daylight-saving change an hour too long or short, leaving gaps
1065
+ // and overlaps between consecutive ranges.
1066
+ //
1040
1067
  // TODAY/YESTERDAY: subtract dayStartHour before startOf("day") to find the
1041
1068
  // correct production day boundary, then re-add it. This handles the case where
1042
1069
  // e.g. it's 02:00 but the production day started at 06:00 the previous calendar day.
1043
1070
  today: () => {
1044
- const day = (0, moment_timezone_1.default)(now).tz(plant.timezone).add(-plant.dayStartHour, "hour").startOf("day").add(plant.dayStartHour, "hour");
1045
- day.utc();
1046
- return timestampsToTimeRange({ from: day.valueOf(), to: day.add(24, "hours").valueOf() });
1071
+ const date = (0, moment_timezone_1.default)(now).tz(plant.timezone).add(-plant.dayStartHour, "hour").startOf("day");
1072
+ return plantDayRange(date, 1, plant.dayStartHour);
1047
1073
  },
1048
1074
  yesterday: () => {
1049
- const day = (0, moment_timezone_1.default)(now).tz(plant.timezone).add(-plant.dayStartHour, "hour").startOf("day").add(-1, "day").add(plant.dayStartHour, "hour");
1050
- day.utc();
1051
- return timestampsToTimeRange({ from: day.valueOf(), to: day.add(24, "hours").valueOf() });
1075
+ const date = (0, moment_timezone_1.default)(now).tz(plant.timezone).add(-plant.dayStartHour, "hour").startOf("day").add(-1, "day");
1076
+ return plantDayRange(date, 1, plant.dayStartHour);
1052
1077
  },
1053
1078
  day: () => {
1054
- const day = moment_timezone_1.default.tz(`${parseInt(parts[1])}_${parseInt(parts[2])}_${parseInt(parts[3])}`, "YYYY_MM_DD", plant.timezone);
1055
- day.add(plant.dayStartHour, "hour");
1056
- day.utc();
1057
- return timestampsToTimeRange({ from: day.valueOf(), to: day.add(24, "hours").valueOf() });
1079
+ const date = moment_timezone_1.default.tz(`${parseInt(parts[1])}_${parseInt(parts[2])}_${parseInt(parts[3])}`, "YYYY_MM_DD", plant.timezone);
1080
+ return plantDayRange(date, 1, plant.dayStartHour);
1058
1081
  },
1059
1082
  week: () => {
1060
1083
  const week = plantWeekStart(parseInt(parts[1]), parseInt(parts[2]), plant.weekStartDay ?? 0, plant.timezone);
1061
- week.add(plant.dayStartHour, "hour");
1062
- week.utc();
1063
- return timestampsToTimeRange({ from: week.valueOf(), to: week.add(24 * 7, "hours").valueOf() });
1084
+ return plantDayRange(week, DAYS_PER_WEEK, plant.dayStartHour);
1064
1085
  },
1065
1086
  month: () => {
1066
1087
  const month = moment_timezone_1.default.tz(`${parseInt(parts[1])}_${parseInt(parts[2])}}`, "YYYY_MM", plant.timezone).startOf("month");
1067
- month.add(plant.dayStartHour, "hour");
1068
- month.utc();
1069
- return timestampsToTimeRange({ from: month.valueOf(), to: month.add(month.daysInMonth() * 24, "hours").valueOf() });
1088
+ return plantDayRange(month, month.daysInMonth(), plant.dayStartHour);
1070
1089
  },
1071
1090
  // QUARTER: 13 ISO weeks (14 for Q4 in 53-week years). Start at the first ISO week of the quarter,
1072
1091
  // then apply the plant's weekStartDay and dayStartHour offsets exactly like the week handler.
@@ -1076,18 +1095,14 @@ var require_times = __commonJS({
1076
1095
  const weeks = getWeeksInQuarter(year, quarter);
1077
1096
  const firstWeek = weeks[0];
1078
1097
  const start = plantWeekStart(year, firstWeek, plant.weekStartDay ?? 0, plant.timezone);
1079
- start.add(plant.dayStartHour, "hour");
1080
- start.utc();
1081
- return timestampsToTimeRange({ from: start.valueOf(), to: start.add(weeks.length * 7 * 24, "hours").valueOf() });
1098
+ return plantDayRange(start, weeks.length * DAYS_PER_WEEK, plant.dayStartHour);
1082
1099
  },
1083
1100
  // YEAR: full ISO week year (52 or 53 weeks). Start at ISO week 1, apply plant offsets like the week handler.
1084
1101
  year: () => {
1085
1102
  const year = parseInt(parts[1]);
1086
1103
  const weeksInYear = isoWeeksInIsoWeekYear(year);
1087
1104
  const start = plantWeekStart(year, 1, plant.weekStartDay ?? 0, plant.timezone);
1088
- start.add(plant.dayStartHour, "hour");
1089
- start.utc();
1090
- return timestampsToTimeRange({ from: start.valueOf(), to: start.add(weeksInYear * 7 * 24, "hours").valueOf() });
1105
+ return plantDayRange(start, weeksInYear * DAYS_PER_WEEK, plant.dayStartHour);
1091
1106
  },
1092
1107
  custom: () => timestampsToTimeRange({ from: 0, to: 0 }),
1093
1108
  // Already handled above
@@ -1383,6 +1398,25 @@ var require_times = __commonJS({
1383
1398
  endAt: (0, moment_timezone_1.default)(endAtTimestamp).toISOString()
1384
1399
  };
1385
1400
  }
1401
+ function generatePlantDayWindows(startAt, days, until, timezone) {
1402
+ const windows = [];
1403
+ let endAtTimestamp = 0;
1404
+ for (let i = 0; ; i++) {
1405
+ const windowStartAtTimestamp = addPlantDays(startAt, days * i, timezone);
1406
+ const windowEndAtTimestamp = addPlantDays(startAt, days * (i + 1), timezone);
1407
+ if (windowEndAtTimestamp > until) {
1408
+ break;
1409
+ }
1410
+ endAtTimestamp = windowEndAtTimestamp;
1411
+ windows.push({
1412
+ windowStartAtTimestamp,
1413
+ windowEndAtTimestamp,
1414
+ windowStartAt: (0, moment_timezone_1.default)(windowStartAtTimestamp).toISOString(),
1415
+ windowEndAt: (0, moment_timezone_1.default)(windowEndAtTimestamp).toISOString()
1416
+ });
1417
+ }
1418
+ return { windows, endAtTimestamp };
1419
+ }
1386
1420
  function BusrootDateTimeParse(obj, now = moment_timezone_1.default.utc().valueOf()) {
1387
1421
  const fields = ["plannedStartAt", "plannedEndAt", "actualStartAt", "actualEndAt"];
1388
1422
  for (const field of fields) {
@@ -9907,11 +9941,11 @@ var require_station_windows = __commonJS({
9907
9941
  if (windows.length === 0) {
9908
9942
  throw new Error("Must be at least 1 window.");
9909
9943
  }
9910
- const windowDuration = windows[0].totalMs;
9944
+ const windowDuration = (0, time_1.nominalDurationMs)(windows[0].totalMs);
9911
9945
  const window2 = windows.reduce((a, b, i) => {
9912
9946
  const isFirstWindow = i === 0;
9913
9947
  const isConsecutive = a.windowEndAt === b.windowStartAt;
9914
- const isSameDuration = b.totalMs === windowDuration;
9948
+ const isSameDuration = (0, time_1.nominalDurationMs)(b.totalMs) === windowDuration;
9915
9949
  if (!isFirstWindow && !skipConsecutiveCheck) {
9916
9950
  if (!isConsecutive) {
9917
9951
  throw new Error("Windows are not consecutive.");
@@ -10190,7 +10224,7 @@ var require_station_windows = __commonJS({
10190
10224
  const batch = [];
10191
10225
  for (let i = 0; i < windows.length; i++) {
10192
10226
  const thisWindow = windows[i];
10193
- const thisWindowDuration = thisWindow.windowEndAtTimestamp - thisWindow.windowStartAtTimestamp;
10227
+ const thisWindowDuration = (0, time_1.nominalDurationMs)(thisWindow.windowEndAtTimestamp - thisWindow.windowStartAtTimestamp);
10194
10228
  if (thisWindowDuration > aggregateWindowInMs) {
10195
10229
  throw new Error("Windows being aggregated must be less than or equal to the aggregate window. " + windows[i].totalMs + " " + aggregateWindowInMinutes);
10196
10230
  }
@@ -10202,7 +10236,7 @@ var require_station_windows = __commonJS({
10202
10236
  }
10203
10237
  }
10204
10238
  batch.push(windows[i]);
10205
- const durationOfBatch = batch.reduce((a, b) => a + b.totalMs, 0);
10239
+ const durationOfBatch = batch.reduce((a, b) => a + (0, time_1.nominalDurationMs)(b.totalMs), 0);
10206
10240
  if (durationOfBatch >= aggregateWindowInMs) {
10207
10241
  aggregatedWindows.push(combineStationWindows(batch, inShiftAverages));
10208
10242
  batch.length = 0;
@@ -10213,8 +10247,8 @@ var require_station_windows = __commonJS({
10213
10247
  const lastAggregatedWindowEndAtTimestamp = aggregatedWindows[aggregatedWindows.length - 1]?.windowEndAtTimestamp;
10214
10248
  const lastWindowEndAtTimestamp = lastAggregatedWindowEndAtTimestamp ?? windows[windows.length - 1].windowEndAtTimestamp;
10215
10249
  const futureWindowsStartAt = lastAggregatedWindowEndAtTimestamp == null && aggregateWindowInMinutes < time_1.TimeIntervals["1h"].min ? lastWindowEndAtTimestamp - lastWindowEndAtTimestamp % windowDurationMs : lastWindowEndAtTimestamp;
10216
- const requiredFutureWindowsCount = Math.floor((includeFutureWindowsUntil - futureWindowsStartAt) / windowDurationMs);
10217
- const { windows: futureTimeWindows, endAtTimestamp } = (0, times_1.generateTimeWindows)(futureWindowsStartAt, windowDurationMs, requiredFutureWindowsCount, void 0, false);
10250
+ const windowDays = windowDurationMs / time_1.TimeIntervals["1d"].ms;
10251
+ const { windows: futureTimeWindows, endAtTimestamp } = Number.isInteger(windowDays) ? (0, times_1.generatePlantDayWindows)(futureWindowsStartAt, windowDays, includeFutureWindowsUntil, station.timezone) : (0, times_1.generateTimeWindows)(futureWindowsStartAt, windowDurationMs, Math.floor((includeFutureWindowsUntil - futureWindowsStartAt) / windowDurationMs), void 0, false);
10218
10252
  const futureWindows = futureTimeWindows.map((x) => {
10219
10253
  const isInShift = shiftUtils.isTimeInShifts({
10220
10254
  time: x.windowStartAtTimestamp,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "busroot-sdk",
3
- "version": "0.0.8-dev.2920350130",
3
+ "version": "0.0.8-dev.2920950808",
4
4
  "description": "An SDK for accessing Busroot from output.industries",
5
5
  "homepage": "https://www.output.industries",
6
6
  "main": "./build/index.js",