@gigabuddy/gadgets 0.1.6 → 0.1.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/index.js CHANGED
@@ -200,7 +200,9 @@ function createGadgetRenderer(componentCode, data = {}, options) {
200
200
  _originalRect: null,
201
201
  request: function() {
202
202
  if (window.gadget.breakout._active) return;
203
+ window.gadget.breakout._active = true;
203
204
  window.parent.postMessage({ type: 'gadget-request-breakout' }, '*');
205
+ window.__rerenderGadget && window.__rerenderGadget();
204
206
  },
205
207
  exit: function() {
206
208
  if (!window.gadget.breakout._active) return;
@@ -256,9 +258,10 @@ ${contextBridgeScript}
256
258
  window.__rerenderGadget();
257
259
  }
258
260
  if (d && d.type === 'gadget-breakout-started') {
261
+ var wasActive = window.gadget.breakout._active;
259
262
  window.gadget.breakout._active = true;
260
263
  window.gadget.breakout._originalRect = d.originalRect || null;
261
- window.__rerenderGadget();
264
+ if (!wasActive) window.__rerenderGadget();
262
265
  }
263
266
  if (d && d.type === 'gadget-update-component' && d.code) {
264
267
  try {
package/index.js.map CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../libs/gadgets/src/lib/createGadgetRenderer.ts", "../../../libs/gadgets/src/lib/setupGadgetBreakout.ts"],
4
- "sourcesContent": ["/**\n * Creates a self-contained HTML string for rendering a gadget component in an iframe.\n *\n * Loads React 18, ReactDOM, Babel (for JSX transpilation), and Tailwind CSS from CDNs.\n * Sets up the full gadget bridge: state, breakout, actions, chat, context, and hot-swap.\n *\n * Usage:\n * import { createGadgetRenderer, setupGadgetBreakout } from '@gigabuddy/chat';\n *\n * const html = createGadgetRenderer(componentCode, data, { viewport: 'compact', stateEnabled: true });\n * iframe.srcdoc = html;\n * setupGadgetBreakout(iframe);\n *\n * The gadget component receives these props:\n * function Gadget({ data, viewport, state, userId, breakout, chat, context })\n *\n * Bridge protocol (postMessage):\n * - Host \u2192 iframe: `gadget-set-data` \u2014 push new props\n * - Host \u2192 iframe: `gadget-state-init` / `gadget-state-update` \u2014 state changes\n * - Host \u2192 iframe: `gadget-update-component` \u2014 hot-swap component code\n * - Host \u2192 iframe: `gadget-breakout-started` \u2014 breakout activated with originalRect\n * - iframe \u2192 Host: `gadget-interaction` \u2014 user dispatched an action\n * - iframe \u2192 Host: `gadget-resize` \u2014 auto-height\n * - iframe \u2192 Host: `gadget-request-breakout` / `gadget-exit-breakout` \u2014 breakout lifecycle\n * - iframe \u2192 Host: `gadget-action-request` / `gadget-chat-request` / `gadget-context-request` \u2014 API calls\n */\nexport function createGadgetRenderer(\n componentCode: string,\n data: unknown = {},\n options?: {\n viewport?: 'compact' | 'full' | 'mobile';\n stateEnabled?: boolean;\n chatEnabled?: boolean;\n contextEnabled?: boolean;\n assets?: Record<string, { url: string; name: string }>;\n },\n): string {\n const serializedData = JSON.stringify(data);\n const viewport = options?.viewport ?? 'full';\n const stateEnabled = options?.stateEnabled ?? false;\n const chatEnabled = options?.chatEnabled ?? false;\n const contextEnabled = options?.contextEnabled ?? false;\n const escapedCode = componentCode.replace(/<\\/script>/g, '<\\\\/script>');\n const serializedAssets = JSON.stringify(options?.assets ?? {});\n\n const stateBridgeScript = stateEnabled\n ? `\n window.gadget.state = {\n shared: {},\n user: {},\n userId: null,\n _sharedCallbacks: [],\n _userCallbacks: [],\n\n dispatch: function(action, data) {\n window.parent.postMessage({ type: 'gadget-interaction', action: action, data: data || {} }, '*');\n },\n\n onSharedChange: function(callback) {\n window.gadget.state._sharedCallbacks.push(callback);\n callback(window.gadget.state.shared);\n return function() {\n var i = window.gadget.state._sharedCallbacks.indexOf(callback);\n if (i !== -1) window.gadget.state._sharedCallbacks.splice(i, 1);\n };\n },\n\n onUserChange: function(callback) {\n window.gadget.state._userCallbacks.push(callback);\n callback(window.gadget.state.user);\n return function() {\n var i = window.gadget.state._userCallbacks.indexOf(callback);\n if (i !== -1) window.gadget.state._userCallbacks.splice(i, 1);\n };\n },\n };\n\n window.addEventListener('message', function(event) {\n var d = event.data;\n if (d && (d.type === 'gadget-state-init' || d.type === 'gadget-state-update')) {\n if (d.userId !== undefined) {\n window.gadget.state.userId = d.userId;\n }\n if (d.shared !== undefined) {\n window.gadget.state.shared = d.shared;\n window.gadget.state._sharedCallbacks.forEach(function(cb) { try { cb(d.shared); } catch(e) {} });\n }\n if (d.user !== undefined) {\n window.gadget.state.user = d.user;\n window.gadget.state._userCallbacks.forEach(function(cb) { try { cb(d.user); } catch(e) {} });\n }\n window.__rerenderGadget();\n }\n });`\n : '';\n\n const chatBridgeScript = chatEnabled\n ? `\n window.gadget.chat = {\n _request: function(method, params) {\n var requestId = Math.random().toString(36).slice(2) + Date.now().toString(36);\n return new Promise(function(resolve, reject) {\n var handler = function(event) {\n var d = event.data;\n if (d && d.type === 'gadget-chat-response' && d.requestId === requestId) {\n window.removeEventListener('message', handler);\n if (d.error) reject(new Error(d.error));\n else resolve(d.result);\n }\n };\n window.addEventListener('message', handler);\n setTimeout(function() { window.removeEventListener('message', handler); reject(new Error('Timed out')); }, 30000);\n window.parent.postMessage({ type: 'gadget-chat-request', requestId: requestId, method: method, params: params || {} }, '*');\n });\n },\n\n _eventCallbacks: [],\n\n createChannel: function(opts) { return window.gadget.chat._request('createChannel', opts); },\n findOrCreateChannel: function(name, opts) { return window.gadget.chat._request('findOrCreateChannel', { name: name, description: opts && opts.description }); },\n listChannels: function() { return window.gadget.chat._request('listChannels'); },\n joinChannel: function(conversationId) { return window.gadget.chat._request('joinChannel', { conversationId: conversationId }); },\n sendMessage: function(conversationId, text) { return window.gadget.chat._request('sendMessage', { conversationId: conversationId, text: text }); },\n getMessages: function(conversationId, opts) { return window.gadget.chat._request('getMessages', { conversationId: conversationId, limit: opts && opts.limit, before: opts && opts.before }); },\n updateChannel: function(conversationId, updates) { return window.gadget.chat._request('updateChannel', { conversationId: conversationId, description: updates && updates.description }); },\n createInvite: function(conversationId) { return window.gadget.chat._request('createInvite', { conversationId: conversationId }); },\n redeemInvite: function(token) { return window.gadget.chat._request('redeemInvite', { token: token }); },\n\n onEvent: function(callback) {\n window.gadget.chat._eventCallbacks.push(callback);\n return function() {\n var i = window.gadget.chat._eventCallbacks.indexOf(callback);\n if (i !== -1) window.gadget.chat._eventCallbacks.splice(i, 1);\n };\n },\n };\n\n window.addEventListener('message', function(event) {\n var d = event.data;\n if (d && d.type === 'gadget-chat-event') {\n window.gadget.chat._eventCallbacks.forEach(function(cb) { try { cb(d.event); } catch(e) {} });\n window.__rerenderGadget();\n }\n });`\n : '';\n\n const contextBridgeScript = contextEnabled\n ? `\n window.gadget.context = {\n _request: function(method, params) {\n var requestId = Math.random().toString(36).slice(2) + Date.now().toString(36);\n return new Promise(function(resolve, reject) {\n var handler = function(event) {\n var d = event.data;\n if (d && d.type === 'gadget-context-response' && d.id === requestId) {\n window.removeEventListener('message', handler);\n if (d.error) reject(new Error(d.error));\n else resolve(d.result);\n }\n };\n window.addEventListener('message', handler);\n setTimeout(function() { window.removeEventListener('message', handler); reject(new Error('Timed out')); }, 30000);\n window.parent.postMessage({ type: 'gadget-context-request', id: requestId, method: method, params: params || {} }, '*');\n });\n },\n\n _eventCallbacks: [],\n\n listTypes: function() { return window.gadget.context._request('listTypes', {}); },\n getType: function(contextType) { return window.gadget.context._request('getType', { contextType: contextType }); },\n listInstances: function(params) { return window.gadget.context._request('listInstances', params || {}); },\n getInstance: function(id) { return window.gadget.context._request('getInstance', { id: id }); },\n createInstance: function(params) { return window.gadget.context._request('createInstance', params); },\n updateInstance: function(id, data) { return window.gadget.context._request('updateInstance', { id: id, data: data }); },\n deleteInstance: function(id) { return window.gadget.context._request('deleteInstance', { id: id }); },\n searchKnowledge: function(params) { return window.gadget.context._request('searchKnowledge', params); },\n getEnriched: function(id) { return window.gadget.context._request('getEnriched', { id: id }); },\n getRelated: function(id) { return window.gadget.context._request('getRelated', { id: id }); },\n\n onEvent: function(callback) {\n window.gadget.context._eventCallbacks.push(callback);\n return function() {\n var i = window.gadget.context._eventCallbacks.indexOf(callback);\n if (i !== -1) window.gadget.context._eventCallbacks.splice(i, 1);\n };\n },\n };\n\n window.addEventListener('message', function(event) {\n var d = event.data;\n if (d && d.type === 'gadget-context-event') {\n window.gadget.context._eventCallbacks.forEach(function(cb) { try { cb(d.event); } catch(e) {} });\n window.__rerenderGadget();\n }\n });`\n : '';\n\n // When state is enabled, pass state prop alongside data and viewport\n const chatPropFragment = chatEnabled ? ', chat: window.gadget.chat' : '';\n const contextPropFragment = contextEnabled ? ', context: window.gadget.context' : '';\n const breakoutPropFragment =\n ', breakout: { active: window.gadget.breakout._active, originalRect: window.gadget.breakout._originalRect, request: window.gadget.breakout.request, exit: window.gadget.breakout.exit }';\n const componentProps = stateEnabled\n ? `{ data: window.__GADGET_DATA__, viewport: window.__GADGET_VIEWPORT__, state: window.gadget.state ? { shared: window.gadget.state.shared, user: window.gadget.state.user } : undefined, userId: window.gadget.state ? window.gadget.state.userId : undefined${chatPropFragment}${contextPropFragment}${breakoutPropFragment} }`\n : `{ data: window.__GADGET_DATA__, viewport: window.__GADGET_VIEWPORT__${chatPropFragment}${contextPropFragment}${breakoutPropFragment} }`;\n\n return `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n <script src=\"https://cdn.jsdelivr.net/npm/react@18/umd/react.production.min.js\"></script>\n <script src=\"https://cdn.jsdelivr.net/npm/react-dom@18/umd/react-dom.production.min.js\"></script>\n <script src=\"https://cdn.jsdelivr.net/npm/@babel/standalone@7/babel.min.js\"></script>\n <script src=\"https://cdn.tailwindcss.com\"></script>\n <style>\n * { margin: 0; padding: 0; box-sizing: border-box; }\n html, body { background: transparent; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; min-height: 100%; }\n #root { min-height: 100vh; }\n .gadget-error {\n padding: 16px;\n background: #fef2f2;\n border: 1px solid #fecaca;\n border-radius: 8px;\n color: #991b1b;\n font-family: monospace;\n font-size: 13px;\n white-space: pre-wrap;\n word-break: break-word;\n }\n .gadget-error-title {\n font-weight: 600;\n margin-bottom: 8px;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n }\n </style>\n</head>\n<body>\n <div id=\"root\"></div>\n <script>\n window.__GADGET_DATA__ = ${serializedData};\n window.__GADGET_VIEWPORT__ = '${viewport}';\n\n window.gadget = {\n data: window.__GADGET_DATA__,\n assets: ${serializedAssets},\n\n breakout: {\n _active: false,\n _originalRect: null,\n request: function() {\n if (window.gadget.breakout._active) return;\n window.parent.postMessage({ type: 'gadget-request-breakout' }, '*');\n },\n exit: function() {\n if (!window.gadget.breakout._active) return;\n window.gadget.breakout._active = false;\n window.gadget.breakout._originalRect = null;\n window.parent.postMessage({ type: 'gadget-exit-breakout' }, '*');\n window.__rerenderGadget();\n },\n },\n\n callAction: function(input) {\n var requestId = Math.random().toString(36).slice(2) + Date.now().toString(36);\n return new Promise(function(resolve, reject) {\n var handler = function(event) {\n var d = event.data;\n if (d && d.type === 'gadget-action-response' && d.requestId === requestId) {\n window.removeEventListener('message', handler);\n if (d.error) reject(new Error(d.error));\n else resolve(d.result);\n }\n };\n window.addEventListener('message', handler);\n setTimeout(function() {\n window.removeEventListener('message', handler);\n reject(new Error('Action timed out'));\n }, 30000);\n window.parent.postMessage({ type: 'gadget-action-request', requestId: requestId, input: input }, '*');\n });\n },\n };\n${stateBridgeScript}\n${chatBridgeScript}\n${contextBridgeScript}\n\n window.__gadgetRoot = null;\n window.__gadgetComponent = null;\n\n window.__rerenderGadget = function() {\n if (window.__gadgetRoot && window.__gadgetComponent) {\n var C = window.__gadgetComponent;\n var EB = window.__gadgetErrorBoundary;\n window.__gadgetRoot.render(\n React.createElement(EB, null, React.createElement(C, ${componentProps}))\n );\n }\n };\n\n window.addEventListener('message', function(event) {\n var d = event.data;\n if (d && d.type === 'gadget-set-data') {\n window.__GADGET_DATA__ = d.data;\n window.gadget.data = d.data;\n window.__rerenderGadget();\n }\n if (d && d.type === 'gadget-breakout-started') {\n window.gadget.breakout._active = true;\n window.gadget.breakout._originalRect = d.originalRect || null;\n window.__rerenderGadget();\n }\n if (d && d.type === 'gadget-update-component' && d.code) {\n try {\n var compiled = Babel.transform(d.code, { presets: ['react'] }).code;\n var fn = new Function('React', 'useState', 'useEffect', 'useCallback', 'useMemo', 'useRef',\n compiled + '\\\\nreturn typeof Gadget !== \"undefined\" ? Gadget : null;');\n var NewComponent = fn(React, React.useState, React.useEffect, React.useCallback, React.useMemo, React.useRef);\n if (NewComponent) {\n window.__gadgetComponent = NewComponent;\n if (window.__gadgetErrorBoundaryInstance) {\n window.__gadgetErrorBoundaryInstance.setState({ error: null });\n }\n window.__rerenderGadget();\n }\n } catch (err) {\n console.error('[gadget-hmr] Component update failed:', err);\n }\n }\n });\n </script>\n <script type=\"text/babel\" data-type=\"module\">\n const { useState, useEffect, useCallback, useMemo, useRef } = React;\n\n class ErrorBoundary extends React.Component {\n constructor(props) {\n super(props);\n this.state = { error: null };\n window.__gadgetErrorBoundaryInstance = this;\n }\n static getDerivedStateFromError(error) {\n return { error };\n }\n render() {\n if (this.state.error) {\n return React.createElement('div', { className: 'gadget-error' },\n React.createElement('div', { className: 'gadget-error-title' }, 'Runtime Error'),\n this.state.error.message\n );\n }\n return this.props.children;\n }\n }\n window.__gadgetErrorBoundary = ErrorBoundary;\n\n try {\n ${escapedCode}\n\n const ComponentToRender = typeof Gadget !== 'undefined' ? Gadget : null;\n\n if (ComponentToRender) {\n window.__gadgetComponent = ComponentToRender;\n const root = ReactDOM.createRoot(document.getElementById('root'));\n window.__gadgetRoot = root;\n root.render(\n <ErrorBoundary>\n <ComponentToRender data={window.__GADGET_DATA__} viewport={window.__GADGET_VIEWPORT__}${stateEnabled ? ' state={window.gadget.state ? { shared: window.gadget.state.shared, user: window.gadget.state.user } : undefined} userId={window.gadget.state ? window.gadget.state.userId : undefined}' : ''}${chatEnabled ? ' chat={window.gadget.chat}' : ''}${contextEnabled ? ' context={window.gadget.context}' : ''} breakout={{ active: window.gadget.breakout._active, originalRect: window.gadget.breakout._originalRect, request: window.gadget.breakout.request, exit: window.gadget.breakout.exit }} />\n </ErrorBoundary>\n );\n } else {\n document.getElementById('root').innerHTML =\n '<div class=\"gadget-error\"><div class=\"gadget-error-title\">No component found</div>Define a function called Gadget.</div>';\n }\n } catch (err) {\n document.getElementById('root').innerHTML =\n '<div class=\"gadget-error\"><div class=\"gadget-error-title\">Error</div>' +\n err.message.replace(/</g, '&lt;').replace(/>/g, '&gt;') +\n '</div>';\n }\n\n const rootEl = document.getElementById('root');\n const observer = new ResizeObserver(() => {\n window.parent.postMessage({\n type: 'gadget-resize',\n height: rootEl.scrollHeight,\n }, '*');\n });\n observer.observe(rootEl);\n </script>\n</body>\n</html>`;\n}\n", "/**\n * Enables the gadget bridge protocols on an iframe.\n *\n * **Breakout protocol:** When a gadget calls `breakout.request()`, this handler\n * promotes the iframe to a fullscreen transparent overlay so the gadget can\n * render across the entire viewport (e.g. dice rolls, confetti). When the\n * gadget calls `breakout.exit()`, the iframe is restored.\n *\n * **File URL resolution:** When `resolveFileUrl` is provided, gadgets can request\n * fresh signed URLs for internal file references via `gadget-file-url-request`.\n * This solves the expired signed URL problem for images and files.\n *\n * Usage:\n * import { setupGadgetBreakout } from '@gigabuddy/gadgets';\n * const cleanup = setupGadgetBreakout(iframeElement);\n *\n * // With file URL resolution:\n * const cleanup = setupGadgetBreakout(iframeElement, {\n * resolveFileUrl: async (fileId) => {\n * const res = await fetch(`/api/get-file-url`, { ... });\n * return (await res.json()).url;\n * },\n * });\n */\nexport interface GadgetBridgeOptions {\n resolveFileUrl: (fileId: string) => Promise<string>;\n}\n\nexport function setupGadgetBreakout(iframe: HTMLIFrameElement, options?: GadgetBridgeOptions): () => void {\n const savedStyles: Record<string, string> = {};\n const STYLE_KEYS = [\n 'position',\n 'top',\n 'left',\n 'width',\n 'height',\n 'zIndex',\n 'background',\n 'border',\n 'borderRadius',\n 'maxWidth',\n 'maxHeight',\n 'margin',\n 'transform',\n 'pointerEvents',\n 'overflow',\n 'visibility',\n ] as const;\n\n // Track ancestor overrides so we can restore them\n const ancestorOverrides: { el: HTMLElement; key: string; original: string }[] = [];\n let placeholderDiv: HTMLDivElement | null = null;\n\n function clearAncestorClipping(): void {\n let el = iframe.parentElement;\n while (el && el !== document.body && el !== document.documentElement) {\n const computed = getComputedStyle(el);\n const overflow = computed.overflow + computed.overflowX + computed.overflowY;\n const hasClipping = /hidden|auto|scroll|clip/.test(overflow);\n const hasContainingBlock =\n computed.transform !== 'none' ||\n computed.willChange === 'transform' ||\n computed.contain !== 'none' ||\n computed.filter !== 'none';\n\n if (hasClipping || hasContainingBlock) {\n if (hasClipping) {\n ancestorOverrides.push({ el, key: 'overflow', original: el.style.overflow });\n ancestorOverrides.push({ el, key: 'overflowX', original: el.style.overflowX });\n ancestorOverrides.push({ el, key: 'overflowY', original: el.style.overflowY });\n el.style.overflow = 'visible';\n el.style.overflowX = 'visible';\n el.style.overflowY = 'visible';\n }\n if (hasContainingBlock && computed.transform !== 'none') {\n ancestorOverrides.push({ el, key: 'transform', original: el.style.transform });\n el.style.transform = 'none';\n }\n if (hasContainingBlock && computed.contain !== 'none') {\n ancestorOverrides.push({ el, key: 'contain', original: el.style.contain });\n el.style.contain = 'none';\n }\n }\n el = el.parentElement;\n }\n }\n\n function restoreAncestorClipping(): void {\n for (const { el, key, original } of ancestorOverrides) {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n (el.style as any)[key] = original;\n }\n ancestorOverrides.length = 0;\n }\n\n function handler(event: MessageEvent): void {\n if (event.source !== iframe.contentWindow) return;\n const d = event.data;\n if (!d || typeof d !== 'object') return;\n\n if (d.type === 'gadget-request-breakout') {\n const rect = iframe.getBoundingClientRect();\n\n // Save current inline styles and attributes\n for (const key of STYLE_KEYS) {\n savedStyles[key] = iframe.style[key as keyof CSSStyleDeclaration] as string;\n }\n savedStyles['_scrolling'] = iframe.getAttribute('scrolling') ?? '';\n\n // Insert a placeholder to preserve layout space while iframe is position:fixed\n placeholderDiv = document.createElement('div');\n placeholderDiv.style.width = `${rect.width}px`;\n placeholderDiv.style.height = `${rect.height}px`;\n placeholderDiv.style.flexShrink = '0';\n iframe.parentElement?.insertBefore(placeholderDiv, iframe);\n\n // Remove scrolling restriction during breakout\n iframe.removeAttribute('scrolling');\n\n // Neutralize ancestor clipping so position:fixed works viewport-wide\n clearAncestorClipping();\n\n // Promote to fullscreen overlay (hidden initially to avoid single-frame flicker\n // while gadget repositions its content based on originalRect)\n Object.assign(iframe.style, {\n position: 'fixed',\n top: '0',\n left: '0',\n width: '100vw',\n height: '100vh',\n zIndex: '99999',\n background: 'transparent',\n border: 'none',\n borderRadius: '0',\n maxWidth: 'none',\n maxHeight: 'none',\n margin: '0',\n transform: 'none',\n pointerEvents: 'none',\n overflow: 'visible',\n visibility: 'hidden',\n });\n\n // Tell the gadget its original position for seamless visual continuity\n iframe.contentWindow?.postMessage(\n {\n type: 'gadget-breakout-started',\n originalRect: { x: rect.x, y: rect.y, width: rect.width, height: rect.height },\n },\n '*',\n );\n\n // Reveal after gadget has repositioned (double-rAF ensures both the\n // style application and the gadget's postMessage handler have run)\n requestAnimationFrame(() =>\n requestAnimationFrame(() => {\n iframe.style.visibility = 'visible';\n }),\n );\n }\n\n if (d.type === 'gadget-file-url-request' && options?.resolveFileUrl) {\n const requestId = d.requestId as string;\n const fileId = d.fileId as string;\n if (!requestId || !fileId) return;\n\n void (async () => {\n try {\n const url = await options.resolveFileUrl!(fileId);\n iframe.contentWindow?.postMessage({ type: 'gadget-file-url-response', requestId, url }, '*');\n } catch (err) {\n iframe.contentWindow?.postMessage(\n {\n type: 'gadget-file-url-response',\n requestId,\n error: err instanceof Error ? err.message : 'Failed to resolve file URL',\n },\n '*',\n );\n }\n })();\n return;\n }\n\n if (d.type === 'gadget-exit-breakout') {\n // Remove placeholder\n if (placeholderDiv) {\n placeholderDiv.remove();\n placeholderDiv = null;\n }\n\n // Restore iframe styles\n for (const key of STYLE_KEYS) {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n (iframe.style as any)[key] = savedStyles[key] ?? '';\n }\n if (savedStyles['_scrolling']) {\n iframe.setAttribute('scrolling', savedStyles['_scrolling']);\n }\n\n // Restore ancestor clipping\n restoreAncestorClipping();\n }\n }\n\n window.addEventListener('message', handler);\n return () => {\n if (placeholderDiv) {\n placeholderDiv.remove();\n placeholderDiv = null;\n }\n restoreAncestorClipping();\n window.removeEventListener('message', handler);\n };\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["/**\n * Creates a self-contained HTML string for rendering a gadget component in an iframe.\n *\n * Loads React 18, ReactDOM, Babel (for JSX transpilation), and Tailwind CSS from CDNs.\n * Sets up the full gadget bridge: state, breakout, actions, chat, context, and hot-swap.\n *\n * Usage:\n * import { createGadgetRenderer, setupGadgetBreakout } from '@gigabuddy/chat';\n *\n * const html = createGadgetRenderer(componentCode, data, { viewport: 'compact', stateEnabled: true });\n * iframe.srcdoc = html;\n * setupGadgetBreakout(iframe);\n *\n * The gadget component receives these props:\n * function Gadget({ data, viewport, state, userId, breakout, chat, context })\n *\n * Bridge protocol (postMessage):\n * - Host \u2192 iframe: `gadget-set-data` \u2014 push new props\n * - Host \u2192 iframe: `gadget-state-init` / `gadget-state-update` \u2014 state changes\n * - Host \u2192 iframe: `gadget-update-component` \u2014 hot-swap component code\n * - Host \u2192 iframe: `gadget-breakout-started` \u2014 breakout activated with originalRect\n * - iframe \u2192 Host: `gadget-interaction` \u2014 user dispatched an action\n * - iframe \u2192 Host: `gadget-resize` \u2014 auto-height\n * - iframe \u2192 Host: `gadget-request-breakout` / `gadget-exit-breakout` \u2014 breakout lifecycle\n * - iframe \u2192 Host: `gadget-action-request` / `gadget-chat-request` / `gadget-context-request` \u2014 API calls\n */\nexport function createGadgetRenderer(\n componentCode: string,\n data: unknown = {},\n options?: {\n viewport?: 'compact' | 'full' | 'mobile';\n stateEnabled?: boolean;\n chatEnabled?: boolean;\n contextEnabled?: boolean;\n assets?: Record<string, { url: string; name: string }>;\n },\n): string {\n const serializedData = JSON.stringify(data);\n const viewport = options?.viewport ?? 'full';\n const stateEnabled = options?.stateEnabled ?? false;\n const chatEnabled = options?.chatEnabled ?? false;\n const contextEnabled = options?.contextEnabled ?? false;\n const escapedCode = componentCode.replace(/<\\/script>/g, '<\\\\/script>');\n const serializedAssets = JSON.stringify(options?.assets ?? {});\n\n const stateBridgeScript = stateEnabled\n ? `\n window.gadget.state = {\n shared: {},\n user: {},\n userId: null,\n _sharedCallbacks: [],\n _userCallbacks: [],\n\n dispatch: function(action, data) {\n window.parent.postMessage({ type: 'gadget-interaction', action: action, data: data || {} }, '*');\n },\n\n onSharedChange: function(callback) {\n window.gadget.state._sharedCallbacks.push(callback);\n callback(window.gadget.state.shared);\n return function() {\n var i = window.gadget.state._sharedCallbacks.indexOf(callback);\n if (i !== -1) window.gadget.state._sharedCallbacks.splice(i, 1);\n };\n },\n\n onUserChange: function(callback) {\n window.gadget.state._userCallbacks.push(callback);\n callback(window.gadget.state.user);\n return function() {\n var i = window.gadget.state._userCallbacks.indexOf(callback);\n if (i !== -1) window.gadget.state._userCallbacks.splice(i, 1);\n };\n },\n };\n\n window.addEventListener('message', function(event) {\n var d = event.data;\n if (d && (d.type === 'gadget-state-init' || d.type === 'gadget-state-update')) {\n if (d.userId !== undefined) {\n window.gadget.state.userId = d.userId;\n }\n if (d.shared !== undefined) {\n window.gadget.state.shared = d.shared;\n window.gadget.state._sharedCallbacks.forEach(function(cb) { try { cb(d.shared); } catch(e) {} });\n }\n if (d.user !== undefined) {\n window.gadget.state.user = d.user;\n window.gadget.state._userCallbacks.forEach(function(cb) { try { cb(d.user); } catch(e) {} });\n }\n window.__rerenderGadget();\n }\n });`\n : '';\n\n const chatBridgeScript = chatEnabled\n ? `\n window.gadget.chat = {\n _request: function(method, params) {\n var requestId = Math.random().toString(36).slice(2) + Date.now().toString(36);\n return new Promise(function(resolve, reject) {\n var handler = function(event) {\n var d = event.data;\n if (d && d.type === 'gadget-chat-response' && d.requestId === requestId) {\n window.removeEventListener('message', handler);\n if (d.error) reject(new Error(d.error));\n else resolve(d.result);\n }\n };\n window.addEventListener('message', handler);\n setTimeout(function() { window.removeEventListener('message', handler); reject(new Error('Timed out')); }, 30000);\n window.parent.postMessage({ type: 'gadget-chat-request', requestId: requestId, method: method, params: params || {} }, '*');\n });\n },\n\n _eventCallbacks: [],\n\n createChannel: function(opts) { return window.gadget.chat._request('createChannel', opts); },\n findOrCreateChannel: function(name, opts) { return window.gadget.chat._request('findOrCreateChannel', { name: name, description: opts && opts.description }); },\n listChannels: function() { return window.gadget.chat._request('listChannels'); },\n joinChannel: function(conversationId) { return window.gadget.chat._request('joinChannel', { conversationId: conversationId }); },\n sendMessage: function(conversationId, text) { return window.gadget.chat._request('sendMessage', { conversationId: conversationId, text: text }); },\n getMessages: function(conversationId, opts) { return window.gadget.chat._request('getMessages', { conversationId: conversationId, limit: opts && opts.limit, before: opts && opts.before }); },\n updateChannel: function(conversationId, updates) { return window.gadget.chat._request('updateChannel', { conversationId: conversationId, description: updates && updates.description }); },\n createInvite: function(conversationId) { return window.gadget.chat._request('createInvite', { conversationId: conversationId }); },\n redeemInvite: function(token) { return window.gadget.chat._request('redeemInvite', { token: token }); },\n\n onEvent: function(callback) {\n window.gadget.chat._eventCallbacks.push(callback);\n return function() {\n var i = window.gadget.chat._eventCallbacks.indexOf(callback);\n if (i !== -1) window.gadget.chat._eventCallbacks.splice(i, 1);\n };\n },\n };\n\n window.addEventListener('message', function(event) {\n var d = event.data;\n if (d && d.type === 'gadget-chat-event') {\n window.gadget.chat._eventCallbacks.forEach(function(cb) { try { cb(d.event); } catch(e) {} });\n window.__rerenderGadget();\n }\n });`\n : '';\n\n const contextBridgeScript = contextEnabled\n ? `\n window.gadget.context = {\n _request: function(method, params) {\n var requestId = Math.random().toString(36).slice(2) + Date.now().toString(36);\n return new Promise(function(resolve, reject) {\n var handler = function(event) {\n var d = event.data;\n if (d && d.type === 'gadget-context-response' && d.id === requestId) {\n window.removeEventListener('message', handler);\n if (d.error) reject(new Error(d.error));\n else resolve(d.result);\n }\n };\n window.addEventListener('message', handler);\n setTimeout(function() { window.removeEventListener('message', handler); reject(new Error('Timed out')); }, 30000);\n window.parent.postMessage({ type: 'gadget-context-request', id: requestId, method: method, params: params || {} }, '*');\n });\n },\n\n _eventCallbacks: [],\n\n listTypes: function() { return window.gadget.context._request('listTypes', {}); },\n getType: function(contextType) { return window.gadget.context._request('getType', { contextType: contextType }); },\n listInstances: function(params) { return window.gadget.context._request('listInstances', params || {}); },\n getInstance: function(id) { return window.gadget.context._request('getInstance', { id: id }); },\n createInstance: function(params) { return window.gadget.context._request('createInstance', params); },\n updateInstance: function(id, data) { return window.gadget.context._request('updateInstance', { id: id, data: data }); },\n deleteInstance: function(id) { return window.gadget.context._request('deleteInstance', { id: id }); },\n searchKnowledge: function(params) { return window.gadget.context._request('searchKnowledge', params); },\n getEnriched: function(id) { return window.gadget.context._request('getEnriched', { id: id }); },\n getRelated: function(id) { return window.gadget.context._request('getRelated', { id: id }); },\n\n onEvent: function(callback) {\n window.gadget.context._eventCallbacks.push(callback);\n return function() {\n var i = window.gadget.context._eventCallbacks.indexOf(callback);\n if (i !== -1) window.gadget.context._eventCallbacks.splice(i, 1);\n };\n },\n };\n\n window.addEventListener('message', function(event) {\n var d = event.data;\n if (d && d.type === 'gadget-context-event') {\n window.gadget.context._eventCallbacks.forEach(function(cb) { try { cb(d.event); } catch(e) {} });\n window.__rerenderGadget();\n }\n });`\n : '';\n\n // When state is enabled, pass state prop alongside data and viewport\n const chatPropFragment = chatEnabled ? ', chat: window.gadget.chat' : '';\n const contextPropFragment = contextEnabled ? ', context: window.gadget.context' : '';\n const breakoutPropFragment =\n ', breakout: { active: window.gadget.breakout._active, originalRect: window.gadget.breakout._originalRect, request: window.gadget.breakout.request, exit: window.gadget.breakout.exit }';\n const componentProps = stateEnabled\n ? `{ data: window.__GADGET_DATA__, viewport: window.__GADGET_VIEWPORT__, state: window.gadget.state ? { shared: window.gadget.state.shared, user: window.gadget.state.user } : undefined, userId: window.gadget.state ? window.gadget.state.userId : undefined${chatPropFragment}${contextPropFragment}${breakoutPropFragment} }`\n : `{ data: window.__GADGET_DATA__, viewport: window.__GADGET_VIEWPORT__${chatPropFragment}${contextPropFragment}${breakoutPropFragment} }`;\n\n return `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n <script src=\"https://cdn.jsdelivr.net/npm/react@18/umd/react.production.min.js\"></script>\n <script src=\"https://cdn.jsdelivr.net/npm/react-dom@18/umd/react-dom.production.min.js\"></script>\n <script src=\"https://cdn.jsdelivr.net/npm/@babel/standalone@7/babel.min.js\"></script>\n <script src=\"https://cdn.tailwindcss.com\"></script>\n <style>\n * { margin: 0; padding: 0; box-sizing: border-box; }\n html, body { background: transparent; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; min-height: 100%; }\n #root { min-height: 100vh; }\n .gadget-error {\n padding: 16px;\n background: #fef2f2;\n border: 1px solid #fecaca;\n border-radius: 8px;\n color: #991b1b;\n font-family: monospace;\n font-size: 13px;\n white-space: pre-wrap;\n word-break: break-word;\n }\n .gadget-error-title {\n font-weight: 600;\n margin-bottom: 8px;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n }\n </style>\n</head>\n<body>\n <div id=\"root\"></div>\n <script>\n window.__GADGET_DATA__ = ${serializedData};\n window.__GADGET_VIEWPORT__ = '${viewport}';\n\n window.gadget = {\n data: window.__GADGET_DATA__,\n assets: ${serializedAssets},\n\n breakout: {\n _active: false,\n _originalRect: null,\n request: function() {\n if (window.gadget.breakout._active) return;\n window.gadget.breakout._active = true;\n window.parent.postMessage({ type: 'gadget-request-breakout' }, '*');\n window.__rerenderGadget && window.__rerenderGadget();\n },\n exit: function() {\n if (!window.gadget.breakout._active) return;\n window.gadget.breakout._active = false;\n window.gadget.breakout._originalRect = null;\n window.parent.postMessage({ type: 'gadget-exit-breakout' }, '*');\n window.__rerenderGadget();\n },\n },\n\n callAction: function(input) {\n var requestId = Math.random().toString(36).slice(2) + Date.now().toString(36);\n return new Promise(function(resolve, reject) {\n var handler = function(event) {\n var d = event.data;\n if (d && d.type === 'gadget-action-response' && d.requestId === requestId) {\n window.removeEventListener('message', handler);\n if (d.error) reject(new Error(d.error));\n else resolve(d.result);\n }\n };\n window.addEventListener('message', handler);\n setTimeout(function() {\n window.removeEventListener('message', handler);\n reject(new Error('Action timed out'));\n }, 30000);\n window.parent.postMessage({ type: 'gadget-action-request', requestId: requestId, input: input }, '*');\n });\n },\n };\n${stateBridgeScript}\n${chatBridgeScript}\n${contextBridgeScript}\n\n window.__gadgetRoot = null;\n window.__gadgetComponent = null;\n\n window.__rerenderGadget = function() {\n if (window.__gadgetRoot && window.__gadgetComponent) {\n var C = window.__gadgetComponent;\n var EB = window.__gadgetErrorBoundary;\n window.__gadgetRoot.render(\n React.createElement(EB, null, React.createElement(C, ${componentProps}))\n );\n }\n };\n\n window.addEventListener('message', function(event) {\n var d = event.data;\n if (d && d.type === 'gadget-set-data') {\n window.__GADGET_DATA__ = d.data;\n window.gadget.data = d.data;\n window.__rerenderGadget();\n }\n if (d && d.type === 'gadget-breakout-started') {\n var wasActive = window.gadget.breakout._active;\n window.gadget.breakout._active = true;\n window.gadget.breakout._originalRect = d.originalRect || null;\n if (!wasActive) window.__rerenderGadget();\n }\n if (d && d.type === 'gadget-update-component' && d.code) {\n try {\n var compiled = Babel.transform(d.code, { presets: ['react'] }).code;\n var fn = new Function('React', 'useState', 'useEffect', 'useCallback', 'useMemo', 'useRef',\n compiled + '\\\\nreturn typeof Gadget !== \"undefined\" ? Gadget : null;');\n var NewComponent = fn(React, React.useState, React.useEffect, React.useCallback, React.useMemo, React.useRef);\n if (NewComponent) {\n window.__gadgetComponent = NewComponent;\n if (window.__gadgetErrorBoundaryInstance) {\n window.__gadgetErrorBoundaryInstance.setState({ error: null });\n }\n window.__rerenderGadget();\n }\n } catch (err) {\n console.error('[gadget-hmr] Component update failed:', err);\n }\n }\n });\n </script>\n <script type=\"text/babel\" data-type=\"module\">\n const { useState, useEffect, useCallback, useMemo, useRef } = React;\n\n class ErrorBoundary extends React.Component {\n constructor(props) {\n super(props);\n this.state = { error: null };\n window.__gadgetErrorBoundaryInstance = this;\n }\n static getDerivedStateFromError(error) {\n return { error };\n }\n render() {\n if (this.state.error) {\n return React.createElement('div', { className: 'gadget-error' },\n React.createElement('div', { className: 'gadget-error-title' }, 'Runtime Error'),\n this.state.error.message\n );\n }\n return this.props.children;\n }\n }\n window.__gadgetErrorBoundary = ErrorBoundary;\n\n try {\n ${escapedCode}\n\n const ComponentToRender = typeof Gadget !== 'undefined' ? Gadget : null;\n\n if (ComponentToRender) {\n window.__gadgetComponent = ComponentToRender;\n const root = ReactDOM.createRoot(document.getElementById('root'));\n window.__gadgetRoot = root;\n root.render(\n <ErrorBoundary>\n <ComponentToRender data={window.__GADGET_DATA__} viewport={window.__GADGET_VIEWPORT__}${stateEnabled ? ' state={window.gadget.state ? { shared: window.gadget.state.shared, user: window.gadget.state.user } : undefined} userId={window.gadget.state ? window.gadget.state.userId : undefined}' : ''}${chatEnabled ? ' chat={window.gadget.chat}' : ''}${contextEnabled ? ' context={window.gadget.context}' : ''} breakout={{ active: window.gadget.breakout._active, originalRect: window.gadget.breakout._originalRect, request: window.gadget.breakout.request, exit: window.gadget.breakout.exit }} />\n </ErrorBoundary>\n );\n } else {\n document.getElementById('root').innerHTML =\n '<div class=\"gadget-error\"><div class=\"gadget-error-title\">No component found</div>Define a function called Gadget.</div>';\n }\n } catch (err) {\n document.getElementById('root').innerHTML =\n '<div class=\"gadget-error\"><div class=\"gadget-error-title\">Error</div>' +\n err.message.replace(/</g, '&lt;').replace(/>/g, '&gt;') +\n '</div>';\n }\n\n const rootEl = document.getElementById('root');\n const observer = new ResizeObserver(() => {\n window.parent.postMessage({\n type: 'gadget-resize',\n height: rootEl.scrollHeight,\n }, '*');\n });\n observer.observe(rootEl);\n </script>\n</body>\n</html>`;\n}\n", "/**\n * Enables the gadget bridge protocols on an iframe.\n *\n * **Breakout protocol:** When a gadget calls `breakout.request()`, this handler\n * promotes the iframe to a fullscreen transparent overlay so the gadget can\n * render across the entire viewport (e.g. dice rolls, confetti). When the\n * gadget calls `breakout.exit()`, the iframe is restored.\n *\n * **File URL resolution:** When `resolveFileUrl` is provided, gadgets can request\n * fresh signed URLs for internal file references via `gadget-file-url-request`.\n * This solves the expired signed URL problem for images and files.\n *\n * Usage:\n * import { setupGadgetBreakout } from '@gigabuddy/gadgets';\n * const cleanup = setupGadgetBreakout(iframeElement);\n *\n * // With file URL resolution:\n * const cleanup = setupGadgetBreakout(iframeElement, {\n * resolveFileUrl: async (fileId) => {\n * const res = await fetch(`/api/get-file-url`, { ... });\n * return (await res.json()).url;\n * },\n * });\n */\nexport interface GadgetBridgeOptions {\n resolveFileUrl: (fileId: string) => Promise<string>;\n}\n\nexport function setupGadgetBreakout(iframe: HTMLIFrameElement, options?: GadgetBridgeOptions): () => void {\n const savedStyles: Record<string, string> = {};\n const STYLE_KEYS = [\n 'position',\n 'top',\n 'left',\n 'width',\n 'height',\n 'zIndex',\n 'background',\n 'border',\n 'borderRadius',\n 'maxWidth',\n 'maxHeight',\n 'margin',\n 'transform',\n 'pointerEvents',\n 'overflow',\n 'visibility',\n ] as const;\n\n // Track ancestor overrides so we can restore them\n const ancestorOverrides: { el: HTMLElement; key: string; original: string }[] = [];\n let placeholderDiv: HTMLDivElement | null = null;\n\n function clearAncestorClipping(): void {\n let el = iframe.parentElement;\n while (el && el !== document.body && el !== document.documentElement) {\n const computed = getComputedStyle(el);\n const overflow = computed.overflow + computed.overflowX + computed.overflowY;\n const hasClipping = /hidden|auto|scroll|clip/.test(overflow);\n const hasContainingBlock =\n computed.transform !== 'none' ||\n computed.willChange === 'transform' ||\n computed.contain !== 'none' ||\n computed.filter !== 'none';\n\n if (hasClipping || hasContainingBlock) {\n if (hasClipping) {\n ancestorOverrides.push({ el, key: 'overflow', original: el.style.overflow });\n ancestorOverrides.push({ el, key: 'overflowX', original: el.style.overflowX });\n ancestorOverrides.push({ el, key: 'overflowY', original: el.style.overflowY });\n el.style.overflow = 'visible';\n el.style.overflowX = 'visible';\n el.style.overflowY = 'visible';\n }\n if (hasContainingBlock && computed.transform !== 'none') {\n ancestorOverrides.push({ el, key: 'transform', original: el.style.transform });\n el.style.transform = 'none';\n }\n if (hasContainingBlock && computed.contain !== 'none') {\n ancestorOverrides.push({ el, key: 'contain', original: el.style.contain });\n el.style.contain = 'none';\n }\n }\n el = el.parentElement;\n }\n }\n\n function restoreAncestorClipping(): void {\n for (const { el, key, original } of ancestorOverrides) {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n (el.style as any)[key] = original;\n }\n ancestorOverrides.length = 0;\n }\n\n function handler(event: MessageEvent): void {\n if (event.source !== iframe.contentWindow) return;\n const d = event.data;\n if (!d || typeof d !== 'object') return;\n\n if (d.type === 'gadget-request-breakout') {\n const rect = iframe.getBoundingClientRect();\n\n // Save current inline styles and attributes\n for (const key of STYLE_KEYS) {\n savedStyles[key] = iframe.style[key as keyof CSSStyleDeclaration] as string;\n }\n savedStyles['_scrolling'] = iframe.getAttribute('scrolling') ?? '';\n\n // Insert a placeholder to preserve layout space while iframe is position:fixed\n placeholderDiv = document.createElement('div');\n placeholderDiv.style.width = `${rect.width}px`;\n placeholderDiv.style.height = `${rect.height}px`;\n placeholderDiv.style.flexShrink = '0';\n iframe.parentElement?.insertBefore(placeholderDiv, iframe);\n\n // Remove scrolling restriction during breakout\n iframe.removeAttribute('scrolling');\n\n // Neutralize ancestor clipping so position:fixed works viewport-wide\n clearAncestorClipping();\n\n // Promote to fullscreen overlay (hidden initially to avoid single-frame flicker\n // while gadget repositions its content based on originalRect)\n Object.assign(iframe.style, {\n position: 'fixed',\n top: '0',\n left: '0',\n width: '100vw',\n height: '100vh',\n zIndex: '99999',\n background: 'transparent',\n border: 'none',\n borderRadius: '0',\n maxWidth: 'none',\n maxHeight: 'none',\n margin: '0',\n transform: 'none',\n pointerEvents: 'none',\n overflow: 'visible',\n visibility: 'hidden',\n });\n\n // Tell the gadget its original position for seamless visual continuity\n iframe.contentWindow?.postMessage(\n {\n type: 'gadget-breakout-started',\n originalRect: { x: rect.x, y: rect.y, width: rect.width, height: rect.height },\n },\n '*',\n );\n\n // Reveal after gadget has repositioned (double-rAF ensures both the\n // style application and the gadget's postMessage handler have run)\n requestAnimationFrame(() =>\n requestAnimationFrame(() => {\n iframe.style.visibility = 'visible';\n }),\n );\n }\n\n if (d.type === 'gadget-file-url-request' && options?.resolveFileUrl) {\n const requestId = d.requestId as string;\n const fileId = d.fileId as string;\n if (!requestId || !fileId) return;\n\n void (async () => {\n try {\n const url = await options.resolveFileUrl!(fileId);\n iframe.contentWindow?.postMessage({ type: 'gadget-file-url-response', requestId, url }, '*');\n } catch (err) {\n iframe.contentWindow?.postMessage(\n {\n type: 'gadget-file-url-response',\n requestId,\n error: err instanceof Error ? err.message : 'Failed to resolve file URL',\n },\n '*',\n );\n }\n })();\n return;\n }\n\n if (d.type === 'gadget-exit-breakout') {\n // Remove placeholder\n if (placeholderDiv) {\n placeholderDiv.remove();\n placeholderDiv = null;\n }\n\n // Restore iframe styles\n for (const key of STYLE_KEYS) {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n (iframe.style as any)[key] = savedStyles[key] ?? '';\n }\n if (savedStyles['_scrolling']) {\n iframe.setAttribute('scrolling', savedStyles['_scrolling']);\n }\n\n // Restore ancestor clipping\n restoreAncestorClipping();\n }\n }\n\n window.addEventListener('message', handler);\n return () => {\n if (placeholderDiv) {\n placeholderDiv.remove();\n placeholderDiv = null;\n }\n restoreAncestorClipping();\n window.removeEventListener('message', handler);\n };\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gigabuddy/gadgets",
3
- "version": "0.1.6",
3
+ "version": "0.1.7",
4
4
  "description": "Gigabuddy Gadgets SDK — render interactive gadgets with breakout, state, and hot-swap",
5
5
  "type": "module",
6
6
  "main": "./index.js",
package/react.js CHANGED
@@ -235,7 +235,9 @@ function createGadgetRenderer(componentCode, data = {}, options) {
235
235
  _originalRect: null,
236
236
  request: function() {
237
237
  if (window.gadget.breakout._active) return;
238
+ window.gadget.breakout._active = true;
238
239
  window.parent.postMessage({ type: 'gadget-request-breakout' }, '*');
240
+ window.__rerenderGadget && window.__rerenderGadget();
239
241
  },
240
242
  exit: function() {
241
243
  if (!window.gadget.breakout._active) return;
@@ -291,9 +293,10 @@ ${contextBridgeScript}
291
293
  window.__rerenderGadget();
292
294
  }
293
295
  if (d && d.type === 'gadget-breakout-started') {
296
+ var wasActive = window.gadget.breakout._active;
294
297
  window.gadget.breakout._active = true;
295
298
  window.gadget.breakout._originalRect = d.originalRect || null;
296
- window.__rerenderGadget();
299
+ if (!wasActive) window.__rerenderGadget();
297
300
  }
298
301
  if (d && d.type === 'gadget-update-component' && d.code) {
299
302
  try {
@@ -502,7 +505,12 @@ function GadgetFrame({
502
505
  if (!iframeLoaded || !latestStateRef.current)
503
506
  return;
504
507
  iframeRef.current?.contentWindow?.postMessage(
505
- { type: "gadget-state-init", shared: latestStateRef.current.shared, user: latestStateRef.current.user, userId: userIdRef.current },
508
+ {
509
+ type: "gadget-state-init",
510
+ shared: latestStateRef.current.shared,
511
+ user: latestStateRef.current.user,
512
+ userId: userIdRef.current
513
+ },
506
514
  "*"
507
515
  );
508
516
  }, [iframeLoaded]);
@@ -568,7 +576,10 @@ function GadgetFrame({
568
576
  setBreakoutRevealed(false);
569
577
  onBreakoutChange?.(true);
570
578
  iframe.contentWindow?.postMessage(
571
- { type: "gadget-breakout-started", originalRect: { x: rect.x, y: rect.y, width: rect.width, height: rect.height } },
579
+ {
580
+ type: "gadget-breakout-started",
581
+ originalRect: { x: rect.x, y: rect.y, width: rect.width, height: rect.height }
582
+ },
572
583
  "*"
573
584
  );
574
585
  requestAnimationFrame(() => requestAnimationFrame(() => setBreakoutRevealed(true)));
@@ -641,7 +652,11 @@ function GadgetFrame({
641
652
  iframeRef.current?.contentWindow?.postMessage({ type: "gadget-file-url-response", requestId, url }, "*");
642
653
  } catch (err) {
643
654
  iframeRef.current?.contentWindow?.postMessage(
644
- { type: "gadget-file-url-response", requestId, error: err instanceof Error ? err.message : "Failed to resolve file URL" },
655
+ {
656
+ type: "gadget-file-url-response",
657
+ requestId,
658
+ error: err instanceof Error ? err.message : "Failed to resolve file URL"
659
+ },
645
660
  "*"
646
661
  );
647
662
  }
@@ -698,14 +713,48 @@ function GadgetFrame({
698
713
  return () => window.removeEventListener("message", handleMessage);
699
714
  }, [handleMessage]);
700
715
  if (error) {
701
- return /* @__PURE__ */ jsx2("div", { className, style: { padding: "8px 12px", fontSize: 12, color: "#b91c1c", background: "#fef2f2", border: "1px solid #fecaca", borderRadius: 8 }, children: error });
716
+ return /* @__PURE__ */ jsx2(
717
+ "div",
718
+ {
719
+ className,
720
+ style: {
721
+ padding: "8px 12px",
722
+ fontSize: 12,
723
+ color: "#b91c1c",
724
+ background: "#fef2f2",
725
+ border: "1px solid #fecaca",
726
+ borderRadius: 8
727
+ },
728
+ children: error
729
+ }
730
+ );
702
731
  }
703
732
  if (loading) {
704
- return /* @__PURE__ */ jsxs("div", { className, style: { display: "flex", alignItems: "center", gap: 8, padding: "12px", fontSize: 12, color: "#6b7280" }, children: [
705
- /* @__PURE__ */ jsx2("span", { style: { display: "inline-block", width: 16, height: 16, border: "2px solid #d1d5db", borderTopColor: "#6b7280", borderRadius: "50%", animation: "gadget-spin 0.6s linear infinite" } }),
706
- "Loading gadget...",
707
- /* @__PURE__ */ jsx2("style", { children: `@keyframes gadget-spin { to { transform: rotate(360deg) } }` })
708
- ] });
733
+ return /* @__PURE__ */ jsxs(
734
+ "div",
735
+ {
736
+ className,
737
+ style: { display: "flex", alignItems: "center", gap: 8, padding: "12px", fontSize: 12, color: "#6b7280" },
738
+ children: [
739
+ /* @__PURE__ */ jsx2(
740
+ "span",
741
+ {
742
+ style: {
743
+ display: "inline-block",
744
+ width: 16,
745
+ height: 16,
746
+ border: "2px solid #d1d5db",
747
+ borderTopColor: "#6b7280",
748
+ borderRadius: "50%",
749
+ animation: "gadget-spin 0.6s linear infinite"
750
+ }
751
+ }
752
+ ),
753
+ "Loading gadget...",
754
+ /* @__PURE__ */ jsx2("style", { children: `@keyframes gadget-spin { to { transform: rotate(360deg) } }` })
755
+ ]
756
+ }
757
+ );
709
758
  }
710
759
  if (!html)
711
760
  return null;
package/react.js.map CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../libs/gadgets/src/lib/react/GadgetContext.tsx", "../../../libs/gadgets/src/lib/react/GadgetFrame.tsx", "../../../libs/gadgets/src/lib/createGadgetRenderer.ts"],
4
- "sourcesContent": ["import { createContext, useContext, useMemo, type ReactNode } from 'react';\n\nexport interface GadgetConfig {\n /** Base API URL (e.g. \"https://api.gigabuddy.com\") */\n apiUrl: string;\n /** Organization ID */\n orgId: string;\n /** Project ID */\n projectId: string;\n /** Returns a fresh auth token */\n getToken: () => Promise<string>;\n /** Optional SSE stream base URL (falls back to apiUrl) */\n streamBaseUrl?: string;\n}\n\ninterface GadgetContextValue {\n config: GadgetConfig;\n /** Resolves a file ID to a fresh signed URL */\n resolveFileUrl: (fileId: string) => Promise<string>;\n}\n\nconst GadgetCtx = createContext<GadgetContextValue | null>(null);\n\nexport function GadgetProvider({ config, children }: { config: GadgetConfig; children: ReactNode }) {\n const value = useMemo<GadgetContextValue>(() => {\n const base = `${config.apiUrl}/${config.orgId}/${config.projectId}`;\n\n return {\n config,\n resolveFileUrl: async (fileId: string) => {\n const token = await config.getToken();\n const res = await fetch(`${base}/context/get-file-url`, {\n method: 'POST',\n headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },\n body: JSON.stringify({ fileId }),\n });\n if (!res.ok) throw new Error(`HTTP ${res.status}`);\n const data = (await res.json()) as { url: string };\n return data.url;\n },\n };\n }, [config.apiUrl, config.orgId, config.projectId, config.getToken, config.streamBaseUrl]);\n\n return <GadgetCtx.Provider value={value}>{children}</GadgetCtx.Provider>;\n}\n\nexport function useGadgetConfig(): GadgetContextValue {\n const ctx = useContext(GadgetCtx);\n if (!ctx) throw new Error('GadgetFrame must be wrapped in a <GadgetProvider>');\n return ctx;\n}\n", "import { useCallback, useEffect, useRef, useState } from 'react';\nimport { createGadgetRenderer } from '../createGadgetRenderer.js';\nimport { useGadgetConfig } from './GadgetContext.js';\n\n// =============================================================================\n// Types\n// =============================================================================\n\nexport interface GadgetFrameProps {\n /** The gadget entity ID to load */\n gadgetId: string;\n /** Data props to pass to the gadget */\n props?: Record<string, unknown>;\n /** Display mode \u2014 compact (inline, resizable) or full (fills container) */\n mode?: 'compact' | 'full';\n /** Whether breakout is enabled (default: true in compact mode) */\n breakout?: boolean;\n /** Max height in compact mode before scrolling (default: 300) */\n maxHeight?: number;\n /** Deployment ID for mission-backed gadgets (auto-generated if not provided) */\n deploymentId?: string;\n /** Conversation ID \u2014 used when updating message content after action */\n conversationId?: string;\n /** Message ID \u2014 used when updating message content after action */\n messageId?: string;\n /** Additional className for the wrapper div */\n className?: string;\n /** Called when breakout state changes */\n onBreakoutChange?: (active: boolean) => void;\n /** Called on load error */\n onError?: (error: string) => void;\n}\n\ninterface GadgetEntity {\n data: {\n type: string;\n componentCode: string;\n actionRef?: { type: string; id: string };\n missionRef?: { type: string; id: string };\n stateBindings?: {\n shared?: { contextFields: string[] };\n user?: { contextFields: string[] };\n };\n assets?: Record<string, { fileId: string; url: string; name: string; contentType: string }>;\n };\n}\n\n// =============================================================================\n// Component\n// =============================================================================\n\nexport function GadgetFrame({\n gadgetId,\n props,\n mode = 'compact',\n breakout: breakoutEnabled = true,\n maxHeight = 300,\n deploymentId: externalDeploymentId,\n conversationId,\n messageId,\n className,\n onBreakoutChange,\n onError,\n}: GadgetFrameProps) {\n const { config, resolveFileUrl } = useGadgetConfig();\n const base = `${config.apiUrl}/${config.orgId}/${config.projectId}`;\n\n // \u2500\u2500 State \u2500\u2500\n const [html, setHtml] = useState<string | null>(null);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<string | null>(null);\n const [naturalHeight, setNaturalHeight] = useState(60);\n const [iframeLoaded, setIframeLoaded] = useState(false);\n const [breakoutActive, setBreakoutActive] = useState(false);\n const [breakoutRevealed, setBreakoutRevealed] = useState(false);\n\n // \u2500\u2500 Refs \u2500\u2500\n const iframeRef = useRef<HTMLIFrameElement>(null);\n const entityRef = useRef<GadgetEntity | null>(null);\n const initialPropsRef = useRef(props);\n const deploymentIdRef = useRef<string | null>(externalDeploymentId ?? null);\n const sseRef = useRef<EventSource | null>(null);\n const userIdRef = useRef<string | null>(null);\n const latestStateRef = useRef<{ shared: Record<string, unknown>; user: Record<string, unknown> } | null>(null);\n const placeholderRef = useRef<HTMLDivElement | null>(null);\n const ancestorOverridesRef = useRef<{ el: HTMLElement; key: string; original: string }[]>([]);\n const breakoutActiveRef = useRef(false);\n breakoutActiveRef.current = breakoutActive;\n\n // \u2500\u2500 Derived \u2500\u2500\n const isCompact = mode === 'compact';\n const isCapped = isCompact && naturalHeight > maxHeight;\n const iframeHeight = isCapped ? maxHeight : naturalHeight;\n\n // \u2500\u2500 Fetch entity + build HTML + deploy \u2500\u2500\n useEffect(() => {\n let cancelled = false;\n\n (async () => {\n try {\n const token = await config.getToken();\n const res = await fetch(`${base}/chat/get-gadget`, {\n method: 'POST',\n headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },\n body: JSON.stringify({ gadgetId }),\n });\n if (!res.ok) throw new Error(`Failed to load gadget: ${res.status}`);\n\n const entity = (await res.json()) as GadgetEntity;\n if (cancelled) return;\n\n entityRef.current = entity;\n const hasMission = entity.data.missionRef?.id != null;\n\n const assetMap = entity.data.assets\n ? Object.fromEntries(Object.entries(entity.data.assets).map(([k, v]) => [k, { url: v.url, name: v.name }]))\n : undefined;\n\n const builtHtml = createGadgetRenderer(entity.data.componentCode, initialPropsRef.current ?? {}, {\n viewport: mode,\n stateEnabled: hasMission,\n assets: assetMap,\n });\n setHtml(builtHtml);\n\n // Deploy if mission-backed\n if (hasMission) {\n const depId = externalDeploymentId ?? messageId ?? `gadget_${gadgetId}_${Date.now()}`;\n deploymentIdRef.current = depId;\n\n const deployRes = await fetch(`${base}/gadget-deploy`, {\n method: 'POST',\n headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },\n body: JSON.stringify({\n gadgetId,\n deploymentId: depId,\n initialData: initialPropsRef.current,\n conversationId,\n }),\n });\n if (!deployRes.ok) throw new Error(`Failed to deploy gadget: ${deployRes.status}`);\n\n const deployData = (await deployRes.json()) as {\n deploymentId: string;\n missionInstanceId: string;\n initialState: { shared: Record<string, unknown>; user: Record<string, unknown> };\n userId?: string;\n };\n if (cancelled) return;\n\n if (deployData.userId) userIdRef.current = deployData.userId;\n latestStateRef.current = deployData.initialState;\n\n // Connect SSE\n const streamBase = config.streamBaseUrl ?? config.apiUrl;\n const sseUrl = `${streamBase}/${config.orgId}/${config.projectId}/gadget-state/${depId}/stream?token=${encodeURIComponent(token)}`;\n const sse = new EventSource(sseUrl);\n sseRef.current = sse;\n\n sse.addEventListener('state-update', (event) => {\n if (cancelled) return;\n try {\n const state = JSON.parse(event.data) as {\n shared: Record<string, unknown>;\n user: Record<string, unknown>;\n userId?: string;\n };\n if (state.userId && !userIdRef.current) userIdRef.current = state.userId;\n latestStateRef.current = state;\n iframeRef.current?.contentWindow?.postMessage(\n { type: 'gadget-state-update', shared: state.shared, user: state.user, userId: userIdRef.current },\n '*',\n );\n } catch {\n // Ignore malformed SSE\n }\n });\n }\n } catch (err) {\n if (!cancelled) {\n const msg = err instanceof Error ? err.message : 'Failed to load gadget';\n setError(msg);\n onError?.(msg);\n }\n } finally {\n if (!cancelled) setLoading(false);\n }\n })();\n\n return () => {\n cancelled = true;\n if (sseRef.current) {\n sseRef.current.close();\n sseRef.current = null;\n }\n };\n }, [gadgetId, base, config.getToken, config.streamBaseUrl, config.orgId, config.projectId, mode]);\n\n // \u2500\u2500 Push initial state on iframe load \u2500\u2500\n useEffect(() => {\n if (!iframeLoaded || !latestStateRef.current) return;\n iframeRef.current?.contentWindow?.postMessage(\n { type: 'gadget-state-init', shared: latestStateRef.current.shared, user: latestStateRef.current.user, userId: userIdRef.current },\n '*',\n );\n }, [iframeLoaded]);\n\n // \u2500\u2500 Push props changes \u2500\u2500\n useEffect(() => {\n if (!iframeLoaded || !props) return;\n iframeRef.current?.contentWindow?.postMessage({ type: 'gadget-set-data', data: props }, '*');\n }, [props, iframeLoaded]);\n\n // \u2500\u2500 Breakout handler \u2500\u2500\n useEffect(() => {\n if (!iframeRef.current || !html || !breakoutEnabled) return;\n const iframe = iframeRef.current;\n\n function clearAncestorClipping() {\n let el = iframe.parentElement;\n while (el && el !== document.body && el !== document.documentElement) {\n const cs = getComputedStyle(el);\n const overflow = cs.overflow + cs.overflowX + cs.overflowY;\n const hasClip = /hidden|auto|scroll|clip/.test(overflow);\n const hasContain = cs.transform !== 'none' || cs.willChange === 'transform' || cs.contain !== 'none' || cs.filter !== 'none';\n\n if (hasClip || hasContain) {\n if (hasClip) {\n ancestorOverridesRef.current.push({ el, key: 'overflow', original: el.style.overflow });\n ancestorOverridesRef.current.push({ el, key: 'overflowX', original: el.style.overflowX });\n ancestorOverridesRef.current.push({ el, key: 'overflowY', original: el.style.overflowY });\n el.style.overflow = 'visible';\n el.style.overflowX = 'visible';\n el.style.overflowY = 'visible';\n }\n if (hasContain && cs.transform !== 'none') {\n ancestorOverridesRef.current.push({ el, key: 'transform', original: el.style.transform });\n el.style.transform = 'none';\n }\n if (hasContain && cs.contain !== 'none') {\n ancestorOverridesRef.current.push({ el, key: 'contain', original: el.style.contain });\n el.style.contain = 'none';\n }\n }\n el = el.parentElement;\n }\n }\n\n function restoreAncestorClipping() {\n for (const { el, key, original } of ancestorOverridesRef.current) {\n (el.style as unknown as Record<string, string>)[key] = original;\n }\n ancestorOverridesRef.current.length = 0;\n }\n\n function onMessage(event: MessageEvent) {\n if (event.source !== iframe.contentWindow) return;\n const d = event.data;\n if (!d || typeof d !== 'object') return;\n\n if (d.type === 'gadget-request-breakout') {\n const rect = iframe.getBoundingClientRect();\n\n // Placeholder to preserve layout\n const ph = document.createElement('div');\n ph.style.width = `${rect.width}px`;\n ph.style.height = `${rect.height}px`;\n ph.style.flexShrink = '0';\n iframe.parentElement?.insertBefore(ph, iframe);\n placeholderRef.current = ph;\n\n clearAncestorClipping();\n setBreakoutActive(true);\n setBreakoutRevealed(false);\n onBreakoutChange?.(true);\n\n iframe.contentWindow?.postMessage(\n { type: 'gadget-breakout-started', originalRect: { x: rect.x, y: rect.y, width: rect.width, height: rect.height } },\n '*',\n );\n\n // Reveal after repositioning\n requestAnimationFrame(() => requestAnimationFrame(() => setBreakoutRevealed(true)));\n }\n\n if (d.type === 'gadget-exit-breakout') {\n if (placeholderRef.current) {\n placeholderRef.current.remove();\n placeholderRef.current = null;\n }\n restoreAncestorClipping();\n setBreakoutActive(false);\n setBreakoutRevealed(false);\n onBreakoutChange?.(false);\n }\n }\n\n window.addEventListener('message', onMessage);\n return () => {\n window.removeEventListener('message', onMessage);\n if (placeholderRef.current) {\n placeholderRef.current.remove();\n placeholderRef.current = null;\n }\n restoreAncestorClipping();\n setBreakoutActive(false);\n setBreakoutRevealed(false);\n };\n }, [html, breakoutEnabled, onBreakoutChange]);\n\n // \u2500\u2500 Bridge handler (actions, interactions, file URL, resize) \u2500\u2500\n const handleMessage = useCallback(\n async (event: MessageEvent<unknown>) => {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const data = event.data as any;\n if (!data || typeof data !== 'object') return;\n if (event.source !== iframeRef.current?.contentWindow) return;\n\n const type = data.type as string;\n\n // Resize (compact only)\n if (type === 'gadget-resize') {\n if (breakoutActiveRef.current || !isCompact) return;\n const h = data.height as number;\n if (h > 0) setNaturalHeight(h);\n return;\n }\n\n // Interaction dispatch\n if (type === 'gadget-interaction' && deploymentIdRef.current) {\n void (async () => {\n try {\n const token = await config.getToken();\n await fetch(`${base}/gadget-interact`, {\n method: 'POST',\n headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },\n body: JSON.stringify({\n deploymentId: deploymentIdRef.current,\n action: data.action as string,\n data: (data.data as Record<string, unknown>) ?? {},\n }),\n });\n } catch {\n // Fire-and-forget\n }\n })();\n return;\n }\n\n // File URL resolution\n if (type === 'gadget-file-url-request') {\n const requestId = data.requestId as string;\n const fileId = data.fileId as string;\n if (!requestId || !fileId) return;\n void (async () => {\n try {\n const url = await resolveFileUrl(fileId);\n iframeRef.current?.contentWindow?.postMessage({ type: 'gadget-file-url-response', requestId, url }, '*');\n } catch (err) {\n iframeRef.current?.contentWindow?.postMessage(\n { type: 'gadget-file-url-response', requestId, error: err instanceof Error ? err.message : 'Failed to resolve file URL' },\n '*',\n );\n }\n })();\n return;\n }\n\n // Action execution\n if (type === 'gadget-action-request') {\n const requestId = data.requestId as string;\n const input = (data.input as Record<string, unknown>) || {};\n const entity = entityRef.current;\n\n if (!entity?.data.actionRef?.id) {\n iframeRef.current?.contentWindow?.postMessage(\n { type: 'gadget-action-response', requestId, error: 'No action configured' },\n '*',\n );\n return;\n }\n\n try {\n const token = await config.getToken();\n const res = await fetch(`${base}/chat/execute-gadget`, {\n method: 'POST',\n headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },\n body: JSON.stringify({ gadgetId, input }),\n });\n\n const result = (await res.json()) as { status?: string; error?: string; errorMessage?: string; output?: unknown };\n\n if (!res.ok) {\n iframeRef.current?.contentWindow?.postMessage(\n { type: 'gadget-action-response', requestId, error: result.error || `HTTP ${res.status}` },\n '*',\n );\n } else if (result.status === 'failure') {\n iframeRef.current?.contentWindow?.postMessage(\n { type: 'gadget-action-response', requestId, error: result.errorMessage || 'Action failed' },\n '*',\n );\n } else {\n iframeRef.current?.contentWindow?.postMessage(\n { type: 'gadget-action-response', requestId, result: result.output },\n '*',\n );\n }\n } catch (err) {\n iframeRef.current?.contentWindow?.postMessage(\n { type: 'gadget-action-response', requestId, error: err instanceof Error ? err.message : 'Unknown error' },\n '*',\n );\n }\n }\n },\n [base, config.getToken, resolveFileUrl, gadgetId, isCompact],\n );\n\n useEffect(() => {\n window.addEventListener('message', handleMessage);\n return () => window.removeEventListener('message', handleMessage);\n }, [handleMessage]);\n\n // \u2500\u2500 Render \u2500\u2500\n\n if (error) {\n return (\n <div className={className} style={{ padding: '8px 12px', fontSize: 12, color: '#b91c1c', background: '#fef2f2', border: '1px solid #fecaca', borderRadius: 8 }}>\n {error}\n </div>\n );\n }\n\n if (loading) {\n return (\n <div className={className} style={{ display: 'flex', alignItems: 'center', gap: 8, padding: '12px', fontSize: 12, color: '#6b7280' }}>\n <span style={{ display: 'inline-block', width: 16, height: 16, border: '2px solid #d1d5db', borderTopColor: '#6b7280', borderRadius: '50%', animation: 'gadget-spin 0.6s linear infinite' }} />\n Loading gadget...\n <style>{`@keyframes gadget-spin { to { transform: rotate(360deg) } }`}</style>\n </div>\n );\n }\n\n if (!html) return null;\n\n const compactStyle = breakoutActive\n ? {\n position: 'fixed' as const,\n top: 0, left: 0,\n width: '100vw', height: '100vh',\n zIndex: 99999,\n background: 'transparent',\n border: 'none', borderRadius: 0,\n maxWidth: 'none', maxHeight: 'none',\n margin: 0, transform: 'none',\n pointerEvents: 'none' as const,\n overflow: 'visible',\n visibility: breakoutRevealed ? 'visible' as const : 'hidden' as const,\n }\n : {\n width: '100%',\n height: iframeHeight,\n border: 'none',\n borderRadius: 8,\n overflow: isCapped ? undefined : ('hidden' as const),\n };\n\n const fullStyle = {\n width: '100%',\n height: '100%',\n border: 'none',\n };\n\n return (\n <div className={className} style={isCompact ? { position: 'relative' } : { width: '100%', height: '100%' }}>\n <iframe\n ref={iframeRef}\n srcDoc={html}\n style={isCompact ? compactStyle : fullStyle}\n scrolling={isCompact && !breakoutActive && !isCapped ? 'no' : undefined}\n sandbox=\"allow-scripts allow-same-origin allow-popups allow-popups-to-escape-sandbox\"\n title=\"Gadget\"\n onLoad={() => setIframeLoaded(true)}\n />\n </div>\n );\n}\n", "/**\n * Creates a self-contained HTML string for rendering a gadget component in an iframe.\n *\n * Loads React 18, ReactDOM, Babel (for JSX transpilation), and Tailwind CSS from CDNs.\n * Sets up the full gadget bridge: state, breakout, actions, chat, context, and hot-swap.\n *\n * Usage:\n * import { createGadgetRenderer, setupGadgetBreakout } from '@gigabuddy/chat';\n *\n * const html = createGadgetRenderer(componentCode, data, { viewport: 'compact', stateEnabled: true });\n * iframe.srcdoc = html;\n * setupGadgetBreakout(iframe);\n *\n * The gadget component receives these props:\n * function Gadget({ data, viewport, state, userId, breakout, chat, context })\n *\n * Bridge protocol (postMessage):\n * - Host \u2192 iframe: `gadget-set-data` \u2014 push new props\n * - Host \u2192 iframe: `gadget-state-init` / `gadget-state-update` \u2014 state changes\n * - Host \u2192 iframe: `gadget-update-component` \u2014 hot-swap component code\n * - Host \u2192 iframe: `gadget-breakout-started` \u2014 breakout activated with originalRect\n * - iframe \u2192 Host: `gadget-interaction` \u2014 user dispatched an action\n * - iframe \u2192 Host: `gadget-resize` \u2014 auto-height\n * - iframe \u2192 Host: `gadget-request-breakout` / `gadget-exit-breakout` \u2014 breakout lifecycle\n * - iframe \u2192 Host: `gadget-action-request` / `gadget-chat-request` / `gadget-context-request` \u2014 API calls\n */\nexport function createGadgetRenderer(\n componentCode: string,\n data: unknown = {},\n options?: {\n viewport?: 'compact' | 'full' | 'mobile';\n stateEnabled?: boolean;\n chatEnabled?: boolean;\n contextEnabled?: boolean;\n assets?: Record<string, { url: string; name: string }>;\n },\n): string {\n const serializedData = JSON.stringify(data);\n const viewport = options?.viewport ?? 'full';\n const stateEnabled = options?.stateEnabled ?? false;\n const chatEnabled = options?.chatEnabled ?? false;\n const contextEnabled = options?.contextEnabled ?? false;\n const escapedCode = componentCode.replace(/<\\/script>/g, '<\\\\/script>');\n const serializedAssets = JSON.stringify(options?.assets ?? {});\n\n const stateBridgeScript = stateEnabled\n ? `\n window.gadget.state = {\n shared: {},\n user: {},\n userId: null,\n _sharedCallbacks: [],\n _userCallbacks: [],\n\n dispatch: function(action, data) {\n window.parent.postMessage({ type: 'gadget-interaction', action: action, data: data || {} }, '*');\n },\n\n onSharedChange: function(callback) {\n window.gadget.state._sharedCallbacks.push(callback);\n callback(window.gadget.state.shared);\n return function() {\n var i = window.gadget.state._sharedCallbacks.indexOf(callback);\n if (i !== -1) window.gadget.state._sharedCallbacks.splice(i, 1);\n };\n },\n\n onUserChange: function(callback) {\n window.gadget.state._userCallbacks.push(callback);\n callback(window.gadget.state.user);\n return function() {\n var i = window.gadget.state._userCallbacks.indexOf(callback);\n if (i !== -1) window.gadget.state._userCallbacks.splice(i, 1);\n };\n },\n };\n\n window.addEventListener('message', function(event) {\n var d = event.data;\n if (d && (d.type === 'gadget-state-init' || d.type === 'gadget-state-update')) {\n if (d.userId !== undefined) {\n window.gadget.state.userId = d.userId;\n }\n if (d.shared !== undefined) {\n window.gadget.state.shared = d.shared;\n window.gadget.state._sharedCallbacks.forEach(function(cb) { try { cb(d.shared); } catch(e) {} });\n }\n if (d.user !== undefined) {\n window.gadget.state.user = d.user;\n window.gadget.state._userCallbacks.forEach(function(cb) { try { cb(d.user); } catch(e) {} });\n }\n window.__rerenderGadget();\n }\n });`\n : '';\n\n const chatBridgeScript = chatEnabled\n ? `\n window.gadget.chat = {\n _request: function(method, params) {\n var requestId = Math.random().toString(36).slice(2) + Date.now().toString(36);\n return new Promise(function(resolve, reject) {\n var handler = function(event) {\n var d = event.data;\n if (d && d.type === 'gadget-chat-response' && d.requestId === requestId) {\n window.removeEventListener('message', handler);\n if (d.error) reject(new Error(d.error));\n else resolve(d.result);\n }\n };\n window.addEventListener('message', handler);\n setTimeout(function() { window.removeEventListener('message', handler); reject(new Error('Timed out')); }, 30000);\n window.parent.postMessage({ type: 'gadget-chat-request', requestId: requestId, method: method, params: params || {} }, '*');\n });\n },\n\n _eventCallbacks: [],\n\n createChannel: function(opts) { return window.gadget.chat._request('createChannel', opts); },\n findOrCreateChannel: function(name, opts) { return window.gadget.chat._request('findOrCreateChannel', { name: name, description: opts && opts.description }); },\n listChannels: function() { return window.gadget.chat._request('listChannels'); },\n joinChannel: function(conversationId) { return window.gadget.chat._request('joinChannel', { conversationId: conversationId }); },\n sendMessage: function(conversationId, text) { return window.gadget.chat._request('sendMessage', { conversationId: conversationId, text: text }); },\n getMessages: function(conversationId, opts) { return window.gadget.chat._request('getMessages', { conversationId: conversationId, limit: opts && opts.limit, before: opts && opts.before }); },\n updateChannel: function(conversationId, updates) { return window.gadget.chat._request('updateChannel', { conversationId: conversationId, description: updates && updates.description }); },\n createInvite: function(conversationId) { return window.gadget.chat._request('createInvite', { conversationId: conversationId }); },\n redeemInvite: function(token) { return window.gadget.chat._request('redeemInvite', { token: token }); },\n\n onEvent: function(callback) {\n window.gadget.chat._eventCallbacks.push(callback);\n return function() {\n var i = window.gadget.chat._eventCallbacks.indexOf(callback);\n if (i !== -1) window.gadget.chat._eventCallbacks.splice(i, 1);\n };\n },\n };\n\n window.addEventListener('message', function(event) {\n var d = event.data;\n if (d && d.type === 'gadget-chat-event') {\n window.gadget.chat._eventCallbacks.forEach(function(cb) { try { cb(d.event); } catch(e) {} });\n window.__rerenderGadget();\n }\n });`\n : '';\n\n const contextBridgeScript = contextEnabled\n ? `\n window.gadget.context = {\n _request: function(method, params) {\n var requestId = Math.random().toString(36).slice(2) + Date.now().toString(36);\n return new Promise(function(resolve, reject) {\n var handler = function(event) {\n var d = event.data;\n if (d && d.type === 'gadget-context-response' && d.id === requestId) {\n window.removeEventListener('message', handler);\n if (d.error) reject(new Error(d.error));\n else resolve(d.result);\n }\n };\n window.addEventListener('message', handler);\n setTimeout(function() { window.removeEventListener('message', handler); reject(new Error('Timed out')); }, 30000);\n window.parent.postMessage({ type: 'gadget-context-request', id: requestId, method: method, params: params || {} }, '*');\n });\n },\n\n _eventCallbacks: [],\n\n listTypes: function() { return window.gadget.context._request('listTypes', {}); },\n getType: function(contextType) { return window.gadget.context._request('getType', { contextType: contextType }); },\n listInstances: function(params) { return window.gadget.context._request('listInstances', params || {}); },\n getInstance: function(id) { return window.gadget.context._request('getInstance', { id: id }); },\n createInstance: function(params) { return window.gadget.context._request('createInstance', params); },\n updateInstance: function(id, data) { return window.gadget.context._request('updateInstance', { id: id, data: data }); },\n deleteInstance: function(id) { return window.gadget.context._request('deleteInstance', { id: id }); },\n searchKnowledge: function(params) { return window.gadget.context._request('searchKnowledge', params); },\n getEnriched: function(id) { return window.gadget.context._request('getEnriched', { id: id }); },\n getRelated: function(id) { return window.gadget.context._request('getRelated', { id: id }); },\n\n onEvent: function(callback) {\n window.gadget.context._eventCallbacks.push(callback);\n return function() {\n var i = window.gadget.context._eventCallbacks.indexOf(callback);\n if (i !== -1) window.gadget.context._eventCallbacks.splice(i, 1);\n };\n },\n };\n\n window.addEventListener('message', function(event) {\n var d = event.data;\n if (d && d.type === 'gadget-context-event') {\n window.gadget.context._eventCallbacks.forEach(function(cb) { try { cb(d.event); } catch(e) {} });\n window.__rerenderGadget();\n }\n });`\n : '';\n\n // When state is enabled, pass state prop alongside data and viewport\n const chatPropFragment = chatEnabled ? ', chat: window.gadget.chat' : '';\n const contextPropFragment = contextEnabled ? ', context: window.gadget.context' : '';\n const breakoutPropFragment =\n ', breakout: { active: window.gadget.breakout._active, originalRect: window.gadget.breakout._originalRect, request: window.gadget.breakout.request, exit: window.gadget.breakout.exit }';\n const componentProps = stateEnabled\n ? `{ data: window.__GADGET_DATA__, viewport: window.__GADGET_VIEWPORT__, state: window.gadget.state ? { shared: window.gadget.state.shared, user: window.gadget.state.user } : undefined, userId: window.gadget.state ? window.gadget.state.userId : undefined${chatPropFragment}${contextPropFragment}${breakoutPropFragment} }`\n : `{ data: window.__GADGET_DATA__, viewport: window.__GADGET_VIEWPORT__${chatPropFragment}${contextPropFragment}${breakoutPropFragment} }`;\n\n return `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n <script src=\"https://cdn.jsdelivr.net/npm/react@18/umd/react.production.min.js\"></script>\n <script src=\"https://cdn.jsdelivr.net/npm/react-dom@18/umd/react-dom.production.min.js\"></script>\n <script src=\"https://cdn.jsdelivr.net/npm/@babel/standalone@7/babel.min.js\"></script>\n <script src=\"https://cdn.tailwindcss.com\"></script>\n <style>\n * { margin: 0; padding: 0; box-sizing: border-box; }\n html, body { background: transparent; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; min-height: 100%; }\n #root { min-height: 100vh; }\n .gadget-error {\n padding: 16px;\n background: #fef2f2;\n border: 1px solid #fecaca;\n border-radius: 8px;\n color: #991b1b;\n font-family: monospace;\n font-size: 13px;\n white-space: pre-wrap;\n word-break: break-word;\n }\n .gadget-error-title {\n font-weight: 600;\n margin-bottom: 8px;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n }\n </style>\n</head>\n<body>\n <div id=\"root\"></div>\n <script>\n window.__GADGET_DATA__ = ${serializedData};\n window.__GADGET_VIEWPORT__ = '${viewport}';\n\n window.gadget = {\n data: window.__GADGET_DATA__,\n assets: ${serializedAssets},\n\n breakout: {\n _active: false,\n _originalRect: null,\n request: function() {\n if (window.gadget.breakout._active) return;\n window.parent.postMessage({ type: 'gadget-request-breakout' }, '*');\n },\n exit: function() {\n if (!window.gadget.breakout._active) return;\n window.gadget.breakout._active = false;\n window.gadget.breakout._originalRect = null;\n window.parent.postMessage({ type: 'gadget-exit-breakout' }, '*');\n window.__rerenderGadget();\n },\n },\n\n callAction: function(input) {\n var requestId = Math.random().toString(36).slice(2) + Date.now().toString(36);\n return new Promise(function(resolve, reject) {\n var handler = function(event) {\n var d = event.data;\n if (d && d.type === 'gadget-action-response' && d.requestId === requestId) {\n window.removeEventListener('message', handler);\n if (d.error) reject(new Error(d.error));\n else resolve(d.result);\n }\n };\n window.addEventListener('message', handler);\n setTimeout(function() {\n window.removeEventListener('message', handler);\n reject(new Error('Action timed out'));\n }, 30000);\n window.parent.postMessage({ type: 'gadget-action-request', requestId: requestId, input: input }, '*');\n });\n },\n };\n${stateBridgeScript}\n${chatBridgeScript}\n${contextBridgeScript}\n\n window.__gadgetRoot = null;\n window.__gadgetComponent = null;\n\n window.__rerenderGadget = function() {\n if (window.__gadgetRoot && window.__gadgetComponent) {\n var C = window.__gadgetComponent;\n var EB = window.__gadgetErrorBoundary;\n window.__gadgetRoot.render(\n React.createElement(EB, null, React.createElement(C, ${componentProps}))\n );\n }\n };\n\n window.addEventListener('message', function(event) {\n var d = event.data;\n if (d && d.type === 'gadget-set-data') {\n window.__GADGET_DATA__ = d.data;\n window.gadget.data = d.data;\n window.__rerenderGadget();\n }\n if (d && d.type === 'gadget-breakout-started') {\n window.gadget.breakout._active = true;\n window.gadget.breakout._originalRect = d.originalRect || null;\n window.__rerenderGadget();\n }\n if (d && d.type === 'gadget-update-component' && d.code) {\n try {\n var compiled = Babel.transform(d.code, { presets: ['react'] }).code;\n var fn = new Function('React', 'useState', 'useEffect', 'useCallback', 'useMemo', 'useRef',\n compiled + '\\\\nreturn typeof Gadget !== \"undefined\" ? Gadget : null;');\n var NewComponent = fn(React, React.useState, React.useEffect, React.useCallback, React.useMemo, React.useRef);\n if (NewComponent) {\n window.__gadgetComponent = NewComponent;\n if (window.__gadgetErrorBoundaryInstance) {\n window.__gadgetErrorBoundaryInstance.setState({ error: null });\n }\n window.__rerenderGadget();\n }\n } catch (err) {\n console.error('[gadget-hmr] Component update failed:', err);\n }\n }\n });\n </script>\n <script type=\"text/babel\" data-type=\"module\">\n const { useState, useEffect, useCallback, useMemo, useRef } = React;\n\n class ErrorBoundary extends React.Component {\n constructor(props) {\n super(props);\n this.state = { error: null };\n window.__gadgetErrorBoundaryInstance = this;\n }\n static getDerivedStateFromError(error) {\n return { error };\n }\n render() {\n if (this.state.error) {\n return React.createElement('div', { className: 'gadget-error' },\n React.createElement('div', { className: 'gadget-error-title' }, 'Runtime Error'),\n this.state.error.message\n );\n }\n return this.props.children;\n }\n }\n window.__gadgetErrorBoundary = ErrorBoundary;\n\n try {\n ${escapedCode}\n\n const ComponentToRender = typeof Gadget !== 'undefined' ? Gadget : null;\n\n if (ComponentToRender) {\n window.__gadgetComponent = ComponentToRender;\n const root = ReactDOM.createRoot(document.getElementById('root'));\n window.__gadgetRoot = root;\n root.render(\n <ErrorBoundary>\n <ComponentToRender data={window.__GADGET_DATA__} viewport={window.__GADGET_VIEWPORT__}${stateEnabled ? ' state={window.gadget.state ? { shared: window.gadget.state.shared, user: window.gadget.state.user } : undefined} userId={window.gadget.state ? window.gadget.state.userId : undefined}' : ''}${chatEnabled ? ' chat={window.gadget.chat}' : ''}${contextEnabled ? ' context={window.gadget.context}' : ''} breakout={{ active: window.gadget.breakout._active, originalRect: window.gadget.breakout._originalRect, request: window.gadget.breakout.request, exit: window.gadget.breakout.exit }} />\n </ErrorBoundary>\n );\n } else {\n document.getElementById('root').innerHTML =\n '<div class=\"gadget-error\"><div class=\"gadget-error-title\">No component found</div>Define a function called Gadget.</div>';\n }\n } catch (err) {\n document.getElementById('root').innerHTML =\n '<div class=\"gadget-error\"><div class=\"gadget-error-title\">Error</div>' +\n err.message.replace(/</g, '&lt;').replace(/>/g, '&gt;') +\n '</div>';\n }\n\n const rootEl = document.getElementById('root');\n const observer = new ResizeObserver(() => {\n window.parent.postMessage({\n type: 'gadget-resize',\n height: rootEl.scrollHeight,\n }, '*');\n });\n observer.observe(rootEl);\n </script>\n</body>\n</html>`;\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { createContext, useContext, useMemo, type ReactNode } from 'react';\n\nexport interface GadgetConfig {\n /** Base API URL (e.g. \"https://api.gigabuddy.com\") */\n apiUrl: string;\n /** Organization ID */\n orgId: string;\n /** Project ID */\n projectId: string;\n /** Returns a fresh auth token */\n getToken: () => Promise<string>;\n /** Optional SSE stream base URL (falls back to apiUrl) */\n streamBaseUrl?: string;\n}\n\ninterface GadgetContextValue {\n config: GadgetConfig;\n /** Resolves a file ID to a fresh signed URL */\n resolveFileUrl: (fileId: string) => Promise<string>;\n}\n\nconst GadgetCtx = createContext<GadgetContextValue | null>(null);\n\nexport function GadgetProvider({ config, children }: { config: GadgetConfig; children: ReactNode }) {\n const value = useMemo<GadgetContextValue>(() => {\n const base = `${config.apiUrl}/${config.orgId}/${config.projectId}`;\n\n return {\n config,\n resolveFileUrl: async (fileId: string) => {\n const token = await config.getToken();\n const res = await fetch(`${base}/context/get-file-url`, {\n method: 'POST',\n headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },\n body: JSON.stringify({ fileId }),\n });\n if (!res.ok) throw new Error(`HTTP ${res.status}`);\n const data = (await res.json()) as { url: string };\n return data.url;\n },\n };\n }, [config.apiUrl, config.orgId, config.projectId, config.getToken, config.streamBaseUrl]);\n\n return <GadgetCtx.Provider value={value}>{children}</GadgetCtx.Provider>;\n}\n\nexport function useGadgetConfig(): GadgetContextValue {\n const ctx = useContext(GadgetCtx);\n if (!ctx) throw new Error('GadgetFrame must be wrapped in a <GadgetProvider>');\n return ctx;\n}\n", "import { useCallback, useEffect, useRef, useState } from 'react';\nimport { createGadgetRenderer } from '../createGadgetRenderer.js';\nimport { useGadgetConfig } from './GadgetContext.js';\n\n// =============================================================================\n// Types\n// =============================================================================\n\nexport interface GadgetFrameProps {\n /** The gadget entity ID to load */\n gadgetId: string;\n /** Data props to pass to the gadget */\n props?: Record<string, unknown>;\n /** Display mode \u2014 compact (inline, resizable) or full (fills container) */\n mode?: 'compact' | 'full';\n /** Whether breakout is enabled (default: true in compact mode) */\n breakout?: boolean;\n /** Max height in compact mode before scrolling (default: 300) */\n maxHeight?: number;\n /** Deployment ID for mission-backed gadgets (auto-generated if not provided) */\n deploymentId?: string;\n /** Conversation ID \u2014 used when updating message content after action */\n conversationId?: string;\n /** Message ID \u2014 used when updating message content after action */\n messageId?: string;\n /** Additional className for the wrapper div */\n className?: string;\n /** Called when breakout state changes */\n onBreakoutChange?: (active: boolean) => void;\n /** Called on load error */\n onError?: (error: string) => void;\n}\n\ninterface GadgetEntity {\n data: {\n type: string;\n componentCode: string;\n actionRef?: { type: string; id: string };\n missionRef?: { type: string; id: string };\n stateBindings?: {\n shared?: { contextFields: string[] };\n user?: { contextFields: string[] };\n };\n assets?: Record<string, { fileId: string; url: string; name: string; contentType: string }>;\n };\n}\n\n// =============================================================================\n// Component\n// =============================================================================\n\nexport function GadgetFrame({\n gadgetId,\n props,\n mode = 'compact',\n breakout: breakoutEnabled = true,\n maxHeight = 300,\n deploymentId: externalDeploymentId,\n conversationId,\n messageId,\n className,\n onBreakoutChange,\n onError,\n}: GadgetFrameProps) {\n const { config, resolveFileUrl } = useGadgetConfig();\n const base = `${config.apiUrl}/${config.orgId}/${config.projectId}`;\n\n // \u2500\u2500 State \u2500\u2500\n const [html, setHtml] = useState<string | null>(null);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<string | null>(null);\n const [naturalHeight, setNaturalHeight] = useState(60);\n const [iframeLoaded, setIframeLoaded] = useState(false);\n const [breakoutActive, setBreakoutActive] = useState(false);\n const [breakoutRevealed, setBreakoutRevealed] = useState(false);\n\n // \u2500\u2500 Refs \u2500\u2500\n const iframeRef = useRef<HTMLIFrameElement>(null);\n const entityRef = useRef<GadgetEntity | null>(null);\n const initialPropsRef = useRef(props);\n const deploymentIdRef = useRef<string | null>(externalDeploymentId ?? null);\n const sseRef = useRef<EventSource | null>(null);\n const userIdRef = useRef<string | null>(null);\n const latestStateRef = useRef<{ shared: Record<string, unknown>; user: Record<string, unknown> } | null>(null);\n const placeholderRef = useRef<HTMLDivElement | null>(null);\n const ancestorOverridesRef = useRef<{ el: HTMLElement; key: string; original: string }[]>([]);\n const breakoutActiveRef = useRef(false);\n breakoutActiveRef.current = breakoutActive;\n\n // \u2500\u2500 Derived \u2500\u2500\n const isCompact = mode === 'compact';\n const isCapped = isCompact && naturalHeight > maxHeight;\n const iframeHeight = isCapped ? maxHeight : naturalHeight;\n\n // \u2500\u2500 Fetch entity + build HTML + deploy \u2500\u2500\n useEffect(() => {\n let cancelled = false;\n\n (async () => {\n try {\n const token = await config.getToken();\n const res = await fetch(`${base}/chat/get-gadget`, {\n method: 'POST',\n headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },\n body: JSON.stringify({ gadgetId }),\n });\n if (!res.ok) throw new Error(`Failed to load gadget: ${res.status}`);\n\n const entity = (await res.json()) as GadgetEntity;\n if (cancelled) return;\n\n entityRef.current = entity;\n const hasMission = entity.data.missionRef?.id != null;\n\n const assetMap = entity.data.assets\n ? Object.fromEntries(Object.entries(entity.data.assets).map(([k, v]) => [k, { url: v.url, name: v.name }]))\n : undefined;\n\n const builtHtml = createGadgetRenderer(entity.data.componentCode, initialPropsRef.current ?? {}, {\n viewport: mode,\n stateEnabled: hasMission,\n assets: assetMap,\n });\n setHtml(builtHtml);\n\n // Deploy if mission-backed\n if (hasMission) {\n const depId = externalDeploymentId ?? messageId ?? `gadget_${gadgetId}_${Date.now()}`;\n deploymentIdRef.current = depId;\n\n const deployRes = await fetch(`${base}/gadget-deploy`, {\n method: 'POST',\n headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },\n body: JSON.stringify({\n gadgetId,\n deploymentId: depId,\n initialData: initialPropsRef.current,\n conversationId,\n }),\n });\n if (!deployRes.ok) throw new Error(`Failed to deploy gadget: ${deployRes.status}`);\n\n const deployData = (await deployRes.json()) as {\n deploymentId: string;\n missionInstanceId: string;\n initialState: { shared: Record<string, unknown>; user: Record<string, unknown> };\n userId?: string;\n };\n if (cancelled) return;\n\n if (deployData.userId) userIdRef.current = deployData.userId;\n latestStateRef.current = deployData.initialState;\n\n // Connect SSE\n const streamBase = config.streamBaseUrl ?? config.apiUrl;\n const sseUrl = `${streamBase}/${config.orgId}/${config.projectId}/gadget-state/${depId}/stream?token=${encodeURIComponent(token)}`;\n const sse = new EventSource(sseUrl);\n sseRef.current = sse;\n\n sse.addEventListener('state-update', (event) => {\n if (cancelled) return;\n try {\n const state = JSON.parse(event.data) as {\n shared: Record<string, unknown>;\n user: Record<string, unknown>;\n userId?: string;\n };\n if (state.userId && !userIdRef.current) userIdRef.current = state.userId;\n latestStateRef.current = state;\n iframeRef.current?.contentWindow?.postMessage(\n { type: 'gadget-state-update', shared: state.shared, user: state.user, userId: userIdRef.current },\n '*',\n );\n } catch {\n // Ignore malformed SSE\n }\n });\n }\n } catch (err) {\n if (!cancelled) {\n const msg = err instanceof Error ? err.message : 'Failed to load gadget';\n setError(msg);\n onError?.(msg);\n }\n } finally {\n if (!cancelled) setLoading(false);\n }\n })();\n\n return () => {\n cancelled = true;\n if (sseRef.current) {\n sseRef.current.close();\n sseRef.current = null;\n }\n };\n }, [gadgetId, base, config.getToken, config.streamBaseUrl, config.orgId, config.projectId, mode]);\n\n // \u2500\u2500 Push initial state on iframe load \u2500\u2500\n useEffect(() => {\n if (!iframeLoaded || !latestStateRef.current) return;\n iframeRef.current?.contentWindow?.postMessage(\n {\n type: 'gadget-state-init',\n shared: latestStateRef.current.shared,\n user: latestStateRef.current.user,\n userId: userIdRef.current,\n },\n '*',\n );\n }, [iframeLoaded]);\n\n // \u2500\u2500 Push props changes \u2500\u2500\n useEffect(() => {\n if (!iframeLoaded || !props) return;\n iframeRef.current?.contentWindow?.postMessage({ type: 'gadget-set-data', data: props }, '*');\n }, [props, iframeLoaded]);\n\n // \u2500\u2500 Breakout handler \u2500\u2500\n useEffect(() => {\n if (!iframeRef.current || !html || !breakoutEnabled) return;\n const iframe = iframeRef.current;\n\n function clearAncestorClipping() {\n let el = iframe.parentElement;\n while (el && el !== document.body && el !== document.documentElement) {\n const cs = getComputedStyle(el);\n const overflow = cs.overflow + cs.overflowX + cs.overflowY;\n const hasClip = /hidden|auto|scroll|clip/.test(overflow);\n const hasContain =\n cs.transform !== 'none' || cs.willChange === 'transform' || cs.contain !== 'none' || cs.filter !== 'none';\n\n if (hasClip || hasContain) {\n if (hasClip) {\n ancestorOverridesRef.current.push({ el, key: 'overflow', original: el.style.overflow });\n ancestorOverridesRef.current.push({ el, key: 'overflowX', original: el.style.overflowX });\n ancestorOverridesRef.current.push({ el, key: 'overflowY', original: el.style.overflowY });\n el.style.overflow = 'visible';\n el.style.overflowX = 'visible';\n el.style.overflowY = 'visible';\n }\n if (hasContain && cs.transform !== 'none') {\n ancestorOverridesRef.current.push({ el, key: 'transform', original: el.style.transform });\n el.style.transform = 'none';\n }\n if (hasContain && cs.contain !== 'none') {\n ancestorOverridesRef.current.push({ el, key: 'contain', original: el.style.contain });\n el.style.contain = 'none';\n }\n }\n el = el.parentElement;\n }\n }\n\n function restoreAncestorClipping() {\n for (const { el, key, original } of ancestorOverridesRef.current) {\n (el.style as unknown as Record<string, string>)[key] = original;\n }\n ancestorOverridesRef.current.length = 0;\n }\n\n function onMessage(event: MessageEvent) {\n if (event.source !== iframe.contentWindow) return;\n const d = event.data;\n if (!d || typeof d !== 'object') return;\n\n if (d.type === 'gadget-request-breakout') {\n const rect = iframe.getBoundingClientRect();\n\n // Placeholder to preserve layout\n const ph = document.createElement('div');\n ph.style.width = `${rect.width}px`;\n ph.style.height = `${rect.height}px`;\n ph.style.flexShrink = '0';\n iframe.parentElement?.insertBefore(ph, iframe);\n placeholderRef.current = ph;\n\n clearAncestorClipping();\n setBreakoutActive(true);\n setBreakoutRevealed(false);\n onBreakoutChange?.(true);\n\n iframe.contentWindow?.postMessage(\n {\n type: 'gadget-breakout-started',\n originalRect: { x: rect.x, y: rect.y, width: rect.width, height: rect.height },\n },\n '*',\n );\n\n // Reveal after repositioning\n requestAnimationFrame(() => requestAnimationFrame(() => setBreakoutRevealed(true)));\n }\n\n if (d.type === 'gadget-exit-breakout') {\n if (placeholderRef.current) {\n placeholderRef.current.remove();\n placeholderRef.current = null;\n }\n restoreAncestorClipping();\n setBreakoutActive(false);\n setBreakoutRevealed(false);\n onBreakoutChange?.(false);\n }\n }\n\n window.addEventListener('message', onMessage);\n return () => {\n window.removeEventListener('message', onMessage);\n if (placeholderRef.current) {\n placeholderRef.current.remove();\n placeholderRef.current = null;\n }\n restoreAncestorClipping();\n setBreakoutActive(false);\n setBreakoutRevealed(false);\n };\n }, [html, breakoutEnabled, onBreakoutChange]);\n\n // \u2500\u2500 Bridge handler (actions, interactions, file URL, resize) \u2500\u2500\n const handleMessage = useCallback(\n async (event: MessageEvent<unknown>) => {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const data = event.data as any;\n if (!data || typeof data !== 'object') return;\n if (event.source !== iframeRef.current?.contentWindow) return;\n\n const type = data.type as string;\n\n // Resize (compact only)\n if (type === 'gadget-resize') {\n if (breakoutActiveRef.current || !isCompact) return;\n const h = data.height as number;\n if (h > 0) setNaturalHeight(h);\n return;\n }\n\n // Interaction dispatch\n if (type === 'gadget-interaction' && deploymentIdRef.current) {\n void (async () => {\n try {\n const token = await config.getToken();\n await fetch(`${base}/gadget-interact`, {\n method: 'POST',\n headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },\n body: JSON.stringify({\n deploymentId: deploymentIdRef.current,\n action: data.action as string,\n data: (data.data as Record<string, unknown>) ?? {},\n }),\n });\n } catch {\n // Fire-and-forget\n }\n })();\n return;\n }\n\n // File URL resolution\n if (type === 'gadget-file-url-request') {\n const requestId = data.requestId as string;\n const fileId = data.fileId as string;\n if (!requestId || !fileId) return;\n void (async () => {\n try {\n const url = await resolveFileUrl(fileId);\n iframeRef.current?.contentWindow?.postMessage({ type: 'gadget-file-url-response', requestId, url }, '*');\n } catch (err) {\n iframeRef.current?.contentWindow?.postMessage(\n {\n type: 'gadget-file-url-response',\n requestId,\n error: err instanceof Error ? err.message : 'Failed to resolve file URL',\n },\n '*',\n );\n }\n })();\n return;\n }\n\n // Action execution\n if (type === 'gadget-action-request') {\n const requestId = data.requestId as string;\n const input = (data.input as Record<string, unknown>) || {};\n const entity = entityRef.current;\n\n if (!entity?.data.actionRef?.id) {\n iframeRef.current?.contentWindow?.postMessage(\n { type: 'gadget-action-response', requestId, error: 'No action configured' },\n '*',\n );\n return;\n }\n\n try {\n const token = await config.getToken();\n const res = await fetch(`${base}/chat/execute-gadget`, {\n method: 'POST',\n headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },\n body: JSON.stringify({ gadgetId, input }),\n });\n\n const result = (await res.json()) as {\n status?: string;\n error?: string;\n errorMessage?: string;\n output?: unknown;\n };\n\n if (!res.ok) {\n iframeRef.current?.contentWindow?.postMessage(\n { type: 'gadget-action-response', requestId, error: result.error || `HTTP ${res.status}` },\n '*',\n );\n } else if (result.status === 'failure') {\n iframeRef.current?.contentWindow?.postMessage(\n { type: 'gadget-action-response', requestId, error: result.errorMessage || 'Action failed' },\n '*',\n );\n } else {\n iframeRef.current?.contentWindow?.postMessage(\n { type: 'gadget-action-response', requestId, result: result.output },\n '*',\n );\n }\n } catch (err) {\n iframeRef.current?.contentWindow?.postMessage(\n { type: 'gadget-action-response', requestId, error: err instanceof Error ? err.message : 'Unknown error' },\n '*',\n );\n }\n }\n },\n [base, config.getToken, resolveFileUrl, gadgetId, isCompact],\n );\n\n useEffect(() => {\n window.addEventListener('message', handleMessage);\n return () => window.removeEventListener('message', handleMessage);\n }, [handleMessage]);\n\n // \u2500\u2500 Render \u2500\u2500\n\n if (error) {\n return (\n <div\n className={className}\n style={{\n padding: '8px 12px',\n fontSize: 12,\n color: '#b91c1c',\n background: '#fef2f2',\n border: '1px solid #fecaca',\n borderRadius: 8,\n }}\n >\n {error}\n </div>\n );\n }\n\n if (loading) {\n return (\n <div\n className={className}\n style={{ display: 'flex', alignItems: 'center', gap: 8, padding: '12px', fontSize: 12, color: '#6b7280' }}\n >\n <span\n style={{\n display: 'inline-block',\n width: 16,\n height: 16,\n border: '2px solid #d1d5db',\n borderTopColor: '#6b7280',\n borderRadius: '50%',\n animation: 'gadget-spin 0.6s linear infinite',\n }}\n />\n Loading gadget...\n <style>{`@keyframes gadget-spin { to { transform: rotate(360deg) } }`}</style>\n </div>\n );\n }\n\n if (!html) return null;\n\n const compactStyle = breakoutActive\n ? {\n position: 'fixed' as const,\n top: 0,\n left: 0,\n width: '100vw',\n height: '100vh',\n zIndex: 99999,\n background: 'transparent',\n border: 'none',\n borderRadius: 0,\n maxWidth: 'none',\n maxHeight: 'none',\n margin: 0,\n transform: 'none',\n pointerEvents: 'none' as const,\n overflow: 'visible',\n visibility: breakoutRevealed ? ('visible' as const) : ('hidden' as const),\n }\n : {\n width: '100%',\n height: iframeHeight,\n border: 'none',\n borderRadius: 8,\n overflow: isCapped ? undefined : ('hidden' as const),\n };\n\n const fullStyle = {\n width: '100%',\n height: '100%',\n border: 'none',\n };\n\n return (\n <div className={className} style={isCompact ? { position: 'relative' } : { width: '100%', height: '100%' }}>\n <iframe\n ref={iframeRef}\n srcDoc={html}\n style={isCompact ? compactStyle : fullStyle}\n scrolling={isCompact && !breakoutActive && !isCapped ? 'no' : undefined}\n sandbox=\"allow-scripts allow-same-origin allow-popups allow-popups-to-escape-sandbox\"\n title=\"Gadget\"\n onLoad={() => setIframeLoaded(true)}\n />\n </div>\n );\n}\n", "/**\n * Creates a self-contained HTML string for rendering a gadget component in an iframe.\n *\n * Loads React 18, ReactDOM, Babel (for JSX transpilation), and Tailwind CSS from CDNs.\n * Sets up the full gadget bridge: state, breakout, actions, chat, context, and hot-swap.\n *\n * Usage:\n * import { createGadgetRenderer, setupGadgetBreakout } from '@gigabuddy/chat';\n *\n * const html = createGadgetRenderer(componentCode, data, { viewport: 'compact', stateEnabled: true });\n * iframe.srcdoc = html;\n * setupGadgetBreakout(iframe);\n *\n * The gadget component receives these props:\n * function Gadget({ data, viewport, state, userId, breakout, chat, context })\n *\n * Bridge protocol (postMessage):\n * - Host \u2192 iframe: `gadget-set-data` \u2014 push new props\n * - Host \u2192 iframe: `gadget-state-init` / `gadget-state-update` \u2014 state changes\n * - Host \u2192 iframe: `gadget-update-component` \u2014 hot-swap component code\n * - Host \u2192 iframe: `gadget-breakout-started` \u2014 breakout activated with originalRect\n * - iframe \u2192 Host: `gadget-interaction` \u2014 user dispatched an action\n * - iframe \u2192 Host: `gadget-resize` \u2014 auto-height\n * - iframe \u2192 Host: `gadget-request-breakout` / `gadget-exit-breakout` \u2014 breakout lifecycle\n * - iframe \u2192 Host: `gadget-action-request` / `gadget-chat-request` / `gadget-context-request` \u2014 API calls\n */\nexport function createGadgetRenderer(\n componentCode: string,\n data: unknown = {},\n options?: {\n viewport?: 'compact' | 'full' | 'mobile';\n stateEnabled?: boolean;\n chatEnabled?: boolean;\n contextEnabled?: boolean;\n assets?: Record<string, { url: string; name: string }>;\n },\n): string {\n const serializedData = JSON.stringify(data);\n const viewport = options?.viewport ?? 'full';\n const stateEnabled = options?.stateEnabled ?? false;\n const chatEnabled = options?.chatEnabled ?? false;\n const contextEnabled = options?.contextEnabled ?? false;\n const escapedCode = componentCode.replace(/<\\/script>/g, '<\\\\/script>');\n const serializedAssets = JSON.stringify(options?.assets ?? {});\n\n const stateBridgeScript = stateEnabled\n ? `\n window.gadget.state = {\n shared: {},\n user: {},\n userId: null,\n _sharedCallbacks: [],\n _userCallbacks: [],\n\n dispatch: function(action, data) {\n window.parent.postMessage({ type: 'gadget-interaction', action: action, data: data || {} }, '*');\n },\n\n onSharedChange: function(callback) {\n window.gadget.state._sharedCallbacks.push(callback);\n callback(window.gadget.state.shared);\n return function() {\n var i = window.gadget.state._sharedCallbacks.indexOf(callback);\n if (i !== -1) window.gadget.state._sharedCallbacks.splice(i, 1);\n };\n },\n\n onUserChange: function(callback) {\n window.gadget.state._userCallbacks.push(callback);\n callback(window.gadget.state.user);\n return function() {\n var i = window.gadget.state._userCallbacks.indexOf(callback);\n if (i !== -1) window.gadget.state._userCallbacks.splice(i, 1);\n };\n },\n };\n\n window.addEventListener('message', function(event) {\n var d = event.data;\n if (d && (d.type === 'gadget-state-init' || d.type === 'gadget-state-update')) {\n if (d.userId !== undefined) {\n window.gadget.state.userId = d.userId;\n }\n if (d.shared !== undefined) {\n window.gadget.state.shared = d.shared;\n window.gadget.state._sharedCallbacks.forEach(function(cb) { try { cb(d.shared); } catch(e) {} });\n }\n if (d.user !== undefined) {\n window.gadget.state.user = d.user;\n window.gadget.state._userCallbacks.forEach(function(cb) { try { cb(d.user); } catch(e) {} });\n }\n window.__rerenderGadget();\n }\n });`\n : '';\n\n const chatBridgeScript = chatEnabled\n ? `\n window.gadget.chat = {\n _request: function(method, params) {\n var requestId = Math.random().toString(36).slice(2) + Date.now().toString(36);\n return new Promise(function(resolve, reject) {\n var handler = function(event) {\n var d = event.data;\n if (d && d.type === 'gadget-chat-response' && d.requestId === requestId) {\n window.removeEventListener('message', handler);\n if (d.error) reject(new Error(d.error));\n else resolve(d.result);\n }\n };\n window.addEventListener('message', handler);\n setTimeout(function() { window.removeEventListener('message', handler); reject(new Error('Timed out')); }, 30000);\n window.parent.postMessage({ type: 'gadget-chat-request', requestId: requestId, method: method, params: params || {} }, '*');\n });\n },\n\n _eventCallbacks: [],\n\n createChannel: function(opts) { return window.gadget.chat._request('createChannel', opts); },\n findOrCreateChannel: function(name, opts) { return window.gadget.chat._request('findOrCreateChannel', { name: name, description: opts && opts.description }); },\n listChannels: function() { return window.gadget.chat._request('listChannels'); },\n joinChannel: function(conversationId) { return window.gadget.chat._request('joinChannel', { conversationId: conversationId }); },\n sendMessage: function(conversationId, text) { return window.gadget.chat._request('sendMessage', { conversationId: conversationId, text: text }); },\n getMessages: function(conversationId, opts) { return window.gadget.chat._request('getMessages', { conversationId: conversationId, limit: opts && opts.limit, before: opts && opts.before }); },\n updateChannel: function(conversationId, updates) { return window.gadget.chat._request('updateChannel', { conversationId: conversationId, description: updates && updates.description }); },\n createInvite: function(conversationId) { return window.gadget.chat._request('createInvite', { conversationId: conversationId }); },\n redeemInvite: function(token) { return window.gadget.chat._request('redeemInvite', { token: token }); },\n\n onEvent: function(callback) {\n window.gadget.chat._eventCallbacks.push(callback);\n return function() {\n var i = window.gadget.chat._eventCallbacks.indexOf(callback);\n if (i !== -1) window.gadget.chat._eventCallbacks.splice(i, 1);\n };\n },\n };\n\n window.addEventListener('message', function(event) {\n var d = event.data;\n if (d && d.type === 'gadget-chat-event') {\n window.gadget.chat._eventCallbacks.forEach(function(cb) { try { cb(d.event); } catch(e) {} });\n window.__rerenderGadget();\n }\n });`\n : '';\n\n const contextBridgeScript = contextEnabled\n ? `\n window.gadget.context = {\n _request: function(method, params) {\n var requestId = Math.random().toString(36).slice(2) + Date.now().toString(36);\n return new Promise(function(resolve, reject) {\n var handler = function(event) {\n var d = event.data;\n if (d && d.type === 'gadget-context-response' && d.id === requestId) {\n window.removeEventListener('message', handler);\n if (d.error) reject(new Error(d.error));\n else resolve(d.result);\n }\n };\n window.addEventListener('message', handler);\n setTimeout(function() { window.removeEventListener('message', handler); reject(new Error('Timed out')); }, 30000);\n window.parent.postMessage({ type: 'gadget-context-request', id: requestId, method: method, params: params || {} }, '*');\n });\n },\n\n _eventCallbacks: [],\n\n listTypes: function() { return window.gadget.context._request('listTypes', {}); },\n getType: function(contextType) { return window.gadget.context._request('getType', { contextType: contextType }); },\n listInstances: function(params) { return window.gadget.context._request('listInstances', params || {}); },\n getInstance: function(id) { return window.gadget.context._request('getInstance', { id: id }); },\n createInstance: function(params) { return window.gadget.context._request('createInstance', params); },\n updateInstance: function(id, data) { return window.gadget.context._request('updateInstance', { id: id, data: data }); },\n deleteInstance: function(id) { return window.gadget.context._request('deleteInstance', { id: id }); },\n searchKnowledge: function(params) { return window.gadget.context._request('searchKnowledge', params); },\n getEnriched: function(id) { return window.gadget.context._request('getEnriched', { id: id }); },\n getRelated: function(id) { return window.gadget.context._request('getRelated', { id: id }); },\n\n onEvent: function(callback) {\n window.gadget.context._eventCallbacks.push(callback);\n return function() {\n var i = window.gadget.context._eventCallbacks.indexOf(callback);\n if (i !== -1) window.gadget.context._eventCallbacks.splice(i, 1);\n };\n },\n };\n\n window.addEventListener('message', function(event) {\n var d = event.data;\n if (d && d.type === 'gadget-context-event') {\n window.gadget.context._eventCallbacks.forEach(function(cb) { try { cb(d.event); } catch(e) {} });\n window.__rerenderGadget();\n }\n });`\n : '';\n\n // When state is enabled, pass state prop alongside data and viewport\n const chatPropFragment = chatEnabled ? ', chat: window.gadget.chat' : '';\n const contextPropFragment = contextEnabled ? ', context: window.gadget.context' : '';\n const breakoutPropFragment =\n ', breakout: { active: window.gadget.breakout._active, originalRect: window.gadget.breakout._originalRect, request: window.gadget.breakout.request, exit: window.gadget.breakout.exit }';\n const componentProps = stateEnabled\n ? `{ data: window.__GADGET_DATA__, viewport: window.__GADGET_VIEWPORT__, state: window.gadget.state ? { shared: window.gadget.state.shared, user: window.gadget.state.user } : undefined, userId: window.gadget.state ? window.gadget.state.userId : undefined${chatPropFragment}${contextPropFragment}${breakoutPropFragment} }`\n : `{ data: window.__GADGET_DATA__, viewport: window.__GADGET_VIEWPORT__${chatPropFragment}${contextPropFragment}${breakoutPropFragment} }`;\n\n return `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n <script src=\"https://cdn.jsdelivr.net/npm/react@18/umd/react.production.min.js\"></script>\n <script src=\"https://cdn.jsdelivr.net/npm/react-dom@18/umd/react-dom.production.min.js\"></script>\n <script src=\"https://cdn.jsdelivr.net/npm/@babel/standalone@7/babel.min.js\"></script>\n <script src=\"https://cdn.tailwindcss.com\"></script>\n <style>\n * { margin: 0; padding: 0; box-sizing: border-box; }\n html, body { background: transparent; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; min-height: 100%; }\n #root { min-height: 100vh; }\n .gadget-error {\n padding: 16px;\n background: #fef2f2;\n border: 1px solid #fecaca;\n border-radius: 8px;\n color: #991b1b;\n font-family: monospace;\n font-size: 13px;\n white-space: pre-wrap;\n word-break: break-word;\n }\n .gadget-error-title {\n font-weight: 600;\n margin-bottom: 8px;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n }\n </style>\n</head>\n<body>\n <div id=\"root\"></div>\n <script>\n window.__GADGET_DATA__ = ${serializedData};\n window.__GADGET_VIEWPORT__ = '${viewport}';\n\n window.gadget = {\n data: window.__GADGET_DATA__,\n assets: ${serializedAssets},\n\n breakout: {\n _active: false,\n _originalRect: null,\n request: function() {\n if (window.gadget.breakout._active) return;\n window.gadget.breakout._active = true;\n window.parent.postMessage({ type: 'gadget-request-breakout' }, '*');\n window.__rerenderGadget && window.__rerenderGadget();\n },\n exit: function() {\n if (!window.gadget.breakout._active) return;\n window.gadget.breakout._active = false;\n window.gadget.breakout._originalRect = null;\n window.parent.postMessage({ type: 'gadget-exit-breakout' }, '*');\n window.__rerenderGadget();\n },\n },\n\n callAction: function(input) {\n var requestId = Math.random().toString(36).slice(2) + Date.now().toString(36);\n return new Promise(function(resolve, reject) {\n var handler = function(event) {\n var d = event.data;\n if (d && d.type === 'gadget-action-response' && d.requestId === requestId) {\n window.removeEventListener('message', handler);\n if (d.error) reject(new Error(d.error));\n else resolve(d.result);\n }\n };\n window.addEventListener('message', handler);\n setTimeout(function() {\n window.removeEventListener('message', handler);\n reject(new Error('Action timed out'));\n }, 30000);\n window.parent.postMessage({ type: 'gadget-action-request', requestId: requestId, input: input }, '*');\n });\n },\n };\n${stateBridgeScript}\n${chatBridgeScript}\n${contextBridgeScript}\n\n window.__gadgetRoot = null;\n window.__gadgetComponent = null;\n\n window.__rerenderGadget = function() {\n if (window.__gadgetRoot && window.__gadgetComponent) {\n var C = window.__gadgetComponent;\n var EB = window.__gadgetErrorBoundary;\n window.__gadgetRoot.render(\n React.createElement(EB, null, React.createElement(C, ${componentProps}))\n );\n }\n };\n\n window.addEventListener('message', function(event) {\n var d = event.data;\n if (d && d.type === 'gadget-set-data') {\n window.__GADGET_DATA__ = d.data;\n window.gadget.data = d.data;\n window.__rerenderGadget();\n }\n if (d && d.type === 'gadget-breakout-started') {\n var wasActive = window.gadget.breakout._active;\n window.gadget.breakout._active = true;\n window.gadget.breakout._originalRect = d.originalRect || null;\n if (!wasActive) window.__rerenderGadget();\n }\n if (d && d.type === 'gadget-update-component' && d.code) {\n try {\n var compiled = Babel.transform(d.code, { presets: ['react'] }).code;\n var fn = new Function('React', 'useState', 'useEffect', 'useCallback', 'useMemo', 'useRef',\n compiled + '\\\\nreturn typeof Gadget !== \"undefined\" ? Gadget : null;');\n var NewComponent = fn(React, React.useState, React.useEffect, React.useCallback, React.useMemo, React.useRef);\n if (NewComponent) {\n window.__gadgetComponent = NewComponent;\n if (window.__gadgetErrorBoundaryInstance) {\n window.__gadgetErrorBoundaryInstance.setState({ error: null });\n }\n window.__rerenderGadget();\n }\n } catch (err) {\n console.error('[gadget-hmr] Component update failed:', err);\n }\n }\n });\n </script>\n <script type=\"text/babel\" data-type=\"module\">\n const { useState, useEffect, useCallback, useMemo, useRef } = React;\n\n class ErrorBoundary extends React.Component {\n constructor(props) {\n super(props);\n this.state = { error: null };\n window.__gadgetErrorBoundaryInstance = this;\n }\n static getDerivedStateFromError(error) {\n return { error };\n }\n render() {\n if (this.state.error) {\n return React.createElement('div', { className: 'gadget-error' },\n React.createElement('div', { className: 'gadget-error-title' }, 'Runtime Error'),\n this.state.error.message\n );\n }\n return this.props.children;\n }\n }\n window.__gadgetErrorBoundary = ErrorBoundary;\n\n try {\n ${escapedCode}\n\n const ComponentToRender = typeof Gadget !== 'undefined' ? Gadget : null;\n\n if (ComponentToRender) {\n window.__gadgetComponent = ComponentToRender;\n const root = ReactDOM.createRoot(document.getElementById('root'));\n window.__gadgetRoot = root;\n root.render(\n <ErrorBoundary>\n <ComponentToRender data={window.__GADGET_DATA__} viewport={window.__GADGET_VIEWPORT__}${stateEnabled ? ' state={window.gadget.state ? { shared: window.gadget.state.shared, user: window.gadget.state.user } : undefined} userId={window.gadget.state ? window.gadget.state.userId : undefined}' : ''}${chatEnabled ? ' chat={window.gadget.chat}' : ''}${contextEnabled ? ' context={window.gadget.context}' : ''} breakout={{ active: window.gadget.breakout._active, originalRect: window.gadget.breakout._originalRect, request: window.gadget.breakout.request, exit: window.gadget.breakout.exit }} />\n </ErrorBoundary>\n );\n } else {\n document.getElementById('root').innerHTML =\n '<div class=\"gadget-error\"><div class=\"gadget-error-title\">No component found</div>Define a function called Gadget.</div>';\n }\n } catch (err) {\n document.getElementById('root').innerHTML =\n '<div class=\"gadget-error\"><div class=\"gadget-error-title\">Error</div>' +\n err.message.replace(/</g, '&lt;').replace(/>/g, '&gt;') +\n '</div>';\n }\n\n const rootEl = document.getElementById('root');\n const observer = new ResizeObserver(() => {\n window.parent.postMessage({\n type: 'gadget-resize',\n height: rootEl.scrollHeight,\n }, '*');\n });\n observer.observe(rootEl);\n </script>\n</body>\n</html>`;\n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["jsx"]
7
7
  }