@dreamdata_io/verify-tracking 0.1.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/LICENSE +21 -0
- package/README.md +756 -0
- package/dist/ai/checker.js +222 -0
- package/dist/ai/checker.js.map +1 -0
- package/dist/ai/checklist.js +190 -0
- package/dist/ai/checklist.js.map +1 -0
- package/dist/ai/cli-presets.js +27 -0
- package/dist/ai/cli-presets.js.map +1 -0
- package/dist/ai/evidence-view.js +143 -0
- package/dist/ai/evidence-view.js.map +1 -0
- package/dist/ai/local-cli.js +58 -0
- package/dist/ai/local-cli.js.map +1 -0
- package/dist/ai/openai-compatible.js +78 -0
- package/dist/ai/openai-compatible.js.map +1 -0
- package/dist/ai/response-parser.js +105 -0
- package/dist/ai/response-parser.js.map +1 -0
- package/dist/ai/types.js +2 -0
- package/dist/ai/types.js.map +1 -0
- package/dist/analysis/consent-mode.js +225 -0
- package/dist/analysis/consent-mode.js.map +1 -0
- package/dist/analysis/deployment.js +2658 -0
- package/dist/analysis/deployment.js.map +1 -0
- package/dist/analysis/diagnosis/copy.en.js +303 -0
- package/dist/analysis/diagnosis/copy.en.js.map +1 -0
- package/dist/analysis/diagnosis/diagnose.js +172 -0
- package/dist/analysis/diagnosis/diagnose.js.map +1 -0
- package/dist/analysis/diagnosis/docs.js +118 -0
- package/dist/analysis/diagnosis/docs.js.map +1 -0
- package/dist/analysis/diagnosis/index.js +5 -0
- package/dist/analysis/diagnosis/index.js.map +1 -0
- package/dist/analysis/diagnosis/rules.js +656 -0
- package/dist/analysis/diagnosis/rules.js.map +1 -0
- package/dist/analysis/diagnosis/types.js +2 -0
- package/dist/analysis/diagnosis/types.js.map +1 -0
- package/dist/cli.js +344 -0
- package/dist/cli.js.map +1 -0
- package/dist/config/env.js +100 -0
- package/dist/config/env.js.map +1 -0
- package/dist/config/preflight.js +167 -0
- package/dist/config/preflight.js.map +1 -0
- package/dist/config/user-config.js +79 -0
- package/dist/config/user-config.js.map +1 -0
- package/dist/evidence/collect.js +527 -0
- package/dist/evidence/collect.js.map +1 -0
- package/dist/evidence/consent-accept.js +377 -0
- package/dist/evidence/consent-accept.js.map +1 -0
- package/dist/evidence/consent.js +340 -0
- package/dist/evidence/consent.js.map +1 -0
- package/dist/evidence/constants.js +615 -0
- package/dist/evidence/constants.js.map +1 -0
- package/dist/evidence/globals.js +132 -0
- package/dist/evidence/globals.js.map +1 -0
- package/dist/evidence/gtm-container.js +432 -0
- package/dist/evidence/gtm-container.js.map +1 -0
- package/dist/evidence/heuristic-banner.js +107 -0
- package/dist/evidence/heuristic-banner.js.map +1 -0
- package/dist/evidence/http-probe.js +139 -0
- package/dist/evidence/http-probe.js.map +1 -0
- package/dist/evidence/init-script.js +112 -0
- package/dist/evidence/init-script.js.map +1 -0
- package/dist/evidence/network.js +365 -0
- package/dist/evidence/network.js.map +1 -0
- package/dist/evidence/preference-center.js +368 -0
- package/dist/evidence/preference-center.js.map +1 -0
- package/dist/evidence/script.js +425 -0
- package/dist/evidence/script.js.map +1 -0
- package/dist/evidence/second-page.js +332 -0
- package/dist/evidence/second-page.js.map +1 -0
- package/dist/evidence/selector-probe.js +53 -0
- package/dist/evidence/selector-probe.js.map +1 -0
- package/dist/evidence/stealth.js +21 -0
- package/dist/evidence/stealth.js.map +1 -0
- package/dist/evidence/types.js +14 -0
- package/dist/evidence/types.js.map +1 -0
- package/dist/interactive/prompt.js +31 -0
- package/dist/interactive/prompt.js.map +1 -0
- package/dist/mcp/server.js +308 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/mcp/summary.js +41 -0
- package/dist/mcp/summary.js.map +1 -0
- package/dist/report/context.js +184 -0
- package/dist/report/context.js.map +1 -0
- package/dist/report/projection.js +125 -0
- package/dist/report/projection.js.map +1 -0
- package/dist/report/quote-check.js +90 -0
- package/dist/report/quote-check.js.map +1 -0
- package/dist/report/render.js +178 -0
- package/dist/report/render.js.map +1 -0
- package/dist/report/serializers.js +124 -0
- package/dist/report/serializers.js.map +1 -0
- package/dist/report/store.js +139 -0
- package/dist/report/store.js.map +1 -0
- package/dist/run/verify.js +77 -0
- package/dist/run/verify.js.map +1 -0
- package/dist/utils/duration.js +10 -0
- package/dist/utils/duration.js.map +1 -0
- package/dist/utils/errors.js +17 -0
- package/dist/utils/errors.js.map +1 -0
- package/dist/utils/logger.js +59 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/runTimingsLog.js +27 -0
- package/dist/utils/runTimingsLog.js.map +1 -0
- package/dist/utils/slug.js +27 -0
- package/dist/utils/slug.js.map +1 -0
- package/dist/version.js +10 -0
- package/dist/version.js.map +1 -0
- package/package.json +57 -0
- package/scripts/install.sh +314 -0
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import { AJS_COOKIE_NAMES, AJS_COOKIE_PREFIX, COOKIELESS_GLOBAL_KEY, DD_COOKIE_NAMES, DREAMDATA_METHODS, mentionsDreamdata, SEGMENT_COMPAT_GLOBAL_KEY, } from "./constants.js";
|
|
2
|
+
export function attachConsoleCollector(page) {
|
|
3
|
+
const errors = [];
|
|
4
|
+
const warnings = [];
|
|
5
|
+
page.on("console", (msg) => {
|
|
6
|
+
const text = msg.text();
|
|
7
|
+
if (!mentionsDreamdata(text))
|
|
8
|
+
return;
|
|
9
|
+
if (msg.type() === "error")
|
|
10
|
+
errors.push(text);
|
|
11
|
+
else if (msg.type() === "warning")
|
|
12
|
+
warnings.push(text);
|
|
13
|
+
});
|
|
14
|
+
page.on("pageerror", (err) => {
|
|
15
|
+
if (mentionsDreamdata(err.message))
|
|
16
|
+
errors.push(err.message);
|
|
17
|
+
});
|
|
18
|
+
return { errors, warnings };
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Probes one window key. `isStubQueue` is the important one: a loader snippet
|
|
22
|
+
* creates its global as an *array* that queues calls until the real bundle
|
|
23
|
+
* replaces it, so an array here means the bundle never arrived — which is
|
|
24
|
+
* expected when it is consent-gated, and a defect when it is not.
|
|
25
|
+
*/
|
|
26
|
+
async function probeGlobals(page, keys, methodNames) {
|
|
27
|
+
return page
|
|
28
|
+
.evaluate(({ keys, methodNames }) => {
|
|
29
|
+
const w = window;
|
|
30
|
+
const out = {};
|
|
31
|
+
for (const key of keys) {
|
|
32
|
+
const value = w[key];
|
|
33
|
+
const exists = value !== undefined && value !== null;
|
|
34
|
+
out[key] = {
|
|
35
|
+
exists,
|
|
36
|
+
initialized: exists ? Boolean(value?.initialized) : false,
|
|
37
|
+
isStubQueue: Array.isArray(value),
|
|
38
|
+
methods: exists ? methodNames.filter((name) => typeof value?.[name] === "function") : [],
|
|
39
|
+
hasReady: typeof value?.["ready"] === "function",
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
return out;
|
|
43
|
+
}, { keys: [...keys], methodNames: [...methodNames] })
|
|
44
|
+
.catch(() => ({}));
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Waits for ready() on the first global that exposes it. Segment-compatible
|
|
48
|
+
* installs only ever have it on window.analytics, so anchoring solely on
|
|
49
|
+
* window.dreamdata would report a healthy install as broken.
|
|
50
|
+
*/
|
|
51
|
+
async function awaitReadyCallback(page, candidateKeys, timeoutMs) {
|
|
52
|
+
for (const key of candidateKeys) {
|
|
53
|
+
const fired = await page
|
|
54
|
+
.evaluate(({ key, timeoutMs }) => new Promise((resolve) => {
|
|
55
|
+
const target = window[key];
|
|
56
|
+
if (typeof target?.ready !== "function") {
|
|
57
|
+
resolve(false);
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
const timer = setTimeout(() => resolve(false), timeoutMs);
|
|
61
|
+
target.ready(() => {
|
|
62
|
+
clearTimeout(timer);
|
|
63
|
+
resolve(true);
|
|
64
|
+
});
|
|
65
|
+
}), { key, timeoutMs })
|
|
66
|
+
.catch(() => false);
|
|
67
|
+
if (fired)
|
|
68
|
+
return { readyCallbackFired: true, readyCallbackGlobal: key };
|
|
69
|
+
}
|
|
70
|
+
return { readyCallbackFired: false, readyCallbackGlobal: null };
|
|
71
|
+
}
|
|
72
|
+
export async function readDreamdataGlobals(page, readyTimeoutMs) {
|
|
73
|
+
const probes = await probeGlobals(page, ["dreamdata", COOKIELESS_GLOBAL_KEY, SEGMENT_COMPAT_GLOBAL_KEY], DREAMDATA_METHODS);
|
|
74
|
+
const empty = { exists: false, initialized: false, isStubQueue: false, methods: [], hasReady: false };
|
|
75
|
+
const dd = probes["dreamdata"] ?? empty;
|
|
76
|
+
const cl = probes[COOKIELESS_GLOBAL_KEY] ?? empty;
|
|
77
|
+
const seg = probes[SEGMENT_COMPAT_GLOBAL_KEY] ?? empty;
|
|
78
|
+
// Prefer whichever global actually exposes ready(); dreamdata first so a
|
|
79
|
+
// dual install still reports the primary one.
|
|
80
|
+
const readyCandidates = ["dreamdata", COOKIELESS_GLOBAL_KEY, SEGMENT_COMPAT_GLOBAL_KEY].filter((key) => (probes[key] ?? empty).hasReady);
|
|
81
|
+
const ready = await awaitReadyCallback(page, readyCandidates, readyTimeoutMs);
|
|
82
|
+
const gtagUserDataSeen = await page
|
|
83
|
+
.evaluate(() => {
|
|
84
|
+
const w = window;
|
|
85
|
+
const calls = w.__ddEvidence?.gtagCalls ?? [];
|
|
86
|
+
return calls.some((call) => call.args[0] === "set" && call.args[1] === "user_data");
|
|
87
|
+
})
|
|
88
|
+
.catch(() => false);
|
|
89
|
+
return {
|
|
90
|
+
dreamdataExists: dd.exists,
|
|
91
|
+
initialized: dd.initialized,
|
|
92
|
+
supportedMethods: dd.methods.length > 0 ? dd.methods : seg.methods,
|
|
93
|
+
dreamdataIsStubQueue: dd.isStubQueue,
|
|
94
|
+
cookielessGlobalExists: cl.exists,
|
|
95
|
+
cookielessInitialized: cl.initialized,
|
|
96
|
+
segmentCompatGlobalExists: seg.exists,
|
|
97
|
+
segmentCompatInitialized: seg.initialized,
|
|
98
|
+
segmentCompatIsStubQueue: seg.isStubQueue,
|
|
99
|
+
gtagUserDataSeen,
|
|
100
|
+
...ready,
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
async function readLocalStorage(page, names) {
|
|
104
|
+
return page
|
|
105
|
+
.evaluate((keys) => {
|
|
106
|
+
const out = {};
|
|
107
|
+
for (const key of keys) {
|
|
108
|
+
try {
|
|
109
|
+
out[key] = window.localStorage.getItem(key);
|
|
110
|
+
}
|
|
111
|
+
catch {
|
|
112
|
+
out[key] = null;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
return out;
|
|
116
|
+
}, [...names])
|
|
117
|
+
.catch(() => Object.fromEntries(names.map((n) => [n, null])));
|
|
118
|
+
}
|
|
119
|
+
export async function readCookiesAndStorage(page) {
|
|
120
|
+
const cookies = await page.context().cookies();
|
|
121
|
+
const pick = (names) => Object.fromEntries(names.map((name) => [name, cookies.find((c) => c.name === name)?.value ?? null]));
|
|
122
|
+
const values = pick(DD_COOKIE_NAMES);
|
|
123
|
+
const ajsValues = pick(AJS_COOKIE_NAMES);
|
|
124
|
+
const anyAjsCookie = cookies.some((c) => c.name.startsWith(AJS_COOKIE_PREFIX));
|
|
125
|
+
const usesAjsCompatPrefix = anyAjsCookie && Object.values(values).every((v) => v === null);
|
|
126
|
+
const [localStorageValues, ajsLocalStorageValues] = await Promise.all([
|
|
127
|
+
readLocalStorage(page, DD_COOKIE_NAMES),
|
|
128
|
+
readLocalStorage(page, AJS_COOKIE_NAMES),
|
|
129
|
+
]);
|
|
130
|
+
return { values, localStorageValues, ajsValues, ajsLocalStorageValues, usesAjsCompatPrefix };
|
|
131
|
+
}
|
|
132
|
+
//# sourceMappingURL=globals.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"globals.js","sourceRoot":"","sources":["../../src/evidence/globals.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,432 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reading a published GTM container's own gating rules.
|
|
3
|
+
*
|
|
4
|
+
* A container served from googletagmanager.com is a public static file whose
|
|
5
|
+
* `data.resource` holds the whole published version: every tag, every trigger
|
|
6
|
+
* compiled down to `predicates` + `rules`, and every variable. Nothing here
|
|
7
|
+
* needs the customer's GTM account — the container id is in their page.
|
|
8
|
+
*
|
|
9
|
+
* This exists because a tag's `consent` list is only half of its gate. A tag
|
|
10
|
+
* can also carry a BLOCKING trigger (an "exception" in the GTM UI), which
|
|
11
|
+
* stops it firing no matter what Consent Mode says. Reporting only the
|
|
12
|
+
* consent list describes abcam's Dreamdata tag as "gated on analytics_storage"
|
|
13
|
+
* when analytics_storage is granted before the banner is answered and the
|
|
14
|
+
* thing actually holding the tag back is an exception on a OneTrust group.
|
|
15
|
+
* The two are worth telling apart: one of them is the Consent Mode layer
|
|
16
|
+
* working, the other is a second mechanism compensating for it not working.
|
|
17
|
+
*/
|
|
18
|
+
/**
|
|
19
|
+
* Lifts `data.resource` out of a gtm.js body.
|
|
20
|
+
*
|
|
21
|
+
* The file is minified JS with the container embedded as an object literal,
|
|
22
|
+
* so the JSON has to be found by brace-matching from the `{` that opens the
|
|
23
|
+
* object containing "resource" — string contents are skipped so a `}` inside
|
|
24
|
+
* a tag's HTML cannot end the scan early.
|
|
25
|
+
*/
|
|
26
|
+
export function parseGtmResource(body) {
|
|
27
|
+
const marker = body.indexOf('"resource"');
|
|
28
|
+
if (marker === -1)
|
|
29
|
+
return null;
|
|
30
|
+
const start = body.lastIndexOf("{", marker);
|
|
31
|
+
if (start === -1)
|
|
32
|
+
return null;
|
|
33
|
+
let depth = 0;
|
|
34
|
+
let inString = false;
|
|
35
|
+
let escaped = false;
|
|
36
|
+
for (let i = start; i < body.length; i++) {
|
|
37
|
+
const ch = body[i];
|
|
38
|
+
if (inString) {
|
|
39
|
+
if (escaped)
|
|
40
|
+
escaped = false;
|
|
41
|
+
else if (ch === "\\")
|
|
42
|
+
escaped = true;
|
|
43
|
+
else if (ch === '"')
|
|
44
|
+
inString = false;
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
if (ch === '"')
|
|
48
|
+
inString = true;
|
|
49
|
+
else if (ch === "{")
|
|
50
|
+
depth++;
|
|
51
|
+
else if (ch === "}") {
|
|
52
|
+
depth--;
|
|
53
|
+
if (depth === 0) {
|
|
54
|
+
try {
|
|
55
|
+
return JSON.parse(body.slice(start, i + 1)).resource ?? null;
|
|
56
|
+
}
|
|
57
|
+
catch {
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* GTM serialises every built-in URL variable as the same `__u` function, with
|
|
67
|
+
* `vtp_component` naming the part it reads. Absent means the whole URL.
|
|
68
|
+
*/
|
|
69
|
+
const URL_COMPONENT_NAMES = {
|
|
70
|
+
URL: "Page URL",
|
|
71
|
+
undefined: "Page URL",
|
|
72
|
+
HOST: "Page Hostname",
|
|
73
|
+
PATH: "Page Path",
|
|
74
|
+
QUERY: "Query String",
|
|
75
|
+
FRAGMENT: "Page Fragment",
|
|
76
|
+
PROTOCOL: "Page Protocol",
|
|
77
|
+
PORT: "Page Port",
|
|
78
|
+
IS_OUTBOUND: "the outbound-link flag",
|
|
79
|
+
};
|
|
80
|
+
/** The readable name of whatever a predicate is testing. */
|
|
81
|
+
function describeOperand(operand, macros) {
|
|
82
|
+
if (Array.isArray(operand) && operand[0] === "macro" && typeof operand[1] === "number") {
|
|
83
|
+
const macro = macros[operand[1]];
|
|
84
|
+
if (macro?.vtp_name)
|
|
85
|
+
return macro.vtp_name;
|
|
86
|
+
// GTM strips the names of built-ins and Custom JS variables from the
|
|
87
|
+
// published container, so the function id is all there is to report.
|
|
88
|
+
if (macro?.function === "__e")
|
|
89
|
+
return "event";
|
|
90
|
+
if (macro?.function === "__jsm")
|
|
91
|
+
return "a custom JavaScript variable";
|
|
92
|
+
// GTM's built-in URL variable is one function with a component selector,
|
|
93
|
+
// so without it a gate on the hostname and a gate on the query string
|
|
94
|
+
// both read as "__u" — the same name for two different conditions.
|
|
95
|
+
if (macro?.function === "__u")
|
|
96
|
+
return URL_COMPONENT_NAMES[String(macro.vtp_component)] ?? "Page URL";
|
|
97
|
+
if (macro?.function === "__ref")
|
|
98
|
+
return URL_COMPONENT_NAMES[String(macro.vtp_component)]?.replace("Page", "Referrer") ?? "Referrer";
|
|
99
|
+
return macro?.function ?? "an unnamed variable";
|
|
100
|
+
}
|
|
101
|
+
return typeof operand === "string" ? operand : JSON.stringify(operand);
|
|
102
|
+
}
|
|
103
|
+
/** Affirmative and negative phrasing for each predicate GTM compiles to. */
|
|
104
|
+
const PREDICATE_VERBS = {
|
|
105
|
+
_eq: ["is", "is not"],
|
|
106
|
+
_sw: ["starts with", "does not start with"],
|
|
107
|
+
_ew: ["ends with", "does not end with"],
|
|
108
|
+
_cn: ["contains", "does not contain"],
|
|
109
|
+
_css: ["matches the CSS selector", "does not match the CSS selector"],
|
|
110
|
+
_re: ["matches", "does not match"],
|
|
111
|
+
_lt: ["is less than", "is not less than"],
|
|
112
|
+
_le: ["is at most", "is more than"],
|
|
113
|
+
_gt: ["is greater than", "is not greater than"],
|
|
114
|
+
_ge: ["is at least", "is less than"],
|
|
115
|
+
};
|
|
116
|
+
function describePredicate(predicate, negated, macros) {
|
|
117
|
+
const subject = describeOperand(predicate.arg0, macros);
|
|
118
|
+
const fallback = predicate.function ?? "matches";
|
|
119
|
+
const [affirmative, negative] = PREDICATE_VERBS[predicate.function ?? ""] ?? [fallback, `does not satisfy ${fallback}`];
|
|
120
|
+
const object = typeof predicate.arg1 === "string" ? predicate.arg1 : JSON.stringify(predicate.arg1);
|
|
121
|
+
return `${subject} ${negated ? negative : affirmative} ${object}`;
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* True for a clause that names WHEN a rule gets re-evaluated rather than a
|
|
125
|
+
* state a visitor has to be in: any test against GTM's built-in `event`
|
|
126
|
+
* variable ("on gtm.js", "on gtm.dom", "on OneTrustGroupsUpdated", the
|
|
127
|
+
* catch-all "on every event"), or against `gtm.triggers` (a reference to
|
|
128
|
+
* another Trigger Group's own compiled id, e.g. "(^$|((^|,)8002876_348($|,)))"
|
|
129
|
+
* — internal compiler wiring, not a condition, and not one this function
|
|
130
|
+
* resolves recursively: see resolveTriggerGroupGates). Reporting either kind
|
|
131
|
+
* adds nothing and buries the clause that actually decides the outcome.
|
|
132
|
+
*/
|
|
133
|
+
function isTrivialEventClause(predicate, macros) {
|
|
134
|
+
const subject = describeOperand(predicate.arg0, macros);
|
|
135
|
+
return subject === "event" || subject === "gtm.triggers";
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* The non-trivial clauses of one rule, phrased as conditions that BLOCK the
|
|
139
|
+
* tag.
|
|
140
|
+
*
|
|
141
|
+
* `sense` is what the rule does with the tag, and it decides the polarity. A
|
|
142
|
+
* `block` rule's clauses already describe when blocking happens, so an "if"
|
|
143
|
+
* clause blocks when it IS met. An `add` rule's clauses describe what makes
|
|
144
|
+
* the tag fire, so the mapping inverts: an "if" clause blocks when it is NOT
|
|
145
|
+
* met, and an "unless" clause blocks when it IS.
|
|
146
|
+
*/
|
|
147
|
+
function describeRuleAsBlocking(rule, sense, predicates, macros) {
|
|
148
|
+
const blockingClause = sense === "block" ? "unless" : "if";
|
|
149
|
+
const conditions = [];
|
|
150
|
+
for (const clause of rule) {
|
|
151
|
+
if (clause[0] !== "if" && clause[0] !== "unless")
|
|
152
|
+
continue;
|
|
153
|
+
for (const index of clause.slice(1)) {
|
|
154
|
+
const predicate = typeof index === "number" ? predicates[index] : undefined;
|
|
155
|
+
if (!predicate || isTrivialEventClause(predicate, macros))
|
|
156
|
+
continue;
|
|
157
|
+
conditions.push(describePredicate(predicate, clause[0] === blockingClause, macros));
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
return conditions;
|
|
161
|
+
}
|
|
162
|
+
/** Every rule that can fire `tagIndex` directly. GTM ORs them together. */
|
|
163
|
+
function firingRulesFor(rules, tagIndex) {
|
|
164
|
+
return rules.filter((rule) => rule.some((clause) => clause[0] === "add" && clause.slice(1).includes(tagIndex)));
|
|
165
|
+
}
|
|
166
|
+
/** Matches the group id GTM embeds in a Trigger Group's own regex, e.g. "8002876_348" out of "(^$|((^|,)8002876_348($|,)))". */
|
|
167
|
+
const TRIGGER_GROUP_ID_IN_REGEX = /\(\^\|,\)([\w-]+)\(\$\|,\)/g;
|
|
168
|
+
/**
|
|
169
|
+
* The conditions a tag inherits from firing through a GTM Trigger Group
|
|
170
|
+
* instead of a direct rule on the tag itself, phrased as blocking conditions
|
|
171
|
+
* the same way readTagGating's direct `block` clauses are.
|
|
172
|
+
*
|
|
173
|
+
* A Trigger Group is GTM's AND of several sub-triggers — the compound
|
|
174
|
+
* `gtm.triggerGroup` event only fires once every one of them has. Each
|
|
175
|
+
* sub-trigger is compiled as its own "listening" tag (function `__tg`,
|
|
176
|
+
* `vtp_isListeningTag: true`), added by an ordinary rule whose conditions
|
|
177
|
+
* are exactly what has to hold for that one position. Those conditions are a
|
|
178
|
+
* REQUIREMENT for firing, the mirror image of a `block` exception: a
|
|
179
|
+
* required ("if") clause blocks the tag when it is NOT met, and a forbidden
|
|
180
|
+
* ("unless") clause blocks it when it IS met — the opposite of the mapping
|
|
181
|
+
* used for a direct exception, because this clause set describes what makes
|
|
182
|
+
* the tag fire, not what stops it.
|
|
183
|
+
*
|
|
184
|
+
* abcam expresses its OneTrust gate as an "unless" exception directly on the
|
|
185
|
+
* Dreamdata tag's own rule; idtdna expresses the identical gate — the
|
|
186
|
+
* visitor's OnetrustActiveGroups must contain C0002 — as a required
|
|
187
|
+
* sub-trigger inside a Trigger Group ANDed with the tag's normal "on page
|
|
188
|
+
* load" trigger. Reading only direct block clauses misses the second form
|
|
189
|
+
* entirely, which is why idtdna's blockedWhen came back empty even though a
|
|
190
|
+
* behaviourally equivalent gate exists and the run showed it holding.
|
|
191
|
+
*
|
|
192
|
+
* A sub-trigger position contributes nothing unless EVERY rule capable of
|
|
193
|
+
* satisfying it carries a real (non-trivial) condition: if a visitor can
|
|
194
|
+
* reach that position through even one unconditional path, the position
|
|
195
|
+
* imposes no actual restriction and reporting one would overclaim a gate
|
|
196
|
+
* that is not really there.
|
|
197
|
+
*
|
|
198
|
+
* The same overclaiming risk exists one level up, across the tag's OWN
|
|
199
|
+
* `add` rules — GTM ORs them together, so the tag fires if ANY one matches.
|
|
200
|
+
* abcam's Dreamdata tag has three: "Virtual Page View", "gtm.dom", and a
|
|
201
|
+
* Trigger Group requiring the URL not be /auth/login. That URL exclusion
|
|
202
|
+
* only governs the third path — the tag fires perfectly well through either
|
|
203
|
+
* of the other two regardless of the URL — so treating it as a gate on the
|
|
204
|
+
* tag as a whole would be wrong, not merely unhelpful. Trigger-group
|
|
205
|
+
* conditions are trustworthy as a GLOBAL gate only when the group is the
|
|
206
|
+
* tag's ONLY way to fire, i.e. it has exactly one `add` rule.
|
|
207
|
+
*/
|
|
208
|
+
function resolveTriggerGroupGates(resource, tagIndex) {
|
|
209
|
+
const tags = resource.tags ?? [];
|
|
210
|
+
const rules = resource.rules ?? [];
|
|
211
|
+
const predicates = resource.predicates ?? [];
|
|
212
|
+
const macros = resource.macros ?? [];
|
|
213
|
+
const addRules = firingRulesFor(rules, tagIndex);
|
|
214
|
+
if (addRules.length !== 1)
|
|
215
|
+
return [];
|
|
216
|
+
const groupIds = new Set();
|
|
217
|
+
for (const rule of addRules) {
|
|
218
|
+
for (const clause of rule) {
|
|
219
|
+
if (clause[0] !== "if" && clause[0] !== "unless")
|
|
220
|
+
continue;
|
|
221
|
+
for (const index of clause.slice(1)) {
|
|
222
|
+
const predicate = typeof index === "number" ? predicates[index] : undefined;
|
|
223
|
+
if (!predicate || predicate.function !== "_re" || typeof predicate.arg1 !== "string")
|
|
224
|
+
continue;
|
|
225
|
+
if (describeOperand(predicate.arg0, macros) !== "gtm.triggers")
|
|
226
|
+
continue;
|
|
227
|
+
for (const m of predicate.arg1.matchAll(TRIGGER_GROUP_ID_IN_REGEX))
|
|
228
|
+
groupIds.add(m[1]);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
if (groupIds.size === 0)
|
|
233
|
+
return [];
|
|
234
|
+
const results = [];
|
|
235
|
+
for (const groupId of groupIds) {
|
|
236
|
+
const orchestrator = tags.find((t) => t.function === "__tg" && t.vtp_uniqueTriggerId === groupId);
|
|
237
|
+
const rawTriggerIds = orchestrator?.vtp_triggerIds;
|
|
238
|
+
const firingIds = Array.isArray(rawTriggerIds)
|
|
239
|
+
? rawTriggerIds.filter((v) => typeof v === "string")
|
|
240
|
+
: [];
|
|
241
|
+
for (const firingId of firingIds) {
|
|
242
|
+
const listenerIndex = tags.findIndex((t) => t.function === "__tg" && t.vtp_isListeningTag === true && t.vtp_firingId === firingId);
|
|
243
|
+
if (listenerIndex === -1)
|
|
244
|
+
continue;
|
|
245
|
+
const branches = rules.filter((rule) => rule.some((clause) => clause[0] === "add" && clause.slice(1).includes(listenerIndex)));
|
|
246
|
+
if (branches.length === 0)
|
|
247
|
+
continue;
|
|
248
|
+
let sawRequirement = false;
|
|
249
|
+
let everyBranchGated = true;
|
|
250
|
+
const branchConditions = [];
|
|
251
|
+
for (const rule of branches) {
|
|
252
|
+
const conditions = describeRuleAsBlocking(rule, "add", predicates, macros);
|
|
253
|
+
if (conditions.length > 0)
|
|
254
|
+
sawRequirement = true;
|
|
255
|
+
branchConditions.push(conditions);
|
|
256
|
+
if (conditions.length === 0)
|
|
257
|
+
everyBranchGated = false;
|
|
258
|
+
}
|
|
259
|
+
if (sawRequirement && everyBranchGated) {
|
|
260
|
+
results.push(branchConditions.map((c) => c.join(" and ")).join(", or "));
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
return [...new Set(results)];
|
|
265
|
+
}
|
|
266
|
+
/**
|
|
267
|
+
* The custom dataLayer events the tag cannot fire without.
|
|
268
|
+
*
|
|
269
|
+
* `isTrivialEventClause` drops every clause testing GTM's built-in `event`
|
|
270
|
+
* variable, on the grounds that it names WHEN a rule is re-evaluated rather
|
|
271
|
+
* than a state the visitor has to be in. That is right for `gtm.js` /
|
|
272
|
+
* `gtm.dom` / `gtm.load`, which GTM pushes by itself on every page: the tag
|
|
273
|
+
* fires there whatever the site's own code does. It is wrong for a custom
|
|
274
|
+
* event, which only exists if the site pushes it — verda.com's Dreamdata tag
|
|
275
|
+
* fires on `virtualPageView` or `cookie_consent_update` and on nothing else,
|
|
276
|
+
* so a release that stops pushing `virtualPageView` silently ends tracking
|
|
277
|
+
* while the container still reads as a healthy, correctly consent-gated
|
|
278
|
+
* install. That is a gate, and this is the function that reports it.
|
|
279
|
+
*
|
|
280
|
+
* Same soundness rule as the two functions above, applied per rule instead of
|
|
281
|
+
* by counting them: GTM ORs a tag's `add` rules together, so a required event
|
|
282
|
+
* is a global requirement only when EVERY firing path requires one. A path
|
|
283
|
+
* triggered on `gtm.js`, or on a condition this cannot read as a single event
|
|
284
|
+
* name (a regex match on `event`, say), makes the tag reachable without any
|
|
285
|
+
* custom event and returns nothing rather than overclaiming a gate. The union
|
|
286
|
+
* across paths is what is reported: any one of these events is enough.
|
|
287
|
+
*/
|
|
288
|
+
function resolveRequiredCustomEvents(resource, tagIndex) {
|
|
289
|
+
const predicates = resource.predicates ?? [];
|
|
290
|
+
const macros = resource.macros ?? [];
|
|
291
|
+
const addRules = firingRulesFor(resource.rules ?? [], tagIndex);
|
|
292
|
+
if (addRules.length === 0)
|
|
293
|
+
return [];
|
|
294
|
+
const required = new Set();
|
|
295
|
+
for (const rule of addRules) {
|
|
296
|
+
const onThisPath = [];
|
|
297
|
+
for (const clause of rule) {
|
|
298
|
+
// Only a required ("if") equality names an event the visitor must
|
|
299
|
+
// receive; an "unless" clause forbids one, which is not a requirement.
|
|
300
|
+
if (clause[0] !== "if")
|
|
301
|
+
continue;
|
|
302
|
+
for (const index of clause.slice(1)) {
|
|
303
|
+
const predicate = typeof index === "number" ? predicates[index] : undefined;
|
|
304
|
+
if (!predicate || predicate.function !== "_eq")
|
|
305
|
+
continue;
|
|
306
|
+
if (describeOperand(predicate.arg0, macros) !== "event")
|
|
307
|
+
continue;
|
|
308
|
+
// GTM's own events fire unprompted on every page, so requiring one is
|
|
309
|
+
// not a gate the site can accidentally break.
|
|
310
|
+
if (typeof predicate.arg1 === "string" && !predicate.arg1.startsWith("gtm."))
|
|
311
|
+
onThisPath.push(predicate.arg1);
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
if (onThisPath.length === 0)
|
|
315
|
+
return [];
|
|
316
|
+
for (const name of onThisPath)
|
|
317
|
+
required.add(name);
|
|
318
|
+
}
|
|
319
|
+
return [...required];
|
|
320
|
+
}
|
|
321
|
+
/**
|
|
322
|
+
* The conditions a tag inherits from the ONLY rule that can fire it.
|
|
323
|
+
*
|
|
324
|
+
* A trigger's own conditions are not exceptions and do not compile to `block`
|
|
325
|
+
* clauses: they land as `if`/`unless` clauses on the rule that adds the tag.
|
|
326
|
+
* ptc.com's Dreamdata tag carries no exception at all — its gate is exactly
|
|
327
|
+
* this shape, a required Page Hostname of www.ptc.com plus a list of URL
|
|
328
|
+
* substrings that must not appear — so reading only `block` clauses reports
|
|
329
|
+
* it as ungated while a run from any other hostname watches it never fire.
|
|
330
|
+
*
|
|
331
|
+
* Same soundness rule as resolveTriggerGroupGates, for the same reason: GTM
|
|
332
|
+
* ORs a tag's `add` rules together, so a condition on one of several firing
|
|
333
|
+
* paths is not a gate on the tag. Only a sole `add` rule makes its conditions
|
|
334
|
+
* global. Clauses naming WHEN the rule is evaluated (`event`) or wiring it to
|
|
335
|
+
* a Trigger Group (`gtm.triggers`) are dropped as trivial — the latter is
|
|
336
|
+
* resolved properly by resolveTriggerGroupGates instead, so the two functions
|
|
337
|
+
* report disjoint sets rather than the same gate twice.
|
|
338
|
+
*/
|
|
339
|
+
function resolveSoleFiringRuleGates(resource, tagIndex) {
|
|
340
|
+
const addRules = firingRulesFor(resource.rules ?? [], tagIndex);
|
|
341
|
+
if (addRules.length !== 1)
|
|
342
|
+
return [];
|
|
343
|
+
return describeRuleAsBlocking(addRules[0], "add", resource.predicates ?? [], resource.macros ?? []);
|
|
344
|
+
}
|
|
345
|
+
/**
|
|
346
|
+
* The whole gate on one tag, by index: its consent list, plus every way it
|
|
347
|
+
* can be held back.
|
|
348
|
+
*
|
|
349
|
+
* The single definition of what "gated" means, so the per-bundle read
|
|
350
|
+
* (readTagGating) and the per-tag one (readDreamdataTags) can never describe
|
|
351
|
+
* the same tag differently.
|
|
352
|
+
*/
|
|
353
|
+
function gatingForTagIndex(resource, tagIndex) {
|
|
354
|
+
const macros = resource.macros ?? [];
|
|
355
|
+
const predicates = resource.predicates ?? [];
|
|
356
|
+
const rawConsent = (resource.tags ?? [])[tagIndex]?.consent;
|
|
357
|
+
const consent = Array.isArray(rawConsent)
|
|
358
|
+
? rawConsent.filter((v) => typeof v === "string" && v !== "list")
|
|
359
|
+
: null;
|
|
360
|
+
const blockedWhen = [];
|
|
361
|
+
for (const rule of resource.rules ?? []) {
|
|
362
|
+
const blocksThisTag = rule.some((clause) => clause[0] === "block" && clause.slice(1).includes(tagIndex));
|
|
363
|
+
if (!blocksThisTag)
|
|
364
|
+
continue;
|
|
365
|
+
const conditions = describeRuleAsBlocking(rule, "block", predicates, macros);
|
|
366
|
+
if (conditions.length > 0)
|
|
367
|
+
blockedWhen.push(conditions.join(" and "));
|
|
368
|
+
}
|
|
369
|
+
// A tag can carry a direct exception AND fire through a Trigger Group AND
|
|
370
|
+
// have conditions on its own firing trigger — all three are read, since any
|
|
371
|
+
// one alone would understate the gate.
|
|
372
|
+
blockedWhen.push(...resolveTriggerGroupGates(resource, tagIndex));
|
|
373
|
+
blockedWhen.push(...resolveSoleFiringRuleGates(resource, tagIndex));
|
|
374
|
+
return {
|
|
375
|
+
tagIndex,
|
|
376
|
+
consent: consent !== null && consent.length > 0 ? consent : null,
|
|
377
|
+
blockedWhen: [...new Set(blockedWhen)],
|
|
378
|
+
requiresEvents: resolveRequiredCustomEvents(resource, tagIndex),
|
|
379
|
+
};
|
|
380
|
+
}
|
|
381
|
+
/** Every tag whose serialised form mentions `scriptFile`, in container order. */
|
|
382
|
+
function tagIndexesLoading(resource, scriptFile) {
|
|
383
|
+
const indexes = [];
|
|
384
|
+
const tags = resource.tags ?? [];
|
|
385
|
+
for (let i = 0; i < tags.length; i++) {
|
|
386
|
+
if (JSON.stringify(tags[i]).includes(scriptFile))
|
|
387
|
+
indexes.push(i);
|
|
388
|
+
}
|
|
389
|
+
return indexes;
|
|
390
|
+
}
|
|
391
|
+
/**
|
|
392
|
+
* The gating on the first tag whose serialised form mentions `scriptFile`.
|
|
393
|
+
*
|
|
394
|
+
* Matching on the injected script's filename is what ties a tag back to a
|
|
395
|
+
* specific bundle: the tag's own name is not in the published container.
|
|
396
|
+
*/
|
|
397
|
+
export function readTagGating(resource, scriptFile) {
|
|
398
|
+
const tagIndex = tagIndexesLoading(resource, scriptFile)[0];
|
|
399
|
+
return tagIndex === undefined ? null : gatingForTagIndex(resource, tagIndex);
|
|
400
|
+
}
|
|
401
|
+
/**
|
|
402
|
+
* Every Dreamdata tag in the container, grouped BY TAG rather than by bundle.
|
|
403
|
+
*
|
|
404
|
+
* readTagGating answers "how is the standard bundle gated" and takes the
|
|
405
|
+
* first tag that loads it, which is the right shape for a per-bundle field
|
|
406
|
+
* and the wrong one for two questions this cannot express:
|
|
407
|
+
*
|
|
408
|
+
* - One tag loading BOTH bundles. Asking per bundle returns the same
|
|
409
|
+
* tagIndex twice and reads back as two independently gated installs, when
|
|
410
|
+
* in fact no GTM configuration can gate them apart — see TagManagerBundleTag.
|
|
411
|
+
* - Two tags loading the SAME bundle, which is a duplicate install rather
|
|
412
|
+
* than a gate, and which the first-match read silently drops.
|
|
413
|
+
*
|
|
414
|
+
* `files` maps each bundle to the filename its loader requests, so the caller
|
|
415
|
+
* owns the constants and this stays a pure function of the container.
|
|
416
|
+
*/
|
|
417
|
+
export function readDreamdataTags(resource, files) {
|
|
418
|
+
const byTag = new Map();
|
|
419
|
+
for (const bundle of Object.keys(files)) {
|
|
420
|
+
for (const tagIndex of tagIndexesLoading(resource, files[bundle])) {
|
|
421
|
+
const bundles = byTag.get(tagIndex);
|
|
422
|
+
if (bundles)
|
|
423
|
+
bundles.push(bundle);
|
|
424
|
+
else
|
|
425
|
+
byTag.set(tagIndex, [bundle]);
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
return [...byTag.entries()]
|
|
429
|
+
.sort(([a], [b]) => a - b)
|
|
430
|
+
.map(([tagIndex, bundles]) => ({ ...gatingForTagIndex(resource, tagIndex), bundles }));
|
|
431
|
+
}
|
|
432
|
+
//# sourceMappingURL=gtm-container.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gtm-container.js","sourceRoot":"","sources":["../../src/evidence/gtm-container.ts"],"names":[],"mappings":"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"}
|