/** * GoogleTagGateway feature. * * Orchestrates the client-side half of the Google Tag Gateway destination: * * 1. Maintains `window.dataLayer` / `window.gtag`. * 2. Pushes Consent Mode v2 defaults BEFORE gtag.js loads, and re-pushes * on `consent:updated` events. * 3. Injects `gtag/js?id=` from the vTilt gateway (`/gt`) so * every measurement request flows through the first-party origin. * 4. Subscribes to EVENT_CAPTURED and forwards mapped events to Ads * (`gtag('event', 'conversion', ...)`). * 5. Exposes a flat `vt.gtag(...)` passthrough for power users. * * Forwards only after `__remote_config_loaded` is true (same signal as * EventBuffer: fresh `/decide` applied, bootstrap, or fetch failure). * Captures before that are queued so we never drop events just because * `/decide` has not committed yet. After remote is ready, we install the * official `dataLayer` + `gtag` shim (`ensureDataLayer`) and forward * immediately — the shim queues until `gtag.js` loads; we do not maintain a * second SDK queue for that window. * * Feature lifecycle matches the rest of the SDK — registered with * FeatureManager via a descriptor that pulls the admin-configured shape * out of `/decide` under the `googleTag` key. */ import type { VTilt } from "../../vtilt"; import type { VTiltConfig, GoogleTagClientConfig } from "../../types"; import type { Feature, FeatureConfig } from "../../feature"; import { type GtagFn } from "./consent-bridge"; import { type GtagCall } from "./public-api"; import { type RawUserData } from "./enhanced-conversions"; export interface GoogleTagGatewayFeatureConfig extends FeatureConfig { remote?: GoogleTagClientConfig; } export interface DeliveryLogEntry { ts: number; tag_ids: string[]; event_name: string; send_to: string; status: "fired" | "dropped"; reason?: string; } export declare class GoogleTagGateway implements Feature { readonly name = "GoogleTagGateway"; private _instance; private _config; private _isStarted; private _scriptInjected; private _scriptLoaded; private _consentDefaultsPushed; private _gtag; private _publicApi; private _loaderOptions; private _unsubscribeCaptured; private _unsubscribeConsent; private _deliveryLog; private readonly _maxDeliveryLog; /** * Captures observed before `__remote_config_loaded` only. Once remote * commits, `ensureDataLayer` + gtag forward — gtag's own queue handles * ordering until `gtag.js` is on the wire. */ private readonly _pendingCaptures; constructor(instance: VTilt, config?: GoogleTagGatewayFeatureConfig); static extractConfig(config: VTiltConfig): GoogleTagGatewayFeatureConfig; get isEnabled(): boolean; get isStarted(): boolean; /** Exposed for tests and the public `vt.gtag` binding. */ get gtag(): GtagFn; get deliveryLog(): DeliveryLogEntry[]; startIfEnabled(): void; stop(): void; onConfigUpdate(config: VTiltConfig): void; /** * Set the user identifiers that power Enhanced Conversions. Values are * normalized + SHA-256 hashed client-side before being pushed to gtag, * so raw PII never leaves the browser. */ setUserData(raw: RawUserData): Promise; getRecentPublicCalls(): GtagCall[]; private _start; private _drainPending; private _pushConsentDefaultsOnce; private _subscribeCaptured; /** * Handle one captured event. Only `__remote_config_loaded === false` uses * `_pendingCaptures`. After remote commits, we boot the gtag pipeline on * demand (`startIfEnabled`) and forward — the dataLayer shim buffers until * `gtag.js` loads. */ private _handleCaptured; private _subscribeConsent; private _record; }