tatvic-implementation-sdk 0.0.0-stage → 1.0.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/README.md +102 -2
- package/dist/bundle.d.ts +3 -0
- package/dist/custom-element.d.ts +17 -0
- package/dist/defaults.d.ts +13 -0
- package/dist/express.d.ts +28 -0
- package/dist/index.d.ts +28 -0
- package/dist/index.js +871 -0
- package/dist/interceptor.d.ts +58 -0
- package/dist/morph-gtm.d.ts +7 -0
- package/dist/next.d.ts +16 -0
- package/dist/react.d.ts +26 -0
- package/dist/server-proxy.d.ts +7 -0
- package/dist/tatvic.js +13 -0
- package/dist/types.d.ts +103 -0
- package/dist/url-matcher.d.ts +30 -0
- package/package.json +69 -4
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import type { ProxySdkOptions } from './types.js';
|
|
2
|
+
interface TatvicXhrMetadata {
|
|
3
|
+
isProxied?: boolean;
|
|
4
|
+
originalUrl?: string;
|
|
5
|
+
headerName?: string;
|
|
6
|
+
headerValue?: string;
|
|
7
|
+
previewToken?: string;
|
|
8
|
+
}
|
|
9
|
+
declare global {
|
|
10
|
+
interface XMLHttpRequest {
|
|
11
|
+
__tatvicMeta?: TatvicXhrMetadata;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
export declare class RequestInterceptor {
|
|
15
|
+
private matcher;
|
|
16
|
+
private options;
|
|
17
|
+
private isInstalled;
|
|
18
|
+
private originalFetch?;
|
|
19
|
+
private originalXhrOpen?;
|
|
20
|
+
private originalXhrSend?;
|
|
21
|
+
private originalSendBeacon?;
|
|
22
|
+
private originalScriptSrcDesc?;
|
|
23
|
+
private originalImageSrcDesc?;
|
|
24
|
+
constructor(options?: ProxySdkOptions);
|
|
25
|
+
/**
|
|
26
|
+
* Installs monkey-patches on fetch, XMLHttpRequest, sendBeacon, <script src>, and <img src>.
|
|
27
|
+
*/
|
|
28
|
+
install(): void;
|
|
29
|
+
/**
|
|
30
|
+
* Restores all patched browser APIs to their original native implementations.
|
|
31
|
+
*/
|
|
32
|
+
uninstall(): void;
|
|
33
|
+
/**
|
|
34
|
+
* Patch window.fetch
|
|
35
|
+
*/
|
|
36
|
+
private patchFetch;
|
|
37
|
+
/**
|
|
38
|
+
* Patch XMLHttpRequest
|
|
39
|
+
*/
|
|
40
|
+
private patchXhr;
|
|
41
|
+
/**
|
|
42
|
+
* Patch navigator.sendBeacon
|
|
43
|
+
*/
|
|
44
|
+
private patchSendBeacon;
|
|
45
|
+
/**
|
|
46
|
+
* Patch HTMLScriptElement.prototype.src for dynamically injected scripts (GTM, pixels)
|
|
47
|
+
*/
|
|
48
|
+
private patchScriptElements;
|
|
49
|
+
/**
|
|
50
|
+
* Patch HTMLImageElement.prototype.src for tracking pixels (<img src="...">)
|
|
51
|
+
*/
|
|
52
|
+
private patchImageElements;
|
|
53
|
+
/**
|
|
54
|
+
* Helper to detect active Server-Side GTM Preview & Debug tokens from current URL.
|
|
55
|
+
*/
|
|
56
|
+
private detectPreviewToken;
|
|
57
|
+
}
|
|
58
|
+
export {};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Morphs Google Tag Manager (gtm.js) container script to route all third-party
|
|
3
|
+
* ad and analytics tracking endpoints through your first-party relay, while
|
|
4
|
+
* strictly preserving GTM core runtime, service worker bridge, and Tag Assistant
|
|
5
|
+
* Preview & Debug mode capabilities.
|
|
6
|
+
*/
|
|
7
|
+
export declare function morphGtmScript(originalCode: string, relayEndpoint?: string): string;
|
package/dist/next.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { ServerProxyOptions } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Pre-configured Next.js App Router route handler.
|
|
4
|
+
*
|
|
5
|
+
* In your Next.js project, create `app/_tatvic/relay/route.ts`:
|
|
6
|
+
* ```typescript
|
|
7
|
+
* import { tatvicRelayRoute } from 'tatvic-implementation-sdk/next';
|
|
8
|
+
*
|
|
9
|
+
* export const { GET, POST, OPTIONS } = tatvicRelayRoute();
|
|
10
|
+
* ```
|
|
11
|
+
*/
|
|
12
|
+
export declare function tatvicRelayRoute(options?: ServerProxyOptions): {
|
|
13
|
+
GET: (request: Request) => Promise<Response>;
|
|
14
|
+
POST: (request: Request) => Promise<Response>;
|
|
15
|
+
OPTIONS: (request: Request) => Promise<Response>;
|
|
16
|
+
};
|
package/dist/react.d.ts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import './custom-element.js';
|
|
3
|
+
import type { ProxySdkOptions } from './types.js';
|
|
4
|
+
export interface TatvicWrapperProps extends ProxySdkOptions {
|
|
5
|
+
children?: React.ReactNode;
|
|
6
|
+
className?: string;
|
|
7
|
+
style?: React.CSSProperties;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Universal React & Next.js App Wrapper.
|
|
11
|
+
*
|
|
12
|
+
* Wrap your entire app once:
|
|
13
|
+
*
|
|
14
|
+
* ```tsx
|
|
15
|
+
* import { TatvicWrapper } from 'tatvic-implementation-sdk';
|
|
16
|
+
*
|
|
17
|
+
* export default function RootLayout({ children }: { children: React.ReactNode }) {
|
|
18
|
+
* return (
|
|
19
|
+
* <TatvicWrapper>
|
|
20
|
+
* {children}
|
|
21
|
+
* </TatvicWrapper>
|
|
22
|
+
* );
|
|
23
|
+
* }
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
export declare function TatvicWrapper({ children, className, style, ...options }: TatvicWrapperProps): React.JSX.Element;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { ServerProxyOptions } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Creates a server-side proxy handler that receives proxied first-party requests
|
|
4
|
+
* from the client SDK, validates them, safely forwards them to upstream targets,
|
|
5
|
+
* and morphs GTM container scripts to bypass ad blockers while preserving Tag Assistant preview mode.
|
|
6
|
+
*/
|
|
7
|
+
export declare function createProxyHandler(options?: ServerProxyOptions): (request: Request) => Promise<Response>;
|
package/dist/tatvic.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
(()=>{var nt=Object.create;var{getPrototypeOf:ot,defineProperty:I,getOwnPropertyNames:De,getOwnPropertyDescriptor:st}=Object,oe=Object.prototype.hasOwnProperty;function Ie(r){return this[r]}var at,it,ct=(r,c,d)=>{var a=r!=null&&typeof r==="object";if(a){var u=c?at??=new WeakMap:it??=new WeakMap,g=u.get(r);if(g)return g}d=r!=null?nt(ot(r)):{};let m=c||!r||!r.__esModule||!oe.call(r,"default")?I(d,"default",{value:r,enumerable:!0}):d;if(r&&typeof r==="object"||typeof r==="function"){for(let p of De(r))if(!oe.call(m,p))I(m,p,{get:Ie.bind(r,p),enumerable:!0})}if(a)u.set(r,m);return m},ut=(r)=>{var c=(Ne??=new WeakMap).get(r),d;if(c)return c;if(c=I({},"__esModule",{value:!0}),r&&typeof r==="object"||typeof r==="function"){for(var a of De(r))if(!oe.call(c,a))I(c,a,{get:Ie.bind(r,a),enumerable:!(d=st(r,a))||d.enumerable})}return Ne.set(r,c),c},Ne,He=(r,c)=>()=>(c||r((c={exports:{}}).exports,c),c.exports);var lt=(r)=>r;function dt(r,c){this[r]=lt.bind(null,c)}var pt=(r,c)=>{for(var d in c)I(r,d,{get:c[d],enumerable:!0,configurable:!0,set:dt.bind(c,d)})};var qe=He(function(l,Y){(function(){function r(e,t){Object.defineProperty(a.prototype,e,{get:function(){console.warn("%s(...) is deprecated in plain JavaScript React classes. %s",t[0],t[1])}})}function c(e){if(e===null||typeof e!=="object")return null;return e=be&&e[be]||e["@@iterator"],typeof e==="function"?e:null}function d(e,t){e=(e=e.constructor)&&(e.displayName||e.name)||"ReactClass";var n=e+"."+t;Te[n]||(console.error("Can't call %s on a component that is not yet mounted. This is a no-op, but it might indicate a bug in your application. Instead, assign to `this.state` directly or define a `state = {};` class property with the desired state in the %s component.",t,e),Te[n]=!0)}function a(e,t,n){this.props=e,this.context=t,this.refs=re,this.updater=n||Re}function u(){}function g(e,t,n){this.props=e,this.context=t,this.refs=re,this.updater=n||Re}function m(){}function p(e){return""+e}function E(e){try{p(e);var t=!1}catch(s){t=!0}if(t){t=console;var n=t.error,o=typeof Symbol==="function"&&Symbol.toStringTag&&e[Symbol.toStringTag]||e.constructor.name||"Object";return n.call(t,"The provided key is an unsupported type %s. This value must be coerced to a string before using it here.",o),p(e)}}function y(e){if(e==null)return null;if(typeof e==="function")return e.$$typeof===Je?null:e.displayName||e.name||null;if(typeof e==="string")return e;switch(e){case Z:return"Fragment";case me:return"Profiler";case ge:return"StrictMode";case ve:return"Suspense";case Qe:return"SuspenseList";case Ee:return"Activity";case _e:return"ViewTransition"}if(typeof e==="object")switch(typeof e.tag==="number"&&console.error("Received an unexpected object in getComponentNameFromType(). This is likely a bug in React. Please file an issue."),e.$$typeof){case he:return"Portal";case ye:return e.displayName||"Context";case ee:return(e._context.displayName||"Context")+".Consumer";case we:var t=e.render;return e=e.displayName,e||(e=t.displayName||t.name||"",e=e!==""?"ForwardRef("+e+")":"ForwardRef"),e;case te:return t=e.displayName||null,t!==null?t:y(e.type)||"Memo";case N:t=e._payload,e=e._init;try{return y(e(t))}catch(n){}}return null}function T(e){if(e===Z)return"<>";if(typeof e==="object"&&e!==null&&e.$$typeof===N)return"<...>";try{var t=y(e);return t?"<"+t+">":"<...>"}catch(n){return"<...>"}}function _(){var e=h.A;return e===null?null:e.getOwner()}function R(){return Error("react-stack-top-frame")}function x(e){if(X.call(e,"key")){var t=Object.getOwnPropertyDescriptor(e,"key").get;if(t&&t.isReactWarning)return!1}return e.key!==void 0}function S(e,t){function n(){Oe||(Oe=!0,console.error("%s: `key` is not a prop. Trying to access it will result in `undefined` being returned. If you need to access the same value within the child component, you should pass it as a different prop. (https://react.dev/link/special-props)",t))}n.isReactWarning=!0,Object.defineProperty(e,"key",{get:n,configurable:!0})}function A(){var e=y(this.type);return Ae[e]||(Ae[e]=!0,console.error("Accessing element.ref was removed in React 19. ref is now a regular prop. It will be removed from the JSX Element type in a future release.")),e=this.props.ref,e!==void 0?e:null}function z(e,t,n,o,s,v){var i=n.ref;return e={$$typeof:J,type:e,key:t,props:n,_owner:o},(i!==void 0?i:null)!==null?Object.defineProperty(e,"ref",{enumerable:!1,get:A}):Object.defineProperty(e,"ref",{enumerable:!1,value:null}),e._store={},Object.defineProperty(e._store,"validated",{configurable:!1,enumerable:!1,writable:!0,value:0}),Object.defineProperty(e,"_debugInfo",{configurable:!1,enumerable:!1,writable:!0,value:null}),Object.defineProperty(e,"_debugStack",{configurable:!1,enumerable:!1,writable:!0,value:s}),Object.defineProperty(e,"_debugTask",{configurable:!1,enumerable:!1,writable:!0,value:v}),Object.freeze&&(Object.freeze(e.props),Object.freeze(e)),e}function Ye(e,t){return t=z(e.type,t,e.props,e._owner,e._debugStack,e._debugTask),e._store&&(t._store.validated=e._store.validated),t}function le(e){C(e)?e._store&&(e._store.validated=1):typeof e==="object"&&e!==null&&e.$$typeof===N&&(e._payload.status==="fulfilled"?C(e._payload.value)&&e._payload.value._store&&(e._payload.value._store.validated=1):e._store&&(e._store.validated=1))}function C(e){return typeof e==="object"&&e!==null&&e.$$typeof===J}function ze(e){var t={"=":"=0",":":"=2"};return"$"+e.replace(/[=:]/g,function(n){return t[n]})}function V(e,t){return typeof e==="object"&&e!==null&&e.key!=null?(E(e.key),ze(""+e.key)):t.toString(36)}function Ve(e){switch(e.status){case"fulfilled":return e.value;case"rejected":throw e.reason;default:switch(typeof e.status==="string"?e.then(m,m):(e.status="pending",e.then(function(t){e.status==="pending"&&(e.status="fulfilled",e.value=t)},function(t){e.status==="pending"&&(e.status="rejected",e.reason=t)})),e.status){case"fulfilled":return e.value;case"rejected":throw e.reason}}throw e}function L(e,t,n,o,s){var v=typeof e;if(v==="undefined"||v==="boolean")e=null;var i=!1;if(e===null)i=!0;else switch(v){case"bigint":case"string":case"number":i=!0;break;case"object":switch(e.$$typeof){case J:case he:i=!0;break;case N:return i=e._init,L(i(e._payload),t,n,o,s)}}if(i){i=e,s=s(i);var f=o===""?"."+V(i,0):o;return Pe(s)?(n="",f!=null&&(n=f.replace(Le,"$&/")+"/"),L(s,t,n,"",function(O){return O})):s!=null&&(C(s)&&(s.key!=null&&(i&&i.key===s.key||E(s.key)),n=Ye(s,n+(s.key==null||i&&i.key===s.key?"":(""+s.key).replace(Le,"$&/")+"/")+f),o!==""&&i!=null&&C(i)&&i.key==null&&i._store&&!i._store.validated&&(n._store.validated=2),s=n),t.push(s)),1}if(i=0,f=o===""?".":o+":",Pe(e))for(var w=0;w<e.length;w++)o=e[w],v=f+V(o,w),i+=L(o,t,n,v,s);else if(w=c(e),typeof w==="function")for(w===e.entries&&(Ce||console.warn("Using Maps as children is not supported. Use an array of keyed ReactElements instead."),Ce=!0),e=w.call(e),w=0;!(o=e.next()).done;)o=o.value,v=f+V(o,w++),i+=L(o,t,n,v,s);else if(v==="object"){if(typeof e.then==="function")return L(Ve(e),t,n,o,s);throw t=String(e),Error("Objects are not valid as a React child (found: "+(t==="[object Object]"?"object with keys {"+Object.keys(e).join(", ")+"}":t)+"). If you meant to render a collection of children, use an array instead.")}return i}function H(e,t,n){if(e==null)return e;var o=[],s=0;return L(e,o,"","",function(v){return t.call(n,v,s++)}),o}function Ke(e){if(e._status===-1){var t=null,n=null,o=e._ioInfo;o!=null&&(o.start=o.end=performance.now(),o.value=new Promise(function(i,f){t=i,n=f})),o=e._result;var s=o();if(s.then(function(i){if(e._status===0||e._status===-1){e._status=1,e._result=i;var f=e._ioInfo;if(f!=null){f.end=performance.now();var w=i==null?void 0:i.default;t(w),f.value.status="fulfilled",f.value.value=w}s.status===void 0&&(s.status="fulfilled",s.value=i)}},function(i){if(e._status===0||e._status===-1){e._status=2,e._result=i;var f=e._ioInfo;f!=null&&(f.end=performance.now(),f.value.then(m,m),n(i),f.value.status="rejected",f.value.reason=i),s.status===void 0&&(s.status="rejected",s.reason=i)}}),o=e._ioInfo,o!=null){var v=s.displayName;typeof v==="string"&&(o.name=v)}e._status===-1&&(e._status=0,e._result=s)}if(e._status===1)return o=e._result,o===void 0&&console.error(`lazy: Expected the result of a dynamic import() call. Instead received: %s
|
|
2
|
+
|
|
3
|
+
Your code should look like:
|
|
4
|
+
const MyComponent = lazy(() => import('./MyComponent'))
|
|
5
|
+
|
|
6
|
+
Did you accidentally put curly braces around the import?`,o),"default"in o||console.error(`lazy: Expected the result of a dynamic import() call. Instead received: %s
|
|
7
|
+
|
|
8
|
+
Your code should look like:
|
|
9
|
+
const MyComponent = lazy(() => import('./MyComponent'))`,o),o.default;throw e._result}function b(){var e=h.H;return e===null&&console.error(`Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:
|
|
10
|
+
1. You might have mismatching versions of React and the renderer (such as React DOM)
|
|
11
|
+
2. You might be breaking the Rules of Hooks
|
|
12
|
+
3. You might have more than one copy of React in the same app
|
|
13
|
+
See https://react.dev/link/invalid-hook-call for tips about how to debug and fix this problem.`),e}function de(){h.asyncTransitions--}function pe(e){var t=h.T,n={};n.types=t!==null?t.types:null,n._updatedFibers=new Set,h.T=n;try{var o=e(),s=h.S;s!==null&&s(n,o),typeof o==="object"&&o!==null&&typeof o.then==="function"&&(h.asyncTransitions++,o.then(de,de),o.then(m,Me))}catch(v){Me(v)}finally{t===null&&n._updatedFibers&&(e=n._updatedFibers.size,n._updatedFibers.clear(),10<e&&console.warn("Detected a large number of updates inside startTransition. If this is due to a subscription please re-write it to use React provided hooks. Otherwise concurrent mode guarantees are off the table.")),t!==null&&n.types!==null&&(t.types!==null&&t.types!==n.types&&console.error("We expected inner Transitions to have transferred the outer types set and that you cannot add to the outer Transition while inside the inner.This is a bug in React."),t.types=n.types),h.T=t}}function fe(e){var t=h.T;if(t!==null){var n=t.types;n===null?t.types=[e]:n.indexOf(e)===-1&&n.push(e)}else h.asyncTransitions===0&&console.error("addTransitionType can only be called inside a `startTransition()` callback. It must be associated with a specific Transition."),pe(fe.bind(null,e))}function F(e){if(B===null)try{var t=("require"+Math.random()).slice(0,7);B=(Y&&Y[t]).call(Y,"timers").setImmediate}catch(n){B=function(o){je===!1&&(je=!0,typeof MessageChannel>"u"&&console.error("This browser does not have a MessageChannel implementation, so enqueuing tasks via await act(async () => ...) will fail. Please file an issue at https://github.com/facebook/react/issues if you encounter this warning."));var s=new MessageChannel;s.port1.onmessage=o,s.port2.postMessage(void 0)}}return B(e)}function U(e){return 1<e.length&&typeof AggregateError==="function"?AggregateError(e):e[0]}function q(e,t){t!==W-1&&console.error("You seem to have overlapping act() calls, this is not supported. Be sure to await previous act() calls before making a new one. "),W=t}function K(e,t,n){var o=h.actQueue;if(o!==null)if(o.length!==0)try{Q(o),F(function(){return K(e,t,n)});return}catch(s){h.thrownErrors.push(s)}else h.actQueue=null;0<h.thrownErrors.length?(o=U(h.thrownErrors),h.thrownErrors.length=0,n(o)):t(e)}function Q(e){if(!ne){ne=!0;var t=0;try{for(;t<e.length;t++){var n=e[t];do{h.didUsePromise=!1;var o=n(!1);if(o!==null){if(h.didUsePromise){e[t]=n,e.splice(0,t);return}n=o}else break}while(1)}e.length=0}catch(s){e.splice(0,t+1),h.thrownErrors.push(s)}finally{ne=!1}}}typeof __REACT_DEVTOOLS_GLOBAL_HOOK__<"u"&&typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart==="function"&&__REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart(Error());var J=Symbol.for("react.transitional.element"),he=Symbol.for("react.portal"),Z=Symbol.for("react.fragment"),ge=Symbol.for("react.strict_mode"),me=Symbol.for("react.profiler"),ee=Symbol.for("react.consumer"),ye=Symbol.for("react.context"),we=Symbol.for("react.forward_ref"),ve=Symbol.for("react.suspense"),Qe=Symbol.for("react.suspense_list"),te=Symbol.for("react.memo"),N=Symbol.for("react.lazy"),Ee=Symbol.for("react.activity"),_e=Symbol.for("react.view_transition"),be=Symbol.iterator,Te={},Re={isMounted:function(){return!1},enqueueForceUpdate:function(e){d(e,"forceUpdate")},enqueueReplaceState:function(e){d(e,"replaceState")},enqueueSetState:function(e){d(e,"setState")}},Se=Object.assign,re={};Object.freeze(re),a.prototype.isReactComponent={},a.prototype.setState=function(e,t){if(typeof e!=="object"&&typeof e!=="function"&&e!=null)throw Error("takes an object of state variables to update or a function which returns an object of state variables.");this.updater.enqueueSetState(this,e,t,"setState")},a.prototype.forceUpdate=function(e){this.updater.enqueueForceUpdate(this,e,"forceUpdate")};var P={isMounted:["isMounted","Instead, make sure to clean up subscriptions and pending requests in componentWillUnmount to prevent memory leaks."],replaceState:["replaceState","Refactor your code to use setState instead (see https://github.com/facebook/react/issues/3236)."]};for(D in P)P.hasOwnProperty(D)&&r(D,P[D]);u.prototype=a.prototype,P=g.prototype=new u,P.constructor=g,Se(P,a.prototype),P.isPureReactComponent=!0;var Pe=Array.isArray,Je=Symbol.for("react.client.reference"),h={H:null,A:null,T:null,S:null,actQueue:null,asyncTransitions:0,isBatchingLegacy:!1,didScheduleLegacyUpdate:!1,didUsePromise:!1,thrownErrors:[],getCurrentStack:null,recentlyCreatedOwnerStacks:0},X=Object.prototype.hasOwnProperty,xe=console.createTask?console.createTask:function(){return null};P={react_stack_bottom_frame:function(e){return e()}};var Oe,ke,Ae={},Ze=P.react_stack_bottom_frame.bind(P,R)(),et=xe(T(R)),Ce=!1,Le=/\/+/g,Me=typeof reportError==="function"?reportError:function(e){if(typeof window==="object"&&typeof window.ErrorEvent==="function"){var t=new window.ErrorEvent("error",{bubbles:!0,cancelable:!0,message:typeof e==="object"&&e!==null&&typeof e.message==="string"?String(e.message):String(e),error:e});if(!window.dispatchEvent(t))return}else if(typeof process==="object"&&typeof process.emit==="function"){process.emit("uncaughtException",e);return}console.error(e)},je=!1,B=null,W=0,G=!1,ne=!1,Ue=typeof queueMicrotask==="function"?function(e){queueMicrotask(function(){return queueMicrotask(e)})}:F;P=Object.freeze({__proto__:null,c:function(e){return b().useMemoCache(e)}});var D={map:H,forEach:function(e,t,n){H(e,function(){t.apply(this,arguments)},n)},count:function(e){var t=0;return H(e,function(){t++}),t},toArray:function(e){return H(e,function(t){return t})||[]},only:function(e){if(!C(e))throw Error("React.Children.only expected to receive a single React element child.");return e}};l.Activity=Ee,l.Children=D,l.Component=a,l.Fragment=Z,l.Profiler=me,l.PureComponent=g,l.StrictMode=ge,l.Suspense=ve,l.ViewTransition=_e,l.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE=h,l.__COMPILER_RUNTIME=P,l.act=function(e){var t=h.actQueue,n=W;W++;var o=h.actQueue=t!==null?t:[],s=!1;try{var v=e()}catch(w){h.thrownErrors.push(w)}if(0<h.thrownErrors.length)throw q(t,n),e=U(h.thrownErrors),h.thrownErrors.length=0,e;if(v!==null&&typeof v==="object"&&typeof v.then==="function"){var i=v;return Ue(function(){s||G||(G=!0,console.error("You called act(async () => ...) without await. This could lead to unexpected testing behaviour, interleaving multiple act calls and mixing their scopes. You should - await act(async () => ...);"))}),{then:function(w,O){s=!0,i.then(function(M){if(q(t,n),n===0){try{Q(o),F(function(){return K(M,w,O)})}catch(rt){h.thrownErrors.push(rt)}if(0<h.thrownErrors.length){var tt=U(h.thrownErrors);h.thrownErrors.length=0,O(tt)}}else w(M)},function(M){q(t,n),0<h.thrownErrors.length?(M=U(h.thrownErrors),h.thrownErrors.length=0,O(M)):O(M)})}}}var f=v;if(q(t,n),n===0&&(Q(o),o.length!==0&&Ue(function(){s||G||(G=!0,console.error("A component suspended inside an `act` scope, but the `act` call was not awaited. When testing React components that depend on asynchronous data, you must await the result:\n\nawait act(() => ...)"))}),h.actQueue=null),0<h.thrownErrors.length)throw e=U(h.thrownErrors),h.thrownErrors.length=0,e;return{then:function(w,O){s=!0,n===0?(h.actQueue=o,F(function(){return K(f,w,O)})):w(f)}}},l.addTransitionType=fe,l.cache=function(e){return function(){return e.apply(null,arguments)}},l.cacheSignal=function(){return null},l.captureOwnerStack=function(){var e=h.getCurrentStack;return e===null?null:e()},l.cloneElement=function(e,t,n){if(e===null||e===void 0)throw Error("The argument must be a React element, but you passed "+e+".");var o=Se({},e.props),{key:s,_owner:v}=e;if(t!=null){var i;e:{if(X.call(t,"ref")&&(i=Object.getOwnPropertyDescriptor(t,"ref").get)&&i.isReactWarning){i=!1;break e}i=t.ref!==void 0}i&&(v=_()),x(t)&&(E(t.key),s=""+t.key);for(f in t)!X.call(t,f)||f==="key"||f==="__self"||f==="__source"||f==="ref"&&t.ref===void 0||(o[f]=t[f])}var f=arguments.length-2;if(f===1)o.children=n;else if(1<f){i=Array(f);for(var w=0;w<f;w++)i[w]=arguments[w+2];o.children=i}o=z(e.type,s,o,v,e._debugStack,e._debugTask);for(s=2;s<arguments.length;s++)le(arguments[s]);return o},l.createContext=function(e){return e={$$typeof:ye,_currentValue:e,_currentValue2:e,_threadCount:0,Provider:null,Consumer:null},e.Provider=e,e.Consumer={$$typeof:ee,_context:e},e._currentRenderer=null,e._currentRenderer2=null,e},l.createElement=function(e,t,n){for(var o=2;o<arguments.length;o++)le(arguments[o]);var s;o={};var v=null;if(t!=null)for(s in ke||!("__self"in t)||"key"in t||(ke=!0,console.warn("Your app (or one of its dependencies) is using an outdated JSX transform. Update to the modern JSX transform for faster performance: https://react.dev/link/new-jsx-transform")),x(t)&&(E(t.key),v=""+t.key),t)X.call(t,s)&&s!=="key"&&s!=="__self"&&s!=="__source"&&(o[s]=t[s]);var i=arguments.length-2;if(i===1)o.children=n;else if(1<i){for(var f=Array(i),w=0;w<i;w++)f[w]=arguments[w+2];Object.freeze&&Object.freeze(f),o.children=f}if(e&&e.defaultProps)for(s in i=e.defaultProps,i)o[s]===void 0&&(o[s]=i[s]);return v&&S(o,typeof e==="function"?e.displayName||e.name||"Unknown":e),(s=1e4>h.recentlyCreatedOwnerStacks++)?(f=Error.stackTraceLimit,Error.stackTraceLimit=10,i=Error("react-stack-top-frame"),Error.stackTraceLimit=f):i=Ze,z(e,v,o,_(),i,s?xe(T(e)):et)},l.createRef=function(){var e={current:null};return Object.seal(e),e},l.forwardRef=function(e){e!=null&&e.$$typeof===te?console.error("forwardRef requires a render function but received a `memo` component. Instead of forwardRef(memo(...)), use memo(forwardRef(...))."):typeof e!=="function"?console.error("forwardRef requires a render function but was given %s.",e===null?"null":typeof e):e.length!==0&&e.length!==2&&console.error("forwardRef render functions accept exactly two parameters: props and ref. %s",e.length===1?"Did you forget to use the ref parameter?":"Any additional parameter will be undefined."),e!=null&&e.defaultProps!=null&&console.error("forwardRef render functions do not support defaultProps. Did you accidentally pass a React component?");var t={$$typeof:we,render:e},n;return Object.defineProperty(t,"displayName",{enumerable:!1,configurable:!0,get:function(){return n},set:function(o){n=o,e.name||e.displayName||(Object.defineProperty(e,"name",{value:o}),e.displayName=o)}}),t},l.isValidElement=C,l.lazy=function(e){e={_status:-1,_result:e};var t={$$typeof:N,_payload:e,_init:Ke},n={name:"lazy",start:-1,end:-1,value:null,owner:null,debugStack:Error("react-stack-top-frame"),debugTask:console.createTask?console.createTask("lazy()"):null};return e._ioInfo=n,t._debugInfo=[{awaited:n}],t},l.memo=function(e,t){e==null&&console.error("memo: The first argument must be a component. Instead received: %s",e===null?"null":typeof e),t={$$typeof:te,type:e,compare:t===void 0?null:t};var n;return Object.defineProperty(t,"displayName",{enumerable:!1,configurable:!0,get:function(){return n},set:function(o){n=o,e.name||e.displayName||(Object.defineProperty(e,"name",{value:o}),e.displayName=o)}}),t},l.startTransition=pe,l.unstable_useCacheRefresh=function(){return b().useCacheRefresh()},l.use=function(e){return b().use(e)},l.useActionState=function(e,t,n){return b().useActionState(e,t,n)},l.useCallback=function(e,t){return b().useCallback(e,t)},l.useContext=function(e){var t=b();return e.$$typeof===ee&&console.error("Calling useContext(Context.Consumer) is not supported and will cause bugs. Did you mean to call useContext(Context) instead?"),t.useContext(e)},l.useDebugValue=function(e,t){return b().useDebugValue(e,t)},l.useDeferredValue=function(e,t){return b().useDeferredValue(e,t)},l.useEffect=function(e,t){return e==null&&console.warn("React Hook useEffect requires an effect callback. Did you forget to pass a callback to the hook?"),b().useEffect(e,t)},l.useEffectEvent=function(e){return b().useEffectEvent(e)},l.useId=function(){return b().useId()},l.useImperativeHandle=function(e,t,n){return b().useImperativeHandle(e,t,n)},l.useInsertionEffect=function(e,t){return e==null&&console.warn("React Hook useInsertionEffect requires an effect callback. Did you forget to pass a callback to the hook?"),b().useInsertionEffect(e,t)},l.useLayoutEffect=function(e,t){return e==null&&console.warn("React Hook useLayoutEffect requires an effect callback. Did you forget to pass a callback to the hook?"),b().useLayoutEffect(e,t)},l.useMemo=function(e,t){return b().useMemo(e,t)},l.useOptimistic=function(e,t){return b().useOptimistic(e,t)},l.useReducer=function(e,t,n){return b().useReducer(e,t,n)},l.useRef=function(e){return b().useRef(e)},l.useState=function(e){return b().useState(e)},l.useSyncExternalStore=function(e,t,n){return b().useSyncExternalStore(e,t,n)},l.useTransition=function(){return b().useTransition()},l.version="19.3.1",typeof __REACT_DEVTOOLS_GLOBAL_HOOK__<"u"&&typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop==="function"&&__REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop(Error())})()});var Be=He(function(ft,Xe){Xe.exports=qe()});var gt={};pt(gt,{initFirstPartyWrapper:()=>j,uninstallFirstPartyWrapper:()=>Ge});var se="/_tatvic/relay",ae="x-tatvic-target",ie=["google-analytics.com","analytics.google.com","googletagmanager.com","stats.g.doubleclick.net","googleadservices.com","googleads.g.doubleclick.net","pagead2.googlesyndication.com","google.com","stape.io","stape.net","a.run.app","appspot.com","connect.facebook.net","facebook.com","graph.facebook.com","facebook.net","clarity.ms","c.bing.com","bat.bing.com","analytics.tiktok.com","tiktok.com","static.hotjar.com","script.hotjar.com","in.hotjar.com","static.ads-twitter.com","ads-twitter.com","snap.licdn.com","px.ads.linkedin.com","ct.pinterest.com","pintrk.com","sc-static.net","tr.snapchat.com","static.criteo.net","sslwidget.criteo.com","widgets.outbrain.com","tr.outbrain.com","cdn.taboola.com","trc.taboola.com","segment.io","api.segment.io","cdn.segment.com","mixpanel.com","api-js.mixpanel.com","amplitude.com","api.amplitude.com","api2.amplitude.com","heapanalytics.com","cdn.heapanalytics.com","posthog.com","app.posthog.com","eu.posthog.com"],Fe=["api.stripe.com","js.stripe.com","m.stripe.network","paypal.com","sandbox.paypal.com","razorpay.com","checkout.razorpay.com","square.com","squareup.com","auth0.com","clerk.dev","clerk.com","supabase.co","firebaseio.com","accounts.google.com","appleid.apple.com","amazonaws.com","googleapis.com","cloudflare.com"];class ce{targetDomains;excludeDomains;proxyEndpoint;targetHeaderName;obfuscateTarget;routingMode;debug;constructor(r={}){this.targetDomains=r.targetDomains??ie,this.excludeDomains=r.excludeDomains??Fe,this.proxyEndpoint=r.proxyEndpoint??se,this.targetHeaderName=(r.targetHeaderName??ae).toLowerCase(),this.obfuscateTarget=r.obfuscateTarget??!1,this.routingMode=r.routingMode??"auto",this.debug=r.debug??!1}shouldProxy(r){let c=this.parseUrl(r);if(!c)return!1;let d=c.hostname.toLowerCase();if(typeof window<"u"&&window.location?.origin&&c.origin===window.location.origin){if(c.pathname.startsWith(this.proxyEndpoint))return!1}for(let a of this.excludeDomains)if(this.matchesRule(d,a))return!1;for(let a of this.targetDomains)if(this.matchesRule(d,a))return!0;return!1}encodeTarget(r){if(this.obfuscateTarget){if(typeof btoa<"u")return btoa(r);return Buffer.from(r).toString("base64")}return r}getProxiedRequestInfo(r,c){let d=c??(this.routingMode==="auto"?"header":this.routingMode),a=this.encodeTarget(r);if(d==="query"){let u=this.proxyEndpoint.includes("?")?"&":"?";return{proxyUrl:`${this.proxyEndpoint}${u}_tgt=${encodeURIComponent(a)}`}}return{proxyUrl:this.proxyEndpoint,headerName:this.targetHeaderName,headerValue:a}}log(...r){if(this.debug)console.log("[Tatvic Proxy SDK]",...r)}matchesRule(r,c){if(c instanceof RegExp)return c.test(r);let d=c.toLowerCase().trim();return r===d||r.endsWith(`.${d}`)}parseUrl(r){try{if(typeof window<"u"&&window.location?.origin)return new URL(r,window.location.origin);return new URL(r)}catch{return null}}}class ue{matcher;options;isInstalled=!1;originalFetch;originalXhrOpen;originalXhrSend;originalSendBeacon;originalScriptSrcDesc;originalImageSrcDesc;constructor(r={}){this.options=r,this.matcher=new ce(r)}install(){if(this.isInstalled||typeof window>"u")return;if(this.options.enabled===!1){this.matcher.log("SDK disabled via configuration.");return}this.patchFetch(),this.patchXhr(),this.patchSendBeacon(),this.patchScriptElements(),this.patchImageElements(),this.isInstalled=!0,this.matcher.log("First-party request interceptor active.")}uninstall(){if(!this.isInstalled||typeof window>"u")return;if(this.originalFetch)window.fetch=this.originalFetch,this.originalFetch=void 0;if(this.originalXhrOpen)XMLHttpRequest.prototype.open=this.originalXhrOpen,this.originalXhrOpen=void 0;if(this.originalXhrSend)XMLHttpRequest.prototype.send=this.originalXhrSend,this.originalXhrSend=void 0;if(this.originalSendBeacon&&navigator.sendBeacon)navigator.sendBeacon=this.originalSendBeacon,this.originalSendBeacon=void 0;if(this.originalScriptSrcDesc&&typeof HTMLScriptElement<"u")Object.defineProperty(HTMLScriptElement.prototype,"src",this.originalScriptSrcDesc),this.originalScriptSrcDesc=void 0;if(this.originalImageSrcDesc&&typeof HTMLImageElement<"u")Object.defineProperty(HTMLImageElement.prototype,"src",this.originalImageSrcDesc),this.originalImageSrcDesc=void 0;this.isInstalled=!1,this.matcher.log("First-party request interceptor uninstalled.")}patchFetch(){if(!window.fetch)return;this.originalFetch=window.fetch.bind(window);let r=this.originalFetch,c=this.matcher,d=async(a,u)=>{let g;if(typeof a==="string")g=a;else if(a instanceof URL)g=a.toString();else if(typeof Request<"u"&&a instanceof Request)g=a.url;else g=String(a);if(!c.shouldProxy(g))return r(a,u);c.log("Intercepted fetch:",g);let m=u?.mode==="no-cors"||typeof Request<"u"&&a instanceof Request&&a.mode==="no-cors",p=c.getProxiedRequestInfo(g,m?"query":void 0),E=this.options.serverPreviewToken||this.detectPreviewToken();if(typeof Request<"u"&&a instanceof Request){let _=new Headers(a.headers);if(u?.headers)new Headers(u.headers).forEach((x,S)=>_.set(S,x));if(p.headerName&&p.headerValue&&!m)_.set(p.headerName,p.headerValue);if(E&&!_.has("x-gtm-server-preview"))_.set("x-gtm-server-preview",E);let R=new Request(p.proxyUrl,{method:u?.method??a.method,headers:_,body:u?.body??a.body,mode:m?"cors":u?.mode??a.mode??"cors",credentials:u?.credentials??a.credentials,cache:u?.cache??a.cache,redirect:u?.redirect??a.redirect,referrer:u?.referrer??a.referrer,integrity:u?.integrity??a.integrity,keepalive:u?.keepalive??a.keepalive,signal:u?.signal??a.signal});return r(R)}let y=new Headers(u?.headers);if(p.headerName&&p.headerValue&&!m)y.set(p.headerName,p.headerValue);if(E&&!y.has("x-gtm-server-preview"))y.set("x-gtm-server-preview",E);let T={...u,headers:y,mode:m?"cors":u?.mode??"cors"};return r(p.proxyUrl,T)};Object.assign(d,r),window.fetch=d}patchXhr(){if(typeof XMLHttpRequest>"u")return;this.originalXhrOpen=XMLHttpRequest.prototype.open,this.originalXhrSend=XMLHttpRequest.prototype.send;let r=this.originalXhrOpen,c=this.originalXhrSend,d=this.matcher,a=()=>this.options.serverPreviewToken||this.detectPreviewToken();XMLHttpRequest.prototype.open=function(u,g,m=!0,p,E){let y=g.toString();if(d.shouldProxy(y)){d.log("Intercepted XHR:",y);let T=d.getProxiedRequestInfo(y),_=a();return this.__tatvicMeta={isProxied:!0,originalUrl:y,headerName:T.headerName,headerValue:T.headerValue,previewToken:_},r.call(this,u,T.proxyUrl,m,p,E)}return this.__tatvicMeta={isProxied:!1},r.call(this,u,g,m,p,E)},XMLHttpRequest.prototype.send=function(u){if(this.__tatvicMeta?.isProxied){let{headerName:g,headerValue:m,previewToken:p}=this.__tatvicMeta;if(g&&m)try{this.setRequestHeader(g,m)}catch(E){d.log("Failed to set proxy header on XHR:",E)}if(p)try{this.setRequestHeader("x-gtm-server-preview",p)}catch(E){d.log("Failed to set preview header on XHR:",E)}}return c.call(this,u)}}patchSendBeacon(){if(typeof navigator>"u"||!navigator.sendBeacon)return;this.originalSendBeacon=navigator.sendBeacon.bind(navigator);let r=this.originalSendBeacon,c=this.matcher,d=this.options.polyfillBeaconWithKeepalive!==!1;navigator.sendBeacon=(a,u)=>{let g=a.toString();if(!c.shouldProxy(g))return r(a,u);if(c.log("Intercepted sendBeacon:",g),d&&typeof window.fetch==="function"){let y=c.getProxiedRequestInfo(g),T=this.options.serverPreviewToken||this.detectPreviewToken(),_=new Headers;if(y.headerName&&y.headerValue)_.set(y.headerName,y.headerValue);if(T)_.set("x-gtm-server-preview",T);try{return window.fetch(y.proxyUrl,{method:"POST",body:u,headers:_,keepalive:!0,mode:"cors"}).catch((R)=>{c.log("Async sendBeacon keepalive fetch error:",R)}),!0}catch{}}let p=c.getProxiedRequestInfo(g,"query").proxyUrl,E=this.options.serverPreviewToken||this.detectPreviewToken();if(E)p+=(p.includes("?")?"&":"?")+"_gtm_server_preview="+encodeURIComponent(E);return r(p,u)}}patchScriptElements(){if(typeof HTMLScriptElement>"u")return;let r=Object.getOwnPropertyDescriptor(HTMLScriptElement.prototype,"src");if(!r||!r.set||!r.get)return;this.originalScriptSrcDesc=r;let c=this.matcher,{set:d,get:a}=r;Object.defineProperty(HTMLScriptElement.prototype,"src",{set(u){if(typeof u==="string"&&(u.includes("googletagmanager.com/gtm.js")||u.includes("/_tatvic/gtm.js")||u.includes("/_tatvic/loader.js")))try{let g=typeof window<"u"&&window.location?window.location.search:"",m=new URLSearchParams(g),p=new URL(u,typeof window<"u"&&window.location?window.location.origin:"http://localhost"),E=p.searchParams.get("cid")||p.searchParams.get("container")||p.searchParams.get("tag")||p.searchParams.get("id")||"GTM-T32XGF8F",y=new URLSearchParams;y.set("cid",E),p.searchParams.forEach((_,R)=>{if(R!=="id"&&R!=="cid"&&R!=="container"&&R!=="tag")y.set(R,_)});for(let _ of["gtm_debug","gtm_auth","gtm_preview","gtm_cookies_win"])if(m.has(_)&&!y.has(_))y.set(_,m.get(_));let T=`/_tatvic/loader.js?${y.toString()}`;return c.log("Morphed GTM script element to stealth loader:",u,"->",T),d.call(this,T)}catch{}if(c.shouldProxy(u)){let g=c.getProxiedRequestInfo(u,"query");return c.log("Intercepted dynamic script element:",u,"->",g.proxyUrl),d.call(this,g.proxyUrl)}return d.call(this,u)},get(){return a.call(this)},configurable:!0,enumerable:!0})}patchImageElements(){if(typeof HTMLImageElement>"u")return;let r=Object.getOwnPropertyDescriptor(HTMLImageElement.prototype,"src");if(!r||!r.set||!r.get)return;this.originalImageSrcDesc=r;let c=this.matcher,{set:d,get:a}=r;Object.defineProperty(HTMLImageElement.prototype,"src",{set(u){if(c.shouldProxy(u)){let g=c.getProxiedRequestInfo(u,"query");return c.log("Intercepted tracking pixel image:",u,"->",g.proxyUrl),d.call(this,g.proxyUrl)}return d.call(this,u)},get(){return a.call(this)},configurable:!0,enumerable:!0})}detectPreviewToken(){if(typeof window>"u"||!window.location)return;try{return new URLSearchParams(window.location.search).get("gtm_server_preview")||void 0}catch{return}}}class $e extends(typeof HTMLElement<"u"?HTMLElement:Object){connectedCallback(){if(typeof window>"u")return;if(this.style)this.style.display="contents";let r=this.getAttribute?this.getAttribute("endpoint")??void 0:void 0,c=this.getAttribute?this.getAttribute("debug")==="true":!1,d=this.getAttribute?this.getAttribute("server-preview")||this.getAttribute("server-preview-token")||void 0:void 0,a={};if(r)a.proxyEndpoint=r;if(c)a.debug=!0;if(d)a.serverPreviewToken=d;j(a);let u=()=>{try{if(this.querySelectorAll&&typeof document<"u")this.querySelectorAll("script[src]").forEach((m)=>{let p=m.getAttribute("src");if(!p)return;if(p.includes("googletagmanager.com/gtm.js")||p.includes("/_tatvic/gtm.js")||p.includes("/_tatvic/loader.js")){let E=typeof window<"u"&&window.location?window.location.search:"",y=new URLSearchParams(E),T=new URL(p,typeof window<"u"&&window.location?window.location.origin:"http://localhost"),_=T.searchParams.get("cid")||T.searchParams.get("container")||T.searchParams.get("tag")||T.searchParams.get("id")||"GTM-T32XGF8F",R=new URLSearchParams;R.set("cid",_),T.searchParams.forEach((S,A)=>{if(A!=="id"&&A!=="cid"&&A!=="container"&&A!=="tag")R.set(A,S)});for(let S of["gtm_debug","gtm_auth","gtm_preview","gtm_cookies_win"])if(y.has(S)&&!R.has(S))R.set(S,y.get(S));let x=`/_tatvic/loader.js?${R.toString()}`;if(m.getAttribute("src")!==x){m.setAttribute("src",x);let S=document.createElement("script");S.async=m.hasAttribute("async"),S.src=x,m.parentNode?.replaceChild(S,m)}return}if(!p.startsWith("/_tatvic/")){let E=(a.proxyEndpoint||"/_tatvic/relay").includes("?")?"&":"?",y=`${a.proxyEndpoint||"/_tatvic/relay"}${E}_tgt=${encodeURIComponent(p)}`;m.setAttribute("src",y)}})}catch{}};if(u(),typeof queueMicrotask<"u")queueMicrotask(u);else if(typeof setTimeout<"u")setTimeout(u,0)}}if(typeof window<"u"&&typeof customElements<"u"&&!customElements.get("tatvic-wrapper"))try{customElements.define("tatvic-wrapper",$e)}catch{}var We=ct(Be(),1);var k=null;function j(r={}){if(k)k.uninstall();return k=new ue(r),k.install(),k}function Ge(){if(k)k.uninstall(),k=null}if(typeof window<"u")j();})();
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Configuration options for the First-Party Proxy SDK.
|
|
3
|
+
*/
|
|
4
|
+
export interface ProxySdkOptions {
|
|
5
|
+
/**
|
|
6
|
+
* The first-party proxy endpoint on your own server.
|
|
7
|
+
* Example: "/api/v1/relay" or "https://yourdomain.com/api/v1/relay"
|
|
8
|
+
* Default: "/api/v1/relay"
|
|
9
|
+
*/
|
|
10
|
+
proxyEndpoint?: string;
|
|
11
|
+
/**
|
|
12
|
+
* List of external domains or RegExp patterns to intercept and route through the first-party proxy.
|
|
13
|
+
* Example: ["google-analytics.com", "analytics.google.com", "connect.facebook.net"]
|
|
14
|
+
*/
|
|
15
|
+
targetDomains?: (string | RegExp)[];
|
|
16
|
+
/**
|
|
17
|
+
* Domains to explicitly exclude from interception (e.g., payment gateways, auth).
|
|
18
|
+
* Example: ["api.stripe.com", "auth0.com"]
|
|
19
|
+
*/
|
|
20
|
+
excludeDomains?: (string | RegExp)[];
|
|
21
|
+
/**
|
|
22
|
+
* Header name used to transmit the upstream destination to the first-party proxy.
|
|
23
|
+
* Default: "x-relay-target"
|
|
24
|
+
*/
|
|
25
|
+
targetHeaderName?: string;
|
|
26
|
+
/**
|
|
27
|
+
* Whether to obfuscate (Base64-encode) the target URL in headers/query params
|
|
28
|
+
* to avoid basic string inspection by aggressive content filters.
|
|
29
|
+
* Default: false
|
|
30
|
+
*/
|
|
31
|
+
obfuscateTarget?: boolean;
|
|
32
|
+
/**
|
|
33
|
+
* Strategy for transmitting the upstream target to the proxy:
|
|
34
|
+
* - "header": Uses custom HTTP header (recommended for fetch/XHR)
|
|
35
|
+
* - "query": Appends target as a query parameter (e.g. ?_tgt=...)
|
|
36
|
+
* - "auto": Uses header for fetch/XHR and query parameter for sendBeacon.
|
|
37
|
+
* Default: "auto"
|
|
38
|
+
*/
|
|
39
|
+
routingMode?: 'header' | 'query' | 'auto';
|
|
40
|
+
/**
|
|
41
|
+
* If true, converts navigator.sendBeacon calls to fetch with { keepalive: true }.
|
|
42
|
+
* This allows custom headers and more reliable delivery.
|
|
43
|
+
* Default: true
|
|
44
|
+
*/
|
|
45
|
+
polyfillBeaconWithKeepalive?: boolean;
|
|
46
|
+
/**
|
|
47
|
+
* Enable debug console logging.
|
|
48
|
+
* Default: false
|
|
49
|
+
*/
|
|
50
|
+
debug?: boolean;
|
|
51
|
+
/**
|
|
52
|
+
* Optional Server-Side GTM Preview & Debug token (from Tag Assistant "Send requests manually").
|
|
53
|
+
* When provided, or detected in URL query params (?gtm_server_preview=... or ?gtm_debug=...),
|
|
54
|
+
* this token is automatically attached to upstream requests as the `X-Gtm-Server-Preview` header.
|
|
55
|
+
*/
|
|
56
|
+
serverPreviewToken?: string;
|
|
57
|
+
/**
|
|
58
|
+
* Whether the interceptor is enabled.
|
|
59
|
+
* Default: true
|
|
60
|
+
*/
|
|
61
|
+
enabled?: boolean;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Options for the server-side proxy handler.
|
|
65
|
+
*/
|
|
66
|
+
export interface ServerProxyOptions {
|
|
67
|
+
/**
|
|
68
|
+
* Server-Side GTM Preview token to forward upstream if not provided by client.
|
|
69
|
+
*/
|
|
70
|
+
serverPreviewToken?: string;
|
|
71
|
+
/**
|
|
72
|
+
* Optional Server-Side GTM container URL (e.g. "https://tpozgxiu.usu.stape.io").
|
|
73
|
+
* When configured, any outgoing Google Analytics collect requests (google-analytics.com/g/collect)
|
|
74
|
+
* are automatically routed to this server container URL.
|
|
75
|
+
*/
|
|
76
|
+
serverContainerUrl?: string;
|
|
77
|
+
/**
|
|
78
|
+
* Whitelist of permitted upstream target domains.
|
|
79
|
+
* Crucial security control to prevent Server-Side Request Forgery (SSRF).
|
|
80
|
+
* Defaults to preconfigured list of all major analytics & tracking services.
|
|
81
|
+
*/
|
|
82
|
+
allowedDomains?: (string | RegExp)[];
|
|
83
|
+
/**
|
|
84
|
+
* Header name containing the upstream target URL.
|
|
85
|
+
* Default: "x-relay-target"
|
|
86
|
+
*/
|
|
87
|
+
targetHeaderName?: string;
|
|
88
|
+
/**
|
|
89
|
+
* Whether targets were obfuscated (Base64 encoded).
|
|
90
|
+
* Default: false
|
|
91
|
+
*/
|
|
92
|
+
obfuscateTarget?: boolean;
|
|
93
|
+
/**
|
|
94
|
+
* Timeout in milliseconds for upstream requests.
|
|
95
|
+
* Default: 10000 (10s)
|
|
96
|
+
*/
|
|
97
|
+
timeoutMs?: number;
|
|
98
|
+
/**
|
|
99
|
+
* Headers to strip from upstream forwarding for privacy/security.
|
|
100
|
+
* Default: ['host', 'cookie', 'authorization', 'connection']
|
|
101
|
+
*/
|
|
102
|
+
stripHeaders?: string[];
|
|
103
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { ProxySdkOptions } from './types.js';
|
|
2
|
+
export declare class UrlMatcher {
|
|
3
|
+
private targetDomains;
|
|
4
|
+
private excludeDomains;
|
|
5
|
+
private proxyEndpoint;
|
|
6
|
+
private targetHeaderName;
|
|
7
|
+
private obfuscateTarget;
|
|
8
|
+
private routingMode;
|
|
9
|
+
private debug;
|
|
10
|
+
constructor(options?: ProxySdkOptions);
|
|
11
|
+
/**
|
|
12
|
+
* Determine if a given URL should be routed through the first-party proxy.
|
|
13
|
+
*/
|
|
14
|
+
shouldProxy(urlStr: string): boolean;
|
|
15
|
+
/**
|
|
16
|
+
* Encodes the destination target according to options.
|
|
17
|
+
*/
|
|
18
|
+
encodeTarget(targetUrl: string): string;
|
|
19
|
+
/**
|
|
20
|
+
* Generates the proxy request information.
|
|
21
|
+
*/
|
|
22
|
+
getProxiedRequestInfo(originalUrl: string, forcedMode?: 'header' | 'query'): {
|
|
23
|
+
proxyUrl: string;
|
|
24
|
+
headerName?: string;
|
|
25
|
+
headerValue?: string;
|
|
26
|
+
};
|
|
27
|
+
log(...args: unknown[]): void;
|
|
28
|
+
private matchesRule;
|
|
29
|
+
private parseUrl;
|
|
30
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,71 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tatvic-implementation-sdk",
|
|
3
|
-
"version": "
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Universal First-Party Analytics Proxy & Morphed GTM Loader SDK for Web, React, Next.js, and Node",
|
|
5
|
+
"main": "./dist/index.js",
|
|
6
|
+
"module": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"type": "module",
|
|
9
|
+
"files": [
|
|
10
|
+
"dist",
|
|
11
|
+
"README.md"
|
|
12
|
+
],
|
|
13
|
+
"exports": {
|
|
14
|
+
".": {
|
|
15
|
+
"types": "./dist/index.d.ts",
|
|
16
|
+
"import": "./dist/index.js"
|
|
17
|
+
},
|
|
18
|
+
"./react": {
|
|
19
|
+
"types": "./dist/react.d.ts",
|
|
20
|
+
"import": "./dist/index.js"
|
|
21
|
+
},
|
|
22
|
+
"./next": {
|
|
23
|
+
"types": "./dist/next.d.ts",
|
|
24
|
+
"import": "./dist/index.js"
|
|
25
|
+
},
|
|
26
|
+
"./express": {
|
|
27
|
+
"types": "./dist/express.d.ts",
|
|
28
|
+
"import": "./dist/index.js"
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
"scripts": {
|
|
32
|
+
"build:bundle": "bun build src/bundle.ts --target=browser --format=iife --outfile=dist/tatvic.js --minify",
|
|
33
|
+
"build:esm": "bun build src/index.ts --target=browser --format=esm --outfile=dist/index.js --external react",
|
|
34
|
+
"build:types": "bun x tsc -p tsconfig.build.json",
|
|
35
|
+
"build": "bun run build:bundle && bun run build:esm && bun run build:types",
|
|
36
|
+
"prepublishOnly": "bun run test && bun run build",
|
|
37
|
+
"test": "bun test",
|
|
38
|
+
"typecheck": "bun x tsc --noEmit"
|
|
39
|
+
},
|
|
40
|
+
"devDependencies": {
|
|
41
|
+
"@types/bun": "latest",
|
|
42
|
+
"@types/react": "19.3.0",
|
|
43
|
+
"@types/react-dom": "^19.3.0",
|
|
44
|
+
"react": "19.3.1",
|
|
45
|
+
"react-dom": "^19.3.1"
|
|
46
|
+
},
|
|
47
|
+
"peerDependencies": {
|
|
48
|
+
"react": ">=18.0.0"
|
|
49
|
+
},
|
|
50
|
+
"peerDependenciesMeta": {
|
|
51
|
+
"react": {
|
|
52
|
+
"optional": true
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
"repository": {
|
|
56
|
+
"type": "git",
|
|
57
|
+
"url": "https://github.com/jimitchavdadev/tatvic-implementation-sdk.git"
|
|
58
|
+
},
|
|
59
|
+
"keywords": [
|
|
60
|
+
"gtm",
|
|
61
|
+
"sgtm",
|
|
62
|
+
"google-tag-manager",
|
|
63
|
+
"ad-blocker-bypass",
|
|
64
|
+
"first-party-data",
|
|
65
|
+
"ga4",
|
|
66
|
+
"server-side-tagging",
|
|
67
|
+
"analytics"
|
|
68
|
+
],
|
|
69
|
+
"author": "Jimit Chavda <jimit@tatvic.com>",
|
|
70
|
+
"license": "MIT"
|
|
71
|
+
}
|