@letpeoplework/lighthouse-client 1.10.0 → 1.12.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.
package/dist/index.cjs CHANGED
@@ -37,6 +37,20 @@ const PROCESS_BEHAVIOR_CHART_ROUTES = {
37
37
  const isProcessBehaviorMetricType = (value) => Object.hasOwn(PROCESS_BEHAVIOR_CHART_ROUTES, value);
38
38
  //#endregion
39
39
  //#region src/usageData.ts
40
+ const reportTemplateWeDisclose = { "then-and-now": "ThenAndNow" };
41
+ /**
42
+ * The opening of a report Lighthouse sent: its type and nothing else about it. A refused read, or a report of a
43
+ * type this version does not know, counts nothing.
44
+ */
45
+ const reportOpenedOccurrencesOf = (answered) => {
46
+ if (!answered.ok || !isRecord$1(answered.value)) return [];
47
+ const { templateKey } = answered.value;
48
+ const reportTemplate = Object.entries(reportTemplateWeDisclose).find(([key]) => key === templateKey)?.[1];
49
+ return reportTemplate === void 0 ? [] : [{
50
+ name: "ReportOpened",
51
+ reportTemplate
52
+ }];
53
+ };
40
54
  /**
41
55
  * When a vote was cast, from Lighthouse's answer rather than this machine's clock: Lighthouse counts days in
42
56
  * the instance's time zone and knows which cadence days are blacked out. The web counts it the same way.
@@ -242,13 +256,26 @@ const textOf = (value) => typeof value === "string" && value.length > 0 ? value
242
256
  const isDay = (value) => isText(value) && formatCalendarDay(value) !== null;
243
257
  /** The calendar day as a person reads it, or the text exactly as sent when it is not one. */
244
258
  const dayOf = (wire) => formatCalendarDay(wire) ?? wire;
245
- /** The date a list of chances gives for one probability, or undefined when it holds none for it. */
246
- const expectedDateAt = (chances, probability) => {
259
+ /** The chance a list gives for one probability, or undefined when it holds none for it. */
260
+ const chanceAt = (chances, probability) => {
247
261
  if (!Array.isArray(chances)) return;
248
262
  const chance = chances.find((entry) => isRecord(entry) && entry.probability === probability);
249
- return isRecord(chance) ? textOf(chance.expectedDate) : void 0;
263
+ return isRecord(chance) ? chance : void 0;
250
264
  };
251
265
  //#endregion
266
+ //#region src/forecastPercentileText.ts
267
+ /**
268
+ * The years of the horizon a percentile lies beyond, or undefined when its date is the forecast. Keyed on
269
+ * the flag itself, never on the server's version: an older Lighthouse never sends it.
270
+ */
271
+ const yearsBeyondHorizon = (percentile) => isRecord(percentile) && percentile.beyondHorizon === true && isNumber(percentile.horizonYears) ? percentile.horizonYears : void 0;
272
+ /** The words shown in place of a date for a percentile too few simulated runs reached. */
273
+ const moreThanYearsText = (horizonYears) => `More than ${horizonYears} years`;
274
+ /** A percentile's day as a person reads it, or "More than 5 years" when it lies beyond that horizon. */
275
+ const describePercentileDay = (expectedDate, horizonYearsBeyond) => horizonYearsBeyond === void 0 ? dayOf(expectedDate) : moreThanYearsText(horizonYearsBeyond);
276
+ /** One percentile as text: its day, or the words when it lies beyond the horizon. */
277
+ const describePercentileDate = (percentile) => describePercentileDay(percentile.expectedDate, yearsBeyondHorizon(percentile));
278
+ //#endregion
252
279
  //#region src/ownerWording.ts
253
280
  /** A mark for a cell Lighthouse sent nothing for. */
254
281
  const NOT_SENT = "—";
@@ -408,9 +435,11 @@ const startOf = (value) => {
408
435
  observedOn: void 0,
409
436
  likelyBy: void 0
410
437
  };
438
+ const chance = chanceAt(value.percentiles, LISTED_CHANCE$1);
411
439
  return {
412
440
  observedOn: value.source === "Observed" ? textOf(value.observedDate) : void 0,
413
- likelyBy: expectedDateAt(value.percentiles, LISTED_CHANCE$1)
441
+ likelyBy: textOf(chance?.expectedDate),
442
+ likelyByBeyondHorizonYears: yearsBeyondHorizon(chance)
414
443
  };
415
444
  };
416
445
  const readFeatureListItem = (value) => {
@@ -420,6 +449,7 @@ const readFeatureListItem = (value) => {
420
449
  const state = textOf(value.state);
421
450
  const totalWork = workOf(value.totalWork);
422
451
  const remainingWork = workOf(value.remainingWork);
452
+ const completion = chanceAt(value.forecasts, LISTED_CHANCE$1);
423
453
  if (referenceId === void 0 || name === void 0 || state === void 0 || totalWork === null || remainingWork === null) return null;
424
454
  return {
425
455
  referenceId,
@@ -429,7 +459,8 @@ const readFeatureListItem = (value) => {
429
459
  remainingWork,
430
460
  cannotBeForecast: Array.isArray(value.teamsWithoutForecast) && value.teamsWithoutForecast.length > 0,
431
461
  start: startOf(value.startForecast),
432
- likelyBy: expectedDateAt(value.forecasts, LISTED_CHANCE$1)
462
+ likelyBy: textOf(completion?.expectedDate),
463
+ likelyByBeyondHorizonYears: yearsBeyondHorizon(completion)
433
464
  };
434
465
  };
435
466
  /**
@@ -465,12 +496,15 @@ const describeFeatureProgress = (feature, terms) => `${feature.totalWork - featu
465
496
  const describeFeatureStart = (feature) => {
466
497
  if (feature.start.observedOn !== void 0) return dayOf(feature.start.observedOn);
467
498
  if (feature.cannotBeForecast) return CANNOT_FORECAST_SHORT;
468
- return feature.start.likelyBy === void 0 ? "—" : dayOf(feature.start.likelyBy);
499
+ return feature.start.likelyBy === void 0 ? "—" : describePercentileDay(feature.start.likelyBy, feature.start.likelyByBeyondHorizonYears);
469
500
  };
470
- /** The day the Feature is 85% likely to be done by, "Cannot forecast", or the mark when none was sent. */
501
+ /**
502
+ * The day the Feature is 85% likely to be done by, "More than 5 years" when that lies beyond the simulation
503
+ * horizon, "Cannot forecast", or the mark when none was sent.
504
+ */
471
505
  const describeFeatureCompletion = (feature) => {
472
506
  if (feature.cannotBeForecast) return CANNOT_FORECAST_SHORT;
473
- return feature.likelyBy === void 0 ? "—" : dayOf(feature.likelyBy);
507
+ return feature.likelyBy === void 0 ? "—" : describePercentileDay(feature.likelyBy, feature.likelyByBeyondHorizonYears);
474
508
  };
475
509
  /** One Feature as a row of the list, in the order of its headings. */
476
510
  const describeFeatureRow = (feature, terms) => [
@@ -633,6 +667,7 @@ const readDeliveryListItem = (value) => {
633
667
  const name = textOf(value.name);
634
668
  const date = textOf(value.date);
635
669
  if (name === void 0 || date === void 0) return null;
670
+ const likely = chanceAt(value.completionDates, LISTED_CHANCE);
636
671
  return {
637
672
  id: value.id,
638
673
  name,
@@ -644,7 +679,8 @@ const readDeliveryListItem = (value) => {
644
679
  cannotBeForecast: teamsWithoutForecastIn(value),
645
680
  hasSufficientData: flagOf(value.hasSufficientData),
646
681
  isOverdue: flagOf(value.isOverdue),
647
- likelyBy: expectedDateAt(value.completionDates, LISTED_CHANCE)
682
+ likelyBy: textOf(likely?.expectedDate),
683
+ likelyByBeyondHorizonYears: yearsBeyondHorizon(likely)
648
684
  };
649
685
  };
650
686
  /**
@@ -728,7 +764,7 @@ const describeDeliveryRow = (delivery, terms) => [
728
764
  delivery.featureCount === void 0 ? "—" : String(delivery.featureCount),
729
765
  describeDeliveryDone(delivery, terms),
730
766
  describeDeliveryLikelihood(delivery),
731
- delivery.likelyBy === void 0 ? "—" : dayOf(delivery.likelyBy)
767
+ delivery.likelyBy === void 0 ? "—" : describePercentileDay(delivery.likelyBy, delivery.likelyByBeyondHorizonYears)
732
768
  ];
733
769
  /** What heads the archived Deliveries, below the active ones: "Archived Deliveries". */
734
770
  const describeArchivedDeliveriesTitle = (terms) => `Archived ${terms.deliveries}`;
@@ -831,18 +867,23 @@ const describeDeliveryFeatureRow = (feature) => [
831
867
  ];
832
868
  /** The forecast distribution's column headings. */
833
869
  const describeDeliveryChanceHeadings = () => ["Chance", "Done by"];
834
- /** One chance of the day's forecast: "85%" and the day it is that likely to be done by. */
835
- const describeDeliveryChanceRow = (chance) => [`${chance.probability}%`, dayOf(chance.expectedDate)];
870
+ /** One chance of the day's forecast: "85%" and the day it is that likely to be done by, or "More than 5 years". */
871
+ const describeDeliveryChanceRow = (chance) => [`${chance.probability}%`, describePercentileDate(chance)];
836
872
  //#endregion
837
873
  //#region src/forecastWording.ts
838
- const optionalBoolean = (value) => {
874
+ const optionalBoolean$1 = (value) => {
839
875
  if (value === void 0 || typeof value === "boolean") return value;
840
876
  return null;
841
877
  };
842
- const readChanceByDay = (value) => isRecord(value) && isNumber(value.probability) && isDay(value.expectedDate) ? {
843
- probability: value.probability,
844
- expectedDate: value.expectedDate
845
- } : null;
878
+ const readChanceByDay = (value) => {
879
+ if (!isRecord(value) || !isNumber(value.probability) || !isDay(value.expectedDate)) return null;
880
+ return {
881
+ probability: value.probability,
882
+ expectedDate: value.expectedDate,
883
+ ...typeof value.beyondHorizon === "boolean" ? { beyondHorizon: value.beyondHorizon } : {},
884
+ ...isNumber(value.horizonYears) ? { horizonYears: value.horizonYears } : {}
885
+ };
886
+ };
846
887
  const readChanceOfCount = (value) => isRecord(value) && isNumber(value.probability) && isNumber(value.value) ? {
847
888
  probability: value.probability,
848
889
  value: value.value
@@ -858,8 +899,8 @@ const readManualForecast = (value) => {
858
899
  const { remainingItems, targetDate, likelihood } = value;
859
900
  const whenForecasts = readEvery$1(value.whenForecasts, readChanceByDay);
860
901
  const howManyForecasts = readEvery$1(value.howManyForecasts, readChanceOfCount);
861
- const filterApplied = optionalBoolean(value.filterApplied);
862
- const hasSufficientData = optionalBoolean(value.hasSufficientData);
902
+ const filterApplied = optionalBoolean$1(value.filterApplied);
903
+ const hasSufficientData = optionalBoolean$1(value.hasSufficientData);
863
904
  if (!isNumber(remainingItems) || !(targetDate === null || isDay(targetDate)) || !(likelihood === null || isNumber(likelihood)) || whenForecasts === null || howManyForecasts === null || filterApplied === null || hasSufficientData === null) return null;
864
905
  return {
865
906
  remainingItems,
@@ -1146,13 +1187,28 @@ const readRunChart = (value, range) => {
1146
1187
  const optionalText = (value) => isText(value) ? value : void 0;
1147
1188
  const optionalNumber = (value) => isNumber(value) ? value : void 0;
1148
1189
  const optionalDay = (value) => isDay(value) ? value : void 0;
1190
+ const optionalBoolean = (value) => typeof value === "boolean" ? value : void 0;
1191
+ const STALE_REASON_KINDS = [
1192
+ "TimeInState",
1193
+ "BlockedDuration",
1194
+ "TimeInStateWhileBlocked"
1195
+ ];
1196
+ const isStaleReasonKind = (value) => STALE_REASON_KINDS.some((kind) => kind === value);
1197
+ const readStaleReason = (value) => isRecord(value) && isStaleReasonKind(value.kind) && isNumber(value.days) ? {
1198
+ kind: value.kind,
1199
+ days: value.days,
1200
+ stateName: optionalText(value.stateName)
1201
+ } : null;
1202
+ const optionalStaleReasons = (value) => Array.isArray(value) ? value.map(readStaleReason).filter((reason) => reason !== null) : void 0;
1149
1203
  const readInProgressItem = (value) => isRecord(value) && (value.isBlocked === void 0 || typeof value.isBlocked === "boolean") ? {
1150
1204
  isBlocked: value.isBlocked,
1151
1205
  referenceId: optionalText(value.referenceId),
1152
1206
  name: optionalText(value.name),
1153
1207
  state: optionalText(value.state),
1154
1208
  workItemAge: optionalNumber(value.workItemAge),
1155
- blockedSince: optionalDay(value.blockedSince)
1209
+ blockedSince: optionalDay(value.blockedSince),
1210
+ isStale: optionalBoolean(value.isStale),
1211
+ staleReasons: optionalStaleReasons(value.staleReasons)
1156
1212
  } : null;
1157
1213
  const readInProgressNow = (value) => {
1158
1214
  if (!isRecord(value) || !isDay(value.asOfDate) || !isNumber(value.count)) return null;
@@ -1351,6 +1407,7 @@ const metricsHeadlineLabel = (part, scope, terms) => {
1351
1407
  throughput: `Total ${terms.throughput}`,
1352
1408
  arrivals: "Total Arrivals",
1353
1409
  blocked: `${terms.blocked} ${counted.many}`,
1410
+ stale: `Stale ${counted.many}`,
1354
1411
  totalWorkItemAge: `Total ${terms.workItemAge}`,
1355
1412
  predictabilityScore: "Predictability Score",
1356
1413
  cycleTimePercentiles: `${terms.cycleTime} percentiles`,
@@ -1394,27 +1451,31 @@ const describeInProgressNow = (now, scope, terms, systemWipLimit) => ({
1394
1451
  value: String(now.count),
1395
1452
  detail: systemWipLimit === void 0 ? "" : wipLimitOf(systemWipLimit, scope, terms)
1396
1453
  });
1454
+ const blockedFlag = (item) => item.isBlocked;
1455
+ const staleFlag = (item) => item.isStale;
1456
+ const saysWhichAre = (now, flag) => now.items.some((item) => flag(item) !== void 0);
1457
+ const countFlaggedNow = (part, flag, now, scope, terms) => saysWhichAre(now, flag) ? {
1458
+ label: metricsHeadlineLabel(part, scope, terms),
1459
+ value: String(now.items.filter((item) => flag(item) === true).length),
1460
+ detail: ""
1461
+ } : null;
1397
1462
  /** "Blocked Work Items 2", or null when Lighthouse does not say which items are blocked. */
1398
- const describeBlockedNow = (now, scope, terms) => {
1399
- if (!now.items.some((item) => item.isBlocked !== void 0)) return null;
1400
- const blocked = now.items.filter((item) => item.isBlocked === true).length;
1401
- return {
1402
- label: metricsHeadlineLabel("blocked", scope, terms),
1403
- value: String(blocked),
1404
- detail: ""
1405
- };
1406
- };
1463
+ const describeBlockedNow = (now, scope, terms) => countFlaggedNow("blocked", blockedFlag, now, scope, terms);
1464
+ /** "Stale Work Items 2", or null when Lighthouse does not say which items are stale. */
1465
+ const describeStaleNow = (now, scope, terms) => countFlaggedNow("stale", staleFlag, now, scope, terms);
1407
1466
  /**
1408
1467
  * The sentences that stand in for what a WIP answer cannot show: no System WIP Limit, a Lighthouse that does
1409
- * not say which Work Items are Blocked (which is not the same as none being Blocked), and nothing in progress.
1410
- * A limit of null means the Team or Portfolio could not be read; it may well have one, so nothing is said.
1468
+ * not say which Work Items are Blocked or Stale (which is not the same as none being so), and nothing in
1469
+ * progress. A limit of null means the Team or Portfolio could not be read; it may well have one, so nothing
1470
+ * is said.
1411
1471
  */
1412
1472
  const describeWhatWipLeavesUnsaid = (now, scope, terms, systemWipLimit) => {
1413
1473
  const counted = countedOf(scope, terms);
1414
- const blockedUnknown = now.items.length > 0 && now.items.every((item) => item.isBlocked === void 0);
1474
+ const silentOn = (flag) => now.items.length > 0 && !saysWhichAre(now, flag);
1415
1475
  return [
1416
1476
  ...systemWipLimit === void 0 ? [`No System ${terms.wip} Limit is set.`] : [],
1417
- ...blockedUnknown ? [`Lighthouse does not say which ${counted.many} are ${terms.blocked}.`] : [],
1477
+ ...silentOn(blockedFlag) ? [`Lighthouse does not say which ${counted.many} are ${terms.blocked}.`] : [],
1478
+ ...silentOn(staleFlag) ? [`Lighthouse does not say which ${counted.many} are Stale.`] : [],
1418
1479
  ...now.items.length === 0 ? [`No ${counted.many} are in progress.`] : []
1419
1480
  ];
1420
1481
  };
@@ -2118,6 +2179,114 @@ const readNameOfMyVote = async (client, teamId, workItem, voterKey) => {
2118
2179
  return log.ok ? nameOfMyVote(log.value) : null;
2119
2180
  };
2120
2181
  //#endregion
2182
+ //#region src/reportWording.ts
2183
+ const readWindow = (value) => isRecord(value) && isDay(value.start) && isDay(value.end) ? {
2184
+ start: value.start,
2185
+ end: value.end
2186
+ } : null;
2187
+ /** The report's name and windows, or null when the answer does not carry all three. */
2188
+ const readReport = (value) => {
2189
+ if (!isRecord(value) || !isRecord(value.thenAndNow)) return null;
2190
+ const name = textOf(value.name);
2191
+ const thenWindow = readWindow(value.thenAndNow.thenWindow);
2192
+ const nowWindow = readWindow(value.thenAndNow.nowWindow);
2193
+ if (name === void 0 || thenWindow === null || nowWindow === null) return null;
2194
+ return {
2195
+ name,
2196
+ thenWindow,
2197
+ nowWindow
2198
+ };
2199
+ };
2200
+ const readReportListItem = (value) => {
2201
+ if (!isRecord(value) || typeof value.id !== "number") return null;
2202
+ const name = textOf(value.name);
2203
+ if (name === void 0) return null;
2204
+ return {
2205
+ id: value.id,
2206
+ name,
2207
+ templateKey: textOf(value.templateKey),
2208
+ createdOn: textOf(value.createdOn)
2209
+ };
2210
+ };
2211
+ /**
2212
+ * Every report in the list, or null when the answer holds no list or any one report comes without its id or
2213
+ * name: a row that cannot say which report it is would misname the whole list.
2214
+ */
2215
+ const readReportList = (value) => {
2216
+ if (!isRecord(value) || !Array.isArray(value.reports)) return null;
2217
+ const items = value.reports.map(readReportListItem);
2218
+ return items.every((item) => item !== null) ? items : null;
2219
+ };
2220
+ const ownerTerm$1 = (kind, terms) => kind === "team" ? terms.team : terms.portfolio;
2221
+ /** The owner as the instance names it, "Team Lightspeed", or by its id when its name could not be read. */
2222
+ const describeReportOwner = (kind, id, owner, terms) => {
2223
+ const term = ownerTerm$1(kind, terms);
2224
+ const name = isRecord(owner) ? textOf(owner.name) : void 0;
2225
+ return name === void 0 ? `${term} [id: ${id}]` : `${term} ${name}`;
2226
+ };
2227
+ const describeWindow = (label, window) => `${label} ${dayOf(window.start)} – ${dayOf(window.end)}`;
2228
+ /** The report's name, its owner and its two windows, one to a line. */
2229
+ const describeReportSummary = (report, owner) => [
2230
+ report.name,
2231
+ owner,
2232
+ `${describeWindow("Then", report.thenWindow)} · ${describeWindow("Now", report.nowWindow)}`
2233
+ ].join("\n");
2234
+ const describeReportCount = (count) => {
2235
+ if (count === 0) return "No reports";
2236
+ return count === 1 ? "1 report" : `${count} reports`;
2237
+ };
2238
+ const describeReportListItem = (item) => [
2239
+ `${item.name} [id: ${item.id}]`,
2240
+ item.templateKey,
2241
+ item.createdOn === void 0 ? void 0 : `created ${dayOf(item.createdOn)}`
2242
+ ].filter((part) => part !== void 0).join(" · ");
2243
+ /** How many reports the owner has, then each report's name, type and created day. */
2244
+ const describeReportListSummary = (reports, owner) => [`${owner} · ${describeReportCount(reports.length)}`, ...reports.map(describeReportListItem)].join("\n");
2245
+ const summariseReport = (value, owner) => {
2246
+ const report = readReport(value);
2247
+ return report === null ? null : describeReportSummary(report, owner);
2248
+ };
2249
+ const summariseReportList = (value, owner) => {
2250
+ const reports = readReportList(value);
2251
+ return reports === null ? null : describeReportListSummary(reports, owner);
2252
+ };
2253
+ const FORBIDDEN = 403;
2254
+ const NOT_FOUND = 404;
2255
+ const NOTHING_THERE = {
2256
+ list: (owner) => `There is no such ${owner}.`,
2257
+ report: (owner) => `There is no such report for that ${owner}.`
2258
+ };
2259
+ /**
2260
+ * Why a report or a list could not be read, in words the reader can act on: the web's sentence where it has
2261
+ * one. Any other refusal, the client's own "upgrade Lighthouse" among them, keeps its category and reason.
2262
+ */
2263
+ const describeReportRefusal = (error, kind, read, terms) => {
2264
+ if (error.statusCode === FORBIDDEN) return `You have no access to that ${ownerTerm$1(kind, terms)}'s reports.`;
2265
+ if (error.problemCode === "template-not-supported") return "This report was made by a newer version of Lighthouse and can't be shown here.";
2266
+ if (error.statusCode === NOT_FOUND) return NOTHING_THERE[read](ownerTerm$1(kind, terms));
2267
+ return `${error.category}: ${error.reason}`;
2268
+ };
2269
+ /**
2270
+ * {@link describeReportRefusal} in the instance's own words. A refusal the client made before asking, as for a
2271
+ * Lighthouse too old for reports, asks that Lighthouse nothing more, not even its words.
2272
+ */
2273
+ const readReportRefusal = async (source, error, kind, read) => describeReportRefusal(error, kind, read, error.statusCode === void 0 ? SEEDED_TERMS : await readTerms(source));
2274
+ //#endregion
2275
+ //#region src/reportReads.ts
2276
+ /** The owner's list of reports, exactly as Lighthouse answers it. */
2277
+ const readOwnersReports = (reads, owner) => owner.kind === "team" ? reads.getTeamReports(owner.id) : reads.getPortfolioReports(owner.id);
2278
+ /** One of the owner's reports, exactly as Lighthouse answers it. */
2279
+ const readOwnersReport = (reads, owner, reportId) => owner.kind === "team" ? reads.getTeamReport(owner.id, reportId) : reads.getPortfolioReport(owner.id, reportId);
2280
+ /**
2281
+ * {@link describeReportOwner} for an owner read from Lighthouse. Its name only labels a summary, so an owner that
2282
+ * cannot be read is named by its id instead, and this never fails.
2283
+ */
2284
+ const readReportOwner = async (source, owner) => {
2285
+ const read = owner.kind === "team" ? source.getTeam(owner.id) : source.getPortfolio(owner.id);
2286
+ const [terms, named] = await Promise.all([readTerms(source), read.then((answer) => answer.ok ? answer.value : void 0, () => void 0)]);
2287
+ return describeReportOwner(owner.kind, owner.id, named, terms);
2288
+ };
2289
+ //#endregion
2121
2290
  //#region src/usageDataReporter.ts
2122
2291
  /** A command's own answer never waits on usage data for longer than this, whatever Lighthouse does. */
2123
2292
  const USAGE_DATA_BUDGET_MS = 1e3;
@@ -3159,7 +3328,9 @@ const FEATURE_REQUIRES_SERVER_NEWER_THAN = {
3159
3328
  deliveryMetricsHistory: "v26.5.29.5",
3160
3329
  sleRisk: "v26.9.19.10",
3161
3330
  teamRefinement: "v26.10.3.6",
3162
- refinementVotes: "v26.10.3.6"
3331
+ refinementVotes: "v26.10.3.6",
3332
+ staleness: "v26.10.16.6",
3333
+ reports: "v26.10.10.1"
3163
3334
  };
3164
3335
  /**
3165
3336
  * Parses a Lighthouse version string ("v26.5.24.10", "26.5.24") into numeric
@@ -3221,6 +3392,7 @@ const createLighthouseClient = (configuration, dependencies = {}) => {
3221
3392
  }
3222
3393
  };
3223
3394
  };
3395
+ const readReports = async (route) => await ensureServerSupports("reports") ?? requestJson(configuration, dependencies, route, { method: "GET" });
3224
3396
  return {
3225
3397
  checkConnectivity: async () => {
3226
3398
  const fetchDependency = getFetchDependency(dependencies);
@@ -3297,6 +3469,10 @@ const createLighthouseClient = (configuration, dependencies = {}) => {
3297
3469
  headers: voterKeyHeaders(options?.voterKey)
3298
3470
  });
3299
3471
  },
3472
+ getTeamReports: async (teamId) => readReports(`/v1/teams/${teamId}/reports`),
3473
+ getTeamReport: async (teamId, reportId) => readReports(`/v1/teams/${teamId}/reports/${reportId}`),
3474
+ getPortfolioReports: async (portfolioId) => readReports(`/v1/portfolios/${portfolioId}/reports`),
3475
+ getPortfolioReport: async (portfolioId, reportId) => readReports(`/v1/portfolios/${portfolioId}/reports/${reportId}`),
3300
3476
  getTerminology: async () => requestJson(configuration, dependencies, "/v1/terminology/all", { method: "GET" }),
3301
3477
  listPortfolios: async () => requestJson(configuration, dependencies, "/v1/portfolios", { method: "GET" }),
3302
3478
  getPortfolio: async (portfolioId) => requestJson(configuration, dependencies, `/v1/portfolios/${portfolioId}`, { method: "GET" }),
@@ -3706,6 +3882,8 @@ exports.describeOwnerListHeadings = describeOwnerListHeadings;
3706
3882
  exports.describeOwnerListTitle = describeOwnerListTitle;
3707
3883
  exports.describeOwnerName = describeOwnerName;
3708
3884
  exports.describeOwnerWriteConfirmation = describeOwnerWriteConfirmation;
3885
+ exports.describePercentileDate = describePercentileDate;
3886
+ exports.describePercentileDay = describePercentileDay;
3709
3887
  exports.describePercentileRows = describePercentileRows;
3710
3888
  exports.describePercentilesOverTime = describePercentilesOverTime;
3711
3889
  exports.describePercentilesOverTimeDays = describePercentilesOverTimeDays;
@@ -3725,7 +3903,12 @@ exports.describeRecordedVote = describeRecordedVote;
3725
3903
  exports.describeRefinementSummary = describeRefinementSummary;
3726
3904
  exports.describeRefreshConfirmation = describeRefreshConfirmation;
3727
3905
  exports.describeRefusedMetric = describeRefusedMetric;
3906
+ exports.describeReportListSummary = describeReportListSummary;
3907
+ exports.describeReportOwner = describeReportOwner;
3908
+ exports.describeReportRefusal = describeReportRefusal;
3909
+ exports.describeReportSummary = describeReportSummary;
3728
3910
  exports.describeSleRiskNow = describeSleRiskNow;
3911
+ exports.describeStaleNow = describeStaleNow;
3729
3912
  exports.describeTags = describeTags;
3730
3913
  exports.describeTakenBack = describeTakenBack;
3731
3914
  exports.describeTeamSummary = describeTeamSummary;
@@ -3774,6 +3957,7 @@ exports.likelihoodAnswer = likelihoodAnswer;
3774
3957
  exports.loadStandaloneDiscoveryContract = loadStandaloneDiscoveryContract;
3775
3958
  exports.metricsHeadlineLabel = metricsHeadlineLabel;
3776
3959
  exports.mintVoterKey = mintVoterKey;
3960
+ exports.moreThanYearsText = moreThanYearsText;
3777
3961
  exports.myVoteOn = myVoteOn;
3778
3962
  exports.nameOrFallback = nameOrFallback;
3779
3963
  exports.ordinalOf = ordinalOf;
@@ -3805,6 +3989,8 @@ exports.readMetricAnswer = readMetricAnswer;
3805
3989
  exports.readMetricsSubject = readMetricsSubject;
3806
3990
  exports.readNameOfMyVote = readNameOfMyVote;
3807
3991
  exports.readOwnerList = readOwnerList;
3992
+ exports.readOwnersReport = readOwnersReport;
3993
+ exports.readOwnersReports = readOwnersReports;
3808
3994
  exports.readPercentilesOverTime = readPercentilesOverTime;
3809
3995
  exports.readPortfolio = readPortfolio;
3810
3996
  exports.readPortfolioDeliveries = readPortfolioDeliveries;
@@ -3813,6 +3999,10 @@ exports.readProcessBehaviorChart = readProcessBehaviorChart;
3813
3999
  exports.readProcessBehaviorOverTime = readProcessBehaviorOverTime;
3814
4000
  exports.readRefinementTerms = readRefinementTerms;
3815
4001
  exports.readRefinementWording = readRefinementWording;
4002
+ exports.readReport = readReport;
4003
+ exports.readReportList = readReportList;
4004
+ exports.readReportOwner = readReportOwner;
4005
+ exports.readReportRefusal = readReportRefusal;
3816
4006
  exports.readRunChart = readRunChart;
3817
4007
  exports.readServiceLevelExpectation = readServiceLevelExpectation;
3818
4008
  exports.readSleRisk = readSleRisk;
@@ -3834,14 +4024,18 @@ exports.readWorkTrackingConnections = readWorkTrackingConnections;
3834
4024
  exports.readWrittenBlackoutRule = readWrittenBlackoutRule;
3835
4025
  exports.readWrittenOwner = readWrittenOwner;
3836
4026
  exports.refinementDayVerdictOf = refinementDayVerdictOf;
4027
+ exports.reportOpenedOccurrencesOf = reportOpenedOccurrencesOf;
3837
4028
  exports.resolveTerms = resolveTerms;
3838
4029
  exports.settleUsageDataStep = settleUsageDataStep;
3839
4030
  exports.sizingMomentOf = sizingMomentOf;
3840
4031
  exports.startCliAuthSession = startCliAuthSession;
3841
4032
  exports.summariseDeliveryMetricsHistory = summariseDeliveryMetricsHistory;
4033
+ exports.summariseReport = summariseReport;
4034
+ exports.summariseReportList = summariseReportList;
3842
4035
  exports.switchUsageDataOn = switchUsageDataOn;
3843
4036
  exports.timeInStateItemCount = timeInStateItemCount;
3844
4037
  exports.usageDataStoreFor = usageDataStoreFor;
3845
4038
  exports.validateLighthouseConnectivity = validateLighthouseConnectivity;
3846
4039
  exports.voterKeyStoreFor = voterKeyStoreFor;
3847
4040
  exports.withdrawUsageData = withdrawUsageData;
4041
+ exports.yearsBeyondHorizon = yearsBeyondHorizon;