@flagshark/core 2.0.0 → 2.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. package/README.md +2 -0
  2. package/dist/config/schema.d.ts +112 -0
  3. package/dist/config/schema.d.ts.map +1 -1
  4. package/dist/config/schema.js +63 -0
  5. package/dist/config/schema.js.map +1 -1
  6. package/dist/detection/detectors/typescript.d.ts.map +1 -1
  7. package/dist/detection/detectors/typescript.js +41 -0
  8. package/dist/detection/detectors/typescript.js.map +1 -1
  9. package/dist/detection/feature-flag.d.ts +28 -0
  10. package/dist/detection/feature-flag.d.ts.map +1 -1
  11. package/dist/detection/helpers.d.ts +16 -0
  12. package/dist/detection/helpers.d.ts.map +1 -1
  13. package/dist/detection/helpers.js +117 -6
  14. package/dist/detection/helpers.js.map +1 -1
  15. package/dist/detection/import-graph.d.ts +234 -0
  16. package/dist/detection/import-graph.d.ts.map +1 -0
  17. package/dist/detection/import-graph.js +641 -0
  18. package/dist/detection/import-graph.js.map +1 -0
  19. package/dist/detection/interface.d.ts +57 -0
  20. package/dist/detection/interface.d.ts.map +1 -1
  21. package/dist/detection/interface.js.map +1 -1
  22. package/dist/detection/polyglot-analyzer.d.ts +8 -0
  23. package/dist/detection/polyglot-analyzer.d.ts.map +1 -1
  24. package/dist/detection/polyglot-analyzer.js +2 -0
  25. package/dist/detection/polyglot-analyzer.js.map +1 -1
  26. package/dist/detection/tree-sitter/engine.d.ts.map +1 -1
  27. package/dist/detection/tree-sitter/engine.js +62 -15
  28. package/dist/detection/tree-sitter/engine.js.map +1 -1
  29. package/dist/detection/tree-sitter/parser-cache.d.ts +20 -0
  30. package/dist/detection/tree-sitter/parser-cache.d.ts.map +1 -1
  31. package/dist/detection/tree-sitter/parser-cache.js +32 -1
  32. package/dist/detection/tree-sitter/parser-cache.js.map +1 -1
  33. package/dist/output/json.d.ts.map +1 -1
  34. package/dist/output/json.js +28 -0
  35. package/dist/output/json.js.map +1 -1
  36. package/dist/output/markdown.d.ts.map +1 -1
  37. package/dist/output/markdown.js +47 -1
  38. package/dist/output/markdown.js.map +1 -1
  39. package/dist/output/text.d.ts.map +1 -1
  40. package/dist/output/text.js +89 -0
  41. package/dist/output/text.js.map +1 -1
  42. package/dist/providers/cross-reference.d.ts +36 -2
  43. package/dist/providers/cross-reference.d.ts.map +1 -1
  44. package/dist/providers/cross-reference.js +102 -7
  45. package/dist/providers/cross-reference.js.map +1 -1
  46. package/dist/providers/interface.d.ts +116 -2
  47. package/dist/providers/interface.d.ts.map +1 -1
  48. package/dist/providers/launchdarkly/client.d.ts +12 -0
  49. package/dist/providers/launchdarkly/client.d.ts.map +1 -1
  50. package/dist/providers/launchdarkly/client.js +243 -24
  51. package/dist/providers/launchdarkly/client.js.map +1 -1
  52. package/dist/providers/launchdarkly/types.d.ts +318 -0
  53. package/dist/providers/launchdarkly/types.d.ts.map +1 -1
  54. package/dist/providers/launchdarkly/types.js +82 -0
  55. package/dist/providers/launchdarkly/types.js.map +1 -1
  56. package/dist/providers/orchestrate.d.ts +34 -2
  57. package/dist/providers/orchestrate.d.ts.map +1 -1
  58. package/dist/providers/orchestrate.js +59 -7
  59. package/dist/providers/orchestrate.js.map +1 -1
  60. package/dist/scan-repo.d.ts +28 -0
  61. package/dist/scan-repo.d.ts.map +1 -1
  62. package/dist/scan-repo.js +290 -4
  63. package/dist/scan-repo.js.map +1 -1
  64. package/dist/staleness.d.ts +31 -1
  65. package/dist/staleness.d.ts.map +1 -1
  66. package/dist/staleness.js +66 -10
  67. package/dist/staleness.js.map +1 -1
  68. package/package.json +2 -1
