PageSourceSearch

https://mariniosiptvv.com/wp-content/plugins/ai-chatbot-live-chat-…/assets/ai-chatbot-cart-bridge.js?ver=3.0.3

js mariniosiptvv.com collected 2026-09-26 14:59:24 UTC 6,798 bytes, 206 lines download raw bytes

1/**
2 * AI Chatbot – WooCommerce Cart Bridge
3 *
4 * Runs on the WordPress parent page (same origin as WooCommerce).
5 * Listens for postMessage requests from the chatbot iframe (agents.robofy.ai)
6 * and proxies WooCommerce Store API cart calls back, forwarding the WC nonce
7 * and session cookies that are inaccessible from the cross-origin iframe.
8 *
9 * Incoming message types (from iframe):
10 *   { type: 'wc_bridge_ping' }
11 *   { type: 'wc_cart_request', requestId: '<id>', action: 'get_cart' }
12 *   { type: 'wc_cart_request', requestId: '<id>', action: 'add_item',    payload: { product_id, quantity, variation } }
13 *   { type: 'wc_cart_request', requestId: '<id>', action: 'remove_item', payload: { cart_item_key } }
14 *
15 * Outgoing message types (to iframe):
16 *   { type: 'wc_bridge_ready',   nonce: '<nonce>' }
17 *   { type: 'wc_cart_response',  requestId: '<id>', success: true,  data: { ... } }
18 *   { type: 'wc_cart_response',  requestId: '<id>', success: false, error: '<message>' }
19 */
20( function () {
21	'use strict';
22
23	// Config is injected by PHP via wp_localize_script.
24	var config = window.aiChatbotWooBridge;
25	if ( ! config || ! config.iframeOrigin || ! config.nonce || ! config.storeApiUrl ) {
26		return;
27	}
28
29	var iframeOrigin = config.iframeOrigin; // e.g. 'https://agents.robofy.ai'
30	var nonce        = config.nonce;
31	var storeApiUrl  = config.storeApiUrl.replace( /\/$/, '' ); // e.g. 'https://example.com/wp-json/wc/store/v1'
32
33	/**
34	 * Build standard headers for every WC Store API request.
35	 */
36	function buildHeaders() {
37		return {
38			'Content-Type'        : 'application/json',
39			'Nonce'               : nonce,
40			'X-WC-Store-API-Nonce': nonce
41		};
42	}
43
44	/**
45	 * Send a postMessage back to the iframe.
46	 *
47	 * @param {Window} source  The iframe's contentWindow (event.source).
48	 * @param {Object} payload The message object to send.
49	 */
50	function reply( source, payload ) {
51		if ( source && typeof source.postMessage === 'function' ) {
52			source.postMessage( payload, iframeOrigin );
53		}
54	}
55
56	/**
57	 * Parse an error message out of a WC Store API error response.
58	 *
59	 * @param  {Response} response The fetch Response object.
60	 * @return {Promise<string>}
61	 */
62	function parseErrorMessage( response ) {
63		return response.json()
64			.then( function ( body ) {
65				return ( body && body.message ) ? body.message : response.statusText;
66			} )
67			.catch( function () {
68				return response.statusText || 'Unknown error';
69			} );
70	}
71
72	/**
73	 * Handle a wc_cart_request message from the iframe.
74	 *
75	 * @param {Window} source    event.source
76	 * @param {string} requestId Caller-supplied correlation ID.
77	 * @param {string} action    'get_cart' | 'add_item' | 'remove_item'
78	 * @param {Object} payload   Action-specific parameters.
79	 */
80	function handleCartRequest( source, requestId, action, payload ) {
81		var fetchOptions;
82
83		if ( action === 'get_cart' ) {
84			fetchOptions = {
85				method     : 'GET',
86				headers    : buildHeaders(),
87				credentials: 'include'
88			};
89
90			fetch( storeApiUrl + '/cart', fetchOptions )
91				.then( function ( response ) {
92					if ( response.ok ) {
93						return response.json().then( function ( data ) {
94							reply( source, { type: 'wc_cart_response', requestId: requestId, success: true, data: data } );
95						} );
96					}
97					return parseErrorMessage( response ).then( function ( msg ) {
98						reply( source, { type: 'wc_cart_response', requestId: requestId, success: false, error: msg } );
99					} );
100				} )
101				.catch( function () {
102					reply( source, { type: 'wc_cart_response', requestId: requestId, success: false, error: 'Network error' } );
103				} );
104
105		} else if ( action === 'add_item' ) {
106			var addBody = {
107				id       : payload && payload.product_id ? payload.product_id : 0,
108				quantity : payload && payload.quantity   ? payload.quantity   : 1,
109				variation: payload && payload.variation  ? payload.variation  : []
110			};
111
112			fetchOptions = {
113				method     : 'POST',
114				headers    : buildHeaders(),
115				credentials: 'include',
116				body       : JSON.stringify( addBody )
117			};
118
119			fetch( storeApiUrl + '/cart/add-item', fetchOptions )
120				.then( function ( response ) {
121					if ( response.ok ) {
122						return response.json().then( function ( data ) {
123							reply( source, { type: 'wc_cart_response', requestId: requestId, success: true, data: data } );
124						} );
125					}
126					return parseErrorMessage( response ).then( function ( msg ) {
127						reply( source, { type: 'wc_cart_response', requestId: requestId, success: false, error: msg } );
128					} );
129				} )
130				.catch( function () {
131					reply( source, { type: 'wc_cart_response', requestId: requestId, success: false, error: 'Network error' } );
132				} );
133
134		} else if ( action === 'remove_item' ) {
135			var removeBody = {
136				key: payload && payload.cart_item_key ? payload.cart_item_key : ''
137			};
138
139			fetchOptions = {
140				method     : 'POST',
141				headers    : buildHeaders(),
142				credentials: 'include',
143				body       : JSON.stringify( removeBody )
144			};
145
146			fetch( storeApiUrl + '/cart/remove-item', fetchOptions )
147				.then( function ( response ) {
148					if ( response.ok ) {
149						return response.json().then( function ( data ) {
150							reply( source, { type: 'wc_cart_response', requestId: requestId, success: true, data: data } );
151						} );
152					}
153					return parseErrorMessage( response ).then( function ( msg ) {
154						reply( source, { type: 'wc_cart_response', requestId: requestId, success: false, error: msg } );
155					} );
156				} )
157				.catch( function () {
158					reply( source, { type: 'wc_cart_response', requestId: requestId, success: false, error: 'Network error' } );
159				} );
160
161		} else {
162			reply( source, { type: 'wc_cart_response', requestId: requestId, success: false, error: 'Unknown action: ' + action } );
163		}
164	}
165
166	/**
167	 * Central message listener.
168	 */
169	function onMessage( event ) {
170		// Security: only accept messages from the trusted iframe origin.
171		if ( event.origin !== iframeOrigin ) {
172			return;
173		}
174
175		var data = event.data;
176		if ( ! data || typeof data !== 'object' ) {
177			return;
178		}
179
180		if ( data.type === 'wc_bridge_ping' ) {
181			// Handshake — let the iframe know the bridge is present and share the nonce.
182			reply( event.source, { type: 'wc_bridge_ready', nonce: nonce } );
183			return;
184		}
185
186		if ( data.type === 'wc_cart_request' ) {
187			handleCartRequest(
188				event.source,
189				data.requestId || '',
190				data.action    || '',
191				data.payload   || {}
192			);
193		}
194	}
195
196	// Attach listener. DOMContentLoaded may have already fired if the script is
197	// in the footer (in_footer = true), so use a readyState guard.
198	if ( document.readyState === 'loading' ) {
199		document.addEventListener( 'DOMContentLoaded', function () {
200			window.addEventListener( 'message', onMessage );
201		} );
202	} else {
203		window.addEventListener( 'message', onMessage );
204	}
205
206}() );

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.