/** * DreamStack Embed SDK — ~3KB standalone * Enables embedding DreamStack apps in any website. * * Usage: * * * * Or via JS API: * DreamStack.connect('https://yourapp.com', '#container'); */ (function (root, factory) { if (typeof module !== 'undefined' && module.exports) module.exports = factory(); else root.DreamStack = factory(); })(typeof globalThis !== 'undefined' ? globalThis : this, function () { 'use strict'; // ── Iframe Embed ── function embed(src, container, options) { var opts = options || {}; var el = typeof container === 'string' ? document.querySelector(container) : container; if (!el) throw new Error('[DreamStack] Container not found: ' + container); var iframe = document.createElement('iframe'); iframe.src = src; iframe.style.border = 'none'; iframe.style.width = opts.width || '100%'; iframe.style.height = opts.height || '400px'; iframe.style.borderRadius = opts.borderRadius || '12px'; iframe.style.overflow = 'hidden'; iframe.setAttribute('sandbox', 'allow-scripts allow-same-origin'); iframe.setAttribute('loading', 'lazy'); if (opts.className) iframe.className = opts.className; el.appendChild(iframe); return { iframe: iframe, destroy: function () { el.removeChild(iframe); }, resize: function (w, h) { iframe.style.width = typeof w === 'number' ? w + 'px' : w; iframe.style.height = typeof h === 'number' ? h + 'px' : h; } }; } // ── Signal Bridge (bidirectional) ── function connect(src, container, options) { var handle = embed(src, container, options); var listeners = {}; // Listen for messages from the DreamStack app window.addEventListener('message', function (e) { if (e.source !== handle.iframe.contentWindow) return; var data = e.data; if (data && data.type === 'ds:signal') { var name = data.name; if (listeners[name]) { listeners[name].forEach(function (fn) { fn(data.value); }); } if (listeners['*']) { listeners['*'].forEach(function (fn) { fn(name, data.value); }); } } }); return { iframe: handle.iframe, destroy: handle.destroy, resize: handle.resize, // Send a signal value to the DreamStack app send: function (name, value) { handle.iframe.contentWindow.postMessage( { type: 'ds:signal', name: name, value: value }, '*' ); }, // Listen for signal changes from the DreamStack app on: function (name, fn) { if (!listeners[name]) listeners[name] = []; listeners[name].push(fn); return function () { listeners[name] = listeners[name].filter(function (f) { return f !== fn; }); }; } }; } // ── Web Component: ── if (typeof customElements !== 'undefined') { customElements.define('ds-stream', class extends HTMLElement { constructor() { super(); this._handle = null; } connectedCallback() { var src = this.getAttribute('src'); if (!src) return; var shadow = this.attachShadow({ mode: 'open' }); var wrapper = document.createElement('div'); wrapper.style.width = '100%'; wrapper.style.height = this.getAttribute('height') || '400px'; shadow.appendChild(wrapper); this._handle = embed(src, wrapper, { width: '100%', height: '100%', borderRadius: this.getAttribute('radius') || '12px' }); } disconnectedCallback() { if (this._handle) this._handle.destroy(); } static get observedAttributes() { return ['src', 'height']; } attributeChangedCallback(name, old, val) { if (name === 'src' && this._handle) { this._handle.iframe.src = val; } else if (name === 'height' && this._handle) { this._handle.resize('100%', val); } } }); } return { embed: embed, connect: connect, version: '0.1.0' }; });