@contractspec/lib.analytics 1.56.1 → 1.58.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/browser/churn/index.js +77 -0
- package/dist/browser/churn/predictor.js +77 -0
- package/dist/browser/cohort/index.js +117 -0
- package/dist/browser/cohort/tracker.js +117 -0
- package/dist/browser/funnel/analyzer.js +68 -0
- package/dist/browser/funnel/index.js +68 -0
- package/dist/browser/growth/hypothesis-generator.js +46 -0
- package/dist/browser/growth/index.js +46 -0
- package/dist/browser/index.js +723 -0
- package/dist/browser/lifecycle/index.js +287 -0
- package/dist/browser/lifecycle/metric-collectors.js +58 -0
- package/dist/browser/lifecycle/posthog-bridge.js +79 -0
- package/dist/browser/lifecycle/posthog-metric-source.js +205 -0
- package/dist/browser/posthog/event-source.js +138 -0
- package/dist/browser/posthog/index.js +138 -0
- package/dist/browser/types.js +0 -0
- package/dist/churn/index.d.ts +2 -2
- package/dist/churn/index.d.ts.map +1 -0
- package/dist/churn/index.js +77 -2
- package/dist/churn/predictor.d.ts +15 -19
- package/dist/churn/predictor.d.ts.map +1 -1
- package/dist/churn/predictor.js +72 -68
- package/dist/cohort/index.d.ts +2 -2
- package/dist/cohort/index.d.ts.map +1 -0
- package/dist/cohort/index.js +117 -2
- package/dist/cohort/tracker.d.ts +3 -7
- package/dist/cohort/tracker.d.ts.map +1 -1
- package/dist/cohort/tracker.js +106 -90
- package/dist/funnel/analyzer.d.ts +4 -8
- package/dist/funnel/analyzer.d.ts.map +1 -1
- package/dist/funnel/analyzer.js +67 -62
- package/dist/funnel/index.d.ts +2 -2
- package/dist/funnel/index.d.ts.map +1 -0
- package/dist/funnel/index.js +69 -3
- package/dist/growth/hypothesis-generator.d.ts +11 -15
- package/dist/growth/hypothesis-generator.d.ts.map +1 -1
- package/dist/growth/hypothesis-generator.js +46 -39
- package/dist/growth/index.d.ts +2 -2
- package/dist/growth/index.d.ts.map +1 -0
- package/dist/growth/index.js +47 -3
- package/dist/index.d.ts +8 -8
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +724 -10
- package/dist/lifecycle/index.d.ts +4 -3
- package/dist/lifecycle/index.d.ts.map +1 -0
- package/dist/lifecycle/index.js +287 -3
- package/dist/lifecycle/metric-collectors.d.ts +22 -26
- package/dist/lifecycle/metric-collectors.d.ts.map +1 -1
- package/dist/lifecycle/metric-collectors.js +55 -44
- package/dist/lifecycle/posthog-bridge.d.ts +9 -13
- package/dist/lifecycle/posthog-bridge.d.ts.map +1 -1
- package/dist/lifecycle/posthog-bridge.js +77 -25
- package/dist/lifecycle/posthog-metric-source.d.ts +43 -0
- package/dist/lifecycle/posthog-metric-source.d.ts.map +1 -0
- package/dist/lifecycle/posthog-metric-source.js +206 -0
- package/dist/node/churn/index.js +77 -0
- package/dist/node/churn/predictor.js +77 -0
- package/dist/node/cohort/index.js +117 -0
- package/dist/node/cohort/tracker.js +117 -0
- package/dist/node/funnel/analyzer.js +68 -0
- package/dist/node/funnel/index.js +68 -0
- package/dist/node/growth/hypothesis-generator.js +46 -0
- package/dist/node/growth/index.js +46 -0
- package/dist/node/index.js +723 -0
- package/dist/node/lifecycle/index.js +287 -0
- package/dist/node/lifecycle/metric-collectors.js +58 -0
- package/dist/node/lifecycle/posthog-bridge.js +79 -0
- package/dist/node/lifecycle/posthog-metric-source.js +205 -0
- package/dist/node/posthog/event-source.js +138 -0
- package/dist/node/posthog/index.js +138 -0
- package/dist/node/types.js +0 -0
- package/dist/posthog/event-source.d.ts +21 -0
- package/dist/posthog/event-source.d.ts.map +1 -0
- package/dist/posthog/event-source.js +139 -0
- package/dist/posthog/index.d.ts +2 -0
- package/dist/posthog/index.d.ts.map +1 -0
- package/dist/posthog/index.js +139 -0
- package/dist/types.d.ts +52 -55
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +1 -0
- package/package.json +189 -39
- package/dist/churn/predictor.js.map +0 -1
- package/dist/cohort/tracker.js.map +0 -1
- package/dist/funnel/analyzer.js.map +0 -1
- package/dist/growth/hypothesis-generator.js.map +0 -1
- package/dist/lifecycle/metric-collectors.js.map +0 -1
- package/dist/lifecycle/posthog-bridge.js.map +0 -1
package/dist/types.d.ts
CHANGED
|
@@ -1,68 +1,65 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
properties?: Record<string, unknown>;
|
|
1
|
+
export interface AnalyticsEvent {
|
|
2
|
+
name: string;
|
|
3
|
+
userId: string;
|
|
4
|
+
tenantId?: string;
|
|
5
|
+
timestamp: string | Date;
|
|
6
|
+
properties?: Record<string, unknown>;
|
|
8
7
|
}
|
|
9
|
-
interface FunnelStep {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
8
|
+
export interface FunnelStep {
|
|
9
|
+
id: string;
|
|
10
|
+
eventName: string;
|
|
11
|
+
match?: (event: AnalyticsEvent) => boolean;
|
|
13
12
|
}
|
|
14
|
-
interface FunnelDefinition {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
13
|
+
export interface FunnelDefinition {
|
|
14
|
+
name: string;
|
|
15
|
+
steps: FunnelStep[];
|
|
16
|
+
windowHours?: number;
|
|
18
17
|
}
|
|
19
|
-
interface FunnelStepResult {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
18
|
+
export interface FunnelStepResult {
|
|
19
|
+
step: FunnelStep;
|
|
20
|
+
count: number;
|
|
21
|
+
conversionRate: number;
|
|
22
|
+
dropOffRate: number;
|
|
24
23
|
}
|
|
25
|
-
interface FunnelAnalysis {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
24
|
+
export interface FunnelAnalysis {
|
|
25
|
+
definition: FunnelDefinition;
|
|
26
|
+
totalUsers: number;
|
|
27
|
+
steps: FunnelStepResult[];
|
|
29
28
|
}
|
|
30
|
-
interface CohortEvent extends AnalyticsEvent {
|
|
31
|
-
|
|
29
|
+
export interface CohortEvent extends AnalyticsEvent {
|
|
30
|
+
amount?: number;
|
|
32
31
|
}
|
|
33
|
-
interface CohortDefinition {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
32
|
+
export interface CohortDefinition {
|
|
33
|
+
bucket: 'day' | 'week' | 'month';
|
|
34
|
+
periods: number;
|
|
35
|
+
startDate?: Date;
|
|
37
36
|
}
|
|
38
|
-
interface CohortStats {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
37
|
+
export interface CohortStats {
|
|
38
|
+
cohortKey: string;
|
|
39
|
+
users: number;
|
|
40
|
+
retention: number[];
|
|
41
|
+
ltv: number;
|
|
43
42
|
}
|
|
44
|
-
interface CohortAnalysis {
|
|
45
|
-
|
|
46
|
-
|
|
43
|
+
export interface CohortAnalysis {
|
|
44
|
+
definition: CohortDefinition;
|
|
45
|
+
cohorts: CohortStats[];
|
|
47
46
|
}
|
|
48
|
-
interface ChurnSignal {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
47
|
+
export interface ChurnSignal {
|
|
48
|
+
userId: string;
|
|
49
|
+
score: number;
|
|
50
|
+
bucket: 'low' | 'medium' | 'high';
|
|
51
|
+
drivers: string[];
|
|
53
52
|
}
|
|
54
|
-
interface GrowthMetric {
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
53
|
+
export interface GrowthMetric {
|
|
54
|
+
name: string;
|
|
55
|
+
current: number;
|
|
56
|
+
previous?: number;
|
|
57
|
+
target?: number;
|
|
59
58
|
}
|
|
60
|
-
interface GrowthHypothesis {
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
59
|
+
export interface GrowthHypothesis {
|
|
60
|
+
statement: string;
|
|
61
|
+
metric: string;
|
|
62
|
+
confidence: 'low' | 'medium' | 'high';
|
|
63
|
+
impact: 'low' | 'medium' | 'high';
|
|
65
64
|
}
|
|
66
|
-
//#endregion
|
|
67
|
-
export { AnalyticsEvent, ChurnSignal, CohortAnalysis, CohortDefinition, CohortEvent, CohortStats, FunnelAnalysis, FunnelDefinition, FunnelStep, FunnelStepResult, GrowthHypothesis, GrowthMetric };
|
|
68
65
|
//# sourceMappingURL=types.d.ts.map
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACtC;AAED,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,cAAc,KAAK,OAAO,CAAC;CAC5C;AAED,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,UAAU,EAAE,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,UAAU,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,cAAc,EAAE,MAAM,CAAC;IACvB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,cAAc;IAC7B,UAAU,EAAE,gBAAgB,CAAC;IAC7B,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,gBAAgB,EAAE,CAAC;CAC3B;AAED,MAAM,WAAW,WAAY,SAAQ,cAAc;IACjD,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,KAAK,GAAG,MAAM,GAAG,OAAO,CAAC;IACjC,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,IAAI,CAAC;CAClB;AAED,MAAM,WAAW,WAAW;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,cAAc;IAC7B,UAAU,EAAE,gBAAgB,CAAC;IAC7B,OAAO,EAAE,WAAW,EAAE,CAAC;CACxB;AAED,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,CAAC;IAClC,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,gBAAgB;IAC/B,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,CAAC;IACtC,MAAM,EAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,CAAC;CACnC"}
|
package/dist/types.js
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
// @bun
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@contractspec/lib.analytics",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.58.0",
|
|
4
4
|
"description": "Product analytics and growth metrics",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"contractspec",
|
|
@@ -19,59 +19,209 @@
|
|
|
19
19
|
"scripts": {
|
|
20
20
|
"publish:pkg": "bun publish --tolerate-republish --ignore-scripts --verbose",
|
|
21
21
|
"publish:pkg:canary": "bun publish:pkg --tag canary",
|
|
22
|
-
"build": "bun build:
|
|
23
|
-
"build:bundle": "
|
|
24
|
-
"build:types": "
|
|
25
|
-
"dev": "bun
|
|
22
|
+
"build": "bun run prebuild && bun run build:bundle && bun run build:types",
|
|
23
|
+
"build:bundle": "contractspec-bun-build transpile",
|
|
24
|
+
"build:types": "contractspec-bun-build types",
|
|
25
|
+
"dev": "contractspec-bun-build dev",
|
|
26
26
|
"clean": "rimraf dist .turbo",
|
|
27
27
|
"lint": "bun lint:fix",
|
|
28
28
|
"lint:fix": "eslint src --fix",
|
|
29
29
|
"lint:check": "eslint src",
|
|
30
|
-
"test": "bun test"
|
|
30
|
+
"test": "bun test",
|
|
31
|
+
"prebuild": "contractspec-bun-build prebuild",
|
|
32
|
+
"typecheck": "tsc --noEmit"
|
|
31
33
|
},
|
|
32
34
|
"dependencies": {
|
|
33
|
-
"@contractspec/lib.
|
|
35
|
+
"@contractspec/lib.contracts": "1.58.0",
|
|
36
|
+
"@contractspec/lib.lifecycle": "1.58.0",
|
|
34
37
|
"dayjs": "^1.11.13"
|
|
35
38
|
},
|
|
36
39
|
"devDependencies": {
|
|
37
|
-
"@contractspec/tool.
|
|
38
|
-
"
|
|
39
|
-
"
|
|
40
|
-
"typescript": "^5.9.3"
|
|
40
|
+
"@contractspec/tool.typescript": "1.58.0",
|
|
41
|
+
"typescript": "^5.9.3",
|
|
42
|
+
"@contractspec/tool.bun": "1.57.0"
|
|
41
43
|
},
|
|
42
44
|
"exports": {
|
|
43
|
-
".": "./
|
|
44
|
-
"./churn": "./
|
|
45
|
-
"./churn/
|
|
46
|
-
"./
|
|
47
|
-
"./cohort
|
|
48
|
-
"./
|
|
49
|
-
"./
|
|
50
|
-
"./
|
|
51
|
-
"./
|
|
52
|
-
"./
|
|
53
|
-
"./
|
|
54
|
-
"./
|
|
55
|
-
"./
|
|
56
|
-
"
|
|
45
|
+
".": "./src/index.ts",
|
|
46
|
+
"./churn": "./src/churn/index.ts",
|
|
47
|
+
"./churn/index": "./src/churn/index.ts",
|
|
48
|
+
"./churn/predictor": "./src/churn/predictor.ts",
|
|
49
|
+
"./cohort": "./src/cohort/index.ts",
|
|
50
|
+
"./cohort/index": "./src/cohort/index.ts",
|
|
51
|
+
"./cohort/tracker": "./src/cohort/tracker.ts",
|
|
52
|
+
"./funnel": "./src/funnel/index.ts",
|
|
53
|
+
"./funnel/analyzer": "./src/funnel/analyzer.ts",
|
|
54
|
+
"./funnel/index": "./src/funnel/index.ts",
|
|
55
|
+
"./growth": "./src/growth/index.ts",
|
|
56
|
+
"./growth/hypothesis-generator": "./src/growth/hypothesis-generator.ts",
|
|
57
|
+
"./growth/index": "./src/growth/index.ts",
|
|
58
|
+
"./lifecycle": "./src/lifecycle/index.ts",
|
|
59
|
+
"./lifecycle/index": "./src/lifecycle/index.ts",
|
|
60
|
+
"./lifecycle/metric-collectors": "./src/lifecycle/metric-collectors.ts",
|
|
61
|
+
"./lifecycle/posthog-bridge": "./src/lifecycle/posthog-bridge.ts",
|
|
62
|
+
"./lifecycle/posthog-metric-source": "./src/lifecycle/posthog-metric-source.ts",
|
|
63
|
+
"./posthog": "./src/posthog/index.ts",
|
|
64
|
+
"./posthog/event-source": "./src/posthog/event-source.ts",
|
|
65
|
+
"./posthog/index": "./src/posthog/index.ts",
|
|
66
|
+
"./types": "./src/types.ts"
|
|
57
67
|
},
|
|
58
68
|
"publishConfig": {
|
|
59
69
|
"access": "public",
|
|
60
70
|
"exports": {
|
|
61
|
-
".":
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
"./
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
71
|
+
".": {
|
|
72
|
+
"types": "./dist/index.d.ts",
|
|
73
|
+
"bun": "./dist/index.js",
|
|
74
|
+
"node": "./dist/node/index.mjs",
|
|
75
|
+
"browser": "./dist/browser/index.js",
|
|
76
|
+
"default": "./dist/index.js"
|
|
77
|
+
},
|
|
78
|
+
"./churn": {
|
|
79
|
+
"types": "./dist/churn/index.d.ts",
|
|
80
|
+
"bun": "./dist/churn/index.js",
|
|
81
|
+
"node": "./dist/node/churn/index.mjs",
|
|
82
|
+
"browser": "./dist/browser/churn/index.js",
|
|
83
|
+
"default": "./dist/churn/index.js"
|
|
84
|
+
},
|
|
85
|
+
"./churn/index": {
|
|
86
|
+
"types": "./dist/churn/index.d.ts",
|
|
87
|
+
"bun": "./dist/churn/index.js",
|
|
88
|
+
"node": "./dist/node/churn/index.mjs",
|
|
89
|
+
"browser": "./dist/browser/churn/index.js",
|
|
90
|
+
"default": "./dist/churn/index.js"
|
|
91
|
+
},
|
|
92
|
+
"./churn/predictor": {
|
|
93
|
+
"types": "./dist/churn/predictor.d.ts",
|
|
94
|
+
"bun": "./dist/churn/predictor.js",
|
|
95
|
+
"node": "./dist/node/churn/predictor.mjs",
|
|
96
|
+
"browser": "./dist/browser/churn/predictor.js",
|
|
97
|
+
"default": "./dist/churn/predictor.js"
|
|
98
|
+
},
|
|
99
|
+
"./cohort": {
|
|
100
|
+
"types": "./dist/cohort/index.d.ts",
|
|
101
|
+
"bun": "./dist/cohort/index.js",
|
|
102
|
+
"node": "./dist/node/cohort/index.mjs",
|
|
103
|
+
"browser": "./dist/browser/cohort/index.js",
|
|
104
|
+
"default": "./dist/cohort/index.js"
|
|
105
|
+
},
|
|
106
|
+
"./cohort/index": {
|
|
107
|
+
"types": "./dist/cohort/index.d.ts",
|
|
108
|
+
"bun": "./dist/cohort/index.js",
|
|
109
|
+
"node": "./dist/node/cohort/index.mjs",
|
|
110
|
+
"browser": "./dist/browser/cohort/index.js",
|
|
111
|
+
"default": "./dist/cohort/index.js"
|
|
112
|
+
},
|
|
113
|
+
"./cohort/tracker": {
|
|
114
|
+
"types": "./dist/cohort/tracker.d.ts",
|
|
115
|
+
"bun": "./dist/cohort/tracker.js",
|
|
116
|
+
"node": "./dist/node/cohort/tracker.mjs",
|
|
117
|
+
"browser": "./dist/browser/cohort/tracker.js",
|
|
118
|
+
"default": "./dist/cohort/tracker.js"
|
|
119
|
+
},
|
|
120
|
+
"./funnel": {
|
|
121
|
+
"types": "./dist/funnel/index.d.ts",
|
|
122
|
+
"bun": "./dist/funnel/index.js",
|
|
123
|
+
"node": "./dist/node/funnel/index.mjs",
|
|
124
|
+
"browser": "./dist/browser/funnel/index.js",
|
|
125
|
+
"default": "./dist/funnel/index.js"
|
|
126
|
+
},
|
|
127
|
+
"./funnel/analyzer": {
|
|
128
|
+
"types": "./dist/funnel/analyzer.d.ts",
|
|
129
|
+
"bun": "./dist/funnel/analyzer.js",
|
|
130
|
+
"node": "./dist/node/funnel/analyzer.mjs",
|
|
131
|
+
"browser": "./dist/browser/funnel/analyzer.js",
|
|
132
|
+
"default": "./dist/funnel/analyzer.js"
|
|
133
|
+
},
|
|
134
|
+
"./funnel/index": {
|
|
135
|
+
"types": "./dist/funnel/index.d.ts",
|
|
136
|
+
"bun": "./dist/funnel/index.js",
|
|
137
|
+
"node": "./dist/node/funnel/index.mjs",
|
|
138
|
+
"browser": "./dist/browser/funnel/index.js",
|
|
139
|
+
"default": "./dist/funnel/index.js"
|
|
140
|
+
},
|
|
141
|
+
"./growth": {
|
|
142
|
+
"types": "./dist/growth/index.d.ts",
|
|
143
|
+
"bun": "./dist/growth/index.js",
|
|
144
|
+
"node": "./dist/node/growth/index.mjs",
|
|
145
|
+
"browser": "./dist/browser/growth/index.js",
|
|
146
|
+
"default": "./dist/growth/index.js"
|
|
147
|
+
},
|
|
148
|
+
"./growth/hypothesis-generator": {
|
|
149
|
+
"types": "./dist/growth/hypothesis-generator.d.ts",
|
|
150
|
+
"bun": "./dist/growth/hypothesis-generator.js",
|
|
151
|
+
"node": "./dist/node/growth/hypothesis-generator.mjs",
|
|
152
|
+
"browser": "./dist/browser/growth/hypothesis-generator.js",
|
|
153
|
+
"default": "./dist/growth/hypothesis-generator.js"
|
|
154
|
+
},
|
|
155
|
+
"./growth/index": {
|
|
156
|
+
"types": "./dist/growth/index.d.ts",
|
|
157
|
+
"bun": "./dist/growth/index.js",
|
|
158
|
+
"node": "./dist/node/growth/index.mjs",
|
|
159
|
+
"browser": "./dist/browser/growth/index.js",
|
|
160
|
+
"default": "./dist/growth/index.js"
|
|
161
|
+
},
|
|
162
|
+
"./lifecycle": {
|
|
163
|
+
"types": "./dist/lifecycle/index.d.ts",
|
|
164
|
+
"bun": "./dist/lifecycle/index.js",
|
|
165
|
+
"node": "./dist/node/lifecycle/index.mjs",
|
|
166
|
+
"browser": "./dist/browser/lifecycle/index.js",
|
|
167
|
+
"default": "./dist/lifecycle/index.js"
|
|
168
|
+
},
|
|
169
|
+
"./lifecycle/index": {
|
|
170
|
+
"types": "./dist/lifecycle/index.d.ts",
|
|
171
|
+
"bun": "./dist/lifecycle/index.js",
|
|
172
|
+
"node": "./dist/node/lifecycle/index.mjs",
|
|
173
|
+
"browser": "./dist/browser/lifecycle/index.js",
|
|
174
|
+
"default": "./dist/lifecycle/index.js"
|
|
175
|
+
},
|
|
176
|
+
"./lifecycle/metric-collectors": {
|
|
177
|
+
"types": "./dist/lifecycle/metric-collectors.d.ts",
|
|
178
|
+
"bun": "./dist/lifecycle/metric-collectors.js",
|
|
179
|
+
"node": "./dist/node/lifecycle/metric-collectors.mjs",
|
|
180
|
+
"browser": "./dist/browser/lifecycle/metric-collectors.js",
|
|
181
|
+
"default": "./dist/lifecycle/metric-collectors.js"
|
|
182
|
+
},
|
|
183
|
+
"./lifecycle/posthog-bridge": {
|
|
184
|
+
"types": "./dist/lifecycle/posthog-bridge.d.ts",
|
|
185
|
+
"bun": "./dist/lifecycle/posthog-bridge.js",
|
|
186
|
+
"node": "./dist/node/lifecycle/posthog-bridge.mjs",
|
|
187
|
+
"browser": "./dist/browser/lifecycle/posthog-bridge.js",
|
|
188
|
+
"default": "./dist/lifecycle/posthog-bridge.js"
|
|
189
|
+
},
|
|
190
|
+
"./lifecycle/posthog-metric-source": {
|
|
191
|
+
"types": "./dist/lifecycle/posthog-metric-source.d.ts",
|
|
192
|
+
"bun": "./dist/lifecycle/posthog-metric-source.js",
|
|
193
|
+
"node": "./dist/node/lifecycle/posthog-metric-source.mjs",
|
|
194
|
+
"browser": "./dist/browser/lifecycle/posthog-metric-source.js",
|
|
195
|
+
"default": "./dist/lifecycle/posthog-metric-source.js"
|
|
196
|
+
},
|
|
197
|
+
"./posthog": {
|
|
198
|
+
"types": "./dist/posthog/index.d.ts",
|
|
199
|
+
"bun": "./dist/posthog/index.js",
|
|
200
|
+
"node": "./dist/node/posthog/index.mjs",
|
|
201
|
+
"browser": "./dist/browser/posthog/index.js",
|
|
202
|
+
"default": "./dist/posthog/index.js"
|
|
203
|
+
},
|
|
204
|
+
"./posthog/event-source": {
|
|
205
|
+
"types": "./dist/posthog/event-source.d.ts",
|
|
206
|
+
"bun": "./dist/posthog/event-source.js",
|
|
207
|
+
"node": "./dist/node/posthog/event-source.mjs",
|
|
208
|
+
"browser": "./dist/browser/posthog/event-source.js",
|
|
209
|
+
"default": "./dist/posthog/event-source.js"
|
|
210
|
+
},
|
|
211
|
+
"./posthog/index": {
|
|
212
|
+
"types": "./dist/posthog/index.d.ts",
|
|
213
|
+
"bun": "./dist/posthog/index.js",
|
|
214
|
+
"node": "./dist/node/posthog/index.mjs",
|
|
215
|
+
"browser": "./dist/browser/posthog/index.js",
|
|
216
|
+
"default": "./dist/posthog/index.js"
|
|
217
|
+
},
|
|
218
|
+
"./types": {
|
|
219
|
+
"types": "./dist/types.d.ts",
|
|
220
|
+
"bun": "./dist/types.js",
|
|
221
|
+
"node": "./dist/node/types.mjs",
|
|
222
|
+
"browser": "./dist/browser/types.js",
|
|
223
|
+
"default": "./dist/types.js"
|
|
224
|
+
}
|
|
75
225
|
},
|
|
76
226
|
"registry": "https://registry.npmjs.org/"
|
|
77
227
|
},
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"predictor.js","names":[],"sources":["../../src/churn/predictor.ts"],"sourcesContent":["import dayjs from 'dayjs';\nimport type { AnalyticsEvent, ChurnSignal } from '../types';\n\nexport interface ChurnPredictorOptions {\n recencyWeight?: number;\n frequencyWeight?: number;\n errorWeight?: number;\n decayDays?: number;\n}\n\nexport class ChurnPredictor {\n private readonly recencyWeight: number;\n private readonly frequencyWeight: number;\n private readonly errorWeight: number;\n private readonly decayDays: number;\n\n constructor(options?: ChurnPredictorOptions) {\n this.recencyWeight = options?.recencyWeight ?? 0.5;\n this.frequencyWeight = options?.frequencyWeight ?? 0.3;\n this.errorWeight = options?.errorWeight ?? 0.2;\n this.decayDays = options?.decayDays ?? 14;\n }\n\n score(events: AnalyticsEvent[]): ChurnSignal[] {\n const grouped = groupBy(events, (event) => event.userId);\n const signals: ChurnSignal[] = [];\n for (const [userId, userEvents] of grouped.entries()) {\n const score = this.computeScore(userEvents);\n signals.push({\n userId,\n score,\n bucket: score >= 0.7 ? 'high' : score >= 0.4 ? 'medium' : 'low',\n drivers: this.drivers(userEvents),\n });\n }\n return signals.sort((a, b) => b.score - a.score);\n }\n\n private computeScore(events: AnalyticsEvent[]): number {\n if (!events.length) return 0;\n const sorted = events.sort((a, b) => dateMs(a) - dateMs(b));\n const lastEvent = sorted[sorted.length - 1];\n if (!lastEvent) return 0;\n const daysSinceLast = dayjs().diff(dayjs(lastEvent.timestamp), 'day');\n const recencyScore = Math.max(0, 1 - daysSinceLast / this.decayDays);\n\n const windowStart = dayjs().subtract(this.decayDays, 'day');\n const recentEvents = sorted.filter((event) =>\n dayjs(event.timestamp).isAfter(windowStart)\n );\n const averagePerDay = recentEvents.length / Math.max(this.decayDays, 1);\n const frequencyScore = Math.min(1, averagePerDay * 5);\n\n const errorEvents = recentEvents.filter(\n (event) =>\n typeof event.properties?.error !== 'undefined' ||\n /error|failed/i.test(event.name)\n ).length;\n const errorScore = Math.min(1, errorEvents / 3);\n\n const score =\n recencyScore * this.recencyWeight +\n frequencyScore * this.frequencyWeight +\n (1 - errorScore) * this.errorWeight;\n return Number(score.toFixed(3));\n }\n\n private drivers(events: AnalyticsEvent[]): string[] {\n const drivers: string[] = [];\n const sorted = events.sort((a, b) => dateMs(a) - dateMs(b));\n const lastEvent = sorted[sorted.length - 1];\n if (lastEvent) {\n const days = dayjs().diff(dayjs(lastEvent.timestamp), 'day');\n if (days > this.decayDays) drivers.push(`Inactive for ${days} days`);\n }\n const errorEvents = events.filter(\n (event) =>\n typeof event.properties?.error !== 'undefined' ||\n /error|failed/i.test(event.name)\n );\n if (errorEvents.length) drivers.push(`${errorEvents.length} errors logged`);\n return drivers;\n }\n}\n\nfunction groupBy<T>(\n items: T[],\n selector: (item: T) => string\n): Map<string, T[]> {\n const map = new Map<string, T[]>();\n for (const item of items) {\n const key = selector(item);\n const list = map.get(key) ?? [];\n list.push(item);\n map.set(key, list);\n }\n return map;\n}\n\nfunction dateMs(event: AnalyticsEvent) {\n return new Date(event.timestamp).getTime();\n}\n"],"mappings":";;;AAUA,IAAa,iBAAb,MAA4B;CAC1B,AAAiB;CACjB,AAAiB;CACjB,AAAiB;CACjB,AAAiB;CAEjB,YAAY,SAAiC;AAC3C,OAAK,gBAAgB,SAAS,iBAAiB;AAC/C,OAAK,kBAAkB,SAAS,mBAAmB;AACnD,OAAK,cAAc,SAAS,eAAe;AAC3C,OAAK,YAAY,SAAS,aAAa;;CAGzC,MAAM,QAAyC;EAC7C,MAAM,UAAU,QAAQ,SAAS,UAAU,MAAM,OAAO;EACxD,MAAM,UAAyB,EAAE;AACjC,OAAK,MAAM,CAAC,QAAQ,eAAe,QAAQ,SAAS,EAAE;GACpD,MAAM,QAAQ,KAAK,aAAa,WAAW;AAC3C,WAAQ,KAAK;IACX;IACA;IACA,QAAQ,SAAS,KAAM,SAAS,SAAS,KAAM,WAAW;IAC1D,SAAS,KAAK,QAAQ,WAAW;IAClC,CAAC;;AAEJ,SAAO,QAAQ,MAAM,GAAG,MAAM,EAAE,QAAQ,EAAE,MAAM;;CAGlD,AAAQ,aAAa,QAAkC;AACrD,MAAI,CAAC,OAAO,OAAQ,QAAO;EAC3B,MAAM,SAAS,OAAO,MAAM,GAAG,MAAM,OAAO,EAAE,GAAG,OAAO,EAAE,CAAC;EAC3D,MAAM,YAAY,OAAO,OAAO,SAAS;AACzC,MAAI,CAAC,UAAW,QAAO;EACvB,MAAM,gBAAgB,OAAO,CAAC,KAAK,MAAM,UAAU,UAAU,EAAE,MAAM;EACrE,MAAM,eAAe,KAAK,IAAI,GAAG,IAAI,gBAAgB,KAAK,UAAU;EAEpE,MAAM,cAAc,OAAO,CAAC,SAAS,KAAK,WAAW,MAAM;EAC3D,MAAM,eAAe,OAAO,QAAQ,UAClC,MAAM,MAAM,UAAU,CAAC,QAAQ,YAAY,CAC5C;EACD,MAAM,gBAAgB,aAAa,SAAS,KAAK,IAAI,KAAK,WAAW,EAAE;EACvE,MAAM,iBAAiB,KAAK,IAAI,GAAG,gBAAgB,EAAE;EAErD,MAAM,cAAc,aAAa,QAC9B,UACC,OAAO,MAAM,YAAY,UAAU,eACnC,gBAAgB,KAAK,MAAM,KAAK,CACnC,CAAC;EACF,MAAM,aAAa,KAAK,IAAI,GAAG,cAAc,EAAE;EAE/C,MAAM,QACJ,eAAe,KAAK,gBACpB,iBAAiB,KAAK,mBACrB,IAAI,cAAc,KAAK;AAC1B,SAAO,OAAO,MAAM,QAAQ,EAAE,CAAC;;CAGjC,AAAQ,QAAQ,QAAoC;EAClD,MAAM,UAAoB,EAAE;EAC5B,MAAM,SAAS,OAAO,MAAM,GAAG,MAAM,OAAO,EAAE,GAAG,OAAO,EAAE,CAAC;EAC3D,MAAM,YAAY,OAAO,OAAO,SAAS;AACzC,MAAI,WAAW;GACb,MAAM,OAAO,OAAO,CAAC,KAAK,MAAM,UAAU,UAAU,EAAE,MAAM;AAC5D,OAAI,OAAO,KAAK,UAAW,SAAQ,KAAK,gBAAgB,KAAK,OAAO;;EAEtE,MAAM,cAAc,OAAO,QACxB,UACC,OAAO,MAAM,YAAY,UAAU,eACnC,gBAAgB,KAAK,MAAM,KAAK,CACnC;AACD,MAAI,YAAY,OAAQ,SAAQ,KAAK,GAAG,YAAY,OAAO,gBAAgB;AAC3E,SAAO;;;AAIX,SAAS,QACP,OACA,UACkB;CAClB,MAAM,sBAAM,IAAI,KAAkB;AAClC,MAAK,MAAM,QAAQ,OAAO;EACxB,MAAM,MAAM,SAAS,KAAK;EAC1B,MAAM,OAAO,IAAI,IAAI,IAAI,IAAI,EAAE;AAC/B,OAAK,KAAK,KAAK;AACf,MAAI,IAAI,KAAK,KAAK;;AAEpB,QAAO;;AAGT,SAAS,OAAO,OAAuB;AACrC,QAAO,IAAI,KAAK,MAAM,UAAU,CAAC,SAAS"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"tracker.js","names":[],"sources":["../../src/cohort/tracker.ts"],"sourcesContent":["import dayjs from 'dayjs';\nimport type {\n AnalyticsEvent,\n CohortAnalysis,\n CohortDefinition,\n CohortStats,\n} from '../types';\n\nexport class CohortTracker {\n analyze(\n events: AnalyticsEvent[],\n definition: CohortDefinition\n ): CohortAnalysis {\n const groupedByUser = groupBy(events, (event) => event.userId);\n const cohorts = new Map<string, CohortStatsBuilder>();\n\n for (const [userId, userEvents] of groupedByUser.entries()) {\n userEvents.sort((a, b) => dateMs(a) - dateMs(b));\n const signup = userEvents[0];\n if (!signup) continue;\n const cohortKey = bucketKey(signup.timestamp, definition.bucket);\n const builder =\n cohorts.get(cohortKey) ?? new CohortStatsBuilder(cohortKey, definition);\n builder.addUser(userId);\n for (const event of userEvents) {\n builder.addEvent(userId, event);\n }\n cohorts.set(cohortKey, builder);\n }\n\n return {\n definition,\n cohorts: [...cohorts.values()].map((builder) => builder.build()),\n };\n }\n}\n\nclass CohortStatsBuilder {\n private readonly users = new Set<string>();\n private readonly retentionMap = new Map<number, Set<string>>();\n private ltv = 0;\n constructor(\n private readonly key: string,\n private readonly definition: CohortDefinition\n ) {}\n\n addUser(userId: string) {\n this.users.add(userId);\n }\n\n addEvent(userId: string, event: AnalyticsEvent) {\n const period = bucketDiff(\n this.key,\n event.timestamp,\n this.definition.bucket\n );\n if (period < 0 || period >= this.definition.periods) return;\n const bucket = this.retentionMap.get(period) ?? new Set<string>();\n bucket.add(userId);\n this.retentionMap.set(period, bucket);\n const amount =\n typeof event.properties?.amount === 'number'\n ? event.properties.amount\n : 0;\n this.ltv += amount;\n }\n\n build(): CohortStats {\n const totalUsers = this.users.size || 1;\n const retention: number[] = [];\n for (let period = 0; period < this.definition.periods; period++) {\n const active = this.retentionMap.get(period)?.size ?? 0;\n retention.push(Number((active / totalUsers).toFixed(3)));\n }\n return {\n cohortKey: this.key,\n users: this.users.size,\n retention,\n ltv: Number(this.ltv.toFixed(2)),\n };\n }\n}\n\nfunction groupBy<T>(\n items: T[],\n selector: (item: T) => string\n): Map<string, T[]> {\n const map = new Map<string, T[]>();\n for (const item of items) {\n const key = selector(item);\n const list = map.get(key) ?? [];\n list.push(item);\n map.set(key, list);\n }\n return map;\n}\n\nfunction bucketKey(\n timestamp: string | Date,\n bucket: CohortDefinition['bucket']\n): string {\n const dt = dayjs(timestamp);\n switch (bucket) {\n case 'day':\n return dt.startOf('day').format('YYYY-MM-DD');\n case 'week':\n return dt.startOf('week').format('YYYY-[W]WW');\n case 'month':\n default:\n return dt.startOf('month').format('YYYY-MM');\n }\n}\n\nfunction bucketDiff(\n cohortKey: string,\n timestamp: string | Date,\n bucket: CohortDefinition['bucket']\n): number {\n const start = parseBucketKey(cohortKey, bucket);\n const target = dayjs(timestamp);\n switch (bucket) {\n case 'day':\n return target.diff(start, 'day');\n case 'week':\n return target.diff(start, 'week');\n case 'month':\n default:\n return target.diff(start, 'month');\n }\n}\n\nfunction parseBucketKey(key: string, bucket: CohortDefinition['bucket']) {\n switch (bucket) {\n case 'day':\n return dayjs(key, 'YYYY-MM-DD');\n case 'week':\n return dayjs(key.replace('W', ''), 'YYYY-ww');\n case 'month':\n default:\n return dayjs(key, 'YYYY-MM');\n }\n}\n\nfunction dateMs(event: AnalyticsEvent) {\n return new Date(event.timestamp).getTime();\n}\n"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"analyzer.js","names":[],"sources":["../../src/funnel/analyzer.ts"],"sourcesContent":["import type {\n AnalyticsEvent,\n FunnelAnalysis,\n FunnelDefinition,\n FunnelStep,\n FunnelStepResult,\n} from '../types';\n\nexport class FunnelAnalyzer {\n analyze(\n events: AnalyticsEvent[],\n definition: FunnelDefinition\n ): FunnelAnalysis {\n const windowMs = (definition.windowHours ?? 72) * 60 * 60 * 1000;\n const eventsByUser = groupByUser(events);\n const stepCounts = definition.steps.map(() => 0);\n\n for (const userEvents of eventsByUser.values()) {\n const completionIndex = this.evaluateUser(\n userEvents,\n definition.steps,\n windowMs\n );\n completionIndex.forEach((hit, stepIdx) => {\n if (hit) {\n stepCounts[stepIdx] = (stepCounts[stepIdx] ?? 0) + 1;\n }\n });\n }\n\n const totalUsers = eventsByUser.size;\n const steps: FunnelStepResult[] = definition.steps.map((step, index) => {\n const prevCount = index === 0 ? totalUsers : stepCounts[index - 1] || 1;\n const count = stepCounts[index] ?? 0;\n const conversionRate =\n prevCount === 0 ? 0 : Number((count / prevCount).toFixed(3));\n const dropOffRate = Number((1 - conversionRate).toFixed(3));\n return { step, count, conversionRate, dropOffRate };\n });\n\n return {\n definition,\n totalUsers,\n steps,\n };\n }\n\n private evaluateUser(\n events: AnalyticsEvent[],\n steps: FunnelStep[],\n windowMs: number\n ) {\n const sorted = [...events].sort(\n (a, b) =>\n new Date(a.timestamp).getTime() - new Date(b.timestamp).getTime()\n );\n const completion: boolean[] = Array(steps.length).fill(false);\n let cursor = 0;\n let anchorTime: number | undefined;\n\n for (const event of sorted) {\n const step = steps[cursor];\n if (!step) break;\n if (event.name !== step.eventName) continue;\n if (step.match && !step.match(event)) continue;\n\n const eventTime = new Date(event.timestamp).getTime();\n if (cursor === 0) {\n anchorTime = eventTime;\n completion[cursor] = true;\n cursor += 1;\n continue;\n }\n\n if (anchorTime && eventTime - anchorTime <= windowMs) {\n completion[cursor] = true;\n cursor += 1;\n }\n }\n\n return completion;\n }\n}\n\nfunction groupByUser(events: AnalyticsEvent[]): Map<string, AnalyticsEvent[]> {\n const map = new Map<string, AnalyticsEvent[]>();\n for (const event of events) {\n const list = map.get(event.userId) ?? [];\n list.push(event);\n map.set(event.userId, list);\n }\n return map;\n}\n"],"mappings":";AAQA,IAAa,iBAAb,MAA4B;CAC1B,QACE,QACA,YACgB;EAChB,MAAM,YAAY,WAAW,eAAe,MAAM,KAAK,KAAK;EAC5D,MAAM,eAAe,YAAY,OAAO;EACxC,MAAM,aAAa,WAAW,MAAM,UAAU,EAAE;AAEhD,OAAK,MAAM,cAAc,aAAa,QAAQ,CAM5C,CALwB,KAAK,aAC3B,YACA,WAAW,OACX,SACD,CACe,SAAS,KAAK,YAAY;AACxC,OAAI,IACF,YAAW,YAAY,WAAW,YAAY,KAAK;IAErD;EAGJ,MAAM,aAAa,aAAa;AAUhC,SAAO;GACL;GACA;GACA,OAZgC,WAAW,MAAM,KAAK,MAAM,UAAU;IACtE,MAAM,YAAY,UAAU,IAAI,aAAa,WAAW,QAAQ,MAAM;IACtE,MAAM,QAAQ,WAAW,UAAU;IACnC,MAAM,iBACJ,cAAc,IAAI,IAAI,QAAQ,QAAQ,WAAW,QAAQ,EAAE,CAAC;AAE9D,WAAO;KAAE;KAAM;KAAO;KAAgB,aADlB,QAAQ,IAAI,gBAAgB,QAAQ,EAAE,CAAC;KACR;KACnD;GAMD;;CAGH,AAAQ,aACN,QACA,OACA,UACA;EACA,MAAM,SAAS,CAAC,GAAG,OAAO,CAAC,MACxB,GAAG,MACF,IAAI,KAAK,EAAE,UAAU,CAAC,SAAS,GAAG,IAAI,KAAK,EAAE,UAAU,CAAC,SAAS,CACpE;EACD,MAAM,aAAwB,MAAM,MAAM,OAAO,CAAC,KAAK,MAAM;EAC7D,IAAI,SAAS;EACb,IAAI;AAEJ,OAAK,MAAM,SAAS,QAAQ;GAC1B,MAAM,OAAO,MAAM;AACnB,OAAI,CAAC,KAAM;AACX,OAAI,MAAM,SAAS,KAAK,UAAW;AACnC,OAAI,KAAK,SAAS,CAAC,KAAK,MAAM,MAAM,CAAE;GAEtC,MAAM,YAAY,IAAI,KAAK,MAAM,UAAU,CAAC,SAAS;AACrD,OAAI,WAAW,GAAG;AAChB,iBAAa;AACb,eAAW,UAAU;AACrB,cAAU;AACV;;AAGF,OAAI,cAAc,YAAY,cAAc,UAAU;AACpD,eAAW,UAAU;AACrB,cAAU;;;AAId,SAAO;;;AAIX,SAAS,YAAY,QAAyD;CAC5E,MAAM,sBAAM,IAAI,KAA+B;AAC/C,MAAK,MAAM,SAAS,QAAQ;EAC1B,MAAM,OAAO,IAAI,IAAI,MAAM,OAAO,IAAI,EAAE;AACxC,OAAK,KAAK,MAAM;AAChB,MAAI,IAAI,MAAM,QAAQ,KAAK;;AAE7B,QAAO"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"hypothesis-generator.js","names":[],"sources":["../../src/growth/hypothesis-generator.ts"],"sourcesContent":["import type { GrowthHypothesis, GrowthMetric } from '../types';\n\nexport interface HypothesisGeneratorOptions {\n minDelta?: number;\n}\n\nexport class GrowthHypothesisGenerator {\n private readonly minDelta: number;\n\n constructor(options?: HypothesisGeneratorOptions) {\n this.minDelta = options?.minDelta ?? 0.05;\n }\n\n generate(metrics: GrowthMetric[]): GrowthHypothesis[] {\n return metrics\n .map((metric) => this.fromMetric(metric))\n .filter((hypothesis): hypothesis is GrowthHypothesis =>\n Boolean(hypothesis)\n );\n }\n\n private fromMetric(metric: GrowthMetric): GrowthHypothesis | null {\n const change = this.delta(metric);\n if (Math.abs(change) < this.minDelta) return null;\n const direction = change > 0 ? 'rising' : 'declining';\n const statement = this.statement(metric, change, direction);\n return {\n statement,\n metric: metric.name,\n confidence: Math.abs(change) > 0.2 ? 'high' : 'medium',\n impact: this.impact(metric),\n };\n }\n\n private delta(metric: GrowthMetric): number {\n if (metric.previous == null) return 0;\n const prev = metric.previous || 1;\n return (metric.current - prev) / Math.abs(prev);\n }\n\n private impact(metric: GrowthMetric): GrowthHypothesis['impact'] {\n if (metric.target && metric.current < metric.target * 0.8) return 'high';\n if (metric.target && metric.current < metric.target) return 'medium';\n return 'low';\n }\n\n private statement(\n metric: GrowthMetric,\n change: number,\n direction: string\n ): string {\n const percent = Math.abs(parseFloat((change * 100).toFixed(1)));\n if (direction === 'declining') {\n return `${metric.name} is down ${percent}% vs last period; test new onboarding prompts to recover activation.`;\n }\n return `${metric.name} grew ${percent}% period-over-period; double down with expanded experiment or pricing test.`;\n }\n}\n"],"mappings":";AAMA,IAAa,4BAAb,MAAuC;CACrC,AAAiB;CAEjB,YAAY,SAAsC;AAChD,OAAK,WAAW,SAAS,YAAY;;CAGvC,SAAS,SAA6C;AACpD,SAAO,QACJ,KAAK,WAAW,KAAK,WAAW,OAAO,CAAC,CACxC,QAAQ,eACP,QAAQ,WAAW,CACpB;;CAGL,AAAQ,WAAW,QAA+C;EAChE,MAAM,SAAS,KAAK,MAAM,OAAO;AACjC,MAAI,KAAK,IAAI,OAAO,GAAG,KAAK,SAAU,QAAO;EAC7C,MAAM,YAAY,SAAS,IAAI,WAAW;AAE1C,SAAO;GACL,WAFgB,KAAK,UAAU,QAAQ,QAAQ,UAAU;GAGzD,QAAQ,OAAO;GACf,YAAY,KAAK,IAAI,OAAO,GAAG,KAAM,SAAS;GAC9C,QAAQ,KAAK,OAAO,OAAO;GAC5B;;CAGH,AAAQ,MAAM,QAA8B;AAC1C,MAAI,OAAO,YAAY,KAAM,QAAO;EACpC,MAAM,OAAO,OAAO,YAAY;AAChC,UAAQ,OAAO,UAAU,QAAQ,KAAK,IAAI,KAAK;;CAGjD,AAAQ,OAAO,QAAkD;AAC/D,MAAI,OAAO,UAAU,OAAO,UAAU,OAAO,SAAS,GAAK,QAAO;AAClE,MAAI,OAAO,UAAU,OAAO,UAAU,OAAO,OAAQ,QAAO;AAC5D,SAAO;;CAGT,AAAQ,UACN,QACA,QACA,WACQ;EACR,MAAM,UAAU,KAAK,IAAI,YAAY,SAAS,KAAK,QAAQ,EAAE,CAAC,CAAC;AAC/D,MAAI,cAAc,YAChB,QAAO,GAAG,OAAO,KAAK,WAAW,QAAQ;AAE3C,SAAO,GAAG,OAAO,KAAK,QAAQ,QAAQ"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"metric-collectors.js","names":[],"sources":["../../src/lifecycle/metric-collectors.ts"],"sourcesContent":["import type {\n LifecycleMetricSnapshot,\n LifecycleSignal,\n LifecycleStage,\n} from '@contractspec/lib.lifecycle';\nimport type { AnalyticsEvent } from '../types';\n\nexport interface LifecycleMetricSource {\n getActiveUsers(): Promise<number | undefined>;\n getWeeklyActiveUsers?(): Promise<number | undefined>;\n getRetentionRate?(): Promise<number | undefined>;\n getMonthlyRecurringRevenue?(): Promise<number | undefined>;\n getCustomerCount?(): Promise<number | undefined>;\n getTeamSize?(): Promise<number | undefined>;\n getBurnMultiple?(): Promise<number | undefined>;\n}\n\nexport const collectLifecycleMetrics = async (\n source: LifecycleMetricSource\n): Promise<LifecycleMetricSnapshot> => {\n const [\n activeUsers,\n weeklyActiveUsers,\n retentionRate,\n monthlyRecurringRevenue,\n customerCount,\n teamSize,\n burnMultiple,\n ] = await Promise.all([\n source.getActiveUsers(),\n source.getWeeklyActiveUsers?.(),\n source.getRetentionRate?.(),\n source.getMonthlyRecurringRevenue?.(),\n source.getCustomerCount?.(),\n source.getTeamSize?.(),\n source.getBurnMultiple?.(),\n ]);\n\n return {\n activeUsers,\n weeklyActiveUsers,\n retentionRate,\n monthlyRecurringRevenue,\n customerCount,\n teamSize,\n burnMultiple,\n };\n};\n\nexport const metricsToSignals = (\n metrics: LifecycleMetricSnapshot,\n tenantId?: string\n): LifecycleSignal[] =>\n Object.entries(metrics)\n .filter(([, value]) => value !== undefined && value !== null)\n .map(([metricKey, value]) => ({\n id: `lifecycle-metric:${metricKey}`,\n kind: 'metric',\n source: 'analytics',\n name: metricKey,\n value,\n weight: 1,\n confidence: 0.8,\n details: tenantId ? { tenantId } : undefined,\n capturedAt: new Date().toISOString(),\n }));\n\nexport const lifecycleEventNames = {\n assessmentRun: 'lifecycle_assessment_run',\n stageChanged: 'lifecycle_stage_changed',\n guidanceConsumed: 'lifecycle_guidance_consumed',\n} as const;\n\nexport interface LifecycleStageChangePayload {\n tenantId?: string;\n previousStage?: LifecycleStage;\n nextStage: LifecycleStage;\n confidence: number;\n}\n\nexport const createStageChangeEvent = (\n payload: LifecycleStageChangePayload\n): AnalyticsEvent => ({\n name: lifecycleEventNames.stageChanged,\n userId: 'system',\n tenantId: payload.tenantId,\n timestamp: new Date(),\n properties: { ...payload },\n});\n"],"mappings":";AAiBA,MAAa,0BAA0B,OACrC,WACqC;CACrC,MAAM,CACJ,aACA,mBACA,eACA,yBACA,eACA,UACA,gBACE,MAAM,QAAQ,IAAI;EACpB,OAAO,gBAAgB;EACvB,OAAO,wBAAwB;EAC/B,OAAO,oBAAoB;EAC3B,OAAO,8BAA8B;EACrC,OAAO,oBAAoB;EAC3B,OAAO,eAAe;EACtB,OAAO,mBAAmB;EAC3B,CAAC;AAEF,QAAO;EACL;EACA;EACA;EACA;EACA;EACA;EACA;EACD;;AAGH,MAAa,oBACX,SACA,aAEA,OAAO,QAAQ,QAAQ,CACpB,QAAQ,GAAG,WAAW,UAAU,UAAa,UAAU,KAAK,CAC5D,KAAK,CAAC,WAAW,YAAY;CAC5B,IAAI,oBAAoB;CACxB,MAAM;CACN,QAAQ;CACR,MAAM;CACN;CACA,QAAQ;CACR,YAAY;CACZ,SAAS,WAAW,EAAE,UAAU,GAAG;CACnC,6BAAY,IAAI,MAAM,EAAC,aAAa;CACrC,EAAE;AAEP,MAAa,sBAAsB;CACjC,eAAe;CACf,cAAc;CACd,kBAAkB;CACnB;AASD,MAAa,0BACX,aACoB;CACpB,MAAM,oBAAoB;CAC1B,QAAQ;CACR,UAAU,QAAQ;CAClB,2BAAW,IAAI,MAAM;CACrB,YAAY,EAAE,GAAG,SAAS;CAC3B"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"posthog-bridge.js","names":[],"sources":["../../src/lifecycle/posthog-bridge.ts"],"sourcesContent":["import type { LifecycleAssessment } from '@contractspec/lib.lifecycle';\nimport { lifecycleEventNames } from './metric-collectors';\n\nexport interface PostHogLikeClient {\n capture: (event: {\n distinctId: string;\n event: string;\n properties?: Record<string, unknown>;\n }) => Promise<void> | void;\n}\n\nexport const trackLifecycleAssessment = async (\n client: PostHogLikeClient,\n tenantId: string,\n assessment: LifecycleAssessment\n) => {\n await client.capture({\n distinctId: tenantId,\n event: lifecycleEventNames.assessmentRun,\n properties: {\n stage: assessment.stage,\n confidence: assessment.confidence,\n axes: assessment.axes,\n },\n });\n};\n\nexport const trackLifecycleStageChange = async (\n client: PostHogLikeClient,\n tenantId: string,\n previousStage: number | undefined,\n nextStage: number\n) => {\n await client.capture({\n distinctId: tenantId,\n event: lifecycleEventNames.stageChanged,\n properties: {\n previousStage,\n nextStage,\n },\n });\n};\n"],"mappings":";;;AAWA,MAAa,2BAA2B,OACtC,QACA,UACA,eACG;AACH,OAAM,OAAO,QAAQ;EACnB,YAAY;EACZ,OAAO,oBAAoB;EAC3B,YAAY;GACV,OAAO,WAAW;GAClB,YAAY,WAAW;GACvB,MAAM,WAAW;GAClB;EACF,CAAC;;AAGJ,MAAa,4BAA4B,OACvC,QACA,UACA,eACA,cACG;AACH,OAAM,OAAO,QAAQ;EACnB,YAAY;EACZ,OAAO,oBAAoB;EAC3B,YAAY;GACV;GACA;GACD;EACF,CAAC"}
|