@pageviews/tracker 0.2.4 → 0.4.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.
- package/README.md +2 -0
- package/dist/module/index.cjs +52 -6
- package/dist/module/index.d.ts +2 -0
- package/dist/module/index.mjs +52 -6
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -37,6 +37,8 @@ track('signup', { props: { plan: 'pro' } })
|
|
|
37
37
|
identify({ userId: 'user-123' })
|
|
38
38
|
```
|
|
39
39
|
|
|
40
|
+
`track()` and `identify()` are safe to call before `init()` has finished, or even before it has been called: up to 100 calls are queued and sent, in order, as soon as tracking starts. Awaiting `init()` is optional.
|
|
41
|
+
|
|
40
42
|
Your site ID is available in the Pageviews dashboard under **Settings → Tracking**.
|
|
41
43
|
|
|
42
44
|
## Framework Examples
|
package/dist/module/index.cjs
CHANGED
|
@@ -36,7 +36,14 @@ function sendBeaconEvent(endpoint, payload, siteId) {
|
|
|
36
36
|
|
|
37
37
|
// src/core/utils.ts
|
|
38
38
|
const ALLOWED_QUERY_PARAMS = new Set([
|
|
39
|
+
// Attribution
|
|
39
40
|
'utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'ref',
|
|
41
|
+
// Pagination
|
|
42
|
+
'page', 'p', 'offset', 'limit', 'per_page',
|
|
43
|
+
// Sorting & filtering
|
|
44
|
+
'sort', 'order', 'orderby', 'order_by', 'filter', 'category', 'cat', 'tag', 'type',
|
|
45
|
+
// Content identifiers
|
|
46
|
+
'id', 'v', 'tab', 'view', 'lang', 'locale', 'hl',
|
|
40
47
|
]);
|
|
41
48
|
function sanitizeUrl(url) {
|
|
42
49
|
try {
|
|
@@ -469,6 +476,23 @@ const CACHE_KEY = 'pageviews_config';
|
|
|
469
476
|
const CACHE_TTL = 1000 * 60 * 60; // 1 hour
|
|
470
477
|
let instance = null;
|
|
471
478
|
let initialized = false;
|
|
479
|
+
/** Bumped by destroy(), so a config fetch that resolves afterwards does not start tracking. */
|
|
480
|
+
let generation = 0;
|
|
481
|
+
const MAX_QUEUED_CALLS = 100;
|
|
482
|
+
/** track()/identify() calls made before init() has finished, replayed once tracking starts. */
|
|
483
|
+
let queued = [];
|
|
484
|
+
function enqueue(call) {
|
|
485
|
+
if (queued.length < MAX_QUEUED_CALLS)
|
|
486
|
+
queued.push(call);
|
|
487
|
+
}
|
|
488
|
+
function replayQueued() {
|
|
489
|
+
if (!instance)
|
|
490
|
+
return;
|
|
491
|
+
const calls = queued;
|
|
492
|
+
queued = [];
|
|
493
|
+
for (const call of calls)
|
|
494
|
+
call(instance.tracker);
|
|
495
|
+
}
|
|
472
496
|
function getCachedConfig(siteId) {
|
|
473
497
|
try {
|
|
474
498
|
const raw = localStorage.getItem(`${CACHE_KEY}_${siteId}`);
|
|
@@ -499,6 +523,7 @@ async function fetchConfig(endpoint, siteId) {
|
|
|
499
523
|
}
|
|
500
524
|
function startTracking(config) {
|
|
501
525
|
instance = initTracking(config);
|
|
526
|
+
replayQueued();
|
|
502
527
|
}
|
|
503
528
|
async function init(options) {
|
|
504
529
|
if (initialized)
|
|
@@ -506,6 +531,7 @@ async function init(options) {
|
|
|
506
531
|
initialized = true;
|
|
507
532
|
const ingestEndpoint = (options.endpoint || 'https://data.pageviews.ai') + '/api/event';
|
|
508
533
|
const cfgEndpoint = options.configEndpoint || 'https://pageviews.ai';
|
|
534
|
+
const current = generation;
|
|
509
535
|
const cached = getCachedConfig(options.siteId);
|
|
510
536
|
if (cached) {
|
|
511
537
|
startTracking(Object.assign(Object.assign({}, cached), { siteId: options.siteId, endpoint: ingestEndpoint }));
|
|
@@ -515,26 +541,46 @@ async function init(options) {
|
|
|
515
541
|
}).catch(() => { });
|
|
516
542
|
return;
|
|
517
543
|
}
|
|
518
|
-
|
|
544
|
+
let configData;
|
|
545
|
+
try {
|
|
546
|
+
configData = await fetchConfig(cfgEndpoint, options.siteId);
|
|
547
|
+
}
|
|
548
|
+
catch (error) {
|
|
549
|
+
if (current === generation) {
|
|
550
|
+
initialized = false;
|
|
551
|
+
queued = [];
|
|
552
|
+
}
|
|
553
|
+
throw error;
|
|
554
|
+
}
|
|
555
|
+
if (current !== generation)
|
|
556
|
+
return;
|
|
519
557
|
setCachedConfig(options.siteId, configData);
|
|
520
558
|
startTracking(Object.assign(Object.assign({}, configData), { siteId: options.siteId, endpoint: ingestEndpoint }));
|
|
521
559
|
}
|
|
560
|
+
/** Sends a custom event. Calls made before init() has finished are queued and sent once it has. */
|
|
522
561
|
function track(eventName, options) {
|
|
523
|
-
if (!instance)
|
|
524
|
-
|
|
562
|
+
if (!instance) {
|
|
563
|
+
enqueue((tracker) => tracker.track(eventName, options));
|
|
564
|
+
return;
|
|
565
|
+
}
|
|
525
566
|
instance.tracker.track(eventName, options);
|
|
526
567
|
}
|
|
568
|
+
/** Identifies the visitor. Calls made before init() has finished are queued and sent once it has. */
|
|
527
569
|
function identify(data) {
|
|
528
|
-
if (!instance)
|
|
529
|
-
|
|
570
|
+
if (!instance) {
|
|
571
|
+
enqueue((tracker) => tracker.identify(data));
|
|
572
|
+
return;
|
|
573
|
+
}
|
|
530
574
|
instance.tracker.identify(data);
|
|
531
575
|
}
|
|
532
576
|
function destroy() {
|
|
577
|
+
generation++;
|
|
578
|
+
queued = [];
|
|
579
|
+
initialized = false;
|
|
533
580
|
if (!instance)
|
|
534
581
|
return;
|
|
535
582
|
instance.destroy();
|
|
536
583
|
instance = null;
|
|
537
|
-
initialized = false;
|
|
538
584
|
}
|
|
539
585
|
|
|
540
586
|
exports.destroy = destroy;
|
package/dist/module/index.d.ts
CHANGED
|
@@ -38,7 +38,9 @@ interface InitOptions {
|
|
|
38
38
|
configEndpoint?: string;
|
|
39
39
|
}
|
|
40
40
|
declare function init(options: InitOptions): Promise<void>;
|
|
41
|
+
/** Sends a custom event. Calls made before init() has finished are queued and sent once it has. */
|
|
41
42
|
declare function track(eventName: string, options?: TrackOptions): void;
|
|
43
|
+
/** Identifies the visitor. Calls made before init() has finished are queued and sent once it has. */
|
|
42
44
|
declare function identify(data: IdentifyData): void;
|
|
43
45
|
declare function destroy(): void;
|
|
44
46
|
|
package/dist/module/index.mjs
CHANGED
|
@@ -34,7 +34,14 @@ function sendBeaconEvent(endpoint, payload, siteId) {
|
|
|
34
34
|
|
|
35
35
|
// src/core/utils.ts
|
|
36
36
|
const ALLOWED_QUERY_PARAMS = new Set([
|
|
37
|
+
// Attribution
|
|
37
38
|
'utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'ref',
|
|
39
|
+
// Pagination
|
|
40
|
+
'page', 'p', 'offset', 'limit', 'per_page',
|
|
41
|
+
// Sorting & filtering
|
|
42
|
+
'sort', 'order', 'orderby', 'order_by', 'filter', 'category', 'cat', 'tag', 'type',
|
|
43
|
+
// Content identifiers
|
|
44
|
+
'id', 'v', 'tab', 'view', 'lang', 'locale', 'hl',
|
|
38
45
|
]);
|
|
39
46
|
function sanitizeUrl(url) {
|
|
40
47
|
try {
|
|
@@ -467,6 +474,23 @@ const CACHE_KEY = 'pageviews_config';
|
|
|
467
474
|
const CACHE_TTL = 1000 * 60 * 60; // 1 hour
|
|
468
475
|
let instance = null;
|
|
469
476
|
let initialized = false;
|
|
477
|
+
/** Bumped by destroy(), so a config fetch that resolves afterwards does not start tracking. */
|
|
478
|
+
let generation = 0;
|
|
479
|
+
const MAX_QUEUED_CALLS = 100;
|
|
480
|
+
/** track()/identify() calls made before init() has finished, replayed once tracking starts. */
|
|
481
|
+
let queued = [];
|
|
482
|
+
function enqueue(call) {
|
|
483
|
+
if (queued.length < MAX_QUEUED_CALLS)
|
|
484
|
+
queued.push(call);
|
|
485
|
+
}
|
|
486
|
+
function replayQueued() {
|
|
487
|
+
if (!instance)
|
|
488
|
+
return;
|
|
489
|
+
const calls = queued;
|
|
490
|
+
queued = [];
|
|
491
|
+
for (const call of calls)
|
|
492
|
+
call(instance.tracker);
|
|
493
|
+
}
|
|
470
494
|
function getCachedConfig(siteId) {
|
|
471
495
|
try {
|
|
472
496
|
const raw = localStorage.getItem(`${CACHE_KEY}_${siteId}`);
|
|
@@ -497,6 +521,7 @@ async function fetchConfig(endpoint, siteId) {
|
|
|
497
521
|
}
|
|
498
522
|
function startTracking(config) {
|
|
499
523
|
instance = initTracking(config);
|
|
524
|
+
replayQueued();
|
|
500
525
|
}
|
|
501
526
|
async function init(options) {
|
|
502
527
|
if (initialized)
|
|
@@ -504,6 +529,7 @@ async function init(options) {
|
|
|
504
529
|
initialized = true;
|
|
505
530
|
const ingestEndpoint = (options.endpoint || 'https://data.pageviews.ai') + '/api/event';
|
|
506
531
|
const cfgEndpoint = options.configEndpoint || 'https://pageviews.ai';
|
|
532
|
+
const current = generation;
|
|
507
533
|
const cached = getCachedConfig(options.siteId);
|
|
508
534
|
if (cached) {
|
|
509
535
|
startTracking(Object.assign(Object.assign({}, cached), { siteId: options.siteId, endpoint: ingestEndpoint }));
|
|
@@ -513,26 +539,46 @@ async function init(options) {
|
|
|
513
539
|
}).catch(() => { });
|
|
514
540
|
return;
|
|
515
541
|
}
|
|
516
|
-
|
|
542
|
+
let configData;
|
|
543
|
+
try {
|
|
544
|
+
configData = await fetchConfig(cfgEndpoint, options.siteId);
|
|
545
|
+
}
|
|
546
|
+
catch (error) {
|
|
547
|
+
if (current === generation) {
|
|
548
|
+
initialized = false;
|
|
549
|
+
queued = [];
|
|
550
|
+
}
|
|
551
|
+
throw error;
|
|
552
|
+
}
|
|
553
|
+
if (current !== generation)
|
|
554
|
+
return;
|
|
517
555
|
setCachedConfig(options.siteId, configData);
|
|
518
556
|
startTracking(Object.assign(Object.assign({}, configData), { siteId: options.siteId, endpoint: ingestEndpoint }));
|
|
519
557
|
}
|
|
558
|
+
/** Sends a custom event. Calls made before init() has finished are queued and sent once it has. */
|
|
520
559
|
function track(eventName, options) {
|
|
521
|
-
if (!instance)
|
|
522
|
-
|
|
560
|
+
if (!instance) {
|
|
561
|
+
enqueue((tracker) => tracker.track(eventName, options));
|
|
562
|
+
return;
|
|
563
|
+
}
|
|
523
564
|
instance.tracker.track(eventName, options);
|
|
524
565
|
}
|
|
566
|
+
/** Identifies the visitor. Calls made before init() has finished are queued and sent once it has. */
|
|
525
567
|
function identify(data) {
|
|
526
|
-
if (!instance)
|
|
527
|
-
|
|
568
|
+
if (!instance) {
|
|
569
|
+
enqueue((tracker) => tracker.identify(data));
|
|
570
|
+
return;
|
|
571
|
+
}
|
|
528
572
|
instance.tracker.identify(data);
|
|
529
573
|
}
|
|
530
574
|
function destroy() {
|
|
575
|
+
generation++;
|
|
576
|
+
queued = [];
|
|
577
|
+
initialized = false;
|
|
531
578
|
if (!instance)
|
|
532
579
|
return;
|
|
533
580
|
instance.destroy();
|
|
534
581
|
instance = null;
|
|
535
|
-
initialized = false;
|
|
536
582
|
}
|
|
537
583
|
|
|
538
584
|
export { destroy, identify, init, track };
|
package/package.json
CHANGED