@contractspec/lib.analytics 1.57.0 → 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.
Files changed (89) hide show
  1. package/dist/browser/churn/index.js +77 -0
  2. package/dist/browser/churn/predictor.js +77 -0
  3. package/dist/browser/cohort/index.js +117 -0
  4. package/dist/browser/cohort/tracker.js +117 -0
  5. package/dist/browser/funnel/analyzer.js +68 -0
  6. package/dist/browser/funnel/index.js +68 -0
  7. package/dist/browser/growth/hypothesis-generator.js +46 -0
  8. package/dist/browser/growth/index.js +46 -0
  9. package/dist/browser/index.js +723 -0
  10. package/dist/browser/lifecycle/index.js +287 -0
  11. package/dist/browser/lifecycle/metric-collectors.js +58 -0
  12. package/dist/browser/lifecycle/posthog-bridge.js +79 -0
  13. package/dist/browser/lifecycle/posthog-metric-source.js +205 -0
  14. package/dist/browser/posthog/event-source.js +138 -0
  15. package/dist/browser/posthog/index.js +138 -0
  16. package/dist/browser/types.js +0 -0
  17. package/dist/churn/index.d.ts +2 -2
  18. package/dist/churn/index.d.ts.map +1 -0
  19. package/dist/churn/index.js +77 -2
  20. package/dist/churn/predictor.d.ts +15 -19
  21. package/dist/churn/predictor.d.ts.map +1 -1
  22. package/dist/churn/predictor.js +72 -68
  23. package/dist/cohort/index.d.ts +2 -2
  24. package/dist/cohort/index.d.ts.map +1 -0
  25. package/dist/cohort/index.js +117 -2
  26. package/dist/cohort/tracker.d.ts +3 -7
  27. package/dist/cohort/tracker.d.ts.map +1 -1
  28. package/dist/cohort/tracker.js +106 -87
  29. package/dist/funnel/analyzer.d.ts +4 -8
  30. package/dist/funnel/analyzer.d.ts.map +1 -1
  31. package/dist/funnel/analyzer.js +67 -62
  32. package/dist/funnel/index.d.ts +2 -2
  33. package/dist/funnel/index.d.ts.map +1 -0
  34. package/dist/funnel/index.js +69 -3
  35. package/dist/growth/hypothesis-generator.d.ts +11 -15
  36. package/dist/growth/hypothesis-generator.d.ts.map +1 -1
  37. package/dist/growth/hypothesis-generator.js +46 -39
  38. package/dist/growth/index.d.ts +2 -2
  39. package/dist/growth/index.d.ts.map +1 -0
  40. package/dist/growth/index.js +47 -3
  41. package/dist/index.d.ts +8 -10
  42. package/dist/index.d.ts.map +1 -0
  43. package/dist/index.js +724 -12
  44. package/dist/lifecycle/index.d.ts +4 -4
  45. package/dist/lifecycle/index.d.ts.map +1 -0
  46. package/dist/lifecycle/index.js +287 -4
  47. package/dist/lifecycle/metric-collectors.d.ts +22 -26
  48. package/dist/lifecycle/metric-collectors.d.ts.map +1 -1
  49. package/dist/lifecycle/metric-collectors.js +55 -44
  50. package/dist/lifecycle/posthog-bridge.d.ts +9 -13
  51. package/dist/lifecycle/posthog-bridge.d.ts.map +1 -1
  52. package/dist/lifecycle/posthog-bridge.js +77 -25
  53. package/dist/lifecycle/posthog-metric-source.d.ts +40 -44
  54. package/dist/lifecycle/posthog-metric-source.d.ts.map +1 -1
  55. package/dist/lifecycle/posthog-metric-source.js +200 -180
  56. package/dist/node/churn/index.js +77 -0
  57. package/dist/node/churn/predictor.js +77 -0
  58. package/dist/node/cohort/index.js +117 -0
  59. package/dist/node/cohort/tracker.js +117 -0
  60. package/dist/node/funnel/analyzer.js +68 -0
  61. package/dist/node/funnel/index.js +68 -0
  62. package/dist/node/growth/hypothesis-generator.js +46 -0
  63. package/dist/node/growth/index.js +46 -0
  64. package/dist/node/index.js +723 -0
  65. package/dist/node/lifecycle/index.js +287 -0
  66. package/dist/node/lifecycle/metric-collectors.js +58 -0
  67. package/dist/node/lifecycle/posthog-bridge.js +79 -0
  68. package/dist/node/lifecycle/posthog-metric-source.js +205 -0
  69. package/dist/node/posthog/event-source.js +138 -0
  70. package/dist/node/posthog/index.js +138 -0
  71. package/dist/node/types.js +0 -0
  72. package/dist/posthog/event-source.d.ts +18 -22
  73. package/dist/posthog/event-source.d.ts.map +1 -1
  74. package/dist/posthog/event-source.js +131 -111
  75. package/dist/posthog/index.d.ts +2 -2
  76. package/dist/posthog/index.d.ts.map +1 -0
  77. package/dist/posthog/index.js +139 -3
  78. package/dist/types.d.ts +52 -55
  79. package/dist/types.d.ts.map +1 -1
  80. package/dist/types.js +1 -0
  81. package/package.json +189 -46
  82. package/dist/churn/predictor.js.map +0 -1
  83. package/dist/cohort/tracker.js.map +0 -1
  84. package/dist/funnel/analyzer.js.map +0 -1
  85. package/dist/growth/hypothesis-generator.js.map +0 -1
  86. package/dist/lifecycle/metric-collectors.js.map +0 -1
  87. package/dist/lifecycle/posthog-bridge.js.map +0 -1
  88. package/dist/lifecycle/posthog-metric-source.js.map +0 -1
  89. package/dist/posthog/event-source.js.map +0 -1
