@aranova/tracking-react 0.2.3 → 0.4.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.ts CHANGED
@@ -1,4 +1,6 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import { ReactNode } from 'react';
3
+ import { z } from 'zod';
2
4
 
3
5
  declare function ConsentBanner(): react_jsx_runtime.JSX.Element | null;
4
6
 
@@ -28,6 +30,7 @@ interface TrackingClientContext {
28
30
  }
29
31
  interface TrackingSessionUpsertPayload {
30
32
  session_id: string;
33
+ visitor_id: string | null;
31
34
  gclid: string | null;
32
35
  fbclid: string | null;
33
36
  utm_source: string | null;
@@ -67,6 +70,7 @@ declare global {
67
70
  getTrackingParams: () => TrackingParams;
68
71
  getConsentState: () => ConsentState;
69
72
  setConsentState: (state: 'granted' | 'denied') => void;
73
+ trackEvent: (eventType: string, metadata: Record<string, unknown>) => void;
70
74
  };
71
75
  }
72
76
  }
@@ -92,6 +96,7 @@ interface TrackingSessionInput {
92
96
  consentState?: Record<string, unknown> | null;
93
97
  firstPage?: string | null;
94
98
  sessionId: string;
99
+ visitorId?: string | null;
95
100
  }
96
101
  declare function createTrackingClientContext(surface: TrackingInstallSurface, input?: TrackingContextInput): TrackingClientContext;
97
102
  declare function createTrackingSessionUpsertPayload(trackingParams: TrackingParams, input: TrackingSessionInput, context: TrackingClientContext): TrackingSessionUpsertPayload;
