@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.
- package/README.md +2 -0
- package/dist/config/schema.d.ts +112 -0
- package/dist/config/schema.d.ts.map +1 -1
- package/dist/config/schema.js +63 -0
- package/dist/config/schema.js.map +1 -1
- package/dist/detection/detectors/typescript.d.ts.map +1 -1
- package/dist/detection/detectors/typescript.js +41 -0
- package/dist/detection/detectors/typescript.js.map +1 -1
- package/dist/detection/feature-flag.d.ts +28 -0
- package/dist/detection/feature-flag.d.ts.map +1 -1
- package/dist/detection/helpers.d.ts +16 -0
- package/dist/detection/helpers.d.ts.map +1 -1
- package/dist/detection/helpers.js +117 -6
- package/dist/detection/helpers.js.map +1 -1
- package/dist/detection/import-graph.d.ts +234 -0
- package/dist/detection/import-graph.d.ts.map +1 -0
- package/dist/detection/import-graph.js +641 -0
- package/dist/detection/import-graph.js.map +1 -0
- package/dist/detection/interface.d.ts +57 -0
- package/dist/detection/interface.d.ts.map +1 -1
- package/dist/detection/interface.js.map +1 -1
- package/dist/detection/polyglot-analyzer.d.ts +8 -0
- package/dist/detection/polyglot-analyzer.d.ts.map +1 -1
- package/dist/detection/polyglot-analyzer.js +2 -0
- package/dist/detection/polyglot-analyzer.js.map +1 -1
- package/dist/detection/tree-sitter/engine.d.ts.map +1 -1
- package/dist/detection/tree-sitter/engine.js +62 -15
- package/dist/detection/tree-sitter/engine.js.map +1 -1
- package/dist/detection/tree-sitter/parser-cache.d.ts +20 -0
- package/dist/detection/tree-sitter/parser-cache.d.ts.map +1 -1
- package/dist/detection/tree-sitter/parser-cache.js +32 -1
- package/dist/detection/tree-sitter/parser-cache.js.map +1 -1
- package/dist/output/json.d.ts.map +1 -1
- package/dist/output/json.js +28 -0
- package/dist/output/json.js.map +1 -1
- package/dist/output/markdown.d.ts.map +1 -1
- package/dist/output/markdown.js +47 -1
- package/dist/output/markdown.js.map +1 -1
- package/dist/output/text.d.ts.map +1 -1
- package/dist/output/text.js +89 -0
- package/dist/output/text.js.map +1 -1
- package/dist/providers/cross-reference.d.ts +36 -2
- package/dist/providers/cross-reference.d.ts.map +1 -1
- package/dist/providers/cross-reference.js +102 -7
- package/dist/providers/cross-reference.js.map +1 -1
- package/dist/providers/interface.d.ts +116 -2
- package/dist/providers/interface.d.ts.map +1 -1
- package/dist/providers/launchdarkly/client.d.ts +12 -0
- package/dist/providers/launchdarkly/client.d.ts.map +1 -1
- package/dist/providers/launchdarkly/client.js +243 -24
- package/dist/providers/launchdarkly/client.js.map +1 -1
- package/dist/providers/launchdarkly/types.d.ts +318 -0
- package/dist/providers/launchdarkly/types.d.ts.map +1 -1
- package/dist/providers/launchdarkly/types.js +82 -0
- package/dist/providers/launchdarkly/types.js.map +1 -1
- package/dist/providers/orchestrate.d.ts +34 -2
- package/dist/providers/orchestrate.d.ts.map +1 -1
- package/dist/providers/orchestrate.js +59 -7
- package/dist/providers/orchestrate.js.map +1 -1
- package/dist/scan-repo.d.ts +28 -0
- package/dist/scan-repo.d.ts.map +1 -1
- package/dist/scan-repo.js +290 -4
- package/dist/scan-repo.js.map +1 -1
- package/dist/staleness.d.ts +31 -1
- package/dist/staleness.d.ts.map +1 -1
- package/dist/staleness.js +66 -10
- package/dist/staleness.js.map +1 -1
- package/package.json +2 -1
package/dist/output/text.js
CHANGED
|
@@ -33,10 +33,39 @@ function buildTable(flags) {
|
|
|
33
33
|
return 'missing-in-platform';
|
|
34
34
|
if (s.type === 'archived-in-platform')
|
|
35
35
|
return 'archived-in-platform';
|
|
36
|
+
if (s.type === 'platform-too-old')
|
|
37
|
+
return 'platform-too-old';
|
|
38
|
+
if (s.type === 'platform-inactive')
|
|
39
|
+
return 'platform-inactive';
|
|
40
|
+
if (s.type === 'platform-launched')
|
|
41
|
+
return 'platform-launched';
|
|
42
|
+
if (s.type === 'platform-zero-evaluations')
|
|
43
|
+
return 'platform-zero-evaluations';
|
|
44
|
+
if (s.type === 'platform-low-evaluations')
|
|
45
|
+
return 'platform-low-evaluations';
|
|
36
46
|
return s.description;
|
|
37
47
|
})
|
|
38
48
|
.join(', ');
|
|
39
49
|
lines.push(`│ ${pad(sf.name, cols.flag)} │ ${pad(fileRef, cols.file)} │ ${pad(sf.age ?? 'unknown', cols.added)} │ ${pad(signalText, cols.signal)} │`);
|
|
50
|
+
// Compact second row when we have platform metadata to surface.
|
|
51
|
+
// Indented under the flag column, kept brief so the table doesn't
|
|
52
|
+
// explode in width. Skipped when there's nothing to say.
|
|
53
|
+
const metaParts = [];
|
|
54
|
+
if (sf.tags && sf.tags.length > 0) {
|
|
55
|
+
metaParts.push(`tags: ${sf.tags.join(', ')}`);
|
|
56
|
+
}
|
|
57
|
+
if (sf.maintainer) {
|
|
58
|
+
metaParts.push(`maintainer: ${sf.maintainer}`);
|
|
59
|
+
}
|
|
60
|
+
if (sf.platformStatus && sf.platformStatus !== 'active') {
|
|
61
|
+
metaParts.push(`platform-status: ${sf.platformStatus}`);
|
|
62
|
+
}
|
|
63
|
+
if (metaParts.length > 0) {
|
|
64
|
+
const metaText = metaParts.join(' • ');
|
|
65
|
+
// Wide layout — span all 4 column widths plus borders.
|
|
66
|
+
const totalWidth = cols.flag + cols.file + cols.added + cols.signal + 9; // 3 inner separators + 6 padding
|
|
67
|
+
lines.push(`│ ${pad('└─ ' + metaText, totalWidth)} │`);
|
|
68
|
+
}
|
|
40
69
|
}
|
|
41
70
|
lines.push(hBorder('└', '┴', '┘'));
|
|
42
71
|
return lines.join('\n');
|
|
@@ -50,11 +79,53 @@ export function formatText(result, options) {
|
|
|
50
79
|
if (result.excludedCount && result.excludedCount > 0) {
|
|
51
80
|
lines.push(`(${result.excludedCount} excluded via .flagsharkignore + excludes)`);
|
|
52
81
|
}
|
|
82
|
+
// Surface files where the detector errored. A small number is the long tail
|
|
83
|
+
// of edge cases (mid-edit syntax errors, exotic source files, etc.) — note
|
|
84
|
+
// it but don't shout. A large fraction means the analysis is materially
|
|
85
|
+
// incomplete (e.g. PostHog on 1.3.x: ~27% of files aborted from the python
|
|
86
|
+
// tree-sitter grammar) and the user needs to know before they trust the
|
|
87
|
+
// flag count or health score. Threshold of >5% picks up "noticeably broken"
|
|
88
|
+
// without firing on the dozen-files-out-of-ten-thousand case.
|
|
89
|
+
const parseErrorCount = result.parseErrorCount ?? 0;
|
|
90
|
+
if (parseErrorCount > 0 && result.filesScanned > 0) {
|
|
91
|
+
const pct = (parseErrorCount / result.filesScanned) * 100;
|
|
92
|
+
// Compare on the rounded value so the threshold and the displayed
|
|
93
|
+
// percentage cannot disagree. Pre-fix, `pct > 5` with `Math.round(pct)`
|
|
94
|
+
// could fire the warning branch while rendering "(5%)" — same number
|
|
95
|
+
// we document as the quiet/loud boundary in the comment above. See
|
|
96
|
+
// ultrareview bug_018.
|
|
97
|
+
const rounded = Math.round(pct);
|
|
98
|
+
const pctStr = pct >= 1 ? ` (${rounded}%)` : '';
|
|
99
|
+
if (rounded > 5) {
|
|
100
|
+
lines.push(`⚠ ${parseErrorCount} of ${result.filesScanned} files${pctStr} couldn't be parsed — results may be incomplete. See the "Parse errors during analysis" warning on stderr for the top failing patterns.`);
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
lines.push(`(${parseErrorCount} file${parseErrorCount === 1 ? '' : 's'} couldn't be parsed — see the "Parse errors during analysis" warning above)`);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
53
106
|
if (result.totalFlags === 0) {
|
|
54
107
|
lines.push('No feature flags detected.');
|
|
55
108
|
lines.push('');
|
|
56
109
|
lines.push('Supported providers: LaunchDarkly, Unleash, Flipt, Split.io, PostHog, and more.');
|
|
57
110
|
lines.push('Run flagshark scan --help for configuration options.');
|
|
111
|
+
// Troubleshooting hint when a non-trivial repo turns up empty. Pre-fix,
|
|
112
|
+
// this was the single most common confused-user response: "I have 50
|
|
113
|
+
// feature flags, your scan found 0, what's wrong?". The hint surfaces
|
|
114
|
+
// the three real causes (SDK wrappers loaded at runtime, TS path
|
|
115
|
+
// aliases, config-struct flag systems) without falsely promising
|
|
116
|
+
// "this WILL find them"; see README#known-limitations for the design
|
|
117
|
+
// trade-offs that lead here. We only fire on repos large enough that
|
|
118
|
+
// "no flags at all" is suspicious (≥100 files); empty/tiny repos
|
|
119
|
+
// legitimately have no flags and don't deserve scolding.
|
|
120
|
+
const SUSPICIOUS_THRESHOLD = 100;
|
|
121
|
+
if (result.filesScanned >= SUSPICIOUS_THRESHOLD) {
|
|
122
|
+
lines.push('');
|
|
123
|
+
lines.push(`Expected results in this ${result.filesScanned}-file repo? Three patterns FlagShark can't see today:`);
|
|
124
|
+
lines.push(' • SDK loaded at runtime via window/globalThis (instead of static `import`)');
|
|
125
|
+
lines.push(' • TS path aliases (`@/...`, `~/...`) bridging the consumer file to the SDK');
|
|
126
|
+
lines.push(' • Typed config-struct flag systems (e.g. `Config().FeatureFlags.X`)');
|
|
127
|
+
lines.push('See https://github.com/FlagShark/flagshark#known-limitations for details + workarounds.');
|
|
128
|
+
}
|
|
58
129
|
return lines.join('\n');
|
|
59
130
|
}
|
|
60
131
|
if (result.detectedProviders.length > 0) {
|
|
@@ -63,6 +134,24 @@ export function formatText(result, options) {
|
|
|
63
134
|
const uniqueStaleNames = new Set(result.staleFlags.map((f) => f.name));
|
|
64
135
|
const staleCount = uniqueStaleNames.size;
|
|
65
136
|
lines.push(`Found ${result.totalFlags} feature flags, ${staleCount} stale`);
|
|
137
|
+
// Surface permanent-flag exclusions so users see WHY a flag they expected
|
|
138
|
+
// to appear in the stale table doesn't. Per-platform breakdown so the
|
|
139
|
+
// attribution is clear when multiple platforms are configured.
|
|
140
|
+
if (result.permanentByPlatform && Object.keys(result.permanentByPlatform).length > 0) {
|
|
141
|
+
for (const [platform, names] of Object.entries(result.permanentByPlatform)) {
|
|
142
|
+
if (names.length === 0)
|
|
143
|
+
continue;
|
|
144
|
+
const flagWord = names.length === 1 ? 'flag' : 'flags';
|
|
145
|
+
// Cap the inline list at 5 names to keep the line readable on
|
|
146
|
+
// medium-sized projects. Verbose mode could show all — but the
|
|
147
|
+
// existing verbose option drives the stale-table cap, not this.
|
|
148
|
+
// For now, a fixed cap: anyone with >5 permanent flags can see
|
|
149
|
+
// the full list in JSON output.
|
|
150
|
+
const preview = names.slice(0, 5).join(', ');
|
|
151
|
+
const overflow = names.length > 5 ? `, +${names.length - 5} more` : '';
|
|
152
|
+
lines.push(`${names.length} ${flagWord} excluded as permanent in ${platform}: ${preview}${overflow}`);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
66
155
|
if (staleCount > 0) {
|
|
67
156
|
lines.push('');
|
|
68
157
|
lines.push('Stale flags:');
|
package/dist/output/text.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"text.js","sourceRoot":"","sources":["../../src/output/text.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"text.js","sourceRoot":"","sources":["../../src/output/text.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,13 +1,47 @@
|
|
|
1
1
|
import type { FeatureFlag } from '../detection/feature-flag.js';
|
|
2
2
|
import type { PlatformFlag, PlatformSignal } from './interface.js';
|
|
3
|
+
export interface CrossReferenceOptions {
|
|
4
|
+
/**
|
|
5
|
+
* Staleness threshold in days. When set, cross-reference can emit
|
|
6
|
+
* `platform-too-old` for matched flags whose platform-side
|
|
7
|
+
* `createdAt` exceeds the threshold — a code-independent staleness
|
|
8
|
+
* signal that's stronger than either code-age or platform-age alone.
|
|
9
|
+
* When unset, the platform-too-old signal is never emitted.
|
|
10
|
+
*/
|
|
11
|
+
thresholdDays?: number;
|
|
12
|
+
/**
|
|
13
|
+
* Minimum evaluation count over the platform's reporting window
|
|
14
|
+
* (30 days for LD) below which a flag is considered "rarely used"
|
|
15
|
+
* and emits `platform-low-evaluations`. The `platform-zero-evaluations`
|
|
16
|
+
* signal (count exactly 0) is independent of this — it always fires
|
|
17
|
+
* regardless of threshold when the platform reports a real zero.
|
|
18
|
+
*
|
|
19
|
+
* Default: 10. Tuned for "small project, real usage" — set higher
|
|
20
|
+
* for high-traffic prod environments where 10 evaluations/30d is
|
|
21
|
+
* still effectively dead.
|
|
22
|
+
*/
|
|
23
|
+
evaluationThreshold?: number;
|
|
24
|
+
}
|
|
3
25
|
/**
|
|
4
26
|
* Pure function: joins detected flag keys against a platform's flag list,
|
|
5
|
-
* emits PlatformSignals
|
|
27
|
+
* emits PlatformSignals based on the platform's view of each flag.
|
|
28
|
+
*
|
|
29
|
+
* Signal precedence (most-specific wins; only one primary signal per flag):
|
|
30
|
+
* 1. missing-in-platform — flag not in platform at all (error)
|
|
31
|
+
* 2. archived-in-platform — flag archived (warning)
|
|
32
|
+
* 3. platform-launched — LD says single variation for 7+ days (error)
|
|
33
|
+
* 4. platform-inactive — LD says no eval events for 7+ days (warning)
|
|
34
|
+
* 5. platform-permanent — user marked permanent (control signal)
|
|
35
|
+
* 6. platform-too-old — created > thresholdDays ago (warning)
|
|
36
|
+
*
|
|
37
|
+
* Permanent + too-old can coexist; permanent + inactive can coexist;
|
|
38
|
+
* permanent is the strongest CONTROL signal (it suppresses code-side
|
|
39
|
+
* heuristics) but doesn't displace platform-side activity signals.
|
|
6
40
|
*
|
|
7
41
|
* Does NOT surface platform flags with no code reference — that's a separate
|
|
8
42
|
* "orphan platform flags" feature, out of scope.
|
|
9
43
|
*/
|
|
10
|
-
export declare function crossReference(detectedFlags: Map<string, FeatureFlag[]>, platformFlags: PlatformFlag[], platformDisplayName: string): Map<string, PlatformSignal[]>;
|
|
44
|
+
export declare function crossReference(detectedFlags: Map<string, FeatureFlag[]>, platformFlags: PlatformFlag[], platformDisplayName: string, options?: CrossReferenceOptions): Map<string, PlatformSignal[]>;
|
|
11
45
|
/**
|
|
12
46
|
* Merge platform signals from multiple platforms into a single per-flag map.
|
|
13
47
|
* If both LaunchDarkly and Unleash say a flag is missing, the flag's entry
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cross-reference.d.ts","sourceRoot":"","sources":["../../src/providers/cross-reference.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAA;AAC/D,OAAO,KAAK,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAA;AAElE;;;;;;
|
|
1
|
+
{"version":3,"file":"cross-reference.d.ts","sourceRoot":"","sources":["../../src/providers/cross-reference.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAA;AAC/D,OAAO,KAAK,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAA;AAElE,MAAM,WAAW,qBAAqB;IACpC;;;;;;OAMG;IACH,aAAa,CAAC,EAAE,MAAM,CAAA;IAEtB;;;;;;;;;;OAUG;IACH,mBAAmB,CAAC,EAAE,MAAM,CAAA;CAC7B;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,cAAc,CAC5B,aAAa,EAAE,GAAG,CAAC,MAAM,EAAE,WAAW,EAAE,CAAC,EACzC,aAAa,EAAE,YAAY,EAAE,EAC7B,mBAAmB,EAAE,MAAM,EAC3B,OAAO,GAAE,qBAA0B,GAClC,GAAG,CAAC,MAAM,EAAE,cAAc,EAAE,CAAC,CAgH/B;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,GAAG,CAAC,MAAM,EAAE,cAAc,EAAE,CAAC,EACnC,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,cAAc,EAAE,CAAC,GACpC,IAAI,CASN"}
|
|
@@ -1,28 +1,123 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Pure function: joins detected flag keys against a platform's flag list,
|
|
3
|
-
* emits PlatformSignals
|
|
3
|
+
* emits PlatformSignals based on the platform's view of each flag.
|
|
4
|
+
*
|
|
5
|
+
* Signal precedence (most-specific wins; only one primary signal per flag):
|
|
6
|
+
* 1. missing-in-platform — flag not in platform at all (error)
|
|
7
|
+
* 2. archived-in-platform — flag archived (warning)
|
|
8
|
+
* 3. platform-launched — LD says single variation for 7+ days (error)
|
|
9
|
+
* 4. platform-inactive — LD says no eval events for 7+ days (warning)
|
|
10
|
+
* 5. platform-permanent — user marked permanent (control signal)
|
|
11
|
+
* 6. platform-too-old — created > thresholdDays ago (warning)
|
|
12
|
+
*
|
|
13
|
+
* Permanent + too-old can coexist; permanent + inactive can coexist;
|
|
14
|
+
* permanent is the strongest CONTROL signal (it suppresses code-side
|
|
15
|
+
* heuristics) but doesn't displace platform-side activity signals.
|
|
4
16
|
*
|
|
5
17
|
* Does NOT surface platform flags with no code reference — that's a separate
|
|
6
18
|
* "orphan platform flags" feature, out of scope.
|
|
7
19
|
*/
|
|
8
|
-
export function crossReference(detectedFlags, platformFlags, platformDisplayName) {
|
|
20
|
+
export function crossReference(detectedFlags, platformFlags, platformDisplayName, options = {}) {
|
|
9
21
|
const platformByKey = new Map(platformFlags.map((f) => [f.key, f]));
|
|
10
22
|
const out = new Map();
|
|
23
|
+
const now = Date.now();
|
|
24
|
+
const thresholdMs = options.thresholdDays != null ? options.thresholdDays * 86_400_000 : null;
|
|
11
25
|
for (const key of detectedFlags.keys()) {
|
|
12
26
|
const platform = platformByKey.get(key);
|
|
13
27
|
if (!platform) {
|
|
14
|
-
out.set(key, [
|
|
28
|
+
out.set(key, [
|
|
29
|
+
{
|
|
15
30
|
type: 'missing-in-platform',
|
|
16
31
|
severity: 'error',
|
|
17
32
|
description: `referenced in code but not found in ${platformDisplayName}`,
|
|
18
|
-
}
|
|
33
|
+
},
|
|
34
|
+
]);
|
|
35
|
+
continue;
|
|
19
36
|
}
|
|
20
|
-
|
|
21
|
-
out.set(key, [
|
|
37
|
+
if (platform.archived) {
|
|
38
|
+
out.set(key, [
|
|
39
|
+
{
|
|
22
40
|
type: 'archived-in-platform',
|
|
23
41
|
severity: 'warning',
|
|
24
42
|
description: `archived in ${platformDisplayName}`,
|
|
25
|
-
}
|
|
43
|
+
},
|
|
44
|
+
]);
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
// Stack-able signals: platform-permanent (control), platform-too-old,
|
|
48
|
+
// platform-inactive/launched. A single flag can carry multiple.
|
|
49
|
+
const signals = [];
|
|
50
|
+
if (platform.status === 'launched') {
|
|
51
|
+
signals.push({
|
|
52
|
+
type: 'platform-launched',
|
|
53
|
+
severity: 'error',
|
|
54
|
+
description: `${platformDisplayName} reports this flag has served one variation for 7+ days — likely ready for removal`,
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
else if (platform.status === 'inactive') {
|
|
58
|
+
signals.push({
|
|
59
|
+
type: 'platform-inactive',
|
|
60
|
+
severity: 'warning',
|
|
61
|
+
description: `no evaluations recorded in ${platformDisplayName} in the last 7+ days`,
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
if (platform.permanent) {
|
|
65
|
+
// Control signal: tells staleness.ts to suppress age + low-usage
|
|
66
|
+
// signals. Filtered out of the user-facing StaleFlag.signals array
|
|
67
|
+
// before display. Kill-switches and other intentionally permanent
|
|
68
|
+
// flags should not be flagged as stale by code-side heuristics.
|
|
69
|
+
signals.push({
|
|
70
|
+
type: 'platform-permanent',
|
|
71
|
+
severity: 'info',
|
|
72
|
+
description: `marked permanent in ${platformDisplayName}`,
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
// platform-too-old: platform-side staleness independent of code age.
|
|
76
|
+
// Only fires when caller provided a threshold AND the platform
|
|
77
|
+
// exposed a createdAt timestamp. Permanent flags suppress this too —
|
|
78
|
+
// the user explicitly chose to keep a long-lived flag, so don't
|
|
79
|
+
// contradict them with a too-old warning.
|
|
80
|
+
if (!platform.permanent &&
|
|
81
|
+
thresholdMs != null &&
|
|
82
|
+
platform.createdAt &&
|
|
83
|
+
now - platform.createdAt.getTime() > thresholdMs) {
|
|
84
|
+
const ageDays = Math.floor((now - platform.createdAt.getTime()) / 86_400_000);
|
|
85
|
+
signals.push({
|
|
86
|
+
type: 'platform-too-old',
|
|
87
|
+
severity: 'warning',
|
|
88
|
+
description: `created in ${platformDisplayName} ${ageDays} days ago — past the ${options.thresholdDays}-day threshold`,
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
// Real evaluation counts beat every heuristic above when present.
|
|
92
|
+
// `evaluations30d === 0` is a hard signal: the platform itself
|
|
93
|
+
// confirms the code path is unused. Suppressed on permanent flags
|
|
94
|
+
// because the user explicitly opted into keeping the flag — same
|
|
95
|
+
// logic as too-old.
|
|
96
|
+
//
|
|
97
|
+
// `undefined` means the feature isn't available for this account
|
|
98
|
+
// (tier-gated / endpoint 404'd); `null` means available but no
|
|
99
|
+
// window data yet. Both fall through to no signal.
|
|
100
|
+
if (!platform.permanent && typeof platform.evaluations30d === 'number') {
|
|
101
|
+
if (platform.evaluations30d === 0) {
|
|
102
|
+
signals.push({
|
|
103
|
+
type: 'platform-zero-evaluations',
|
|
104
|
+
severity: 'error',
|
|
105
|
+
description: `0 evaluations in ${platformDisplayName} over the last 30 days — code path is unused`,
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
else {
|
|
109
|
+
const threshold = options.evaluationThreshold ?? 10;
|
|
110
|
+
if (platform.evaluations30d < threshold) {
|
|
111
|
+
signals.push({
|
|
112
|
+
type: 'platform-low-evaluations',
|
|
113
|
+
severity: 'warning',
|
|
114
|
+
description: `only ${platform.evaluations30d} evaluation${platform.evaluations30d === 1 ? '' : 's'} in ${platformDisplayName} over the last 30 days (below threshold ${threshold})`,
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
if (signals.length > 0) {
|
|
120
|
+
out.set(key, signals);
|
|
26
121
|
}
|
|
27
122
|
}
|
|
28
123
|
return out;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cross-reference.js","sourceRoot":"","sources":["../../src/providers/cross-reference.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"cross-reference.js","sourceRoot":"","sources":["../../src/providers/cross-reference.ts"],"names":[],"mappings":"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"}
|
|
@@ -5,6 +5,91 @@ export interface PlatformFlag {
|
|
|
5
5
|
/** Each platform maps its concept (archived/disabled/stale) to this boolean. */
|
|
6
6
|
archived: boolean;
|
|
7
7
|
lastModified: Date | null;
|
|
8
|
+
/**
|
|
9
|
+
* True when the platform considers this flag permanent — i.e. NOT a
|
|
10
|
+
* temporary feature toggle that should ever be removed. Kill-switches,
|
|
11
|
+
* operational config flags, and "long-lived experiments" fall here.
|
|
12
|
+
*
|
|
13
|
+
* Maps from LaunchDarkly's `temporary` field (we invert: `permanent =
|
|
14
|
+
* !temporary`). Other platforms may not have an equivalent concept —
|
|
15
|
+
* leave undefined when unknown, which the staleness engine treats
|
|
16
|
+
* exactly as it always did (no special-case suppression).
|
|
17
|
+
*
|
|
18
|
+
* Why surface this: the staleness engine's age and low-usage signals
|
|
19
|
+
* are false positives on intentionally permanent flags. A
|
|
20
|
+
* personal-access-tokens kill switch shouldn't be flagged as "stale"
|
|
21
|
+
* just because it's three years old and only appears in one place;
|
|
22
|
+
* that's the entire point of a kill switch.
|
|
23
|
+
*/
|
|
24
|
+
permanent?: boolean;
|
|
25
|
+
/**
|
|
26
|
+
* When the flag was first created in the platform. Distinct from
|
|
27
|
+
* `lastModified` (which tracks the most recent environment-level
|
|
28
|
+
* edit). The cross-reference layer compares this against the
|
|
29
|
+
* staleness threshold to emit `platform-too-old` — a code-independent
|
|
30
|
+
* staleness signal. A flag that LD created 18 months ago AND still
|
|
31
|
+
* has code references is a stronger candidate for cleanup than either
|
|
32
|
+
* data point alone.
|
|
33
|
+
*/
|
|
34
|
+
createdAt?: Date | null;
|
|
35
|
+
/**
|
|
36
|
+
* Platform-side classification labels. LaunchDarkly's tag list maps
|
|
37
|
+
* directly; other platforms may map their equivalent concept (Unleash
|
|
38
|
+
* `strategies`, Split.io `traffic_types`, etc.). Surfaced in output
|
|
39
|
+
* so reviewers see the LD-side classification alongside flag names.
|
|
40
|
+
*/
|
|
41
|
+
tags?: string[];
|
|
42
|
+
/**
|
|
43
|
+
* Human-readable maintainer label. Producer is responsible for
|
|
44
|
+
* resolving any opaque ID (e.g. LD `maintainerId`) into a display
|
|
45
|
+
* string ('First Last <email>') before populating this field.
|
|
46
|
+
*/
|
|
47
|
+
maintainer?: string;
|
|
48
|
+
/**
|
|
49
|
+
* Platform-computed activity verdict for this flag in the configured
|
|
50
|
+
* environment. Maps directly from LD's flag-statuses endpoint:
|
|
51
|
+
*
|
|
52
|
+
* - 'new': created in the last 7 days; not enough data yet → no
|
|
53
|
+
* staleness verdict, suppresses code-side age signals
|
|
54
|
+
* - 'active': serving evaluations as expected → no signal
|
|
55
|
+
* - 'inactive': no evaluation events in 7+ days → emit
|
|
56
|
+
* `platform-inactive` (warning) — code reference may be dead
|
|
57
|
+
* - 'launched': single variation served consistently for 7+ days →
|
|
58
|
+
* emit `platform-launched` (error) — flag is effectively rolled
|
|
59
|
+
* out and the conditional code can be removed
|
|
60
|
+
*
|
|
61
|
+
* Other platforms may not have an equivalent; leave undefined when
|
|
62
|
+
* unknown.
|
|
63
|
+
*/
|
|
64
|
+
status?: 'new' | 'active' | 'inactive' | 'launched';
|
|
65
|
+
/**
|
|
66
|
+
* When this flag was last evaluated, per the platform's runtime
|
|
67
|
+
* telemetry. Null when no evaluations have occurred yet (`status:
|
|
68
|
+
* 'new'`). Surface this in output so reviewers can decide whether
|
|
69
|
+
* "7 days ago" or "9 months ago" before pulling the trigger.
|
|
70
|
+
*/
|
|
71
|
+
lastRequested?: Date | null;
|
|
72
|
+
/**
|
|
73
|
+
* Total evaluations recorded across all variations in the configured
|
|
74
|
+
* environment over the last 30 days. Distinct from `status` (which is
|
|
75
|
+
* LD's 7-day verdict) — gives a number we can compare against a
|
|
76
|
+
* threshold, and a stronger signal than the status alone.
|
|
77
|
+
*
|
|
78
|
+
* `0` → flag definitively unused over the window; emit
|
|
79
|
+
* `platform-zero-evaluations` (error severity — same as
|
|
80
|
+
* missing-in-platform: the code path can be removed).
|
|
81
|
+
* `< N` → flag rarely evaluated; emit `platform-low-evaluations`
|
|
82
|
+
* (warning). Threshold N is configurable per-platform.
|
|
83
|
+
* `>= N` → no signal — actively used.
|
|
84
|
+
*
|
|
85
|
+
* Set to `null` when the platform supports the field but couldn't
|
|
86
|
+
* resolve a count (e.g. flag just created — no window yet). Set to
|
|
87
|
+
* `undefined` when the platform's evaluation-counts feature isn't
|
|
88
|
+
* available at all (tier-gated, or feature off project-wide). The
|
|
89
|
+
* cross-reference layer treats `undefined` and `null` the same way:
|
|
90
|
+
* no signal emitted.
|
|
91
|
+
*/
|
|
92
|
+
evaluations30d?: number | null;
|
|
8
93
|
}
|
|
9
94
|
/** Runtime client for a configured platform. Returned by PlatformDefinition.createClient. */
|
|
10
95
|
export interface PlatformClient {
|
|
@@ -30,8 +115,37 @@ export interface PlatformDefinition<TConfig = unknown> {
|
|
|
30
115
|
}
|
|
31
116
|
/** Signal type emitted by crossReference(). Merged into StaleFlag.signals[] by staleness.ts. */
|
|
32
117
|
export interface PlatformSignal {
|
|
33
|
-
|
|
34
|
-
|
|
118
|
+
/**
|
|
119
|
+
* Signal types:
|
|
120
|
+
*
|
|
121
|
+
* - `missing-in-platform` (error): code references a flag that's not
|
|
122
|
+
* in the platform at all. Almost always a dead reference.
|
|
123
|
+
* - `archived-in-platform` (warning): user archived the flag in the
|
|
124
|
+
* platform but code still references it — cleanup time.
|
|
125
|
+
* - `platform-permanent` (info, CONTROL signal): user marked the
|
|
126
|
+
* flag permanent. Tells the staleness engine to suppress age + low-
|
|
127
|
+
* usage signals; filtered out of user-facing output. See
|
|
128
|
+
* PlatformFlag.permanent docstring for full reasoning.
|
|
129
|
+
* - `platform-too-old` (warning): the flag was created in the
|
|
130
|
+
* platform more than `thresholdDays` ago — a code-independent
|
|
131
|
+
* staleness signal. Survives even when code-age signal is clean
|
|
132
|
+
* (e.g. flag was copy-pasted into a new file last week, but
|
|
133
|
+
* originated in LD 2 years ago).
|
|
134
|
+
* - `platform-inactive` (warning): LD's own flag-status verdict —
|
|
135
|
+
* no evaluations recorded against this flag in the last 7 days.
|
|
136
|
+
* Sourced from the /flag-statuses endpoint.
|
|
137
|
+
* - `platform-launched` (error): LD's own verdict — flag has been
|
|
138
|
+
* serving a single variation consistently for the past 7 days.
|
|
139
|
+
* "Ready for removal" from LD's perspective.
|
|
140
|
+
* - `platform-zero-evaluations` (error): real runtime data — zero
|
|
141
|
+
* evaluations recorded in the last 30 days. Sourced from LD's
|
|
142
|
+
* evaluation analytics endpoint. Strongest possible stale signal
|
|
143
|
+
* because it's based on actual usage, not heuristics.
|
|
144
|
+
* - `platform-low-evaluations` (warning): evaluations below the
|
|
145
|
+
* configured threshold over the window. Default threshold: 10/30d.
|
|
146
|
+
*/
|
|
147
|
+
type: 'missing-in-platform' | 'archived-in-platform' | 'platform-permanent' | 'platform-too-old' | 'platform-inactive' | 'platform-launched' | 'platform-zero-evaluations' | 'platform-low-evaluations';
|
|
148
|
+
severity: 'error' | 'warning' | 'info';
|
|
35
149
|
description: string;
|
|
36
150
|
}
|
|
37
151
|
//# sourceMappingURL=interface.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"interface.d.ts","sourceRoot":"","sources":["../../src/providers/interface.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,KAAK,CAAA;AAElC,oEAAoE;AACpE,MAAM,WAAW,YAAY;IAC3B,GAAG,EAAE,MAAM,CAAA;IACX,gFAAgF;IAChF,QAAQ,EAAE,OAAO,CAAA;IACjB,YAAY,EAAE,IAAI,GAAG,IAAI,CAAA;
|
|
1
|
+
{"version":3,"file":"interface.d.ts","sourceRoot":"","sources":["../../src/providers/interface.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,KAAK,CAAA;AAElC,oEAAoE;AACpE,MAAM,WAAW,YAAY;IAC3B,GAAG,EAAE,MAAM,CAAA;IACX,gFAAgF;IAChF,QAAQ,EAAE,OAAO,CAAA;IACjB,YAAY,EAAE,IAAI,GAAG,IAAI,CAAA;IACzB;;;;;;;;;;;;;;;OAeG;IACH,SAAS,CAAC,EAAE,OAAO,CAAA;IAEnB;;;;;;;;OAQG;IACH,SAAS,CAAC,EAAE,IAAI,GAAG,IAAI,CAAA;IAEvB;;;;;OAKG;IACH,IAAI,CAAC,EAAE,MAAM,EAAE,CAAA;IAEf;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAA;IAEnB;;;;;;;;;;;;;;;OAeG;IACH,MAAM,CAAC,EAAE,KAAK,GAAG,QAAQ,GAAG,UAAU,GAAG,UAAU,CAAA;IAEnD;;;;;OAKG;IACH,aAAa,CAAC,EAAE,IAAI,GAAG,IAAI,CAAA;IAE3B;;;;;;;;;;;;;;;;;;;OAmBG;IACH,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAC/B;AAED,6FAA6F;AAC7F,MAAM,WAAW,cAAc;IAC7B,yCAAyC;IACzC,IAAI,EAAE,MAAM,CAAA;IACZ,4EAA4E;IAC5E,WAAW,EAAE,MAAM,CAAA;IACnB,SAAS,CAAC,IAAI,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,WAAW,CAAA;KAAE,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,CAAA;CACpE;AAED,iFAAiF;AACjF,MAAM,WAAW,kBAAkB,CAAC,OAAO,GAAG,OAAO;IACnD,2DAA2D;IAC3D,IAAI,EAAE,MAAM,CAAA;IACZ,WAAW,EAAE,MAAM,CAAA;IACnB,0EAA0E;IAC1E,eAAe,EAAE,MAAM,CAAA;IACvB,0DAA0D;IAC1D,YAAY,EAAE,OAAO,CAAC,OAAO,CAAC,CAAA;IAC9B,uGAAuG;IACvG,YAAY,EAAE,CAAC,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,KAAK,cAAc,CAAA;CACjE;AAED,gGAAgG;AAChG,MAAM,WAAW,cAAc;IAC7B;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA4BG;IACH,IAAI,EACA,qBAAqB,GACrB,sBAAsB,GACtB,oBAAoB,GACpB,kBAAkB,GAClB,mBAAmB,GACnB,mBAAmB,GACnB,2BAA2B,GAC3B,0BAA0B,CAAA;IAC9B,QAAQ,EAAE,OAAO,GAAG,SAAS,GAAG,MAAM,CAAA;IACtC,WAAW,EAAE,MAAM,CAAA;CACpB"}
|
|
@@ -9,5 +9,17 @@ export interface FetchAllFlagsOptions {
|
|
|
9
9
|
fetch?: typeof globalThis.fetch;
|
|
10
10
|
signal?: AbortSignal;
|
|
11
11
|
}
|
|
12
|
+
/**
|
|
13
|
+
* Fetches every flag in `config.project` (active + archived), then enriches
|
|
14
|
+
* the result with platform-side signals from two auxiliary LD endpoints:
|
|
15
|
+
*
|
|
16
|
+
* /api/v2/flag-statuses/{project}/{env} → status + lastRequested
|
|
17
|
+
* /api/v2/members?limit=500 → maintainer name resolution
|
|
18
|
+
*
|
|
19
|
+
* Both auxiliary calls are best-effort: if they fail (e.g. token lacks
|
|
20
|
+
* permission, network blip), we log via thrown LdApiError only for the
|
|
21
|
+
* primary /flags request. Aux failures are swallowed so the core
|
|
22
|
+
* cross-reference path still functions with partial data.
|
|
23
|
+
*/
|
|
12
24
|
export declare function fetchAllFlags(config: FetchAllFlagsConfig, opts?: FetchAllFlagsOptions): Promise<PlatformFlag[]>;
|
|
13
25
|
//# sourceMappingURL=client.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../../src/providers/launchdarkly/client.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../../src/providers/launchdarkly/client.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAA;AAanD,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,MAAM,CAAA;IACf,WAAW,EAAE,MAAM,CAAA;IACnB,KAAK,EAAE,MAAM,CAAA;CACd;AAED,MAAM,WAAW,oBAAoB;IACnC,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,KAAK,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAA;IAC/B,MAAM,CAAC,EAAE,WAAW,CAAA;CACrB;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,aAAa,CACjC,MAAM,EAAE,mBAAmB,EAC3B,IAAI,GAAE,oBAAyB,GAC9B,OAAO,CAAC,YAAY,EAAE,CAAC,CAuGzB"}
|