import type { DiagramDocument } from '../types'; import type { HostAdapter } from './HostAdapter'; /** * postMessage handshake with the Bitrix bridge script (see * docs/bitrix-integration.md for the PHP side). `targetOrigin` is always a * concrete origin, never '*' — matches the security requirement from the * original design doc. */ const READY_MESSAGE = 'diagram:ready'; const INIT_MESSAGE = 'diagram:init'; const CHANGE_MESSAGE = 'diagram:change'; function getBitrixOrigin(): string { const origin = import.meta.env.VITE_BITRIX_ORIGIN; if (!origin) { throw new Error( 'VITE_BITRIX_ORIGIN is not set. The bridge needs a concrete parent origin — postMessage must never target "*".', ); } return origin; } export function createBitrixAdapter(): HostAdapter { const targetOrigin = getBitrixOrigin(); return { onReady(callback) { let delivered = false; function onMessage(event: MessageEvent) { if (event.origin !== targetOrigin || event.source !== window.parent) return; if (delivered || event.data?.type !== INIT_MESSAGE) return; delivered = true; window.removeEventListener('message', onMessage); const payload = event.data.payload as string | null | undefined; if (!payload) { callback(null); return; } try { callback(JSON.parse(payload) as DiagramDocument); } catch { callback(null); } } window.addEventListener('message', onMessage); window.parent.postMessage({ type: READY_MESSAGE }, targetOrigin); }, onChange(doc) { window.parent.postMessage({ type: CHANGE_MESSAGE, payload: JSON.stringify(doc) }, targetOrigin); }, }; }