@letpeoplework/lighthouse-client 0.7.0 → 1.0.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
@@ -24,6 +24,8 @@ __export(index_exports, {
24
24
  createLighthouseClient: () => createLighthouseClient,
25
25
  getClientPackageContract: () => getClientPackageContract,
26
26
  getDefaultMetricsDateRange: () => getDefaultMetricsDateRange,
27
+ getStandaloneDiscoveryLockfilePath: () => getStandaloneDiscoveryLockfilePath,
28
+ loadStandaloneDiscoveryContract: () => loadStandaloneDiscoveryContract,
27
29
  parseStandaloneDiscoveryContract: () => parseStandaloneDiscoveryContract,
28
30
  pollCliAuthSession: () => pollCliAuthSession,
29
31
  queryServerAuthMode: () => queryServerAuthMode,
@@ -31,6 +33,9 @@ __export(index_exports, {
31
33
  validateLighthouseConnectivity: () => validateLighthouseConnectivity
32
34
  });
33
35
  module.exports = __toCommonJS(index_exports);
36
+ var import_promises = require("fs/promises");
37
+ var import_node_os = require("os");
38
+ var import_node_path = require("path");
34
39
  var getClientPackageContract = () => ({
35
40
  name: "@letpeoplework/lighthouse-client",
36
41
  capabilities: [
@@ -41,6 +46,7 @@ var getClientPackageContract = () => ({
41
46
  ]
42
47
  });
43
48
  var SUPPORTED_DISCOVERY_CONTRACT_VERSION = 1;
49
+ var STANDALONE_DISCOVERY_LOCKFILE_NAME = "standalone.lock.json";
44
50
  var isObjectRecord = (value) => {
45
51
  return typeof value === "object" && value !== null && !Array.isArray(value);
46
52
  };
@@ -155,6 +161,47 @@ var parseStandaloneDiscoveryContract = (serializedContract) => {
155
161
  detectedAtUtc
156
162
  });
157
163
  };
164
+ var getStandaloneDiscoveryLockfilePath = () => {
165
+ if (process.env.LIGHTHOUSE_STANDALONE_LOCKFILE_PATH !== void 0) {
166
+ return process.env.LIGHTHOUSE_STANDALONE_LOCKFILE_PATH;
167
+ }
168
+ if (process.platform === "darwin") {
169
+ return (0, import_node_path.join)(
170
+ (0, import_node_os.homedir)(),
171
+ "Library",
172
+ "Application Support",
173
+ "Lighthouse",
174
+ STANDALONE_DISCOVERY_LOCKFILE_NAME
175
+ );
176
+ }
177
+ if (process.platform === "win32") {
178
+ return (0, import_node_path.join)(
179
+ process.env.APPDATA ?? (0, import_node_path.join)((0, import_node_os.homedir)(), "AppData", "Roaming"),
180
+ "Lighthouse",
181
+ STANDALONE_DISCOVERY_LOCKFILE_NAME
182
+ );
183
+ }
184
+ return (0, import_node_path.join)(
185
+ process.env.XDG_CONFIG_HOME ?? (0, import_node_path.join)((0, import_node_os.homedir)(), ".config"),
186
+ "Lighthouse",
187
+ STANDALONE_DISCOVERY_LOCKFILE_NAME
188
+ );
189
+ };
190
+ var loadStandaloneDiscoveryContract = async () => {
191
+ try {
192
+ const serializedContract = await (0, import_promises.readFile)(
193
+ getStandaloneDiscoveryLockfilePath(),
194
+ "utf8"
195
+ );
196
+ const parsedContract = parseStandaloneDiscoveryContract(serializedContract);
197
+ if (!parsedContract.isValid) {
198
+ return null;
199
+ }
200
+ return parsedContract.contract;
201
+ } catch {
202
+ return null;
203
+ }
204
+ };
158
205
  var getResolvedEndpoint = (mode, lighthouseUrl) => {
159
206
  const apiBaseUrl = getApiBaseUrl(lighthouseUrl);
160
207
  return {
@@ -656,6 +703,54 @@ var requestNoContent = async (configuration, dependencies, route, requestOptions
656
703
  var getResolvedMetricsDateRange = (range) => range ?? getDefaultMetricsDateRange();
657
704
  var getMetricsDateRangeQuery = (range) => `startDate=${encodeURIComponent(range.startDate)}&endDate=${encodeURIComponent(range.endDate)}`;
658
705
  var getMetricsAsOfDateQuery = (asOfDate) => `asOfDate=${encodeURIComponent(asOfDate)}`;
706
+ var addUtcDays = (dateStr, days) => {
707
+ const d = /* @__PURE__ */ new Date(`${dateStr}T00:00:00Z`);
708
+ d.setUTCDate(d.getUTCDate() + days);
709
+ return d.toISOString().split("T")[0];
710
+ };
711
+ var computeItemAge = (dayDate, startedDate) => {
712
+ const day = Date.parse(`${dayDate}T00:00:00Z`);
713
+ const started = Date.parse(startedDate);
714
+ const diffDays = Math.floor((day - started) / 864e5);
715
+ return Math.max(1, diffDays + 1);
716
+ };
717
+ var deriveWorkItemAgeOverTime = (startDate, endDate, wipData) => {
718
+ const daily = Object.entries(
719
+ wipData.workItemsPerUnitOfTime
720
+ ).map(([dayIndexStr, items]) => {
721
+ const dayIndex = Number.parseInt(dayIndexStr, 10);
722
+ const date = addUtcDays(startDate, dayIndex);
723
+ const ageItems = items.filter(
724
+ (item) => item.startedDate != null && item.startedDate.length > 0
725
+ ).map((item) => ({
726
+ id: item.id,
727
+ name: item.name,
728
+ referenceId: item.referenceId,
729
+ age: computeItemAge(date, item.startedDate)
730
+ }));
731
+ return { date, items: ageItems };
732
+ });
733
+ daily.sort((a, b) => a.date.localeCompare(b.date));
734
+ return { startDate, endDate, daily };
735
+ };
736
+ var deriveTotalWorkItemAgeOverTime = (startDate, endDate, wipData) => {
737
+ const daily = Object.entries(
738
+ wipData.workItemsPerUnitOfTime
739
+ ).map(([dayIndexStr, items]) => {
740
+ const dayIndex = Number.parseInt(dayIndexStr, 10);
741
+ const date = addUtcDays(startDate, dayIndex);
742
+ const activeItems = items.filter(
743
+ (item) => item.startedDate != null && item.startedDate.length > 0
744
+ );
745
+ const totalAge = activeItems.reduce(
746
+ (sum, item) => sum + computeItemAge(date, item.startedDate),
747
+ 0
748
+ );
749
+ return { date, totalAge, itemCount: activeItems.length };
750
+ });
751
+ daily.sort((a, b) => a.date.localeCompare(b.date));
752
+ return { startDate, endDate, daily };
753
+ };
659
754
  var createLighthouseClient = (configuration, dependencies = {}) => ({
660
755
  checkConnectivity: async () => {
661
756
  const fetchDependency = getFetchDependency(dependencies);
@@ -850,6 +945,42 @@ var createLighthouseClient = (configuration, dependencies = {}) => ({
850
945
  { method: "GET" }
851
946
  );
852
947
  },
948
+ getTeamWorkItemAgeOverTime: async (teamId, range) => {
949
+ const r = getResolvedMetricsDateRange(range);
950
+ const wipResult = await requestJson(
951
+ configuration,
952
+ dependencies,
953
+ `/v1/teams/${teamId}/metrics/wipOverTime?${getMetricsDateRangeQuery(r)}`,
954
+ { method: "GET" }
955
+ );
956
+ if (!wipResult.ok) {
957
+ return wipResult;
958
+ }
959
+ return {
960
+ ok: true,
961
+ value: deriveWorkItemAgeOverTime(r.startDate, r.endDate, wipResult.value)
962
+ };
963
+ },
964
+ getTeamTotalWorkItemAgeOverTime: async (teamId, range) => {
965
+ const r = getResolvedMetricsDateRange(range);
966
+ const wipResult = await requestJson(
967
+ configuration,
968
+ dependencies,
969
+ `/v1/teams/${teamId}/metrics/wipOverTime?${getMetricsDateRangeQuery(r)}`,
970
+ { method: "GET" }
971
+ );
972
+ if (!wipResult.ok) {
973
+ return wipResult;
974
+ }
975
+ return {
976
+ ok: true,
977
+ value: deriveTotalWorkItemAgeOverTime(
978
+ r.startDate,
979
+ r.endDate,
980
+ wipResult.value
981
+ )
982
+ };
983
+ },
853
984
  getPortfolioThroughput: async (portfolioId, range) => {
854
985
  const r = getResolvedMetricsDateRange(range);
855
986
  return requestJson(
@@ -925,6 +1056,42 @@ var createLighthouseClient = (configuration, dependencies = {}) => ({
925
1056
  { method: "GET" }
926
1057
  );
927
1058
  },
1059
+ getPortfolioWorkItemAgeOverTime: async (portfolioId, range) => {
1060
+ const r = getResolvedMetricsDateRange(range);
1061
+ const wipResult = await requestJson(
1062
+ configuration,
1063
+ dependencies,
1064
+ `/v1/portfolios/${portfolioId}/metrics/wipOverTime?${getMetricsDateRangeQuery(r)}`,
1065
+ { method: "GET" }
1066
+ );
1067
+ if (!wipResult.ok) {
1068
+ return wipResult;
1069
+ }
1070
+ return {
1071
+ ok: true,
1072
+ value: deriveWorkItemAgeOverTime(r.startDate, r.endDate, wipResult.value)
1073
+ };
1074
+ },
1075
+ getPortfolioTotalWorkItemAgeOverTime: async (portfolioId, range) => {
1076
+ const r = getResolvedMetricsDateRange(range);
1077
+ const wipResult = await requestJson(
1078
+ configuration,
1079
+ dependencies,
1080
+ `/v1/portfolios/${portfolioId}/metrics/wipOverTime?${getMetricsDateRangeQuery(r)}`,
1081
+ { method: "GET" }
1082
+ );
1083
+ if (!wipResult.ok) {
1084
+ return wipResult;
1085
+ }
1086
+ return {
1087
+ ok: true,
1088
+ value: deriveTotalWorkItemAgeOverTime(
1089
+ r.startDate,
1090
+ r.endDate,
1091
+ wipResult.value
1092
+ )
1093
+ };
1094
+ },
928
1095
  getFeaturesByIds: async (ids) => {
929
1096
  const queryString = ids.map((id) => `ids=${encodeURIComponent(id)}`).join("&");
930
1097
  return requestJson(
@@ -992,6 +1159,8 @@ var createLighthouseClient = (configuration, dependencies = {}) => ({
992
1159
  createLighthouseClient,
993
1160
  getClientPackageContract,
994
1161
  getDefaultMetricsDateRange,
1162
+ getStandaloneDiscoveryLockfilePath,
1163
+ loadStandaloneDiscoveryContract,
995
1164
  parseStandaloneDiscoveryContract,
996
1165
  pollCliAuthSession,
997
1166
  queryServerAuthMode,
package/dist/index.d.cts CHANGED
@@ -50,6 +50,8 @@ type ConnectivityValidationResult = {
50
50
  readonly endpoint?: ResolvedLighthouseEndpoint;
51
51
  };
52
52
  declare const parseStandaloneDiscoveryContract: (serializedContract: string) => StandaloneDiscoveryContractParseResult;
53
+ declare const getStandaloneDiscoveryLockfilePath: () => string;
54
+ declare const loadStandaloneDiscoveryContract: () => Promise<StandaloneDiscoveryContract | null>;
53
55
  declare const validateLighthouseConnectivity: (configuration: LighthouseConnectionConfiguration, dependencies: ConnectivityDependencies, requestInit?: RequestInit) => Promise<ConnectivityValidationResult>;
54
56
  type LighthouseClientAuth = {
55
57
  readonly kind: "none";
@@ -167,6 +169,31 @@ type BacktestInput = {
167
169
  readonly historicalStartDate: string;
168
170
  readonly historicalEndDate: string;
169
171
  };
172
+ type WorkItemAgeEntry = {
173
+ readonly id: number;
174
+ readonly name: string;
175
+ readonly referenceId: string;
176
+ readonly age: number;
177
+ };
178
+ type DailyWorkItemAge = {
179
+ readonly date: string;
180
+ readonly items: readonly WorkItemAgeEntry[];
181
+ };
182
+ type DailyTotalWorkItemAge = {
183
+ readonly date: string;
184
+ readonly totalAge: number;
185
+ readonly itemCount: number;
186
+ };
187
+ type WorkItemAgeOverTimeResult = {
188
+ readonly startDate: string;
189
+ readonly endDate: string;
190
+ readonly daily: readonly DailyWorkItemAge[];
191
+ };
192
+ type TotalWorkItemAgeOverTimeResult = {
193
+ readonly startDate: string;
194
+ readonly endDate: string;
195
+ readonly daily: readonly DailyTotalWorkItemAge[];
196
+ };
170
197
  type LighthouseClient = {
171
198
  readonly checkConnectivity: () => Promise<ConnectivityValidationResult>;
172
199
  readonly getVersion: () => Promise<LighthouseApiResult<string>>;
@@ -203,8 +230,12 @@ type LighthouseClient = {
203
230
  readonly getPortfolioWip: (portfolioId: number, asOfDate: string) => Promise<LighthouseApiResult<readonly unknown[]>>;
204
231
  readonly getPortfolioCycleTimeData: (portfolioId: number, range?: MetricsDateRange) => Promise<LighthouseApiResult<readonly unknown[]>>;
205
232
  readonly getPortfolioPredictabilityScore: (portfolioId: number, range?: MetricsDateRange) => Promise<LighthouseApiResult<unknown>>;
233
+ readonly getTeamWorkItemAgeOverTime: (teamId: number, range?: MetricsDateRange) => Promise<LighthouseApiResult<WorkItemAgeOverTimeResult>>;
234
+ readonly getTeamTotalWorkItemAgeOverTime: (teamId: number, range?: MetricsDateRange) => Promise<LighthouseApiResult<TotalWorkItemAgeOverTimeResult>>;
206
235
  readonly getPortfolioTotalWorkItemAge: (portfolioId: number, asOfDate: string) => Promise<LighthouseApiResult<number>>;
207
236
  readonly getPortfolioTotalWorkItemAgeInfo: (portfolioId: number, range?: MetricsDateRange) => Promise<LighthouseApiResult<unknown>>;
237
+ readonly getPortfolioWorkItemAgeOverTime: (portfolioId: number, range?: MetricsDateRange) => Promise<LighthouseApiResult<WorkItemAgeOverTimeResult>>;
238
+ readonly getPortfolioTotalWorkItemAgeOverTime: (portfolioId: number, range?: MetricsDateRange) => Promise<LighthouseApiResult<TotalWorkItemAgeOverTimeResult>>;
208
239
  readonly getFeaturesByIds: (ids: readonly number[]) => Promise<LighthouseApiResult<readonly unknown[]>>;
209
240
  readonly getFeaturesByReferences: (refs: readonly string[]) => Promise<LighthouseApiResult<readonly unknown[]>>;
210
241
  readonly getFeatureWorkItems: (featureId: number) => Promise<LighthouseApiResult<readonly unknown[]>>;
@@ -220,4 +251,4 @@ type LighthouseClientDependencies = {
220
251
  };
221
252
  declare const createLighthouseClient: (configuration: LighthouseClientConfiguration, dependencies?: LighthouseClientDependencies) => LighthouseClient;
222
253
 
223
- 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 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, createLighthouseAuthContext, createLighthouseClient, getClientPackageContract, getDefaultMetricsDateRange, parseStandaloneDiscoveryContract, pollCliAuthSession, queryServerAuthMode, startCliAuthSession, validateLighthouseConnectivity };
254
+ 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 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 TotalWorkItemAgeOverTimeResult, type WorkItemAgeEntry, type WorkItemAgeOverTimeResult, createLighthouseAuthContext, createLighthouseClient, getClientPackageContract, getDefaultMetricsDateRange, getStandaloneDiscoveryLockfilePath, loadStandaloneDiscoveryContract, parseStandaloneDiscoveryContract, pollCliAuthSession, queryServerAuthMode, startCliAuthSession, validateLighthouseConnectivity };
package/dist/index.d.ts CHANGED
@@ -50,6 +50,8 @@ type ConnectivityValidationResult = {
50
50
  readonly endpoint?: ResolvedLighthouseEndpoint;
51
51
  };
52
52
  declare const parseStandaloneDiscoveryContract: (serializedContract: string) => StandaloneDiscoveryContractParseResult;
53
+ declare const getStandaloneDiscoveryLockfilePath: () => string;
54
+ declare const loadStandaloneDiscoveryContract: () => Promise<StandaloneDiscoveryContract | null>;
53
55
  declare const validateLighthouseConnectivity: (configuration: LighthouseConnectionConfiguration, dependencies: ConnectivityDependencies, requestInit?: RequestInit) => Promise<ConnectivityValidationResult>;
54
56
  type LighthouseClientAuth = {
55
57
  readonly kind: "none";
@@ -167,6 +169,31 @@ type BacktestInput = {
167
169
  readonly historicalStartDate: string;
168
170
  readonly historicalEndDate: string;
169
171
  };
172
+ type WorkItemAgeEntry = {
173
+ readonly id: number;
174
+ readonly name: string;
175
+ readonly referenceId: string;
176
+ readonly age: number;
177
+ };
178
+ type DailyWorkItemAge = {
179
+ readonly date: string;
180
+ readonly items: readonly WorkItemAgeEntry[];
181
+ };
182
+ type DailyTotalWorkItemAge = {
183
+ readonly date: string;
184
+ readonly totalAge: number;
185
+ readonly itemCount: number;
186
+ };
187
+ type WorkItemAgeOverTimeResult = {
188
+ readonly startDate: string;
189
+ readonly endDate: string;
190
+ readonly daily: readonly DailyWorkItemAge[];
191
+ };
192
+ type TotalWorkItemAgeOverTimeResult = {
193
+ readonly startDate: string;
194
+ readonly endDate: string;
195
+ readonly daily: readonly DailyTotalWorkItemAge[];
196
+ };
170
197
  type LighthouseClient = {
171
198
  readonly checkConnectivity: () => Promise<ConnectivityValidationResult>;
172
199
  readonly getVersion: () => Promise<LighthouseApiResult<string>>;
@@ -203,8 +230,12 @@ type LighthouseClient = {
203
230
  readonly getPortfolioWip: (portfolioId: number, asOfDate: string) => Promise<LighthouseApiResult<readonly unknown[]>>;
204
231
  readonly getPortfolioCycleTimeData: (portfolioId: number, range?: MetricsDateRange) => Promise<LighthouseApiResult<readonly unknown[]>>;
205
232
  readonly getPortfolioPredictabilityScore: (portfolioId: number, range?: MetricsDateRange) => Promise<LighthouseApiResult<unknown>>;
233
+ readonly getTeamWorkItemAgeOverTime: (teamId: number, range?: MetricsDateRange) => Promise<LighthouseApiResult<WorkItemAgeOverTimeResult>>;
234
+ readonly getTeamTotalWorkItemAgeOverTime: (teamId: number, range?: MetricsDateRange) => Promise<LighthouseApiResult<TotalWorkItemAgeOverTimeResult>>;
206
235
  readonly getPortfolioTotalWorkItemAge: (portfolioId: number, asOfDate: string) => Promise<LighthouseApiResult<number>>;
207
236
  readonly getPortfolioTotalWorkItemAgeInfo: (portfolioId: number, range?: MetricsDateRange) => Promise<LighthouseApiResult<unknown>>;
237
+ readonly getPortfolioWorkItemAgeOverTime: (portfolioId: number, range?: MetricsDateRange) => Promise<LighthouseApiResult<WorkItemAgeOverTimeResult>>;
238
+ readonly getPortfolioTotalWorkItemAgeOverTime: (portfolioId: number, range?: MetricsDateRange) => Promise<LighthouseApiResult<TotalWorkItemAgeOverTimeResult>>;
208
239
  readonly getFeaturesByIds: (ids: readonly number[]) => Promise<LighthouseApiResult<readonly unknown[]>>;
209
240
  readonly getFeaturesByReferences: (refs: readonly string[]) => Promise<LighthouseApiResult<readonly unknown[]>>;
210
241
  readonly getFeatureWorkItems: (featureId: number) => Promise<LighthouseApiResult<readonly unknown[]>>;
@@ -220,4 +251,4 @@ type LighthouseClientDependencies = {
220
251
  };
221
252
  declare const createLighthouseClient: (configuration: LighthouseClientConfiguration, dependencies?: LighthouseClientDependencies) => LighthouseClient;
222
253
 
223
- 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 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, createLighthouseAuthContext, createLighthouseClient, getClientPackageContract, getDefaultMetricsDateRange, parseStandaloneDiscoveryContract, pollCliAuthSession, queryServerAuthMode, startCliAuthSession, validateLighthouseConnectivity };
254
+ 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 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 TotalWorkItemAgeOverTimeResult, type WorkItemAgeEntry, type WorkItemAgeOverTimeResult, createLighthouseAuthContext, createLighthouseClient, getClientPackageContract, getDefaultMetricsDateRange, getStandaloneDiscoveryLockfilePath, loadStandaloneDiscoveryContract, parseStandaloneDiscoveryContract, pollCliAuthSession, queryServerAuthMode, startCliAuthSession, validateLighthouseConnectivity };
package/dist/index.js CHANGED
@@ -1,4 +1,7 @@
1
1
  // src/index.ts
2
+ import { readFile } from "fs/promises";
3
+ import { homedir } from "os";
4
+ import { join } from "path";
2
5
  var getClientPackageContract = () => ({
3
6
  name: "@letpeoplework/lighthouse-client",
4
7
  capabilities: [
@@ -9,6 +12,7 @@ var getClientPackageContract = () => ({
9
12
  ]
10
13
  });
11
14
  var SUPPORTED_DISCOVERY_CONTRACT_VERSION = 1;
15
+ var STANDALONE_DISCOVERY_LOCKFILE_NAME = "standalone.lock.json";
12
16
  var isObjectRecord = (value) => {
13
17
  return typeof value === "object" && value !== null && !Array.isArray(value);
14
18
  };
@@ -123,6 +127,47 @@ var parseStandaloneDiscoveryContract = (serializedContract) => {
123
127
  detectedAtUtc
124
128
  });
125
129
  };
130
+ var getStandaloneDiscoveryLockfilePath = () => {
131
+ if (process.env.LIGHTHOUSE_STANDALONE_LOCKFILE_PATH !== void 0) {
132
+ return process.env.LIGHTHOUSE_STANDALONE_LOCKFILE_PATH;
133
+ }
134
+ if (process.platform === "darwin") {
135
+ return join(
136
+ homedir(),
137
+ "Library",
138
+ "Application Support",
139
+ "Lighthouse",
140
+ STANDALONE_DISCOVERY_LOCKFILE_NAME
141
+ );
142
+ }
143
+ if (process.platform === "win32") {
144
+ return join(
145
+ process.env.APPDATA ?? join(homedir(), "AppData", "Roaming"),
146
+ "Lighthouse",
147
+ STANDALONE_DISCOVERY_LOCKFILE_NAME
148
+ );
149
+ }
150
+ return join(
151
+ process.env.XDG_CONFIG_HOME ?? join(homedir(), ".config"),
152
+ "Lighthouse",
153
+ STANDALONE_DISCOVERY_LOCKFILE_NAME
154
+ );
155
+ };
156
+ var loadStandaloneDiscoveryContract = async () => {
157
+ try {
158
+ const serializedContract = await readFile(
159
+ getStandaloneDiscoveryLockfilePath(),
160
+ "utf8"
161
+ );
162
+ const parsedContract = parseStandaloneDiscoveryContract(serializedContract);
163
+ if (!parsedContract.isValid) {
164
+ return null;
165
+ }
166
+ return parsedContract.contract;
167
+ } catch {
168
+ return null;
169
+ }
170
+ };
126
171
  var getResolvedEndpoint = (mode, lighthouseUrl) => {
127
172
  const apiBaseUrl = getApiBaseUrl(lighthouseUrl);
128
173
  return {
@@ -624,6 +669,54 @@ var requestNoContent = async (configuration, dependencies, route, requestOptions
624
669
  var getResolvedMetricsDateRange = (range) => range ?? getDefaultMetricsDateRange();
625
670
  var getMetricsDateRangeQuery = (range) => `startDate=${encodeURIComponent(range.startDate)}&endDate=${encodeURIComponent(range.endDate)}`;
626
671
  var getMetricsAsOfDateQuery = (asOfDate) => `asOfDate=${encodeURIComponent(asOfDate)}`;
672
+ var addUtcDays = (dateStr, days) => {
673
+ const d = /* @__PURE__ */ new Date(`${dateStr}T00:00:00Z`);
674
+ d.setUTCDate(d.getUTCDate() + days);
675
+ return d.toISOString().split("T")[0];
676
+ };
677
+ var computeItemAge = (dayDate, startedDate) => {
678
+ const day = Date.parse(`${dayDate}T00:00:00Z`);
679
+ const started = Date.parse(startedDate);
680
+ const diffDays = Math.floor((day - started) / 864e5);
681
+ return Math.max(1, diffDays + 1);
682
+ };
683
+ var deriveWorkItemAgeOverTime = (startDate, endDate, wipData) => {
684
+ const daily = Object.entries(
685
+ wipData.workItemsPerUnitOfTime
686
+ ).map(([dayIndexStr, items]) => {
687
+ const dayIndex = Number.parseInt(dayIndexStr, 10);
688
+ const date = addUtcDays(startDate, dayIndex);
689
+ const ageItems = items.filter(
690
+ (item) => item.startedDate != null && item.startedDate.length > 0
691
+ ).map((item) => ({
692
+ id: item.id,
693
+ name: item.name,
694
+ referenceId: item.referenceId,
695
+ age: computeItemAge(date, item.startedDate)
696
+ }));
697
+ return { date, items: ageItems };
698
+ });
699
+ daily.sort((a, b) => a.date.localeCompare(b.date));
700
+ return { startDate, endDate, daily };
701
+ };
702
+ var deriveTotalWorkItemAgeOverTime = (startDate, endDate, wipData) => {
703
+ const daily = Object.entries(
704
+ wipData.workItemsPerUnitOfTime
705
+ ).map(([dayIndexStr, items]) => {
706
+ const dayIndex = Number.parseInt(dayIndexStr, 10);
707
+ const date = addUtcDays(startDate, dayIndex);
708
+ const activeItems = items.filter(
709
+ (item) => item.startedDate != null && item.startedDate.length > 0
710
+ );
711
+ const totalAge = activeItems.reduce(
712
+ (sum, item) => sum + computeItemAge(date, item.startedDate),
713
+ 0
714
+ );
715
+ return { date, totalAge, itemCount: activeItems.length };
716
+ });
717
+ daily.sort((a, b) => a.date.localeCompare(b.date));
718
+ return { startDate, endDate, daily };
719
+ };
627
720
  var createLighthouseClient = (configuration, dependencies = {}) => ({
628
721
  checkConnectivity: async () => {
629
722
  const fetchDependency = getFetchDependency(dependencies);
@@ -818,6 +911,42 @@ var createLighthouseClient = (configuration, dependencies = {}) => ({
818
911
  { method: "GET" }
819
912
  );
820
913
  },
914
+ getTeamWorkItemAgeOverTime: async (teamId, range) => {
915
+ const r = getResolvedMetricsDateRange(range);
916
+ const wipResult = await requestJson(
917
+ configuration,
918
+ dependencies,
919
+ `/v1/teams/${teamId}/metrics/wipOverTime?${getMetricsDateRangeQuery(r)}`,
920
+ { method: "GET" }
921
+ );
922
+ if (!wipResult.ok) {
923
+ return wipResult;
924
+ }
925
+ return {
926
+ ok: true,
927
+ value: deriveWorkItemAgeOverTime(r.startDate, r.endDate, wipResult.value)
928
+ };
929
+ },
930
+ getTeamTotalWorkItemAgeOverTime: async (teamId, range) => {
931
+ const r = getResolvedMetricsDateRange(range);
932
+ const wipResult = await requestJson(
933
+ configuration,
934
+ dependencies,
935
+ `/v1/teams/${teamId}/metrics/wipOverTime?${getMetricsDateRangeQuery(r)}`,
936
+ { method: "GET" }
937
+ );
938
+ if (!wipResult.ok) {
939
+ return wipResult;
940
+ }
941
+ return {
942
+ ok: true,
943
+ value: deriveTotalWorkItemAgeOverTime(
944
+ r.startDate,
945
+ r.endDate,
946
+ wipResult.value
947
+ )
948
+ };
949
+ },
821
950
  getPortfolioThroughput: async (portfolioId, range) => {
822
951
  const r = getResolvedMetricsDateRange(range);
823
952
  return requestJson(
@@ -893,6 +1022,42 @@ var createLighthouseClient = (configuration, dependencies = {}) => ({
893
1022
  { method: "GET" }
894
1023
  );
895
1024
  },
1025
+ getPortfolioWorkItemAgeOverTime: async (portfolioId, range) => {
1026
+ const r = getResolvedMetricsDateRange(range);
1027
+ const wipResult = await requestJson(
1028
+ configuration,
1029
+ dependencies,
1030
+ `/v1/portfolios/${portfolioId}/metrics/wipOverTime?${getMetricsDateRangeQuery(r)}`,
1031
+ { method: "GET" }
1032
+ );
1033
+ if (!wipResult.ok) {
1034
+ return wipResult;
1035
+ }
1036
+ return {
1037
+ ok: true,
1038
+ value: deriveWorkItemAgeOverTime(r.startDate, r.endDate, wipResult.value)
1039
+ };
1040
+ },
1041
+ getPortfolioTotalWorkItemAgeOverTime: async (portfolioId, range) => {
1042
+ const r = getResolvedMetricsDateRange(range);
1043
+ const wipResult = await requestJson(
1044
+ configuration,
1045
+ dependencies,
1046
+ `/v1/portfolios/${portfolioId}/metrics/wipOverTime?${getMetricsDateRangeQuery(r)}`,
1047
+ { method: "GET" }
1048
+ );
1049
+ if (!wipResult.ok) {
1050
+ return wipResult;
1051
+ }
1052
+ return {
1053
+ ok: true,
1054
+ value: deriveTotalWorkItemAgeOverTime(
1055
+ r.startDate,
1056
+ r.endDate,
1057
+ wipResult.value
1058
+ )
1059
+ };
1060
+ },
896
1061
  getFeaturesByIds: async (ids) => {
897
1062
  const queryString = ids.map((id) => `ids=${encodeURIComponent(id)}`).join("&");
898
1063
  return requestJson(
@@ -959,6 +1124,8 @@ export {
959
1124
  createLighthouseClient,
960
1125
  getClientPackageContract,
961
1126
  getDefaultMetricsDateRange,
1127
+ getStandaloneDiscoveryLockfilePath,
1128
+ loadStandaloneDiscoveryContract,
962
1129
  parseStandaloneDiscoveryContract,
963
1130
  pollCliAuthSession,
964
1131
  queryServerAuthMode,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@letpeoplework/lighthouse-client",
3
- "version": "0.7.0",
3
+ "version": "1.0.0",
4
4
  "description": "Shared Lighthouse API client contracts",
5
5
  "repository": "https://github.com/LetPeopleWork/lighthouse-clients",
6
6
  "type": "module",