@d8a-tech/gd 0.32.1 → 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 CHANGED
@@ -1,8 +1,8 @@
1
- /* ga4-duplicator - built 2026-02-12T21:35:49.861Z */
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.32.1" ? "v0.32.1" : devVersionUtc();
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
- originalFetch(duplicateUrl, { method: "POST", body: dupBody, keepalive: true }).catch(
39
- (error) => {
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
- fetch(duplicateUrl, { method: "POST", body, keepalive: true }).catch(
73
- (error) => {
74
- if (ctx.debug)
75
- console.error("gtm interceptor: error duplicating POST xhr:", error);
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
- originalSendBeacon.call(navigator, ctx.buildDuplicateUrl(url), data);
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
- destinations.push(options.destinations[i]);
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-12T21:35:49.861Z */
2
- "use strict";(()=>{var S="v0.32.1";window.createGA4Duplicator=function(g){class b{install(e){let r=window.fetch;window.fetch=function(n,i){let c=typeof n=="string"?n:n instanceof URL?n.toString():n.url,s=i&&i.method||n.method||"GET";if(e.isTargetUrl(c)){let o=(s||"GET").toUpperCase(),a=Promise.resolve(void 0);if(o==="POST"){if(i&&Object.prototype.hasOwnProperty.call(i,"body"))a=Promise.resolve(i.body);else if(typeof Request!="undefined"&&n instanceof Request)try{a=n.clone().blob().catch(()=>{})}catch(l){a=Promise.resolve(void 0)}}let u=r.apply(this,arguments),h=e.buildDuplicateUrl(c);return o==="GET"?r(h,{method:"GET",keepalive:!0}).catch(l=>{e.debug&&console.error("gtm interceptor: error duplicating GET fetch:",l)}):o==="POST"&&a.then(l=>{r(h,{method:"POST",body:l,keepalive:!0}).catch(f=>{e.debug&&console.error("gtm interceptor: error duplicating POST fetch:",f)})}),u}return r.apply(this,arguments)}}}class U{install(e){let r=XMLHttpRequest.prototype.open,n=XMLHttpRequest.prototype.send;XMLHttpRequest.prototype.open=function(i,c){return this._requestMethod=i,this._requestUrl=c,r.apply(this,arguments)},XMLHttpRequest.prototype.send=function(i){if(this._requestUrl&&e.isTargetUrl(this._requestUrl)){let c=n.apply(this,arguments);try{let s=(this._requestMethod||"GET").toUpperCase(),o=e.buildDuplicateUrl(this._requestUrl);s==="GET"?fetch(o,{method:"GET",keepalive:!0}).catch(a=>{e.debug&&console.error("gtm interceptor: error duplicating GET xhr:",a)}):s==="POST"&&fetch(o,{method:"POST",body:i,keepalive:!0}).catch(a=>{e.debug&&console.error("gtm interceptor: error duplicating POST xhr:",a)})}catch(s){e.debug&&console.error("gtm interceptor: xhr duplication failed:",s)}return c}return n.apply(this,arguments)}}}class D{install(e){if(!navigator.sendBeacon)return;let r=navigator.sendBeacon;navigator.sendBeacon=function(n,i){if(e.isTargetUrl(n)){let c=r.apply(this,arguments);try{r.call(navigator,e.buildDuplicateUrl(n),i)}catch(s){e.debug&&console.error("gtm interceptor: error duplicating sendBeacon:",s)}return c}return r.apply(this,arguments)}}}class I{install(e){try{let r=Object.getOwnPropertyDescriptor(HTMLScriptElement.prototype,"src"),n=r&&r.set,i=r&&r.get,c=HTMLScriptElement.prototype.setAttribute,s=o=>{try{if(!e.isTargetUrl(o))return;fetch(e.buildDuplicateUrl(o),{method:"GET",keepalive:!0}).catch(a=>{e.debug&&console.error("gtm interceptor: error duplicating script GET:",a)})}catch(a){}};if(n&&i){let o=n,a=i;Object.defineProperty(HTMLScriptElement.prototype,"src",{configurable:!0,enumerable:!0,get:function(){return a.call(this)},set:function(u){try{let h=this.__ga4LastSrcDuplicated;u&&u!==h&&(s(String(u)),this.__ga4LastSrcDuplicated=String(u));let l=this,f=function(){try{let d=l.src;d&&d!==l.__ga4LastSrcDuplicated&&(s(d),l.__ga4LastSrcDuplicated=d)}catch(d){}l.removeEventListener("load",f)};this.addEventListener("load",f)}catch(h){}o.call(this,u)}})}HTMLScriptElement.prototype.setAttribute=function(o,a){try{if(String(o).toLowerCase()==="src"){let u=String(a),h=this.__ga4LastSrcDuplicated;u&&u!==h&&(s(u),this.__ga4LastSrcDuplicated=u);let l=this,f=function(){try{let d=l.src;d&&d!==l.__ga4LastSrcDuplicated&&(s(d),l.__ga4LastSrcDuplicated=d)}catch(d){}l.removeEventListener("load",f)};this.addEventListener("load",f)}}catch(u){}return c.apply(this,arguments)}}catch(r){}}}if(window.__ga4DuplicatorInitialized){g.debug&&console.warn("GA4 Duplicator: already initialized.");return}let p=[];if(g.destinations&&Array.isArray(g.destinations))for(let t=0;t<g.destinations.length;t++)p.push(g.destinations[t]);if(g.server_container_url&&p.push({measurement_id:"*",server_container_url:g.server_container_url}),p.length===0){console.error("GA4 Duplicator: either server_container_url or destinations array is required");return}function y(t){return t=String(t||""),t=t.replace(/\/+$/,""),t===""?"/":t}function L(t,e){if(!t||t==="*")return!0;try{let r=t.replace(/[.+^${}()|[\]\\]/g,"\\$&").replace(/\*/g,".*");return new RegExp("^"+r+"$","i").test(e)}catch(r){return t.toLowerCase()===e.toLowerCase()}}function v(t){try{let e=new URL(t,location.href);return e.searchParams.get("tid")||e.searchParams.get("id")||""}catch(e){let r=t.match(/[?&](?:tid|id)=([^&?#]+)/);return r?decodeURIComponent(r[1]):""}}function w(t){for(let e=0;e<p.length;e++)if(L(p[e].measurement_id,t))return p[e];return null}function m(t){let e=String(t.server_container_url||"").trim(),r=new URL(e,location.href);return r.search="",r.hash="",r}function T(t){if(!t||typeof t!="string")return!1;try{let e=new URL(t,location.href);for(let o=0;o<p.length;o++){let a=m(p[o]);if(e.origin===a.origin&&y(e.pathname)===y(a.pathname))return!1}let r=e.searchParams,n=r.has("gtm"),i=r.has("tag_exp"),c=r.get("tid")||r.get("id")||"",s=/^G-[A-Z0-9]+$/i.test(c);return n&&i&&s}catch(e){if(typeof t=="string"){for(let c=0;c<p.length;c++)try{let s=m(p[c]),o=s.origin+s.pathname;if(t.indexOf(o)!==-1)return!1}catch(s){}let r=t.indexOf("gtm=")!==-1,n=t.indexOf("tag_exp=")!==-1,i=t.match(/[?&](?:tid|id)=G-[A-Za-z0-9]+/);return!!(r&&n&&i)}return!1}}function R(t){let e=v(t),r=w(e);if(!r)return"";let n=m(r);try{let i=new URL(t,location.href);n.search=i.search,n.searchParams.set("_dtv",S),n.searchParams.set("_dtn","gd")}catch(i){}return n.toString()}let G={debug:!!g.debug,isTargetUrl:T,buildDuplicateUrl:R},_=[new b,new U,new D,new I];for(let t=0;t<_.length;t++)try{_[t].install(G)}catch(e){g.debug&&console.error("GA4 Duplicator: failed to install interceptor",e)}window.__ga4DuplicatorInitialized=!0};})();
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
@@ -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,UCG7D,OAAe,oBAAsB,SAAUC,EAA+B,CAiB7E,MAAMC,CAA+C,CACnD,QAAQC,EAA+B,CACrC,IAAMC,EAAgB,OAAO,MAC7B,OAAO,MAAQ,SAEbC,EACAC,EACmB,CACnB,IAAMC,EACJ,OAAOF,GAAa,SAChBA,EACAA,aAAoB,IAClBA,EAAS,SAAS,EACjBA,EAAiB,IACpBG,EAAUF,GAAUA,EAAO,QAAYD,EAAiB,QAAU,MAExE,GAAIF,EAAI,YAAYI,CAAU,EAAG,CAC/B,IAAME,GAAeD,GAAU,OAAO,YAAY,EAG9CE,EAAmC,QAAQ,QAAQ,MAAS,EAChE,GAAID,IAAgB,QAClB,GAAIH,GAAU,OAAO,UAAU,eAAe,KAAKA,EAAQ,MAAM,EAC/DI,EAAqB,QAAQ,QAAQJ,EAAO,IAAI,UACvC,OAAO,SAAY,aAAeD,aAAoB,QAC/D,GAAI,CAEFK,EADkBL,EAAS,MAAM,EACF,KAAK,EAAE,MAAM,IAAG,EAAY,CAC7D,OAAQM,EAAA,CACND,EAAqB,QAAQ,QAAQ,MAAS,CAChD,EAKJ,IAAME,EAAkBR,EAAc,MAAM,KAAM,SAAgB,EAG5DS,EAAeV,EAAI,kBAAkBI,CAAU,EAErD,OAAIE,IAAgB,MAClBL,EAAcS,EAAc,CAAE,OAAQ,MAAO,UAAW,EAAK,CAAC,EAAE,MAAOC,GAAU,CAC3EX,EAAI,OAAO,QAAQ,MAAM,gDAAiDW,CAAK,CACrF,CAAC,EACQL,IAAgB,QACzBC,EAAmB,KAAMK,GAAY,CACnCX,EAAcS,EAAc,CAAE,OAAQ,OAAQ,KAAME,EAAS,UAAW,EAAK,CAAC,EAAE,MAC7ED,GAAU,CACLX,EAAI,OACN,QAAQ,MAAM,iDAAkDW,CAAK,CACzE,CACF,CACF,CAAC,EAGIF,CACT,CAEA,OAAOR,EAAc,MAAM,KAAM,SAAgB,CACnD,CACF,CACF,CAEA,MAAMY,CAA6C,CACjD,QAAQb,EAA+B,CACrC,IAAMc,EAAkB,eAAe,UAAU,KAC3CC,EAAkB,eAAe,UAAU,KAEjD,eAAe,UAAU,KAAO,SAAqBV,EAAgBW,EAAmB,CACtF,YAAK,eAAiBX,EACtB,KAAK,YAAcW,EACZF,EAAgB,MAAM,KAAM,SAAgB,CACrD,EAEA,eAAe,UAAU,KAAO,SAE9BG,EACA,CACA,GAAI,KAAK,aAAejB,EAAI,YAAY,KAAK,WAAW,EAAG,CAEzD,IAAMkB,EAAiBH,EAAgB,MAAM,KAAM,SAAgB,EAGnE,GAAI,CACF,IAAMV,GAAU,KAAK,gBAAkB,OAAO,YAAY,EACpDK,EAAeV,EAAI,kBAAkB,KAAK,WAAW,EAEvDK,IAAW,MACb,MAAMK,EAAc,CAAE,OAAQ,MAAO,UAAW,EAAK,CAAC,EAAE,MAAOC,GAAU,CACnEX,EAAI,OAAO,QAAQ,MAAM,8CAA+CW,CAAK,CACnF,CAAC,EACQN,IAAW,QACpB,MAAMK,EAAc,CAAE,OAAQ,OAAQ,KAAMO,EAAa,UAAW,EAAK,CAAC,EAAE,MACzEN,GAAU,CACLX,EAAI,OACN,QAAQ,MAAM,+CAAgDW,CAAK,CACvE,CACF,CAEJ,OAASQ,EAAQ,CACXnB,EAAI,OAAO,QAAQ,MAAM,2CAA4CmB,CAAM,CACjF,CACA,OAAOD,CACT,CACA,OAAOH,EAAgB,MAAM,KAAM,SAAgB,CACrD,CACF,CACF,CAEA,MAAMK,CAAgD,CACpD,QAAQpB,EAA+B,CACrC,GAAI,CAAC,UAAU,WAAY,OAE3B,IAAMqB,EAAqB,UAAU,WACrC,UAAU,WAAa,SAErBL,EACAM,EACS,CACT,GAAItB,EAAI,YAAYgB,CAAa,EAAG,CAClC,IAAME,EAAiBG,EAAmB,MAAM,KAAM,SAAgB,EACtE,GAAI,CACFA,EAAmB,KAAK,UAAWrB,EAAI,kBAAkBgB,CAAa,EAAGM,CAAI,CAC/E,OAASd,EAAG,CACNR,EAAI,OAAO,QAAQ,MAAM,iDAAkDQ,CAAC,CAClF,CACA,OAAOU,CACT,CACA,OAAOG,EAAmB,MAAM,KAAM,SAAgB,CACxD,CACF,CACF,CAEA,MAAME,CAAgD,CACpD,QAAQvB,EAA+B,CACrC,GAAI,CACF,IAAMwB,EAAsB,OAAO,yBACjC,kBAAkB,UAClB,KACF,EACMC,EAA0BD,GAAuBA,EAAoB,IACrEE,EAA0BF,GAAuBA,EAAoB,IACrEG,EAA6B,kBAAkB,UAAU,aAEzDC,EAAqBC,GAAsB,CAC/C,GAAI,CACF,GAAI,CAAC7B,EAAI,YAAY6B,CAAS,EAAG,OACjC,MAAM7B,EAAI,kBAAkB6B,CAAS,EAAG,CAAE,OAAQ,MAAO,UAAW,EAAK,CAAC,EAAE,MACzElB,GAAU,CACLX,EAAI,OACN,QAAQ,MAAM,iDAAkDW,CAAK,CACzE,CACF,CACF,OAAQH,EAAA,CAER,CACF,EAEA,GAAIiB,GAA2BC,EAAyB,CACtD,IAAMI,EAASL,EACTM,EAASL,EACf,OAAO,eAAe,kBAAkB,UAAW,MAAO,CACxD,aAAc,GACd,WAAY,GACZ,IAAK,UAAqB,CACxB,OAAOK,EAAO,KAAK,IAAI,CACzB,EACA,IAAK,SAAqBC,EAAe,CACvC,GAAI,CACF,IAAMC,EAAO,KAAK,uBACdD,GAASA,IAAUC,IACrBL,EAAkB,OAAOI,CAAK,CAAC,EAC/B,KAAK,uBAAyB,OAAOA,CAAK,GAE5C,IAAME,EAAO,KACPC,EAAa,UAAY,CAC7B,GAAI,CACF,IAAMC,EAAWF,EAAK,IAClBE,GAAYA,IAAaF,EAAK,yBAChCN,EAAkBQ,CAAQ,EAC1BF,EAAK,uBAAyBE,EAElC,OAAQ5B,EAAA,CAAC,CACT0B,EAAK,oBAAoB,OAAQC,CAAU,CAC7C,EACA,KAAK,iBAAiB,OAAQA,CAAU,CAC1C,OAAQ3B,EAAA,CAAC,CACTsB,EAAO,KAAK,KAAME,CAAK,CACzB,CACF,CAAC,CACH,CAEA,kBAAkB,UAAU,aAAe,SAEzCK,EACAL,EACA,CACA,GAAI,CACF,GAAI,OAAOK,CAAI,EAAE,YAAY,IAAM,MAAO,CACxC,IAAMC,EAAI,OAAON,CAAK,EAChBC,EAAO,KAAK,uBACdK,GAAKA,IAAML,IACbL,EAAkBU,CAAC,EACnB,KAAK,uBAAyBA,GAEhC,IAAMC,EAAW,KACXC,EAAiB,UAAY,CACjC,GAAI,CACF,IAAMC,EAAeF,EAAS,IAC1BE,GAAgBA,IAAiBF,EAAS,yBAC5CX,EAAkBa,CAAY,EAC9BF,EAAS,uBAAyBE,EAEtC,OAAQjC,EAAA,CAAC,CACT+B,EAAS,oBAAoB,OAAQC,CAAc,CACrD,EACA,KAAK,iBAAiB,OAAQA,CAAc,CAC9C,CACF,OAAQhC,EAAA,CAER,CACA,OAAOmB,EAA2B,MAAM,KAAM,SAAgB,CAChE,CACF,OAAQnB,EAAA,CAAC,CACX,CACF,CAEA,GAAK,OAAe,2BAA4B,CAC1CV,EAAQ,OAAO,QAAQ,KAAK,sCAAsC,EACtE,MACF,CAEA,IAAM4C,EAAiC,CAAC,EACxC,GAAI5C,EAAQ,cAAgB,MAAM,QAAQA,EAAQ,YAAY,EAC5D,QAAS6C,EAAI,EAAGA,EAAI7C,EAAQ,aAAa,OAAQ6C,IAC/CD,EAAa,KAAK5C,EAAQ,aAAa6C,CAAC,CAAC,EAW7C,GAPI7C,EAAQ,sBACV4C,EAAa,KAAK,CAChB,eAAgB,IAChB,qBAAsB5C,EAAQ,oBAChC,CAAC,EAGC4C,EAAa,SAAW,EAAG,CAC7B,QAAQ,MAAM,+EAA+E,EAC7F,MACF,CAEA,SAASE,EAAcC,EAAmB,CACxC,OAAAA,EAAI,OAAOA,GAAK,EAAE,EAClBA,EAAIA,EAAE,QAAQ,OAAQ,EAAE,EACjBA,IAAM,GAAK,IAAMA,CAC1B,CAEA,SAASC,EAAUC,EAAiBC,EAAqB,CACvD,GAAI,CAACD,GAAWA,IAAY,IAAK,MAAO,GACxC,GAAI,CACF,IAAME,EAAWF,EAAQ,QAAQ,oBAAqB,MAAM,EAAE,QAAQ,MAAO,IAAI,EACjF,OAAO,IAAI,OAAO,IAAME,EAAW,IAAK,GAAG,EAAE,KAAKD,CAAE,CACtD,OAAQxC,EAAA,CACN,OAAOuC,EAAQ,YAAY,IAAMC,EAAG,YAAY,CAClD,CACF,CAEA,SAASE,EAAiBlC,EAAqB,CAC7C,GAAI,CACF,IAAMmC,EAAS,IAAI,IAAInC,EAAK,SAAS,IAAI,EACzC,OAAOmC,EAAO,aAAa,IAAI,KAAK,GAAKA,EAAO,aAAa,IAAI,IAAI,GAAK,EAC5E,OAAQ,GACN,IAAMC,EAAQpC,EAAI,MAAM,0BAA0B,EAClD,OAAOoC,EAAQ,mBAAmBA,EAAM,CAAC,CAAC,EAAI,EAChD,CACF,CAEA,SAASC,EAAoBL,EAAmC,CAC9D,QAASL,EAAI,EAAGA,EAAID,EAAa,OAAQC,IACvC,GAAIG,EAAUJ,EAAaC,CAAC,EAAE,eAAgBK,CAAE,EAC9C,OAAON,EAAaC,CAAC,EAGzB,OAAO,IACT,CAEA,SAASW,EAAwBC,EAA2B,CAC1D,IAAMC,EAAc,OAAOD,EAAK,sBAAwB,EAAE,EAAE,KAAK,EAC3DE,EAAI,IAAI,IAAID,EAAa,SAAS,IAAI,EAC5C,OAAAC,EAAE,OAAS,GACXA,EAAE,KAAO,GACFA,CACT,CAEA,SAASC,EAAY1C,EAAyC,CAC5D,GAAI,CAACA,GAAO,OAAOA,GAAQ,SAAU,MAAO,GAC5C,GAAI,CACF,IAAMmC,EAAS,IAAI,IAAInC,EAAK,SAAS,IAAI,EAEzC,QAAS2B,EAAI,EAAGA,EAAID,EAAa,OAAQC,IAAK,CAC5C,IAAMgB,EAAkBL,EAAwBZ,EAAaC,CAAC,CAAC,EAC/D,GACEQ,EAAO,SAAWQ,EAAgB,QAClCf,EAAcO,EAAO,QAAQ,IAAMP,EAAce,EAAgB,QAAQ,EAEzE,MAAO,EAEX,CAEA,IAAMC,EAAST,EAAO,aAChBU,EAASD,EAAO,IAAI,KAAK,EACzBE,EAAYF,EAAO,IAAI,SAAS,EAChCG,EAAgBH,EAAO,IAAI,KAAK,GAAKA,EAAO,IAAI,IAAI,GAAK,GACzDI,EAAqB,iBAAiB,KAAKD,CAAa,EAE9D,OAAOF,GAAUC,GAAaE,CAChC,OAAQ,GACN,GAAI,OAAOhD,GAAQ,SAAU,CAC3B,QAASiD,EAAI,EAAGA,EAAIvB,EAAa,OAAQuB,IACvC,GAAI,CACF,IAAMC,EAASZ,EAAwBZ,EAAauB,CAAC,CAAC,EAChDE,EAAgBD,EAAO,OAASA,EAAO,SAC7C,GAAIlD,EAAI,QAAQmD,CAAa,IAAM,GAAI,MAAO,EAChD,OAAQ3D,EAAA,CAER,CAGF,IAAM4D,EAAiBpD,EAAI,QAAQ,MAAM,IAAM,GACzCqD,EAAoBrD,EAAI,QAAQ,UAAU,IAAM,GAChDsD,EAAUtD,EAAI,MAAM,+BAA+B,EACzD,MAAO,CAAC,EAAEoD,GAAkBC,GAAqBC,EACnD,CACA,MAAO,EACT,CACF,CAEA,SAASC,EAAkBC,EAA6B,CACtD,IAAMxB,EAAKE,EAAiBsB,CAAW,EACjCjB,EAAOF,EAAoBL,CAAE,EACnC,GAAI,CAACO,EAAM,MAAO,GAElB,IAAMkB,EAAMnB,EAAwBC,CAAI,EACxC,GAAI,CACF,IAAMmB,EAAM,IAAI,IAAIF,EAAa,SAAS,IAAI,EAC9CC,EAAI,OAASC,EAAI,OACjBD,EAAI,aAAa,IAAI,OAAQE,CAAO,EACpCF,EAAI,aAAa,IAAI,OAAQ,IAAI,CACnC,OAAQjE,EAAA,CAAC,CACT,OAAOiE,EAAI,SAAS,CACtB,CAEA,IAAMG,EAA8B,CAClC,MAAO,CAAC,CAAC9E,EAAQ,MACjB,YAAA4D,EACA,kBAAAa,CACF,EAEMM,EAAqC,CACzC,IAAI9E,EACJ,IAAIc,EACJ,IAAIO,EACJ,IAAIG,CACN,EAEA,QAASoB,EAAI,EAAGA,EAAIkC,EAAa,OAAQlC,IACvC,GAAI,CACFkC,EAAalC,CAAC,EAAE,QAAQiC,CAAO,CACjC,OAAS,EAAG,CACN9E,EAAQ,OAAO,QAAQ,MAAM,gDAAiD,CAAC,CACrF,CAGD,OAAe,2BAA6B,EAC/C",
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", "i", "normalizePath", "p", "matchesId", "pattern", "id", "regexStr", "getMeasurementId", "parsed", "match", "getDestinationForId", "getDuplicateEndpointUrl", "dest", "trackingURL", "u", "isTargetUrl", "duplicateTarget", "params", "hasGtm", "hasTagExp", "measurementId", "isMeasurementIdGA4", "j", "target", "targetNoQuery", "hasGtmFallback", "hasTagExpFallback", "idMatch", "buildDuplicateUrl", "originalUrl", "dst", "src", "version", "context", "interceptors"]
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@d8a-tech/gd",
3
- "version": "0.32.1",
3
+ "version": "0.33.0",
4
4
  "type": "module",
5
5
  "description": "GA4 network request duplicator (browser inline script) - TypeScript source + minified dist build.",
6
6
  "license": "MIT",
package/src.hash CHANGED
@@ -1 +1 @@
1
- fb8b6f478bb01b736aecd674032ed8001e1ea7e1da43e5cb00f2abae0aa4611e -
1
+ 6b6786210e256dbaa47f415b2c30fe87022faef5818f8cc3f4e41728fc3dc123 -