@@ -0,0 +1,138 @@
1
+ // src/posthog/event-source.ts
2
+ class PosthogAnalyticsEventSource {
3
+ reader;
4
+ limitPerEvent;
5
+ tenantPropertyKey;
6
+ defaultRangeDays;
7
+ constructor(reader, options = {}) {
8
+ this.reader = reader;
9
+ this.limitPerEvent = options.limitPerEvent ?? 1000;
10
+ this.tenantPropertyKey = options.tenantPropertyKey ?? "tenantId";
11
+ this.defaultRangeDays = options.defaultRangeDays ?? 30;
12
+ }
13
+ async getEventsForFunnel(definition, dateRange) {
14
+ const eventNames = definition.steps.map((step) => step.eventName);
15
+ return this.getEventsByNames(eventNames, dateRange);
16
+ }
17
+ async getEventsForCohort(definition, dateRange, eventNames) {
18
+ const events = eventNames && eventNames.length > 0 ? eventNames : ["*"];
19
+ if (events[0] === "*") {
20
+ return this.getEventsByNames([], dateRange, definition.periods * 500);
21
+ }
22
+ return this.getEventsByNames(events, dateRange, definition.periods * 500);
23
+ }
24
+ async getUserActivity(userId, dateRange, limit = 1000) {
25
+ if (!this.reader.getEvents) {
26
+ throw new Error("Analytics reader does not support event queries.");
27
+ }
28
+ const response = await this.reader.getEvents({
29
+ distinctId: userId,
30
+ dateRange,
31
+ limit
32
+ });
33
+ return response.results.map((event) => toAnalyticsEvent(event, this.tenantPropertyKey));
34
+ }
35
+ async getGrowthMetrics(metricNames, dateRange) {
36
+ const range = resolveRange(dateRange, this.defaultRangeDays);
37
+ const previous = shiftRange(range);
38
+ const results = [];
39
+ for (const metricName of metricNames) {
40
+ const current = await this.countEvents(metricName, range);
41
+ const previousCount = await this.countEvents(metricName, previous);
42
+ results.push({
43
+ name: metricName,
44
+ current,
45
+ previous: previousCount
46
+ });
47
+ }
48
+ return results;
49
+ }
50
+ async getEventsByNames(eventNames, dateRange, limitPerEvent = this.limitPerEvent) {
51
+ if (!this.reader.getEvents) {
52
+ throw new Error("Analytics reader does not support event queries.");
53
+ }
54
+ if (eventNames.length === 0) {
55
+ const response = await this.reader.getEvents({
56
+ dateRange,
57
+ limit: limitPerEvent
58
+ });
59
+ return response.results.map((event) => toAnalyticsEvent(event, this.tenantPropertyKey));
60
+ }
61
+ const events = [];
62
+ for (const eventName of eventNames) {
63
+ const response = await this.reader.getEvents({
64
+ event: eventName,
65
+ dateRange,
66
+ limit: limitPerEvent
67
+ });
68
+ response.results.forEach((event) => {
69
+ events.push(toAnalyticsEvent(event, this.tenantPropertyKey));
70
+ });
71
+ }
72
+ return events;
73
+ }
74
+ async countEvents(eventName, range) {
75
+ if (!this.reader.queryHogQL) {
76
+ throw new Error("Analytics reader does not support HogQL queries.");
77
+ }
78
+ const result = await this.reader.queryHogQL({
79
+ query: [
80
+ "select",
81
+ " count() as total",
82
+ "from events",
83
+ "where event = {eventName}",
84
+ "and timestamp >= {dateFrom}",
85
+ "and timestamp < {dateTo}"
86
+ ].join(`
87
+ `),
88
+ values: {
89
+ eventName,
90
+ dateFrom: range.from.toISOString(),
91
+ dateTo: range.to.toISOString()
92
+ }
93
+ });
94
+ return readSingleNumber(result) ?? 0;
95
+ }
96
+ }
97
+ function toAnalyticsEvent(event, tenantPropertyKey) {
98
+ const tenantIdValue = event.properties?.[tenantPropertyKey] ?? event.properties?.tenantId;
99
+ return {
100
+ name: event.event,
101
+ userId: event.distinctId,
102
+ tenantId: typeof tenantIdValue === "string" ? tenantIdValue : undefined,
103
+ timestamp: event.timestamp,
104
+ properties: event.properties
105
+ };
106
+ }
107
+ function resolveRange(dateRange, defaultDays) {
108
+ const to = dateRange?.to instanceof Date ? dateRange.to : dateRange?.to ? new Date(dateRange.to) : new Date;
109
+ const from = dateRange?.from instanceof Date ? dateRange.from : dateRange?.from ? new Date(dateRange.from) : new Date(to.getTime() - defaultDays * 24 * 60 * 60 * 1000);
110
+ return { from, to };
111
+ }
112
+ function shiftRange(range) {
113
+ const duration = range.to.getTime() - range.from.getTime();
114
+ return {
115
+ from: new Date(range.from.getTime() - duration),
116
+ to: new Date(range.to.getTime() - duration)
117
+ };
118
+ }
119
+ function readSingleNumber(result) {
120
+ if (!Array.isArray(result.results) || result.results.length === 0) {
121
+ return;
122
+ }
123
+ const firstRow = result.results[0];
124
+ if (Array.isArray(firstRow) && firstRow.length > 0) {
125
+ const value = firstRow[0];
126
+ if (typeof value === "number" && Number.isFinite(value))
127
+ return value;
128
+ if (typeof value === "string" && value.trim()) {
129
+ const parsed = Number(value);
130
+ if (Number.isFinite(parsed))
131
+ return parsed;
132
+ }
133
+ }
134
+ return;
135
+ }
136
+ export {
137
+ PosthogAnalyticsEventSource
138
+ };
@@ -0,0 +1,138 @@
1
+ // src/posthog/event-source.ts
2
+ class PosthogAnalyticsEventSource {
3
+ reader;
4
+ limitPerEvent;
5
+ tenantPropertyKey;
6
+ defaultRangeDays;
7
+ constructor(reader, options = {}) {
8
+ this.reader = reader;
9
+ this.limitPerEvent = options.limitPerEvent ?? 1000;
10
+ this.tenantPropertyKey = options.tenantPropertyKey ?? "tenantId";
11
+ this.defaultRangeDays = options.defaultRangeDays ?? 30;
12
+ }
13
+ async getEventsForFunnel(definition, dateRange) {
14
+ const eventNames = definition.steps.map((step) => step.eventName);
15
+ return this.getEventsByNames(eventNames, dateRange);
16
+ }
17
+ async getEventsForCohort(definition, dateRange, eventNames) {
18
+ const events = eventNames && eventNames.length > 0 ? eventNames : ["*"];
19
+ if (events[0] === "*") {
20
+ return this.getEventsByNames([], dateRange, definition.periods * 500);
21
+ }
22
+ return this.getEventsByNames(events, dateRange, definition.periods * 500);
23
+ }
24
+ async getUserActivity(userId, dateRange, limit = 1000) {
25
+ if (!this.reader.getEvents) {
26
+ throw new Error("Analytics reader does not support event queries.");
27
+ }
28
+ const response = await this.reader.getEvents({
29
+ distinctId: userId,
30
+ dateRange,
31
+ limit
32
+ });
33
+ return response.results.map((event) => toAnalyticsEvent(event, this.tenantPropertyKey));
34
+ }
35
+ async getGrowthMetrics(metricNames, dateRange) {
36
+ const range = resolveRange(dateRange, this.defaultRangeDays);
37
+ const previous = shiftRange(range);
38
+ const results = [];
39
+ for (const metricName of metricNames) {
40
+ const current = await this.countEvents(metricName, range);
41
+ const previousCount = await this.countEvents(metricName, previous);
42
+ results.push({
43
+ name: metricName,
44
+ current,
45
+ previous: previousCount
46
+ });
47
+ }
48
+ return results;
49
+ }
50
+ async getEventsByNames(eventNames, dateRange, limitPerEvent = this.limitPerEvent) {
51
+ if (!this.reader.getEvents) {
52
+ throw new Error("Analytics reader does not support event queries.");
53
+ }
54
+ if (eventNames.length === 0) {
55
+ const response = await this.reader.getEvents({
56
+ dateRange,
57
+ limit: limitPerEvent
58
+ });
59
+ return response.results.map((event) => toAnalyticsEvent(event, this.tenantPropertyKey));
60
+ }
61
+ const events = [];
62
+ for (const eventName of eventNames) {
63
+ const response = await this.reader.getEvents({
64
+ event: eventName,
65
+ dateRange,
66
+ limit: limitPerEvent
67
+ });
68
+ response.results.forEach((event) => {
69
+ events.push(toAnalyticsEvent(event, this.tenantPropertyKey));
70
+ });
71
+ }
72
+ return events;
73
+ }
74
+ async countEvents(eventName, range) {
75
+ if (!this.reader.queryHogQL) {
76
+ throw new Error("Analytics reader does not support HogQL queries.");
77
+ }
78
+ const result = await this.reader.queryHogQL({
79
+ query: [
80
+ "select",
81
+ " count() as total",
82
+ "from events",
83
+ "where event = {eventName}",
84
+ "and timestamp >= {dateFrom}",
85
+ "and timestamp < {dateTo}"
86
+ ].join(`
87
+ `),
88
+ values: {
89
+ eventName,
90
+ dateFrom: range.from.toISOString(),
91
+ dateTo: range.to.toISOString()
92
+ }
93
+ });
94
+ return readSingleNumber(result) ?? 0;
95
+ }
96
+ }
97
+ function toAnalyticsEvent(event, tenantPropertyKey) {
98
+ const tenantIdValue = event.properties?.[tenantPropertyKey] ?? event.properties?.tenantId;
99
+ return {
100
+ name: event.event,
101
+ userId: event.distinctId,
102
+ tenantId: typeof tenantIdValue === "string" ? tenantIdValue : undefined,
103
+ timestamp: event.timestamp,
104
+ properties: event.properties
105
+ };
106
+ }
107
+ function resolveRange(dateRange, defaultDays) {
108
+ const to = dateRange?.to instanceof Date ? dateRange.to : dateRange?.to ? new Date(dateRange.to) : new Date;
109
+ const from = dateRange?.from instanceof Date ? dateRange.from : dateRange?.from ? new Date(dateRange.from) : new Date(to.getTime() - defaultDays * 24 * 60 * 60 * 1000);
110
+ return { from, to };
111
+ }
112
+ function shiftRange(range) {
113
+ const duration = range.to.getTime() - range.from.getTime();
114
+ return {
115
+ from: new Date(range.from.getTime() - duration),
116
+ to: new Date(range.to.getTime() - duration)
117
+ };
118
+ }
119
+ function readSingleNumber(result) {
120
+ if (!Array.isArray(result.results) || result.results.length === 0) {
121
+ return;
122
+ }
123
+ const firstRow = result.results[0];
124
+ if (Array.isArray(firstRow) && firstRow.length > 0) {
125
+ const value = firstRow[0];
126
+ if (typeof value === "number" && Number.isFinite(value))
127
+ return value;
128
+ if (typeof value === "string" && value.trim()) {
129
+ const parsed = Number(value);
130
+ if (Number.isFinite(parsed))
131
+ return parsed;
132
+ }
133
+ }
134
+ return;
135
+ }
136
+ export {
137
+ PosthogAnalyticsEventSource
138
+ };
File without changes
@@ -1,25 +1,21 @@
1
- import { AnalyticsEvent, CohortDefinition, FunnelDefinition, GrowthMetric } from "../types.js";
2
- import { AnalyticsReader, DateRangeInput } from "@contractspec/lib.contracts/integrations/providers/analytics";
3
-
4
- //#region src/posthog/event-source.d.ts
5
- interface PosthogAnalyticsEventSourceOptions {
6
- limitPerEvent?: number;
7
- tenantPropertyKey?: string;
8
- defaultRangeDays?: number;
1
+ import type { AnalyticsReader, DateRangeInput } from '@contractspec/lib.contracts/integrations/providers/analytics';
2
+ import type { AnalyticsEvent, CohortDefinition, FunnelDefinition, GrowthMetric } from '../types';
3
+ export interface PosthogAnalyticsEventSourceOptions {
4
+ limitPerEvent?: number;
5
+ tenantPropertyKey?: string;
6
+ defaultRangeDays?: number;
9
7
  }
10
- declare class PosthogAnalyticsEventSource {
11
- private readonly reader;
12
- private readonly limitPerEvent;
13
- private readonly tenantPropertyKey;
14
- private readonly defaultRangeDays;
15
- constructor(reader: AnalyticsReader, options?: PosthogAnalyticsEventSourceOptions);
16
- getEventsForFunnel(definition: FunnelDefinition, dateRange?: DateRangeInput): Promise<AnalyticsEvent[]>;
17
- getEventsForCohort(definition: CohortDefinition, dateRange?: DateRangeInput, eventNames?: string[]): Promise<AnalyticsEvent[]>;
18
- getUserActivity(userId: string, dateRange?: DateRangeInput, limit?: number): Promise<AnalyticsEvent[]>;
19
- getGrowthMetrics(metricNames: string[], dateRange?: DateRangeInput): Promise<GrowthMetric[]>;
20
- private getEventsByNames;
21
- private countEvents;
8
+ export declare class PosthogAnalyticsEventSource {
9
+ private readonly reader;
10
+ private readonly limitPerEvent;
11
+ private readonly tenantPropertyKey;
12
+ private readonly defaultRangeDays;
13
+ constructor(reader: AnalyticsReader, options?: PosthogAnalyticsEventSourceOptions);
14
+ getEventsForFunnel(definition: FunnelDefinition, dateRange?: DateRangeInput): Promise<AnalyticsEvent[]>;
15
+ getEventsForCohort(definition: CohortDefinition, dateRange?: DateRangeInput, eventNames?: string[]): Promise<AnalyticsEvent[]>;
16
+ getUserActivity(userId: string, dateRange?: DateRangeInput, limit?: number): Promise<AnalyticsEvent[]>;
17
+ getGrowthMetrics(metricNames: string[], dateRange?: DateRangeInput): Promise<GrowthMetric[]>;
18
+ private getEventsByNames;
19
+ private countEvents;
22
20
  }
23
- //#endregion
24
- export { PosthogAnalyticsEventSource, PosthogAnalyticsEventSourceOptions };
25
21
  //# sourceMappingURL=event-source.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"event-source.d.ts","names":[],"sources":["../../src/posthog/event-source.ts"],"mappings":";;;;UAWiB,kCAAA;EACf,aAAA;EACA,iBAAA;EACA,gBAAA;AAAA;AAAA,cAGW,2BAAA;EAAA,iBACM,MAAA;EAAA,iBACA,aAAA;EAAA,iBACA,iBAAA;EAAA,iBACA,gBAAA;cAGf,MAAA,EAAQ,eAAA,EACR,OAAA,GAAS,kCAAA;EAQL,kBAAA,CACJ,UAAA,EAAY,gBAAA,EACZ,SAAA,GAAY,cAAA,GACX,OAAA,CAAQ,cAAA;EAKL,kBAAA,CACJ,UAAA,EAAY,gBAAA,EACZ,SAAA,GAAY,cAAA,EACZ,UAAA,cACC,OAAA,CAAQ,cAAA;EAQL,eAAA,CACJ,MAAA,UACA,SAAA,GAAY,cAAA,EACZ,KAAA,YACC,OAAA,CAAQ,cAAA;EAcL,gBAAA,CACJ,WAAA,YACA,SAAA,GAAY,cAAA,GACX,OAAA,CAAQ,YAAA;EAAA,QAgBG,gBAAA;EAAA,QA+BA,WAAA;AAAA"}
1
+ {"version":3,"file":"event-source.d.ts","sourceRoot":"","sources":["../../src/posthog/event-source.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,eAAe,EACf,cAAc,EACf,MAAM,8DAA8D,CAAC;AACtE,OAAO,KAAK,EACV,cAAc,EACd,gBAAgB,EAChB,gBAAgB,EAChB,YAAY,EACb,MAAM,UAAU,CAAC;AAElB,MAAM,WAAW,kCAAkC;IACjD,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,qBAAa,2BAA2B;IACtC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAkB;IACzC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAS;IACvC,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAS;IAC3C,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAS;gBAGxC,MAAM,EAAE,eAAe,EACvB,OAAO,GAAE,kCAAuC;IAQ5C,kBAAkB,CACtB,UAAU,EAAE,gBAAgB,EAC5B,SAAS,CAAC,EAAE,cAAc,GACzB,OAAO,CAAC,cAAc,EAAE,CAAC;IAKtB,kBAAkB,CACtB,UAAU,EAAE,gBAAgB,EAC5B,SAAS,CAAC,EAAE,cAAc,EAC1B,UAAU,CAAC,EAAE,MAAM,EAAE,GACpB,OAAO,CAAC,cAAc,EAAE,CAAC;IAQtB,eAAe,CACnB,MAAM,EAAE,MAAM,EACd,SAAS,CAAC,EAAE,cAAc,EAC1B,KAAK,SAAO,GACX,OAAO,CAAC,cAAc,EAAE,CAAC;IActB,gBAAgB,CACpB,WAAW,EAAE,MAAM,EAAE,EACrB,SAAS,CAAC,EAAE,cAAc,GACzB,OAAO,CAAC,YAAY,EAAE,CAAC;YAgBZ,gBAAgB;YA+BhB,WAAW;CAwB1B"}
@@ -1,119 +1,139 @@
1
- //#region src/posthog/event-source.ts
2
- var PosthogAnalyticsEventSource = class {
3
- reader;
4
- limitPerEvent;
5
- tenantPropertyKey;
6
- defaultRangeDays;
7
- constructor(reader, options = {}) {
8
- this.reader = reader;
9
- this.limitPerEvent = options.limitPerEvent ?? 1e3;
10
- this.tenantPropertyKey = options.tenantPropertyKey ?? "tenantId";
11
- this.defaultRangeDays = options.defaultRangeDays ?? 30;
12
- }
13
- async getEventsForFunnel(definition, dateRange) {
14
- const eventNames = definition.steps.map((step) => step.eventName);
15
- return this.getEventsByNames(eventNames, dateRange);
16
- }
17
- async getEventsForCohort(definition, dateRange, eventNames) {
18
- const events = eventNames && eventNames.length > 0 ? eventNames : ["*"];
19
- if (events[0] === "*") return this.getEventsByNames([], dateRange, definition.periods * 500);
20
- return this.getEventsByNames(events, dateRange, definition.periods * 500);
21
- }
22
- async getUserActivity(userId, dateRange, limit = 1e3) {
23
- if (!this.reader.getEvents) throw new Error("Analytics reader does not support event queries.");
24
- return (await this.reader.getEvents({
25
- distinctId: userId,
26
- dateRange,
27
- limit
28
- })).results.map((event) => toAnalyticsEvent(event, this.tenantPropertyKey));
29
- }
30
- async getGrowthMetrics(metricNames, dateRange) {
31
- const range = resolveRange(dateRange, this.defaultRangeDays);
32
- const previous = shiftRange(range);
33
- const results = [];
34
- for (const metricName of metricNames) {
35
- const current = await this.countEvents(metricName, range);
36
- const previousCount = await this.countEvents(metricName, previous);
37
- results.push({
38
- name: metricName,
39
- current,
40
- previous: previousCount
41
- });
42
- }
43
- return results;
44
- }
45
- async getEventsByNames(eventNames, dateRange, limitPerEvent = this.limitPerEvent) {
46
- if (!this.reader.getEvents) throw new Error("Analytics reader does not support event queries.");
47
- if (eventNames.length === 0) return (await this.reader.getEvents({
48
- dateRange,
49
- limit: limitPerEvent
50
- })).results.map((event) => toAnalyticsEvent(event, this.tenantPropertyKey));
51
- const events = [];
52
- for (const eventName of eventNames) (await this.reader.getEvents({
53
- event: eventName,
54
- dateRange,
55
- limit: limitPerEvent
56
- })).results.forEach((event) => {
57
- events.push(toAnalyticsEvent(event, this.tenantPropertyKey));
58
- });
59
- return events;
60
- }
61
- async countEvents(eventName, range) {
62
- if (!this.reader.queryHogQL) throw new Error("Analytics reader does not support HogQL queries.");
63
- return readSingleNumber(await this.reader.queryHogQL({
64
- query: [
65
- "select",
66
- " count() as total",
67
- "from events",
68
- "where event = {eventName}",
69
- "and timestamp >= {dateFrom}",
70
- "and timestamp < {dateTo}"
71
- ].join("\n"),
72
- values: {
73
- eventName,
74
- dateFrom: range.from.toISOString(),
75
- dateTo: range.to.toISOString()
76
- }
77
- })) ?? 0;
78
- }
79
- };
1
+ // @bun
2
+ // src/posthog/event-source.ts
3
+ class PosthogAnalyticsEventSource {
4
+ reader;
5
+ limitPerEvent;
6
+ tenantPropertyKey;
7
+ defaultRangeDays;
8
+ constructor(reader, options = {}) {
9
+ this.reader = reader;
10
+ this.limitPerEvent = options.limitPerEvent ?? 1000;
11
+ this.tenantPropertyKey = options.tenantPropertyKey ?? "tenantId";
12
+ this.defaultRangeDays = options.defaultRangeDays ?? 30;
13
+ }
14
+ async getEventsForFunnel(definition, dateRange) {
15
+ const eventNames = definition.steps.map((step) => step.eventName);
16
+ return this.getEventsByNames(eventNames, dateRange);
17
+ }
18
+ async getEventsForCohort(definition, dateRange, eventNames) {
19
+ const events = eventNames && eventNames.length > 0 ? eventNames : ["*"];
20
+ if (events[0] === "*") {
21
+ return this.getEventsByNames([], dateRange, definition.periods * 500);
22
+ }
23
+ return this.getEventsByNames(events, dateRange, definition.periods * 500);
24
+ }
25
+ async getUserActivity(userId, dateRange, limit = 1000) {
26
+ if (!this.reader.getEvents) {
27
+ throw new Error("Analytics reader does not support event queries.");
28
+ }
29
+ const response = await this.reader.getEvents({
30
+ distinctId: userId,
31
+ dateRange,
32
+ limit
33
+ });
34
+ return response.results.map((event) => toAnalyticsEvent(event, this.tenantPropertyKey));
35
+ }
36
+ async getGrowthMetrics(metricNames, dateRange) {
37
+ const range = resolveRange(dateRange, this.defaultRangeDays);
38
+ const previous = shiftRange(range);
39
+ const results = [];
40
+ for (const metricName of metricNames) {
41
+ const current = await this.countEvents(metricName, range);
42
+ const previousCount = await this.countEvents(metricName, previous);
43
+ results.push({
44
+ name: metricName,
45
+ current,
46
+ previous: previousCount
47
+ });
48
+ }
49
+ return results;
50
+ }
51
+ async getEventsByNames(eventNames, dateRange, limitPerEvent = this.limitPerEvent) {
52
+ if (!this.reader.getEvents) {
53
+ throw new Error("Analytics reader does not support event queries.");
54
+ }
55
+ if (eventNames.length === 0) {
56
+ const response = await this.reader.getEvents({
57
+ dateRange,
58
+ limit: limitPerEvent
59
+ });
60
+ return response.results.map((event) => toAnalyticsEvent(event, this.tenantPropertyKey));
61
+ }
62
+ const events = [];
63
+ for (const eventName of eventNames) {
64
+ const response = await this.reader.getEvents({
65
+ event: eventName,
66
+ dateRange,
67
+ limit: limitPerEvent
68
+ });
69
+ response.results.forEach((event) => {
70
+ events.push(toAnalyticsEvent(event, this.tenantPropertyKey));
71
+ });
72
+ }
73
+ return events;
74
+ }
75
+ async countEvents(eventName, range) {
76
+ if (!this.reader.queryHogQL) {
77
+ throw new Error("Analytics reader does not support HogQL queries.");
78
+ }
79
+ const result = await this.reader.queryHogQL({
80
+ query: [
81
+ "select",
82
+ " count() as total",
83
+ "from events",
84
+ "where event = {eventName}",
85
+ "and timestamp >= {dateFrom}",
86
+ "and timestamp < {dateTo}"
87
+ ].join(`
88
+ `),
89
+ values: {
90
+ eventName,
91
+ dateFrom: range.from.toISOString(),
92
+ dateTo: range.to.toISOString()
93
+ }
94
+ });
95
+ return readSingleNumber(result) ?? 0;
96
+ }
97
+ }
80
98
  function toAnalyticsEvent(event, tenantPropertyKey) {
81
- const tenantIdValue = event.properties?.[tenantPropertyKey] ?? event.properties?.tenantId;
82
- return {
83
- name: event.event,
84
- userId: event.distinctId,
85
- tenantId: typeof tenantIdValue === "string" ? tenantIdValue : void 0,
86
- timestamp: event.timestamp,
87
- properties: event.properties
88
- };
99
+ const tenantIdValue = event.properties?.[tenantPropertyKey] ?? event.properties?.tenantId;
100
+ return {
101
+ name: event.event,
102
+ userId: event.distinctId,
103
+ tenantId: typeof tenantIdValue === "string" ? tenantIdValue : undefined,
104
+ timestamp: event.timestamp,
105
+ properties: event.properties
106
+ };
89
107
  }
90
108
  function resolveRange(dateRange, defaultDays) {
91
- const to = dateRange?.to instanceof Date ? dateRange.to : dateRange?.to ? new Date(dateRange.to) : /* @__PURE__ */ new Date();
92
- return {
93
- from: dateRange?.from instanceof Date ? dateRange.from : dateRange?.from ? new Date(dateRange.from) : /* @__PURE__ */ new Date(to.getTime() - defaultDays * 24 * 60 * 60 * 1e3),
94
- to
95
- };
109
+ const to = dateRange?.to instanceof Date ? dateRange.to : dateRange?.to ? new Date(dateRange.to) : new Date;
110
+ const from = dateRange?.from instanceof Date ? dateRange.from : dateRange?.from ? new Date(dateRange.from) : new Date(to.getTime() - defaultDays * 24 * 60 * 60 * 1000);
111
+ return { from, to };
96
112
  }
97
113
  function shiftRange(range) {
98
- const duration = range.to.getTime() - range.from.getTime();
99
- return {
100
- from: new Date(range.from.getTime() - duration),
101
- to: new Date(range.to.getTime() - duration)
102
- };
114
+ const duration = range.to.getTime() - range.from.getTime();
115
+ return {
116
+ from: new Date(range.from.getTime() - duration),
117
+ to: new Date(range.to.getTime() - duration)
118
+ };
103
119
  }
104
120
  function readSingleNumber(result) {
105
- if (!Array.isArray(result.results) || result.results.length === 0) return;
106
- const firstRow = result.results[0];
107
- if (Array.isArray(firstRow) && firstRow.length > 0) {
108
- const value = firstRow[0];
109
- if (typeof value === "number" && Number.isFinite(value)) return value;
110
- if (typeof value === "string" && value.trim()) {
111
- const parsed = Number(value);
112
- if (Number.isFinite(parsed)) return parsed;
113
- }
114
- }
121
+ if (!Array.isArray(result.results) || result.results.length === 0) {
122
+ return;
123
+ }
124
+ const firstRow = result.results[0];
125
+ if (Array.isArray(firstRow) && firstRow.length > 0) {
126
+ const value = firstRow[0];
127
+ if (typeof value === "number" && Number.isFinite(value))
128
+ return value;
129
+ if (typeof value === "string" && value.trim()) {
130
+ const parsed = Number(value);
131
+ if (Number.isFinite(parsed))
132
+ return parsed;
133
+ }
134
+ }
135
+ return;
115
136
  }
116
-
117
- //#endregion
118
- export { PosthogAnalyticsEventSource };
119
- //# sourceMappingURL=event-source.js.map
137
+ export {
138
+ PosthogAnalyticsEventSource
139
+ };
@@ -1,2 +1,2 @@
1
- import { PosthogAnalyticsEventSource, PosthogAnalyticsEventSourceOptions } from "./event-source.js";
2
- export { PosthogAnalyticsEventSource, PosthogAnalyticsEventSourceOptions };
1
+ export * from './event-source';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/posthog/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAC"}