@jenil_121/ga-bridge 1.0.2 → 1.0.4

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/README.md CHANGED
@@ -1,72 +1,28 @@
1
1
  # Twinalyze GA Bridge
2
2
 
3
- Twinalyze GA Bridge is a lightweight browser bridge that listens to GA4 `gtag('event', ...)` calls and forwards the same event to Twinalyze using the existing Twinalyze web SDK.
3
+ A lightweight bridge to forward Google Analytics (`gtag.js`) events to Twinalyze automatically.
4
4
 
5
- ## What it does
5
+ This allows you to use Google Analytics as the source of truth and mirror the same events into Twinalyze without modifying existing tracking code.
6
6
 
7
- - waits for `window.gtag`
8
- - wraps GA4 `gtag('event', eventName, params)` calls
9
- - lets GA handle the event first
10
- - then sends the same event to `window.twinalyze.track(eventName, params)`
11
- - optionally validates GA-safe event names
12
- - queues events if Twinalyze SDK is not ready yet
7
+ ---
13
8
 
14
- ## Files
9
+ ## 🚀 Features
15
10
 
16
- - `src/twinalyze-ga-bridge.js` source file
17
- - `dist/twinalyze-ga-bridge.min.js` minified build output
11
+ - Forward GA events (`gtag('event', ...)`) to Twinalyze
12
+ - Uses **GA callback-based forwarding**
13
+ - Ensures:
14
+ - If GA event succeeds → Twinalyze receives it
15
+ - If GA event fails → Twinalyze does NOT receive it
16
+ - No fallback (strict dependency on GA)
17
+ - Automatic installation
18
+ - Debug mode support
19
+ - Adds `__from_bridge: true` flag to all forwarded events
18
20
 
19
- ## Installation
21
+ ---
20
22
 
21
- Load scripts in this order:
23
+ ## 📦 Installation
22
24
 
23
- 1. Google Analytics
24
- 2. Twinalyze Web SDK
25
- 3. Twinalyze GA Bridge
25
+ ### CDN (Recommended)
26
26
 
