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.
@@ -0,0 +1,186 @@
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 { readFileSync } from 'fs';
20
+ // =============================================================================
21
+ // IMPORT FUNCTIONS
22
+ // =============================================================================
23
+ /**
24
+ * Import sessions from a JSON file.
25
+ */
26
+ export function importFromJson(filePath, options = {}) {
27
+ const content = readFileSync(filePath, 'utf-8');
28
+ const raw = JSON.parse(content);
29
+ // Handle both array and object with data property
30
+ const rows = Array.isArray(raw) ? raw : raw.data || raw.sessions || [];
31
+ return processRows(rows, options);
32
+ }
33
+ /**
34
+ * Import sessions from a CSV file.
35
+ */
36
+ export function importFromCsv(filePath, options = {}) {
37
+ const content = readFileSync(filePath, 'utf-8');
38
+ const lines = content.trim().split('\n');
39
+ if (lines.length < 2) {
40
+ throw new Error('CSV must have header row and at least one data row');
41
+ }
42
+ const headers = parseCsvLine(lines[0]);
43
+ const rows = [];
44
+ for (let i = 1; i < lines.length; i++) {
45
+ const values = parseCsvLine(lines[i]);
46
+ const row = {};
47
+ headers.forEach((header, index) => {
48
+ const key = header.toLowerCase().trim().replace(/\s+/g, '_');
49
+ row[key] = values[index];
50
+ });
51
+ rows.push(row);
52
+ }
53
+ return processRows(rows, options);
54
+ }
55
+ /**
56
+ * Import from file (auto-detect format).
57
+ */
58
+ export function importFromFile(filePath, options = {}) {
59
+ if (filePath.endsWith('.json')) {
60
+ return importFromJson(filePath, options);
61
+ }
62
+ if (filePath.endsWith('.csv')) {
63
+ return importFromCsv(filePath, options);
64
+ }
65
+ throw new Error('Unsupported file format. Use .json or .csv');
66
+ }
67
+ // =============================================================================
68
+ // ROW PROCESSING
69
+ // =============================================================================
70
+ function processRows(rows, options) {
71
+ const startTime = Date.now();
72
+ const sessions = [];
73
+ for (const row of rows) {
74
+ const session = normalizeRow(row);
75
+ if (session) {
76
+ sessions.push(session);
77
+ }
78
+ }
79
+ // Determine period
80
+ const timestamps = sessions
81
+ .map((s) => s.timestamp)
82
+ .filter((t) => t)
83
+ .sort();
84
+ const start = options.startDate || timestamps[0]?.split('T')[0] || new Date().toISOString().split('T')[0];
85
+ const end = options.endDate || timestamps[timestamps.length - 1]?.split('T')[0] || new Date().toISOString().split('T')[0];
86
+ const startDate = new Date(start);
87
+ const endDate = new Date(end);
88
+ const days = Math.max(1, Math.ceil((endDate.getTime() - startDate.getTime()) / (1000 * 60 * 60 * 24)) + 1);
89
+ return {
90
+ sessions,
91
+ metadata: {
92
+ total_sessions: sessions.length,
93
+ sessions_with_lcp: sessions.filter((s) => s.lcp_ms !== null).length,
94
+ sessions_with_conversions: sessions.filter((s) => s.has_purchase).length,
95
+ query_time_ms: Date.now() - startTime,
96
+ period: { start, end, days },
97
+ },
98
+ };
99
+ }
100
+ function normalizeRow(row) {
101
+ // Get session ID
102
+ const sessionId = row.session_id || row.sessionId || row.id;
103
+ if (!sessionId)
104
+ return null;
105
+ // Parse LCP
106
+ const lcpRaw = row.lcp_ms ?? row.lcp;
107
+ const lcp = parseNumber(lcpRaw);
108
+ // Parse INP
109
+ const inpRaw = row.inp_ms ?? row.inp;
110
+ const inp = parseNumber(inpRaw);
111
+ // Parse CLS
112
+ const cls = parseNumber(row.cls);
113
+ // Parse conversion
114
+ const convertedRaw = row.converted ?? row.has_purchase ?? row.purchased;
115
+ const converted = parseBoolean(convertedRaw);
116
+ // Parse order value
117
+ const valueRaw = row.order_value ?? row.purchase_value ?? row.revenue ?? row.value;
118
+ const orderValue = converted ? (parseNumber(valueRaw) || 0) : 0;
119
+ // Parse device
120
+ const deviceRaw = row.device || row.device_type || 'desktop';
121
+ const device = normalizeDevice(deviceRaw);
122
+ // Parse page type
123
+ const pageType = row.page_type || row.page || 'unknown';
124
+ // Parse timestamp
125
+ const timestamp = row.timestamp || row.date || new Date().toISOString();
126
+ return {
127
+ session_id: String(sessionId),
128
+ lcp_ms: lcp,
129
+ inp_ms: inp,
130
+ cls,
131
+ has_purchase: converted,
132
+ purchase_value: orderValue,
133
+ device,
134
+ page_type: pageType,
135
+ timestamp,
136
+ };
137
+ }
138
+ // =============================================================================
139
+ // HELPERS
140
+ // =============================================================================
141
+ function parseNumber(value) {
142
+ if (value === null || value === undefined || value === '')
143
+ return null;
144
+ const num = Number(value);
145
+ return isNaN(num) ? null : num;
146
+ }
147
+ function parseBoolean(value) {
148
+ if (typeof value === 'boolean')
149
+ return value;
150
+ if (typeof value === 'number')
151
+ return value !== 0;
152
+ if (typeof value === 'string') {
153
+ const lower = value.toLowerCase().trim();
154
+ return lower === 'true' || lower === '1' || lower === 'yes';
155
+ }
156
+ return false;
157
+ }
158
+ function normalizeDevice(value) {
159
+ const lower = value.toLowerCase();
160
+ if (lower.includes('mobile') || lower.includes('phone'))
161
+ return 'mobile';
162
+ if (lower.includes('tablet') || lower.includes('ipad'))
163
+ return 'tablet';
164
+ return 'desktop';
165
+ }
166
+ function parseCsvLine(line) {
167
+ const result = [];
168
+ let current = '';
169
+ let inQuotes = false;
170
+ for (let i = 0; i < line.length; i++) {
171
+ const char = line[i];
172
+ if (char === '"') {
173
+ inQuotes = !inQuotes;
174
+ }
175
+ else if (char === ',' && !inQuotes) {
176
+ result.push(current.trim());
177
+ current = '';
178
+ }
179
+ else {
180
+ current += char;
181
+ }
182
+ }
183
+ result.push(current.trim());
184
+ return result;
185
+ }
186
+ //# sourceMappingURL=data-import.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"data-import.js","sourceRoot":"","sources":["../../src/empirical/data-import.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,66 @@
1
+ /**
2
+ * Datadog Session Query
3
+ *
4
+ * Queries Datadog RUM for session-level data with Core Web Vitals AND conversion outcomes.
5
+ * This is the foundation for building empirical conversion curves.
6
+ *
7
+ * Prerequisites:
8
+ * - Datadog RUM installed with session tracking
9
+ * - Conversion actions tracked: datadogRum.addAction('purchase', { value: orderTotal })
10
+ *
11
+ * @author Kanmi Obasa <i@kanmiobasa.com>
12
+ */
13
+ export interface SessionData {
14
+ session_id: string;
15
+ lcp_ms: number | null;
16
+ inp_ms: number | null;
17
+ cls: number | null;
18
+ has_purchase: boolean;
19
+ purchase_value: number;
20
+ device: 'mobile' | 'desktop' | 'tablet';
21
+ page_type: string;
22
+ timestamp: string;
23
+ }
24
+ export interface DatadogQueryConfig {
25
+ apiKey: string;
26
+ appKey: string;
27
+ site?: string;
28
+ startDate: string;
29
+ endDate: string;
30
+ pageTypes?: string[];
31
+ devices?: ('mobile' | 'desktop' | 'tablet')[];
32
+ purchaseActionName?: string;
33
+ }
34
+ export interface QueryResult {
35
+ sessions: SessionData[];
36
+ metadata: {
37
+ total_sessions: number;
38
+ sessions_with_lcp: number;
39
+ sessions_with_conversions: number;
40
+ query_time_ms: number;
41
+ period: {
42
+ start: string;
43
+ end: string;
44
+ days: number;
45
+ };
46
+ };
47
+ }
48
+ /**
49
+ * Query Datadog RUM for session-level data.
50
+ *
51
+ * Note: This uses the Datadog RUM Events API. In production, you'd want to
52
+ * use the RUM Analytics API for aggregations or export to a data warehouse.
53
+ */
54
+ export declare function queryDatadogSessions(config: DatadogQueryConfig): Promise<QueryResult>;
55
+ /**
56
+ * Generate mock session data for testing without Datadog credentials.
57
+ * Models realistic e-commerce conversion patterns.
58
+ */
59
+ export declare function generateMockSessions(options: {
60
+ count: number;
61
+ startDate: string;
62
+ endDate: string;
63
+ baseConversionRate?: number;
64
+ lcpConversionImpact?: number;
65
+ }): QueryResult;
66
+ //# sourceMappingURL=datadog-session-query.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"datadog-session-query.d.ts","sourceRoot":"","sources":["../../src/empirical/datadog-session-query.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAMH,MAAM,WAAW,WAAW;IAC1B,UAAU,EAAE,MAAM,CAAC;IAEnB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IAEnB,YAAY,EAAE,OAAO,CAAC;IACtB,cAAc,EAAE,MAAM,CAAC;IAEvB,MAAM,EAAE,QAAQ,GAAG,SAAS,GAAG,QAAQ,CAAC;IACxC,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB,OAAO,CAAC,EAAE,CAAC,QAAQ,GAAG,SAAS,GAAG,QAAQ,CAAC,EAAE,CAAC;IAC9C,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,WAAW,EAAE,CAAC;IACxB,QAAQ,EAAE;QACR,cAAc,EAAE,MAAM,CAAC;QACvB,iBAAiB,EAAE,MAAM,CAAC;QAC1B,yBAAyB,EAAE,MAAM,CAAC;QAClC,aAAa,EAAE,MAAM,CAAC;QACtB,MAAM,EAAE;YAAE,KAAK,EAAE,MAAM,CAAC;YAAC,GAAG,EAAE,MAAM,CAAC;YAAC,IAAI,EAAE,MAAM,CAAA;SAAE,CAAC;KACtD,CAAC;CACH;AAMD;;;;;GAKG;AACH,wBAAsB,oBAAoB,CACxC,MAAM,EAAE,kBAAkB,GACzB,OAAO,CAAC,WAAW,CAAC,CAuItB;AAMD;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE;IAC5C,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,mBAAmB,CAAC,EAAE,MAAM,CAAC;CAC9B,GAAG,WAAW,CAsEd"}
@@ -0,0 +1,260 @@
1
+ /**
2
+ * Datadog Session Query
3
+ *
4
+ * Queries Datadog RUM for session-level data with Core Web Vitals AND conversion outcomes.
5
+ * This is the foundation for building empirical conversion curves.
6
+ *
7
+ * Prerequisites:
8
+ * - Datadog RUM installed with session tracking
9
+ * - Conversion actions tracked: datadogRum.addAction('purchase', { value: orderTotal })
10
+ *
11
+ * @author Kanmi Obasa <i@kanmiobasa.com>
12
+ */
13
+ // =============================================================================
14
+ // DATADOG RUM API QUERY
15
+ // =============================================================================
16
+ /**
17
+ * Query Datadog RUM for session-level data.
18
+ *
19
+ * Note: This uses the Datadog RUM Events API. In production, you'd want to
20
+ * use the RUM Analytics API for aggregations or export to a data warehouse.
21
+ */
22
+ export async function queryDatadogSessions(config) {
23
+ const startTime = Date.now();
24
+ const site = config.site || 'datadoghq.com';
25
+ const purchaseAction = config.purchaseActionName || 'purchase';
26
+ // Build the query filter
27
+ const filters = [
28
+ `@type:session`,
29
+ `@session.time_spent:>0`,
30
+ ];
31
+ if (config.pageTypes?.length) {
32
+ filters.push(`@view.url_path:(${config.pageTypes.join(' OR ')})`);
33
+ }
34
+ if (config.devices?.length) {
35
+ filters.push(`@device.type:(${config.devices.join(' OR ')})`);
36
+ }
37
+ // Query sessions with their LCP, INP, CLS values
38
+ const response = await fetch(`https://api.${site}/api/v2/rum/events/search`, {
39
+ method: 'POST',
40
+ headers: {
41
+ 'Content-Type': 'application/json',
42
+ 'DD-API-KEY': config.apiKey,
43
+ 'DD-APPLICATION-KEY': config.appKey,
44
+ },
45
+ body: JSON.stringify({
46
+ filter: {
47
+ query: filters.join(' '),
48
+ from: `${config.startDate}T00:00:00Z`,
49
+ to: `${config.endDate}T23:59:59Z`,
50
+ },
51
+ page: {
52
+ limit: 10000, // Datadog max per request
53
+ },
54
+ sort: '-timestamp',
55
+ }),
56
+ });
57
+ if (!response.ok) {
58
+ const error = await response.text();
59
+ throw new Error(`Datadog API error: ${response.status} - ${error}`);
60
+ }
61
+ const data = await response.json();
62
+ // Transform Datadog events to our session format
63
+ const sessions = [];
64
+ const sessionMap = new Map();
65
+ for (const event of data.data || []) {
66
+ const attrs = event.attributes;
67
+ const sessionId = attrs.session?.id;
68
+ if (!sessionId)
69
+ continue;
70
+ // Get or create session entry
71
+ let session = sessionMap.get(sessionId);
72
+ if (!session) {
73
+ session = {
74
+ session_id: sessionId,
75
+ lcp_ms: null,
76
+ inp_ms: null,
77
+ cls: null,
78
+ has_purchase: false,
79
+ purchase_value: 0,
80
+ device: normalizeDevice(attrs.device?.type),
81
+ page_type: extractPageType(attrs.view?.url_path),
82
+ timestamp: attrs['@timestamp'] || attrs.date,
83
+ };
84
+ sessionMap.set(sessionId, session);
85
+ }
86
+ // Update CWV if present (take worst/highest values)
87
+ if (attrs.view?.largest_contentful_paint != null) {
88
+ session.lcp_ms = Math.max(session.lcp_ms || 0, attrs.view.largest_contentful_paint);
89
+ }
90
+ if (attrs.view?.interaction_to_next_paint != null) {
91
+ session.inp_ms = Math.max(session.inp_ms || 0, attrs.view.interaction_to_next_paint);
92
+ }
93
+ if (attrs.view?.cumulative_layout_shift != null) {
94
+ session.cls = Math.max(session.cls || 0, attrs.view.cumulative_layout_shift);
95
+ }
96
+ // Check for purchase action
97
+ if (attrs.action?.type === 'custom' &&
98
+ attrs.action?.name === purchaseAction) {
99
+ session.has_purchase = true;
100
+ session.purchase_value += attrs.action?.custom?.value || 0;
101
+ }
102
+ }
103
+ sessions.push(...sessionMap.values());
104
+ // Calculate metadata
105
+ const sessionsWithLcp = sessions.filter((s) => s.lcp_ms !== null).length;
106
+ const sessionsWithConversions = sessions.filter((s) => s.has_purchase).length;
107
+ const startDate = new Date(config.startDate);
108
+ const endDate = new Date(config.endDate);
109
+ const days = Math.ceil((endDate.getTime() - startDate.getTime()) / (1000 * 60 * 60 * 24)) + 1;
110
+ return {
111
+ sessions,
112
+ metadata: {
113
+ total_sessions: sessions.length,
114
+ sessions_with_lcp: sessionsWithLcp,
115
+ sessions_with_conversions: sessionsWithConversions,
116
+ query_time_ms: Date.now() - startTime,
117
+ period: {
118
+ start: config.startDate,
119
+ end: config.endDate,
120
+ days,
121
+ },
122
+ },
123
+ };
124
+ }
125
+ // =============================================================================
126
+ // MOCK DATA FOR TESTING
127
+ // =============================================================================
128
+ /**
129
+ * Generate mock session data for testing without Datadog credentials.
130
+ * Models realistic e-commerce conversion patterns.
131
+ */
132
+ export function generateMockSessions(options) {
133
+ const startTime = Date.now();
134
+ const { count, startDate, endDate, baseConversionRate = 0.03, lcpConversionImpact = 0.85, } = options;
135
+ const sessions = [];
136
+ for (let i = 0; i < count; i++) {
137
+ // Generate realistic LCP distribution (log-normal)
138
+ const lcp = generateLogNormalLcp();
139
+ const inp = generateLogNormalInp();
140
+ const cls = generateCls();
141
+ // Calculate conversion probability based on LCP
142
+ // Empirical model: CVR drops as LCP increases
143
+ const lcpSeconds = lcp / 1000;
144
+ const lcpPenalty = Math.pow(lcpConversionImpact, Math.max(0, lcpSeconds - 1));
145
+ const conversionProbability = baseConversionRate * lcpPenalty;
146
+ const hasPurchase = Math.random() < conversionProbability;
147
+ const purchaseValue = hasPurchase ? generateOrderValue() : 0;
148
+ const device = weightedRandom([
149
+ { value: 'mobile', weight: 0.65 },
150
+ { value: 'desktop', weight: 0.30 },
151
+ { value: 'tablet', weight: 0.05 },
152
+ ]);
153
+ const pageType = weightedRandom([
154
+ { value: 'pdp', weight: 0.40 },
155
+ { value: 'plp', weight: 0.30 },
156
+ { value: 'checkout', weight: 0.15 },
157
+ { value: 'homepage', weight: 0.15 },
158
+ ]);
159
+ sessions.push({
160
+ session_id: `mock-${i}-${Date.now()}`,
161
+ lcp_ms: lcp,
162
+ inp_ms: inp,
163
+ cls,
164
+ has_purchase: hasPurchase,
165
+ purchase_value: purchaseValue,
166
+ device,
167
+ page_type: pageType,
168
+ timestamp: generateRandomTimestamp(startDate, endDate),
169
+ });
170
+ }
171
+ const sessionsWithLcp = sessions.filter((s) => s.lcp_ms !== null).length;
172
+ const sessionsWithConversions = sessions.filter((s) => s.has_purchase).length;
173
+ const start = new Date(startDate);
174
+ const end = new Date(endDate);
175
+ const days = Math.ceil((end.getTime() - start.getTime()) / (1000 * 60 * 60 * 24)) + 1;
176
+ return {
177
+ sessions,
178
+ metadata: {
179
+ total_sessions: sessions.length,
180
+ sessions_with_lcp: sessionsWithLcp,
181
+ sessions_with_conversions: sessionsWithConversions,
182
+ query_time_ms: Date.now() - startTime,
183
+ period: { start: startDate, end: endDate, days },
184
+ },
185
+ };
186
+ }
187
+ // =============================================================================
188
+ // HELPERS
189
+ // =============================================================================
190
+ function normalizeDevice(type) {
191
+ if (!type)
192
+ return 'desktop';
193
+ const normalized = type.toLowerCase();
194
+ if (normalized.includes('mobile') || normalized.includes('phone'))
195
+ return 'mobile';
196
+ if (normalized.includes('tablet') || normalized.includes('ipad'))
197
+ return 'tablet';
198
+ return 'desktop';
199
+ }
200
+ function extractPageType(urlPath) {
201
+ if (!urlPath)
202
+ return 'unknown';
203
+ const path = urlPath.toLowerCase();
204
+ if (path.includes('/product/') || path.includes('/p/'))
205
+ return 'pdp';
206
+ if (path.includes('/category/') || path.includes('/c/') || path.includes('/shop/'))
207
+ return 'plp';
208
+ if (path.includes('/checkout') || path.includes('/cart'))
209
+ return 'checkout';
210
+ if (path === '/' || path.includes('/home'))
211
+ return 'homepage';
212
+ return 'other';
213
+ }
214
+ function generateLogNormalLcp() {
215
+ // Log-normal distribution centered around 2.5s with variance
216
+ const mu = Math.log(2500);
217
+ const sigma = 0.5;
218
+ const u1 = Math.random();
219
+ const u2 = Math.random();
220
+ const z = Math.sqrt(-2 * Math.log(u1)) * Math.cos(2 * Math.PI * u2);
221
+ return Math.round(Math.exp(mu + sigma * z));
222
+ }
223
+ function generateLogNormalInp() {
224
+ // INP centered around 150ms
225
+ const mu = Math.log(150);
226
+ const sigma = 0.6;
227
+ const u1 = Math.random();
228
+ const u2 = Math.random();
229
+ const z = Math.sqrt(-2 * Math.log(u1)) * Math.cos(2 * Math.PI * u2);
230
+ return Math.round(Math.exp(mu + sigma * z));
231
+ }
232
+ function generateCls() {
233
+ // CLS: most are low, some are high
234
+ const base = Math.random() * 0.1;
235
+ const spike = Math.random() < 0.1 ? Math.random() * 0.3 : 0;
236
+ return Math.round((base + spike) * 1000) / 1000;
237
+ }
238
+ function generateOrderValue() {
239
+ // Typical e-commerce AOV distribution
240
+ const base = 50 + Math.random() * 100;
241
+ const highValue = Math.random() < 0.1 ? Math.random() * 300 : 0;
242
+ return Math.round((base + highValue) * 100) / 100;
243
+ }
244
+ function weightedRandom(options) {
245
+ const total = options.reduce((sum, opt) => sum + opt.weight, 0);
246
+ let random = Math.random() * total;
247
+ for (const opt of options) {
248
+ random -= opt.weight;
249
+ if (random <= 0)
250
+ return opt.value;
251
+ }
252
+ return options[0].value;
253
+ }
254
+ function generateRandomTimestamp(start, end) {
255
+ const startMs = new Date(start).getTime();
256
+ const endMs = new Date(end).getTime();
257
+ const randomMs = startMs + Math.random() * (endMs - startMs);
258
+ return new Date(randomMs).toISOString();
259
+ }
260
+ //# sourceMappingURL=datadog-session-query.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"datadog-session-query.js","sourceRoot":"","sources":["../../src/empirical/datadog-session-query.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,109 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Empirical Performance Revenue Engine
4
+ *
5
+ * A simpler, more transparent approach to performance-revenue analysis.
6
+ * Uses actual session-level data to build empirical conversion curves.
7
+ *
8
+ * Key differences from coefficient-based models:
9
+ * - No assumed "0.5% CVR per 100ms LCP" coefficients
10
+ * - Measures actual CVR at each performance bucket from YOUR data
11
+ * - More honest about what we know vs. assume
12
+ *
13
+ * Usage:
14
+ * // With Datadog credentials
15
+ * const result = await analyzeWithDatadog({
16
+ * apiKey: 'xxx',
17
+ * appKey: 'xxx',
18
+ * startDate: '2024-01-01',
19
+ * endDate: '2024-01-14',
20
+ * });
21
+ *
22
+ * // With mock data (for testing)
23
+ * const result = analyzeWithMockData({
24
+ * sessionCount: 50000,
25
+ * startDate: '2024-01-01',
26
+ * endDate: '2024-01-14',
27
+ * });
28
+ *
29
+ * @author Kanmi Obasa <i@kanmiobasa.com>
30
+ */
31
+ import { type DatadogQueryConfig } from './datadog-session-query.js';
32
+ import { type ConversionCurve } from './conversion-curve.js';
33
+ import { type OpportunityReport } from './opportunity-calculator.js';
34
+ export interface AnalysisResult {
35
+ /** Empirical conversion curves */
36
+ curves: {
37
+ lcp: ConversionCurve;
38
+ inp: ConversionCurve;
39
+ cls: ConversionCurve;
40
+ };
41
+ /** Revenue opportunity analysis */
42
+ opportunities: {
43
+ lcp: OpportunityReport;
44
+ inp: OpportunityReport;
45
+ cls: OpportunityReport;
46
+ };
47
+ /** The single highest-impact opportunity */
48
+ topOpportunity: {
49
+ metric: 'lcp' | 'inp' | 'cls';
50
+ monthlyRevenue: number;
51
+ summary: string;
52
+ } | null;
53
+ /** Generated markdown report */
54
+ report: string;
55
+ /** Query metadata */
56
+ metadata: {
57
+ totalSessions: number;
58
+ sessionsWithLcp: number;
59
+ sessionsWithConversions: number;
60
+ period: {
61
+ start: string;
62
+ end: string;
63
+ days: number;
64
+ };
65
+ };
66
+ }
67
+ export interface DatadogAnalysisOptions extends DatadogQueryConfig {
68
+ clientName?: string;
69
+ }
70
+ export interface MockAnalysisOptions {
71
+ sessionCount: number;
72
+ startDate: string;
73
+ endDate: string;
74
+ clientName?: string;
75
+ baseConversionRate?: number;
76
+ }
77
+ export interface FileAnalysisOptions {
78
+ filePath: string;
79
+ clientName?: string;
80
+ startDate?: string;
81
+ endDate?: string;
82
+ }
83
+ /**
84
+ * Run full analysis using Datadog RUM data.
85
+ */
86
+ export declare function analyzeWithDatadog(options: DatadogAnalysisOptions): Promise<AnalysisResult>;
87
+ /**
88
+ * Run analysis with mock data (for testing/demo).
89
+ */
90
+ export declare function analyzeWithMockData(options: MockAnalysisOptions): AnalysisResult;
91
+ /**
92
+ * Run analysis from CSV or JSON file.
93
+ * Bring your own data from any source.
94
+ */
95
+ export declare function analyzeFromFile(options: FileAnalysisOptions): AnalysisResult;
96
+ /**
97
+ * CLI entry point.
98
+ */
99
+ export declare function main(): Promise<void>;
100
+ export type { SessionData, DatadogQueryConfig, QueryResult } from './datadog-session-query.js';
101
+ export type { ConversionCurve, ConversionBucket, CurveBuilderConfig } from './conversion-curve.js';
102
+ export type { OpportunityReport, OpportunityScenario, OpportunityConfig } from './opportunity-calculator.js';
103
+ export type { ReportConfig, FullReport } from './report.js';
104
+ export { queryDatadogSessions, generateMockSessions } from './datadog-session-query.js';
105
+ export { buildConversionCurve, buildAllCurves, buildSegmentedCurves } from './conversion-curve.js';
106
+ export { calculateOpportunity, calculateAllOpportunities, getTopOpportunity } from './opportunity-calculator.js';
107
+ export { generateReport } from './report.js';
108
+ export { importFromFile, importFromCsv, importFromJson } from './data-import.js';
109
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/empirical/index.ts"],"names":[],"mappings":"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"}