kanmi-perf-revenue 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/README.md ADDED
@@ -0,0 +1,251 @@
1
+ # Performance Revenue Intelligence Engine
2
+
3
+ An autonomous CLI tool that connects web performance data (Datadog RUM) with business outcomes (GA4) to quantify revenue impact and prioritize fixes.
4
+
5
+ **One question answered:** *"What is this performance issue costing the business?"*
6
+
7
+ ## Quick Start
8
+
9
+ ```bash
10
+ # Install
11
+ npm install -g @perf-revenue/engine
12
+
13
+ # Initialize configuration
14
+ perf-revenue config init
15
+
16
+ # Add a client
17
+ perf-revenue config add-client \
18
+ --name acme \
19
+ --display-name "Acme Corp" \
20
+ --ga4-project my-gcp-project \
21
+ --ga4-property 123456789 \
22
+ --datadog-app rum-app-id
23
+
24
+ # Set credentials
25
+ export ANTHROPIC_API_KEY=sk-ant-...
26
+ export DATADOG_API_KEY=...
27
+ export DATADOG_APP_KEY=...
28
+
29
+ # Run autonomous analysis
30
+ perf-revenue analyze --client acme -v
31
+ ```
32
+
33
+ ## How It Works
34
+
35
+ ```
36
+ ┌─────────────────────────────────────────────────────┐
37
+ │ perf-revenue analyze --client acme │
38
+ └─────────────────────────────────────────────────────┘
39
+
40
+
41
+ ┌─────────────────────────────────────────────────────┐
42
+ │ Claude Agent (Autonomous) │
43
+ │ ├── Tool: BigQuery (fetch GA4 business data) │
44
+ │ ├── Tool: Datadog API (fetch RUM performance) │
45
+ │ ├── Tool: Analysis Engine (calculate impact) │
46
+ │ └── Tool: Report Generator (format output) │
47
+ └─────────────────────────────────────────────────────┘
48
+
49
+
50
+ ┌─────────────────────────────────────────────────────┐
51
+ │ Executive Report (markdown) │
52
+ │ • $47K/month revenue opportunity │
53
+ │ • Prioritized by financial impact │
54
+ │ • CFO-ready format │
55
+ └─────────────────────────────────────────────────────┘
56
+ ```
57
+
58
+ ## Features
59
+
60
+ - **Autonomous Analysis** - Claude fetches, analyzes, and reports without manual intervention
61
+ - **Financial-First** - Revenue impact in dollars, not performance scores
62
+ - **Conservative Estimates** - Underestimates by design, defensible assumptions
63
+ - **Executive Output** - VP/Director/CFO-ready reports
64
+
65
+ ## CLI Commands
66
+
67
+ ### `perf-revenue analyze`
68
+
69
+ Run autonomous revenue impact analysis.
70
+
71
+ ```bash
72
+ perf-revenue analyze \
73
+ --client <name> # Client name (required)
74
+ --start <YYYY-MM-DD> # Start date (default: 14 days ago)
75
+ --end <YYYY-MM-DD> # End date (default: yesterday)
76
+ --output <path> # Output file path
77
+ --verbose # Show agent activity
78
+ --max-iterations <n> # Max agent iterations (default: 20)
79
+ ```
80
+
81
+ ### `perf-revenue config`
82
+
83
+ Manage configuration.
84
+
85
+ ```bash
86
+ # Initialize config directory
87
+ perf-revenue config init
88
+
89
+ # Show current configuration
90
+ perf-revenue config show
91
+
92
+ # Add a new client
93
+ perf-revenue config add-client \
94
+ --name <id> # Client identifier
95
+ --display-name <name> # Display name
96
+ --ga4-project <id> # GCP project ID
97
+ --ga4-property <id> # GA4 property ID
98
+ --ga4-key-file <path> # Service account JSON (optional)
99
+ --datadog-app <id> # Datadog RUM app ID
100
+ --datadog-site <site> # Datadog site (default: datadoghq.com)
101
+
102
+ # Remove a client
103
+ perf-revenue config remove-client <name>
104
+
105
+ # List clients
106
+ perf-revenue config list-clients
107
+ ```
108
+
109
+ ### `perf-revenue validate`
110
+
111
+ Validate configuration and connectivity.
112
+
113
+ ```bash
114
+ perf-revenue validate # Validate all
115
+ perf-revenue validate -c <client> # Validate specific client
116
+ ```
117
+
118
+ ## Configuration
119
+
120
+ Configuration is stored in `~/.perf-revenue/`:
121
+
122
+ ```
123
+ ~/.perf-revenue/
124
+ ├── config.json # Client configurations
125
+ └── .env # API keys (optional)
126
+ ```
127
+
128
+ ### Environment Variables
129
+
130
+ | Variable | Required | Description |
131
+ |----------|----------|-------------|
132
+ | `ANTHROPIC_API_KEY` | Yes | Claude API key |
133
+ | `DATADOG_API_KEY` | Yes | Datadog API key |
134
+ | `DATADOG_APP_KEY` | Yes | Datadog application key |
135
+ | `GOOGLE_APPLICATION_CREDENTIALS` | No | Path to GCP service account JSON |
136
+
137
+ ## Conversion Lift Model
138
+
139
+ Conservative estimates based on industry research:
140
+
141
+ | Improvement | Conversion Lift |
142
+ |-------------|-----------------|
143
+ | 100ms LCP improvement | +0.5% conversion rate |
144
+ | 100ms INP improvement | +0.3% conversion rate |
145
+ | 0.01 CLS improvement | +0.1% conversion rate |
146
+
147
+ ## Output Format
148
+
149
+ Reports follow a strict executive-friendly structure:
150
+
151
+ 1. **Executive Summary** - Revenue impact in one paragraph
152
+ 2. **Revenue Impact Analysis** - Detailed breakdown per issue
153
+ 3. **Prioritized Fix Order** - Ranked by financial impact
154
+ 4. **What Not To Fix** - Issues below threshold
155
+ 5. **Decision Guidance** - Actionable recommendations
156
+
157
+ ## Library Usage
158
+
159
+ Can also be used programmatically:
160
+
161
+ ```typescript
162
+ import {
163
+ runAnalysis,
164
+ createGA4Adapter,
165
+ createDatadogAdapter,
166
+ } from '@perf-revenue/engine';
167
+
168
+ // Create adapters
169
+ const ga4 = createGA4Adapter({
170
+ projectId: 'my-project',
171
+ propertyId: '123456789',
172
+ });
173
+
174
+ const datadog = createDatadogAdapter({
175
+ site: 'datadoghq.com',
176
+ applicationId: 'rum-app-id',
177
+ });
178
+
179
+ // Fetch and analyze
180
+ const ga4Data = await fetchGA4Data(ga4);
181
+ const datadogData = await fetchDatadogData(datadog);
182
+ const result = runAnalysis(ga4Data, datadogData, siteTotals);
183
+ ```
184
+
185
+ ## Data Sources
186
+
187
+ ### GA4 (BigQuery Export)
188
+
189
+ - Sessions, conversions, revenue by page type + device
190
+ - Funnel drop-off analysis
191
+ - Conversion path journeys
192
+
193
+ ### Datadog RUM
194
+
195
+ - Core Web Vitals (LCP, INP, CLS) at p75
196
+ - Performance band distribution
197
+ - Frustration signals
198
+
199
+ ## Correlation
200
+
201
+ Data is joined on correlation keys:
202
+ - Date (YYYY-MM-DD)
203
+ - Page type (checkout, pdp, plp, etc.)
204
+ - Device category (mobile, desktop, tablet)
205
+
206
+ Join is **probabilistic** (aggregate dimensions), not deterministic.
207
+
208
+ ## Development
209
+
210
+ ```bash
211
+ # Install dependencies
212
+ npm install
213
+
214
+ # Build
215
+ npm run build
216
+
217
+ # Type check
218
+ npm run typecheck
219
+
220
+ # Run CLI locally
221
+ npm run cli -- analyze --client test -v
222
+ ```
223
+
224
+ ## Project Structure
225
+
226
+ ```
227
+ src/
228
+ ├── adapters/ # GA4 + Datadog data adapters
229
+ │ ├── ga4-adapter.ts
230
+ │ ├── datadog-adapter.ts
231
+ │ └── correlation-spec.ts
232
+ ├── engine/ # Core analysis logic
233
+ │ ├── orchestrator.ts
234
+ │ ├── assisted-attribution.ts
235
+ │ └── period-utils.ts
236
+ ├── schema/ # Type definitions
237
+ ├── cli/ # Autonomous CLI
238
+ │ ├── index.ts # Entry point
239
+ │ ├── agent.ts # Claude agent
240
+ │ ├── config.ts # Configuration
241
+ │ └── tools/ # Agent tools
242
+ └── prompts/ # System prompts
243
+ ```
244
+
245
+ ## License
246
+
247
+ MIT
248
+
249
+ ## Author
250
+
251
+ Kanmi Obasa <i@kanmiobasa.com>
@@ -0,0 +1,95 @@
1
+ /**
2
+ * Empirical Conversion Curve Builder
3
+ *
4
+ * Builds conversion rate curves from actual session data.
5
+ * This is the core differentiator from coefficient-based models:
6
+ * we measure CVR at each performance bucket from YOUR data.
7
+ *
8
+ * @author Kanmi Obasa <i@kanmiobasa.com>
9
+ */
10
+ import type { SessionData } from './datadog-session-query.js';
11
+ export interface ConversionBucket {
12
+ /** Bucket range (e.g., "0-1000" for 0-1s LCP) */
13
+ range: string;
14
+ /** Lower bound in ms */
15
+ lower_ms: number;
16
+ /** Upper bound in ms (Infinity for last bucket) */
17
+ upper_ms: number;
18
+ /** Number of sessions in this bucket */
19
+ sessions: number;
20
+ /** Number of conversions in this bucket */
21
+ conversions: number;
22
+ /** Measured conversion rate (conversions / sessions) */
23
+ conversion_rate: number;
24
+ /** Total revenue from conversions in this bucket */
25
+ revenue: number;
26
+ /** Average order value in this bucket */
27
+ aov: number;
28
+ /** Statistical confidence (based on sample size) */
29
+ confidence: 'high' | 'medium' | 'low';
30
+ }
31
+ export interface ConversionCurve {
32
+ /** The metric being measured (lcp, inp, cls) */
33
+ metric: 'lcp' | 'inp' | 'cls';
34
+ /** Buckets from fastest to slowest */
35
+ buckets: ConversionBucket[];
36
+ /** Summary statistics */
37
+ summary: {
38
+ total_sessions: number;
39
+ total_conversions: number;
40
+ overall_cvr: number;
41
+ total_revenue: number;
42
+ overall_aov: number;
43
+ /** CVR delta between fastest and slowest bucket */
44
+ cvr_range: number;
45
+ /** Relative CVR drop from fast to slow (e.g., 0.35 = 35% lower) */
46
+ relative_cvr_drop: number;
47
+ };
48
+ /** Core Web Vitals thresholds for reference */
49
+ thresholds: {
50
+ good: number;
51
+ needs_improvement: number;
52
+ };
53
+ }
54
+ export interface CurveBuilderConfig {
55
+ /** Custom bucket boundaries in ms. Default: CWV thresholds */
56
+ bucketBoundaries?: number[];
57
+ /** Minimum sessions per bucket for high confidence. Default: 100 */
58
+ minSessionsHighConfidence?: number;
59
+ /** Minimum sessions per bucket for medium confidence. Default: 30 */
60
+ minSessionsMediumConfidence?: number;
61
+ }
62
+ /**
63
+ * Build an empirical conversion curve from session data.
64
+ *
65
+ * This is the key function: it takes raw session data and produces
66
+ * a measured CVR at each performance bucket.
67
+ */
68
+ export declare function buildConversionCurve(sessions: SessionData[], metric: 'lcp' | 'inp' | 'cls', config?: CurveBuilderConfig): ConversionCurve;
69
+ /**
70
+ * Build curves for all CWV metrics at once.
71
+ */
72
+ export declare function buildAllCurves(sessions: SessionData[], config?: CurveBuilderConfig): {
73
+ lcp: ConversionCurve;
74
+ inp: ConversionCurve;
75
+ cls: ConversionCurve;
76
+ };
77
+ /**
78
+ * Build curves segmented by device or page type.
79
+ */
80
+ export declare function buildSegmentedCurves(sessions: SessionData[], segmentBy: 'device' | 'page_type', metric: 'lcp' | 'inp' | 'cls', config?: CurveBuilderConfig): Map<string, ConversionCurve>;
81
+ /**
82
+ * Find the inflection point where CVR starts dropping significantly.
83
+ */
84
+ export declare function findInflectionPoint(curve: ConversionCurve): {
85
+ bucket: ConversionBucket;
86
+ threshold_ms: number;
87
+ cvr_before: number;
88
+ cvr_after: number;
89
+ } | null;
90
+ /**
91
+ * Calculate the conversion rate at a specific metric value.
92
+ * Uses linear interpolation between buckets.
93
+ */
94
+ export declare function getCvrAtValue(curve: ConversionCurve, value: number): number;
95
+ //# sourceMappingURL=conversion-curve.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"conversion-curve.d.ts","sourceRoot":"","sources":["../../src/empirical/conversion-curve.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AAM9D,MAAM,WAAW,gBAAgB;IAC/B,iDAAiD;IACjD,KAAK,EAAE,MAAM,CAAC;IACd,wBAAwB;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB,mDAAmD;IACnD,QAAQ,EAAE,MAAM,CAAC;IACjB,wCAAwC;IACxC,QAAQ,EAAE,MAAM,CAAC;IACjB,2CAA2C;IAC3C,WAAW,EAAE,MAAM,CAAC;IACpB,wDAAwD;IACxD,eAAe,EAAE,MAAM,CAAC;IACxB,oDAAoD;IACpD,OAAO,EAAE,MAAM,CAAC;IAChB,yCAAyC;IACzC,GAAG,EAAE,MAAM,CAAC;IACZ,oDAAoD;IACpD,UAAU,EAAE,MAAM,GAAG,QAAQ,GAAG,KAAK,CAAC;CACvC;AAED,MAAM,WAAW,eAAe;IAC9B,gDAAgD;IAChD,MAAM,EAAE,KAAK,GAAG,KAAK,GAAG,KAAK,CAAC;IAC9B,sCAAsC;IACtC,OAAO,EAAE,gBAAgB,EAAE,CAAC;IAC5B,yBAAyB;IACzB,OAAO,EAAE;QACP,cAAc,EAAE,MAAM,CAAC;QACvB,iBAAiB,EAAE,MAAM,CAAC;QAC1B,WAAW,EAAE,MAAM,CAAC;QACpB,aAAa,EAAE,MAAM,CAAC;QACtB,WAAW,EAAE,MAAM,CAAC;QACpB,mDAAmD;QACnD,SAAS,EAAE,MAAM,CAAC;QAClB,mEAAmE;QACnE,iBAAiB,EAAE,MAAM,CAAC;KAC3B,CAAC;IACF,+CAA+C;IAC/C,UAAU,EAAE;QACV,IAAI,EAAE,MAAM,CAAC;QACb,iBAAiB,EAAE,MAAM,CAAC;KAC3B,CAAC;CACH;AAED,MAAM,WAAW,kBAAkB;IACjC,8DAA8D;IAC9D,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC5B,oEAAoE;IACpE,yBAAyB,CAAC,EAAE,MAAM,CAAC;IACnC,qEAAqE;IACrE,2BAA2B,CAAC,EAAE,MAAM,CAAC;CACtC;AAgBD;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,WAAW,EAAE,EACvB,MAAM,EAAE,KAAK,GAAG,KAAK,GAAG,KAAK,EAC7B,MAAM,GAAE,kBAAuB,GAC9B,eAAe,CA0GjB;AAED;;GAEG;AACH,wBAAgB,cAAc,CAC5B,QAAQ,EAAE,WAAW,EAAE,EACvB,MAAM,GAAE,kBAAuB,GAC9B;IAAE,GAAG,EAAE,eAAe,CAAC;IAAC,GAAG,EAAE,eAAe,CAAC;IAAC,GAAG,EAAE,eAAe,CAAA;CAAE,CAMtE;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,WAAW,EAAE,EACvB,SAAS,EAAE,QAAQ,GAAG,WAAW,EACjC,MAAM,EAAE,KAAK,GAAG,KAAK,GAAG,KAAK,EAC7B,MAAM,GAAE,kBAAuB,GAC9B,GAAG,CAAC,MAAM,EAAE,eAAe,CAAC,CAiB9B;AAMD;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,eAAe,GAAG;IAC3D,MAAM,EAAE,gBAAgB,CAAC;IACzB,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;CACnB,GAAG,IAAI,CA0CP;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,eAAe,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAS3E"}
@@ -0,0 +1,240 @@
1
+ /**
2
+ * Empirical Conversion Curve Builder
3
+ *
4
+ * Builds conversion rate curves from actual session data.
5
+ * This is the core differentiator from coefficient-based models:
6
+ * we measure CVR at each performance bucket from YOUR data.
7
+ *
8
+ * @author Kanmi Obasa <i@kanmiobasa.com>
9
+ */
10
+ // =============================================================================
11
+ // CWV THRESHOLDS
12
+ // =============================================================================
13
+ const CWV_THRESHOLDS = {
14
+ lcp: { good: 2500, needsImprovement: 4000 },
15
+ inp: { good: 200, needsImprovement: 500 },
16
+ cls: { good: 0.1, needsImprovement: 0.25 },
17
+ };
18
+ // =============================================================================
19
+ // CURVE BUILDER
20
+ // =============================================================================
21
+ /**
22
+ * Build an empirical conversion curve from session data.
23
+ *
24
+ * This is the key function: it takes raw session data and produces
25
+ * a measured CVR at each performance bucket.
26
+ */
27
+ export function buildConversionCurve(sessions, metric, config = {}) {
28
+ const { minSessionsHighConfidence = 100, minSessionsMediumConfidence = 30, } = config;
29
+ // Get metric value extractor
30
+ const getValue = getMetricExtractor(metric);
31
+ // Filter to sessions with the metric
32
+ const validSessions = sessions.filter((s) => getValue(s) !== null);
33
+ // Determine bucket boundaries
34
+ const boundaries = config.bucketBoundaries || getDefaultBoundaries(metric);
35
+ // Build buckets
36
+ const bucketMap = new Map();
37
+ for (const boundary of boundaries) {
38
+ bucketMap.set(boundary, { sessions: [] });
39
+ }
40
+ bucketMap.set(Infinity, { sessions: [] }); // Catch-all for > last boundary
41
+ // Assign sessions to buckets
42
+ for (const session of validSessions) {
43
+ const value = getValue(session);
44
+ const bucket = findBucket(value, boundaries);
45
+ bucketMap.get(bucket).sessions.push(session);
46
+ }
47
+ // Calculate stats for each bucket
48
+ const buckets = [];
49
+ const sortedBoundaries = [...boundaries, Infinity].sort((a, b) => a - b);
50
+ let prevBoundary = 0;
51
+ for (const boundary of sortedBoundaries) {
52
+ const bucketSessions = bucketMap.get(boundary)?.sessions || [];
53
+ if (bucketSessions.length === 0) {
54
+ prevBoundary = boundary;
55
+ continue;
56
+ }
57
+ const conversions = bucketSessions.filter((s) => s.has_purchase).length;
58
+ const revenue = bucketSessions.reduce((sum, s) => sum + s.purchase_value, 0);
59
+ const cvr = bucketSessions.length > 0 ? conversions / bucketSessions.length : 0;
60
+ const aov = conversions > 0 ? revenue / conversions : 0;
61
+ // Determine confidence based on sample size
62
+ let confidence = 'low';
63
+ if (bucketSessions.length >= minSessionsHighConfidence) {
64
+ confidence = 'high';
65
+ }
66
+ else if (bucketSessions.length >= minSessionsMediumConfidence) {
67
+ confidence = 'medium';
68
+ }
69
+ buckets.push({
70
+ range: formatRange(prevBoundary, boundary, metric),
71
+ lower_ms: prevBoundary,
72
+ upper_ms: boundary,
73
+ sessions: bucketSessions.length,
74
+ conversions,
75
+ conversion_rate: cvr,
76
+ revenue,
77
+ aov,
78
+ confidence,
79
+ });
80
+ prevBoundary = boundary;
81
+ }
82
+ // Calculate summary
83
+ const totalSessions = validSessions.length;
84
+ const totalConversions = validSessions.filter((s) => s.has_purchase).length;
85
+ const totalRevenue = validSessions.reduce((sum, s) => sum + s.purchase_value, 0);
86
+ const overallCvr = totalSessions > 0 ? totalConversions / totalSessions : 0;
87
+ const overallAov = totalConversions > 0 ? totalRevenue / totalConversions : 0;
88
+ // CVR range and relative drop
89
+ const fastestBucket = buckets[0];
90
+ const slowestBucket = buckets[buckets.length - 1];
91
+ const cvrRange = fastestBucket && slowestBucket
92
+ ? fastestBucket.conversion_rate - slowestBucket.conversion_rate
93
+ : 0;
94
+ const relativeCvrDrop = fastestBucket?.conversion_rate > 0
95
+ ? cvrRange / fastestBucket.conversion_rate
96
+ : 0;
97
+ return {
98
+ metric,
99
+ buckets,
100
+ summary: {
101
+ total_sessions: totalSessions,
102
+ total_conversions: totalConversions,
103
+ overall_cvr: overallCvr,
104
+ total_revenue: totalRevenue,
105
+ overall_aov: overallAov,
106
+ cvr_range: cvrRange,
107
+ relative_cvr_drop: relativeCvrDrop,
108
+ },
109
+ thresholds: {
110
+ good: CWV_THRESHOLDS[metric].good,
111
+ needs_improvement: CWV_THRESHOLDS[metric].needsImprovement,
112
+ },
113
+ };
114
+ }
115
+ /**
116
+ * Build curves for all CWV metrics at once.
117
+ */
118
+ export function buildAllCurves(sessions, config = {}) {
119
+ return {
120
+ lcp: buildConversionCurve(sessions, 'lcp', config),
121
+ inp: buildConversionCurve(sessions, 'inp', config),
122
+ cls: buildConversionCurve(sessions, 'cls', config),
123
+ };
124
+ }
125
+ /**
126
+ * Build curves segmented by device or page type.
127
+ */
128
+ export function buildSegmentedCurves(sessions, segmentBy, metric, config = {}) {
129
+ const segments = new Map();
130
+ for (const session of sessions) {
131
+ const key = segmentBy === 'device' ? session.device : session.page_type;
132
+ if (!segments.has(key)) {
133
+ segments.set(key, []);
134
+ }
135
+ segments.get(key).push(session);
136
+ }
137
+ const curves = new Map();
138
+ for (const [segmentName, segmentSessions] of segments) {
139
+ curves.set(segmentName, buildConversionCurve(segmentSessions, metric, config));
140
+ }
141
+ return curves;
142
+ }
143
+ // =============================================================================
144
+ // CURVE ANALYSIS
145
+ // =============================================================================
146
+ /**
147
+ * Find the inflection point where CVR starts dropping significantly.
148
+ */
149
+ export function findInflectionPoint(curve) {
150
+ if (curve.buckets.length < 2)
151
+ return null;
152
+ let maxDrop = 0;
153
+ let inflectionIndex = 0;
154
+ for (let i = 1; i < curve.buckets.length; i++) {
155
+ const prevBucket = curve.buckets[i - 1];
156
+ const currBucket = curve.buckets[i];
157
+ // Skip low-confidence buckets
158
+ if (prevBucket.confidence === 'low' || currBucket.confidence === 'low') {
159
+ continue;
160
+ }
161
+ const drop = prevBucket.conversion_rate - currBucket.conversion_rate;
162
+ if (drop > maxDrop) {
163
+ maxDrop = drop;
164
+ inflectionIndex = i;
165
+ }
166
+ }
167
+ if (maxDrop === 0)
168
+ return null;
169
+ const inflectionBucket = curve.buckets[inflectionIndex];
170
+ const prevBuckets = curve.buckets.slice(0, inflectionIndex);
171
+ const afterBuckets = curve.buckets.slice(inflectionIndex);
172
+ const cvrBefore = prevBuckets.reduce((sum, b) => sum + b.conversion_rate * b.sessions, 0) /
173
+ prevBuckets.reduce((sum, b) => sum + b.sessions, 0);
174
+ const cvrAfter = afterBuckets.reduce((sum, b) => sum + b.conversion_rate * b.sessions, 0) /
175
+ afterBuckets.reduce((sum, b) => sum + b.sessions, 0);
176
+ return {
177
+ bucket: inflectionBucket,
178
+ threshold_ms: inflectionBucket.lower_ms,
179
+ cvr_before: cvrBefore,
180
+ cvr_after: cvrAfter,
181
+ };
182
+ }
183
+ /**
184
+ * Calculate the conversion rate at a specific metric value.
185
+ * Uses linear interpolation between buckets.
186
+ */
187
+ export function getCvrAtValue(curve, value) {
188
+ for (const bucket of curve.buckets) {
189
+ if (value >= bucket.lower_ms && value < bucket.upper_ms) {
190
+ return bucket.conversion_rate;
191
+ }
192
+ }
193
+ // Value is beyond all buckets, return last bucket's CVR
194
+ return curve.buckets[curve.buckets.length - 1]?.conversion_rate || 0;
195
+ }
196
+ // =============================================================================
197
+ // HELPERS
198
+ // =============================================================================
199
+ function getMetricExtractor(metric) {
200
+ switch (metric) {
201
+ case 'lcp':
202
+ return (s) => s.lcp_ms;
203
+ case 'inp':
204
+ return (s) => s.inp_ms;
205
+ case 'cls':
206
+ return (s) => (s.cls !== null ? s.cls * 1000 : null); // Scale CLS to ms-like for bucketing
207
+ }
208
+ }
209
+ function getDefaultBoundaries(metric) {
210
+ switch (metric) {
211
+ case 'lcp':
212
+ // CWV thresholds + finer granularity
213
+ return [1000, 1500, 2000, 2500, 3000, 3500, 4000, 5000, 6000];
214
+ case 'inp':
215
+ return [50, 100, 150, 200, 300, 400, 500, 750];
216
+ case 'cls':
217
+ // CLS scaled by 1000 (so 0.1 = 100, 0.25 = 250)
218
+ return [25, 50, 75, 100, 150, 200, 250, 350];
219
+ }
220
+ }
221
+ function findBucket(value, boundaries) {
222
+ for (const boundary of boundaries.sort((a, b) => a - b)) {
223
+ if (value < boundary) {
224
+ return boundary;
225
+ }
226
+ }
227
+ return Infinity;
228
+ }
229
+ function formatRange(lower, upper, metric) {
230
+ if (metric === 'cls') {
231
+ // Convert back from scaled values
232
+ const lowerCls = (lower / 1000).toFixed(2);
233
+ const upperCls = upper === Infinity ? '∞' : (upper / 1000).toFixed(2);
234
+ return `${lowerCls}-${upperCls}`;
235
+ }
236
+ const lowerSec = (lower / 1000).toFixed(1);
237
+ const upperSec = upper === Infinity ? '∞' : (upper / 1000).toFixed(1);
238
+ return `${lowerSec}s-${upperSec}s`;
239
+ }
240
+ //# sourceMappingURL=conversion-curve.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"conversion-curve.js","sourceRoot":"","sources":["../../src/empirical/conversion-curve.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,59 @@
1
+ /**
2
+ * Data Import
3
+ *
4
+ * Import session data from CSV/JSON files.
5
+ * Bring your own data from any source.
6
+ *
7
+ * Expected format:
8
+ * - session_id: string
9
+ * - lcp_ms: number (optional)
10
+ * - inp_ms: number (optional)
11
+ * - cls: number (optional)
12
+ * - converted: boolean | 0 | 1
13
+ * - order_value: number (optional, defaults to 0)
14
+ * - device: 'mobile' | 'desktop' | 'tablet' (optional)
15
+ * - page_type: string (optional)
16
+ *
17
+ * @author Kanmi Obasa <i@kanmiobasa.com>
18
+ */
19
+ import type { QueryResult } from './datadog-session-query.js';
20
+ export interface RawSessionRow {
21
+ session_id?: string;
22
+ sessionId?: string;
23
+ id?: string;
24
+ lcp_ms?: number | string | null;
25
+ lcp?: number | string | null;
26
+ inp_ms?: number | string | null;
27
+ inp?: number | string | null;
28
+ cls?: number | string | null;
29
+ converted?: boolean | number | string;
30
+ has_purchase?: boolean | number | string;
31
+ purchased?: boolean | number | string;
32
+ order_value?: number | string;
33
+ purchase_value?: number | string;
34
+ revenue?: number | string;
35
+ value?: number | string;
36
+ device?: string;
37
+ device_type?: string;
38
+ page_type?: string;
39
+ page?: string;
40
+ timestamp?: string;
41
+ date?: string;
42
+ }
43
+ export interface ImportOptions {
44
+ startDate?: string;
45
+ endDate?: string;
46
+ }
47
+ /**
48
+ * Import sessions from a JSON file.
49
+ */
50
+ export declare function importFromJson(filePath: string, options?: ImportOptions): QueryResult;
51
+ /**
52
+ * Import sessions from a CSV file.
53
+ */
54
+ export declare function importFromCsv(filePath: string, options?: ImportOptions): QueryResult;
55
+ /**
56
+ * Import from file (auto-detect format).
57
+ */
58
+ export declare function importFromFile(filePath: string, options?: ImportOptions): QueryResult;
59
+ //# sourceMappingURL=data-import.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"data-import.d.ts","sourceRoot":"","sources":["../../src/empirical/data-import.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAGH,OAAO,KAAK,EAAe,WAAW,EAAE,MAAM,4BAA4B,CAAC;AAM3E,MAAM,WAAW,aAAa;IAC5B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;IAChC,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;IAC7B,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;IAChC,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;IAC7B,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;IAC7B,SAAS,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,MAAM,CAAC;IACtC,YAAY,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,MAAM,CAAC;IACzC,SAAS,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,MAAM,CAAC;IACtC,WAAW,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC9B,cAAc,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACjC,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC1B,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACxB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,aAAa;IAC5B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAMD;;GAEG;AACH,wBAAgB,cAAc,CAC5B,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,aAAkB,GAC1B,WAAW,CAQb;AAED;;GAEG;AACH,wBAAgB,aAAa,CAC3B,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,aAAkB,GAC1B,WAAW,CAwBb;AAED;;GAEG;AACH,wBAAgB,cAAc,CAC5B,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,aAAkB,GAC1B,WAAW,CAQb"}