/* Copyright (C) 2025 Moko Consulting This file is part of a Moko Consulting project. SPDX-License-Identifier: GPL-3.0-or-later */ /* global window, document, navigator */ (() => { "use strict"; /** * @typedef {Object} MokoGtmOptions * @property {string} [id] GTM container ID (e.g., "GTM-XXXXXXX") * @property {string} [dataLayerName] Custom dataLayer name (default: "dataLayer") * @property {boolean} [debug] Log debug messages to console (default: false) * @property {boolean} [ignoreDNT] Ignore Do Not Track and always load (default: false) * @property {boolean} [blockOnDev] Block loading on localhost/*.test/127.0.0.1 (default: true) * @property {string} [envAuth] GTM Environment auth string (optional) * @property {string} [envPreview] GTM Environment preview name (optional) * @property {Record} [consentDefault] * Default Consent Mode v2 map. Keys like: * analytics_storage, ad_storage, ad_user_data, ad_personalization, functionality_storage, security_storage * (default: {analytics_storage:'granted', functionality_storage:'granted', security_storage:'granted'}) * @property {() => (Record|void)} [pageVars] * Function returning extra page variables to push on init (optional) */ const PKG = "moko-gtm"; const PREFIX = `[${PKG}]`; const WIN = window; // Public API placeholder (attached to window at the end) /** @type {{ * init: (opts?: Partial) => void, * setConsent: (updates: Record) => void, * push: (...args:any[]) => void, * isLoaded: () => boolean, * config: () => Required * }} */ const API = {}; // ---- Utilities --------------------------------------------------------- const isDevHost = () => { const h = WIN.location && WIN.location.hostname || ""; return ( h === "localhost" || h === "127.0.0.1" || h.endsWith(".local") || h.endsWith(".test") ); }; const dntEnabled = () => { // Different browsers expose DNT differently; treat "1" or "yes" as enabled. const n = navigator; const v = (n.doNotTrack || n.msDoNotTrack || (n.navigator && n.navigator.doNotTrack) || "").toString().toLowerCase(); return v === "1" || v === "yes"; }; const getCurrentScript = () => { // document.currentScript is best; fallback to last