@d8a-tech/gd 0.32.2 → 0.33.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/gd.js +177 -15
- package/dist/gd.js.map +2 -2
- package/dist/gd.min.js +5 -2
- package/dist/gd.min.js.map +3 -3
- package/package.json +1 -1
- package/src.hash +1 -1
package/dist/gd.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
/* ga4-duplicator - built 2026-02-
|
|
1
|
+
/* ga4-duplicator - built 2026-02-15T19:18:47.320Z */
|
|
2
2
|
"use strict";
|
|
3
3
|
(() => {
|
|
4
4
|
// src/version.ts
|
|
5
|
-
var version = "v0.
|
|
5
|
+
var version = "v0.33.0" ? "v0.33.0" : devVersionUtc();
|
|
6
6
|
|
|
7
7
|
// src/ga4-duplicator.ts
|
|
8
8
|
window.createGA4Duplicator = function(options) {
|
|
@@ -29,18 +29,69 @@
|
|
|
29
29
|
}
|
|
30
30
|
const originalPromise = originalFetch.apply(this, arguments);
|
|
31
31
|
const duplicateUrl = ctx.buildDuplicateUrl(requestUrl);
|
|
32
|
+
const convertToGet = ctx.getConvertToGet(requestUrl);
|
|
32
33
|
if (upperMethod === "GET") {
|
|
33
34
|
originalFetch(duplicateUrl, { method: "GET", keepalive: true }).catch((error) => {
|
|
34
35
|
if (ctx.debug) console.error("gtm interceptor: error duplicating GET fetch:", error);
|
|
35
36
|
});
|
|
36
37
|
} else if (upperMethod === "POST") {
|
|
37
38
|
prepareBodyPromise.then((dupBody) => {
|
|
38
|
-
|
|
39
|
-
|
|
39
|
+
if (convertToGet) {
|
|
40
|
+
let bodyStr = "";
|
|
41
|
+
if (typeof dupBody === "string") {
|
|
42
|
+
bodyStr = dupBody;
|
|
43
|
+
} else if (dupBody instanceof Blob) {
|
|
44
|
+
originalFetch(duplicateUrl, {
|
|
45
|
+
method: "POST",
|
|
46
|
+
body: dupBody,
|
|
47
|
+
keepalive: true
|
|
48
|
+
}).catch((error) => {
|
|
49
|
+
if (ctx.debug)
|
|
50
|
+
console.error(
|
|
51
|
+
"gtm interceptor: error duplicating POST fetch (convert_to_get with Blob):",
|
|
52
|
+
error
|
|
53
|
+
);
|
|
54
|
+
});
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
const lines = bodyStr.split("\n");
|
|
58
|
+
let sentAny = false;
|
|
59
|
+
for (let i = 0; i < lines.length; i++) {
|
|
60
|
+
const line = lines[i].trim();
|
|
61
|
+
if (line) {
|
|
62
|
+
const mergedUrl = ctx.buildDuplicateUrl(requestUrl);
|
|
63
|
+
const urlWithMergedLine = mergeBodyLineWithUrl(mergedUrl, line);
|
|
64
|
+
originalFetch(urlWithMergedLine, { method: "GET", keepalive: true }).catch(
|
|
65
|
+
(error) => {
|
|
66
|
+
if (ctx.debug)
|
|
67
|
+
console.error(
|
|
68
|
+
"gtm interceptor: error duplicating GET fetch (from convert_to_get):",
|
|
69
|
+
error
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
);
|
|
73
|
+
sentAny = true;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
if (!sentAny) {
|
|
77
|
+
originalFetch(duplicateUrl, { method: "GET", keepalive: true }).catch((error) => {
|
|
78
|
+
if (ctx.debug)
|
|
79
|
+
console.error(
|
|
80
|
+
"gtm interceptor: error duplicating GET fetch (empty body convert_to_get):",
|
|
81
|
+
error
|
|
82
|
+
);
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
} else {
|
|
86
|
+
originalFetch(duplicateUrl, {
|
|
87
|
+
method: "POST",
|
|
88
|
+
body: dupBody,
|
|
89
|
+
keepalive: true
|
|
90
|
+
}).catch((error) => {
|
|
40
91
|
if (ctx.debug)
|
|
41
92
|
console.error("gtm interceptor: error duplicating POST fetch:", error);
|
|
42
|
-
}
|
|
43
|
-
|
|
93
|
+
});
|
|
94
|
+
}
|
|
44
95
|
});
|
|
45
96
|
}
|
|
46
97
|
return originalPromise;
|
|
@@ -64,17 +115,57 @@
|
|
|
64
115
|
try {
|
|
65
116
|
const method = (this._requestMethod || "GET").toUpperCase();
|
|
66
117
|
const duplicateUrl = ctx.buildDuplicateUrl(this._requestUrl);
|
|
118
|
+
const convertToGet = ctx.getConvertToGet(this._requestUrl);
|
|
67
119
|
if (method === "GET") {
|
|
68
120
|
fetch(duplicateUrl, { method: "GET", keepalive: true }).catch((error) => {
|
|
69
121
|
if (ctx.debug) console.error("gtm interceptor: error duplicating GET xhr:", error);
|
|
70
122
|
});
|
|
71
123
|
} else if (method === "POST") {
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
124
|
+
if (convertToGet) {
|
|
125
|
+
let bodyStr = "";
|
|
126
|
+
if (typeof body === "string") {
|
|
127
|
+
bodyStr = body;
|
|
128
|
+
} else if (body && typeof body === "object") {
|
|
129
|
+
try {
|
|
130
|
+
bodyStr = String(body);
|
|
131
|
+
} catch (e) {
|
|
132
|
+
bodyStr = "";
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
const lines = bodyStr.split("\n");
|
|
136
|
+
let sentAny = false;
|
|
137
|
+
for (let i = 0; i < lines.length; i++) {
|
|
138
|
+
const line = lines[i].trim();
|
|
139
|
+
if (line) {
|
|
140
|
+
const mergedUrl = ctx.buildDuplicateUrl(this._requestUrl);
|
|
141
|
+
const urlWithMergedLine = mergeBodyLineWithUrl(mergedUrl, line);
|
|
142
|
+
fetch(urlWithMergedLine, { method: "GET", keepalive: true }).catch((error) => {
|
|
143
|
+
if (ctx.debug)
|
|
144
|
+
console.error(
|
|
145
|
+
"gtm interceptor: error duplicating GET xhr (from convert_to_get):",
|
|
146
|
+
error
|
|
147
|
+
);
|
|
148
|
+
});
|
|
149
|
+
sentAny = true;
|
|
150
|
+
}
|
|
76
151
|
}
|
|
77
|
-
|
|
152
|
+
if (!sentAny) {
|
|
153
|
+
fetch(duplicateUrl, { method: "GET", keepalive: true }).catch((error) => {
|
|
154
|
+
if (ctx.debug)
|
|
155
|
+
console.error(
|
|
156
|
+
"gtm interceptor: error duplicating GET xhr (empty body convert_to_get):",
|
|
157
|
+
error
|
|
158
|
+
);
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
} else {
|
|
162
|
+
fetch(duplicateUrl, { method: "POST", body, keepalive: true }).catch(
|
|
163
|
+
(error) => {
|
|
164
|
+
if (ctx.debug)
|
|
165
|
+
console.error("gtm interceptor: error duplicating POST xhr:", error);
|
|
166
|
+
}
|
|
167
|
+
);
|
|
168
|
+
}
|
|
78
169
|
}
|
|
79
170
|
} catch (dupErr) {
|
|
80
171
|
if (ctx.debug) console.error("gtm interceptor: xhr duplication failed:", dupErr);
|
|
@@ -93,7 +184,48 @@
|
|
|
93
184
|
if (ctx.isTargetUrl(url)) {
|
|
94
185
|
const originalResult = originalSendBeacon.apply(this, arguments);
|
|
95
186
|
try {
|
|
96
|
-
|
|
187
|
+
const duplicateUrl = ctx.buildDuplicateUrl(url);
|
|
188
|
+
const convertToGet = ctx.getConvertToGet(url);
|
|
189
|
+
if (convertToGet) {
|
|
190
|
+
let bodyStr = "";
|
|
191
|
+
if (typeof data === "string") {
|
|
192
|
+
bodyStr = data;
|
|
193
|
+
} else if (data && typeof data === "object") {
|
|
194
|
+
try {
|
|
195
|
+
bodyStr = String(data);
|
|
196
|
+
} catch (e) {
|
|
197
|
+
bodyStr = "";
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
const lines = bodyStr.split("\n");
|
|
201
|
+
let sentAny = false;
|
|
202
|
+
for (let i = 0; i < lines.length; i++) {
|
|
203
|
+
const line = lines[i].trim();
|
|
204
|
+
if (line) {
|
|
205
|
+
const mergedUrl = ctx.buildDuplicateUrl(url);
|
|
206
|
+
const urlWithMergedLine = mergeBodyLineWithUrl(mergedUrl, line);
|
|
207
|
+
fetch(urlWithMergedLine, { method: "GET", keepalive: true }).catch((error) => {
|
|
208
|
+
if (ctx.debug)
|
|
209
|
+
console.error(
|
|
210
|
+
"gtm interceptor: error duplicating GET beacon (from convert_to_get):",
|
|
211
|
+
error
|
|
212
|
+
);
|
|
213
|
+
});
|
|
214
|
+
sentAny = true;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
if (!sentAny) {
|
|
218
|
+
fetch(duplicateUrl, { method: "GET", keepalive: true }).catch((error) => {
|
|
219
|
+
if (ctx.debug)
|
|
220
|
+
console.error(
|
|
221
|
+
"gtm interceptor: error duplicating GET beacon (empty body convert_to_get):",
|
|
222
|
+
error
|
|
223
|
+
);
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
} else {
|
|
227
|
+
originalSendBeacon.call(navigator, duplicateUrl, data);
|
|
228
|
+
}
|
|
97
229
|
} catch (e) {
|
|
98
230
|
if (ctx.debug) console.error("gtm interceptor: error duplicating sendBeacon:", e);
|
|
99
231
|
}
|
|
@@ -198,13 +330,19 @@
|
|
|
198
330
|
const destinations = [];
|
|
199
331
|
if (options.destinations && Array.isArray(options.destinations)) {
|
|
200
332
|
for (let i = 0; i < options.destinations.length; i++) {
|
|
201
|
-
|
|
333
|
+
const dest = options.destinations[i];
|
|
334
|
+
destinations.push({
|
|
335
|
+
measurement_id: dest.measurement_id,
|
|
336
|
+
server_container_url: dest.server_container_url,
|
|
337
|
+
convert_to_get: dest.convert_to_get !== void 0 ? dest.convert_to_get : options.convert_to_get
|
|
338
|
+
});
|
|
202
339
|
}
|
|
203
340
|
}
|
|
204
341
|
if (options.server_container_url) {
|
|
205
342
|
destinations.push({
|
|
206
343
|
measurement_id: "*",
|
|
207
|
-
server_container_url: options.server_container_url
|
|
344
|
+
server_container_url: options.server_container_url,
|
|
345
|
+
convert_to_get: options.convert_to_get
|
|
208
346
|
});
|
|
209
347
|
}
|
|
210
348
|
if (destinations.length === 0) {
|
|
@@ -242,6 +380,24 @@
|
|
|
242
380
|
}
|
|
243
381
|
return null;
|
|
244
382
|
}
|
|
383
|
+
function mergeBodyLineWithUrl(originalUrl, bodyLine) {
|
|
384
|
+
try {
|
|
385
|
+
const url = new URL(originalUrl, location.href);
|
|
386
|
+
const lineParams = new URLSearchParams(bodyLine);
|
|
387
|
+
for (const [key] of lineParams.entries()) {
|
|
388
|
+
url.searchParams.delete(key);
|
|
389
|
+
}
|
|
390
|
+
for (const [key, value] of lineParams.entries()) {
|
|
391
|
+
url.searchParams.append(key, value);
|
|
392
|
+
}
|
|
393
|
+
return url.toString();
|
|
394
|
+
} catch (e) {
|
|
395
|
+
const urlWithoutQuery = originalUrl.split("?")[0];
|
|
396
|
+
const originalParams = originalUrl.match(/\?(.*)/) ? originalUrl.match(/\?(.*)/)[1] : "";
|
|
397
|
+
const merged = originalParams + (originalParams && bodyLine ? "&" : "") + bodyLine;
|
|
398
|
+
return urlWithoutQuery + (merged ? "?" + merged : "");
|
|
399
|
+
}
|
|
400
|
+
}
|
|
245
401
|
function getDuplicateEndpointUrl(dest) {
|
|
246
402
|
const trackingURL = String(dest.server_container_url || "").trim();
|
|
247
403
|
const u = new URL(trackingURL, location.href);
|
|
@@ -297,10 +453,16 @@
|
|
|
297
453
|
}
|
|
298
454
|
return dst.toString();
|
|
299
455
|
}
|
|
456
|
+
function getConvertToGet(url) {
|
|
457
|
+
const id = getMeasurementId(url);
|
|
458
|
+
const dest = getDestinationForId(id);
|
|
459
|
+
return dest ? !!dest.convert_to_get : false;
|
|
460
|
+
}
|
|
300
461
|
const context = {
|
|
301
462
|
debug: !!options.debug,
|
|
302
463
|
isTargetUrl,
|
|
303
|
-
buildDuplicateUrl
|
|
464
|
+
buildDuplicateUrl,
|
|
465
|
+
getConvertToGet
|
|
304
466
|
};
|
|
305
467
|
const interceptors = [
|
|
306
468
|
new FetchInterceptor(),
|
package/dist/gd.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/version.ts", "../src/ga4-duplicator.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * Package version identifier.\n * This value is replaced at build time via esbuild define.\n */\ndeclare const __D8A_VERSION__: string;\n\nfunction devVersionUtc(): string {\n const now = new Date();\n const year = String(now.getUTCFullYear()).slice(-2);\n const month = String(now.getUTCMonth() + 1).padStart(2, \"0\");\n return `dev-${year}-${month}`;\n}\n\nexport const version: string =\n typeof __D8A_VERSION__ !== \"undefined\" && __D8A_VERSION__ ? __D8A_VERSION__ : devVersionUtc();\n", "/**\n * GA4 Duplicator - Intercepts GA4 collect calls and sends duplicates to D8A.\n */\n\nimport { version } from \"./version\";\n\ninterface GA4Destination {\n measurement_id: string;\n server_container_url: string;\n}\n\ninterface GA4DuplicatorOptions {\n server_container_url?: string;\n destinations?: GA4Destination[];\n debug?: boolean;\n}\n\n(window as any).createGA4Duplicator = function (options: GA4DuplicatorOptions) {\n /**\n * Shared logic and configuration for interceptors.\n */\n interface InterceptorContext {\n debug: boolean;\n isTargetUrl(url: string | null | undefined): boolean;\n buildDuplicateUrl(url: string): string;\n }\n\n /**\n * Base interface for monkey-patching implementations.\n */\n interface NetworkInterceptor {\n install(context: InterceptorContext): void;\n }\n\n class FetchInterceptor implements NetworkInterceptor {\n install(ctx: InterceptorContext): void {\n const originalFetch = window.fetch;\n window.fetch = function (\n this: any,\n resource: RequestInfo | URL,\n config?: RequestInit,\n ): Promise<Response> {\n const requestUrl =\n typeof resource === \"string\"\n ? resource\n : resource instanceof URL\n ? resource.toString()\n : (resource as any).url;\n const method = (config && config.method) || (resource as any).method || \"GET\";\n\n if (ctx.isTargetUrl(requestUrl)) {\n const upperMethod = (method || \"GET\").toUpperCase();\n\n // If we need the body from a Request, clone BEFORE calling the original fetch\n let prepareBodyPromise: Promise<any> = Promise.resolve(undefined);\n if (upperMethod === \"POST\") {\n if (config && Object.prototype.hasOwnProperty.call(config, \"body\")) {\n prepareBodyPromise = Promise.resolve(config.body);\n } else if (typeof Request !== \"undefined\" && resource instanceof Request) {\n try {\n const clonedReq = resource.clone();\n prepareBodyPromise = clonedReq.blob().catch(() => undefined);\n } catch {\n prepareBodyPromise = Promise.resolve(undefined);\n }\n }\n }\n\n // First send original request to Google Analytics\n const originalPromise = originalFetch.apply(this, arguments as any);\n\n // Then send duplicate\n const duplicateUrl = ctx.buildDuplicateUrl(requestUrl);\n\n if (upperMethod === \"GET\") {\n originalFetch(duplicateUrl, { method: \"GET\", keepalive: true }).catch((error) => {\n if (ctx.debug) console.error(\"gtm interceptor: error duplicating GET fetch:\", error);\n });\n } else if (upperMethod === \"POST\") {\n prepareBodyPromise.then((dupBody) => {\n originalFetch(duplicateUrl, { method: \"POST\", body: dupBody, keepalive: true }).catch(\n (error) => {\n if (ctx.debug)\n console.error(\"gtm interceptor: error duplicating POST fetch:\", error);\n },\n );\n });\n }\n\n return originalPromise;\n }\n\n return originalFetch.apply(this, arguments as any);\n };\n }\n }\n\n class XhrInterceptor implements NetworkInterceptor {\n install(ctx: InterceptorContext): void {\n const originalXHROpen = XMLHttpRequest.prototype.open;\n const originalXHRSend = XMLHttpRequest.prototype.send;\n\n XMLHttpRequest.prototype.open = function (this: any, method: string, url: string | URL) {\n this._requestMethod = method;\n this._requestUrl = url;\n return originalXHROpen.apply(this, arguments as any);\n };\n\n XMLHttpRequest.prototype.send = function (\n this: any,\n body?: Document | XMLHttpRequestBodyInit | null,\n ) {\n if (this._requestUrl && ctx.isTargetUrl(this._requestUrl)) {\n // First send original request to Google Analytics\n const originalResult = originalXHRSend.apply(this, arguments as any);\n\n // Then send duplicate to our endpoint mimicking method and payload\n try {\n const method = (this._requestMethod || \"GET\").toUpperCase();\n const duplicateUrl = ctx.buildDuplicateUrl(this._requestUrl);\n\n if (method === \"GET\") {\n fetch(duplicateUrl, { method: \"GET\", keepalive: true }).catch((error) => {\n if (ctx.debug) console.error(\"gtm interceptor: error duplicating GET xhr:\", error);\n });\n } else if (method === \"POST\") {\n fetch(duplicateUrl, { method: \"POST\", body: body as any, keepalive: true }).catch(\n (error) => {\n if (ctx.debug)\n console.error(\"gtm interceptor: error duplicating POST xhr:\", error);\n },\n );\n }\n } catch (dupErr) {\n if (ctx.debug) console.error(\"gtm interceptor: xhr duplication failed:\", dupErr);\n }\n return originalResult;\n }\n return originalXHRSend.apply(this, arguments as any);\n };\n }\n }\n\n class BeaconInterceptor implements NetworkInterceptor {\n install(ctx: InterceptorContext): void {\n if (!navigator.sendBeacon) return;\n\n const originalSendBeacon = navigator.sendBeacon;\n navigator.sendBeacon = function (\n this: any,\n url: string | URL,\n data?: BodyInit | null,\n ): boolean {\n if (ctx.isTargetUrl(url as string)) {\n const originalResult = originalSendBeacon.apply(this, arguments as any);\n try {\n originalSendBeacon.call(navigator, ctx.buildDuplicateUrl(url as string), data);\n } catch (e) {\n if (ctx.debug) console.error(\"gtm interceptor: error duplicating sendBeacon:\", e);\n }\n return originalResult;\n }\n return originalSendBeacon.apply(this, arguments as any);\n };\n }\n }\n\n class ScriptInterceptor implements NetworkInterceptor {\n install(ctx: InterceptorContext): void {\n try {\n const scriptSrcDescriptor = Object.getOwnPropertyDescriptor(\n HTMLScriptElement.prototype,\n \"src\",\n );\n const originalScriptSrcSetter = scriptSrcDescriptor && scriptSrcDescriptor.set;\n const originalScriptSrcGetter = scriptSrcDescriptor && scriptSrcDescriptor.get;\n const originalScriptSetAttribute = HTMLScriptElement.prototype.setAttribute;\n\n const duplicateIfGA4Url = (urlString: string) => {\n try {\n if (!ctx.isTargetUrl(urlString)) return;\n fetch(ctx.buildDuplicateUrl(urlString), { method: \"GET\", keepalive: true }).catch(\n (error) => {\n if (ctx.debug)\n console.error(\"gtm interceptor: error duplicating script GET:\", error);\n },\n );\n } catch {\n // Intentionally empty\n }\n };\n\n if (originalScriptSrcSetter && originalScriptSrcGetter) {\n const setter = originalScriptSrcSetter;\n const getter = originalScriptSrcGetter;\n Object.defineProperty(HTMLScriptElement.prototype, \"src\", {\n configurable: true,\n enumerable: true,\n get: function (this: any) {\n return getter.call(this);\n },\n set: function (this: any, value: string) {\n try {\n const last = this.__ga4LastSrcDuplicated;\n if (value && value !== last) {\n duplicateIfGA4Url(String(value));\n this.__ga4LastSrcDuplicated = String(value);\n }\n const self = this;\n const onloadOnce = function () {\n try {\n const finalUrl = self.src;\n if (finalUrl && finalUrl !== self.__ga4LastSrcDuplicated) {\n duplicateIfGA4Url(finalUrl);\n self.__ga4LastSrcDuplicated = finalUrl;\n }\n } catch {}\n self.removeEventListener(\"load\", onloadOnce);\n };\n this.addEventListener(\"load\", onloadOnce);\n } catch {}\n setter.call(this, value);\n },\n });\n }\n\n HTMLScriptElement.prototype.setAttribute = function (\n this: any,\n name: string,\n value: string,\n ) {\n try {\n if (String(name).toLowerCase() === \"src\") {\n const v = String(value);\n const last = this.__ga4LastSrcDuplicated;\n if (v && v !== last) {\n duplicateIfGA4Url(v);\n this.__ga4LastSrcDuplicated = v;\n }\n const selfAttr = this;\n const onloadOnceAttr = function () {\n try {\n const finalUrlAttr = selfAttr.src;\n if (finalUrlAttr && finalUrlAttr !== selfAttr.__ga4LastSrcDuplicated) {\n duplicateIfGA4Url(finalUrlAttr);\n selfAttr.__ga4LastSrcDuplicated = finalUrlAttr;\n }\n } catch {}\n selfAttr.removeEventListener(\"load\", onloadOnceAttr);\n };\n this.addEventListener(\"load\", onloadOnceAttr);\n }\n } catch {\n // Intentionally empty\n }\n return originalScriptSetAttribute.apply(this, arguments as any);\n };\n } catch {}\n }\n }\n\n if ((window as any).__ga4DuplicatorInitialized) {\n if (options.debug) console.warn(\"GA4 Duplicator: already initialized.\");\n return;\n }\n\n const destinations: GA4Destination[] = [];\n if (options.destinations && Array.isArray(options.destinations)) {\n for (let i = 0; i < options.destinations.length; i++) {\n destinations.push(options.destinations[i]);\n }\n }\n\n if (options.server_container_url) {\n destinations.push({\n measurement_id: \"*\",\n server_container_url: options.server_container_url,\n });\n }\n\n if (destinations.length === 0) {\n console.error(\"GA4 Duplicator: either server_container_url or destinations array is required\");\n return;\n }\n\n function normalizePath(p: string): string {\n p = String(p || \"\");\n p = p.replace(/\\/+$/, \"\");\n return p === \"\" ? \"/\" : p;\n }\n\n function matchesId(pattern: string, id: string): boolean {\n if (!pattern || pattern === \"*\") return true;\n try {\n const regexStr = pattern.replace(/[.+^${}()|[\\]\\\\]/g, \"\\\\$&\").replace(/\\*/g, \".*\");\n return new RegExp(\"^\" + regexStr + \"$\", \"i\").test(id);\n } catch {\n return pattern.toLowerCase() === id.toLowerCase();\n }\n }\n\n function getMeasurementId(url: string): string {\n try {\n const parsed = new URL(url, location.href);\n return parsed.searchParams.get(\"tid\") || parsed.searchParams.get(\"id\") || \"\";\n } catch {\n const match = url.match(/[?&](?:tid|id)=([^&?#]+)/);\n return match ? decodeURIComponent(match[1]) : \"\";\n }\n }\n\n function getDestinationForId(id: string): GA4Destination | null {\n for (let i = 0; i < destinations.length; i++) {\n if (matchesId(destinations[i].measurement_id, id)) {\n return destinations[i];\n }\n }\n return null;\n }\n\n function getDuplicateEndpointUrl(dest: GA4Destination): URL {\n const trackingURL = String(dest.server_container_url || \"\").trim();\n const u = new URL(trackingURL, location.href);\n u.search = \"\";\n u.hash = \"\";\n return u;\n }\n\n function isTargetUrl(url: string | null | undefined): boolean {\n if (!url || typeof url !== \"string\") return false;\n try {\n const parsed = new URL(url, location.href);\n\n for (let i = 0; i < destinations.length; i++) {\n const duplicateTarget = getDuplicateEndpointUrl(destinations[i]);\n if (\n parsed.origin === duplicateTarget.origin &&\n normalizePath(parsed.pathname) === normalizePath(duplicateTarget.pathname)\n ) {\n return false;\n }\n }\n\n const params = parsed.searchParams;\n const hasGtm = params.has(\"gtm\");\n const hasTagExp = params.has(\"tag_exp\");\n const measurementId = params.get(\"tid\") || params.get(\"id\") || \"\";\n const isMeasurementIdGA4 = /^G-[A-Z0-9]+$/i.test(measurementId);\n\n return hasGtm && hasTagExp && isMeasurementIdGA4;\n } catch {\n if (typeof url === \"string\") {\n for (let j = 0; j < destinations.length; j++) {\n try {\n const target = getDuplicateEndpointUrl(destinations[j]);\n const targetNoQuery = target.origin + target.pathname;\n if (url.indexOf(targetNoQuery) !== -1) return false;\n } catch {\n // Intentionally empty\n }\n }\n\n const hasGtmFallback = url.indexOf(\"gtm=\") !== -1;\n const hasTagExpFallback = url.indexOf(\"tag_exp=\") !== -1;\n const idMatch = url.match(/[?&](?:tid|id)=G-[A-Za-z0-9]+/);\n return !!(hasGtmFallback && hasTagExpFallback && idMatch);\n }\n return false;\n }\n }\n\n function buildDuplicateUrl(originalUrl: string): string {\n const id = getMeasurementId(originalUrl);\n const dest = getDestinationForId(id);\n if (!dest) return \"\";\n\n const dst = getDuplicateEndpointUrl(dest);\n try {\n const src = new URL(originalUrl, location.href);\n dst.search = src.search;\n dst.searchParams.set(\"_dtv\", version);\n dst.searchParams.set(\"_dtn\", \"gd\");\n } catch {}\n return dst.toString();\n }\n\n const context: InterceptorContext = {\n debug: !!options.debug,\n isTargetUrl,\n buildDuplicateUrl,\n };\n\n const interceptors: NetworkInterceptor[] = [\n new FetchInterceptor(),\n new XhrInterceptor(),\n new BeaconInterceptor(),\n new ScriptInterceptor(),\n ];\n\n for (let i = 0; i < interceptors.length; i++) {\n try {\n interceptors[i].install(context);\n } catch (e) {\n if (options.debug) console.error(\"GA4 Duplicator: failed to install interceptor\", e);\n }\n }\n\n (window as any).__ga4DuplicatorInitialized = true;\n};\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["/**\n * Package version identifier.\n * This value is replaced at build time via esbuild define.\n */\ndeclare const __D8A_VERSION__: string;\n\nfunction devVersionUtc(): string {\n const now = new Date();\n const year = String(now.getUTCFullYear()).slice(-2);\n const month = String(now.getUTCMonth() + 1).padStart(2, \"0\");\n return `dev-${year}-${month}`;\n}\n\nexport const version: string =\n typeof __D8A_VERSION__ !== \"undefined\" && __D8A_VERSION__ ? __D8A_VERSION__ : devVersionUtc();\n", "/**\n * GA4 Duplicator - Intercepts GA4 collect calls and sends duplicates to D8A.\n */\n\nimport { version } from \"./version\";\n\ninterface GA4Destination {\n measurement_id: string;\n server_container_url: string;\n convert_to_get?: boolean;\n}\n\ninterface GA4DuplicatorOptions {\n server_container_url?: string;\n destinations?: GA4Destination[];\n debug?: boolean;\n convert_to_get?: boolean;\n}\n\n(window as any).createGA4Duplicator = function (options: GA4DuplicatorOptions) {\n /**\n * Shared logic and configuration for interceptors.\n */\n interface InterceptorContext {\n debug: boolean;\n isTargetUrl(url: string | null | undefined): boolean;\n buildDuplicateUrl(url: string): string;\n getConvertToGet(url: string): boolean;\n }\n\n /**\n * Base interface for monkey-patching implementations.\n */\n interface NetworkInterceptor {\n install(context: InterceptorContext): void;\n }\n\n class FetchInterceptor implements NetworkInterceptor {\n install(ctx: InterceptorContext): void {\n const originalFetch = window.fetch;\n window.fetch = function (\n this: any,\n resource: RequestInfo | URL,\n config?: RequestInit,\n ): Promise<Response> {\n const requestUrl =\n typeof resource === \"string\"\n ? resource\n : resource instanceof URL\n ? resource.toString()\n : (resource as any).url;\n const method = (config && config.method) || (resource as any).method || \"GET\";\n\n if (ctx.isTargetUrl(requestUrl)) {\n const upperMethod = (method || \"GET\").toUpperCase();\n\n // If we need the body from a Request, clone BEFORE calling the original fetch\n let prepareBodyPromise: Promise<any> = Promise.resolve(undefined);\n if (upperMethod === \"POST\") {\n if (config && Object.prototype.hasOwnProperty.call(config, \"body\")) {\n prepareBodyPromise = Promise.resolve(config.body);\n } else if (typeof Request !== \"undefined\" && resource instanceof Request) {\n try {\n const clonedReq = resource.clone();\n prepareBodyPromise = clonedReq.blob().catch(() => undefined);\n } catch {\n prepareBodyPromise = Promise.resolve(undefined);\n }\n }\n }\n\n // First send original request to Google Analytics\n const originalPromise = originalFetch.apply(this, arguments as any);\n\n // Then send duplicate\n const duplicateUrl = ctx.buildDuplicateUrl(requestUrl);\n const convertToGet = ctx.getConvertToGet(requestUrl);\n\n if (upperMethod === \"GET\") {\n originalFetch(duplicateUrl, { method: \"GET\", keepalive: true }).catch((error) => {\n if (ctx.debug) console.error(\"gtm interceptor: error duplicating GET fetch:\", error);\n });\n } else if (upperMethod === \"POST\") {\n prepareBodyPromise.then((dupBody) => {\n if (convertToGet) {\n // Convert POST to GET: split body into lines and send each as a separate GET request\n let bodyStr = \"\";\n if (typeof dupBody === \"string\") {\n bodyStr = dupBody;\n } else if (dupBody instanceof Blob) {\n // For blob, we can't easily convert synchronously, so fall back to POST\n originalFetch(duplicateUrl, {\n method: \"POST\",\n body: dupBody,\n keepalive: true,\n }).catch((error) => {\n if (ctx.debug)\n console.error(\n \"gtm interceptor: error duplicating POST fetch (convert_to_get with Blob):\",\n error,\n );\n });\n return;\n }\n\n const lines = bodyStr.split(\"\\n\");\n let sentAny = false;\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i].trim();\n if (line) {\n const mergedUrl = ctx.buildDuplicateUrl(requestUrl);\n const urlWithMergedLine = mergeBodyLineWithUrl(mergedUrl, line);\n originalFetch(urlWithMergedLine, { method: \"GET\", keepalive: true }).catch(\n (error) => {\n if (ctx.debug)\n console.error(\n \"gtm interceptor: error duplicating GET fetch (from convert_to_get):\",\n error,\n );\n },\n );\n sentAny = true;\n }\n }\n\n // If body is empty or all lines were empty, send one GET with just URL params\n if (!sentAny) {\n originalFetch(duplicateUrl, { method: \"GET\", keepalive: true }).catch((error) => {\n if (ctx.debug)\n console.error(\n \"gtm interceptor: error duplicating GET fetch (empty body convert_to_get):\",\n error,\n );\n });\n }\n } else {\n // Original POST duplication\n originalFetch(duplicateUrl, {\n method: \"POST\",\n body: dupBody,\n keepalive: true,\n }).catch((error) => {\n if (ctx.debug)\n console.error(\"gtm interceptor: error duplicating POST fetch:\", error);\n });\n }\n });\n }\n\n return originalPromise;\n }\n\n return originalFetch.apply(this, arguments as any);\n };\n }\n }\n\n class XhrInterceptor implements NetworkInterceptor {\n install(ctx: InterceptorContext): void {\n const originalXHROpen = XMLHttpRequest.prototype.open;\n const originalXHRSend = XMLHttpRequest.prototype.send;\n\n XMLHttpRequest.prototype.open = function (this: any, method: string, url: string | URL) {\n this._requestMethod = method;\n this._requestUrl = url;\n return originalXHROpen.apply(this, arguments as any);\n };\n\n XMLHttpRequest.prototype.send = function (\n this: any,\n body?: Document | XMLHttpRequestBodyInit | null,\n ) {\n if (this._requestUrl && ctx.isTargetUrl(this._requestUrl)) {\n // First send original request to Google Analytics\n const originalResult = originalXHRSend.apply(this, arguments as any);\n\n // Then send duplicate to our endpoint mimicking method and payload\n try {\n const method = (this._requestMethod || \"GET\").toUpperCase();\n const duplicateUrl = ctx.buildDuplicateUrl(this._requestUrl);\n const convertToGet = ctx.getConvertToGet(this._requestUrl);\n\n if (method === \"GET\") {\n fetch(duplicateUrl, { method: \"GET\", keepalive: true }).catch((error) => {\n if (ctx.debug) console.error(\"gtm interceptor: error duplicating GET xhr:\", error);\n });\n } else if (method === \"POST\") {\n if (convertToGet) {\n // Convert POST to GET: split body into lines and send each as a separate GET request\n let bodyStr = \"\";\n if (typeof body === \"string\") {\n bodyStr = body;\n } else if (body && typeof body === \"object\") {\n // Try to convert Document or other types to string\n try {\n bodyStr = String(body);\n } catch {\n bodyStr = \"\";\n }\n }\n\n const lines = bodyStr.split(\"\\n\");\n let sentAny = false;\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i].trim();\n if (line) {\n const mergedUrl = ctx.buildDuplicateUrl(this._requestUrl);\n const urlWithMergedLine = mergeBodyLineWithUrl(mergedUrl, line);\n fetch(urlWithMergedLine, { method: \"GET\", keepalive: true }).catch((error) => {\n if (ctx.debug)\n console.error(\n \"gtm interceptor: error duplicating GET xhr (from convert_to_get):\",\n error,\n );\n });\n sentAny = true;\n }\n }\n\n // If body is empty or all lines were empty, send one GET with just URL params\n if (!sentAny) {\n fetch(duplicateUrl, { method: \"GET\", keepalive: true }).catch((error) => {\n if (ctx.debug)\n console.error(\n \"gtm interceptor: error duplicating GET xhr (empty body convert_to_get):\",\n error,\n );\n });\n }\n } else {\n // Original POST duplication\n fetch(duplicateUrl, { method: \"POST\", body: body as any, keepalive: true }).catch(\n (error) => {\n if (ctx.debug)\n console.error(\"gtm interceptor: error duplicating POST xhr:\", error);\n },\n );\n }\n }\n } catch (dupErr) {\n if (ctx.debug) console.error(\"gtm interceptor: xhr duplication failed:\", dupErr);\n }\n return originalResult;\n }\n return originalXHRSend.apply(this, arguments as any);\n };\n }\n }\n\n class BeaconInterceptor implements NetworkInterceptor {\n install(ctx: InterceptorContext): void {\n if (!navigator.sendBeacon) return;\n\n const originalSendBeacon = navigator.sendBeacon;\n navigator.sendBeacon = function (\n this: any,\n url: string | URL,\n data?: BodyInit | null,\n ): boolean {\n if (ctx.isTargetUrl(url as string)) {\n const originalResult = originalSendBeacon.apply(this, arguments as any);\n try {\n const duplicateUrl = ctx.buildDuplicateUrl(url as string);\n const convertToGet = ctx.getConvertToGet(url as string);\n\n if (convertToGet) {\n // Convert sendBeacon POST to GET: split body into lines and send each as a separate GET request\n let bodyStr = \"\";\n if (typeof data === \"string\") {\n bodyStr = data;\n } else if (data && typeof data === \"object\") {\n try {\n bodyStr = String(data);\n } catch {\n bodyStr = \"\";\n }\n }\n\n const lines = bodyStr.split(\"\\n\");\n let sentAny = false;\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i].trim();\n if (line) {\n const mergedUrl = ctx.buildDuplicateUrl(url as string);\n const urlWithMergedLine = mergeBodyLineWithUrl(mergedUrl, line);\n fetch(urlWithMergedLine, { method: \"GET\", keepalive: true }).catch((error) => {\n if (ctx.debug)\n console.error(\n \"gtm interceptor: error duplicating GET beacon (from convert_to_get):\",\n error,\n );\n });\n sentAny = true;\n }\n }\n\n // If body is empty or all lines were empty, send one GET with just URL params\n if (!sentAny) {\n fetch(duplicateUrl, { method: \"GET\", keepalive: true }).catch((error) => {\n if (ctx.debug)\n console.error(\n \"gtm interceptor: error duplicating GET beacon (empty body convert_to_get):\",\n error,\n );\n });\n }\n } else {\n // Original sendBeacon duplication\n originalSendBeacon.call(navigator, duplicateUrl, data);\n }\n } catch (e) {\n if (ctx.debug) console.error(\"gtm interceptor: error duplicating sendBeacon:\", e);\n }\n return originalResult;\n }\n return originalSendBeacon.apply(this, arguments as any);\n };\n }\n }\n\n class ScriptInterceptor implements NetworkInterceptor {\n install(ctx: InterceptorContext): void {\n try {\n const scriptSrcDescriptor = Object.getOwnPropertyDescriptor(\n HTMLScriptElement.prototype,\n \"src\",\n );\n const originalScriptSrcSetter = scriptSrcDescriptor && scriptSrcDescriptor.set;\n const originalScriptSrcGetter = scriptSrcDescriptor && scriptSrcDescriptor.get;\n const originalScriptSetAttribute = HTMLScriptElement.prototype.setAttribute;\n\n const duplicateIfGA4Url = (urlString: string) => {\n try {\n if (!ctx.isTargetUrl(urlString)) return;\n fetch(ctx.buildDuplicateUrl(urlString), { method: \"GET\", keepalive: true }).catch(\n (error) => {\n if (ctx.debug)\n console.error(\"gtm interceptor: error duplicating script GET:\", error);\n },\n );\n } catch {\n // Intentionally empty\n }\n };\n\n if (originalScriptSrcSetter && originalScriptSrcGetter) {\n const setter = originalScriptSrcSetter;\n const getter = originalScriptSrcGetter;\n Object.defineProperty(HTMLScriptElement.prototype, \"src\", {\n configurable: true,\n enumerable: true,\n get: function (this: any) {\n return getter.call(this);\n },\n set: function (this: any, value: string) {\n try {\n const last = this.__ga4LastSrcDuplicated;\n if (value && value !== last) {\n duplicateIfGA4Url(String(value));\n this.__ga4LastSrcDuplicated = String(value);\n }\n const self = this;\n const onloadOnce = function () {\n try {\n const finalUrl = self.src;\n if (finalUrl && finalUrl !== self.__ga4LastSrcDuplicated) {\n duplicateIfGA4Url(finalUrl);\n self.__ga4LastSrcDuplicated = finalUrl;\n }\n } catch {}\n self.removeEventListener(\"load\", onloadOnce);\n };\n this.addEventListener(\"load\", onloadOnce);\n } catch {}\n setter.call(this, value);\n },\n });\n }\n\n HTMLScriptElement.prototype.setAttribute = function (\n this: any,\n name: string,\n value: string,\n ) {\n try {\n if (String(name).toLowerCase() === \"src\") {\n const v = String(value);\n const last = this.__ga4LastSrcDuplicated;\n if (v && v !== last) {\n duplicateIfGA4Url(v);\n this.__ga4LastSrcDuplicated = v;\n }\n const selfAttr = this;\n const onloadOnceAttr = function () {\n try {\n const finalUrlAttr = selfAttr.src;\n if (finalUrlAttr && finalUrlAttr !== selfAttr.__ga4LastSrcDuplicated) {\n duplicateIfGA4Url(finalUrlAttr);\n selfAttr.__ga4LastSrcDuplicated = finalUrlAttr;\n }\n } catch {}\n selfAttr.removeEventListener(\"load\", onloadOnceAttr);\n };\n this.addEventListener(\"load\", onloadOnceAttr);\n }\n } catch {\n // Intentionally empty\n }\n return originalScriptSetAttribute.apply(this, arguments as any);\n };\n } catch {}\n }\n }\n\n if ((window as any).__ga4DuplicatorInitialized) {\n if (options.debug) console.warn(\"GA4 Duplicator: already initialized.\");\n return;\n }\n\n const destinations: GA4Destination[] = [];\n if (options.destinations && Array.isArray(options.destinations)) {\n for (let i = 0; i < options.destinations.length; i++) {\n const dest = options.destinations[i];\n destinations.push({\n measurement_id: dest.measurement_id,\n server_container_url: dest.server_container_url,\n convert_to_get:\n dest.convert_to_get !== undefined ? dest.convert_to_get : options.convert_to_get,\n });\n }\n }\n\n if (options.server_container_url) {\n destinations.push({\n measurement_id: \"*\",\n server_container_url: options.server_container_url,\n convert_to_get: options.convert_to_get,\n });\n }\n\n if (destinations.length === 0) {\n console.error(\"GA4 Duplicator: either server_container_url or destinations array is required\");\n return;\n }\n\n function normalizePath(p: string): string {\n p = String(p || \"\");\n p = p.replace(/\\/+$/, \"\");\n return p === \"\" ? \"/\" : p;\n }\n\n function matchesId(pattern: string, id: string): boolean {\n if (!pattern || pattern === \"*\") return true;\n try {\n const regexStr = pattern.replace(/[.+^${}()|[\\]\\\\]/g, \"\\\\$&\").replace(/\\*/g, \".*\");\n return new RegExp(\"^\" + regexStr + \"$\", \"i\").test(id);\n } catch {\n return pattern.toLowerCase() === id.toLowerCase();\n }\n }\n\n function getMeasurementId(url: string): string {\n try {\n const parsed = new URL(url, location.href);\n return parsed.searchParams.get(\"tid\") || parsed.searchParams.get(\"id\") || \"\";\n } catch {\n const match = url.match(/[?&](?:tid|id)=([^&?#]+)/);\n return match ? decodeURIComponent(match[1]) : \"\";\n }\n }\n\n function getDestinationForId(id: string): GA4Destination | null {\n for (let i = 0; i < destinations.length; i++) {\n if (matchesId(destinations[i].measurement_id, id)) {\n return destinations[i];\n }\n }\n return null;\n }\n\n function mergeBodyLineWithUrl(originalUrl: string, bodyLine: string): string {\n try {\n const url = new URL(originalUrl, location.href);\n const lineParams = new URLSearchParams(bodyLine);\n\n // Line parameters override URL parameters\n for (const [key] of lineParams.entries()) {\n url.searchParams.delete(key);\n }\n for (const [key, value] of lineParams.entries()) {\n url.searchParams.append(key, value);\n }\n\n return url.toString();\n } catch {\n // Fallback: if URL parsing fails, try string manipulation\n const urlWithoutQuery = originalUrl.split(\"?\")[0];\n const originalParams = originalUrl.match(/\\?(.*)/) ? originalUrl.match(/\\?(.*)/)![1] : \"\";\n const merged = originalParams + (originalParams && bodyLine ? \"&\" : \"\") + bodyLine;\n return urlWithoutQuery + (merged ? \"?\" + merged : \"\");\n }\n }\n\n function getDuplicateEndpointUrl(dest: GA4Destination): URL {\n const trackingURL = String(dest.server_container_url || \"\").trim();\n const u = new URL(trackingURL, location.href);\n u.search = \"\";\n u.hash = \"\";\n return u;\n }\n\n function isTargetUrl(url: string | null | undefined): boolean {\n if (!url || typeof url !== \"string\") return false;\n try {\n const parsed = new URL(url, location.href);\n\n for (let i = 0; i < destinations.length; i++) {\n const duplicateTarget = getDuplicateEndpointUrl(destinations[i]);\n if (\n parsed.origin === duplicateTarget.origin &&\n normalizePath(parsed.pathname) === normalizePath(duplicateTarget.pathname)\n ) {\n return false;\n }\n }\n\n const params = parsed.searchParams;\n const hasGtm = params.has(\"gtm\");\n const hasTagExp = params.has(\"tag_exp\");\n const measurementId = params.get(\"tid\") || params.get(\"id\") || \"\";\n const isMeasurementIdGA4 = /^G-[A-Z0-9]+$/i.test(measurementId);\n\n return hasGtm && hasTagExp && isMeasurementIdGA4;\n } catch {\n if (typeof url === \"string\") {\n for (let j = 0; j < destinations.length; j++) {\n try {\n const target = getDuplicateEndpointUrl(destinations[j]);\n const targetNoQuery = target.origin + target.pathname;\n if (url.indexOf(targetNoQuery) !== -1) return false;\n } catch {\n // Intentionally empty\n }\n }\n\n const hasGtmFallback = url.indexOf(\"gtm=\") !== -1;\n const hasTagExpFallback = url.indexOf(\"tag_exp=\") !== -1;\n const idMatch = url.match(/[?&](?:tid|id)=G-[A-Za-z0-9]+/);\n return !!(hasGtmFallback && hasTagExpFallback && idMatch);\n }\n return false;\n }\n }\n\n function buildDuplicateUrl(originalUrl: string): string {\n const id = getMeasurementId(originalUrl);\n const dest = getDestinationForId(id);\n if (!dest) return \"\";\n\n const dst = getDuplicateEndpointUrl(dest);\n try {\n const src = new URL(originalUrl, location.href);\n dst.search = src.search;\n dst.searchParams.set(\"_dtv\", version);\n dst.searchParams.set(\"_dtn\", \"gd\");\n } catch {}\n return dst.toString();\n }\n\n function getConvertToGet(url: string): boolean {\n const id = getMeasurementId(url);\n const dest = getDestinationForId(id);\n return dest ? !!dest.convert_to_get : false;\n }\n\n const context: InterceptorContext = {\n debug: !!options.debug,\n isTargetUrl,\n buildDuplicateUrl,\n getConvertToGet,\n };\n\n const interceptors: NetworkInterceptor[] = [\n new FetchInterceptor(),\n new XhrInterceptor(),\n new BeaconInterceptor(),\n new ScriptInterceptor(),\n ];\n\n for (let i = 0; i < interceptors.length; i++) {\n try {\n interceptors[i].install(context);\n } catch (e) {\n if (options.debug) console.error(\"GA4 Duplicator: failed to install interceptor\", e);\n }\n }\n\n (window as any).__ga4DuplicatorInitialized = true;\n};\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["e"]
|
|
7
7
|
}
|
package/dist/gd.min.js
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
-
/* ga4-duplicator - built 2026-02-
|
|
2
|
-
"use strict";(()=>{var
|
|
1
|
+
/* ga4-duplicator - built 2026-02-15T19:18:47.320Z */
|
|
2
|
+
"use strict";(()=>{var E="v0.33.0";window.createGA4Duplicator=function(h){class L{install(t){let r=window.fetch;window.fetch=function(o,n){let c=typeof o=="string"?o:o instanceof URL?o.toString():o.url,a=n&&n.method||o.method||"GET";if(t.isTargetUrl(c)){let l=(a||"GET").toUpperCase(),u=Promise.resolve(void 0);if(l==="POST"){if(n&&Object.prototype.hasOwnProperty.call(n,"body"))u=Promise.resolve(n.body);else if(typeof Request!="undefined"&&o instanceof Request)try{u=o.clone().blob().catch(()=>{})}catch(s){u=Promise.resolve(void 0)}}let i=r.apply(this,arguments),p=t.buildDuplicateUrl(c),g=t.getConvertToGet(c);return l==="GET"?r(p,{method:"GET",keepalive:!0}).catch(s=>{t.debug&&console.error("gtm interceptor: error duplicating GET fetch:",s)}):l==="POST"&&u.then(s=>{if(g){let d="";if(typeof s=="string")d=s;else if(s instanceof Blob){r(p,{method:"POST",body:s,keepalive:!0}).catch(m=>{t.debug&&console.error("gtm interceptor: error duplicating POST fetch (convert_to_get with Blob):",m)});return}let _=d.split(`
|
|
3
|
+
`),y=!1;for(let m=0;m<_.length;m++){let D=_[m].trim();if(D){let C=t.buildDuplicateUrl(c),M=v(C,D);r(M,{method:"GET",keepalive:!0}).catch(H=>{t.debug&&console.error("gtm interceptor: error duplicating GET fetch (from convert_to_get):",H)}),y=!0}}y||r(p,{method:"GET",keepalive:!0}).catch(m=>{t.debug&&console.error("gtm interceptor: error duplicating GET fetch (empty body convert_to_get):",m)})}else r(p,{method:"POST",body:s,keepalive:!0}).catch(d=>{t.debug&&console.error("gtm interceptor: error duplicating POST fetch:",d)})}),i}return r.apply(this,arguments)}}}class w{install(t){let r=XMLHttpRequest.prototype.open,o=XMLHttpRequest.prototype.send;XMLHttpRequest.prototype.open=function(n,c){return this._requestMethod=n,this._requestUrl=c,r.apply(this,arguments)},XMLHttpRequest.prototype.send=function(n){if(this._requestUrl&&t.isTargetUrl(this._requestUrl)){let c=o.apply(this,arguments);try{let a=(this._requestMethod||"GET").toUpperCase(),l=t.buildDuplicateUrl(this._requestUrl),u=t.getConvertToGet(this._requestUrl);if(a==="GET")fetch(l,{method:"GET",keepalive:!0}).catch(i=>{t.debug&&console.error("gtm interceptor: error duplicating GET xhr:",i)});else if(a==="POST")if(u){let i="";if(typeof n=="string")i=n;else if(n&&typeof n=="object")try{i=String(n)}catch(s){i=""}let p=i.split(`
|
|
4
|
+
`),g=!1;for(let s=0;s<p.length;s++){let d=p[s].trim();if(d){let _=t.buildDuplicateUrl(this._requestUrl),y=v(_,d);fetch(y,{method:"GET",keepalive:!0}).catch(m=>{t.debug&&console.error("gtm interceptor: error duplicating GET xhr (from convert_to_get):",m)}),g=!0}}g||fetch(l,{method:"GET",keepalive:!0}).catch(s=>{t.debug&&console.error("gtm interceptor: error duplicating GET xhr (empty body convert_to_get):",s)})}else fetch(l,{method:"POST",body:n,keepalive:!0}).catch(i=>{t.debug&&console.error("gtm interceptor: error duplicating POST xhr:",i)})}catch(a){t.debug&&console.error("gtm interceptor: xhr duplication failed:",a)}return c}return o.apply(this,arguments)}}}class I{install(t){if(!navigator.sendBeacon)return;let r=navigator.sendBeacon;navigator.sendBeacon=function(o,n){if(t.isTargetUrl(o)){let c=r.apply(this,arguments);try{let a=t.buildDuplicateUrl(o);if(t.getConvertToGet(o)){let u="";if(typeof n=="string")u=n;else if(n&&typeof n=="object")try{u=String(n)}catch(g){u=""}let i=u.split(`
|
|
5
|
+
`),p=!1;for(let g=0;g<i.length;g++){let s=i[g].trim();if(s){let d=t.buildDuplicateUrl(o),_=v(d,s);fetch(_,{method:"GET",keepalive:!0}).catch(y=>{t.debug&&console.error("gtm interceptor: error duplicating GET beacon (from convert_to_get):",y)}),p=!0}}p||fetch(a,{method:"GET",keepalive:!0}).catch(g=>{t.debug&&console.error("gtm interceptor: error duplicating GET beacon (empty body convert_to_get):",g)})}else r.call(navigator,a,n)}catch(a){t.debug&&console.error("gtm interceptor: error duplicating sendBeacon:",a)}return c}return r.apply(this,arguments)}}}class R{install(t){try{let r=Object.getOwnPropertyDescriptor(HTMLScriptElement.prototype,"src"),o=r&&r.set,n=r&&r.get,c=HTMLScriptElement.prototype.setAttribute,a=l=>{try{if(!t.isTargetUrl(l))return;fetch(t.buildDuplicateUrl(l),{method:"GET",keepalive:!0}).catch(u=>{t.debug&&console.error("gtm interceptor: error duplicating script GET:",u)})}catch(u){}};if(o&&n){let l=o,u=n;Object.defineProperty(HTMLScriptElement.prototype,"src",{configurable:!0,enumerable:!0,get:function(){return u.call(this)},set:function(i){try{let p=this.__ga4LastSrcDuplicated;i&&i!==p&&(a(String(i)),this.__ga4LastSrcDuplicated=String(i));let g=this,s=function(){try{let d=g.src;d&&d!==g.__ga4LastSrcDuplicated&&(a(d),g.__ga4LastSrcDuplicated=d)}catch(d){}g.removeEventListener("load",s)};this.addEventListener("load",s)}catch(p){}l.call(this,i)}})}HTMLScriptElement.prototype.setAttribute=function(l,u){try{if(String(l).toLowerCase()==="src"){let i=String(u),p=this.__ga4LastSrcDuplicated;i&&i!==p&&(a(i),this.__ga4LastSrcDuplicated=i);let g=this,s=function(){try{let d=g.src;d&&d!==g.__ga4LastSrcDuplicated&&(a(d),g.__ga4LastSrcDuplicated=d)}catch(d){}g.removeEventListener("load",s)};this.addEventListener("load",s)}}catch(i){}return c.apply(this,arguments)}}catch(r){}}}if(window.__ga4DuplicatorInitialized){h.debug&&console.warn("GA4 Duplicator: already initialized.");return}let f=[];if(h.destinations&&Array.isArray(h.destinations))for(let e=0;e<h.destinations.length;e++){let t=h.destinations[e];f.push({measurement_id:t.measurement_id,server_container_url:t.server_container_url,convert_to_get:t.convert_to_get!==void 0?t.convert_to_get:h.convert_to_get})}if(h.server_container_url&&f.push({measurement_id:"*",server_container_url:h.server_container_url,convert_to_get:h.convert_to_get}),f.length===0){console.error("GA4 Duplicator: either server_container_url or destinations array is required");return}function T(e){return e=String(e||""),e=e.replace(/\/+$/,""),e===""?"/":e}function A(e,t){if(!e||e==="*")return!0;try{let r=e.replace(/[.+^${}()|[\]\\]/g,"\\$&").replace(/\*/g,".*");return new RegExp("^"+r+"$","i").test(t)}catch(r){return e.toLowerCase()===t.toLowerCase()}}function S(e){try{let t=new URL(e,location.href);return t.searchParams.get("tid")||t.searchParams.get("id")||""}catch(t){let r=e.match(/[?&](?:tid|id)=([^&?#]+)/);return r?decodeURIComponent(r[1]):""}}function G(e){for(let t=0;t<f.length;t++)if(A(f[t].measurement_id,e))return f[t];return null}function v(e,t){try{let r=new URL(e,location.href),o=new URLSearchParams(t);for(let[n]of o.entries())r.searchParams.delete(n);for(let[n,c]of o.entries())r.searchParams.append(n,c);return r.toString()}catch(r){let o=e.split("?")[0],n=e.match(/\?(.*)/)?e.match(/\?(.*)/)[1]:"",c=n+(n&&t?"&":"")+t;return o+(c?"?"+c:"")}}function b(e){let t=String(e.server_container_url||"").trim(),r=new URL(t,location.href);return r.search="",r.hash="",r}function P(e){if(!e||typeof e!="string")return!1;try{let t=new URL(e,location.href);for(let l=0;l<f.length;l++){let u=b(f[l]);if(t.origin===u.origin&&T(t.pathname)===T(u.pathname))return!1}let r=t.searchParams,o=r.has("gtm"),n=r.has("tag_exp"),c=r.get("tid")||r.get("id")||"",a=/^G-[A-Z0-9]+$/i.test(c);return o&&n&&a}catch(t){if(typeof e=="string"){for(let c=0;c<f.length;c++)try{let a=b(f[c]),l=a.origin+a.pathname;if(e.indexOf(l)!==-1)return!1}catch(a){}let r=e.indexOf("gtm=")!==-1,o=e.indexOf("tag_exp=")!==-1,n=e.match(/[?&](?:tid|id)=G-[A-Za-z0-9]+/);return!!(r&&o&&n)}return!1}}function O(e){let t=S(e),r=G(t);if(!r)return"";let o=b(r);try{let n=new URL(e,location.href);o.search=n.search,o.searchParams.set("_dtv",E),o.searchParams.set("_dtn","gd")}catch(n){}return o.toString()}function k(e){let t=S(e),r=G(t);return r?!!r.convert_to_get:!1}let q={debug:!!h.debug,isTargetUrl:P,buildDuplicateUrl:O,getConvertToGet:k},U=[new L,new w,new I,new R];for(let e=0;e<U.length;e++)try{U[e].install(q)}catch(t){h.debug&&console.error("GA4 Duplicator: failed to install interceptor",t)}window.__ga4DuplicatorInitialized=!0};})();
|
|
3
6
|
//# sourceMappingURL=gd.min.js.map
|
package/dist/gd.min.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/version.ts", "../src/ga4-duplicator.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * Package version identifier.\n * This value is replaced at build time via esbuild define.\n */\ndeclare const __D8A_VERSION__: string;\n\nfunction devVersionUtc(): string {\n const now = new Date();\n const year = String(now.getUTCFullYear()).slice(-2);\n const month = String(now.getUTCMonth() + 1).padStart(2, \"0\");\n return `dev-${year}-${month}`;\n}\n\nexport const version: string =\n typeof __D8A_VERSION__ !== \"undefined\" && __D8A_VERSION__ ? __D8A_VERSION__ : devVersionUtc();\n", "/**\n * GA4 Duplicator - Intercepts GA4 collect calls and sends duplicates to D8A.\n */\n\nimport { version } from \"./version\";\n\ninterface GA4Destination {\n measurement_id: string;\n server_container_url: string;\n}\n\ninterface GA4DuplicatorOptions {\n server_container_url?: string;\n destinations?: GA4Destination[];\n debug?: boolean;\n}\n\n(window as any).createGA4Duplicator = function (options: GA4DuplicatorOptions) {\n /**\n * Shared logic and configuration for interceptors.\n */\n interface InterceptorContext {\n debug: boolean;\n isTargetUrl(url: string | null | undefined): boolean;\n buildDuplicateUrl(url: string): string;\n }\n\n /**\n * Base interface for monkey-patching implementations.\n */\n interface NetworkInterceptor {\n install(context: InterceptorContext): void;\n }\n\n class FetchInterceptor implements NetworkInterceptor {\n install(ctx: InterceptorContext): void {\n const originalFetch = window.fetch;\n window.fetch = function (\n this: any,\n resource: RequestInfo | URL,\n config?: RequestInit,\n ): Promise<Response> {\n const requestUrl =\n typeof resource === \"string\"\n ? resource\n : resource instanceof URL\n ? resource.toString()\n : (resource as any).url;\n const method = (config && config.method) || (resource as any).method || \"GET\";\n\n if (ctx.isTargetUrl(requestUrl)) {\n const upperMethod = (method || \"GET\").toUpperCase();\n\n // If we need the body from a Request, clone BEFORE calling the original fetch\n let prepareBodyPromise: Promise<any> = Promise.resolve(undefined);\n if (upperMethod === \"POST\") {\n if (config && Object.prototype.hasOwnProperty.call(config, \"body\")) {\n prepareBodyPromise = Promise.resolve(config.body);\n } else if (typeof Request !== \"undefined\" && resource instanceof Request) {\n try {\n const clonedReq = resource.clone();\n prepareBodyPromise = clonedReq.blob().catch(() => undefined);\n } catch {\n prepareBodyPromise = Promise.resolve(undefined);\n }\n }\n }\n\n // First send original request to Google Analytics\n const originalPromise = originalFetch.apply(this, arguments as any);\n\n // Then send duplicate\n const duplicateUrl = ctx.buildDuplicateUrl(requestUrl);\n\n if (upperMethod === \"GET\") {\n originalFetch(duplicateUrl, { method: \"GET\", keepalive: true }).catch((error) => {\n if (ctx.debug) console.error(\"gtm interceptor: error duplicating GET fetch:\", error);\n });\n } else if (upperMethod === \"POST\") {\n prepareBodyPromise.then((dupBody) => {\n originalFetch(duplicateUrl, { method: \"POST\", body: dupBody, keepalive: true }).catch(\n (error) => {\n if (ctx.debug)\n console.error(\"gtm interceptor: error duplicating POST fetch:\", error);\n },\n );\n });\n }\n\n return originalPromise;\n }\n\n return originalFetch.apply(this, arguments as any);\n };\n }\n }\n\n class XhrInterceptor implements NetworkInterceptor {\n install(ctx: InterceptorContext): void {\n const originalXHROpen = XMLHttpRequest.prototype.open;\n const originalXHRSend = XMLHttpRequest.prototype.send;\n\n XMLHttpRequest.prototype.open = function (this: any, method: string, url: string | URL) {\n this._requestMethod = method;\n this._requestUrl = url;\n return originalXHROpen.apply(this, arguments as any);\n };\n\n XMLHttpRequest.prototype.send = function (\n this: any,\n body?: Document | XMLHttpRequestBodyInit | null,\n ) {\n if (this._requestUrl && ctx.isTargetUrl(this._requestUrl)) {\n // First send original request to Google Analytics\n const originalResult = originalXHRSend.apply(this, arguments as any);\n\n // Then send duplicate to our endpoint mimicking method and payload\n try {\n const method = (this._requestMethod || \"GET\").toUpperCase();\n const duplicateUrl = ctx.buildDuplicateUrl(this._requestUrl);\n\n if (method === \"GET\") {\n fetch(duplicateUrl, { method: \"GET\", keepalive: true }).catch((error) => {\n if (ctx.debug) console.error(\"gtm interceptor: error duplicating GET xhr:\", error);\n });\n } else if (method === \"POST\") {\n fetch(duplicateUrl, { method: \"POST\", body: body as any, keepalive: true }).catch(\n (error) => {\n if (ctx.debug)\n console.error(\"gtm interceptor: error duplicating POST xhr:\", error);\n },\n );\n }\n } catch (dupErr) {\n if (ctx.debug) console.error(\"gtm interceptor: xhr duplication failed:\", dupErr);\n }\n return originalResult;\n }\n return originalXHRSend.apply(this, arguments as any);\n };\n }\n }\n\n class BeaconInterceptor implements NetworkInterceptor {\n install(ctx: InterceptorContext): void {\n if (!navigator.sendBeacon) return;\n\n const originalSendBeacon = navigator.sendBeacon;\n navigator.sendBeacon = function (\n this: any,\n url: string | URL,\n data?: BodyInit | null,\n ): boolean {\n if (ctx.isTargetUrl(url as string)) {\n const originalResult = originalSendBeacon.apply(this, arguments as any);\n try {\n originalSendBeacon.call(navigator, ctx.buildDuplicateUrl(url as string), data);\n } catch (e) {\n if (ctx.debug) console.error(\"gtm interceptor: error duplicating sendBeacon:\", e);\n }\n return originalResult;\n }\n return originalSendBeacon.apply(this, arguments as any);\n };\n }\n }\n\n class ScriptInterceptor implements NetworkInterceptor {\n install(ctx: InterceptorContext): void {\n try {\n const scriptSrcDescriptor = Object.getOwnPropertyDescriptor(\n HTMLScriptElement.prototype,\n \"src\",\n );\n const originalScriptSrcSetter = scriptSrcDescriptor && scriptSrcDescriptor.set;\n const originalScriptSrcGetter = scriptSrcDescriptor && scriptSrcDescriptor.get;\n const originalScriptSetAttribute = HTMLScriptElement.prototype.setAttribute;\n\n const duplicateIfGA4Url = (urlString: string) => {\n try {\n if (!ctx.isTargetUrl(urlString)) return;\n fetch(ctx.buildDuplicateUrl(urlString), { method: \"GET\", keepalive: true }).catch(\n (error) => {\n if (ctx.debug)\n console.error(\"gtm interceptor: error duplicating script GET:\", error);\n },\n );\n } catch {\n // Intentionally empty\n }\n };\n\n if (originalScriptSrcSetter && originalScriptSrcGetter) {\n const setter = originalScriptSrcSetter;\n const getter = originalScriptSrcGetter;\n Object.defineProperty(HTMLScriptElement.prototype, \"src\", {\n configurable: true,\n enumerable: true,\n get: function (this: any) {\n return getter.call(this);\n },\n set: function (this: any, value: string) {\n try {\n const last = this.__ga4LastSrcDuplicated;\n if (value && value !== last) {\n duplicateIfGA4Url(String(value));\n this.__ga4LastSrcDuplicated = String(value);\n }\n const self = this;\n const onloadOnce = function () {\n try {\n const finalUrl = self.src;\n if (finalUrl && finalUrl !== self.__ga4LastSrcDuplicated) {\n duplicateIfGA4Url(finalUrl);\n self.__ga4LastSrcDuplicated = finalUrl;\n }\n } catch {}\n self.removeEventListener(\"load\", onloadOnce);\n };\n this.addEventListener(\"load\", onloadOnce);\n } catch {}\n setter.call(this, value);\n },\n });\n }\n\n HTMLScriptElement.prototype.setAttribute = function (\n this: any,\n name: string,\n value: string,\n ) {\n try {\n if (String(name).toLowerCase() === \"src\") {\n const v = String(value);\n const last = this.__ga4LastSrcDuplicated;\n if (v && v !== last) {\n duplicateIfGA4Url(v);\n this.__ga4LastSrcDuplicated = v;\n }\n const selfAttr = this;\n const onloadOnceAttr = function () {\n try {\n const finalUrlAttr = selfAttr.src;\n if (finalUrlAttr && finalUrlAttr !== selfAttr.__ga4LastSrcDuplicated) {\n duplicateIfGA4Url(finalUrlAttr);\n selfAttr.__ga4LastSrcDuplicated = finalUrlAttr;\n }\n } catch {}\n selfAttr.removeEventListener(\"load\", onloadOnceAttr);\n };\n this.addEventListener(\"load\", onloadOnceAttr);\n }\n } catch {\n // Intentionally empty\n }\n return originalScriptSetAttribute.apply(this, arguments as any);\n };\n } catch {}\n }\n }\n\n if ((window as any).__ga4DuplicatorInitialized) {\n if (options.debug) console.warn(\"GA4 Duplicator: already initialized.\");\n return;\n }\n\n const destinations: GA4Destination[] = [];\n if (options.destinations && Array.isArray(options.destinations)) {\n for (let i = 0; i < options.destinations.length; i++) {\n destinations.push(options.destinations[i]);\n }\n }\n\n if (options.server_container_url) {\n destinations.push({\n measurement_id: \"*\",\n server_container_url: options.server_container_url,\n });\n }\n\n if (destinations.length === 0) {\n console.error(\"GA4 Duplicator: either server_container_url or destinations array is required\");\n return;\n }\n\n function normalizePath(p: string): string {\n p = String(p || \"\");\n p = p.replace(/\\/+$/, \"\");\n return p === \"\" ? \"/\" : p;\n }\n\n function matchesId(pattern: string, id: string): boolean {\n if (!pattern || pattern === \"*\") return true;\n try {\n const regexStr = pattern.replace(/[.+^${}()|[\\]\\\\]/g, \"\\\\$&\").replace(/\\*/g, \".*\");\n return new RegExp(\"^\" + regexStr + \"$\", \"i\").test(id);\n } catch {\n return pattern.toLowerCase() === id.toLowerCase();\n }\n }\n\n function getMeasurementId(url: string): string {\n try {\n const parsed = new URL(url, location.href);\n return parsed.searchParams.get(\"tid\") || parsed.searchParams.get(\"id\") || \"\";\n } catch {\n const match = url.match(/[?&](?:tid|id)=([^&?#]+)/);\n return match ? decodeURIComponent(match[1]) : \"\";\n }\n }\n\n function getDestinationForId(id: string): GA4Destination | null {\n for (let i = 0; i < destinations.length; i++) {\n if (matchesId(destinations[i].measurement_id, id)) {\n return destinations[i];\n }\n }\n return null;\n }\n\n function getDuplicateEndpointUrl(dest: GA4Destination): URL {\n const trackingURL = String(dest.server_container_url || \"\").trim();\n const u = new URL(trackingURL, location.href);\n u.search = \"\";\n u.hash = \"\";\n return u;\n }\n\n function isTargetUrl(url: string | null | undefined): boolean {\n if (!url || typeof url !== \"string\") return false;\n try {\n const parsed = new URL(url, location.href);\n\n for (let i = 0; i < destinations.length; i++) {\n const duplicateTarget = getDuplicateEndpointUrl(destinations[i]);\n if (\n parsed.origin === duplicateTarget.origin &&\n normalizePath(parsed.pathname) === normalizePath(duplicateTarget.pathname)\n ) {\n return false;\n }\n }\n\n const params = parsed.searchParams;\n const hasGtm = params.has(\"gtm\");\n const hasTagExp = params.has(\"tag_exp\");\n const measurementId = params.get(\"tid\") || params.get(\"id\") || \"\";\n const isMeasurementIdGA4 = /^G-[A-Z0-9]+$/i.test(measurementId);\n\n return hasGtm && hasTagExp && isMeasurementIdGA4;\n } catch {\n if (typeof url === \"string\") {\n for (let j = 0; j < destinations.length; j++) {\n try {\n const target = getDuplicateEndpointUrl(destinations[j]);\n const targetNoQuery = target.origin + target.pathname;\n if (url.indexOf(targetNoQuery) !== -1) return false;\n } catch {\n // Intentionally empty\n }\n }\n\n const hasGtmFallback = url.indexOf(\"gtm=\") !== -1;\n const hasTagExpFallback = url.indexOf(\"tag_exp=\") !== -1;\n const idMatch = url.match(/[?&](?:tid|id)=G-[A-Za-z0-9]+/);\n return !!(hasGtmFallback && hasTagExpFallback && idMatch);\n }\n return false;\n }\n }\n\n function buildDuplicateUrl(originalUrl: string): string {\n const id = getMeasurementId(originalUrl);\n const dest = getDestinationForId(id);\n if (!dest) return \"\";\n\n const dst = getDuplicateEndpointUrl(dest);\n try {\n const src = new URL(originalUrl, location.href);\n dst.search = src.search;\n dst.searchParams.set(\"_dtv\", version);\n dst.searchParams.set(\"_dtn\", \"gd\");\n } catch {}\n return dst.toString();\n }\n\n const context: InterceptorContext = {\n debug: !!options.debug,\n isTargetUrl,\n buildDuplicateUrl,\n };\n\n const interceptors: NetworkInterceptor[] = [\n new FetchInterceptor(),\n new XhrInterceptor(),\n new BeaconInterceptor(),\n new ScriptInterceptor(),\n ];\n\n for (let i = 0; i < interceptors.length; i++) {\n try {\n interceptors[i].install(context);\n } catch (e) {\n if (options.debug) console.error(\"GA4 Duplicator: failed to install interceptor\", e);\n }\n }\n\n (window as any).__ga4DuplicatorInitialized = true;\n};\n"],
|
|
5
|
-
"mappings": ";mBAaO,IAAMA,EACiD,
|
|
6
|
-
"names": ["version", "options", "FetchInterceptor", "ctx", "originalFetch", "resource", "config", "requestUrl", "method", "upperMethod", "prepareBodyPromise", "e", "originalPromise", "duplicateUrl", "error", "dupBody", "XhrInterceptor", "originalXHROpen", "originalXHRSend", "url", "body", "originalResult", "dupErr", "BeaconInterceptor", "originalSendBeacon", "data", "ScriptInterceptor", "scriptSrcDescriptor", "originalScriptSrcSetter", "originalScriptSrcGetter", "originalScriptSetAttribute", "duplicateIfGA4Url", "urlString", "setter", "getter", "value", "last", "self", "onloadOnce", "finalUrl", "name", "v", "selfAttr", "onloadOnceAttr", "finalUrlAttr", "destinations", "
|
|
4
|
+
"sourcesContent": ["/**\n * Package version identifier.\n * This value is replaced at build time via esbuild define.\n */\ndeclare const __D8A_VERSION__: string;\n\nfunction devVersionUtc(): string {\n const now = new Date();\n const year = String(now.getUTCFullYear()).slice(-2);\n const month = String(now.getUTCMonth() + 1).padStart(2, \"0\");\n return `dev-${year}-${month}`;\n}\n\nexport const version: string =\n typeof __D8A_VERSION__ !== \"undefined\" && __D8A_VERSION__ ? __D8A_VERSION__ : devVersionUtc();\n", "/**\n * GA4 Duplicator - Intercepts GA4 collect calls and sends duplicates to D8A.\n */\n\nimport { version } from \"./version\";\n\ninterface GA4Destination {\n measurement_id: string;\n server_container_url: string;\n convert_to_get?: boolean;\n}\n\ninterface GA4DuplicatorOptions {\n server_container_url?: string;\n destinations?: GA4Destination[];\n debug?: boolean;\n convert_to_get?: boolean;\n}\n\n(window as any).createGA4Duplicator = function (options: GA4DuplicatorOptions) {\n /**\n * Shared logic and configuration for interceptors.\n */\n interface InterceptorContext {\n debug: boolean;\n isTargetUrl(url: string | null | undefined): boolean;\n buildDuplicateUrl(url: string): string;\n getConvertToGet(url: string): boolean;\n }\n\n /**\n * Base interface for monkey-patching implementations.\n */\n interface NetworkInterceptor {\n install(context: InterceptorContext): void;\n }\n\n class FetchInterceptor implements NetworkInterceptor {\n install(ctx: InterceptorContext): void {\n const originalFetch = window.fetch;\n window.fetch = function (\n this: any,\n resource: RequestInfo | URL,\n config?: RequestInit,\n ): Promise<Response> {\n const requestUrl =\n typeof resource === \"string\"\n ? resource\n : resource instanceof URL\n ? resource.toString()\n : (resource as any).url;\n const method = (config && config.method) || (resource as any).method || \"GET\";\n\n if (ctx.isTargetUrl(requestUrl)) {\n const upperMethod = (method || \"GET\").toUpperCase();\n\n // If we need the body from a Request, clone BEFORE calling the original fetch\n let prepareBodyPromise: Promise<any> = Promise.resolve(undefined);\n if (upperMethod === \"POST\") {\n if (config && Object.prototype.hasOwnProperty.call(config, \"body\")) {\n prepareBodyPromise = Promise.resolve(config.body);\n } else if (typeof Request !== \"undefined\" && resource instanceof Request) {\n try {\n const clonedReq = resource.clone();\n prepareBodyPromise = clonedReq.blob().catch(() => undefined);\n } catch {\n prepareBodyPromise = Promise.resolve(undefined);\n }\n }\n }\n\n // First send original request to Google Analytics\n const originalPromise = originalFetch.apply(this, arguments as any);\n\n // Then send duplicate\n const duplicateUrl = ctx.buildDuplicateUrl(requestUrl);\n const convertToGet = ctx.getConvertToGet(requestUrl);\n\n if (upperMethod === \"GET\") {\n originalFetch(duplicateUrl, { method: \"GET\", keepalive: true }).catch((error) => {\n if (ctx.debug) console.error(\"gtm interceptor: error duplicating GET fetch:\", error);\n });\n } else if (upperMethod === \"POST\") {\n prepareBodyPromise.then((dupBody) => {\n if (convertToGet) {\n // Convert POST to GET: split body into lines and send each as a separate GET request\n let bodyStr = \"\";\n if (typeof dupBody === \"string\") {\n bodyStr = dupBody;\n } else if (dupBody instanceof Blob) {\n // For blob, we can't easily convert synchronously, so fall back to POST\n originalFetch(duplicateUrl, {\n method: \"POST\",\n body: dupBody,\n keepalive: true,\n }).catch((error) => {\n if (ctx.debug)\n console.error(\n \"gtm interceptor: error duplicating POST fetch (convert_to_get with Blob):\",\n error,\n );\n });\n return;\n }\n\n const lines = bodyStr.split(\"\\n\");\n let sentAny = false;\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i].trim();\n if (line) {\n const mergedUrl = ctx.buildDuplicateUrl(requestUrl);\n const urlWithMergedLine = mergeBodyLineWithUrl(mergedUrl, line);\n originalFetch(urlWithMergedLine, { method: \"GET\", keepalive: true }).catch(\n (error) => {\n if (ctx.debug)\n console.error(\n \"gtm interceptor: error duplicating GET fetch (from convert_to_get):\",\n error,\n );\n },\n );\n sentAny = true;\n }\n }\n\n // If body is empty or all lines were empty, send one GET with just URL params\n if (!sentAny) {\n originalFetch(duplicateUrl, { method: \"GET\", keepalive: true }).catch((error) => {\n if (ctx.debug)\n console.error(\n \"gtm interceptor: error duplicating GET fetch (empty body convert_to_get):\",\n error,\n );\n });\n }\n } else {\n // Original POST duplication\n originalFetch(duplicateUrl, {\n method: \"POST\",\n body: dupBody,\n keepalive: true,\n }).catch((error) => {\n if (ctx.debug)\n console.error(\"gtm interceptor: error duplicating POST fetch:\", error);\n });\n }\n });\n }\n\n return originalPromise;\n }\n\n return originalFetch.apply(this, arguments as any);\n };\n }\n }\n\n class XhrInterceptor implements NetworkInterceptor {\n install(ctx: InterceptorContext): void {\n const originalXHROpen = XMLHttpRequest.prototype.open;\n const originalXHRSend = XMLHttpRequest.prototype.send;\n\n XMLHttpRequest.prototype.open = function (this: any, method: string, url: string | URL) {\n this._requestMethod = method;\n this._requestUrl = url;\n return originalXHROpen.apply(this, arguments as any);\n };\n\n XMLHttpRequest.prototype.send = function (\n this: any,\n body?: Document | XMLHttpRequestBodyInit | null,\n ) {\n if (this._requestUrl && ctx.isTargetUrl(this._requestUrl)) {\n // First send original request to Google Analytics\n const originalResult = originalXHRSend.apply(this, arguments as any);\n\n // Then send duplicate to our endpoint mimicking method and payload\n try {\n const method = (this._requestMethod || \"GET\").toUpperCase();\n const duplicateUrl = ctx.buildDuplicateUrl(this._requestUrl);\n const convertToGet = ctx.getConvertToGet(this._requestUrl);\n\n if (method === \"GET\") {\n fetch(duplicateUrl, { method: \"GET\", keepalive: true }).catch((error) => {\n if (ctx.debug) console.error(\"gtm interceptor: error duplicating GET xhr:\", error);\n });\n } else if (method === \"POST\") {\n if (convertToGet) {\n // Convert POST to GET: split body into lines and send each as a separate GET request\n let bodyStr = \"\";\n if (typeof body === \"string\") {\n bodyStr = body;\n } else if (body && typeof body === \"object\") {\n // Try to convert Document or other types to string\n try {\n bodyStr = String(body);\n } catch {\n bodyStr = \"\";\n }\n }\n\n const lines = bodyStr.split(\"\\n\");\n let sentAny = false;\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i].trim();\n if (line) {\n const mergedUrl = ctx.buildDuplicateUrl(this._requestUrl);\n const urlWithMergedLine = mergeBodyLineWithUrl(mergedUrl, line);\n fetch(urlWithMergedLine, { method: \"GET\", keepalive: true }).catch((error) => {\n if (ctx.debug)\n console.error(\n \"gtm interceptor: error duplicating GET xhr (from convert_to_get):\",\n error,\n );\n });\n sentAny = true;\n }\n }\n\n // If body is empty or all lines were empty, send one GET with just URL params\n if (!sentAny) {\n fetch(duplicateUrl, { method: \"GET\", keepalive: true }).catch((error) => {\n if (ctx.debug)\n console.error(\n \"gtm interceptor: error duplicating GET xhr (empty body convert_to_get):\",\n error,\n );\n });\n }\n } else {\n // Original POST duplication\n fetch(duplicateUrl, { method: \"POST\", body: body as any, keepalive: true }).catch(\n (error) => {\n if (ctx.debug)\n console.error(\"gtm interceptor: error duplicating POST xhr:\", error);\n },\n );\n }\n }\n } catch (dupErr) {\n if (ctx.debug) console.error(\"gtm interceptor: xhr duplication failed:\", dupErr);\n }\n return originalResult;\n }\n return originalXHRSend.apply(this, arguments as any);\n };\n }\n }\n\n class BeaconInterceptor implements NetworkInterceptor {\n install(ctx: InterceptorContext): void {\n if (!navigator.sendBeacon) return;\n\n const originalSendBeacon = navigator.sendBeacon;\n navigator.sendBeacon = function (\n this: any,\n url: string | URL,\n data?: BodyInit | null,\n ): boolean {\n if (ctx.isTargetUrl(url as string)) {\n const originalResult = originalSendBeacon.apply(this, arguments as any);\n try {\n const duplicateUrl = ctx.buildDuplicateUrl(url as string);\n const convertToGet = ctx.getConvertToGet(url as string);\n\n if (convertToGet) {\n // Convert sendBeacon POST to GET: split body into lines and send each as a separate GET request\n let bodyStr = \"\";\n if (typeof data === \"string\") {\n bodyStr = data;\n } else if (data && typeof data === \"object\") {\n try {\n bodyStr = String(data);\n } catch {\n bodyStr = \"\";\n }\n }\n\n const lines = bodyStr.split(\"\\n\");\n let sentAny = false;\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i].trim();\n if (line) {\n const mergedUrl = ctx.buildDuplicateUrl(url as string);\n const urlWithMergedLine = mergeBodyLineWithUrl(mergedUrl, line);\n fetch(urlWithMergedLine, { method: \"GET\", keepalive: true }).catch((error) => {\n if (ctx.debug)\n console.error(\n \"gtm interceptor: error duplicating GET beacon (from convert_to_get):\",\n error,\n );\n });\n sentAny = true;\n }\n }\n\n // If body is empty or all lines were empty, send one GET with just URL params\n if (!sentAny) {\n fetch(duplicateUrl, { method: \"GET\", keepalive: true }).catch((error) => {\n if (ctx.debug)\n console.error(\n \"gtm interceptor: error duplicating GET beacon (empty body convert_to_get):\",\n error,\n );\n });\n }\n } else {\n // Original sendBeacon duplication\n originalSendBeacon.call(navigator, duplicateUrl, data);\n }\n } catch (e) {\n if (ctx.debug) console.error(\"gtm interceptor: error duplicating sendBeacon:\", e);\n }\n return originalResult;\n }\n return originalSendBeacon.apply(this, arguments as any);\n };\n }\n }\n\n class ScriptInterceptor implements NetworkInterceptor {\n install(ctx: InterceptorContext): void {\n try {\n const scriptSrcDescriptor = Object.getOwnPropertyDescriptor(\n HTMLScriptElement.prototype,\n \"src\",\n );\n const originalScriptSrcSetter = scriptSrcDescriptor && scriptSrcDescriptor.set;\n const originalScriptSrcGetter = scriptSrcDescriptor && scriptSrcDescriptor.get;\n const originalScriptSetAttribute = HTMLScriptElement.prototype.setAttribute;\n\n const duplicateIfGA4Url = (urlString: string) => {\n try {\n if (!ctx.isTargetUrl(urlString)) return;\n fetch(ctx.buildDuplicateUrl(urlString), { method: \"GET\", keepalive: true }).catch(\n (error) => {\n if (ctx.debug)\n console.error(\"gtm interceptor: error duplicating script GET:\", error);\n },\n );\n } catch {\n // Intentionally empty\n }\n };\n\n if (originalScriptSrcSetter && originalScriptSrcGetter) {\n const setter = originalScriptSrcSetter;\n const getter = originalScriptSrcGetter;\n Object.defineProperty(HTMLScriptElement.prototype, \"src\", {\n configurable: true,\n enumerable: true,\n get: function (this: any) {\n return getter.call(this);\n },\n set: function (this: any, value: string) {\n try {\n const last = this.__ga4LastSrcDuplicated;\n if (value && value !== last) {\n duplicateIfGA4Url(String(value));\n this.__ga4LastSrcDuplicated = String(value);\n }\n const self = this;\n const onloadOnce = function () {\n try {\n const finalUrl = self.src;\n if (finalUrl && finalUrl !== self.__ga4LastSrcDuplicated) {\n duplicateIfGA4Url(finalUrl);\n self.__ga4LastSrcDuplicated = finalUrl;\n }\n } catch {}\n self.removeEventListener(\"load\", onloadOnce);\n };\n this.addEventListener(\"load\", onloadOnce);\n } catch {}\n setter.call(this, value);\n },\n });\n }\n\n HTMLScriptElement.prototype.setAttribute = function (\n this: any,\n name: string,\n value: string,\n ) {\n try {\n if (String(name).toLowerCase() === \"src\") {\n const v = String(value);\n const last = this.__ga4LastSrcDuplicated;\n if (v && v !== last) {\n duplicateIfGA4Url(v);\n this.__ga4LastSrcDuplicated = v;\n }\n const selfAttr = this;\n const onloadOnceAttr = function () {\n try {\n const finalUrlAttr = selfAttr.src;\n if (finalUrlAttr && finalUrlAttr !== selfAttr.__ga4LastSrcDuplicated) {\n duplicateIfGA4Url(finalUrlAttr);\n selfAttr.__ga4LastSrcDuplicated = finalUrlAttr;\n }\n } catch {}\n selfAttr.removeEventListener(\"load\", onloadOnceAttr);\n };\n this.addEventListener(\"load\", onloadOnceAttr);\n }\n } catch {\n // Intentionally empty\n }\n return originalScriptSetAttribute.apply(this, arguments as any);\n };\n } catch {}\n }\n }\n\n if ((window as any).__ga4DuplicatorInitialized) {\n if (options.debug) console.warn(\"GA4 Duplicator: already initialized.\");\n return;\n }\n\n const destinations: GA4Destination[] = [];\n if (options.destinations && Array.isArray(options.destinations)) {\n for (let i = 0; i < options.destinations.length; i++) {\n const dest = options.destinations[i];\n destinations.push({\n measurement_id: dest.measurement_id,\n server_container_url: dest.server_container_url,\n convert_to_get:\n dest.convert_to_get !== undefined ? dest.convert_to_get : options.convert_to_get,\n });\n }\n }\n\n if (options.server_container_url) {\n destinations.push({\n measurement_id: \"*\",\n server_container_url: options.server_container_url,\n convert_to_get: options.convert_to_get,\n });\n }\n\n if (destinations.length === 0) {\n console.error(\"GA4 Duplicator: either server_container_url or destinations array is required\");\n return;\n }\n\n function normalizePath(p: string): string {\n p = String(p || \"\");\n p = p.replace(/\\/+$/, \"\");\n return p === \"\" ? \"/\" : p;\n }\n\n function matchesId(pattern: string, id: string): boolean {\n if (!pattern || pattern === \"*\") return true;\n try {\n const regexStr = pattern.replace(/[.+^${}()|[\\]\\\\]/g, \"\\\\$&\").replace(/\\*/g, \".*\");\n return new RegExp(\"^\" + regexStr + \"$\", \"i\").test(id);\n } catch {\n return pattern.toLowerCase() === id.toLowerCase();\n }\n }\n\n function getMeasurementId(url: string): string {\n try {\n const parsed = new URL(url, location.href);\n return parsed.searchParams.get(\"tid\") || parsed.searchParams.get(\"id\") || \"\";\n } catch {\n const match = url.match(/[?&](?:tid|id)=([^&?#]+)/);\n return match ? decodeURIComponent(match[1]) : \"\";\n }\n }\n\n function getDestinationForId(id: string): GA4Destination | null {\n for (let i = 0; i < destinations.length; i++) {\n if (matchesId(destinations[i].measurement_id, id)) {\n return destinations[i];\n }\n }\n return null;\n }\n\n function mergeBodyLineWithUrl(originalUrl: string, bodyLine: string): string {\n try {\n const url = new URL(originalUrl, location.href);\n const lineParams = new URLSearchParams(bodyLine);\n\n // Line parameters override URL parameters\n for (const [key] of lineParams.entries()) {\n url.searchParams.delete(key);\n }\n for (const [key, value] of lineParams.entries()) {\n url.searchParams.append(key, value);\n }\n\n return url.toString();\n } catch {\n // Fallback: if URL parsing fails, try string manipulation\n const urlWithoutQuery = originalUrl.split(\"?\")[0];\n const originalParams = originalUrl.match(/\\?(.*)/) ? originalUrl.match(/\\?(.*)/)![1] : \"\";\n const merged = originalParams + (originalParams && bodyLine ? \"&\" : \"\") + bodyLine;\n return urlWithoutQuery + (merged ? \"?\" + merged : \"\");\n }\n }\n\n function getDuplicateEndpointUrl(dest: GA4Destination): URL {\n const trackingURL = String(dest.server_container_url || \"\").trim();\n const u = new URL(trackingURL, location.href);\n u.search = \"\";\n u.hash = \"\";\n return u;\n }\n\n function isTargetUrl(url: string | null | undefined): boolean {\n if (!url || typeof url !== \"string\") return false;\n try {\n const parsed = new URL(url, location.href);\n\n for (let i = 0; i < destinations.length; i++) {\n const duplicateTarget = getDuplicateEndpointUrl(destinations[i]);\n if (\n parsed.origin === duplicateTarget.origin &&\n normalizePath(parsed.pathname) === normalizePath(duplicateTarget.pathname)\n ) {\n return false;\n }\n }\n\n const params = parsed.searchParams;\n const hasGtm = params.has(\"gtm\");\n const hasTagExp = params.has(\"tag_exp\");\n const measurementId = params.get(\"tid\") || params.get(\"id\") || \"\";\n const isMeasurementIdGA4 = /^G-[A-Z0-9]+$/i.test(measurementId);\n\n return hasGtm && hasTagExp && isMeasurementIdGA4;\n } catch {\n if (typeof url === \"string\") {\n for (let j = 0; j < destinations.length; j++) {\n try {\n const target = getDuplicateEndpointUrl(destinations[j]);\n const targetNoQuery = target.origin + target.pathname;\n if (url.indexOf(targetNoQuery) !== -1) return false;\n } catch {\n // Intentionally empty\n }\n }\n\n const hasGtmFallback = url.indexOf(\"gtm=\") !== -1;\n const hasTagExpFallback = url.indexOf(\"tag_exp=\") !== -1;\n const idMatch = url.match(/[?&](?:tid|id)=G-[A-Za-z0-9]+/);\n return !!(hasGtmFallback && hasTagExpFallback && idMatch);\n }\n return false;\n }\n }\n\n function buildDuplicateUrl(originalUrl: string): string {\n const id = getMeasurementId(originalUrl);\n const dest = getDestinationForId(id);\n if (!dest) return \"\";\n\n const dst = getDuplicateEndpointUrl(dest);\n try {\n const src = new URL(originalUrl, location.href);\n dst.search = src.search;\n dst.searchParams.set(\"_dtv\", version);\n dst.searchParams.set(\"_dtn\", \"gd\");\n } catch {}\n return dst.toString();\n }\n\n function getConvertToGet(url: string): boolean {\n const id = getMeasurementId(url);\n const dest = getDestinationForId(id);\n return dest ? !!dest.convert_to_get : false;\n }\n\n const context: InterceptorContext = {\n debug: !!options.debug,\n isTargetUrl,\n buildDuplicateUrl,\n getConvertToGet,\n };\n\n const interceptors: NetworkInterceptor[] = [\n new FetchInterceptor(),\n new XhrInterceptor(),\n new BeaconInterceptor(),\n new ScriptInterceptor(),\n ];\n\n for (let i = 0; i < interceptors.length; i++) {\n try {\n interceptors[i].install(context);\n } catch (e) {\n if (options.debug) console.error(\"GA4 Duplicator: failed to install interceptor\", e);\n }\n }\n\n (window as any).__ga4DuplicatorInitialized = true;\n};\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["version", "options", "FetchInterceptor", "ctx", "originalFetch", "resource", "config", "requestUrl", "method", "upperMethod", "prepareBodyPromise", "e", "originalPromise", "duplicateUrl", "convertToGet", "error", "dupBody", "bodyStr", "lines", "sentAny", "i", "line", "mergedUrl", "urlWithMergedLine", "mergeBodyLineWithUrl", "XhrInterceptor", "originalXHROpen", "originalXHRSend", "url", "body", "originalResult", "dupErr", "BeaconInterceptor", "originalSendBeacon", "data", "ScriptInterceptor", "scriptSrcDescriptor", "originalScriptSrcSetter", "originalScriptSrcGetter", "originalScriptSetAttribute", "duplicateIfGA4Url", "urlString", "setter", "getter", "value", "last", "self", "onloadOnce", "finalUrl", "name", "v", "selfAttr", "onloadOnceAttr", "finalUrlAttr", "destinations", "dest", "normalizePath", "p", "matchesId", "pattern", "id", "regexStr", "getMeasurementId", "parsed", "match", "getDestinationForId", "originalUrl", "bodyLine", "lineParams", "key", "urlWithoutQuery", "originalParams", "merged", "getDuplicateEndpointUrl", "trackingURL", "u", "isTargetUrl", "duplicateTarget", "params", "hasGtm", "hasTagExp", "measurementId", "isMeasurementIdGA4", "j", "target", "targetNoQuery", "hasGtmFallback", "hasTagExpFallback", "idMatch", "buildDuplicateUrl", "dst", "src", "version", "getConvertToGet", "context", "interceptors"]
|
|
7
7
|
}
|
package/package.json
CHANGED
package/src.hash
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
6b6786210e256dbaa47f415b2c30fe87022faef5818f8cc3f4e41728fc3dc123 -
|