@lssm/lib.analytics 0.4.0 → 1.41.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/churn/predictor.js +1 -2
- package/dist/cohort/tracker.js +1 -2
- package/dist/funnel/analyzer.js +1 -2
- package/dist/growth/hypothesis-generator.js +1 -2
- package/dist/lifecycle/metric-collectors.js +1 -2
- package/dist/lifecycle/posthog-bridge.js +1 -2
- package/package.json +35 -19
- package/dist/churn/index.d.ts +0 -2
- package/dist/churn/predictor.d.ts +0 -22
- package/dist/churn/predictor.d.ts.map +0 -1
- package/dist/churn/predictor.js.map +0 -1
- package/dist/cohort/index.d.ts +0 -2
- package/dist/cohort/tracker.d.ts +0 -9
- package/dist/cohort/tracker.d.ts.map +0 -1
- package/dist/cohort/tracker.js.map +0 -1
- package/dist/funnel/analyzer.d.ts +0 -10
- package/dist/funnel/analyzer.d.ts.map +0 -1
- package/dist/funnel/analyzer.js.map +0 -1
- package/dist/funnel/index.d.ts +0 -2
- package/dist/growth/hypothesis-generator.d.ts +0 -18
- package/dist/growth/hypothesis-generator.d.ts.map +0 -1
- package/dist/growth/hypothesis-generator.js.map +0 -1
- package/dist/growth/index.d.ts +0 -2
- package/dist/index.d.ts +0 -8
- package/dist/lifecycle/index.d.ts +0 -3
- package/dist/lifecycle/metric-collectors.d.ts +0 -30
- package/dist/lifecycle/metric-collectors.d.ts.map +0 -1
- package/dist/lifecycle/metric-collectors.js.map +0 -1
- package/dist/lifecycle/posthog-bridge.d.ts +0 -15
- package/dist/lifecycle/posthog-bridge.d.ts.map +0 -1
- package/dist/lifecycle/posthog-bridge.js.map +0 -1
- package/dist/types.d.ts +0 -68
- package/dist/types.d.ts.map +0 -1
package/dist/churn/predictor.js
CHANGED
|
@@ -1,2 +1 @@
|
|
|
1
|
-
import e from"dayjs";var t=class{recencyWeight;frequencyWeight;errorWeight;decayDays;constructor(e){this.recencyWeight=e?.recencyWeight??.5,this.frequencyWeight=e?.frequencyWeight??.3,this.errorWeight=e?.errorWeight??.2,this.decayDays=e?.decayDays??14}score(e){let t=n(e,e=>e.userId),r=[];for(let[e,n]of t.entries()){let t=this.computeScore(n);r.push({userId:e,score:t,bucket:t>=.7?`high`:t>=.4?`medium`:`low`,drivers:this.drivers(n)})}return r.sort((e,t)=>t.score-e.score)}computeScore(t){if(!t.length)return 0;let n=t.sort((e,t)=>r(e)-r(t)),i=n[n.length-1];if(!i)return 0;let a=e().diff(e(i.timestamp),`day`),o=Math.max(0,1-a/this.decayDays),s=e().subtract(this.decayDays,`day`),c=n.filter(t=>e(t.timestamp).isAfter(s)),l=c.length/Math.max(this.decayDays,1),u=Math.min(1,l*5),d=c.filter(e=>e.properties?.error!==void 0||/error|failed/i.test(e.name)).length,f=Math.min(1,d/3),p=o*this.recencyWeight+u*this.frequencyWeight+(1-f)*this.errorWeight;return Number(p.toFixed(3))}drivers(t){let n=[],i=t.sort((e,t)=>r(e)-r(t)),a=i[i.length-1];if(a){let t=e().diff(e(a.timestamp),`day`);t>this.decayDays&&n.push(`Inactive for ${t} days`)}let o=t.filter(e=>e.properties?.error!==void 0||/error|failed/i.test(e.name));return o.length&&n.push(`${o.length} errors logged`),n}};function n(e,t){let n=new Map;for(let r of e){let e=t(r),i=n.get(e)??[];i.push(r),n.set(e,i)}return n}function r(e){return new Date(e.timestamp).getTime()}export{t as ChurnPredictor};
|
|
2
|
-
//# sourceMappingURL=predictor.js.map
|
|
1
|
+
import e from"dayjs";var t=class{recencyWeight;frequencyWeight;errorWeight;decayDays;constructor(e){this.recencyWeight=e?.recencyWeight??.5,this.frequencyWeight=e?.frequencyWeight??.3,this.errorWeight=e?.errorWeight??.2,this.decayDays=e?.decayDays??14}score(e){let t=n(e,e=>e.userId),r=[];for(let[e,n]of t.entries()){let t=this.computeScore(n);r.push({userId:e,score:t,bucket:t>=.7?`high`:t>=.4?`medium`:`low`,drivers:this.drivers(n)})}return r.sort((e,t)=>t.score-e.score)}computeScore(t){if(!t.length)return 0;let n=t.sort((e,t)=>r(e)-r(t)),i=n[n.length-1];if(!i)return 0;let a=e().diff(e(i.timestamp),`day`),o=Math.max(0,1-a/this.decayDays),s=e().subtract(this.decayDays,`day`),c=n.filter(t=>e(t.timestamp).isAfter(s)),l=c.length/Math.max(this.decayDays,1),u=Math.min(1,l*5),d=c.filter(e=>e.properties?.error!==void 0||/error|failed/i.test(e.name)).length,f=Math.min(1,d/3),p=o*this.recencyWeight+u*this.frequencyWeight+(1-f)*this.errorWeight;return Number(p.toFixed(3))}drivers(t){let n=[],i=t.sort((e,t)=>r(e)-r(t)),a=i[i.length-1];if(a){let t=e().diff(e(a.timestamp),`day`);t>this.decayDays&&n.push(`Inactive for ${t} days`)}let o=t.filter(e=>e.properties?.error!==void 0||/error|failed/i.test(e.name));return o.length&&n.push(`${o.length} errors logged`),n}};function n(e,t){let n=new Map;for(let r of e){let e=t(r),i=n.get(e)??[];i.push(r),n.set(e,i)}return n}function r(e){return new Date(e.timestamp).getTime()}export{t as ChurnPredictor};
|
package/dist/cohort/tracker.js
CHANGED
|
@@ -1,2 +1 @@
|
|
|
1
|
-
import e from"dayjs";var t=class{analyze(e,t){let a=r(e,e=>e.userId),o=new Map;for(let[e,r]of a.entries()){r.sort((e,t)=>s(e)-s(t));let a=r[0];if(!a)continue;let c=i(a.timestamp,t.bucket),l=o.get(c)??new n(c,t);l.addUser(e);for(let t of r)l.addEvent(e,t);o.set(c,l)}return{definition:t,cohorts:[...o.values()].map(e=>e.build())}}},n=class{users=new Set;retentionMap=new Map;ltv=0;constructor(e,t){this.key=e,this.definition=t}addUser(e){this.users.add(e)}addEvent(e,t){let n=a(this.key,t.timestamp,this.definition.bucket);if(n<0||n>=this.definition.periods)return;let r=this.retentionMap.get(n)??new Set;r.add(e),this.retentionMap.set(n,r);let i=typeof t.properties?.amount==`number`?t.properties.amount:0;this.ltv+=i}build(){let e=this.users.size||1,t=[];for(let n=0;n<this.definition.periods;n++){let r=this.retentionMap.get(n)?.size??0;t.push(Number((r/e).toFixed(3)))}return{cohortKey:this.key,users:this.users.size,retention:t,ltv:Number(this.ltv.toFixed(2))}}};function r(e,t){let n=new Map;for(let r of e){let e=t(r),i=n.get(e)??[];i.push(r),n.set(e,i)}return n}function i(t,n){let r=e(t);switch(n){case`day`:return r.startOf(`day`).format(`YYYY-MM-DD`);case`week`:return r.startOf(`week`).format(`YYYY-[W]WW`);case`month`:default:return r.startOf(`month`).format(`YYYY-MM`)}}function a(t,n,r){let i=o(t,r),a=e(n);switch(r){case`day`:return a.diff(i,`day`);case`week`:return a.diff(i,`week`);case`month`:default:return a.diff(i,`month`)}}function o(t,n){switch(n){case`day`:return e(t,`YYYY-MM-DD`);case`week`:return e(t.replace(`W`,``),`YYYY-ww`);case`month`:default:return e(t,`YYYY-MM`)}}function s(e){return new Date(e.timestamp).getTime()}export{t as CohortTracker};
|
|
2
|
-
//# sourceMappingURL=tracker.js.map
|
|
1
|
+
import e from"dayjs";var t=class{analyze(e,t){let a=r(e,e=>e.userId),o=new Map;for(let[e,r]of a.entries()){r.sort((e,t)=>s(e)-s(t));let a=r[0];if(!a)continue;let c=i(a.timestamp,t.bucket),l=o.get(c)??new n(c,t);l.addUser(e);for(let t of r)l.addEvent(e,t);o.set(c,l)}return{definition:t,cohorts:[...o.values()].map(e=>e.build())}}},n=class{users=new Set;retentionMap=new Map;ltv=0;constructor(e,t){this.key=e,this.definition=t}addUser(e){this.users.add(e)}addEvent(e,t){let n=a(this.key,t.timestamp,this.definition.bucket);if(n<0||n>=this.definition.periods)return;let r=this.retentionMap.get(n)??new Set;r.add(e),this.retentionMap.set(n,r);let i=typeof t.properties?.amount==`number`?t.properties.amount:0;this.ltv+=i}build(){let e=this.users.size||1,t=[];for(let n=0;n<this.definition.periods;n++){let r=this.retentionMap.get(n)?.size??0;t.push(Number((r/e).toFixed(3)))}return{cohortKey:this.key,users:this.users.size,retention:t,ltv:Number(this.ltv.toFixed(2))}}};function r(e,t){let n=new Map;for(let r of e){let e=t(r),i=n.get(e)??[];i.push(r),n.set(e,i)}return n}function i(t,n){let r=e(t);switch(n){case`day`:return r.startOf(`day`).format(`YYYY-MM-DD`);case`week`:return r.startOf(`week`).format(`YYYY-[W]WW`);case`month`:default:return r.startOf(`month`).format(`YYYY-MM`)}}function a(t,n,r){let i=o(t,r),a=e(n);switch(r){case`day`:return a.diff(i,`day`);case`week`:return a.diff(i,`week`);case`month`:default:return a.diff(i,`month`)}}function o(t,n){switch(n){case`day`:return e(t,`YYYY-MM-DD`);case`week`:return e(t.replace(`W`,``),`YYYY-ww`);case`month`:default:return e(t,`YYYY-MM`)}}function s(e){return new Date(e.timestamp).getTime()}export{t as CohortTracker};
|
package/dist/funnel/analyzer.js
CHANGED
|
@@ -1,2 +1 @@
|
|
|
1
|
-
var e=class{analyze(e,n){let r=(n.windowHours??72)*60*60*1e3,i=t(e),a=n.steps.map(()=>0);for(let e of i.values())this.evaluateUser(e,n.steps,r).forEach((e,t)=>{e&&(a[t]=(a[t]??0)+1)});let o=i.size;return{definition:n,totalUsers:o,steps:n.steps.map((e,t)=>{let n=t===0?o:a[t-1]||1,r=a[t]??0,i=n===0?0:Number((r/n).toFixed(3));return{step:e,count:r,conversionRate:i,dropOffRate:Number((1-i).toFixed(3))}})}}evaluateUser(e,t,n){let r=[...e].sort((e,t)=>new Date(e.timestamp).getTime()-new Date(t.timestamp).getTime()),i=Array(t.length).fill(!1),a=0,o;for(let e of r){let r=t[a];if(!r)break;if(e.name!==r.eventName||r.match&&!r.match(e))continue;let s=new Date(e.timestamp).getTime();if(a===0){o=s,i[a]=!0,a+=1;continue}o&&s-o<=n&&(i[a]=!0,a+=1)}return i}};function t(e){let t=new Map;for(let n of e){let e=t.get(n.userId)??[];e.push(n),t.set(n.userId,e)}return t}export{e as FunnelAnalyzer};
|
|
2
|
-
//# sourceMappingURL=analyzer.js.map
|
|
1
|
+
var e=class{analyze(e,n){let r=(n.windowHours??72)*60*60*1e3,i=t(e),a=n.steps.map(()=>0);for(let e of i.values())this.evaluateUser(e,n.steps,r).forEach((e,t)=>{e&&(a[t]=(a[t]??0)+1)});let o=i.size;return{definition:n,totalUsers:o,steps:n.steps.map((e,t)=>{let n=t===0?o:a[t-1]||1,r=a[t]??0,i=n===0?0:Number((r/n).toFixed(3));return{step:e,count:r,conversionRate:i,dropOffRate:Number((1-i).toFixed(3))}})}}evaluateUser(e,t,n){let r=[...e].sort((e,t)=>new Date(e.timestamp).getTime()-new Date(t.timestamp).getTime()),i=Array(t.length).fill(!1),a=0,o;for(let e of r){let r=t[a];if(!r)break;if(e.name!==r.eventName||r.match&&!r.match(e))continue;let s=new Date(e.timestamp).getTime();if(a===0){o=s,i[a]=!0,a+=1;continue}o&&s-o<=n&&(i[a]=!0,a+=1)}return i}};function t(e){let t=new Map;for(let n of e){let e=t.get(n.userId)??[];e.push(n),t.set(n.userId,e)}return t}export{e as FunnelAnalyzer};
|
|
@@ -1,2 +1 @@
|
|
|
1
|
-
var e=class{minDelta;constructor(e){this.minDelta=e?.minDelta??.05}generate(e){return e.map(e=>this.fromMetric(e)).filter(e=>!!e)}fromMetric(e){let t=this.delta(e);if(Math.abs(t)<this.minDelta)return null;let n=t>0?`rising`:`declining`;return{statement:this.statement(e,t,n),metric:e.name,confidence:Math.abs(t)>.2?`high`:`medium`,impact:this.impact(e)}}delta(e){if(e.previous==null)return 0;let t=e.previous||1;return(e.current-t)/Math.abs(t)}impact(e){return e.target&&e.current<e.target*.8?`high`:e.target&&e.current<e.target?`medium`:`low`}statement(e,t,n){let r=Math.abs(parseFloat((t*100).toFixed(1)));return n===`declining`?`${e.name} is down ${r}% vs last period; test new onboarding prompts to recover activation.`:`${e.name} grew ${r}% period-over-period; double down with expanded experiment or pricing test.`}};export{e as GrowthHypothesisGenerator};
|
|
2
|
-
//# sourceMappingURL=hypothesis-generator.js.map
|
|
1
|
+
var e=class{minDelta;constructor(e){this.minDelta=e?.minDelta??.05}generate(e){return e.map(e=>this.fromMetric(e)).filter(e=>!!e)}fromMetric(e){let t=this.delta(e);if(Math.abs(t)<this.minDelta)return null;let n=t>0?`rising`:`declining`;return{statement:this.statement(e,t,n),metric:e.name,confidence:Math.abs(t)>.2?`high`:`medium`,impact:this.impact(e)}}delta(e){if(e.previous==null)return 0;let t=e.previous||1;return(e.current-t)/Math.abs(t)}impact(e){return e.target&&e.current<e.target*.8?`high`:e.target&&e.current<e.target?`medium`:`low`}statement(e,t,n){let r=Math.abs(parseFloat((t*100).toFixed(1)));return n===`declining`?`${e.name} is down ${r}% vs last period; test new onboarding prompts to recover activation.`:`${e.name} grew ${r}% period-over-period; double down with expanded experiment or pricing test.`}};export{e as GrowthHypothesisGenerator};
|
|
@@ -1,2 +1 @@
|
|
|
1
|
-
const e=async e=>{let[t,n,r,i,a,o,s]=await Promise.all([e.getActiveUsers(),e.getWeeklyActiveUsers?.(),e.getRetentionRate?.(),e.getMonthlyRecurringRevenue?.(),e.getCustomerCount?.(),e.getTeamSize?.(),e.getBurnMultiple?.()]);return{activeUsers:t,weeklyActiveUsers:n,retentionRate:r,monthlyRecurringRevenue:i,customerCount:a,teamSize:o,burnMultiple:s}},t=(e,t)=>Object.entries(e).filter(([,e])=>e!=null).map(([e,n])=>({id:`lifecycle-metric:${e}`,kind:`metric`,source:`analytics`,name:e,value:n,weight:1,confidence:.8,details:t?{tenantId:t}:void 0,capturedAt:new Date().toISOString()})),n={assessmentRun:`lifecycle_assessment_run`,stageChanged:`lifecycle_stage_changed`,guidanceConsumed:`lifecycle_guidance_consumed`},r=e=>({name:n.stageChanged,userId:`system`,tenantId:e.tenantId,timestamp:new Date,properties:{...e}});export{e as collectLifecycleMetrics,r as createStageChangeEvent,n as lifecycleEventNames,t as metricsToSignals};
|
|
2
|
-
//# sourceMappingURL=metric-collectors.js.map
|
|
1
|
+
const e=async e=>{let[t,n,r,i,a,o,s]=await Promise.all([e.getActiveUsers(),e.getWeeklyActiveUsers?.(),e.getRetentionRate?.(),e.getMonthlyRecurringRevenue?.(),e.getCustomerCount?.(),e.getTeamSize?.(),e.getBurnMultiple?.()]);return{activeUsers:t,weeklyActiveUsers:n,retentionRate:r,monthlyRecurringRevenue:i,customerCount:a,teamSize:o,burnMultiple:s}},t=(e,t)=>Object.entries(e).filter(([,e])=>e!=null).map(([e,n])=>({id:`lifecycle-metric:${e}`,kind:`metric`,source:`analytics`,name:e,value:n,weight:1,confidence:.8,details:t?{tenantId:t}:void 0,capturedAt:new Date().toISOString()})),n={assessmentRun:`lifecycle_assessment_run`,stageChanged:`lifecycle_stage_changed`,guidanceConsumed:`lifecycle_guidance_consumed`},r=e=>({name:n.stageChanged,userId:`system`,tenantId:e.tenantId,timestamp:new Date,properties:{...e}});export{e as collectLifecycleMetrics,r as createStageChangeEvent,n as lifecycleEventNames,t as metricsToSignals};
|
|
@@ -1,2 +1 @@
|
|
|
1
|
-
import{lifecycleEventNames as e}from"./metric-collectors.js";const t=async(t,n,r)=>{await t.capture({distinctId:n,event:e.assessmentRun,properties:{stage:r.stage,confidence:r.confidence,axes:r.axes}})},n=async(t,n,r,i)=>{await t.capture({distinctId:n,event:e.stageChanged,properties:{previousStage:r,nextStage:i}})};export{t as trackLifecycleAssessment,n as trackLifecycleStageChange};
|
|
2
|
-
//# sourceMappingURL=posthog-bridge.js.map
|
|
1
|
+
import{lifecycleEventNames as e}from"./metric-collectors.js";const t=async(t,n,r)=>{await t.capture({distinctId:n,event:e.assessmentRun,properties:{stage:r.stage,confidence:r.confidence,axes:r.axes}})},n=async(t,n,r,i)=>{await t.capture({distinctId:n,event:e.stageChanged,properties:{previousStage:r,nextStage:i}})};export{t as trackLifecycleAssessment,n as trackLifecycleStageChange};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lssm/lib.analytics",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "1.41.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.js",
|
|
@@ -22,32 +22,48 @@
|
|
|
22
22
|
"test": "bun run"
|
|
23
23
|
},
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"@lssm/lib.lifecycle": "
|
|
25
|
+
"@lssm/lib.lifecycle": "workspace:*",
|
|
26
26
|
"dayjs": "^1.11.13"
|
|
27
27
|
},
|
|
28
28
|
"devDependencies": {
|
|
29
|
-
"@lssm/tool.tsdown": "
|
|
30
|
-
"@lssm/tool.typescript": "
|
|
31
|
-
"tsdown": "^0.
|
|
29
|
+
"@lssm/tool.tsdown": "workspace:*",
|
|
30
|
+
"@lssm/tool.typescript": "workspace:*",
|
|
31
|
+
"tsdown": "^0.17.4",
|
|
32
32
|
"typescript": "^5.9.3"
|
|
33
33
|
},
|
|
34
34
|
"exports": {
|
|
35
|
-
".": "./
|
|
36
|
-
"./churn": "./
|
|
37
|
-
"./churn/predictor": "./
|
|
38
|
-
"./cohort": "./
|
|
39
|
-
"./cohort/tracker": "./
|
|
40
|
-
"./funnel": "./
|
|
41
|
-
"./funnel/analyzer": "./
|
|
42
|
-
"./growth": "./
|
|
43
|
-
"./growth/hypothesis-generator": "./
|
|
44
|
-
"./lifecycle": "./
|
|
45
|
-
"./lifecycle/metric-collectors": "./
|
|
46
|
-
"./lifecycle/posthog-bridge": "./
|
|
47
|
-
"./types": "./
|
|
35
|
+
".": "./src/index.ts",
|
|
36
|
+
"./churn": "./src/churn/index.ts",
|
|
37
|
+
"./churn/predictor": "./src/churn/predictor.ts",
|
|
38
|
+
"./cohort": "./src/cohort/index.ts",
|
|
39
|
+
"./cohort/tracker": "./src/cohort/tracker.ts",
|
|
40
|
+
"./funnel": "./src/funnel/index.ts",
|
|
41
|
+
"./funnel/analyzer": "./src/funnel/analyzer.ts",
|
|
42
|
+
"./growth": "./src/growth/index.ts",
|
|
43
|
+
"./growth/hypothesis-generator": "./src/growth/hypothesis-generator.ts",
|
|
44
|
+
"./lifecycle": "./src/lifecycle/index.ts",
|
|
45
|
+
"./lifecycle/metric-collectors": "./src/lifecycle/metric-collectors.ts",
|
|
46
|
+
"./lifecycle/posthog-bridge": "./src/lifecycle/posthog-bridge.ts",
|
|
47
|
+
"./types": "./src/types.ts",
|
|
48
48
|
"./*": "./*"
|
|
49
49
|
},
|
|
50
50
|
"publishConfig": {
|
|
51
|
-
"access": "public"
|
|
51
|
+
"access": "public",
|
|
52
|
+
"exports": {
|
|
53
|
+
".": "./dist/index.js",
|
|
54
|
+
"./churn": "./dist/churn/index.js",
|
|
55
|
+
"./churn/predictor": "./dist/churn/predictor.js",
|
|
56
|
+
"./cohort": "./dist/cohort/index.js",
|
|
57
|
+
"./cohort/tracker": "./dist/cohort/tracker.js",
|
|
58
|
+
"./funnel": "./dist/funnel/index.js",
|
|
59
|
+
"./funnel/analyzer": "./dist/funnel/analyzer.js",
|
|
60
|
+
"./growth": "./dist/growth/index.js",
|
|
61
|
+
"./growth/hypothesis-generator": "./dist/growth/hypothesis-generator.js",
|
|
62
|
+
"./lifecycle": "./dist/lifecycle/index.js",
|
|
63
|
+
"./lifecycle/metric-collectors": "./dist/lifecycle/metric-collectors.js",
|
|
64
|
+
"./lifecycle/posthog-bridge": "./dist/lifecycle/posthog-bridge.js",
|
|
65
|
+
"./types": "./dist/types.js",
|
|
66
|
+
"./*": "./*"
|
|
67
|
+
}
|
|
52
68
|
}
|
|
53
69
|
}
|
package/dist/churn/index.d.ts
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import { AnalyticsEvent, ChurnSignal } from "../types.js";
|
|
2
|
-
|
|
3
|
-
//#region src/churn/predictor.d.ts
|
|
4
|
-
interface ChurnPredictorOptions {
|
|
5
|
-
recencyWeight?: number;
|
|
6
|
-
frequencyWeight?: number;
|
|
7
|
-
errorWeight?: number;
|
|
8
|
-
decayDays?: number;
|
|
9
|
-
}
|
|
10
|
-
declare class ChurnPredictor {
|
|
11
|
-
private readonly recencyWeight;
|
|
12
|
-
private readonly frequencyWeight;
|
|
13
|
-
private readonly errorWeight;
|
|
14
|
-
private readonly decayDays;
|
|
15
|
-
constructor(options?: ChurnPredictorOptions);
|
|
16
|
-
score(events: AnalyticsEvent[]): ChurnSignal[];
|
|
17
|
-
private computeScore;
|
|
18
|
-
private drivers;
|
|
19
|
-
}
|
|
20
|
-
//#endregion
|
|
21
|
-
export { ChurnPredictor, ChurnPredictorOptions };
|
|
22
|
-
//# sourceMappingURL=predictor.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"predictor.d.ts","names":[],"sources":["../../src/churn/predictor.ts"],"sourcesContent":[],"mappings":";;;UAGiB,qBAAA;;EAAA,eAAA,CAAA,EAAA,MAAqB;EAOzB,WAAA,CAAA,EAAA,MAAc;EAMH,SAAA,CAAA,EAAA,MAAA;;AAOW,cAbtB,cAAA,CAasB;EAAW,iBAAA,aAAA;;;;wBAPtB;gBAOR,mBAAmB"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"predictor.js","names":["signals: ChurnSignal[]","drivers: string[]"],"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":"qBAUA,IAAa,EAAb,KAA4B,CAC1B,cACA,gBACA,YACA,UAEA,YAAY,EAAiC,CAC3C,KAAK,cAAgB,GAAS,eAAiB,GAC/C,KAAK,gBAAkB,GAAS,iBAAmB,GACnD,KAAK,YAAc,GAAS,aAAe,GAC3C,KAAK,UAAY,GAAS,WAAa,GAGzC,MAAM,EAAyC,CAC7C,IAAM,EAAU,EAAQ,EAAS,GAAU,EAAM,OAAO,CAClDA,EAAyB,EAAE,CACjC,IAAK,GAAM,CAAC,EAAQ,KAAe,EAAQ,SAAS,CAAE,CACpD,IAAM,EAAQ,KAAK,aAAa,EAAW,CAC3C,EAAQ,KAAK,CACX,SACA,QACA,OAAQ,GAAS,GAAM,OAAS,GAAS,GAAM,SAAW,MAC1D,QAAS,KAAK,QAAQ,EAAW,CAClC,CAAC,CAEJ,OAAO,EAAQ,MAAM,EAAG,IAAM,EAAE,MAAQ,EAAE,MAAM,CAGlD,aAAqB,EAAkC,CACrD,GAAI,CAAC,EAAO,OAAQ,MAAO,GAC3B,IAAM,EAAS,EAAO,MAAM,EAAG,IAAM,EAAO,EAAE,CAAG,EAAO,EAAE,CAAC,CACrD,EAAY,EAAO,EAAO,OAAS,GACzC,GAAI,CAAC,EAAW,MAAO,GACvB,IAAM,EAAgB,GAAO,CAAC,KAAK,EAAM,EAAU,UAAU,CAAE,MAAM,CAC/D,EAAe,KAAK,IAAI,EAAG,EAAI,EAAgB,KAAK,UAAU,CAE9D,EAAc,GAAO,CAAC,SAAS,KAAK,UAAW,MAAM,CACrD,EAAe,EAAO,OAAQ,GAClC,EAAM,EAAM,UAAU,CAAC,QAAQ,EAAY,CAC5C,CACK,EAAgB,EAAa,OAAS,KAAK,IAAI,KAAK,UAAW,EAAE,CACjE,EAAiB,KAAK,IAAI,EAAG,EAAgB,EAAE,CAE/C,EAAc,EAAa,OAC9B,GACQ,EAAM,YAAY,QAAU,QACnC,gBAAgB,KAAK,EAAM,KAAK,CACnC,CAAC,OACI,EAAa,KAAK,IAAI,EAAG,EAAc,EAAE,CAEzC,EACJ,EAAe,KAAK,cACpB,EAAiB,KAAK,iBACrB,EAAI,GAAc,KAAK,YAC1B,OAAO,OAAO,EAAM,QAAQ,EAAE,CAAC,CAGjC,QAAgB,EAAoC,CAClD,IAAMC,EAAoB,EAAE,CACtB,EAAS,EAAO,MAAM,EAAG,IAAM,EAAO,EAAE,CAAG,EAAO,EAAE,CAAC,CACrD,EAAY,EAAO,EAAO,OAAS,GACzC,GAAI,EAAW,CACb,IAAM,EAAO,GAAO,CAAC,KAAK,EAAM,EAAU,UAAU,CAAE,MAAM,CACxD,EAAO,KAAK,WAAW,EAAQ,KAAK,gBAAgB,EAAK,OAAO,CAEtE,IAAM,EAAc,EAAO,OACxB,GACQ,EAAM,YAAY,QAAU,QACnC,gBAAgB,KAAK,EAAM,KAAK,CACnC,CAED,OADI,EAAY,QAAQ,EAAQ,KAAK,GAAG,EAAY,OAAO,gBAAgB,CACpE,IAIX,SAAS,EACP,EACA,EACkB,CAClB,IAAM,EAAM,IAAI,IAChB,IAAK,IAAM,KAAQ,EAAO,CACxB,IAAM,EAAM,EAAS,EAAK,CACpB,EAAO,EAAI,IAAI,EAAI,EAAI,EAAE,CAC/B,EAAK,KAAK,EAAK,CACf,EAAI,IAAI,EAAK,EAAK,CAEpB,OAAO,EAGT,SAAS,EAAO,EAAuB,CACrC,OAAO,IAAI,KAAK,EAAM,UAAU,CAAC,SAAS"}
|
package/dist/cohort/index.d.ts
DELETED
package/dist/cohort/tracker.d.ts
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import { AnalyticsEvent, CohortAnalysis, CohortDefinition } from "../types.js";
|
|
2
|
-
|
|
3
|
-
//#region src/cohort/tracker.d.ts
|
|
4
|
-
declare class CohortTracker {
|
|
5
|
-
analyze(events: AnalyticsEvent[], definition: CohortDefinition): CohortAnalysis;
|
|
6
|
-
}
|
|
7
|
-
//#endregion
|
|
8
|
-
export { CohortTracker };
|
|
9
|
-
//# sourceMappingURL=tracker.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"tracker.d.ts","names":[],"sources":["../../src/cohort/tracker.ts"],"sourcesContent":[],"mappings":";;;cAQa,aAAA;kBAED,8BACI,mBACX;AAJL"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"tracker.js","names":["key: string","definition: CohortDefinition","retention: number[]"],"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,10 +0,0 @@
|
|
|
1
|
-
import { AnalyticsEvent, FunnelAnalysis, FunnelDefinition } from "../types.js";
|
|
2
|
-
|
|
3
|
-
//#region src/funnel/analyzer.d.ts
|
|
4
|
-
declare class FunnelAnalyzer {
|
|
5
|
-
analyze(events: AnalyticsEvent[], definition: FunnelDefinition): FunnelAnalysis;
|
|
6
|
-
private evaluateUser;
|
|
7
|
-
}
|
|
8
|
-
//#endregion
|
|
9
|
-
export { FunnelAnalyzer };
|
|
10
|
-
//# sourceMappingURL=analyzer.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"analyzer.d.ts","names":[],"sources":["../../src/funnel/analyzer.ts"],"sourcesContent":[],"mappings":";;;cAQa,cAAA;kBAED,8BACI,mBACX;EAJQ,QAAA,YAAc"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"analyzer.js","names":["completion: boolean[]","anchorTime: number | undefined"],"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,EAAb,KAA4B,CAC1B,QACE,EACA,EACgB,CAChB,IAAM,GAAY,EAAW,aAAe,IAAM,GAAK,GAAK,IACtD,EAAe,EAAY,EAAO,CAClC,EAAa,EAAW,MAAM,QAAU,EAAE,CAEhD,IAAK,IAAM,KAAc,EAAa,QAAQ,CACpB,KAAK,aAC3B,EACA,EAAW,MACX,EACD,CACe,SAAS,EAAK,IAAY,CACpC,IACF,EAAW,IAAY,EAAW,IAAY,GAAK,IAErD,CAGJ,IAAM,EAAa,EAAa,KAUhC,MAAO,CACL,aACA,aACA,MAZgC,EAAW,MAAM,KAAK,EAAM,IAAU,CACtE,IAAM,EAAY,IAAU,EAAI,EAAa,EAAW,EAAQ,IAAM,EAChE,EAAQ,EAAW,IAAU,EAC7B,EACJ,IAAc,EAAI,EAAI,QAAQ,EAAQ,GAAW,QAAQ,EAAE,CAAC,CAE9D,MAAO,CAAE,OAAM,QAAO,iBAAgB,YADlB,QAAQ,EAAI,GAAgB,QAAQ,EAAE,CAAC,CACR,EACnD,CAMD,CAGH,aACE,EACA,EACA,EACA,CACA,IAAM,EAAS,CAAC,GAAG,EAAO,CAAC,MACxB,EAAG,IACF,IAAI,KAAK,EAAE,UAAU,CAAC,SAAS,CAAG,IAAI,KAAK,EAAE,UAAU,CAAC,SAAS,CACpE,CACKA,EAAwB,MAAM,EAAM,OAAO,CAAC,KAAK,GAAM,CACzD,EAAS,EACTC,EAEJ,IAAK,IAAM,KAAS,EAAQ,CAC1B,IAAM,EAAO,EAAM,GACnB,GAAI,CAAC,EAAM,MAEX,GADI,EAAM,OAAS,EAAK,WACpB,EAAK,OAAS,CAAC,EAAK,MAAM,EAAM,CAAE,SAEtC,IAAM,EAAY,IAAI,KAAK,EAAM,UAAU,CAAC,SAAS,CACrD,GAAI,IAAW,EAAG,CAChB,EAAa,EACb,EAAW,GAAU,GACrB,GAAU,EACV,SAGE,GAAc,EAAY,GAAc,IAC1C,EAAW,GAAU,GACrB,GAAU,GAId,OAAO,IAIX,SAAS,EAAY,EAAyD,CAC5E,IAAM,EAAM,IAAI,IAChB,IAAK,IAAM,KAAS,EAAQ,CAC1B,IAAM,EAAO,EAAI,IAAI,EAAM,OAAO,EAAI,EAAE,CACxC,EAAK,KAAK,EAAM,CAChB,EAAI,IAAI,EAAM,OAAQ,EAAK,CAE7B,OAAO"}
|
package/dist/funnel/index.d.ts
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import { GrowthHypothesis, GrowthMetric } from "../types.js";
|
|
2
|
-
|
|
3
|
-
//#region src/growth/hypothesis-generator.d.ts
|
|
4
|
-
interface HypothesisGeneratorOptions {
|
|
5
|
-
minDelta?: number;
|
|
6
|
-
}
|
|
7
|
-
declare class GrowthHypothesisGenerator {
|
|
8
|
-
private readonly minDelta;
|
|
9
|
-
constructor(options?: HypothesisGeneratorOptions);
|
|
10
|
-
generate(metrics: GrowthMetric[]): GrowthHypothesis[];
|
|
11
|
-
private fromMetric;
|
|
12
|
-
private delta;
|
|
13
|
-
private impact;
|
|
14
|
-
private statement;
|
|
15
|
-
}
|
|
16
|
-
//#endregion
|
|
17
|
-
export { GrowthHypothesisGenerator, HypothesisGeneratorOptions };
|
|
18
|
-
//# sourceMappingURL=hypothesis-generator.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"hypothesis-generator.d.ts","names":[],"sources":["../../src/growth/hypothesis-generator.ts"],"sourcesContent":[],"mappings":";;;UAEiB,0BAAA;;AAAjB;AAIa,cAAA,yBAAA,CAAyB;EAGd,iBAAA,QAAA;EAIJ,WAAA,CAAA,OAAA,CAAA,EAJI,0BAIJ;EAAiB,QAAA,CAAA,OAAA,EAAjB,YAAiB,EAAA,CAAA,EAAA,gBAAA,EAAA;EAAgB,QAAA,UAAA"}
|
|
@@ -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,EAAb,KAAuC,CACrC,SAEA,YAAY,EAAsC,CAChD,KAAK,SAAW,GAAS,UAAY,IAGvC,SAAS,EAA6C,CACpD,OAAO,EACJ,IAAK,GAAW,KAAK,WAAW,EAAO,CAAC,CACxC,OAAQ,GACP,EAAQ,EACT,CAGL,WAAmB,EAA+C,CAChE,IAAM,EAAS,KAAK,MAAM,EAAO,CACjC,GAAI,KAAK,IAAI,EAAO,CAAG,KAAK,SAAU,OAAO,KAC7C,IAAM,EAAY,EAAS,EAAI,SAAW,YAE1C,MAAO,CACL,UAFgB,KAAK,UAAU,EAAQ,EAAQ,EAAU,CAGzD,OAAQ,EAAO,KACf,WAAY,KAAK,IAAI,EAAO,CAAG,GAAM,OAAS,SAC9C,OAAQ,KAAK,OAAO,EAAO,CAC5B,CAGH,MAAc,EAA8B,CAC1C,GAAI,EAAO,UAAY,KAAM,MAAO,GACpC,IAAM,EAAO,EAAO,UAAY,EAChC,OAAQ,EAAO,QAAU,GAAQ,KAAK,IAAI,EAAK,CAGjD,OAAe,EAAkD,CAG/D,OAFI,EAAO,QAAU,EAAO,QAAU,EAAO,OAAS,GAAY,OAC9D,EAAO,QAAU,EAAO,QAAU,EAAO,OAAe,SACrD,MAGT,UACE,EACA,EACA,EACQ,CACR,IAAM,EAAU,KAAK,IAAI,YAAY,EAAS,KAAK,QAAQ,EAAE,CAAC,CAAC,CAI/D,OAHI,IAAc,YACT,GAAG,EAAO,KAAK,WAAW,EAAQ,sEAEpC,GAAG,EAAO,KAAK,QAAQ,EAAQ"}
|
package/dist/growth/index.d.ts
DELETED
package/dist/index.d.ts
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import { AnalyticsEvent, ChurnSignal, CohortAnalysis, CohortDefinition, CohortEvent, CohortStats, FunnelAnalysis, FunnelDefinition, FunnelStep, FunnelStepResult, GrowthHypothesis, GrowthMetric } from "./types.js";
|
|
2
|
-
import { ChurnPredictor, ChurnPredictorOptions } from "./churn/predictor.js";
|
|
3
|
-
import { CohortTracker } from "./cohort/tracker.js";
|
|
4
|
-
import { FunnelAnalyzer } from "./funnel/analyzer.js";
|
|
5
|
-
import { GrowthHypothesisGenerator, HypothesisGeneratorOptions } from "./growth/hypothesis-generator.js";
|
|
6
|
-
import { LifecycleMetricSource, LifecycleStageChangePayload, collectLifecycleMetrics, createStageChangeEvent, lifecycleEventNames, metricsToSignals } from "./lifecycle/metric-collectors.js";
|
|
7
|
-
import { PostHogLikeClient, trackLifecycleAssessment, trackLifecycleStageChange } from "./lifecycle/posthog-bridge.js";
|
|
8
|
-
export { AnalyticsEvent, ChurnPredictor, ChurnPredictorOptions, ChurnSignal, CohortAnalysis, CohortDefinition, CohortEvent, CohortStats, CohortTracker, FunnelAnalysis, FunnelAnalyzer, FunnelDefinition, FunnelStep, FunnelStepResult, GrowthHypothesis, GrowthHypothesisGenerator, GrowthMetric, HypothesisGeneratorOptions, LifecycleMetricSource, LifecycleStageChangePayload, PostHogLikeClient, collectLifecycleMetrics, createStageChangeEvent, lifecycleEventNames, metricsToSignals, trackLifecycleAssessment, trackLifecycleStageChange };
|
|
@@ -1,3 +0,0 @@
|
|
|
1
|
-
import { LifecycleMetricSource, LifecycleStageChangePayload, collectLifecycleMetrics, createStageChangeEvent, lifecycleEventNames, metricsToSignals } from "./metric-collectors.js";
|
|
2
|
-
import { PostHogLikeClient, trackLifecycleAssessment, trackLifecycleStageChange } from "./posthog-bridge.js";
|
|
3
|
-
export { LifecycleMetricSource, LifecycleStageChangePayload, PostHogLikeClient, collectLifecycleMetrics, createStageChangeEvent, lifecycleEventNames, metricsToSignals, trackLifecycleAssessment, trackLifecycleStageChange };
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import { AnalyticsEvent } from "../types.js";
|
|
2
|
-
import { LifecycleMetricSnapshot, LifecycleSignal, LifecycleStage } from "@lssm/lib.lifecycle";
|
|
3
|
-
|
|
4
|
-
//#region src/lifecycle/metric-collectors.d.ts
|
|
5
|
-
interface LifecycleMetricSource {
|
|
6
|
-
getActiveUsers(): Promise<number | undefined>;
|
|
7
|
-
getWeeklyActiveUsers?(): Promise<number | undefined>;
|
|
8
|
-
getRetentionRate?(): Promise<number | undefined>;
|
|
9
|
-
getMonthlyRecurringRevenue?(): Promise<number | undefined>;
|
|
10
|
-
getCustomerCount?(): Promise<number | undefined>;
|
|
11
|
-
getTeamSize?(): Promise<number | undefined>;
|
|
12
|
-
getBurnMultiple?(): Promise<number | undefined>;
|
|
13
|
-
}
|
|
14
|
-
declare const collectLifecycleMetrics: (source: LifecycleMetricSource) => Promise<LifecycleMetricSnapshot>;
|
|
15
|
-
declare const metricsToSignals: (metrics: LifecycleMetricSnapshot, tenantId?: string) => LifecycleSignal[];
|
|
16
|
-
declare const lifecycleEventNames: {
|
|
17
|
-
readonly assessmentRun: "lifecycle_assessment_run";
|
|
18
|
-
readonly stageChanged: "lifecycle_stage_changed";
|
|
19
|
-
readonly guidanceConsumed: "lifecycle_guidance_consumed";
|
|
20
|
-
};
|
|
21
|
-
interface LifecycleStageChangePayload {
|
|
22
|
-
tenantId?: string;
|
|
23
|
-
previousStage?: LifecycleStage;
|
|
24
|
-
nextStage: LifecycleStage;
|
|
25
|
-
confidence: number;
|
|
26
|
-
}
|
|
27
|
-
declare const createStageChangeEvent: (payload: LifecycleStageChangePayload) => AnalyticsEvent;
|
|
28
|
-
//#endregion
|
|
29
|
-
export { LifecycleMetricSource, LifecycleStageChangePayload, collectLifecycleMetrics, createStageChangeEvent, lifecycleEventNames, metricsToSignals };
|
|
30
|
-
//# sourceMappingURL=metric-collectors.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"metric-collectors.d.ts","names":[],"sources":["../../src/lifecycle/metric-collectors.ts"],"sourcesContent":[],"mappings":";;;;UAOiB,qBAAA;oBACG;EADH,oBAAA,GAAA,EAEU,OAFW,CAAA,MAAA,GAAA,SAAA,CAAA;EAClB,gBAAA,GAAA,EAEG,OAFH,CAAA,MAAA,GAAA,SAAA,CAAA;EACO,0BAAA,GAAA,EAEM,OAFN,CAAA,MAAA,GAAA,SAAA,CAAA;EACJ,gBAAA,GAAA,EAEA,OAFA,CAAA,MAAA,GAAA,SAAA,CAAA;EACU,WAAA,GAAA,EAEf,OAFe,CAAA,MAAA,GAAA,SAAA,CAAA;EACV,eAAA,GAAA,EAED,OAFC,CAAA,MAAA,GAAA,SAAA,CAAA;;AAED,cAGT,uBAHS,EAAA,CAAA,MAAA,EAIZ,qBAJY,EAAA,GAKnB,OALmB,CAKX,uBALW,CAAA;AAAO,cAmChB,gBAnCgB,EAAA,CAAA,OAAA,EAoClB,uBApCkB,EAAA,QAAA,CAAA,EAAA,MAAA,EAAA,GAsC1B,eAtC0B,EAAA;AAGhB,cAkDA,mBApBZ,EAAA;EA7BS,SAAA,aAAA,EAAA,0BAAA;EACC,SAAA,YAAA,EAAA,yBAAA;EAAR,SAAA,gBAAA,EAAA,6BAAA;CAAO;AA8BG,UAwBI,2BAAA,CAvBN;EAiBE,QAAA,CAAA,EAAA,MAAA;EAMI,aAAA,CAAA,EAEC,cAF0B;EAO/B,SAAA,EAJA,cAYX;;;cARW,kCACF,gCACR"}
|
|
@@ -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 '@lssm/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,EAA0B,KACrC,IACqC,CACrC,GAAM,CACJ,EACA,EACA,EACA,EACA,EACA,EACA,GACE,MAAM,QAAQ,IAAI,CACpB,EAAO,gBAAgB,CACvB,EAAO,wBAAwB,CAC/B,EAAO,oBAAoB,CAC3B,EAAO,8BAA8B,CACrC,EAAO,oBAAoB,CAC3B,EAAO,eAAe,CACtB,EAAO,mBAAmB,CAC3B,CAAC,CAEF,MAAO,CACL,cACA,oBACA,gBACA,0BACA,gBACA,WACA,eACD,EAGU,GACX,EACA,IAEA,OAAO,QAAQ,EAAQ,CACpB,QAAQ,EAAG,KAAW,GAAiC,KAAK,CAC5D,KAAK,CAAC,EAAW,MAAY,CAC5B,GAAI,oBAAoB,IACxB,KAAM,SACN,OAAQ,YACR,KAAM,EACN,QACA,OAAQ,EACR,WAAY,GACZ,QAAS,EAAW,CAAE,WAAU,CAAG,IAAA,GACnC,WAAY,IAAI,MAAM,CAAC,aAAa,CACrC,EAAE,CAEM,EAAsB,CACjC,cAAe,2BACf,aAAc,0BACd,iBAAkB,8BACnB,CASY,EACX,IACoB,CACpB,KAAM,EAAoB,aAC1B,OAAQ,SACR,SAAU,EAAQ,SAClB,UAAW,IAAI,KACf,WAAY,CAAE,GAAG,EAAS,CAC3B"}
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import { LifecycleAssessment } from "@lssm/lib.lifecycle";
|
|
2
|
-
|
|
3
|
-
//#region src/lifecycle/posthog-bridge.d.ts
|
|
4
|
-
interface PostHogLikeClient {
|
|
5
|
-
capture: (event: {
|
|
6
|
-
distinctId: string;
|
|
7
|
-
event: string;
|
|
8
|
-
properties?: Record<string, unknown>;
|
|
9
|
-
}) => Promise<void> | void;
|
|
10
|
-
}
|
|
11
|
-
declare const trackLifecycleAssessment: (client: PostHogLikeClient, tenantId: string, assessment: LifecycleAssessment) => Promise<void>;
|
|
12
|
-
declare const trackLifecycleStageChange: (client: PostHogLikeClient, tenantId: string, previousStage: number | undefined, nextStage: number) => Promise<void>;
|
|
13
|
-
//#endregion
|
|
14
|
-
export { PostHogLikeClient, trackLifecycleAssessment, trackLifecycleStageChange };
|
|
15
|
-
//# sourceMappingURL=posthog-bridge.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"posthog-bridge.d.ts","names":[],"sources":["../../src/lifecycle/posthog-bridge.ts"],"sourcesContent":[],"mappings":";;;UAGiB,iBAAA;;IAAA,UAAA,EAAA,MAAiB;IAQrB,KAAA,EAAA,MAAA;IACH,UAAA,CAAA,EALO,MAKP,CAAA,MAAA,EAAA,OAAA,CAAA;EAEI,CAAA,EAAA,GANN,OAMM,CAAA,IAAA,CAAA,GAAA,IAAA;;AAAmB,cAHpB,wBAGoB,EAAA,CAAA,MAAA,EAFvB,iBAEuB,EAAA,QAAA,EAAA,MAAA,EAAA,UAAA,EAAnB,mBAAmB,EAAA,GAAA,OAAA,CAAA,IAAA,CAAA;AAapB,cAAA,yBACH,EAAA,CAAA,MAAA,EAAA,iBAGS,EAAA,QAAA,EAAA,MAAA,EAAA,aAAA,EAAA,MAAA,GAAA,SAAA,EAAA,SAAA,EAAA,MAAA,EAAA,GAAA,OAAA,CAAA,IAAA,CAAA"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"posthog-bridge.js","names":[],"sources":["../../src/lifecycle/posthog-bridge.ts"],"sourcesContent":["import type { LifecycleAssessment } from '@lssm/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":"6DAWA,MAAa,EAA2B,MACtC,EACA,EACA,IACG,CACH,MAAM,EAAO,QAAQ,CACnB,WAAY,EACZ,MAAO,EAAoB,cAC3B,WAAY,CACV,MAAO,EAAW,MAClB,WAAY,EAAW,WACvB,KAAM,EAAW,KAClB,CACF,CAAC,EAGS,EAA4B,MACvC,EACA,EACA,EACA,IACG,CACH,MAAM,EAAO,QAAQ,CACnB,WAAY,EACZ,MAAO,EAAoB,aAC3B,WAAY,CACV,gBACA,YACD,CACF,CAAC"}
|
package/dist/types.d.ts
DELETED
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
//#region src/types.d.ts
|
|
2
|
-
interface AnalyticsEvent {
|
|
3
|
-
name: string;
|
|
4
|
-
userId: string;
|
|
5
|
-
tenantId?: string;
|
|
6
|
-
timestamp: string | Date;
|
|
7
|
-
properties?: Record<string, unknown>;
|
|
8
|
-
}
|
|
9
|
-
interface FunnelStep {
|
|
10
|
-
id: string;
|
|
11
|
-
eventName: string;
|
|
12
|
-
match?: (event: AnalyticsEvent) => boolean;
|
|
13
|
-
}
|
|
14
|
-
interface FunnelDefinition {
|
|
15
|
-
name: string;
|
|
16
|
-
steps: FunnelStep[];
|
|
17
|
-
windowHours?: number;
|
|
18
|
-
}
|
|
19
|
-
interface FunnelStepResult {
|
|
20
|
-
step: FunnelStep;
|
|
21
|
-
count: number;
|
|
22
|
-
conversionRate: number;
|
|
23
|
-
dropOffRate: number;
|
|
24
|
-
}
|
|
25
|
-
interface FunnelAnalysis {
|
|
26
|
-
definition: FunnelDefinition;
|
|
27
|
-
totalUsers: number;
|
|
28
|
-
steps: FunnelStepResult[];
|
|
29
|
-
}
|
|
30
|
-
interface CohortEvent extends AnalyticsEvent {
|
|
31
|
-
amount?: number;
|
|
32
|
-
}
|
|
33
|
-
interface CohortDefinition {
|
|
34
|
-
bucket: 'day' | 'week' | 'month';
|
|
35
|
-
periods: number;
|
|
36
|
-
startDate?: Date;
|
|
37
|
-
}
|
|
38
|
-
interface CohortStats {
|
|
39
|
-
cohortKey: string;
|
|
40
|
-
users: number;
|
|
41
|
-
retention: number[];
|
|
42
|
-
ltv: number;
|
|
43
|
-
}
|
|
44
|
-
interface CohortAnalysis {
|
|
45
|
-
definition: CohortDefinition;
|
|
46
|
-
cohorts: CohortStats[];
|
|
47
|
-
}
|
|
48
|
-
interface ChurnSignal {
|
|
49
|
-
userId: string;
|
|
50
|
-
score: number;
|
|
51
|
-
bucket: 'low' | 'medium' | 'high';
|
|
52
|
-
drivers: string[];
|
|
53
|
-
}
|
|
54
|
-
interface GrowthMetric {
|
|
55
|
-
name: string;
|
|
56
|
-
current: number;
|
|
57
|
-
previous?: number;
|
|
58
|
-
target?: number;
|
|
59
|
-
}
|
|
60
|
-
interface GrowthHypothesis {
|
|
61
|
-
statement: string;
|
|
62
|
-
metric: string;
|
|
63
|
-
confidence: 'low' | 'medium' | 'high';
|
|
64
|
-
impact: 'low' | 'medium' | 'high';
|
|
65
|
-
}
|
|
66
|
-
//#endregion
|
|
67
|
-
export { AnalyticsEvent, ChurnSignal, CohortAnalysis, CohortDefinition, CohortEvent, CohortStats, FunnelAnalysis, FunnelDefinition, FunnelStep, FunnelStepResult, GrowthHypothesis, GrowthMetric };
|
|
68
|
-
//# sourceMappingURL=types.d.ts.map
|
package/dist/types.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","names":[],"sources":["../src/types.ts"],"sourcesContent":[],"mappings":";UAAiB,cAAA;EAAA,IAAA,EAAA,MAAA;EAQA,MAAA,EAAA,MAAU;EAMV,QAAA,CAAA,EAAA,MAAA;EAMA,SAAA,EAAA,MAAA,GAhBK,IAgBW;EAOhB,UAAA,CAAA,EAtBF,MAsBgB,CAAA,MAAA,EACjB,OAAA,CAAA;AAKd;AAIiB,UA7BA,UAAA,CA6BgB;EAMhB,EAAA,EAAA,MAAA;EAOA,SAAA,EAAA,MAAc;EAKd,KAAA,CAAA,EAAA,CAAA,KAAW,EA5CV,cA4CU,EAAA,GAAA,OAAA;AAO5B;AAOiB,UAvDA,gBAAA,CAuDgB;;SArDxB;;;UAIQ,gBAAA;QACT;;;;;UAMS,cAAA;cACH;;SAEL;;UAGQ,WAAA,SAAoB;;;UAIpB,gBAAA;;;cAGH;;UAGG,WAAA;;;;;;UAOA,cAAA;cACH;WACH;;UAGM,WAAA;;;;;;UAOA,YAAA;;;;;;UAOA,gBAAA"}
|