alphana-sdk 1.0.0 → 1.5.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/index.d.mts CHANGED
@@ -46,19 +46,34 @@ interface TrackerConfig {
46
46
  */
47
47
  trackLogs?: boolean;
48
48
  /**
49
- * List of page paths for which heatmap data should be captured.
50
- * Only paths registered here will be tracked. If empty or undefined, the SDK
51
- * will send data for all pages (the backend enforces limits at ingest time).
49
+ * List of page paths for which heatmap data should be captured client-side.
50
+ * Paths should match the dashboard "Heatmap pages" list (decoded Unicode is
51
+ * fine the SDK normalizes percent-encoding vs `window.location` mismatches).
52
52
  *
53
- * Obtain the list of registered paths from the alphana dashboard under
54
- * "Heatmap Pages" for your app, then pass them here.
53
+ * If empty or undefined, the SDK may still collect moves locally, but the
54
+ * backend only persists points when the app has at least one registered
55
+ * heatmap page and the path matches.
55
56
  *
56
57
  * Example: `heatmapPages: ["/", "/pricing", "/dashboard"]`
57
58
  */
58
59
  heatmapPages?: string[];
60
+ /**
61
+ * When true, records DOM mutations with rrweb and sends `session_replay` events
62
+ * for pixel-accurate session replay in the dashboard (requires plan + platform).
63
+ * @default false
64
+ */
65
+ sessionReplay?: boolean;
66
+ /** rrweb full snapshot interval in ms. @default 600000 (10 min) */
67
+ sessionReplayCheckoutEveryNms?: number;
68
+ /** Max rrweb events per batch before an immediate flush. @default 48 */
69
+ sessionReplayMaxEventsPerBatch?: number;
70
+ /** Periodic flush of buffered rrweb events (ms). @default 4000 */
71
+ sessionReplayFlushIntervalMs?: number;
59
72
  /** Called synchronously for every emitted event. */
60
73
  onEvent?: (event: TrackerEvent) => void;
61
74
  }