@@ -1,44 +1,263 @@
1
- import { FlagsResponseSchema } from './types.js';
1
+ import pLimit from 'p-limit';
2
+ import { EvaluationsResponseSchema, FlagsResponseSchema, FlagStatusesResponseSchema, MembersResponseSchema, } from './types.js';
2
3
  import { LdApiError } from './errors.js';
3
4
  const DEFAULT_API_BASE = 'https://app.launchdarkly.com';
4
5
  const LD_API_VERSION = '20240415';
6
+ // Concurrency cap on the per-flag evaluation-counts fetch fan-out.
7
+ // LD's per-token rate limit is documented at "thousands of requests per
8
+ // minute"; 5 in-flight keeps us comfortably under any reasonable cap
9
+ // even on 200-flag projects. Higher = faster scans, more rate-limit
10
+ // risk. Kept private (not configurable) because tuning this should be
11
+ // a deliberate change visible in code review.
12
+ const EVALUATIONS_CONCURRENCY = 5;
13
+ /**
14
+ * Fetches every flag in `config.project` (active + archived), then enriches
15
+ * the result with platform-side signals from two auxiliary LD endpoints:
16
+ *
17
+ * /api/v2/flag-statuses/{project}/{env} → status + lastRequested
18
+ * /api/v2/members?limit=500 → maintainer name resolution
19
+ *
20
+ * Both auxiliary calls are best-effort: if they fail (e.g. token lacks
21
+ * permission, network blip), we log via thrown LdApiError only for the
22
+ * primary /flags request. Aux failures are swallowed so the core
23
+ * cross-reference path still functions with partial data.
24
+ */
5
25
  export async function fetchAllFlags(config, opts = {}) {
6
26
  const fetchFn = opts.fetch ?? globalThis.fetch;
7
27
  const apiBase = opts.apiBase ?? DEFAULT_API_BASE;
8
28
  const out = [];
9
- let path = buildFirstPath(config.project, config.environment);
10
- while (path) {
11
- const res = await fetchFn(new URL(path, apiBase), {
12
- headers: {
13
- Authorization: config.token,
14
- 'LD-API-Version': LD_API_VERSION,
15
- },
16
- signal: opts.signal,
17
- });
18
- if (!res.ok) {
19
- throw new LdApiError(`LaunchDarkly API ${res.status} ${res.statusText}`, res.status);
20
- }
21
- const json = await res.json();
22
- const parsed = FlagsResponseSchema.parse(json);
23
- for (const item of parsed.items) {
24
- const envData = item.environments?.[config.environment];
25
- out.push({
26
- key: item.key,
27
- archived: item.archived,
28
- lastModified: envData?.lastModified != null ? new Date(envData.lastModified) : null,
29
- });
29
+ // LD's list endpoint EXCLUDES archived flags by default; passing
30
+ // `archived=true` flips it to return ONLY archived flags. There is no
31
+ // "both" mode in the v2 API. So we make two pagination passes — one
32
+ // for active, one for archived — and union the results. Without this,
33
+ // any flag archived in LD silently surfaces as `missing-in-platform`
34
+ // (the exact opposite of `archived-in-platform`), defeating the
35
+ // archived-flag signal entirely.
36
+ const headers = { Authorization: config.token, 'LD-API-Version': LD_API_VERSION };
37
+ const maintainerIds = new Set();
38
+ for (const archivedOnly of [false, true]) {
39
+ let path = buildFirstPath(config.project, config.environment, archivedOnly);
40
+ while (path) {
41
+ const res = await fetchFn(new URL(path, apiBase), { headers, signal: opts.signal });
42
+ if (!res.ok) {
43
+ throw new LdApiError(`LaunchDarkly API ${res.status} ${res.statusText}`, res.status);
44
+ }
45
+ const json = await res.json();
46
+ const parsed = FlagsResponseSchema.parse(json);
47
+ for (const item of parsed.items) {
48
+ const envData = item.environments?.[config.environment];
49
+ if (item.maintainerId)
50
+ maintainerIds.add(item.maintainerId);
51
+ out.push({
52
+ key: item.key,
53
+ archived: item.archived,
54
+ lastModified: envData?.lastModified != null ? new Date(envData.lastModified) : null,
55
+ // LD's `temporary` is true when the user wants the flag removed
56
+ // eventually, false when it's permanent. We invert so downstream
57
+ // logic doesn't have to re-reason the polarity every time.
58
+ permanent: !item.temporary,
59
+ createdAt: item.creationDate != null ? new Date(item.creationDate) : null,
60
+ tags: item.tags,
61
+ // Resolved below from the /members lookup; left as the opaque id
62
+ // for now so the producer/consumer split stays clean.
63
+ maintainer: item.maintainerId,
64
+ });
65
+ }
66
+ path = parsed._links?.next?.href;
67
+ }
68
+ }
69
+ // Aux 1: resolve maintainer IDs → "First Last <email>" display strings.
70
+ // Single batch request, best-effort. If the token lacks /members read
71
+ // permission (Reader role doesn't include it on some LD orgs), we
72
+ // leave the opaque ID in place rather than fail the whole scan.
73
+ if (maintainerIds.size > 0) {
74
+ const members = await fetchMembersMap(apiBase, headers, fetchFn, opts.signal);
75
+ if (members) {
76
+ for (const flag of out) {
77
+ if (flag.maintainer && members.has(flag.maintainer)) {
78
+ flag.maintainer = members.get(flag.maintainer);
79
+ }
80
+ else if (flag.maintainer) {
81
+ // Couldn't resolve — drop the opaque ID rather than display it.
82
+ flag.maintainer = undefined;
83
+ }
84
+ }
85
+ }
86
+ else {
87
+ // Members lookup failed entirely — strip the opaque IDs so they
88
+ // don't leak into output as garbled-looking strings.
89
+ for (const flag of out) {
90
+ if (flag.maintainer)
91
+ flag.maintainer = undefined;
92
+ }
93
+ }
94
+ }
95
+ // Aux 2: fetch the per-environment flag-status verdict (LD's own
96
+ // staleness: 'new' / 'active' / 'inactive' / 'launched'). Cross-reference
97
+ // turns these into platform-inactive / platform-launched signals.
98
+ const statuses = await fetchFlagStatuses(config.project, config.environment, apiBase, headers, fetchFn, opts.signal);
99
+ if (statuses) {
100
+ for (const flag of out) {
101
+ const s = statuses.get(flag.key);
102
+ if (s) {
103
+ flag.status = s.name;
104
+ flag.lastRequested = s.lastRequested;
105
+ }
30
106
  }
31
- path = parsed._links?.next?.href;
32
107
  }
108
+ // Aux 3: 30-day evaluation counts per flag. Per-flag endpoint, so we
109
+ // fan out with a concurrency cap. The endpoint is tier-gated; the
110
+ // first 404/403/401 short-circuits the rest so we don't make N
111
+ // pointless requests on accounts that don't have this feature.
112
+ // Active flags only — archived flags have no evaluation activity by
113
+ // definition, and probing them wastes API calls.
114
+ await enrichWithEvaluations(out, config, apiBase, headers, fetchFn, opts.signal);
33
115
  return out;
34
116
  }
35
- function buildFirstPath(project, environment) {
117
+ /**
118
+ * Fan-out fetch of 30-day evaluation counts per (active, non-archived)
119
+ * flag. Mutates the input PlatformFlag[] in place — sets
120
+ * `evaluations30d` to a number on success, leaves it undefined when
121
+ * the endpoint isn't available. The first request that returns 401 /
122
+ * 403 / 404 disables the feature for the rest of the batch (assumed
123
+ * to be tier-gated or feature-off project-wide).
124
+ *
125
+ * Network errors on individual flags are tolerated: that single flag's
126
+ * `evaluations30d` stays undefined and the rest of the scan continues.
127
+ * Cross-reference treats `undefined` as "no data, no signal".
128
+ */
129
+ async function enrichWithEvaluations(flags, config, apiBase, headers, fetchFn, signal) {
130
+ const candidates = flags.filter((f) => !f.archived);
131
+ if (candidates.length === 0)
132
+ return;
133
+ let featureAvailable = true;
134
+ const limiter = pLimit(EVALUATIONS_CONCURRENCY);
135
+ await Promise.all(candidates.map((flag) => limiter(async () => {
136
+ if (!featureAvailable)
137
+ return;
138
+ try {
139
+ const url = new URL(`/api/v2/usage/evaluations/${encodeURIComponent(config.project)}/${encodeURIComponent(config.environment)}/${encodeURIComponent(flag.key)}`, apiBase);
140
+ const res = await fetchFn(url, { headers, signal });
141
+ if (res.status === 401 || res.status === 403 || res.status === 404) {
142
+ // Disable for the rest of the batch — assume tier-gated /
143
+ // feature off for this project. Leave already-set
144
+ // evaluations30d alone (no rollback).
145
+ featureAvailable = false;
146
+ return;
147
+ }
148
+ if (!res.ok) {
149
+ // 5xx / 429 — transient. Skip this flag, keep the feature
150
+ // enabled for others.
151
+ return;
152
+ }
153
+ const parsed = EvaluationsResponseSchema.parse(await res.json());
154
+ flag.evaluations30d = sumEvaluationSeries(parsed.series);
155
+ }
156
+ catch {
157
+ // Network error / JSON parse failure — same treatment as 5xx,
158
+ // skip this flag, keep going.
159
+ }
160
+ })));
161
+ }
162
+ /**
163
+ * The /usage/evaluations response is a time-series of variation-keyed
164
+ * counts: each series point is `{ time, "0": N, "1": M, ... }`. We
165
+ * don't care which variation served — only the total. Sum every
166
+ * numeric field on every series point.
167
+ */
168
+ function sumEvaluationSeries(series) {
169
+ let total = 0;
170
+ for (const point of series) {
171
+ for (const [key, value] of Object.entries(point)) {
172
+ if (key === 'time')
173
+ continue;
174
+ if (typeof value === 'number' && Number.isFinite(value)) {
175
+ total += value;
176
+ }
177
+ }
178
+ }
179
+ return total;
180
+ }
181
+ function buildFirstPath(project, environment, archived = false) {
36
182
  const params = new URLSearchParams({
37
183
  env: environment,
38
184
  limit: '100',
39
185
  offset: '0',
40
186
  summary: '1',
41
187
  });
188
+ if (archived)
189
+ params.set('archived', 'true');
42
190
  return `/api/v2/flags/${encodeURIComponent(project)}?${params.toString()}`;
43
191
  }
192
+ /**
193
+ * Best-effort fetch of every LD member, returning a map from member ID
194
+ * to "First Last <email>" display string. Returns null when the API
195
+ * rejects the request (typically: token lacks /members read scope).
196
+ * Caller handles null by leaving maintainer fields unresolved.
197
+ */
198
+ async function fetchMembersMap(apiBase, headers, fetchFn, signal) {
199
+ try {
200
+ const url = new URL('/api/v2/members?limit=500', apiBase);
201
+ const res = await fetchFn(url, { headers, signal });
202
+ if (!res.ok)
203
+ return null;
204
+ const parsed = MembersResponseSchema.parse(await res.json());
205
+ const map = new Map();
206
+ for (const m of parsed.items) {
207
+ const name = [m.firstName, m.lastName].filter((s) => s).join(' ').trim();
208
+ const display = name ? `${name} <${m.email}>` : m.email;
209
+ map.set(m._id, display);
210
+ }
211
+ return map;
212
+ }
213
+ catch {
214
+ /* v8 ignore start — defensive catch for malformed JSON / schema
215
+ drift; not exercised by current fixtures. */
216
+ return null;
217
+ /* v8 ignore stop */
218
+ }
219
+ }
220
+ /**
221
+ * Best-effort fetch of LD's per-environment flag-status verdicts for
222
+ * every flag in the project. Returns a Map keyed by flag key whose
223
+ * values include LD's own staleness verdict (`name`) and the
224
+ * lastRequested timestamp. Returns null when the API rejects the
225
+ * request — cross-reference falls back to its non-status code paths.
226
+ *
227
+ * The parent-link parsing extracts the flag key from
228
+ * `/api/v2/flags/{project}/{flagKey}` — LD doesn't return the key
229
+ * inline on each status item.
230
+ */
231
+ async function fetchFlagStatuses(project, environment, apiBase, headers, fetchFn, signal) {
232
+ try {
233
+ const url = new URL(`/api/v2/flag-statuses/${encodeURIComponent(project)}/${encodeURIComponent(environment)}`, apiBase);
234
+ const res = await fetchFn(url, { headers, signal });
235
+ if (!res.ok)
236
+ return null;
237
+ const parsed = FlagStatusesResponseSchema.parse(await res.json());
238
+ const out = new Map();
239
+ for (const item of parsed.items) {
240
+ /* v8 ignore start — defensive guards against LD responses without
241
+ a parent link or with malformed hrefs; production LD always
242
+ sends a well-formed href on this endpoint, but we'd rather
243
+ skip a single item than fail the whole batch on contract drift. */
244
+ const href = item._links?.parent?.href ?? '';
245
+ const key = href.includes('/') ? href.slice(href.lastIndexOf('/') + 1) : '';
246
+ if (!key)
247
+ continue;
248
+ /* v8 ignore stop */
249
+ out.set(key, {
250
+ name: item.name,
251
+ lastRequested: item.lastRequested ? new Date(item.lastRequested) : null,
252
+ });
253
+ }
254
+ return out;
255
+ }
256
+ catch {
257
+ /* v8 ignore start — defensive catch for malformed JSON / schema
258
+ drift; not exercised by current fixtures. */
259
+ return null;
260
+ /* v8 ignore stop */
261
+ }
262
+ }
44
263
  //# sourceMappingURL=client.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"client.js","sourceRoot":"","sources":["../../../src/providers/launchdarkly/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAA;AAChD,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AAGxC,MAAM,gBAAgB,GAAG,8BAA8B,CAAA;AACvD,MAAM,cAAc,GAAG,UAAU,CAAA;AAcjC,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,MAA2B,EAC3B,OAA6B,EAAE;IAE/B,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,IAAI,UAAU,CAAC,KAAK,CAAA;IAC9C,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,IAAI,gBAAgB,CAAA;IAChD,MAAM,GAAG,GAAmB,EAAE,CAAA;IAC9B,IAAI,IAAI,GAAuB,cAAc,CAAC,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,WAAW,CAAC,CAAA;IAEjF,OAAO,IAAI,EAAE,CAAC;QACZ,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,IAAI,GAAG,CAAC,IAAI,EAAE,OAAO,CAAC,EAAE;YAChD,OAAO,EAAE;gBACP,aAAa,EAAE,MAAM,CAAC,KAAK;gBAC3B,gBAAgB,EAAE,cAAc;aACjC;YACD,MAAM,EAAE,IAAI,CAAC,MAAM;SACpB,CAAC,CAAA;QACF,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;YACZ,MAAM,IAAI,UAAU,CAAC,oBAAoB,GAAG,CAAC,MAAM,IAAI,GAAG,CAAC,UAAU,EAAE,EAAE,GAAG,CAAC,MAAM,CAAC,CAAA;QACtF,CAAC;QACD,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAA;QAC7B,MAAM,MAAM,GAAG,mBAAmB,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;QAC9C,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;YAChC,MAAM,OAAO,GAAG,IAAI,CAAC,YAAY,EAAE,CAAC,MAAM,CAAC,WAAW,CAAC,CAAA;YACvD,GAAG,CAAC,IAAI,CAAC;gBACP,GAAG,EAAE,IAAI,CAAC,GAAG;gBACb,QAAQ,EAAE,IAAI,CAAC,QAAQ;gBACvB,YAAY,EAAE,OAAO,EAAE,YAAY,IAAI,IAAI,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,IAAI;aACpF,CAAC,CAAA;QACJ,CAAC;QACD,IAAI,GAAG,MAAM,CAAC,MAAM,EAAE,IAAI,EAAE,IAAI,CAAA;IAClC,CAAC;IAED,OAAO,GAAG,CAAA;AACZ,CAAC;AAED,SAAS,cAAc,CAAC,OAAe,EAAE,WAAmB;IAC1D,MAAM,MAAM,GAAG,IAAI,eAAe,CAAC;QACjC,GAAG,EAAE,WAAW;QAChB,KAAK,EAAE,KAAK;QACZ,MAAM,EAAE,GAAG;QACX,OAAO,EAAE,GAAG;KACb,CAAC,CAAA;IACF,OAAO,iBAAiB,kBAAkB,CAAC,OAAO,CAAC,IAAI,MAAM,CAAC,QAAQ,EAAE,EAAE,CAAA;AAC5E,CAAC"}
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../../../src/providers/launchdarkly/client.ts"],"names":[],"mappings":"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"}