@reservamos/browser-analytics 1.1.6 → 1.1.7-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,139 @@
1
+ import mixpanelService from '@/services/mixpanel';
2
+ import { trackEventError } from '@/track';
3
+
4
+ type IdentifyStage =
5
+ | 'readiness'
6
+ | 'validation'
7
+ | 'profile'
8
+ | 'cache'
9
+ | 'mixpanel'
10
+ | 'people'
11
+ | 'fingerprint'
12
+ | 'datalake';
13
+ type IdentifyReason =
14
+ | 'failed'
15
+ | 'timeout'
16
+ | 'unobserved'
17
+ | 'unconfirmed'
18
+ | 'unavailable'
19
+ | 'invalid_input'
20
+ | 'http_error';
21
+
22
+ export type IdentifyReporter = (
23
+ stage: IdentifyStage,
24
+ reason: IdentifyReason,
25
+ httpStatus?: number,
26
+ ) => void;
27
+ export interface IdentifyStageContext {
28
+ isActive: () => boolean;
29
+ report: IdentifyReporter;
30
+ }
31
+
32
+ /** Reports only SDK-controlled diagnostics; original errors and inputs never enter telemetry. */
33
+ export function createIdentifyReporter(): IdentifyReporter {
34
+ const reported = new Set<string>();
35
+ return (stage, reason, httpStatus) => {
36
+ const key = `${stage}:${reason}`;
37
+ if (reported.has(key)) return;
38
+ reported.add(key);
39
+ const payload = {
40
+ stage,
41
+ reason,
42
+ ...(httpStatus !== undefined ? { httpStatus } : {}),
43
+ };
44
+ try {
45
+ if (mixpanelService.isReady()) {
46
+ trackEventError(
47
+ 'Identify',
48
+ new Error(`Identify ${stage}: ${reason}`),
49
+ payload,
50
+ );
51
+ } else {
52
+ console.error('Identify diagnostic', payload);
53
+ }
54
+ } catch {
55
+ console.error('Identify diagnostic', payload);
56
+ }
57
+ };
58
+ }
59
+
60
+ /** Waits only for this identify attempt, without changing the shared tracking queue. */
61
+ export function waitForIdentifyReady(
62
+ report: IdentifyReporter,
63
+ ): Promise<boolean> {
64
+ if (mixpanelService.isReady()) return Promise.resolve(true);
65
+ return new Promise((resolve) => {
66
+ let active = true;
67
+ const finish = (ready: boolean) => {
68
+ if (!active) return;
69
+ active = false;
70
+ clearTimeout(timer);
71
+ window.removeEventListener('Tracker Ready', onReady);
72
+ if (!ready) report('readiness', 'timeout');
73
+ resolve(ready);
74
+ };
75
+ const onReady = () => {
76
+ if (mixpanelService.isReady()) finish(true);
77
+ };
78
+ const timer = setTimeout(() => finish(false), 5000);
79
+ window.addEventListener('Tracker Ready', onReady);
80
+ onReady();
81
+ });
82
+ }
83
+
84
+ /** Closes optional work at its deadline and consumes late fulfillment or rejection. */
85
+ export function waitForIdentifyStage<T>(
86
+ stage: 'profile' | 'fingerprint',
87
+ timeout: number,
88
+ run: (context: IdentifyStageContext) => Promise<T>,
89
+ report: IdentifyReporter,
90
+ ): Promise<T | undefined> {
91
+ return new Promise((resolve) => {
92
+ let active = true;
93
+ const finish = (value?: T) => {
94
+ if (!active) return;
95
+ active = false;
96
+ clearTimeout(timer);
97
+ resolve(value);
98
+ };
99
+ const timer = setTimeout(() => {
100
+ report(stage, 'timeout');
101
+ finish();
102
+ }, timeout);
103
+ const context: IdentifyStageContext = {
104
+ isActive: () => active,
105
+ report: (...args) => {
106
+ if (active) report(...args);
107
+ },
108
+ };
109
+ void Promise.resolve()
110
+ .then(() => run(context))
111
+ .then(
112
+ (value) => finish(value),
113
+ () => {
114
+ if (active) report(stage, 'failed');
115
+ finish();
116
+ },
117
+ );
118
+ });
119
+ }
120
+
121
+ /** Observes remote outcomes separately from the public identify promise. */
122
+ export function observeIdentifyResult(
123
+ stage: 'people' | 'datalake',
124
+ report: IdentifyReporter,
125
+ onTimeout?: () => void,
126
+ ) {
127
+ let active = true;
128
+ const complete = (reason?: IdentifyReason, httpStatus?: number): void => {
129
+ if (!active) return;
130
+ active = false;
131
+ clearTimeout(timer);
132
+ if (reason) report(stage, reason, httpStatus);
133
+ };
134
+ const timer = setTimeout(() => {
135
+ complete(stage === 'people' ? 'unobserved' : 'timeout');
136
+ onTimeout?.();
137
+ }, 5000);
138
+ return { complete };
139
+ }