75
+ /** Assigned variant key per running A/B experiment (`null` = not in experiment). */
76
+ type AbVariantsMap = Record<string, string | null>;
62
77
  interface GeoLocation {
63
78
  /** ISO 3166-1 alpha-2 country code, e.g. "US" */
64
79
  country: string;
@@ -69,12 +84,32 @@ interface GeoLocation {
69
84
  latitude?: number;
70
85
  longitude?: number;
71
86
  }
87
+ interface UtmParams {
88
+ source?: string;
89
+ medium?: string;
90
+ campaign?: string;
91
+ term?: string;
92
+ content?: string;
93
+ }
94
+ interface AttributionContext {
95
+ landingPage: string;
96
+ referrer?: string;
97
+ referrerHost?: string;
98
+ utm?: UtmParams;
99
+ clickIds?: Record<string, string>;
100
+ capturedAt: number;
101
+ }
72
102
  interface PageView {
73
103
  path: string;
74
104
  title: string;
75
105
  timestamp: number;
76
106
  sessionId: string;
77
107
  referrer?: string;
108
+ utm?: UtmParams;
109
+ attribution?: {
110
+ firstTouch?: AttributionContext;
111
+ lastTouch?: AttributionContext;
112
+ };
78
113
  }
79
114
  interface TimeSpent {
80
115
  path: string;
@@ -121,6 +156,97 @@ interface UTurn {
121
156
  timestamp: number;
122
157
  sessionId: string;
123
158
  }
159
+ type UserProperties = Record<string, string>;
160
+ interface IdentifyEvent {
161
+ properties: UserProperties;
162
+ visitorId: string;
163
+ timestamp: number;
164
+ }
165
+ type RevenueEventStatus = "pending" | "paid" | "refunded" | "cancelled" | "failed";
166
+ interface RevenueLineItem {
167
+ id?: string;
168
+ name?: string;
169
+ category?: string;
170
+ quantity?: number;
171
+ price?: number;
172
+ }
173
+ interface RevenueEventPayload {
174
+ eventName?: "purchase" | "subscription" | "renewal" | "upgrade" | "refund" | string;
175
+ amount: number;
176
+ currency: string;
177
+ transactionId?: string;
178
+ orderId?: string;
179
+ productId?: string;
180
+ planId?: string;
181
+ coupon?: string;
182
+ status?: RevenueEventStatus;
183
+ items?: RevenueLineItem[];
184
+ metadata?: Record<string, string | number | boolean | null>;
185
+ }
186
+ interface RevenueEvent extends RevenueEventPayload {
187
+ sessionId: string;
188
+ visitorId: string;
189
+ timestamp: number;
190
+ attribution?: {
191
+ firstTouch?: AttributionContext;
192
+ lastTouch?: AttributionContext;
193
+ };
194
+ }
195
+ interface GoalEventPayload {
196
+ key: string;
197
+ name?: string;
198
+ value?: number;
199
+ currency?: string;
200
+ metadata?: Record<string, string | number | boolean | null>;
201
+ }
202
+ interface GoalEvent extends GoalEventPayload {
203
+ sessionId: string;
204
+ visitorId: string;
205
+ path: string;
206
+ timestamp: number;
207
+ }
208
+ interface JourneyStepEventPayload {
209
+ key: string;
210
+ label?: string;
211
+ path?: string;
212
+ metadata?: Record<string, string | number | boolean | null>;
213
+ }
214
+ interface JourneyStepEvent extends JourneyStepEventPayload {
215
+ sessionId: string;
216
+ visitorId: string;
217
+ path: string;
218
+ timestamp: number;
219
+ }
220
+ /**
221
+ * One-time (or rare) snapshot of the client environment for a session.
222
+ * Lets the backend align device / OS / browser with what the browser reports
223
+ * (useful vs. reduced User-Agent strings) and store locale / viewport context
224
+ * for session replay catalog rows.
225
+ */
226
+ interface ClientContext {
227
+ sessionId: string;
228
+ timestamp: number;
229
+ device: "desktop" | "mobile" | "tablet";
230
+ os: string;
231
+ browser: string;
232
+ language: string;
233
+ languages: string[];
234
+ /** `prefers-color-scheme` when available */
235
+ colorScheme: "" | "light" | "dark";
236
+ screenWidth: number;
237
+ screenHeight: number;
238
+ viewportWidth: number;
239
+ viewportHeight: number;
240
+ devicePixelRatio: number;
241
+ /** IANA time zone from `Intl`, e.g. `Asia/Tehran` */
242
+ timeZone: string;
243
+ sdkVersion: string;
244
+ }
245
+ /** One batch of rrweb `eventWithTime` payloads for the backend. */
246
+ interface SessionReplayBatch {
247
+ seq: number;
248
+ events: unknown[];
249
+ }
124
250
  type TrackerEvent = {
125
251
  type: "pageview";
126
252
  data: PageView;
@@ -136,6 +262,24 @@ type TrackerEvent = {
136
262
  } | {
137
263
  type: "uturn";
138
264
  data: UTurn;
265
+ } | {
266
+ type: "identify";
267
+ data: IdentifyEvent;
268
+ } | {
269
+ type: "revenue";
270
+ data: RevenueEvent;
271
+ } | {
272
+ type: "goal";
273
+ data: GoalEvent;
274
+ } | {
275
+ type: "journey_step";
276
+ data: JourneyStepEvent;
277
+ } | {
278
+ type: "client_context";
279
+ data: ClientContext;
280
+ } | {
281
+ type: "session_replay";
282
+ data: SessionReplayBatch;
139
283
  };
140
284
  interface SessionData {
141
285
  id: string;
@@ -147,6 +291,13 @@ interface SessionData {
147
291
  timeSpent: Record<string, number>;
148
292
  /** Collected points per path */
149
293
  heatmap: Record<string, HeatmapPoint[]>;
294
+ /** Latest properties supplied through identify(). */
295
+ userProperties: UserProperties;
296
+ /** First and latest marketing touchpoints captured for this visitor. */
297
+ attribution?: {
298
+ firstTouch?: AttributionContext;
299
+ lastTouch?: AttributionContext;
300
+ };
150
301
  /** Approximate visitor location resolved from IP (filled asynchronously) */
151
302
  location?: GeoLocation;
152
303
  }
@@ -215,12 +366,14 @@ declare class LogCapture {
215
366
  declare const DEFAULT_ENDPOINT = "https://api.alphana.ir/api/events";
216
367
  type SubscriberFn = (event: TrackerEvent) => void;
217
368
  type FlagSubscriberFn = (flags: Record<string, boolean>) => void;
369
+ type AbTestSubscriberFn = (variants: AbVariantsMap) => void;
218
370
  declare class UserTracker {
219
371
  private readonly cfg;
220
372
  private session;
221
373
  private navigation?;
222
374
  private time?;
223
375
  private heatmap?;
376
+ private sessionReplay?;
224
377
  /** Public so consumers can call logCapture.capture() for manual log entries. */
225
378
  logCapture?: LogCapture;
226
379
  private initialized;
@@ -232,7 +385,11 @@ declare class UserTracker {
232
385
  private userProperties;
233
386
  private flags;
234
387
  private readonly flagSubscribers;
388
+ private abVariants;
389
+ private readonly abTestSubscribers;
235
390
  constructor(config?: TrackerConfig);
391
+ private updateAttributionForPageView;
392
+ private currentAttribution;
236
393
  /**
237
394
  * Attach event listeners and start tracking.
238
395
  * Safe to call during SSR — returns `this` immediately if `window` is
@@ -277,6 +434,16 @@ declare class UserTracker {
277
434
  * ```
278
435
  */
279
436
  trackPageView(path?: string): void;
437
+ /**
438
+ * Track a monetary conversion such as a purchase, subscription, renewal,
439
+ * upgrade, or refund. Revenue events include the current attribution context
440
+ * so the backend can credit campaigns without recomputing browser state.
441
+ */
442
+ trackRevenue(payload: RevenueEventPayload): void;
443
+ /** Track a business goal such as signup, trial_start, lead, or checkout_start. */
444
+ trackGoal(payload: GoalEventPayload): void;
445
+ /** Track a named product journey milestone beyond automatic pageviews. */
446
+ trackJourneyStep(payload: JourneyStepEventPayload): void;
280
447
  /**
281
448
  * Identify the current user with a set of properties.
282
449
  * Properties are merged with any previously set ones and used for feature
@@ -309,6 +476,34 @@ declare class UserTracker {
309
476
  onFlagsChange(fn: FlagSubscriberFn): () => void;
310
477
  /** Fetch (or re-fetch) flags from the backend evaluate endpoint. */
311
478
  fetchFlags(): Promise<void>;
479
+ /**
480
+ * Returns variant keys assigned to this visitor for each running experiment.
481
+ * Fetched on `init()` and after `fetchAbTests()`.
482
+ *
483
+ * ```ts
484
+ * const variants = tracker.getAbVariants();
485
+ * // { 'checkout-cta-test': 'variant-b' }
486
+ * ```
487
+ */
488
+ getAbVariants(): AbVariantsMap;
489
+ /**
490
+ * Returns the assigned variant key for one experiment, or `null` if the
491
+ * experiment is not running or not found.
492
+ */
493
+ getAbVariant(experimentKey: string): string | null;
494
+ /**
495
+ * Returns `true` when the visitor is assigned to the given variant key.
496
+ */
497
+ isAbVariant(experimentKey: string, variantKey: string): boolean;
498
+ /**
499
+ * Subscribe to A/B assignment updates. Returns an unsubscribe function.
500
+ */
501
+ onAbTestsChange(fn: AbTestSubscriberFn): () => void;
502
+ /**
503
+ * Fetch (or re-fetch) variant assignments from `/ab-tests/evaluate`.
504
+ * @param keys When set, only these experiment keys are evaluated and merged.
505
+ */
506
+ fetchAbTests(keys?: string[]): Promise<void>;
312
507
  /** A read-only snapshot of the current session. */
313
508
  getSession(): Readonly<SessionData>;
314
509
  /** All page views recorded so far. */
@@ -336,4 +531,15 @@ declare class UserTracker {
336
531
  private sendBatch;
337
532
  }
338
533
 
339
- export { DEFAULT_ENDPOINT, type GeoLocation, type HeatmapPoint, type HeatmapRenderOptions, LogCapture, type LogEntry, type LogLevel, type PageView, type RageClick, type SessionData, type TimeSpent, type TrackerConfig, type TrackerEvent, type UTurn, UserTracker };
534
+ declare const ALPHANA_SDK_VERSION = "1.0.2";
535
+
536
+ /**
537
+ * Canonical URL path (+ optional query) for analytics / heatmap matching.
538
+ *
539
+ * Next.js `usePathname()` often returns percent-encoded segments while
540
+ * `window.location.pathname` is decoded — without normalization the backend
541
+ * cannot match registered heatmap pages or aggregate the same route.
542
+ */
543
+ declare function normalizeTrackerPath(path: string): string;
544
+
545
+ export { ALPHANA_SDK_VERSION, type AbVariantsMap, type AttributionContext, type ClientContext, DEFAULT_ENDPOINT, type GeoLocation, type GoalEvent, type GoalEventPayload, type HeatmapPoint, type HeatmapRenderOptions, type JourneyStepEvent, type JourneyStepEventPayload, LogCapture, type LogEntry, type LogLevel, type PageView, type RageClick, type RevenueEvent, type RevenueEventPayload, type RevenueEventStatus, type RevenueLineItem, type SessionData, type TimeSpent, type TrackerConfig, type TrackerEvent, type UTurn, UserTracker, type UtmParams, normalizeTrackerPath };
package/dist/index.d.ts CHANGED
@@ -46,19 +46,34 @@ interface TrackerConfig {
46
46
  */
47
47
  trackLogs?: boolean;
48
48
  /**
49
- * List of page paths for which heatmap data should be captured.
50
- * Only paths registered here will be tracked. If empty or undefined, the SDK
51
- * will send data for all pages (the backend enforces limits at ingest time).
49
+ * List of page paths for which heatmap data should be captured client-side.
50
+ * Paths should match the dashboard "Heatmap pages" list (decoded Unicode is
51
+ * fine the SDK normalizes percent-encoding vs `window.location` mismatches).
52
52
  *
53
- * Obtain the list of registered paths from the alphana dashboard under
54
- * "Heatmap Pages" for your app, then pass them here.
53
+ * If empty or undefined, the SDK may still collect moves locally, but the
54
+ * backend only persists points when the app has at least one registered
55
+ * heatmap page and the path matches.
55
56
  *
56
57
  * Example: `heatmapPages: ["/", "/pricing", "/dashboard"]`
57
58
  */
58
59
  heatmapPages?: string[];
60
+ /**
61
+ * When true, records DOM mutations with rrweb and sends `session_replay` events
62
+ * for pixel-accurate session replay in the dashboard (requires plan + platform).
63
+ * @default false
64
+ */
65
+ sessionReplay?: boolean;
66
+ /** rrweb full snapshot interval in ms. @default 600000 (10 min) */
67
+ sessionReplayCheckoutEveryNms?: number;
68
+ /** Max rrweb events per batch before an immediate flush. @default 48 */
69
+ sessionReplayMaxEventsPerBatch?: number;
70
+ /** Periodic flush of buffered rrweb events (ms). @default 4000 */
71
+ sessionReplayFlushIntervalMs?: number;
59
72
  /** Called synchronously for every emitted event. */
60
73
  onEvent?: (event: TrackerEvent) => void;
61
74
  }
75
+ /** Assigned variant key per running A/B experiment (`null` = not in experiment). */
76
+ type AbVariantsMap = Record<string, string | null>;
62
77
  interface GeoLocation {
63
78
  /** ISO 3166-1 alpha-2 country code, e.g. "US" */
64
79
  country: string;
@@ -69,12 +84,32 @@ interface GeoLocation {
69
84
  latitude?: number;
70
85
  longitude?: number;
71
86
  }
87
+ interface UtmParams {
88
+ source?: string;
89
+ medium?: string;
90
+ campaign?: string;
91
+ term?: string;
92
+ content?: string;
93
+ }
94
+ interface AttributionContext {
95
+ landingPage: string;
96
+ referrer?: string;
97
+ referrerHost?: string;
98
+ utm?: UtmParams;
99
+ clickIds?: Record<string, string>;
100
+ capturedAt: number;
101
+ }
72
102
  interface PageView {
73
103
  path: string;
74
104
  title: string;
75
105
  timestamp: number;
76
106
  sessionId: string;
77
107
  referrer?: string;
108
+ utm?: UtmParams;
109
+ attribution?: {
110
+ firstTouch?: AttributionContext;
111
+ lastTouch?: AttributionContext;
112
+ };
78
113
  }
79
114
  interface TimeSpent {
80
115
  path: string;
@@ -121,6 +156,97 @@ interface UTurn {
121
156
  timestamp: number;
122
157
  sessionId: string;
123
158
  }
159
+ type UserProperties = Record<string, string>;
160
+ interface IdentifyEvent {
161
+ properties: UserProperties;
162
+ visitorId: string;
163
+ timestamp: number;
164
+ }
165
+ type RevenueEventStatus = "pending" | "paid" | "refunded" | "cancelled" | "failed";
166
+ interface RevenueLineItem {
167
+ id?: string;
168
+ name?: string;
169
+ category?: string;
170
+ quantity?: number;
171
+ price?: number;
172
+ }
173
+ interface RevenueEventPayload {
174
+ eventName?: "purchase" | "subscription" | "renewal" | "upgrade" | "refund" | string;
175
+ amount: number;
176
+ currency: string;
177
+ transactionId?: string;
178
+ orderId?: string;
179
+ productId?: string;
180
+ planId?: string;
181
+ coupon?: string;
182
+ status?: RevenueEventStatus;
183
+ items?: RevenueLineItem[];
184
+ metadata?: Record<string, string | number | boolean | null>;
185
+ }
186
+ interface RevenueEvent extends RevenueEventPayload {
187
+ sessionId: string;
188
+ visitorId: string;
189
+ timestamp: number;
190
+ attribution?: {
191
+ firstTouch?: AttributionContext;
192
+ lastTouch?: AttributionContext;
193
+ };
194
+ }
195
+ interface GoalEventPayload {
196
+ key: string;
197
+ name?: string;
198
+ value?: number;
199
+ currency?: string;
200
+ metadata?: Record<string, string | number | boolean | null>;
201
+ }
202
+ interface GoalEvent extends GoalEventPayload {
203
+ sessionId: string;
204
+ visitorId: string;
205
+ path: string;
206
+ timestamp: number;
207
+ }
208
+ interface JourneyStepEventPayload {
209
+ key: string;
210
+ label?: string;
211
+ path?: string;
212
+ metadata?: Record<string, string | number | boolean | null>;
213
+ }
214
+ interface JourneyStepEvent extends JourneyStepEventPayload {
215
+ sessionId: string;
216
+ visitorId: string;
217
+ path: string;
218
+ timestamp: number;
219
+ }
220
+ /**
221
+ * One-time (or rare) snapshot of the client environment for a session.
222
+ * Lets the backend align device / OS / browser with what the browser reports
223
+ * (useful vs. reduced User-Agent strings) and store locale / viewport context
224
+ * for session replay catalog rows.
225
+ */
226
+ interface ClientContext {
227
+ sessionId: string;
228
+ timestamp: number;
229
+ device: "desktop" | "mobile" | "tablet";
230
+ os: string;
231
+ browser: string;
232
+ language: string;
233
+ languages: string[];
234
+ /** `prefers-color-scheme` when available */
235
+ colorScheme: "" | "light" | "dark";
236
+ screenWidth: number;
237
+ screenHeight: number;
238
+ viewportWidth: number;
239
+ viewportHeight: number;
240
+ devicePixelRatio: number;
241
+ /** IANA time zone from `Intl`, e.g. `Asia/Tehran` */
242
+ timeZone: string;
243
+ sdkVersion: string;
244
+ }
245
+ /** One batch of rrweb `eventWithTime` payloads for the backend. */
246
+ interface SessionReplayBatch {
247
+ seq: number;
248
+ events: unknown[];
249
+ }
124
250
  type TrackerEvent = {
125
251
  type: "pageview";
126
252
  data: PageView;
@@ -136,6 +262,24 @@ type TrackerEvent = {
136
262
  } | {
137
263
  type: "uturn";
138
264
  data: UTurn;
265
+ } | {
266
+ type: "identify";
267
+ data: IdentifyEvent;
268
+ } | {
269
+ type: "revenue";
270
+ data: RevenueEvent;
271
+ } | {
272
+ type: "goal";
273
+ data: GoalEvent;
274
+ } | {
275
+ type: "journey_step";
276
+ data: JourneyStepEvent;
277
+ } | {
278
+ type: "client_context";
279
+ data: ClientContext;
280
+ } | {
281
+ type: "session_replay";
282
+ data: SessionReplayBatch;
139
283
  };
140
284
  interface SessionData {
141
285
  id: string;
@@ -147,6 +291,13 @@ interface SessionData {
147
291
  timeSpent: Record<string, number>;
148
292
  /** Collected points per path */
149
293
  heatmap: Record<string, HeatmapPoint[]>;
294
+ /** Latest properties supplied through identify(). */
295
+ userProperties: UserProperties;
296
+ /** First and latest marketing touchpoints captured for this visitor. */
297
+ attribution?: {
298
+ firstTouch?: AttributionContext;
299
+ lastTouch?: AttributionContext;
300
+ };
150
301
  /** Approximate visitor location resolved from IP (filled asynchronously) */
151
302
  location?: GeoLocation;
152
303
  }
@@ -215,12 +366,14 @@ declare class LogCapture {
215
366
  declare const DEFAULT_ENDPOINT = "https://api.alphana.ir/api/events";
216
367
  type SubscriberFn = (event: TrackerEvent) => void;
217
368
  type FlagSubscriberFn = (flags: Record<string, boolean>) => void;
369
+ type AbTestSubscriberFn = (variants: AbVariantsMap) => void;
218
370
  declare class UserTracker {
219
371
  private readonly cfg;
220
372
  private session;
221
373
  private navigation?;
222
374
  private time?;
223
375
  private heatmap?;
376
+ private sessionReplay?;
224
377
  /** Public so consumers can call logCapture.capture() for manual log entries. */
225
378
  logCapture?: LogCapture;
226
379
  private initialized;
@@ -232,7 +385,11 @@ declare class UserTracker {
232
385
  private userProperties;
233
386
  private flags;
234
387
  private readonly flagSubscribers;
388
+ private abVariants;
389
+ private readonly abTestSubscribers;
235
390
  constructor(config?: TrackerConfig);
391
+ private updateAttributionForPageView;
392
+ private currentAttribution;
236
393
  /**
237
394
  * Attach event listeners and start tracking.
238
395
  * Safe to call during SSR — returns `this` immediately if `window` is
@@ -277,6 +434,16 @@ declare class UserTracker {
277
434
  * ```
278
435
  */
279
436
  trackPageView(path?: string): void;
437
+ /**
438
+ * Track a monetary conversion such as a purchase, subscription, renewal,
439
+ * upgrade, or refund. Revenue events include the current attribution context
440
+ * so the backend can credit campaigns without recomputing browser state.
441
+ */
442
+ trackRevenue(payload: RevenueEventPayload): void;
443
+ /** Track a business goal such as signup, trial_start, lead, or checkout_start. */
444
+ trackGoal(payload: GoalEventPayload): void;
445
+ /** Track a named product journey milestone beyond automatic pageviews. */
446
+ trackJourneyStep(payload: JourneyStepEventPayload): void;
280
447
  /**
281
448
  * Identify the current user with a set of properties.
282
449
  * Properties are merged with any previously set ones and used for feature
@@ -309,6 +476,34 @@ declare class UserTracker {
309
476
  onFlagsChange(fn: FlagSubscriberFn): () => void;
310
477
  /** Fetch (or re-fetch) flags from the backend evaluate endpoint. */
311
478
  fetchFlags(): Promise<void>;
479
+ /**
480
+ * Returns variant keys assigned to this visitor for each running experiment.
481
+ * Fetched on `init()` and after `fetchAbTests()`.
482
+ *
483
+ * ```ts
484
+ * const variants = tracker.getAbVariants();
485
+ * // { 'checkout-cta-test': 'variant-b' }
486
+ * ```
487
+ */
488
+ getAbVariants(): AbVariantsMap;
489
+ /**
490
+ * Returns the assigned variant key for one experiment, or `null` if the
491
+ * experiment is not running or not found.
492
+ */
493
+ getAbVariant(experimentKey: string): string | null;
494
+ /**
495
+ * Returns `true` when the visitor is assigned to the given variant key.
496
+ */
497
+ isAbVariant(experimentKey: string, variantKey: string): boolean;
498
+ /**
499
+ * Subscribe to A/B assignment updates. Returns an unsubscribe function.
500
+ */
501
+ onAbTestsChange(fn: AbTestSubscriberFn): () => void;
502
+ /**
503
+ * Fetch (or re-fetch) variant assignments from `/ab-tests/evaluate`.
504
+ * @param keys When set, only these experiment keys are evaluated and merged.
505
+ */
506
+ fetchAbTests(keys?: string[]): Promise<void>;
312
507
  /** A read-only snapshot of the current session. */
313
508
  getSession(): Readonly<SessionData>;
314
509
  /** All page views recorded so far. */
@@ -336,4 +531,15 @@ declare class UserTracker {
336
531
  private sendBatch;
337
532
  }
338
533
 
339
- export { DEFAULT_ENDPOINT, type GeoLocation, type HeatmapPoint, type HeatmapRenderOptions, LogCapture, type LogEntry, type LogLevel, type PageView, type RageClick, type SessionData, type TimeSpent, type TrackerConfig, type TrackerEvent, type UTurn, UserTracker };
534
+ declare const ALPHANA_SDK_VERSION = "1.0.2";
535
+
536
+ /**
537
+ * Canonical URL path (+ optional query) for analytics / heatmap matching.
538
+ *
539
+ * Next.js `usePathname()` often returns percent-encoded segments while
540
+ * `window.location.pathname` is decoded — without normalization the backend
541
+ * cannot match registered heatmap pages or aggregate the same route.
542
+ */
543
+ declare function normalizeTrackerPath(path: string): string;
544
+
545
+ export { ALPHANA_SDK_VERSION, type AbVariantsMap, type AttributionContext, type ClientContext, DEFAULT_ENDPOINT, type GeoLocation, type GoalEvent, type GoalEventPayload, type HeatmapPoint, type HeatmapRenderOptions, type JourneyStepEvent, type JourneyStepEventPayload, LogCapture, type LogEntry, type LogLevel, type PageView, type RageClick, type RevenueEvent, type RevenueEventPayload, type RevenueEventStatus, type RevenueLineItem, type SessionData, type TimeSpent, type TrackerConfig, type TrackerEvent, type UTurn, UserTracker, type UtmParams, normalizeTrackerPath };