@@ -100,8 +105,532 @@ declare function createTrackingEventCreatePayload(trackingParams: TrackingParams
100
105
  declare const TRACKING_PARAM_KEYS: readonly ["gclid", "fbclid", "utm_source", "utm_medium", "utm_campaign", "utm_term", "utm_content"];
101
106
  declare function captureTrackingParamsFromLocation(url?: string, maxAgeSeconds?: number): TrackingParams;
102
107
 
108
+ interface TrackEventInput {
109
+ eventType: string;
110
+ pageUrl?: string | null;
111
+ metadata?: Record<string, unknown> | null;
112
+ occurredAt?: Date | string | null;
113
+ }
114
+ interface TrackingClient {
115
+ trackEvent: (input: TrackEventInput) => void;
116
+ flush: () => Promise<void>;
117
+ getSessionId: () => string;
118
+ getVisitorId: () => string;
119
+ destroy: () => void;
120
+ }
121
+
122
+ declare const pageViewMetadataSchema: z.ZodObject<{
123
+ page: z.ZodObject<{
124
+ title: z.ZodNullable<z.ZodString>;
125
+ path: z.ZodString;
126
+ search: z.ZodString;
127
+ hash: z.ZodString;
128
+ }, "strip", z.ZodTypeAny, {
129
+ search: string;
130
+ title: string | null;
131
+ path: string;
132
+ hash: string;
133
+ }, {
134
+ search: string;
135
+ title: string | null;
136
+ path: string;
137
+ hash: string;
138
+ }>;
139
+ referrer: z.ZodNullable<z.ZodString>;
140
+ viewport: z.ZodOptional<z.ZodNullable<z.ZodObject<{
141
+ w: z.ZodNumber;
142
+ h: z.ZodNumber;
143
+ }, "strip", z.ZodTypeAny, {
144
+ w: number;
145
+ h: number;
146
+ }, {
147
+ w: number;
148
+ h: number;
149
+ }>>>;
150
+ }, "strict", z.ZodTypeAny, {
151
+ page: {
152
+ search: string;
153
+ title: string | null;
154
+ path: string;
155
+ hash: string;
156
+ };
157
+ referrer: string | null;
158
+ viewport?: {
159
+ w: number;
160
+ h: number;
161
+ } | null | undefined;
162
+ }, {
163
+ page: {
164
+ search: string;
165
+ title: string | null;
166
+ path: string;
167
+ hash: string;
168
+ };
169
+ referrer: string | null;
170
+ viewport?: {
171
+ w: number;
172
+ h: number;
173
+ } | null | undefined;
174
+ }>;
175
+ type PageViewMetadata = z.infer<typeof pageViewMetadataSchema>;
176
+ declare const pageViewConfigSchema: z.ZodObject<{}, "strict", z.ZodTypeAny, {}, {}>;
177
+ type PageViewConfig = z.infer<typeof pageViewConfigSchema>;
178
+
179
+ declare const contactPageVisitMetadataSchema: z.ZodObject<{
180
+ page: z.ZodObject<{
181
+ path: z.ZodString;
182
+ }, "strip", z.ZodTypeAny, {
183
+ path: string;
184
+ }, {
185
+ path: string;
186
+ }>;
187
+ }, "strict", z.ZodTypeAny, {
188
+ page: {
189
+ path: string;
190
+ };
191
+ }, {
192
+ page: {
193
+ path: string;
194
+ };
195
+ }>;
196
+ type ContactPageVisitMetadata = z.infer<typeof contactPageVisitMetadataSchema>;
197
+ declare const contactPageVisitConfigSchema: z.ZodObject<{
198
+ pathPattern: z.ZodType<RegExp, z.ZodTypeDef, RegExp>;
199
+ }, "strict", z.ZodTypeAny, {
200
+ pathPattern: RegExp;
201
+ }, {
202
+ pathPattern: RegExp;
203
+ }>;
204
+ type ContactPageVisitConfig = z.infer<typeof contactPageVisitConfigSchema>;
205
+
206
+ declare const formSubmitMetadataSchema: z.ZodObject<{
207
+ form: z.ZodObject<{
208
+ id: z.ZodString;
209
+ action: z.ZodNullable<z.ZodString>;
210
+ }, "strip", z.ZodTypeAny, {
211
+ id: string;
212
+ action: string | null;
213
+ }, {
214
+ id: string;
215
+ action: string | null;
216
+ }>;
217
+ page: z.ZodObject<{
218
+ path: z.ZodString;
219
+ }, "strip", z.ZodTypeAny, {
220
+ path: string;
221
+ }, {
222
+ path: string;
223
+ }>;
224
+ }, "strict", z.ZodTypeAny, {
225
+ form: {
226
+ id: string;
227
+ action: string | null;
228
+ };
229
+ page: {
230
+ path: string;
231
+ };
232
+ }, {
233
+ form: {
234
+ id: string;
235
+ action: string | null;
236
+ };
237
+ page: {
238
+ path: string;
239
+ };
240
+ }>;
241
+ type FormSubmitMetadata = z.infer<typeof formSubmitMetadataSchema>;
242
+ declare const formSubmitConfigSchema: z.ZodObject<{}, "strict", z.ZodTypeAny, {}, {}>;
243
+ type FormSubmitConfig = z.infer<typeof formSubmitConfigSchema>;
244
+
245
+ declare const phoneClickMetadataSchema: z.ZodObject<{
246
+ element: z.ZodObject<{
247
+ tag: z.ZodString;
248
+ text: z.ZodNullable<z.ZodString>;
249
+ href: z.ZodString;
250
+ }, "strip", z.ZodTypeAny, {
251
+ text: string | null;
252
+ tag: string;
253
+ href: string;
254
+ }, {
255
+ text: string | null;
256
+ tag: string;
257
+ href: string;
258
+ }>;
259
+ page: z.ZodObject<{
260
+ path: z.ZodString;
261
+ }, "strip", z.ZodTypeAny, {
262
+ path: string;
263
+ }, {
264
+ path: string;
265
+ }>;
266
+ }, "strict", z.ZodTypeAny, {
267
+ page: {
268
+ path: string;
269
+ };
270
+ element: {
271
+ text: string | null;
272
+ tag: string;
273
+ href: string;
274
+ };
275
+ }, {
276
+ page: {
277
+ path: string;
278
+ };
279
+ element: {
280
+ text: string | null;
281
+ tag: string;
282
+ href: string;
283
+ };
284
+ }>;
285
+ type PhoneClickMetadata = z.infer<typeof phoneClickMetadataSchema>;
286
+ declare const phoneClickConfigSchema: z.ZodObject<{}, "strict", z.ZodTypeAny, {}, {}>;
287
+ type PhoneClickConfig = z.infer<typeof phoneClickConfigSchema>;
288
+
289
+ declare const timeOnSiteMetadataSchema: z.ZodObject<{
290
+ duration_ms: z.ZodNumber;
291
+ page: z.ZodObject<{
292
+ path: z.ZodString;
293
+ }, "strip", z.ZodTypeAny, {
294
+ path: string;
295
+ }, {
296
+ path: string;
297
+ }>;
298
+ }, "strict", z.ZodTypeAny, {
299
+ page: {
300
+ path: string;
301
+ };
302
+ duration_ms: number;
303
+ }, {
304
+ page: {
305
+ path: string;
306
+ };
307
+ duration_ms: number;
308
+ }>;
309
+ type TimeOnSiteMetadata = z.infer<typeof timeOnSiteMetadataSchema>;
310
+ declare const timeOnSiteConfigSchema: z.ZodObject<{
311
+ thresholdSeconds: z.ZodNumber;
312
+ }, "strict", z.ZodTypeAny, {
313
+ thresholdSeconds: number;
314
+ }, {
315
+ thresholdSeconds: number;
316
+ }>;
317
+ type TimeOnSiteConfig = z.infer<typeof timeOnSiteConfigSchema>;
318
+
319
+ declare const EVENT_REGISTRY: {
320
+ readonly page_view: {
321
+ readonly kind: "automatic";
322
+ readonly metadataSchema: z.ZodObject<{
323
+ page: z.ZodObject<{
324
+ title: z.ZodNullable<z.ZodString>;
325
+ path: z.ZodString;
326
+ search: z.ZodString;
327
+ hash: z.ZodString;
328
+ }, "strip", z.ZodTypeAny, {
329
+ search: string;
330
+ title: string | null;
331
+ path: string;
332
+ hash: string;
333
+ }, {
334
+ search: string;
335
+ title: string | null;
336
+ path: string;
337
+ hash: string;
338
+ }>;
339
+ referrer: z.ZodNullable<z.ZodString>;
340
+ viewport: z.ZodOptional<z.ZodNullable<z.ZodObject<{
341
+ w: z.ZodNumber;
342
+ h: z.ZodNumber;
343
+ }, "strip", z.ZodTypeAny, {
344
+ w: number;
345
+ h: number;
346
+ }, {
347
+ w: number;
348
+ h: number;
349
+ }>>>;
350
+ }, "strict", z.ZodTypeAny, {
351
+ page: {
352
+ search: string;
353
+ title: string | null;
354
+ path: string;
355
+ hash: string;
356
+ };
357
+ referrer: string | null;
358
+ viewport?: {
359
+ w: number;
360
+ h: number;
361
+ } | null | undefined;
362
+ }, {
363
+ page: {
364
+ search: string;
365
+ title: string | null;
366
+ path: string;
367
+ hash: string;
368
+ };
369
+ referrer: string | null;
370
+ viewport?: {
371
+ w: number;
372
+ h: number;
373
+ } | null | undefined;
374
+ }>;
375
+ readonly configSchema: z.ZodObject<{}, "strict", z.ZodTypeAny, {}, {}>;
376
+ };
377
+ readonly time_on_site: {
378
+ readonly kind: "automatic";
379
+ readonly metadataSchema: z.ZodObject<{
380
+ duration_ms: z.ZodNumber;
381
+ page: z.ZodObject<{
382
+ path: z.ZodString;
383
+ }, "strip", z.ZodTypeAny, {
384
+ path: string;
385
+ }, {
386
+ path: string;
387
+ }>;
388
+ }, "strict", z.ZodTypeAny, {
389
+ page: {
390
+ path: string;
391
+ };
392
+ duration_ms: number;
393
+ }, {
394
+ page: {
395
+ path: string;
396
+ };
397
+ duration_ms: number;
398
+ }>;
399
+ readonly configSchema: z.ZodObject<{
400
+ thresholdSeconds: z.ZodNumber;
401
+ }, "strict", z.ZodTypeAny, {
402
+ thresholdSeconds: number;
403
+ }, {
404
+ thresholdSeconds: number;
405
+ }>;
406
+ };
407
+ readonly contact_page_visit: {
408
+ readonly kind: "automatic";
409
+ readonly metadataSchema: z.ZodObject<{
410
+ page: z.ZodObject<{
411
+ path: z.ZodString;
412
+ }, "strip", z.ZodTypeAny, {
413
+ path: string;
414
+ }, {
415
+ path: string;
416
+ }>;
417
+ }, "strict", z.ZodTypeAny, {
418
+ page: {
419
+ path: string;
420
+ };
421
+ }, {
422
+ page: {
423
+ path: string;
424
+ };
425
+ }>;
426
+ readonly configSchema: z.ZodObject<{
427
+ pathPattern: z.ZodType<RegExp, z.ZodTypeDef, RegExp>;
428
+ }, "strict", z.ZodTypeAny, {
429
+ pathPattern: RegExp;
430
+ }, {
431
+ pathPattern: RegExp;
432
+ }>;
433
+ };
434
+ readonly form_submit: {
435
+ readonly kind: "manual";
436
+ readonly metadataSchema: z.ZodObject<{
437
+ form: z.ZodObject<{
438
+ id: z.ZodString;
439
+ action: z.ZodNullable<z.ZodString>;
440
+ }, "strip", z.ZodTypeAny, {
441
+ id: string;
442
+ action: string | null;
443
+ }, {
444
+ id: string;
445
+ action: string | null;
446
+ }>;
447
+ page: z.ZodObject<{
448
+ path: z.ZodString;
449
+ }, "strip", z.ZodTypeAny, {
450
+ path: string;
451
+ }, {
452
+ path: string;
453
+ }>;
454
+ }, "strict", z.ZodTypeAny, {
455
+ form: {
456
+ id: string;
457
+ action: string | null;
458
+ };
459
+ page: {
460
+ path: string;
461
+ };
462
+ }, {
463
+ form: {
464
+ id: string;
465
+ action: string | null;
466
+ };
467
+ page: {
468
+ path: string;
469
+ };
470
+ }>;
471
+ readonly configSchema: z.ZodObject<{}, "strict", z.ZodTypeAny, {}, {}>;
472
+ };
473
+ readonly phone_click: {
474
+ readonly kind: "manual";
475
+ readonly metadataSchema: z.ZodObject<{
476
+ element: z.ZodObject<{
477
+ tag: z.ZodString;
478
+ text: z.ZodNullable<z.ZodString>;
479
+ href: z.ZodString;
480
+ }, "strip", z.ZodTypeAny, {
481
+ text: string | null;
482
+ tag: string;
483
+ href: string;
484
+ }, {
485
+ text: string | null;
486
+ tag: string;
487
+ href: string;
488
+ }>;
489
+ page: z.ZodObject<{
490
+ path: z.ZodString;
491
+ }, "strip", z.ZodTypeAny, {
492
+ path: string;
493
+ }, {
494
+ path: string;
495
+ }>;
496
+ }, "strict", z.ZodTypeAny, {
497
+ page: {
498
+ path: string;
499
+ };
500
+ element: {
501
+ text: string | null;
502
+ tag: string;
503
+ href: string;
504
+ };
505
+ }, {
506
+ page: {
507
+ path: string;
508
+ };
509
+ element: {
510
+ text: string | null;
511
+ tag: string;
512
+ href: string;
513
+ };
514
+ }>;
515
+ readonly configSchema: z.ZodObject<{}, "strict", z.ZodTypeAny, {}, {}>;
516
+ };
517
+ };
518
+ type EventName = keyof typeof EVENT_REGISTRY;
519
+ type AutomaticEventName = {
520
+ [K in EventName]: (typeof EVENT_REGISTRY)[K]['kind'] extends 'automatic' ? K : never;
521
+ }[EventName];
522
+ type ManualEventName = {
523
+ [K in EventName]: (typeof EVENT_REGISTRY)[K]['kind'] extends 'manual' ? K : never;
524
+ }[EventName];
525
+ type MetadataByName = {
526
+ page_view: PageViewMetadata;
527
+ time_on_site: TimeOnSiteMetadata;
528
+ contact_page_visit: ContactPageVisitMetadata;
529
+ form_submit: FormSubmitMetadata;
530
+ phone_click: PhoneClickMetadata;
531
+ };
532
+ type ConfigByName = {
533
+ page_view: PageViewConfig;
534
+ time_on_site: TimeOnSiteConfig;
535
+ contact_page_visit: ContactPageVisitConfig;
536
+ form_submit: FormSubmitConfig;
537
+ phone_click: PhoneClickConfig;
538
+ };
539
+ type EventMetadata<K extends EventName> = MetadataByName[K];
540
+ type EventConfig<K extends EventName> = ConfigByName[K];
541
+ type TriggerRegistryConfig = {
542
+ automatic: {
543
+ page_view: EventConfig<'page_view'>;
544
+ } & Partial<{
545
+ time_on_site: EventConfig<'time_on_site'>;
546
+ contact_page_visit: EventConfig<'contact_page_visit'>;
547
+ }>;
548
+ manual?: Partial<{
549
+ form_submit: EventConfig<'form_submit'>;
550
+ phone_click: EventConfig<'phone_click'>;
551
+ }>;
552
+ };
553
+ type RegisteredManualEvents<TRegistry extends TriggerRegistryConfig> = Extract<keyof NonNullable<TRegistry['manual']>, ManualEventName>;
554
+ type RegisteredAutomaticEvents<TRegistry extends TriggerRegistryConfig> = Extract<keyof TRegistry['automatic'], AutomaticEventName>;
555
+
556
+ interface TypedTrackEventOptions {
557
+ /** Override the page URL captured automatically. Rarely needed. */
558
+ pageUrl?: string | null;
559
+ /** Event timestamp override. Defaults to "now" at queue time. */
560
+ occurredAt?: Date | string | null;
561
+ }
562
+ interface TypedTrackingClient<TRegistry extends TriggerRegistryConfig> {
563
+ /**
564
+ * Fire a manually-registered event. The event name must be present in
565
+ * the registry's `manual` map and the metadata must match that event's
566
+ * canonical Zod-derived shape.
567
+ */
568
+ trackEvent<K extends RegisteredManualEvents<TRegistry>>(eventType: K, metadata: EventMetadata<K>, options?: TypedTrackEventOptions): void;
569
+ flush(): Promise<void>;
570
+ getSessionId(): string;
571
+ getVisitorId(): string;
572
+ }
573
+
103
574
  declare function useGclid(): string | null;
104
575
  declare function useTrackingParams(): TrackingParams;
105
576
  declare function useConsentState(): ConsentState;
106
577
 
107
- export { ConsentBanner, type ConsentState, GoogleAdsTracking, type GoogleAdsTrackingProps, TRACKING_PARAM_KEYS, type TrackingClientContext, type TrackingEventCreatePayload, type TrackingInitConfig, type TrackingInstallSurface, type TrackingParams, type TrackingSessionUpsertPayload, captureTrackingParamsFromLocation, createTrackingClientContext, createTrackingEventCreatePayload, createTrackingSessionUpsertPayload, getConsentState, setConsentState, useConsentState, useGclid, useTrackingParams };
578
+ interface CreateTrackingOptions<TRegistry extends TriggerRegistryConfig> {
579
+ /** Public tracking API key issued for this business. Required. */
580
+ apiKey: string;
581
+ /** Full ingest endpoint base URL, e.g. https://api.aranova.io/tracking. Required. */
582
+ endpoint: string;
583
+ /**
584
+ * Trigger registry. Determines which events the SDK fires automatically
585
+ * and which ones the consumer can fire manually via `trackEvent()`.
586
+ * `automatic.page_view` is required — every tracking install needs it.
587
+ */
588
+ triggers: TRegistry;
589
+ /**
590
+ * When true, the typed client validates every `trackEvent()` metadata
591
+ * payload through the Zod schema before forwarding. Errors are thrown
592
+ * loudly. Leave off in prod; turn on in dev to catch shape bugs early.
593
+ */
594
+ debug?: boolean;
595
+ }
596
+ interface TrackingProviderProps {
597
+ /** Optional Google Ads gtag id. If omitted, no gtag script is loaded. */
598
+ gtagId?: string;
599
+ children: ReactNode;
600
+ }
601
+ interface CreateTrackingResult<TRegistry extends TriggerRegistryConfig> {
602
+ TrackingProvider: (props: TrackingProviderProps) => ReactNode;
603
+ useTracking: () => TypedTrackingClient<TRegistry>;
604
+ }
605
+ /**
606
+ * Create a scoped TrackingProvider + useTracking hook for a specific
607
+ * trigger registry. Call this once at app startup (e.g. in a shared
608
+ * `lib/tracking.ts` file) and import the returned `TrackingProvider` /
609
+ * `useTracking` from that module, not from `@aranova/tracking-react`
610
+ * directly. This lets TypeScript thread the registry type through every
611
+ * consumer so `trackEvent()` autocompletes + rejects unregistered events.
612
+ *
613
+ * Example:
614
+ *
615
+ * ```ts
616
+ * // src/lib/tracking.ts
617
+ * import { createTracking } from '@aranova/tracking-react';
618
+ *
619
+ * export const { TrackingProvider, useTracking } = createTracking({
620
+ * apiKey: import.meta.env.VITE_ARANOVA_TRACKING_API_KEY,
621
+ * endpoint: import.meta.env.VITE_ARANOVA_TRACKING_ENDPOINT,
622
+ * triggers: {
623
+ * automatic: {
624
+ * page_view: {},
625
+ * time_on_site: { thresholdSeconds: 60 },
626
+ * },
627
+ * manual: {
628
+ * form_submit: {},
629
+ * },
630
+ * },
631
+ * });
632
+ * ```
633
+ */
634
+ declare function createTracking<TRegistry extends TriggerRegistryConfig>(options: CreateTrackingOptions<TRegistry>): CreateTrackingResult<TRegistry>;
635
+
636
+ export { type AutomaticEventName, ConsentBanner, type ConsentState, type ContactPageVisitConfig, type ContactPageVisitMetadata, type CreateTrackingOptions, type CreateTrackingResult, type EventConfig, type EventMetadata, type EventName, type FormSubmitConfig, type FormSubmitMetadata, GoogleAdsTracking, type GoogleAdsTrackingProps, type ManualEventName, type PageViewConfig, type PageViewMetadata, type PhoneClickConfig, type PhoneClickMetadata, type RegisteredAutomaticEvents, type RegisteredManualEvents, TRACKING_PARAM_KEYS, type TimeOnSiteConfig, type TimeOnSiteMetadata, type TrackingClient, type TrackingClientContext, type TrackingEventCreatePayload, type TrackingInitConfig, type TrackingInstallSurface, type TrackingParams, type TrackingProviderProps, type TrackingSessionUpsertPayload, type TriggerRegistryConfig, type TypedTrackEventOptions, type TypedTrackingClient, captureTrackingParamsFromLocation, createTracking, createTrackingClientContext, createTrackingEventCreatePayload, createTrackingSessionUpsertPayload, getConsentState, setConsentState, useConsentState, useGclid, useTrackingParams };