@compilacion/colleciones-clientos 2.0.30 → 2.0.33
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/browser.domainModel.gtm.js +285 -44
- package/dist/browser.domainModel.gtm.js.map +1 -1
- package/dist/browser.domainModel.gtm.min.js +1 -1
- package/dist/browser.domainModel.gtm.min.js.map +1 -1
- package/dist/browser.gtm.js +285 -44
- package/dist/browser.gtm.js.map +1 -1
- package/dist/browser.gtm.min.js +1 -1
- package/dist/browser.gtm.min.js.map +1 -1
- package/dist/browser.js +285 -44
- package/dist/browser.js.map +1 -1
- package/dist/browser.min.js +1 -1
- package/dist/browser.min.js.map +1 -1
- package/dist/index.cjs +285 -44
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +285 -44
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -15,30 +15,6 @@ const toBase64 = function (str) {
|
|
|
15
15
|
}
|
|
16
16
|
};
|
|
17
17
|
|
|
18
|
-
/**
|
|
19
|
-
* Collects browser-related context values like screen size, language, etc.
|
|
20
|
-
* Returns an empty object if not in browser environment.
|
|
21
|
-
* @returns {Object}
|
|
22
|
-
*/
|
|
23
|
-
const getBrowserContext = function() {
|
|
24
|
-
if (typeof window === 'undefined' || typeof navigator === 'undefined') {
|
|
25
|
-
return {};
|
|
26
|
-
}
|
|
27
|
-
return {
|
|
28
|
-
hasFocus: document.hasFocus(),
|
|
29
|
-
language: navigator.language,
|
|
30
|
-
platform: navigator.platform,
|
|
31
|
-
referrer: document.referrer,
|
|
32
|
-
screenHeight: window.screen.height,
|
|
33
|
-
screenWidth: window.screen.width,
|
|
34
|
-
timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
|
|
35
|
-
url: window.location.href,
|
|
36
|
-
userAgent: navigator.userAgent,
|
|
37
|
-
viewportHeight: window.innerHeight,
|
|
38
|
-
viewportWidth: window.innerWidth,
|
|
39
|
-
};
|
|
40
|
-
};
|
|
41
|
-
|
|
42
18
|
const formatToCamelCase = function(input) {
|
|
43
19
|
return input
|
|
44
20
|
.replace(/[^a-zA-Z0-9]+/g, ' ')
|
|
@@ -256,6 +232,27 @@ class CollecionesEvent {
|
|
|
256
232
|
this.context[context] = value;
|
|
257
233
|
}
|
|
258
234
|
|
|
235
|
+
/**
|
|
236
|
+
* Records a namespaced enrichment under `meta.enrichments`. A producer or
|
|
237
|
+
* processor the event passes through claims its own `name` ("I am X") and may
|
|
238
|
+
* declare what subject the data is `about` ("this tells something about Y"), so a
|
|
239
|
+
* model-aware consumer (e.g. the server) can map it onto entity state. Kept OUT
|
|
240
|
+
* of `context` on purpose: enrichments are transport/environment metadata, not
|
|
241
|
+
* part of the domain-validated event payload.
|
|
242
|
+
* @param {string} name - The enrichment namespace (the source identity).
|
|
243
|
+
* @param {string|string[]} about - The subject(s) the data describes (recommended).
|
|
244
|
+
* @param {*} data - The contributed payload.
|
|
245
|
+
*/
|
|
246
|
+
setEnrichment = function(name, about, data) {
|
|
247
|
+
if (typeof name !== 'string') {
|
|
248
|
+
throw new Error('Enrichment name must be a string');
|
|
249
|
+
}
|
|
250
|
+
if (!this.meta.enrichments) {
|
|
251
|
+
this.meta.enrichments = {};
|
|
252
|
+
}
|
|
253
|
+
this.meta.enrichments[name] = { about, data };
|
|
254
|
+
}
|
|
255
|
+
|
|
259
256
|
/**
|
|
260
257
|
* Alias for `setReference` for compatibility.
|
|
261
258
|
* Declares an external entity referenced by this event.
|
|
@@ -623,6 +620,44 @@ class CollecionesTracker {
|
|
|
623
620
|
this.emitters = emitters;
|
|
624
621
|
this.trackerName = trackerName;
|
|
625
622
|
this.appName = appName;
|
|
623
|
+
this.handlers = [];
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
/**
|
|
627
|
+
* Register an enrichment handler. A handler self-identifies (`name` — "I am X")
|
|
628
|
+
* and may declare what it is `about` (the subject(s) — "this tells about Y"); on
|
|
629
|
+
* track it contributes `collect(event)` into `meta.enrichments[name]`. An optional
|
|
630
|
+
* `appliesTo(event)` lets a handler contribute only for relevant events, and
|
|
631
|
+
* `collect` may return `null`/`undefined` to contribute nothing for this event.
|
|
632
|
+
* Handlers stay model-agnostic — `about` is a plain subject string (or array); a
|
|
633
|
+
* model-aware consumer (the server) does the actual mapping.
|
|
634
|
+
* @param {{name: string, about?: string|string[], collect: function, appliesTo?: function}} handler
|
|
635
|
+
* @returns {CollecionesTracker} this (chainable).
|
|
636
|
+
*/
|
|
637
|
+
use(handler) {
|
|
638
|
+
if (!handler || typeof handler.name !== 'string' || typeof handler.collect !== 'function') {
|
|
639
|
+
throw new Error('Handler must have a string `name` and a `collect(event)` function');
|
|
640
|
+
}
|
|
641
|
+
this.handlers.push(handler);
|
|
642
|
+
return this;
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
/** Run every registered handler against the event, writing namespaced enrichments. */
|
|
646
|
+
runHandlers(collecionesEvent) {
|
|
647
|
+
this.handlers.forEach((handler) => {
|
|
648
|
+
try {
|
|
649
|
+
if (typeof handler.appliesTo === 'function' && !handler.appliesTo(collecionesEvent)) {
|
|
650
|
+
return;
|
|
651
|
+
}
|
|
652
|
+
const data = handler.collect(collecionesEvent);
|
|
653
|
+
if (data === undefined || data === null) {
|
|
654
|
+
return; // handler declined to contribute for this event
|
|
655
|
+
}
|
|
656
|
+
collecionesEvent.setEnrichment(handler.name, handler.about, data);
|
|
657
|
+
} catch (error) {
|
|
658
|
+
// A failing handler must never drop the event; skip its enrichment.
|
|
659
|
+
}
|
|
660
|
+
});
|
|
626
661
|
}
|
|
627
662
|
|
|
628
663
|
/**
|
|
@@ -635,7 +670,8 @@ class CollecionesTracker {
|
|
|
635
670
|
throw new Error('Event must be of type CollecionesEvent');
|
|
636
671
|
}
|
|
637
672
|
collecionesEvent.setTracker(this.trackerName);
|
|
638
|
-
collecionesEvent.setAppName(this.appName);
|
|
673
|
+
collecionesEvent.setAppName(this.appName);
|
|
674
|
+
this.runHandlers(collecionesEvent);
|
|
639
675
|
this.emitters.forEach(element => {
|
|
640
676
|
element.track(collecionesEvent, this.trackerName, this.appName);
|
|
641
677
|
});
|
|
@@ -657,31 +693,236 @@ class CollecionesTracker {
|
|
|
657
693
|
}
|
|
658
694
|
|
|
659
695
|
/**
|
|
660
|
-
*
|
|
661
|
-
*
|
|
696
|
+
* Default browser-context enrichment handler. Contributes the page/browser
|
|
697
|
+
* environment under `meta.enrichments.browserContext`.
|
|
698
|
+
*
|
|
699
|
+
* This is transport/environment metadata — deliberately NOT part of the
|
|
700
|
+
* domain-validated `context`. A model-aware consumer (the server) routes each field
|
|
701
|
+
* onto the matching attribute of one of the declared subjects. Returns an empty
|
|
702
|
+
* payload outside a browser.
|
|
703
|
+
*/
|
|
704
|
+
const browserContextHandler = {
|
|
705
|
+
name: 'browserContext',
|
|
706
|
+
about: ['session', 'webpage'],
|
|
707
|
+
collect() {
|
|
708
|
+
if (typeof window === 'undefined' || typeof navigator === 'undefined') {
|
|
709
|
+
return {};
|
|
710
|
+
}
|
|
711
|
+
return {
|
|
712
|
+
hasFocus: document.hasFocus(),
|
|
713
|
+
language: navigator.language,
|
|
714
|
+
platform: navigator.platform,
|
|
715
|
+
referrer: document.referrer,
|
|
716
|
+
screenHeight: window.screen.height,
|
|
717
|
+
screenWidth: window.screen.width,
|
|
718
|
+
timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
|
|
719
|
+
url: window.location.href,
|
|
720
|
+
userAgent: navigator.userAgent,
|
|
721
|
+
viewportHeight: window.innerHeight,
|
|
722
|
+
viewportWidth: window.innerWidth,
|
|
723
|
+
};
|
|
724
|
+
},
|
|
725
|
+
};
|
|
726
|
+
|
|
727
|
+
/**
|
|
728
|
+
* Marketing / attribution handler. Parses the page URL's query string for the
|
|
729
|
+
* standard UTM parameters and the common ad-network click identifiers, so the
|
|
730
|
+
* model-aware consumer (the server) can attribute the session/visitor.
|
|
731
|
+
*
|
|
732
|
+
* Declares `about: ['session', 'visitor']` — attribution describes entity state,
|
|
733
|
+
* not event payload. Returns `null` when the URL carries no marketing parameters,
|
|
734
|
+
* so the handler adds nothing on the (many) events that have none.
|
|
735
|
+
*
|
|
736
|
+
* Field names are the conventional analytics names the domain model also uses
|
|
737
|
+
* (`utmSource`, `marketingNetwork`, ...) — not domain-model coupling, just the
|
|
738
|
+
* shared vocabulary of web attribution.
|
|
739
|
+
*/
|
|
740
|
+
|
|
741
|
+
// UTM query parameter -> conventional camelCase field name.
|
|
742
|
+
const UTM_FIELDS = [
|
|
743
|
+
['utm_source', 'utmSource'],
|
|
744
|
+
['utm_medium', 'utmMedium'],
|
|
745
|
+
['utm_campaign', 'utmCampaign'],
|
|
746
|
+
['utm_term', 'utmTerm'],
|
|
747
|
+
['utm_content', 'utmContent'],
|
|
748
|
+
];
|
|
749
|
+
|
|
750
|
+
// Known ad-network click identifiers, in resolution priority, mapped to their network.
|
|
751
|
+
const CLICK_ID_NETWORKS = [
|
|
752
|
+
['gclid', 'google'],
|
|
753
|
+
['wbraid', 'google'],
|
|
754
|
+
['gbraid', 'google'],
|
|
755
|
+
['dclid', 'google'],
|
|
756
|
+
['msclkid', 'microsoft'],
|
|
757
|
+
['fbclid', 'meta'],
|
|
758
|
+
['igshid', 'meta'],
|
|
759
|
+
['ttclid', 'tiktok'],
|
|
760
|
+
['li_fat_id', 'linkedin'],
|
|
761
|
+
['twclid', 'twitter'],
|
|
762
|
+
['yclid', 'yandex'],
|
|
763
|
+
['epik', 'pinterest'],
|
|
764
|
+
['scid', 'snapchat'],
|
|
765
|
+
];
|
|
766
|
+
|
|
767
|
+
const marketingHandler = {
|
|
768
|
+
name: 'marketing',
|
|
769
|
+
about: ['session', 'webpage'],
|
|
770
|
+
collect() {
|
|
771
|
+
if (typeof window === 'undefined' || !window.location) {
|
|
772
|
+
return null;
|
|
773
|
+
}
|
|
774
|
+
const params = new URLSearchParams(window.location.search || '');
|
|
775
|
+
const data = {};
|
|
776
|
+
|
|
777
|
+
UTM_FIELDS.forEach(([param, field]) => {
|
|
778
|
+
const value = params.get(param);
|
|
779
|
+
if (value) {
|
|
780
|
+
data[field] = value;
|
|
781
|
+
}
|
|
782
|
+
});
|
|
783
|
+
|
|
784
|
+
for (const [param, network] of CLICK_ID_NETWORKS) {
|
|
785
|
+
const value = params.get(param);
|
|
786
|
+
if (value) {
|
|
787
|
+
data.marketingNetwork = network;
|
|
788
|
+
data.marketingNetworkClickId = value;
|
|
789
|
+
break;
|
|
790
|
+
}
|
|
791
|
+
}
|
|
792
|
+
|
|
793
|
+
return Object.keys(data).length > 0 ? data : null;
|
|
794
|
+
},
|
|
795
|
+
};
|
|
796
|
+
|
|
797
|
+
/**
|
|
798
|
+
* UA Client Hints handler. Surfaces the low-entropy values from
|
|
799
|
+
* `navigator.userAgentData` (Chromium) — `mobile`, `platform`, `brands` — a more
|
|
800
|
+
* reliable device/browser signal than parsing the user-agent string server-side.
|
|
801
|
+
*
|
|
802
|
+
* Declares `about: ['visitor', 'session']`. Returns `null` where UA-CH is
|
|
803
|
+
* unavailable (Firefox/Safari) — the server then falls back to the user-agent
|
|
804
|
+
* string carried by `browserContext`. Only the synchronous low-entropy values are
|
|
805
|
+
* read; the async `getHighEntropyValues()` is intentionally not awaited.
|
|
806
|
+
*/
|
|
807
|
+
const userAgentDataHandler = {
|
|
808
|
+
name: 'userAgentData',
|
|
809
|
+
about: ['session', 'webpage'],
|
|
810
|
+
collect() {
|
|
811
|
+
if (typeof navigator === 'undefined' || !navigator.userAgentData) {
|
|
812
|
+
return null;
|
|
813
|
+
}
|
|
814
|
+
const uaData = navigator.userAgentData;
|
|
815
|
+
const data = {
|
|
816
|
+
mobile: Boolean(uaData.mobile),
|
|
817
|
+
};
|
|
818
|
+
if (uaData.platform) {
|
|
819
|
+
data.platform = uaData.platform;
|
|
820
|
+
}
|
|
821
|
+
if (Array.isArray(uaData.brands) && uaData.brands.length > 0) {
|
|
822
|
+
data.brands = uaData.brands.map((b) => ({ brand: b.brand, version: b.version }));
|
|
823
|
+
}
|
|
824
|
+
return data;
|
|
825
|
+
},
|
|
826
|
+
};
|
|
827
|
+
|
|
828
|
+
/**
|
|
829
|
+
* Consent handler. Surfaces the synchronously-available consent signals: the IAB
|
|
830
|
+
* TCF consent string (from the `euconsent-v2` cookie), the detected CMP provider,
|
|
831
|
+
* and the Global Privacy Control signal. The model-aware consumer (the server)
|
|
832
|
+
* decodes the TCF string into granted categories.
|
|
833
|
+
*
|
|
834
|
+
* Declares `about: ['consent', 'session']`. Returns `null` when no consent signal
|
|
835
|
+
* is present. NOTE: only synchronous sources are read — the async `__tcfapi`
|
|
836
|
+
* in-memory state is intentionally not awaited; the persisted cookie is the
|
|
837
|
+
* source of truth.
|
|
838
|
+
*/
|
|
839
|
+
|
|
840
|
+
// Known CMP globals -> provider name.
|
|
841
|
+
const CMP_PROVIDERS = [
|
|
842
|
+
['Cookiebot', 'cookiebot'],
|
|
843
|
+
['OneTrust', 'onetrust'],
|
|
844
|
+
['Optanon', 'onetrust'],
|
|
845
|
+
['Didomi', 'didomi'],
|
|
846
|
+
['UC_UI', 'usercentrics'],
|
|
847
|
+
];
|
|
848
|
+
|
|
849
|
+
function readCookie(name) {
|
|
850
|
+
if (typeof document === 'undefined' || typeof document.cookie !== 'string') {
|
|
851
|
+
return undefined;
|
|
852
|
+
}
|
|
853
|
+
const match = document.cookie.match(new RegExp('(?:^|; )' + name + '=([^;]*)'));
|
|
854
|
+
return match ? decodeURIComponent(match[1]) : undefined;
|
|
855
|
+
}
|
|
856
|
+
|
|
857
|
+
function detectProvider() {
|
|
858
|
+
if (typeof window === 'undefined') {
|
|
859
|
+
return undefined;
|
|
860
|
+
}
|
|
861
|
+
for (const [global, name] of CMP_PROVIDERS) {
|
|
862
|
+
if (window[global]) {
|
|
863
|
+
return name;
|
|
864
|
+
}
|
|
865
|
+
}
|
|
866
|
+
if (typeof window.__tcfapi === 'function') {
|
|
867
|
+
return 'iab-tcf';
|
|
868
|
+
}
|
|
869
|
+
return undefined;
|
|
870
|
+
}
|
|
871
|
+
|
|
872
|
+
const consentHandler = {
|
|
873
|
+
name: 'consent',
|
|
874
|
+
about: ['consent', 'session', 'visitor'],
|
|
875
|
+
collect() {
|
|
876
|
+
if (typeof window === 'undefined') {
|
|
877
|
+
return null;
|
|
878
|
+
}
|
|
879
|
+
const data = {};
|
|
880
|
+
|
|
881
|
+
const tcfConsentString = readCookie('euconsent-v2');
|
|
882
|
+
if (tcfConsentString) {
|
|
883
|
+
data.tcfConsentString = tcfConsentString;
|
|
884
|
+
}
|
|
885
|
+
|
|
886
|
+
const provider = detectProvider();
|
|
887
|
+
if (provider) {
|
|
888
|
+
data.consentProvider = provider;
|
|
889
|
+
}
|
|
890
|
+
|
|
891
|
+
if (typeof navigator !== 'undefined' && typeof navigator.globalPrivacyControl === 'boolean') {
|
|
892
|
+
data.globalPrivacyControl = navigator.globalPrivacyControl;
|
|
893
|
+
}
|
|
894
|
+
|
|
895
|
+
return Object.keys(data).length > 0 ? data : null;
|
|
896
|
+
},
|
|
897
|
+
};
|
|
898
|
+
|
|
899
|
+
/**
|
|
900
|
+
* The default enrichment handlers registered on every web tracker. Each handler is
|
|
901
|
+
* model-agnostic: it self-identifies (`name`), declares what it is `about` (subject
|
|
902
|
+
* strings) and `collect`s its data; a model-aware consumer maps it onto entity state.
|
|
903
|
+
*/
|
|
904
|
+
const defaultWebHandlers = [
|
|
905
|
+
browserContextHandler,
|
|
906
|
+
marketingHandler,
|
|
907
|
+
userAgentDataHandler,
|
|
908
|
+
consentHandler,
|
|
909
|
+
];
|
|
910
|
+
|
|
911
|
+
/**
|
|
912
|
+
* Web-specific tracker: the base tracker plus the default web enrichment handlers
|
|
913
|
+
* (browser context, marketing/attribution, UA client hints, consent), so every web
|
|
914
|
+
* event carries the client environment and attribution signals in
|
|
915
|
+
* `meta.enrichments` — never in the domain-validated `context`.
|
|
662
916
|
*/
|
|
663
917
|
class CollecionesWebTracker extends CollecionesTracker {
|
|
664
918
|
/**
|
|
665
|
-
*
|
|
666
|
-
* @param {
|
|
667
|
-
* @param {string}
|
|
668
|
-
* @param {string} appName - The name of the application generating events.
|
|
919
|
+
* @param {Array} emitters - Emitter instances used to send events.
|
|
920
|
+
* @param {string} trackerName - The tracker name.
|
|
921
|
+
* @param {string} appName - The application generating events.
|
|
669
922
|
*/
|
|
670
923
|
constructor(emitters, trackerName, appName) {
|
|
671
924
|
super(emitters, trackerName, appName);
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
/**
|
|
675
|
-
* Tracks an event, enriching it with browser context information.
|
|
676
|
-
* @param {CollecionesEvent} collecionesEvent - The event object to track.
|
|
677
|
-
* @throws {Error} If the event is not an instance of CollecionesEvent.
|
|
678
|
-
*/
|
|
679
|
-
track(collecionesEvent) {
|
|
680
|
-
if (!(collecionesEvent instanceof CollecionesEvent)) {
|
|
681
|
-
throw new Error('Event must be of type CollecionesEvent');
|
|
682
|
-
}
|
|
683
|
-
collecionesEvent.setContext('browserContext', getBrowserContext());
|
|
684
|
-
super.track(collecionesEvent);
|
|
925
|
+
defaultWebHandlers.forEach((handler) => this.use(handler));
|
|
685
926
|
}
|
|
686
927
|
}
|
|
687
928
|
|