(function(win, doc) {
// Centralized messaging system
const TBBridgeMessaging = (function() {
// Constants for messaging
const TB_AI = {
INITIALIZE: 'TB_AI_INITIALIZE',
INITIALIZED: 'TB_AI_INITIALIZED',
ERROR: 'TB_AI_ERROR'
};
// Normalize origins and build a set
const normalize = (o) => {
try {
const u = new URL(o);
return `${u.protocol}//${u.hostname}${u.port ? ':' + u.port : ''}`;
} catch {
return '';
}
};
// Parse message data
function parseMessage(data) {
if (typeof data === 'string') {
try {
return JSON.parse(data);
} catch (e) {
console.error('[Bridge] Failed to parse message data:', e);
return null;
}
}
return data; // Already an object
}
// Safe message sending
function sendMessage(target, data, origin = '*') {
try {
// Always stringify to ensure compatibility
const message = JSON.stringify(data);
if (target && target.postMessage) {
target.postMessage(message, origin);
return true;
}
} catch (err) {
console.error('[Bridge] Error sending message:', err);
}
return false;
}
// Return public API
return {
TB_AI,
normalize,
parseMessage,
sendMessage
};
})();
// Get bridge URL from PHP config
const tbAiBridgeUrl = ''.split(',').map(url => url.trim());
if (typeof angular !== 'undefined') {
// Get plan settings from config
angular.module('app').constant('PLAN_SETTINGS', '{"userLimitColumns":{"enable_pdf":"allow_pdf_page","enable_pdf_filler":"allow_pdf_form","enable_pipe_js":"allow_pipe_js","enable_allow_restore":"allow_restore","enable_incoming_webhook":"allow_incoming_webhook","enable_email_catchers":"allow_incoming_webhook","enable_sms":"allow_sms","enable_field_auditor":"allow_field_auditor","allow_data_bridge":"allow_data_bridge","allow_plugin":"allow_plugin","allow_dynamic_field":"allow_dynamic_field","enable2fa":"allow_two_factor","enable_support":"priority_support","allow_search_v2":"allow_search_v2","enable_optimize_new_table":"allow_optimize_table"},"bypassSubscriptionPlanLimit":""}');
}
const allowedOrigins = new Set(tbAiBridgeUrl.map(TBBridgeMessaging.normalize));
const bridgePath = '/js/component-selector-bridge.js';
let loaded = false;
// Create message handler
win.addEventListener('message', (event) => {
if (!checkNested(event, 'data') || !event.data) return;
// Parse and validate message
const data = TBBridgeMessaging.parseMessage(event.data);
if (!data || data.action !== TBBridgeMessaging.TB_AI.INITIALIZE) return;
// Validate origin
const parentOrigin = TBBridgeMessaging.normalize(event.origin);
if (!allowedOrigins.has(parentOrigin)) {
console.warn('[Bridge] Untrusted origin:', parentOrigin);
return;
}
// Handle already loaded case, but allow reinitialization for app changes
if (loaded) {
// Don't just return - we want to reinitialize the bridge
// for new apps or when the app changes
// console.log('[Bridge] Script already loaded, sending initialization confirmation');
TBBridgeMessaging.sendMessage(
event.source, {
type: TBBridgeMessaging.TB_AI.INITIALIZED,
note: 'already_initialized'
},
parentOrigin
);
// return;
// We continue execution to allow the script to refresh handlers
}
// Load the bridge script
const s = doc.createElement('script');
s.src = parentOrigin.replace(/\/+$/, '') + bridgePath;
s.async = true;
// Handle successful load
s.onload = () => {
loaded = true;
console.log('[Bridge] Loaded:', s.src);
// Add a delay to ensure jQuery is available
setTimeout(() => {
TBBridgeMessaging.sendMessage(
event.source, {
type: TBBridgeMessaging.TB_AI.INITIALIZED,
status: 'success'
},
parentOrigin
);
}, 500);
};
// Handle load error
s.onerror = () => {
TBBridgeMessaging.sendMessage(
event.source, {
type: TBBridgeMessaging.TB_AI.ERROR,
error: 'load_failed'
},
parentOrigin
);
};
// Append the script
(doc.head || doc.body || doc.documentElement).appendChild(s);
});
})(window, document);