@letpeoplework/lighthouse-client 1.2.0 → 1.4.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
@@ -579,6 +579,47 @@ var toApiError = (statusCode, reason) => ({
579
579
  reason,
580
580
  statusCode
581
581
  });
582
+ var CONCURRENCY_CONFLICT_STATUS = 409;
583
+ var CONCURRENCY_CONFLICT_GUIDANCE = "This edit conflicts because the item was changed by someone else. Re-fetch the current settings to obtain the latest concurrency token, then re-apply your change.";
584
+ var getProblemDetailsMessage = (body) => {
585
+ if (!isObjectRecord(body)) {
586
+ return void 0;
587
+ }
588
+ for (const key of ["detail", "title", "message"]) {
589
+ const value = body[key];
590
+ if (typeof value === "string" && value.trim().length > 0) {
591
+ return value.trim();
592
+ }
593
+ }
594
+ return void 0;
595
+ };
596
+ var getResponseBody = async (response) => {
597
+ try {
598
+ if (response.json !== void 0) {
599
+ return await response.json();
600
+ }
601
+ return JSON.parse(await response.text());
602
+ } catch {
603
+ return void 0;
604
+ }
605
+ };
606
+ var toConcurrencyConflictError = (serverMessage) => ({
607
+ category: "concurrency-conflict",
608
+ reason: serverMessage === void 0 ? CONCURRENCY_CONFLICT_GUIDANCE : `${serverMessage} ${CONCURRENCY_CONFLICT_GUIDANCE}`,
609
+ statusCode: CONCURRENCY_CONFLICT_STATUS
610
+ });
611
+ var toResponseError = async (response) => {
612
+ if (response.status === CONCURRENCY_CONFLICT_STATUS) {
613
+ const serverMessage = getProblemDetailsMessage(
614
+ await getResponseBody(response)
615
+ );
616
+ return toConcurrencyConflictError(serverMessage);
617
+ }
618
+ return toApiError(
619
+ response.status,
620
+ `Request failed with status ${response.status}.`
621
+ );
622
+ };
582
623
  var requestText = async (configuration, dependencies, route) => {
583
624
  const fetchDependency = getFetchDependency(dependencies);
584
625
  const connectivityResult = await validateLighthouseConnectivity(
@@ -597,12 +638,7 @@ var requestText = async (configuration, dependencies, route) => {
597
638
  getRequestInit(configuration.auth)
598
639
  );
599
640
  if (!response.ok) {
600
- return getErrorResult(
601
- toApiError(
602
- response.status,
603
- `Request failed with status ${response.status}.`
604
- )
605
- );
641
+ return getErrorResult(await toResponseError(response));
606
642
  }
607
643
  return {
608
644
  ok: true,
@@ -636,12 +672,7 @@ var requestJson = async (configuration, dependencies, route, requestOptions) =>
636
672
  getRequestInit(configuration.auth, requestOptions)
637
673
  );
638
674
  if (!response.ok) {
639
- return getErrorResult(
640
- toApiError(
641
- response.status,
642
- `Request failed with status ${response.status}.`
643
- )
644
- );
675
+ return getErrorResult(await toResponseError(response));
645
676
  }
646
677
  if (response.json === void 0) {
647
678
  return {
@@ -682,12 +713,7 @@ var requestNoContent = async (configuration, dependencies, route, requestOptions
682
713
  getRequestInit(configuration.auth, requestOptions)
683
714
  );
684
715
  if (!response.ok) {
685
- return getErrorResult(
686
- toApiError(
687
- response.status,
688
- `Request failed with status ${response.status}.`
689
- )
690
- );
716
+ return getErrorResult(await toResponseError(response));
691
717
  }
692
718
  return {
693
719
  ok: true,
@@ -706,6 +732,7 @@ var getMetricsDateRangeQuery = (range) => `startDate=${encodeURIComponent(range.
706
732
  var getMetricsAsOfDateQuery = (asOfDate) => `asOfDate=${encodeURIComponent(asOfDate)}`;
707
733
  var getItemIdsQuerySuffix = (itemIds) => itemIds && itemIds.length > 0 ? itemIds.map((id) => `&itemIds=${encodeURIComponent(id)}`).join("") : "";
708
734
  var getViewQuerySuffix = (view) => view === "filtered" ? "&view=filtered" : "";
735
+ var getDefinitionIdQuerySuffix = (definitionId) => definitionId !== void 0 ? `&definitionId=${encodeURIComponent(definitionId)}` : "";
709
736
  var addUtcDays = (dateStr, days) => {
710
737
  const d = /* @__PURE__ */ new Date(`${dateStr}T00:00:00Z`);
711
738
  d.setUTCDate(d.getUTCDate() + days);
@@ -756,7 +783,9 @@ var deriveTotalWorkItemAgeOverTime = (startDate, endDate, wipData) => {
756
783
  return { startDate, endDate, daily };
757
784
  };
758
785
  var FEATURE_REQUIRES_SERVER_NEWER_THAN = {
759
- cumulativeStateTime: "v26.5.24.10"
786
+ cumulativeStateTime: "v26.5.24.10",
787
+ recurringBlackoutRules: "v26.5.29.5",
788
+ workItemAgePercentiles: "v26.6.7.1"
760
789
  };
761
790
  var parseServerVersion = (raw) => {
762
791
  const trimmed = raw.trim().replace(/^v/iu, "");
@@ -977,12 +1006,25 @@ var createLighthouseClient = (configuration, dependencies = {}) => {
977
1006
  `/v1/teams/${teamId}/metrics/wip?${getMetricsAsOfDateQuery(asOfDate)}`,
978
1007
  { method: "GET" }
979
1008
  ),
980
- getTeamCycleTimePercentiles: async (teamId, range) => {
1009
+ getTeamCycleTimePercentiles: async (teamId, range, definitionId) => {
1010
+ const r = getResolvedMetricsDateRange(range);
1011
+ return requestJson(
1012
+ configuration,
1013
+ dependencies,
1014
+ `/v1/teams/${teamId}/metrics/cycleTimePercentiles?${getMetricsDateRangeQuery(r)}${getDefinitionIdQuerySuffix(definitionId)}`,
1015
+ { method: "GET" }
1016
+ );
1017
+ },
1018
+ getTeamWorkItemAgePercentiles: async (teamId, range) => {
1019
+ const unsupported = await ensureServerSupports("workItemAgePercentiles");
1020
+ if (unsupported) {
1021
+ return unsupported;
1022
+ }
981
1023
  const r = getResolvedMetricsDateRange(range);
982
1024
  return requestJson(
983
1025
  configuration,
984
1026
  dependencies,
985
- `/v1/teams/${teamId}/metrics/cycleTimePercentiles?${getMetricsDateRangeQuery(r)}`,
1027
+ `/v1/teams/${teamId}/metrics/workItemAgePercentiles?${getMetricsDateRangeQuery(r)}`,
986
1028
  { method: "GET" }
987
1029
  );
988
1030
  },
@@ -1068,12 +1110,25 @@ var createLighthouseClient = (configuration, dependencies = {}) => {
1068
1110
  { method: "GET" }
1069
1111
  );
1070
1112
  },
1071
- getPortfolioCycleTimePercentiles: async (portfolioId, range) => {
1113
+ getPortfolioCycleTimePercentiles: async (portfolioId, range, definitionId) => {
1114
+ const r = getResolvedMetricsDateRange(range);
1115
+ return requestJson(
1116
+ configuration,
1117
+ dependencies,
1118
+ `/v1/portfolios/${portfolioId}/metrics/cycleTimePercentiles?${getMetricsDateRangeQuery(r)}${getDefinitionIdQuerySuffix(definitionId)}`,
1119
+ { method: "GET" }
1120
+ );
1121
+ },
1122
+ getPortfolioWorkItemAgePercentiles: async (portfolioId, range) => {
1123
+ const unsupported = await ensureServerSupports("workItemAgePercentiles");
1124
+ if (unsupported) {
1125
+ return unsupported;
1126
+ }
1072
1127
  const r = getResolvedMetricsDateRange(range);
1073
1128
  return requestJson(
1074
1129
  configuration,
1075
1130
  dependencies,
1076
- `/v1/portfolios/${portfolioId}/metrics/cycleTimePercentiles?${getMetricsDateRangeQuery(r)}`,
1131
+ `/v1/portfolios/${portfolioId}/metrics/workItemAgePercentiles?${getMetricsDateRangeQuery(r)}`,
1077
1132
  { method: "GET" }
1078
1133
  );
1079
1134
  },
@@ -1300,6 +1355,54 @@ var createLighthouseClient = (configuration, dependencies = {}) => {
1300
1355
  `/v1/deliveries/${deliveryId}`,
1301
1356
  { method: "DELETE" }
1302
1357
  ),
1358
+ getRecurringBlackoutRules: async () => {
1359
+ const unsupported = await ensureServerSupports("recurringBlackoutRules");
1360
+ if (unsupported) {
1361
+ return unsupported;
1362
+ }
1363
+ return requestJson(
1364
+ configuration,
1365
+ dependencies,
1366
+ "/v1/recurring-blackout-rules",
1367
+ { method: "GET" }
1368
+ );
1369
+ },
1370
+ createRecurringBlackoutRule: async (payload) => {
1371
+ const unsupported = await ensureServerSupports("recurringBlackoutRules");
1372
+ if (unsupported) {
1373
+ return unsupported;
1374
+ }
1375
+ return requestJson(
1376
+ configuration,
1377
+ dependencies,
1378
+ "/v1/recurring-blackout-rules",
1379
+ { method: "POST", body: payload }
1380
+ );
1381
+ },
1382
+ updateRecurringBlackoutRule: async (id, payload) => {
1383
+ const unsupported = await ensureServerSupports("recurringBlackoutRules");
1384
+ if (unsupported) {
1385
+ return unsupported;
1386
+ }
1387
+ return requestJson(
1388
+ configuration,
1389
+ dependencies,
1390
+ `/v1/recurring-blackout-rules/${id}`,
1391
+ { method: "PUT", body: payload }
1392
+ );
1393
+ },
1394
+ deleteRecurringBlackoutRule: async (id) => {
1395
+ const unsupported = await ensureServerSupports("recurringBlackoutRules");
1396
+ if (unsupported) {
1397
+ return unsupported;
1398
+ }
1399
+ return requestNoContent(
1400
+ configuration,
1401
+ dependencies,
1402
+ `/v1/recurring-blackout-rules/${id}`,
1403
+ { method: "DELETE" }
1404
+ );
1405
+ },
1303
1406
  runManualForecast: async (teamId, payload) => requestJson(
1304
1407
  configuration,
1305
1408
  dependencies,
package/dist/index.d.cts CHANGED
@@ -4,7 +4,7 @@ type ClientPackageContract = {
4
4
  readonly capabilities: readonly ClientCapability[];
5
5
  };
6
6
  declare const getClientPackageContract: () => ClientPackageContract;
7
- type ConnectivityCategory = "success" | "unreachable" | "misconfigured" | "unauthorized" | "dependency-failure" | "unexpected";
7
+ type ConnectivityCategory = "success" | "unreachable" | "misconfigured" | "unauthorized" | "dependency-failure" | "concurrency-conflict" | "unexpected";
8
8
  type StandaloneDiscoveryContract = {
9
9
  readonly contractVersion: 1;
10
10
  readonly lighthouseUrl: string;
@@ -257,6 +257,23 @@ type CumulativeStateTimeCandidateRow = {
257
257
  type CumulativeStateTimeCandidatesResult = {
258
258
  readonly items: readonly CumulativeStateTimeCandidateRow[];
259
259
  };
260
+ type DayOfWeek = "Sunday" | "Monday" | "Tuesday" | "Wednesday" | "Thursday" | "Friday" | "Saturday";
261
+ type RecurringBlackoutRule = {
262
+ readonly id: number;
263
+ readonly weekdays: readonly DayOfWeek[];
264
+ readonly intervalWeeks: number;
265
+ readonly start: string;
266
+ readonly end: string | null;
267
+ readonly description: string;
268
+ readonly summary: string;
269
+ };
270
+ type RecurringBlackoutRuleInput = {
271
+ readonly weekdays: readonly DayOfWeek[];
272
+ readonly intervalWeeks: number;
273
+ readonly start: string;
274
+ readonly end: string | null;
275
+ readonly description: string;
276
+ };
260
277
  type LighthouseClient = {
261
278
  readonly checkConnectivity: () => Promise<ConnectivityValidationResult>;
262
279
  readonly getVersion: () => Promise<LighthouseApiResult<string>>;
@@ -281,13 +298,15 @@ type LighthouseClient = {
281
298
  readonly getTeamArrivals: (teamId: number, range?: MetricsDateRange) => Promise<LighthouseApiResult<unknown>>;
282
299
  readonly getTeamWipOverTime: (teamId: number, range?: MetricsDateRange) => Promise<LighthouseApiResult<unknown>>;
283
300
  readonly getTeamWip: (teamId: number, asOfDate: string) => Promise<LighthouseApiResult<readonly unknown[]>>;
284
- readonly getTeamCycleTimePercentiles: (teamId: number, range?: MetricsDateRange) => Promise<LighthouseApiResult<readonly unknown[]>>;
301
+ readonly getTeamCycleTimePercentiles: (teamId: number, range?: MetricsDateRange, definitionId?: number) => Promise<LighthouseApiResult<readonly unknown[]>>;
302
+ readonly getTeamWorkItemAgePercentiles: (teamId: number, range?: MetricsDateRange) => Promise<LighthouseApiResult<readonly unknown[]>>;
285
303
  readonly getTeamCycleTimeData: (teamId: number, range?: MetricsDateRange) => Promise<LighthouseApiResult<readonly unknown[]>>;
286
304
  readonly getTeamPredictabilityScore: (teamId: number, range?: MetricsDateRange, view?: ThroughputFilterView) => Promise<LighthouseApiResult<unknown>>;
287
305
  readonly getTeamTotalWorkItemAge: (teamId: number, asOfDate: string) => Promise<LighthouseApiResult<number>>;
288
306
  readonly getTeamTotalWorkItemAgeInfo: (teamId: number, range?: MetricsDateRange) => Promise<LighthouseApiResult<unknown>>;
289
307
  readonly getPortfolioThroughput: (portfolioId: number, range?: MetricsDateRange) => Promise<LighthouseApiResult<unknown>>;
290
- readonly getPortfolioCycleTimePercentiles: (portfolioId: number, range?: MetricsDateRange) => Promise<LighthouseApiResult<readonly unknown[]>>;
308
+ readonly getPortfolioCycleTimePercentiles: (portfolioId: number, range?: MetricsDateRange, definitionId?: number) => Promise<LighthouseApiResult<readonly unknown[]>>;
309
+ readonly getPortfolioWorkItemAgePercentiles: (portfolioId: number, range?: MetricsDateRange) => Promise<LighthouseApiResult<readonly unknown[]>>;
291
310
  readonly getPortfolioArrivals: (portfolioId: number, range?: MetricsDateRange) => Promise<LighthouseApiResult<unknown>>;
292
311
  readonly getPortfolioWipOverTime: (portfolioId: number, range?: MetricsDateRange) => Promise<LighthouseApiResult<unknown>>;
293
312
  readonly getPortfolioWip: (portfolioId: number, asOfDate: string) => Promise<LighthouseApiResult<readonly unknown[]>>;
@@ -312,6 +331,10 @@ type LighthouseClient = {
312
331
  readonly createDelivery: (portfolioId: number, payload: LighthouseWritePayload) => Promise<LighthouseApiResult<unknown>>;
313
332
  readonly updateDelivery: (deliveryId: number, payload: LighthouseWritePayload) => Promise<LighthouseApiResult<unknown>>;
314
333
  readonly deleteDelivery: (deliveryId: number) => Promise<LighthouseApiResult<undefined>>;
334
+ readonly getRecurringBlackoutRules: () => Promise<LighthouseApiResult<readonly RecurringBlackoutRule[]>>;
335
+ readonly createRecurringBlackoutRule: (payload: LighthouseWritePayload) => Promise<LighthouseApiResult<RecurringBlackoutRule>>;
336
+ readonly updateRecurringBlackoutRule: (id: number, payload: LighthouseWritePayload) => Promise<LighthouseApiResult<RecurringBlackoutRule>>;
337
+ readonly deleteRecurringBlackoutRule: (id: number) => Promise<LighthouseApiResult<undefined>>;
315
338
  readonly runManualForecast: (teamId: number, payload: ManualForecastInput) => Promise<LighthouseApiResult<unknown>>;
316
339
  readonly runBacktest: (teamId: number, payload: BacktestInput) => Promise<LighthouseApiResult<unknown>>;
317
340
  };
@@ -326,4 +349,4 @@ type LighthouseClientDependencies = {
326
349
  declare const isServerVersionNewerThan: (candidate: string, baseline: string) => boolean | null;
327
350
  declare const createLighthouseClient: (configuration: LighthouseClientConfiguration, dependencies?: LighthouseClientDependencies) => LighthouseClient;
328
351
 
329
- export { type BacktestInput, type CliAuthSessionPollResult, type CliAuthSessionStartError, type CliAuthSessionStartOutcome, type CliAuthSessionStartResult, type CliConnection, type CliServerAuthMode, type CliServerConnection, type CliStandaloneConnection, type ClientCapability, type ClientPackageContract, type ConnectivityCategory, type ConnectivityDependencies, type ConnectivityFetchResponse, type ConnectivityValidationResult, type CumulativeStateTimeCandidateRow, type CumulativeStateTimeCandidatesResult, type CumulativeStateTimeItemRow, type CumulativeStateTimeItemsResult, type CumulativeStateTimeResult, type CumulativeStateTimeStateRow, type DailyTotalWorkItemAge, type DailyWorkItemAge, type LighthouseApiError, type LighthouseApiResult, type LighthouseAuthContext, type LighthouseAuthOverrides, type LighthouseAuthStatus, type LighthouseAuthStore, type LighthouseClient, type LighthouseClientAuth, type LighthouseClientConfiguration, type LighthouseClientDependencies, type LighthouseConnectionConfiguration, type LighthouseWritePayload, type ManualForecastInput, type MetricsDateRange, type ResolvedLighthouseEndpoint, type ServerAuthModeResult, type StandaloneDiscoveryContract, type StandaloneDiscoveryContractParseResult, type StoredLighthouseAuth, type ThroughputFilterView, type TotalWorkItemAgeOverTimeResult, type WorkItemAgeEntry, type WorkItemAgeOverTimeResult, createLighthouseAuthContext, createLighthouseClient, getClientPackageContract, getDefaultMetricsDateRange, getStandaloneDiscoveryLockfilePath, isServerVersionNewerThan, loadStandaloneDiscoveryContract, parseStandaloneDiscoveryContract, pollCliAuthSession, queryServerAuthMode, startCliAuthSession, validateLighthouseConnectivity };
352
+ export { type BacktestInput, type CliAuthSessionPollResult, type CliAuthSessionStartError, type CliAuthSessionStartOutcome, type CliAuthSessionStartResult, type CliConnection, type CliServerAuthMode, type CliServerConnection, type CliStandaloneConnection, type ClientCapability, type ClientPackageContract, type ConnectivityCategory, type ConnectivityDependencies, type ConnectivityFetchResponse, type ConnectivityValidationResult, type CumulativeStateTimeCandidateRow, type CumulativeStateTimeCandidatesResult, type CumulativeStateTimeItemRow, type CumulativeStateTimeItemsResult, type CumulativeStateTimeResult, type CumulativeStateTimeStateRow, type DailyTotalWorkItemAge, type DailyWorkItemAge, type DayOfWeek, type LighthouseApiError, type LighthouseApiResult, type LighthouseAuthContext, type LighthouseAuthOverrides, type LighthouseAuthStatus, type LighthouseAuthStore, type LighthouseClient, type LighthouseClientAuth, type LighthouseClientConfiguration, type LighthouseClientDependencies, type LighthouseConnectionConfiguration, type LighthouseWritePayload, type ManualForecastInput, type MetricsDateRange, type RecurringBlackoutRule, type RecurringBlackoutRuleInput, type ResolvedLighthouseEndpoint, type ServerAuthModeResult, type StandaloneDiscoveryContract, type StandaloneDiscoveryContractParseResult, type StoredLighthouseAuth, type ThroughputFilterView, type TotalWorkItemAgeOverTimeResult, type WorkItemAgeEntry, type WorkItemAgeOverTimeResult, createLighthouseAuthContext, createLighthouseClient, getClientPackageContract, getDefaultMetricsDateRange, getStandaloneDiscoveryLockfilePath, isServerVersionNewerThan, loadStandaloneDiscoveryContract, parseStandaloneDiscoveryContract, pollCliAuthSession, queryServerAuthMode, startCliAuthSession, validateLighthouseConnectivity };
package/dist/index.d.ts CHANGED
@@ -4,7 +4,7 @@ type ClientPackageContract = {
4
4
  readonly capabilities: readonly ClientCapability[];
5
5
  };
6
6
  declare const getClientPackageContract: () => ClientPackageContract;
7
- type ConnectivityCategory = "success" | "unreachable" | "misconfigured" | "unauthorized" | "dependency-failure" | "unexpected";
7
+ type ConnectivityCategory = "success" | "unreachable" | "misconfigured" | "unauthorized" | "dependency-failure" | "concurrency-conflict" | "unexpected";
8
8
  type StandaloneDiscoveryContract = {
9
9
  readonly contractVersion: 1;
10
10
  readonly lighthouseUrl: string;
@@ -257,6 +257,23 @@ type CumulativeStateTimeCandidateRow = {
257
257
  type CumulativeStateTimeCandidatesResult = {
258
258
  readonly items: readonly CumulativeStateTimeCandidateRow[];
259
259
  };
260
+ type DayOfWeek = "Sunday" | "Monday" | "Tuesday" | "Wednesday" | "Thursday" | "Friday" | "Saturday";
261
+ type RecurringBlackoutRule = {
262
+ readonly id: number;
263
+ readonly weekdays: readonly DayOfWeek[];
264
+ readonly intervalWeeks: number;
265
+ readonly start: string;
266
+ readonly end: string | null;
267
+ readonly description: string;
268
+ readonly summary: string;
269
+ };
270
+ type RecurringBlackoutRuleInput = {
271
+ readonly weekdays: readonly DayOfWeek[];
272
+ readonly intervalWeeks: number;
273
+ readonly start: string;
274
+ readonly end: string | null;
275
+ readonly description: string;
276
+ };
260
277
  type LighthouseClient = {
261
278
  readonly checkConnectivity: () => Promise<ConnectivityValidationResult>;
262
279
  readonly getVersion: () => Promise<LighthouseApiResult<string>>;
@@ -281,13 +298,15 @@ type LighthouseClient = {
281
298
  readonly getTeamArrivals: (teamId: number, range?: MetricsDateRange) => Promise<LighthouseApiResult<unknown>>;
282
299
  readonly getTeamWipOverTime: (teamId: number, range?: MetricsDateRange) => Promise<LighthouseApiResult<unknown>>;
283
300
  readonly getTeamWip: (teamId: number, asOfDate: string) => Promise<LighthouseApiResult<readonly unknown[]>>;
284
- readonly getTeamCycleTimePercentiles: (teamId: number, range?: MetricsDateRange) => Promise<LighthouseApiResult<readonly unknown[]>>;
301
+ readonly getTeamCycleTimePercentiles: (teamId: number, range?: MetricsDateRange, definitionId?: number) => Promise<LighthouseApiResult<readonly unknown[]>>;
302
+ readonly getTeamWorkItemAgePercentiles: (teamId: number, range?: MetricsDateRange) => Promise<LighthouseApiResult<readonly unknown[]>>;
285
303
  readonly getTeamCycleTimeData: (teamId: number, range?: MetricsDateRange) => Promise<LighthouseApiResult<readonly unknown[]>>;
286
304
  readonly getTeamPredictabilityScore: (teamId: number, range?: MetricsDateRange, view?: ThroughputFilterView) => Promise<LighthouseApiResult<unknown>>;
287
305
  readonly getTeamTotalWorkItemAge: (teamId: number, asOfDate: string) => Promise<LighthouseApiResult<number>>;
288
306
  readonly getTeamTotalWorkItemAgeInfo: (teamId: number, range?: MetricsDateRange) => Promise<LighthouseApiResult<unknown>>;
289
307
  readonly getPortfolioThroughput: (portfolioId: number, range?: MetricsDateRange) => Promise<LighthouseApiResult<unknown>>;
290
- readonly getPortfolioCycleTimePercentiles: (portfolioId: number, range?: MetricsDateRange) => Promise<LighthouseApiResult<readonly unknown[]>>;
308
+ readonly getPortfolioCycleTimePercentiles: (portfolioId: number, range?: MetricsDateRange, definitionId?: number) => Promise<LighthouseApiResult<readonly unknown[]>>;
309
+ readonly getPortfolioWorkItemAgePercentiles: (portfolioId: number, range?: MetricsDateRange) => Promise<LighthouseApiResult<readonly unknown[]>>;
291
310
  readonly getPortfolioArrivals: (portfolioId: number, range?: MetricsDateRange) => Promise<LighthouseApiResult<unknown>>;
292
311
  readonly getPortfolioWipOverTime: (portfolioId: number, range?: MetricsDateRange) => Promise<LighthouseApiResult<unknown>>;
293
312
  readonly getPortfolioWip: (portfolioId: number, asOfDate: string) => Promise<LighthouseApiResult<readonly unknown[]>>;
@@ -312,6 +331,10 @@ type LighthouseClient = {
312
331
  readonly createDelivery: (portfolioId: number, payload: LighthouseWritePayload) => Promise<LighthouseApiResult<unknown>>;
313
332
  readonly updateDelivery: (deliveryId: number, payload: LighthouseWritePayload) => Promise<LighthouseApiResult<unknown>>;
314
333
  readonly deleteDelivery: (deliveryId: number) => Promise<LighthouseApiResult<undefined>>;
334
+ readonly getRecurringBlackoutRules: () => Promise<LighthouseApiResult<readonly RecurringBlackoutRule[]>>;
335
+ readonly createRecurringBlackoutRule: (payload: LighthouseWritePayload) => Promise<LighthouseApiResult<RecurringBlackoutRule>>;
336
+ readonly updateRecurringBlackoutRule: (id: number, payload: LighthouseWritePayload) => Promise<LighthouseApiResult<RecurringBlackoutRule>>;
337
+ readonly deleteRecurringBlackoutRule: (id: number) => Promise<LighthouseApiResult<undefined>>;
315
338
  readonly runManualForecast: (teamId: number, payload: ManualForecastInput) => Promise<LighthouseApiResult<unknown>>;
316
339
  readonly runBacktest: (teamId: number, payload: BacktestInput) => Promise<LighthouseApiResult<unknown>>;
317
340
  };
@@ -326,4 +349,4 @@ type LighthouseClientDependencies = {
326
349
  declare const isServerVersionNewerThan: (candidate: string, baseline: string) => boolean | null;
327
350
  declare const createLighthouseClient: (configuration: LighthouseClientConfiguration, dependencies?: LighthouseClientDependencies) => LighthouseClient;
328
351
 
329
- export { type BacktestInput, type CliAuthSessionPollResult, type CliAuthSessionStartError, type CliAuthSessionStartOutcome, type CliAuthSessionStartResult, type CliConnection, type CliServerAuthMode, type CliServerConnection, type CliStandaloneConnection, type ClientCapability, type ClientPackageContract, type ConnectivityCategory, type ConnectivityDependencies, type ConnectivityFetchResponse, type ConnectivityValidationResult, type CumulativeStateTimeCandidateRow, type CumulativeStateTimeCandidatesResult, type CumulativeStateTimeItemRow, type CumulativeStateTimeItemsResult, type CumulativeStateTimeResult, type CumulativeStateTimeStateRow, type DailyTotalWorkItemAge, type DailyWorkItemAge, type LighthouseApiError, type LighthouseApiResult, type LighthouseAuthContext, type LighthouseAuthOverrides, type LighthouseAuthStatus, type LighthouseAuthStore, type LighthouseClient, type LighthouseClientAuth, type LighthouseClientConfiguration, type LighthouseClientDependencies, type LighthouseConnectionConfiguration, type LighthouseWritePayload, type ManualForecastInput, type MetricsDateRange, type ResolvedLighthouseEndpoint, type ServerAuthModeResult, type StandaloneDiscoveryContract, type StandaloneDiscoveryContractParseResult, type StoredLighthouseAuth, type ThroughputFilterView, type TotalWorkItemAgeOverTimeResult, type WorkItemAgeEntry, type WorkItemAgeOverTimeResult, createLighthouseAuthContext, createLighthouseClient, getClientPackageContract, getDefaultMetricsDateRange, getStandaloneDiscoveryLockfilePath, isServerVersionNewerThan, loadStandaloneDiscoveryContract, parseStandaloneDiscoveryContract, pollCliAuthSession, queryServerAuthMode, startCliAuthSession, validateLighthouseConnectivity };
352
+ export { type BacktestInput, type CliAuthSessionPollResult, type CliAuthSessionStartError, type CliAuthSessionStartOutcome, type CliAuthSessionStartResult, type CliConnection, type CliServerAuthMode, type CliServerConnection, type CliStandaloneConnection, type ClientCapability, type ClientPackageContract, type ConnectivityCategory, type ConnectivityDependencies, type ConnectivityFetchResponse, type ConnectivityValidationResult, type CumulativeStateTimeCandidateRow, type CumulativeStateTimeCandidatesResult, type CumulativeStateTimeItemRow, type CumulativeStateTimeItemsResult, type CumulativeStateTimeResult, type CumulativeStateTimeStateRow, type DailyTotalWorkItemAge, type DailyWorkItemAge, type DayOfWeek, type LighthouseApiError, type LighthouseApiResult, type LighthouseAuthContext, type LighthouseAuthOverrides, type LighthouseAuthStatus, type LighthouseAuthStore, type LighthouseClient, type LighthouseClientAuth, type LighthouseClientConfiguration, type LighthouseClientDependencies, type LighthouseConnectionConfiguration, type LighthouseWritePayload, type ManualForecastInput, type MetricsDateRange, type RecurringBlackoutRule, type RecurringBlackoutRuleInput, type ResolvedLighthouseEndpoint, type ServerAuthModeResult, type StandaloneDiscoveryContract, type StandaloneDiscoveryContractParseResult, type StoredLighthouseAuth, type ThroughputFilterView, type TotalWorkItemAgeOverTimeResult, type WorkItemAgeEntry, type WorkItemAgeOverTimeResult, createLighthouseAuthContext, createLighthouseClient, getClientPackageContract, getDefaultMetricsDateRange, getStandaloneDiscoveryLockfilePath, isServerVersionNewerThan, loadStandaloneDiscoveryContract, parseStandaloneDiscoveryContract, pollCliAuthSession, queryServerAuthMode, startCliAuthSession, validateLighthouseConnectivity };
package/dist/index.js CHANGED
@@ -544,6 +544,47 @@ var toApiError = (statusCode, reason) => ({
544
544
  reason,
545
545
  statusCode
546
546
  });
547
+ var CONCURRENCY_CONFLICT_STATUS = 409;
548
+ var CONCURRENCY_CONFLICT_GUIDANCE = "This edit conflicts because the item was changed by someone else. Re-fetch the current settings to obtain the latest concurrency token, then re-apply your change.";
549
+ var getProblemDetailsMessage = (body) => {
550
+ if (!isObjectRecord(body)) {
551
+ return void 0;
552
+ }
553
+ for (const key of ["detail", "title", "message"]) {
554
+ const value = body[key];
555
+ if (typeof value === "string" && value.trim().length > 0) {
556
+ return value.trim();
557
+ }
558
+ }
559
+ return void 0;
560
+ };
561
+ var getResponseBody = async (response) => {
562
+ try {
563
+ if (response.json !== void 0) {
564
+ return await response.json();
565
+ }
566
+ return JSON.parse(await response.text());
567
+ } catch {
568
+ return void 0;
569
+ }
570
+ };
571
+ var toConcurrencyConflictError = (serverMessage) => ({
572
+ category: "concurrency-conflict",
573
+ reason: serverMessage === void 0 ? CONCURRENCY_CONFLICT_GUIDANCE : `${serverMessage} ${CONCURRENCY_CONFLICT_GUIDANCE}`,
574
+ statusCode: CONCURRENCY_CONFLICT_STATUS
575
+ });
576
+ var toResponseError = async (response) => {
577
+ if (response.status === CONCURRENCY_CONFLICT_STATUS) {
578
+ const serverMessage = getProblemDetailsMessage(
579
+ await getResponseBody(response)
580
+ );
581
+ return toConcurrencyConflictError(serverMessage);
582
+ }
583
+ return toApiError(
584
+ response.status,
585
+ `Request failed with status ${response.status}.`
586
+ );
587
+ };
547
588
  var requestText = async (configuration, dependencies, route) => {
548
589
  const fetchDependency = getFetchDependency(dependencies);
549
590
  const connectivityResult = await validateLighthouseConnectivity(
@@ -562,12 +603,7 @@ var requestText = async (configuration, dependencies, route) => {
562
603
  getRequestInit(configuration.auth)
563
604
  );
564
605
  if (!response.ok) {
565
- return getErrorResult(
566
- toApiError(
567
- response.status,
568
- `Request failed with status ${response.status}.`
569
- )
570
- );
606
+ return getErrorResult(await toResponseError(response));
571
607
  }
572
608
  return {
573
609
  ok: true,
@@ -601,12 +637,7 @@ var requestJson = async (configuration, dependencies, route, requestOptions) =>
601
637
  getRequestInit(configuration.auth, requestOptions)
602
638
  );
603
639
  if (!response.ok) {
604
- return getErrorResult(
605
- toApiError(
606
- response.status,
607
- `Request failed with status ${response.status}.`
608
- )
609
- );
640
+ return getErrorResult(await toResponseError(response));
610
641
  }
611
642
  if (response.json === void 0) {
612
643
  return {
@@ -647,12 +678,7 @@ var requestNoContent = async (configuration, dependencies, route, requestOptions
647
678
  getRequestInit(configuration.auth, requestOptions)
648
679
  );
649
680
  if (!response.ok) {
650
- return getErrorResult(
651
- toApiError(
652
- response.status,
653
- `Request failed with status ${response.status}.`
654
- )
655
- );
681
+ return getErrorResult(await toResponseError(response));
656
682
  }
657
683
  return {
658
684
  ok: true,
@@ -671,6 +697,7 @@ var getMetricsDateRangeQuery = (range) => `startDate=${encodeURIComponent(range.
671
697
  var getMetricsAsOfDateQuery = (asOfDate) => `asOfDate=${encodeURIComponent(asOfDate)}`;
672
698
  var getItemIdsQuerySuffix = (itemIds) => itemIds && itemIds.length > 0 ? itemIds.map((id) => `&itemIds=${encodeURIComponent(id)}`).join("") : "";
673
699
  var getViewQuerySuffix = (view) => view === "filtered" ? "&view=filtered" : "";
700
+ var getDefinitionIdQuerySuffix = (definitionId) => definitionId !== void 0 ? `&definitionId=${encodeURIComponent(definitionId)}` : "";
674
701
  var addUtcDays = (dateStr, days) => {
675
702
  const d = /* @__PURE__ */ new Date(`${dateStr}T00:00:00Z`);
676
703
  d.setUTCDate(d.getUTCDate() + days);
@@ -721,7 +748,9 @@ var deriveTotalWorkItemAgeOverTime = (startDate, endDate, wipData) => {
721
748
  return { startDate, endDate, daily };
722
749
  };
723
750
  var FEATURE_REQUIRES_SERVER_NEWER_THAN = {
724
- cumulativeStateTime: "v26.5.24.10"
751
+ cumulativeStateTime: "v26.5.24.10",
752
+ recurringBlackoutRules: "v26.5.29.5",
753
+ workItemAgePercentiles: "v26.6.7.1"
725
754
  };
726
755
  var parseServerVersion = (raw) => {
727
756
  const trimmed = raw.trim().replace(/^v/iu, "");
@@ -942,12 +971,25 @@ var createLighthouseClient = (configuration, dependencies = {}) => {
942
971
  `/v1/teams/${teamId}/metrics/wip?${getMetricsAsOfDateQuery(asOfDate)}`,
943
972
  { method: "GET" }
944
973
  ),
945
- getTeamCycleTimePercentiles: async (teamId, range) => {
974
+ getTeamCycleTimePercentiles: async (teamId, range, definitionId) => {
975
+ const r = getResolvedMetricsDateRange(range);
976
+ return requestJson(
977
+ configuration,
978
+ dependencies,
979
+ `/v1/teams/${teamId}/metrics/cycleTimePercentiles?${getMetricsDateRangeQuery(r)}${getDefinitionIdQuerySuffix(definitionId)}`,
980
+ { method: "GET" }
981
+ );
982
+ },
983
+ getTeamWorkItemAgePercentiles: async (teamId, range) => {
984
+ const unsupported = await ensureServerSupports("workItemAgePercentiles");
985
+ if (unsupported) {
986
+ return unsupported;
987
+ }
946
988
  const r = getResolvedMetricsDateRange(range);
947
989
  return requestJson(
948
990
  configuration,
949
991
  dependencies,
950
- `/v1/teams/${teamId}/metrics/cycleTimePercentiles?${getMetricsDateRangeQuery(r)}`,
992
+ `/v1/teams/${teamId}/metrics/workItemAgePercentiles?${getMetricsDateRangeQuery(r)}`,
951
993
  { method: "GET" }
952
994
  );
953
995
  },
@@ -1033,12 +1075,25 @@ var createLighthouseClient = (configuration, dependencies = {}) => {
1033
1075
  { method: "GET" }
1034
1076
  );
1035
1077
  },
1036
- getPortfolioCycleTimePercentiles: async (portfolioId, range) => {
1078
+ getPortfolioCycleTimePercentiles: async (portfolioId, range, definitionId) => {
1079
+ const r = getResolvedMetricsDateRange(range);
1080
+ return requestJson(
1081
+ configuration,
1082
+ dependencies,
1083
+ `/v1/portfolios/${portfolioId}/metrics/cycleTimePercentiles?${getMetricsDateRangeQuery(r)}${getDefinitionIdQuerySuffix(definitionId)}`,
1084
+ { method: "GET" }
1085
+ );
1086
+ },
1087
+ getPortfolioWorkItemAgePercentiles: async (portfolioId, range) => {
1088
+ const unsupported = await ensureServerSupports("workItemAgePercentiles");
1089
+ if (unsupported) {
1090
+ return unsupported;
1091
+ }
1037
1092
  const r = getResolvedMetricsDateRange(range);
1038
1093
  return requestJson(
1039
1094
  configuration,
1040
1095
  dependencies,
1041
- `/v1/portfolios/${portfolioId}/metrics/cycleTimePercentiles?${getMetricsDateRangeQuery(r)}`,
1096
+ `/v1/portfolios/${portfolioId}/metrics/workItemAgePercentiles?${getMetricsDateRangeQuery(r)}`,
1042
1097
  { method: "GET" }
1043
1098
  );
1044
1099
  },
@@ -1265,6 +1320,54 @@ var createLighthouseClient = (configuration, dependencies = {}) => {
1265
1320
  `/v1/deliveries/${deliveryId}`,
1266
1321
  { method: "DELETE" }
1267
1322
  ),
1323
+ getRecurringBlackoutRules: async () => {
1324
+ const unsupported = await ensureServerSupports("recurringBlackoutRules");
1325
+ if (unsupported) {
1326
+ return unsupported;
1327
+ }
1328
+ return requestJson(
1329
+ configuration,
1330
+ dependencies,
1331
+ "/v1/recurring-blackout-rules",
1332
+ { method: "GET" }
1333
+ );
1334
+ },
1335
+ createRecurringBlackoutRule: async (payload) => {
1336
+ const unsupported = await ensureServerSupports("recurringBlackoutRules");
1337
+ if (unsupported) {
1338
+ return unsupported;
1339
+ }
1340
+ return requestJson(
1341
+ configuration,
1342
+ dependencies,
1343
+ "/v1/recurring-blackout-rules",
1344
+ { method: "POST", body: payload }
1345
+ );
1346
+ },
1347
+ updateRecurringBlackoutRule: async (id, payload) => {
1348
+ const unsupported = await ensureServerSupports("recurringBlackoutRules");
1349
+ if (unsupported) {
1350
+ return unsupported;
1351
+ }
1352
+ return requestJson(
1353
+ configuration,
1354
+ dependencies,
1355
+ `/v1/recurring-blackout-rules/${id}`,
1356
+ { method: "PUT", body: payload }
1357
+ );
1358
+ },
1359
+ deleteRecurringBlackoutRule: async (id) => {
1360
+ const unsupported = await ensureServerSupports("recurringBlackoutRules");
1361
+ if (unsupported) {
1362
+ return unsupported;
1363
+ }
1364
+ return requestNoContent(
1365
+ configuration,
1366
+ dependencies,
1367
+ `/v1/recurring-blackout-rules/${id}`,
1368
+ { method: "DELETE" }
1369
+ );
1370
+ },
1268
1371
  runManualForecast: async (teamId, payload) => requestJson(
1269
1372
  configuration,
1270
1373
  dependencies,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@letpeoplework/lighthouse-client",
3
- "version": "1.2.0",
3
+ "version": "1.4.0",
4
4
  "description": "Shared Lighthouse API client contracts",
5
5
  "repository": "https://github.com/LetPeopleWork/lighthouse-clients",
6
6
  "type": "module",