27
27
  ```html
28
- <!-- 1. Load GA -->
29
- <script async src="https://www.googletagmanager.com/gtag/js?id=G-XXXXXXXX"></script>
30
- <script>
31
- window.dataLayer = window.dataLayer || [];
32
- function gtag(){ dataLayer.push(arguments); }
33
- gtag('js', new Date());
34
- gtag('config', 'G-XXXXXXXX');
35
- </script>
36
-
37
- <!-- 2. Load Twinalyze SDK -->
38
- <script src="https://cdn.jsdelivr.net/npm/@twinalyze/web-analytics@1.0.14/dist/cdn.global.min.js"></script>
39
- <script>
40
- window.twinalyze.init({
41
- apiKey: "PUBLIC_WRITE_KEY",
42
- organization: "ORG_ID",
43
- socketUrl: "https://www.twinalyze.com/"
44
- });
45
- </script>
46
-
47
- <!-- 3. Load Twinalyze GA Bridge -->
48
- <script src="https://cdn.jsdelivr.net/npm/@jenil_121/ga-bridge@1.0.1/dist/twinalyze-ga-bridge.min.js"></script>
49
- ```
50
-
51
- ## Usage
52
-
53
- After setup, use GA normally:
54
-
55
- ```html
56
- <script>
57
- gtag('event', 'purchase', {
58
- value: 999,
59
- currency: 'INR'
60
- });
61
- </script>
62
- ```
63
-
64
- This event will be sent to:
65
- - Google Analytics
66
- - Twinalyze
67
-
68
- ## Notes
69
-
70
- - The bridge depends on both `window.gtag` and `window.twinalyze`
71
- - Load order is important
72
- - This package is a bridge plugin, not a replacement for the Twinalyze SDK
28
+ <script src="https://cdn.jsdelivr.net/npm/@jenil_121/ga-bridge@1.0.4/dist/twinalyze-ga-bridge.min.js"></script>
@@ -1 +1,23 @@
1
- !function(e){var t={waitForGaCallback:!0,validateGaEventNames:!0,eventTimeout:2e3,debug:!1,maxWrapRetries:200,wrapRetryInterval:100,skipEvents:["page_view"]},n=/^[A-Za-z][A-Za-z0-9_]{0,39}$/,a={options:t,wrapped:!1,originalGtag:null,wrapRetries:0,queue:[]};function i(){if(a.options.debug)try{console.log.apply(console,["[TwinalyzeGABridge]"].concat([].slice.call(arguments)))}catch(e){}}function r(){try{console.warn.apply(console,["[TwinalyzeGABridge]"].concat([].slice.call(arguments)))}catch(e){}}function o(){return e.twinalyze||e.TwinalyzeAnalytics||null}function l(e){return e&&"object"==typeof e&&!Array.isArray(e)?Object.assign({},e):{}}function c(e,t){a.queue.push({eventName:e,params:t})}function u(){var e=o();if(e&&"function"==typeof e.track)for(;a.queue.length;){var t=a.queue.shift();try{e.track(t.eventName,t.params)}catch(e){r("Failed to flush queued event:",t.eventName,e)}}}function p(e,t){var n=o();if(!n||"function"!=typeof n.track)return c(e,t),void r("Twinalyze SDK not ready, queued event:",e);try{n.track(e,t)}catch(n){r("Twinalyze track failed, queued event:",e,n),c(e,t)}}function s(){if(a.wrapped)return!0;if("function"!=typeof e.gtag)return!1;a.originalGtag=e.gtag;var t=function(){var e=Array.prototype.slice.call(arguments);if("event"!==e[0])return a.originalGtag.apply(this,e);var t,o=e[1],c=l(e[2]);if(t=o,-1!==a.options.skipEvents.indexOf(t))return i("Skipping mirrored event:",o),a.originalGtag.apply(this,e);if(a.options.validateGaEventNames&&!function(e){return"string"==typeof e&&n.test(e)}(o))return r("Invalid GA event name, skipping Twinalyze mirror:",o),a.originalGtag.apply(this,e);var s=c.event_callback,g=c.event_timeout||a.options.eventTimeout;if(a.options.waitForGaCallback){var f=Object.assign({},c,{event_timeout:g,event_callback:function(){try{"function"==typeof s&&s()}catch(e){r("User event_callback failed:",e)}var e=l(c);delete e.event_callback,delete e.event_timeout,p(o,e),u()}});return a.originalGtag.call(this,"event",o,f)}var v=l(c);return delete v.event_callback,delete v.event_timeout,p(o,v),u(),a.originalGtag.apply(this,e)};return t.__twinalyzeWrapped=!0,t.__original=a.originalGtag,e.gtag=t,a.wrapped=!0,u(),i("gtag wrapped successfully"),!0}function g(){s()||(a.wrapRetries+=1,a.wrapRetries>=a.options.maxWrapRetries?r("window.gtag not found. Bridge could not attach."):setTimeout(g,a.options.wrapRetryInterval))}function f(e){a.options=Object.assign({},t,e||{}),g(),u()}e.twinalyzeGABridge={init:f,rebind:s,flushQueue:u,version:"1.0.0"},e.twinalyzeGABridgeConfig&&f(e.twinalyzeGABridgeConfig)}(window);
1
+ // !function(e){"use strict";var t={debug:!0,forwardOnlyValidEvents:!0,addBridgeFlag:!0,bridgeFlagKey:"__from_bridge",installWaitMs:1500,eventTimeout:2e3},n="__gaTwinalyzeBridgeInstalled",o=/^[A-Za-z][A-Za-z0-9_]{0,39}$/;function i(){if(!e.__TWINALYZE_GA_BRIDGE_DEBUG__)return;var t=Array.prototype.slice.call(arguments);t.unshift("[Twinalyze GA Bridge]"),console.log.apply(console,t)}function r(){var t=Array.prototype.slice.call(arguments);t.unshift("[Twinalyze GA Bridge]"),console.warn.apply(console,t)}function a(e){return e&&"object"==typeof e&&!Array.isArray(e)}function l(e){return"string"==typeof e&&o.test(e)}function g(){return e.twinalyze||e.TwinalyzeAnalytics||null}function c(){var n=e.TwinalyzeGABridgeConfig||{},o={};for(var i in t)o[i]=t[i];for(var r in n)o[r]=n[r];return o}function d(){var t=c();if(e.__TWINALYZE_GA_BRIDGE_DEBUG__=!!t.debug,e[n])return void i("already installed");if("function"!=typeof e.gtag)return void r("gtag not found");var o=g();if(!o||"function"!=typeof o.track)return void r("twinalyze.track not found");var d=e.gtag;e.gtag=function(){var n=Array.prototype.slice.call(arguments);if(i("gtag call:",n),"event"===n[0]){var o=n[1],u=a(n[2])?Object.assign({},n[2]):{};if(t.forwardOnlyValidEvents&&!l(o))return r("invalid GA event name:",o),d.apply(e,n);var p=u.event_callback;return u.event_timeout="number"==typeof u.event_timeout?u.event_timeout:t.eventTimeout,u.event_callback=function(){i("GA callback fired:",o);try{"function"==typeof p&&p()}catch(e){console.error("[Twinalyze GA Bridge] old callback error",e)}try{var n=Object.assign({},u);if(delete n.event_callback,delete n.event_timeout,t.addBridgeFlag&&(n[t.bridgeFlagKey]=!0),!(s=g())||"function"!=typeof s.track)return void r("twinalyze.track missing during forward:",o);i("forwarding event:",o,n),s.track(o,n)}catch(e){console.error("[Twinalyze GA Bridge] track error",e)}var s},d.call(e,"event",o,u)}return d.apply(e,n)},e[n]=!0,i("installed successfully")}function u(){var e=c();setTimeout(d,e.installWaitMs)}u()}(window);
2
+
3
+ (function(global){
4
+ "use strict";
5
+ var DEFAULTS={debug:!1,forwardOnlyValidEvents:!0,addBridgeFlag:!0,bridgeFlagKey:"__from_bridge",installPollIntervalMs:100,installTimeoutMs:10000,maxRetryAttempts:3,retryDelayMs:500},
6
+ BRIDGE_INSTALLED_KEY="__gaTwinalyzeBridgeInstalled",
7
+ GA_EVENT_NAME_RE=/^[A-Za-z][A-Za-z0-9_]{0,39}$/;
8
+ global.__twinalyzeBridge=global.__twinalyzeBridge||{};
9
+ var debug=global.__twinalyzeBridge.debug||DEFAULTS.debug;
10
+ function log(){if(!debug)return;var e=Array.prototype.slice.call(arguments);e.unshift("[Twinalyze GA Bridge]");console.log.apply(console,e);}
11
+ function warn(){var e=Array.prototype.slice.call(arguments);e.unshift("[Twinalyze GA Bridge]");console.warn.apply(console,e);}
12
+ function isObject(e){return e&&"object"==typeof e&&!Array.isArray(e);}
13
+ function isValidGaEventName(e){return"string"==typeof e&&GA_EVENT_NAME_RE.test(e);}
14
+ function getTwinalyzeSdk(){return global.twinalyze||global.TwinalyzeAnalytics||null;}
15
+ var eventQueue=[],bridgeReady=!1;
16
+ function retry(fn,attempts,delay){return new Promise(function(resolve,reject){!function r(){Promise.resolve().then(fn).then(resolve).catch(function(err){attempts===1?reject(err):(attempts--,setTimeout(r,delay))})}()});}
17
+ function forwardToTwinalyze(name,params){return retry(function(){var sdk=getTwinalyzeSdk();if(!sdk||"function"!=typeof sdk.track)throw new Error("twinalyze.track missing");log("Forwarding event:",name,params);return sdk.track(name,params)},DEFAULTS.maxRetryAttempts,DEFAULTS.retryDelayMs).catch(function(e){warn("Failed to forward event:",e)});}
18
+ function flushQueue(){if(!bridgeReady)return;for(;eventQueue.length>0;){var e=eventQueue.shift();forwardToTwinalyze(e.eventName,e.params);}}
19
+ function installBridge(){if(global[BRIDGE_INSTALLED_KEY])return void log("Bridge already installed");if("function"!=typeof global.gtag)return void warn("gtag not found");var sdk=getTwinalyzeSdk();if(!sdk||"function"!=typeof sdk.track)return void warn("twinalyze.track not found");var oldGtag=global.gtag;global.gtag=function(){var args=Array.prototype.slice.call(arguments);log("gtag call:",args);"event"===args[0]&&(function(){var name=args[1],params=isObject(args[2])?Object.assign({},args[2]):{};if(DEFAULTS.forwardOnlyValidEvents&&!isValidGaEventName(name))return void(warn("Invalid GA event name, forwarding only to GA:",name),oldGtag.apply(global,args));DEFAULTS.addBridgeFlag&&(params[DEFAULTS.bridgeFlagKey]=!0);bridgeReady?forwardToTwinalyze(name,params):eventQueue.push({eventName:name,params:params})})();return oldGtag.apply(global,args)};bridgeReady=!0;global[BRIDGE_INSTALLED_KEY]=!0;log("Bridge installed successfully");flushQueue();}
20
+ function waitForDependencies(timeout,poll){var elapsed=0;return new Promise(function(resolve,reject){!function check(){var sdk=getTwinalyzeSdk();return"function"==typeof global.gtag&&sdk&&"function"==typeof sdk.track?void resolve():(elapsed+=poll,elapsed>=timeout?void reject(new Error("Timeout waiting for gtag or twinalyze SDK")):void setTimeout(check,poll))}()});}
21
+ function bootstrap(){var cfg=global.TwinalyzeGABridgeConfig||{};for(var key in DEFAULTS)cfg.hasOwnProperty(key)&&(DEFAULTS[key]=cfg[key]);debug=DEFAULTS.debug;waitForDependencies(DEFAULTS.installTimeoutMs,DEFAULTS.installPollIntervalMs).then(installBridge).catch(function(e){warn("Failed to install bridge:",e)});}
22
+ bootstrap();
23
+ })(window);
package/package.json CHANGED
@@ -1,18 +1,18 @@
1
1
  {
2
2
  "name": "@jenil_121/ga-bridge",
3
- "version": "1.0.2",
4
- "description": "GA4 to Twinalyze browser bridge",
3
+ "version": "1.0.4",
4
+ "description": "Twinalyze GA Bridge (GA → Twinalyze event forwarding)",
5
5
  "main": "dist/twinalyze-ga-bridge.min.js",
6
6
  "files": [
7
- "dist",
8
- "README.md"
7
+ "dist"
9
8
  ],
10
- "scripts": {
11
- "build": "terser src/twinalyze-ga-bridge.js -c -m -o dist/twinalyze-ga-bridge.min.js",
12
- "prepublishOnly": "npm run build"
13
- },
14
- "publishConfig": {
15
- "access": "public"
16
- },
9
+ "keywords": [
10
+ "twinalyze",
11
+ "google-analytics",
12
+ "gtag",
13
+ "analytics",
14
+ "bridge"
15
+ ],
16
+ "author": "jenil",
17
17
  "license": "MIT"
18
18
  }