@mochabug/adapt-web
Version:
Browser client library for Adapt automation platform
2 lines (1 loc) • 48.9 kB
JavaScript
import{Code,configure,ConnectError,createAdaptClient,resetConfig}from"@mochabug/adapt-core";import{createConnectClient}from"@mochabug/adapt-core/connect";import{PanelManager,syncGroupIdCounter}from"./panel-manager.js";import{FloatingToolbar,ForkGroupActions,IframePanelComponent,injectPanelManagerStyles,MinimizeManager}from"./panel-setup.js";import{resolveTheme}from"./theme.js";import{resolveTheme as resolveTheme2}from"./theme.js";import{AdaptAutomationElement}from"./AdaptAutomationElement.js";import{FloatingToolbar as FloatingToolbar2,ForkGroupActions as ForkGroupActions2,IframePanelComponent as IframePanelComponent2,MinimizeManager as MinimizeManager2}from"./panel-setup.js";import{PanelManager as PanelManager2}from"./panel-manager.js";function clearPersistedState(automationId,storage="both",persistKey){const key=`mb_adapt_${persistKey??automationId}`;(storage==="session"||storage==="both")&&sessionStorage.removeItem(key),(storage==="local"||storage==="both")&&localStorage.removeItem(key)}const MAIN_PANEL_ID="main",FORK_GROUP_ID="fork-group",DEFAULT_RESPONSIVE_BREAKPOINT=768,DEFAULT_RESPONSIVE_HYSTERESIS=40,_AdaptWebClient=class _AdaptWebClient{constructor(options){this.rootElement=null;this.panelManager=null;this.mainUrl=null;this.sessionToken=null;this.forks=new Map;this.mainRetentionPolicy="retain";this.mainCloseTimer=null;this.components=new Map;this.floatingAutoResized=new Set;this.beforeUnloadHandler=null;this.resizeObserver=null;this._autoMaximizedByResize=!1;this.destroyed=!1;this.sessionTerminated=!1;this.removingPanelProgrammatically=!1;this.restoringSession=!1;this.lastForkActive=null;this.messageHandler=null;this.minimizedTabsContainer=null;this.lastReportedContentHeight=0;this.forkPanelHeights=new Map;this.statusMessageElement=null;this.capWidgetInstance=null;this.minimizeManager=null;this.forkGroupActions=new Map;this.floatingToolbars=new Map;if(!options.automationId)throw new Error('[adapt] AdaptWebClient requires "automationId". Pass it in the options: new WebClient({ automationId: "...", ... })');this.options=options,this.debug=options.debug??!1;const fd=options.forkDisplay??{mode:"side-by-side"};this.forkDisplay=fd,this.darkMode=options.darkMode??!1,this.autoResizing=options.autoResizing??!1,this.allowFloating=options.allowFloating??!0,this.allowDocking=options.allowDocking??!0,this.allowDialogDocking=options.allowDialogDocking??!0,this.allowMinimize=options.allowMinimize??!0,this.allowMaximize=options.allowMaximize??!0,this.floatingAutoResize=options.floatingAutoResize??!1,this.confirmOnClose=options.confirmOnClose??!1,this.theme=options.theme;const container=typeof options.container=="string"?document.getElementById(options.container):options.container;if(!container)throw new Error(`Container with id '${options.container}' not found`);this.container=container;const rawClient=createConnectClient({id:options.automationId});this.client=createAdaptClient(rawClient,options.automationId,{debug:this.debug}),this.log("info",`init automationId=${options.automationId} forkDisplay=${fd.mode}`),injectPanelManagerStyles(),this.createRootElement(),this.createPanelManager(),this.wireBeforeTabClose(),this.setupMessageListener(),this.init().catch(error=>{this.showErrorStatus(error)})}static registerCapWidget(cls){_AdaptWebClient._capWidgetClass=cls}get responsiveBreakpoint(){if(!this.rootElement)return DEFAULT_RESPONSIVE_BREAKPOINT;const v=getComputedStyle(this.rootElement).getPropertyValue("--mb-adapt-responsive-breakpoint").trim(),n=Number(v);return n>0?n:DEFAULT_RESPONSIVE_BREAKPOINT}get responsiveHysteresis(){if(!this.rootElement)return DEFAULT_RESPONSIVE_HYSTERESIS;const v=getComputedStyle(this.rootElement).getPropertyValue("--mb-adapt-responsive-hysteresis").trim(),n=Number(v);return n>=0?n:DEFAULT_RESPONSIVE_HYSTERESIS}log(level,msg,data){if(!this.debug&&level==="info")return;(level==="error"?console.error:level==="warn"?console.warn:console.log)(`[Adapt] ${msg}`,data!==void 0?data:"")}onComponentCreated(panelId,component){this.components.set(panelId,component)}onComponentDisposed(panelId){this.components.delete(panelId)}getDarkMode(){return this.darkMode}getClassNames(){return this.options.classNames}createPanelManager(){if(!this.rootElement)return;this.minimizeManager=new MinimizeManager,this.minimizeManager.setAllowDocking(this.allowDocking),this.minimizedTabsContainer=document.createElement("div"),this.minimizedTabsContainer.className="mb-adapt-minimized-tabs",this.rootElement.appendChild(this.minimizedTabsContainer),this.panelManager=new PanelManager({container:this.rootElement,onGroupCreatedByDrag:group=>{group.dragConstraint="merge-only",this.allowDocking||(group.dockingBlocked=!0),this.allowDialogDocking||(group.dialogDockingBlocked=!0),this.setupForkGroupActions(group),this.saveState()},onLayoutChanged:()=>{this.saveState()}});const mainGroup=this.panelManager.addGroup({id:"main-group"});this.panelManager.setMainGroup(mainGroup),mainGroup.locked="no-drop-target",mainGroup.setHeaderHidden(!0),mainGroup.element.setAttribute("data-main-group","true");const mainComponent=new IframePanelComponent(this);mainComponent.init(MAIN_PANEL_ID,{}),this.panelManager.addPanel({id:MAIN_PANEL_ID,element:mainComponent.element,groupId:mainGroup.id}),this.minimizeManager.init(this.minimizedTabsContainer,this.panelManager),this.minimizeManager.onBarVisibilityChanged(()=>{this.reapplyAutoResizeHeight()}),this.resizeObserver=new ResizeObserver(entries=>{const cr=entries[0]?.contentRect;cr&&this.onContainerResize(cr.width,cr.height)}),this.resizeObserver.observe(this.rootElement)}getOrigin(url){try{return new URL(url).origin}catch{return null}}isValidMessageOrigin(origin){if(this.mainUrl){const mainOrigin=this.getOrigin(this.mainUrl);if(mainOrigin&&origin===mainOrigin)return!0}for(const fork of this.forks.values()){const forkOrigin=this.getOrigin(fork.url);if(forkOrigin&&origin===forkOrigin)return!0}return!1}findComponentBySource(source){for(const[panelId,component]of this.components)if(component.contentWindow===source)return{panelId,component};return null}setupMessageListener(){this.messageHandler=event=>{if(!this.isValidMessageOrigin(event.origin))return;const data=event.data;if(!data||typeof data!="object")return;const source=event.source,found=this.findComponentBySource(source);if(!found)return;const{panelId,component}=found,isMainPanel=panelId===MAIN_PANEL_ID;if(data.type==="adapt-init"&&typeof data.resize=="boolean"){component.resizeCapable=data.resize,isMainPanel&&!data.resize&&this.rootElement&&(this.rootElement.style.height="");const targetOrigin=component.getOrigin();if(targetOrigin){let effective;if(isMainPanel)effective=this.autoResizing&&data.resize;else{const group=this.panelManager?.getPanel(panelId)?.group,inFloating=group?!!this.panelManager?.findOverlayContaining(group.id):!1;effective=data.resize&&(inFloating&&this.floatingAutoResize||!inFloating&&this.autoResizing)}component.postMessage({type:"adapt-autoResizing",autoResizing:effective},targetOrigin),component.postMessage({type:"adapt-darkMode",darkMode:this.darkMode},targetOrigin)}return}if(data.type==="adapt-resize"){const{height}=data;if(typeof height!="number"||!Number.isFinite(height)||height<1)return;if(isMainPanel)this.lastReportedContentHeight=height,component.resizeCapable&&this.autoResizing&&this.rootElement&&this.applyBestAutoResizeHeight();else{this.forkPanelHeights.set(panelId,height);const group=this.panelManager?.getPanel(panelId)?.group;if(group&&group.activePanel?.id===panelId){const inFloating=!!this.panelManager?.findOverlayContaining(group.id);!inFloating&&component.resizeCapable&&this.autoResizing&&this.rootElement&&this.applyBestAutoResizeHeight(),inFloating&&this.floatingAutoResize&&(this.floatingAutoResized.has(group.id)||(this.floatingAutoResized.add(group.id),this.resizeOverlayForGroup(group)))}}return}},window.addEventListener("message",this.messageHandler)}postToComponent(component,message){const origin=component.getOrigin();origin&&component.postMessage(message,origin)}setDarkMode(darkMode){if(this.darkMode===darkMode)return;this.darkMode=darkMode,this.rootElement?.classList.toggle("mb-adapt--dark",darkMode),this.capWidgetInstance?.setDarkMode(darkMode),this.applyTheme();const msg={type:"adapt-darkMode",darkMode};for(const c of this.components.values())this.postToComponent(c,msg)}setTheme(theme){if(this.theme=theme,this.clearThemeVars(),theme?.mode!==void 0){const dark=theme.mode==="dark";if(this.darkMode!==dark){this.setDarkMode(dark);return}}this.applyTheme()}clearThemeVars(){if(!(!this.rootElement||!this._appliedThemeVars)){for(const key of this._appliedThemeVars)this.rootElement.style.removeProperty(key);this._appliedThemeVars=void 0}}applyTheme(){if(!this.rootElement||!this.theme)return;const vars=resolveTheme(this.theme);for(const[key,value]of Object.entries(vars))this.rootElement.style.setProperty(key,value);this._appliedThemeVars=Object.keys(vars)}setAutoResizing(autoResizing){if(this.autoResizing===autoResizing)return;this.autoResizing=autoResizing;const mainComponent=this.components.get(MAIN_PANEL_ID);mainComponent?.resizeCapable&&this.postToComponent(mainComponent,{type:"adapt-autoResizing",autoResizing});for(const[panelId,component]of this.components){if(panelId===MAIN_PANEL_ID||!component.resizeCapable)continue;const group=this.panelManager?.getPanel(panelId)?.group;group&&this.panelManager?.findOverlayContaining(group.id)||this.postToComponent(component,{type:"adapt-autoResizing",autoResizing})}!autoResizing&&this.rootElement&&(this.rootElement.style.height="")}setAllowFloating(allow){if(this.allowFloating!==allow){this.allowFloating=allow;for(const actions of this.forkGroupActions.values())actions.setAllowFloating(allow)}}setAllowDocking(allow){if(this.allowDocking!==allow){if(this.allowDocking=allow,this.minimizeManager?.setAllowDocking(allow),this.panelManager)for(const group of this.getAllForkGroups())group.dockingBlocked=!allow;for(const toolbar of this.floatingToolbars.values())toolbar.setAllowDocking(allow)}}setAllowDialogDocking(allow){if(this.allowDialogDocking!==allow&&(this.allowDialogDocking=allow,this.panelManager))for(const group of this.getAllForkGroups())group.dialogDockingBlocked=!allow}setAllowMinimize(allow){if(this.allowMinimize!==allow){this.allowMinimize=allow;for(const actions of this.forkGroupActions.values())actions.setAllowMinimize(allow);for(const toolbar of this.floatingToolbars.values())toolbar.setAllowMinimize(allow)}}setAllowMaximize(allow){if(this.allowMaximize!==allow){this.allowMaximize=allow;for(const actions of this.forkGroupActions.values())actions.setAllowMaximize(allow);for(const toolbar of this.floatingToolbars.values())toolbar.setAllowMaximize(allow)}}setFloatingAutoResize(enabled){if(this.floatingAutoResize!==enabled){this.floatingAutoResize=enabled,this.floatingAutoResized.clear();for(const[panelId,component]of this.components){if(panelId===MAIN_PANEL_ID||!component.resizeCapable)continue;const group=this.panelManager?.getPanel(panelId)?.group,effective=(group?!!this.panelManager?.findOverlayContaining(group.id):!1)?enabled&&component.resizeCapable:this.autoResizing&&component.resizeCapable;this.postToComponent(component,{type:"adapt-autoResizing",autoResizing:effective})}}}getAllForkGroups(){if(!this.panelManager)return[];const seen=new Set,groups=[],add=g=>{g.id==="main-group"||seen.has(g.id)||(seen.add(g.id),groups.push(g))},forkGroup=this.panelManager.getGroup(FORK_GROUP_ID);forkGroup&&add(forkGroup);for(const g of this.panelManager.getDockedGroups())add(g);for(const[,overlay]of this.panelManager.getFloatingOverlays())for(const g of overlay.getAllGroups())add(g);return groups}applyAutoResizeHeight(contentHeight){if(!this.rootElement)return;const chrome=this.minimizedTabsContainer?.offsetHeight??0;this.rootElement.style.height=`${Math.ceil(contentHeight)+chrome}px`}applyBestAutoResizeHeight(){if(!this.autoResizing||!this.rootElement)return;let maxHeight=0;if(this.components.get(MAIN_PANEL_ID)?.resizeCapable&&this.lastReportedContentHeight>0){const mainGroup=this.panelManager?.getMainGroup();if(mainGroup?mainGroup.element.offsetHeight>0:!0){const headerH=mainGroup?.headerElement?.offsetHeight??0;maxHeight=this.lastReportedContentHeight+headerH}}for(const group of this.getAllForkGroups()){if(this.panelManager?.findOverlayContaining(group.id)||group.element.offsetHeight<=0)continue;const active=group.activePanel;if(active){const h=this.forkPanelHeights.get(active.id)??0,headerH=group.headerElement?.offsetHeight??0,total=h+headerH;total>maxHeight&&(maxHeight=total)}}maxHeight>0&&this.applyAutoResizeHeight(maxHeight)}reapplyAutoResizeHeight(){this.applyBestAutoResizeHeight()}setForkDisplayMode(mode){this.forkDisplay.mode!==mode&&(this.log("info",`setForkDisplayMode ${this.forkDisplay.mode} \u2192 ${mode}`),mode==="side-by-side"?this.forkDisplay={mode:"side-by-side"}:this.forkDisplay={mode:"dialog"},this.forks.size>0&&this.panelManager&&this.rebuildForkGroup(),this.emitForkActive(),this.saveState())}createRootElement(){this.rootElement=document.createElement("div"),this.rootElement.className=this.options.classNames?.root||"mb-adapt",this.darkMode&&this.rootElement.classList.add("mb-adapt--dark"),this.options.styles&&Object.assign(this.rootElement.style,this.options.styles),this.applyTheme(),this.container.appendChild(this.rootElement)}onUrl(msg){if(this.destroyed)return;const fork=msg.fork||"";if(this.log("info",`onUrl fork=${fork||"(main)"} stopped=${!!msg.stopped} done=${!!msg.done} url=${msg.url?msg.url.slice(0,60)+"...":"(none)"}`),msg.stopped){this.handleStoppedMessage(fork),this.saveState();return}if(msg.done){this.handleDoneMessage(fork,msg.retentionPolicy),this.saveState();return}msg.url&&(fork?this.handleForkUrl(msg.url,msg.token,fork,msg.source,msg.retentionPolicy):this.handleMainUrl(msg.url,msg.token,msg.source,msg.retentionPolicy),this.saveState())}handleMainUrl(url,token,_source,retentionPolicy){this.log("info",`handleMainUrl url=${url.slice(0,60)}...`),this.mainCloseTimer&&(clearTimeout(this.mainCloseTimer),this.mainCloseTimer=null);const wasMainEmpty=!this.mainUrl;if(this.removeStatusMessage(),this.mainUrl=url,this.mainToken=token,this.mainRetentionPolicy=this.resolveRetention(retentionPolicy),this.panelManager?.isMainGroupCollapsed()&&this.panelManager.expandMainGroup(),wasMainEmpty){const maximizedGroupId=this.getMaximizedDockedGroupId();if(maximizedGroupId){const actions=this.forkGroupActions.get(maximizedGroupId);actions&&actions.clearMaximized()}}const mainComponent=this.components.get(MAIN_PANEL_ID);mainComponent&&(mainComponent.update({url,token}),mainComponent.show())}handleForkUrl(url,token,fork,source,retentionPolicy){if(!this.panelManager)return;const resolved=this.resolveRetention(retentionPolicy),existing=this.forks.get(fork);if(existing){this.log("info",`handleForkUrl fork=${fork} update existing panel=${existing.panelId}`),existing.closeTimer&&(clearTimeout(existing.closeTimer),existing.closeTimer=null),existing.url=url,existing.token=token,existing.source=source,existing.retentionPolicy=resolved,existing.completed=!1,existing.recyclable=!1;const component2=this.components.get(existing.panelId);component2&&component2.update({url,token});return}const recyclable=this.findRecyclablePanel(source);if(recyclable){this.log("info",`handleForkUrl fork=${fork} recycling panel from fork=${recyclable.forkKey}`);const{forkKey:oldFork,state:rState}=recyclable;rState.closeTimer&&(clearTimeout(rState.closeTimer),rState.closeTimer=null),this.forks.delete(oldFork),rState.url=url,rState.token=token,rState.fork=fork,rState.source=source,rState.retentionPolicy=resolved,rState.completed=!1,rState.recyclable=!1,this.forks.set(fork,rState);const component2=this.components.get(rState.panelId);component2&&component2.update({url,token});return}this.log("info",`handleForkUrl fork=${fork} creating new panel`);const panelId=`fork-${fork}`;this.ensureForkGroup(),!this.mainUrl&&this.panelManager&&!this.panelManager.isMainGroupCollapsed()&&this.panelManager.collapseMainGroup();const component=new IframePanelComponent(this);component.init(panelId,{url,token}),this.panelManager.addPanel({id:panelId,element:component.element,groupId:FORK_GROUP_ID}),this.forks.set(fork,{panelId,url,token,fork,source,completed:!1,recyclable:!1,retentionPolicy:resolved,closeTimer:null}),this.emitForkActive()}ensureForkGroup(){if(!this.panelManager||this.panelManager.getGroup(FORK_GROUP_ID))return;this.log("info",`ensureForkGroup mode=${this.forkDisplay.mode}`);const cw=this.rootElement?.offsetWidth??800,ch=this.rootElement?.offsetHeight??600;if(this.forkDisplay.mode==="dialog"){const isSmall=cw<this.responsiveBreakpoint,vw=window.innerWidth,vh=window.innerHeight,fw=isSmall?Math.min(cw*.95,Math.max(200,vw-20)):Math.min(720,cw*.9),fh=isSmall?Math.min(ch*.9,Math.max(200,vh-20)):Math.min(ch*.8,600),group=this.panelManager.addGroup({id:FORK_GROUP_ID,floating:{width:fw,height:fh,x:Math.max(0,(vw-fw)/2),y:Math.max(0,(vh-fh)/2)}});group.dragConstraint="merge-only",this.allowDocking||(group.dockingBlocked=!0),this.allowDialogDocking||(group.dialogDockingBlocked=!0),this.setupForkGroupActions(group),isSmall&&(this.panelManager.getFloatingOverlay(FORK_GROUP_ID)?.maximize(),this._autoMaximizedByResize=!0)}else{const split=this.forkDisplay.mode==="side-by-side"?this.forkDisplay.split:void 0,initialWidth=split!==void 0?cw*(1-split/100):void 0,group=this.panelManager.addGroup({id:FORK_GROUP_ID,direction:"right",initialSize:initialWidth});if(group.dragConstraint="merge-only",this.allowDocking||(group.dockingBlocked=!0),this.allowDialogDocking||(group.dialogDockingBlocked=!0),this.setupForkGroupActions(group),cw<this.responsiveBreakpoint){const fa=this.forkGroupActions.get(group.id);fa?(fa.setMaximized(),fa.setAutoMaximizedByResize(!0)):this.panelManager.maximizeDockedGroup(group),this._autoMaximizedByResize=!0}}}setupForkGroupActions(group){if(!this.panelManager||!this.minimizeManager)return;const actions=new ForkGroupActions(group,this.minimizeManager,this.panelManager,()=>{if(this.setupFloatingToolbar(group),group.location==="grid"&&!this.mainUrl&&this.panelManager&&!this.panelManager.isMainGroupCollapsed()&&this.panelManager.collapseMainGroup(),group.location==="floating"&&this.floatingAutoResized.delete(group.id),this.updateAutoResizeForGroup(group),group.location==="grid"){const currentWidth=this.rootElement?.offsetWidth??0;if(currentWidth>0&¤tWidth<this.responsiveBreakpoint){const fa=this.forkGroupActions.get(group.id);fa&&!fa.isMaximized&&(fa.setMaximized(),this._autoMaximizedByResize=!0,fa.setAutoMaximizedByResize(!0))}}this.saveState()},{allowFloating:this.allowFloating,allowMinimize:this.allowMinimize,allowMaximize:this.allowMaximize});actions.setBeforeClose(()=>this.confirmCloseGroup(group)),actions.onMaximizeChanged(maximized=>{maximized||(this._autoMaximizedByResize=!1,actions.setAutoMaximizedByResize(!1)),this.saveState()}),group.setHeaderActions(actions.element),this.forkGroupActions.set(group.id,actions),group.onActivePanelChanged(()=>{this.autoResizing&&this.rootElement&&this.applyBestAutoResizeHeight()}),this.setupFloatingToolbar(group)}updateAutoResizeForGroup(group){const inFloating=this.panelManager?!!this.panelManager.findOverlayContaining(group.id):!1;for(const panel of group.panels){const component=this.components.get(panel.id);if(!component?.resizeCapable)continue;const effective=inFloating?this.floatingAutoResize:this.autoResizing;this.postToComponent(component,{type:"adapt-autoResizing",autoResizing:effective})}}setupFloatingToolbar(group){if(!this.panelManager||!this.minimizeManager)return;const overlay=this.panelManager.findOverlayContaining(group.id);if(overlay)if(group.onPanelCountChanged(()=>overlay.updateTotalTabCount()),overlay.hasToolbar)overlay.repositionToolbar();else{const toolbar=new FloatingToolbar(overlay,this.panelManager,this.minimizeManager,{allowDocking:this.allowDocking,allowMinimize:this.allowMinimize,allowMaximize:this.allowMaximize});toolbar.setBeforeClose(()=>this.confirmCloseGroup(overlay.group)),overlay.setToolbar(toolbar.element),this.floatingToolbars.set(overlay.group.id,toolbar),overlay.updateTotalTabCount()}}resolveRetention(policy){return policy?policy.case:"retain"}findRecyclablePanel(source){let anyRecyclable=null;for(const[forkKey,state]of this.forks)if(state.recyclable){if(source&&state.source===source)return{forkKey,state};anyRecyclable||(anyRecyclable={forkKey,state})}return anyRecyclable}handleMainDone(retentionPolicy){switch(retentionPolicy?this.resolveRetention(retentionPolicy):this.mainRetentionPolicy){case"close":this.scheduleMainClose(retentionPolicy?.case==="close"?retentionPolicy.timeoutSeconds:void 0);break;case"recycle":break;default:break}}scheduleForkClose(fork,state,timeoutSeconds){const doClose=()=>{state.closeTimer=null,this.removingPanelProgrammatically=!0;try{if(this.panelManager){const component=this.components.get(state.panelId);component&&component.dispose(),this.panelManager.removePanel(state.panelId)}this.forks.delete(fork),this.removeForkGroupIfEmpty()}finally{this.removingPanelProgrammatically=!1}this.emitForkActive(),this.saveState()};timeoutSeconds&&timeoutSeconds>0?state.closeTimer=setTimeout(doClose,timeoutSeconds*1e3):doClose()}scheduleMainClose(timeoutSeconds){const doClose=()=>{this.mainCloseTimer=null,this.mainUrl=null,this.mainToken=void 0;const mainComponent=this.components.get(MAIN_PANEL_ID);mainComponent&&mainComponent.hide(),this.panelManager&&!this.panelManager.isMainGroupCollapsed()&&this.panelManager.collapseMainGroup(),this.saveState()};timeoutSeconds&&timeoutSeconds>0?this.mainCloseTimer=setTimeout(doClose,timeoutSeconds*1e3):doClose()}restoreFork(pf,targetGroupId){if(!this.panelManager)return;const groupId=targetGroupId??FORK_GROUP_ID;this.log("info",`restoreFork fork=${pf.fork} \u2192 group=${groupId} url=${pf.url.slice(0,60)}...`);const panelId=`fork-${pf.fork}`;groupId===FORK_GROUP_ID&&this.ensureForkGroup(),!this.mainUrl&&this.panelManager&&!this.panelManager.isMainGroupCollapsed()&&this.panelManager.collapseMainGroup();const component=new IframePanelComponent(this);component.init(panelId,{url:pf.url,token:pf.token}),this.panelManager.addPanel({id:panelId,element:component.element,groupId}),this.forks.set(pf.fork,{panelId,url:pf.url,token:pf.token,fork:pf.fork,source:pf.source,completed:!1,recyclable:pf.retentionPolicy==="recycle",retentionPolicy:pf.retentionPolicy,closeTimer:null}),this.emitForkActive()}restoreDockedLayout(serialized){this.panelManager&&(this.createGroupsFromTree(serialized),this.panelManager.rebuildDockedLayout(serialized))}createGroupsFromTree(node){if(this.panelManager){if(node.kind==="leaf"){if(node.groupId==="main-group"||this.panelManager.getGroup(node.groupId))return;const group=this.panelManager.addGroup({id:node.groupId});group.dragConstraint="merge-only",this.allowDocking||(group.dockingBlocked=!0),this.allowDialogDocking||(group.dialogDockingBlocked=!0),this.setupForkGroupActions(group);return}this.createGroupsFromTree(node.first),this.createGroupsFromTree(node.second)}}clearAllForks(){this.log("info",`clearAllForks count=${this.forks.size}`),this.removingPanelProgrammatically=!0;try{if(this.panelManager)for(const state of this.forks.values()){state.closeTimer&&(clearTimeout(state.closeTimer),state.closeTimer=null);const component=this.components.get(state.panelId);component&&component.dispose(),this.panelManager.removePanel(state.panelId)}this.forks.clear(),this.removeForkGroupIfEmpty()}finally{this.removingPanelProgrammatically=!1}}rebuildForkGroup(){if(!this.panelManager)return;const group=this.panelManager.getGroup(FORK_GROUP_ID);if(group)if(this.log("info",`rebuildForkGroup newMode=${this.forkDisplay.mode}`),this.forkDisplay.mode==="dialog"){const cw=this.rootElement?.offsetWidth??800,ch=this.rootElement?.offsetHeight??600,fw=Math.min(720,cw*.9),fh=Math.min(ch*.8,600);this.panelManager.addFloatingGroup(group,{width:fw,height:fh,x:(window.innerWidth-fw)/2,y:(window.innerHeight-fh)/2}),this.setupFloatingToolbar(group)}else{const split=this.forkDisplay.mode==="side-by-side"?this.forkDisplay.split:void 0,initialWidth=split!==void 0?(this.rootElement?.offsetWidth??800)*(1-split/100):void 0;this.panelManager.dockGroup(FORK_GROUP_ID,"right",initialWidth)}}handleSessionComplete(){this.clearAllForks(),this.emitForkActive()}handleDoneMessage(fork,retentionPolicy){if(this.log("info",`handleDoneMessage fork=${fork||"(main)"} retention=${retentionPolicy?.case??"default"}`),!fork){this.handleMainDone(retentionPolicy);return}const state=this.forks.get(fork);if(!state)return;switch(retentionPolicy?this.resolveRetention(retentionPolicy):state.retentionPolicy){case"close":state.completed=!0,this.scheduleForkClose(fork,state,retentionPolicy?.case==="close"?retentionPolicy.timeoutSeconds:void 0);break;case"recycle":state.completed=!0,state.recyclable=!0;break;default:state.completed=!0;break}}handleStoppedMessage(fork){if(this.log("info",`handleStoppedMessage fork=${fork||"(main)"}`),!fork){this.mainCloseTimer&&(clearTimeout(this.mainCloseTimer),this.mainCloseTimer=null),this.mainUrl=null,this.mainToken=void 0;const mainComponent=this.components.get(MAIN_PANEL_ID);mainComponent&&mainComponent.hide(),this.showStatusMessage(this.options.text?.stopped??"This session has been stopped","stopped");return}const state=this.forks.get(fork);if(state){state.closeTimer&&(clearTimeout(state.closeTimer),state.closeTimer=null),this.removingPanelProgrammatically=!0;try{if(this.panelManager){const component=this.components.get(state.panelId);component&&component.dispose(),this.panelManager.removePanel(state.panelId)}this.forks.delete(fork),this.removeForkGroupIfEmpty()}finally{this.removingPanelProgrammatically=!1}this.emitForkActive()}}cleanupGroupTracking(groupId){const actions=this.forkGroupActions.get(groupId);actions&&(actions.dispose(),this.forkGroupActions.delete(groupId)),this.floatingToolbars.delete(groupId),this.floatingAutoResized.delete(groupId),this.minimizeManager?.removeGroup(groupId),groupId===FORK_GROUP_ID&&(this._autoMaximizedByResize=!1)}cleanupStaleGroupTracking(){if(this.panelManager){for(const groupId of[...this.forkGroupActions.keys()])this.panelManager.getGroup(groupId)||this.cleanupGroupTracking(groupId);for(const groupId of[...this.floatingToolbars.keys()])this.panelManager.getGroup(groupId)||this.floatingToolbars.delete(groupId)}}removeForkGroupIfEmpty(){if(!this.panelManager)return;const g=this.panelManager.getGroup(FORK_GROUP_ID);g&&g.size===0?(this.panelManager.removeGroup(FORK_GROUP_ID),this.cleanupGroupTracking(FORK_GROUP_ID)):g||this.cleanupGroupTracking(FORK_GROUP_ID),this.minimizeManager?.removeGroup(FORK_GROUP_ID)}getMaximizedDockedGroupId(){for(const[groupId,actions]of this.forkGroupActions)if(actions.isMaximized)return groupId}emitForkActive(){if(!this.options.onForkActive)return;const active=this.forks.size>0;active!==this.lastForkActive&&(this.lastForkActive=active,this.options.onForkActive(active))}parseInheritToken(){const inheritFrom=this.options.inheritFrom;return inheritFrom?"hash"in inheritFrom?this.parseFromHash(inheritFrom.hash):this.parseFromParam(inheritFrom.param):null}parseFromHash(key){const hash=window.location.hash.slice(1);if(!hash)return null;const params=new URLSearchParams(hash),token=params.get(key);if(!token)return null;params.delete(key);const newHash=params.toString(),newUrl=window.location.pathname+window.location.search+(newHash?"#"+newHash:"");return history.replaceState(null,"",newUrl),decodeURIComponent(token)}parseFromParam(key){const params=new URLSearchParams(window.location.search),token=params.get(key);if(!token)return null;params.delete(key);const newSearch=params.toString(),newUrl=window.location.pathname+(newSearch?"?"+newSearch:"")+window.location.hash;return history.replaceState(null,"",newUrl),decodeURIComponent(token)}async init(){this.panelManager?.onDidRemovePanel(panel=>{if(!this.removingPanelProgrammatically){for(const[fork,state]of this.forks)if(state.panelId===panel.id){state.closeTimer&&(clearTimeout(state.closeTimer),state.closeTimer=null);const component=this.components.get(state.panelId);component&&component.dispose(),this.sessionToken&&this.client.stop(this.sessionToken,fork).catch(()=>{}),this.forks.delete(fork);break}this.emitForkActive(),this.cleanupStaleGroupTracking()}});const handlers={onUrl:msg=>this.onUrl(msg),onSession:sessionJson=>{sessionJson.status==="STATUS_COMPLETED"&&!sessionJson.fork&&this.handleSessionComplete(),!sessionJson.fork&&(sessionJson.status==="STATUS_COMPLETED"||sessionJson.status==="STATUS_STOPPED"||sessionJson.status==="STATUS_ERRORED"||sessionJson.status==="STATUS_DELEGATED"||sessionJson.status==="STATUS_EXPIRED")&&(this.sessionTerminated=!0,this.clearState(),this.beforeUnloadHandler&&(window.removeEventListener("beforeunload",this.beforeUnloadHandler),this.beforeUnloadHandler=null)),this.options.onSession&&this.options.onSession(sessionJson.status||"STATUS_UNSPECIFIED",sessionJson.fork)}};if(this.options.onOutput&&(handlers.onOutput=this.options.onOutput),handlers.onError=error=>{this.showErrorStatus(error),this.beforeUnloadHandler&&(window.removeEventListener("beforeunload",this.beforeUnloadHandler),this.beforeUnloadHandler=null)},!this.options.sessionToken&&this.resolvePersistOptions()){this.log("info","attempting session restore from persisted state");const result=await this.tryRestoreSession(handlers);if(this.log("info",`restore result=${result}`),result!=="none"){this.updateBeforeUnloadGuard();return}}if(this.options.sessionToken)this.log("info","using pre-created sessionToken"),this.sessionToken=this.options.sessionToken,await this.client.subscribe(this.sessionToken,handlers);else{const urlToken=this.parseInheritToken(),inheritToken=urlToken||this.options.inheritToken;if(this.options.inheritFrom&&!urlToken){const source="hash"in this.options.inheritFrom?`hash key '${this.options.inheritFrom.hash}'`:`param '${this.options.inheritFrom.param}'`;this.log("error",`no inherit token found in URL ${source}`);return}let challengeToken=this.options.challengeToken;if(this.options.requiresChallenge&&!challengeToken&&!inheritToken&&(challengeToken=await this.showCapWidgetAndSolve(),!challengeToken)){this.log("error","failed to solve challenge");return}let result;if(inheritToken)this.log("info","starting session via inheritToken"),result=await this.client.runInherit(inheritToken,handlers);else{this.log("info",`starting session via run (transmitter=${this.options.transmitter??"default"})`);const runOptions={...handlers};this.options.transmitter!==void 0&&(runOptions.transmitter=this.options.transmitter),this.options.signals!==void 0&&(runOptions.signals=this.options.signals),this.options.authToken!==void 0&&(runOptions.authToken=this.options.authToken),challengeToken!==void 0&&(runOptions.challengeToken=challengeToken),result=await this.client.run(runOptions)}this.sessionToken=result.sessionToken,this.sessionExpiresAt=result.expiresAt,this.log("info",`session started token=${this.sessionToken?.slice(0,8)}...`),this.saveState()}this.updateBeforeUnloadGuard()}async showCapWidgetAndSolve(){const CapWidgetClass=_AdaptWebClient._capWidgetClass;if(!CapWidgetClass)throw new Error("Cap.js not loaded. Import '@mochabug/adapt-web/cap' or use the full UMD bundle.");return new Promise(resolve=>{this.capWidgetInstance=new CapWidgetClass({container:this.rootElement,automationId:this.options.automationId,client:this.client.raw,...this.options.capWidgetOptions?.workerCount!==void 0&&{workerCount:this.options.capWidgetOptions.workerCount},...this.options.capWidgetOptions?.hiddenFieldName&&{hiddenFieldName:this.options.capWidgetOptions.hiddenFieldName},...this.options.capWidgetOptions?.troubleshootingUrl&&{troubleshootingUrl:this.options.capWidgetOptions.troubleshootingUrl},...this.options.capWidgetOptions?.disableHaptics!==void 0&&{disableHaptics:this.options.capWidgetOptions.disableHaptics},...this.options.capWidgetOptions?.i18n&&{i18n:this.options.capWidgetOptions.i18n},onSolve:token=>{this.capWidgetInstance=null,resolve(token)},onError:error=>{this.log("error","Cap.js error:",error),this.capWidgetInstance=null,resolve(void 0)}}),this.darkMode&&this.capWidgetInstance.setDarkMode(!0)})}resolvePersistOptions(){const p=this.options.persist;if(!p)return null;if(p===!0)return{storage:"session",ttl:3600};const result={storage:p.storage??"session",ttl:p.ttl??3600};return p.key!==void 0&&(result.key=p.key),result}getStorageKey(){return`mb_adapt_${this.resolvePersistOptions()?.key??this.options.automationId}`}getStorage(){const opts=this.resolvePersistOptions();return opts?opts.storage==="local"?localStorage:sessionStorage:null}saveState(){if(this.restoringSession)return;const storage=this.getStorage();if(!storage||!this.sessionToken)return;const opts=this.resolvePersistOptions();this.log("info",`saveState key=${this.getStorageKey()} forks=${this.forks.size} mainUrl=${this.mainUrl?"yes":"none"}`);const state={v:3,token:this.sessionToken,expiresAt:this.sessionExpiresAt?this.sessionExpiresAt.toISOString():null,savedAt:Date.now(),ttl:opts.ttl,mainUrl:this.mainUrl,mainToken:this.mainToken,forks:Array.from(this.forks.values()).filter(f=>!f.completed||f.recyclable).map(f=>{const pf={url:f.url,token:f.token,fork:f.fork,retentionPolicy:f.retentionPolicy};return f.source!==void 0&&(pf.source=f.source),pf}),forkDisplayMode:this.forkDisplay.mode,layout:this.panelManager?.serializeLayout()};if(this.minimizeManager){const minimizedIds=this.minimizeManager.getMinimizedGroupIds();minimizedIds.length>0&&(state.minimizedGroups=minimizedIds.map(gid=>{const entry=this.minimizeManager.getEntry(gid),persisted={groupId:gid,mode:entry?.mode??"floating"};return entry?.savedPosition&&(persisted.savedPosition={...entry.savedPosition}),persisted}))}const maxDockedId=this.getMaximizedDockedGroupId();maxDockedId&&(state.maximizedDockedGroupId=maxDockedId),storage.setItem(this.getStorageKey(),JSON.stringify(state))}loadState(){const storage=this.getStorage();if(!storage)return null;const raw=storage.getItem(this.getStorageKey());if(!raw)return this.log("info","loadState: no persisted state found"),null;let state;try{state=JSON.parse(raw)}catch{return this.log("warn","loadState: invalid JSON, clearing"),this.clearState(),null}if(state.v!==3)return this.log("warn",`loadState: version mismatch v=${state.v}, clearing`),this.clearState(),null;const now=Date.now(),leeway=3e4;if(now-state.savedAt>state.ttl*1e3+leeway)return this.log("info","loadState: TTL expired, clearing"),this.clearState(),null;if(state.expiresAt){const expires=new Date(state.expiresAt).getTime();if(now>expires+leeway)return this.log("info","loadState: session expired, clearing"),this.clearState(),null}return this.log("info",`loadState: found state forks=${state.forks.length} mainUrl=${state.mainUrl?"yes":"none"}`),state}clearState(){this.log("info","clearState");const storage=this.getStorage();storage&&storage.removeItem(this.getStorageKey())}async tryRestoreSession(handlers){const state=this.loadState();if(!state)return"none";const isStale=Date.now()-state.savedAt>1e4;if(this.log("info",`tryRestoreSession token=${state.token.slice(0,8)}... forks=${state.forks.length} stale=${isStale}`),this.sessionToken=state.token,this.sessionExpiresAt=state.expiresAt?new Date(state.expiresAt):void 0,this.mainUrl=state.mainUrl,this.mainToken=state.mainToken,state.forkDisplayMode&&(state.forkDisplayMode==="side-by-side"?this.forkDisplay={mode:"side-by-side"}:this.forkDisplay={mode:"dialog"}),this.mainUrl){const mainComponent=this.components.get(MAIN_PANEL_ID);mainComponent&&mainComponent.update({url:this.mainUrl,token:this.mainToken})}this.restoringSession=!0;try{if(state.layout?.mainLayout&&this.panelManager&&this.restoreDockedLayout(state.layout.mainLayout),state.layout?.floatingGroups&&this.panelManager)for(const fg of state.layout.floatingGroups){if(this.panelManager.getGroup(fg.groupId))continue;const group=this.panelManager.addGroup({id:fg.groupId,floating:fg.bounds});group.dragConstraint="merge-only",this.allowDocking||(group.dockingBlocked=!0),this.allowDialogDocking||(group.dialogDockingBlocked=!0),this.setupForkGroupActions(group),fg.internalLayout&&this.createGroupsFromTree(fg.internalLayout)}this.panelManager&&syncGroupIdCounter(this.panelManager.getGroupIds());const findFallbackGroup=()=>{if(!this.panelManager)return FORK_GROUP_ID;for(const g of this.panelManager.getDockedGroups())if(g.id!=="main-group")return g.id;return FORK_GROUP_ID};this.log("info",`restore phase2: ${state.forks.length} forks, panelLocations=${JSON.stringify(state.layout?.panelLocations??{})}`);for(const pf of state.forks){const panelId=`fork-${pf.fork}`,targetGroupId=state.layout?.panelLocations?.[panelId]??FORK_GROUP_ID,groupExists=this.panelManager?.getGroup(targetGroupId),effectiveGroupId=groupExists?targetGroupId:findFallbackGroup();groupExists||this.log("warn",`restore: target group "${targetGroupId}" not found for ${panelId}, fallback="${effectiveGroupId}"`),this.restoreFork(pf,effectiveGroupId)}if(state.layout?.floatingGroups&&this.panelManager)for(const fg of state.layout.floatingGroups)fg.internalLayout&&this.panelManager.rebuildFloatingInternalLayout(fg.groupId,fg.internalLayout);if(this.panelManager&&this.panelManager.cleanupEmptyGroups(),state.layout&&this.panelManager)for(const fg of state.layout.floatingGroups){const overlay=this.panelManager.getFloatingOverlay(fg.groupId);overlay&&(overlay.setFullBounds(fg.bounds),fg.isMaximized&&(overlay.maximize(),this.floatingToolbars.get(fg.groupId)?.syncMaximizedState()))}if(state.minimizedGroups&&this.minimizeManager&&this.panelManager)for(const mg of state.minimizedGroups){const group=this.panelManager.getGroup(mg.groupId);if(group&&!this.minimizeManager.isMinimized(mg.groupId))if(mg.mode==="floating"){const overlay=this.panelManager.getFloatingOverlay(mg.groupId);overlay&&this.minimizeManager.minimize(mg.groupId,overlay,group)}else mg.mode==="docked"&&this.minimizeManager.minimizeDocked(mg.groupId,group,this.panelManager)}if(state.maximizedDockedGroupId&&this.panelManager){const actions=this.forkGroupActions.get(state.maximizedDockedGroupId);actions&&actions.setMaximized()}isStale||handlers.onSession?.({status:"STATUS_RUNNING"})}finally{this.restoringSession=!1}this.saveState();let subscribeFailed=!1,errorWasSilenced=!1;const originalOnError=handlers.onError,wrappedHandlers={...handlers,onError:error=>{subscribeFailed=!0;const currentState=this.loadState();!currentState||Date.now()-currentState.savedAt>1e4?(errorWasSilenced=!0,this.clearState()):originalOnError?.(error)}};try{await this.client.subscribe(state.token,wrappedHandlers)}catch{subscribeFailed=!0,isStale?(errorWasSilenced=!0,this.clearState()):this.showErrorStatus(new Error("Session restore failed"))}return subscribeFailed?(await this.client.unsubscribe(),this.sessionToken=null,this.sessionExpiresAt=void 0,this.mainUrl=null,this.mainToken=void 0,this.clearAllForks(),this.components.get(MAIN_PANEL_ID)?.hide(),errorWasSilenced?"none":"failed"):"restored"}async newSession(){this.clearState(),this.sessionTerminated=!1,this.mainCloseTimer&&(clearTimeout(this.mainCloseTimer),this.mainCloseTimer=null),this.mainRetentionPolicy="retain",this.sessionToken&&this.client.stop(this.sessionToken).catch(()=>{}),await this.client.unsubscribe(),this.mainUrl=null,this.mainToken=void 0,this.sessionToken=null,this.sessionExpiresAt=void 0,this.lastForkActive=null,this.updateBeforeUnloadGuard(),this.clearAllForks(),this.components.get(MAIN_PANEL_ID)?.hide(),this.removeStatusMessage();try{await this.init()}catch(error){this.showErrorStatus(error)}}resizeOverlayForGroup(group){if(!this.panelManager)return;const overlay=this.panelManager.findOverlayContaining(group.id);if(!overlay)return;const allGroups=overlay.getAllGroups();let maxHeight=0;for(const g of allGroups){const active=g.activePanel;if(active){const h=this.forkPanelHeights.get(active.id)??0;h>maxHeight&&(maxHeight=h)}}if(maxHeight>0){const headerHeight=group.headerElement?.offsetHeight??40,newHeight=Math.ceil(maxHeight)+headerHeight,bounds=overlay.getBounds(),newY=(window.innerHeight-newHeight)/2;overlay.setFullBounds({...bounds,height:newHeight,y:Math.max(0,newY)})}}onContainerResize(width,_height){if(!this.panelManager)return;const forkGroup=this.panelManager.getGroup(FORK_GROUP_ID);if(!forkGroup)return;const bp=this.responsiveBreakpoint,restoreThreshold=bp+this.responsiveHysteresis,forkActions=this.forkGroupActions.get(FORK_GROUP_ID),isDockedMaximized=forkActions?.isMaximized??!1;if(width<bp&&!this._autoMaximizedByResize){if(forkGroup.location==="floating"){const overlay=this.panelManager.getFloatingOverlay(FORK_GROUP_ID);overlay&&!overlay.isMaximized&&(overlay.maximize(),this._autoMaximizedByResize=!0)}else isDockedMaximized||(forkActions?(forkActions.setMaximized(),forkActions.setAutoMaximizedByResize(!0)):this.panelManager.maximizeDockedGroup(forkGroup),this._autoMaximizedByResize=!0);this.applyBestAutoResizeHeight()}width>=restoreThreshold&&this._autoMaximizedByResize&&(forkGroup.location==="floating"?this.panelManager.getFloatingOverlay(FORK_GROUP_ID)?.restore():forkActions?forkActions.clearMaximized():this.panelManager.restoreMaximizedDockedGroup(forkGroup),this._autoMaximizedByResize=!1,forkActions?.setAutoMaximizedByResize(!1))}setConfirmOnClose(enabled){this.confirmOnClose=enabled,this.updateBeforeUnloadGuard()}updateBeforeUnloadGuard(){const shouldGuard=this.confirmOnClose&&!!this.sessionToken&&!this.destroyed;shouldGuard&&!this.beforeUnloadHandler?(this.beforeUnloadHandler=e=>{e.preventDefault()},window.addEventListener("beforeunload",this.beforeUnloadHandler)):!shouldGuard&&this.beforeUnloadHandler&&(window.removeEventListener("beforeunload",this.beforeUnloadHandler),this.beforeUnloadHandler=null)}wireBeforeTabClose(){this.panelManager&&this.panelManager.setBeforeTabClose(panelId=>{if(this.removingPanelProgrammatically||!this.confirmOnClose)return!0;for(const[,state]of this.forks)if(state.panelId===panelId)return state.completed?!0:this.showConfirmDialog("This panel hasn\u2019t finished yet. Are you sure you want to close it?");return!0})}confirmCloseGroup(group){return!this.confirmOnClose||!group.panels.some(panel=>{for(const state of this.forks.values())if(state.panelId===panel.id&&!state.completed)return!0;return!1})?!0:this.showConfirmDialog("Some panels haven\u2019t finished yet. Are you sure you want to close them?")}showConfirmDialog(message){return new Promise(resolve=>{if(!this.rootElement){resolve(!0);return}const overlay=document.createElement("div");overlay.className="mb-adapt mb-adapt__confirm-overlay",this.darkMode&&overlay.classList.add("mb-adapt--dark");const card=document.createElement("div");card.className="mb-adapt__confirm-card";const text=document.createElement("p");text.className="mb-adapt__confirm-text",text.textContent=message,card.appendChild(text);const buttons=document.createElement("div");buttons.className="mb-adapt__confirm-buttons";const cancelBtn=document.createElement("button");cancelBtn.className="mb-adapt__confirm-btn mb-adapt__confirm-btn--cancel",cancelBtn.textContent="Cancel";const confirmBtn=document.createElement("button");confirmBtn.className="mb-adapt__confirm-btn mb-adapt__confirm-btn--confirm",confirmBtn.textContent="Close",buttons.appendChild(cancelBtn),buttons.appendChild(confirmBtn),card.appendChild(buttons),overlay.appendChild(card),document.body.appendChild(overlay);const cleanup=result=>{overlay.remove(),resolve(result)};cancelBtn.addEventListener("click",()=>cleanup(!1)),confirmBtn.addEventListener("click",()=>cleanup(!0)),overlay.addEventListener("click",e=>{e.target===overlay&&cleanup(!1)})})}async destroy(){if(!this.destroyed){this.log("info","destroy"),this.destroyed=!0,this.mainCloseTimer&&(clearTimeout(this.mainCloseTimer),this.mainCloseTimer=null);for(const state of this.forks.values())state.closeTimer&&(clearTimeout(state.closeTimer),state.closeTimer=null);this.beforeUnloadHandler&&(window.removeEventListener("beforeunload",this.beforeUnloadHandler),this.beforeUnloadHandler=null),this.resizeObserver?.disconnect(),this.resizeObserver=null,this.capWidgetInstance?.destroy(),this.capWidgetInstance=null,this.minimizeManager?.dispose(),this.minimizeManager=null,this.sessionToken&&!this.loadState()&&!this.sessionTerminated&&this.client.stop(this.sessionToken).catch(()=>{}),await this.client.unsubscribe(),this.messageHandler&&window.removeEventListener("message",this.messageHandler),this.panelManager&&(this.panelManager.dispose(),this.panelManager=null),this.rootElement?.parentNode?.removeChild(this.rootElement),this.mainUrl=null,this.mainToken=void 0,this.forks.clear(),this.components.clear(),this.forkPanelHeights.clear(),this.forkGroupActions.clear(),this.floatingToolbars.clear(),this.sessionToken=null,this.lastForkActive=null,this.rootElement=null,this.messageHandler=null,this.statusMessageElement=null,this.minimizedTabsContainer=null}}showStatusMessage(text,kind="error"){if(!this.rootElement)return;this.removeStatusMessage();const mainComponent=this.components.get(MAIN_PANEL_ID);mainComponent&&mainComponent.hide(),this.statusMessageElement=document.createElement("div"),this.statusMessageElement.className=this.options.classNames?.statusMessage??"mb-adapt__status-message";const card=document.createElement("div");card.className=this.options.classNames?.statusCard??"mb-adapt__status-card";const iconWrap=document.createElement("div");iconWrap.className=kind==="stopped"||kind==="expired"?"mb-adapt__status-icon mb-adapt__status-icon--stopped":"mb-adapt__status-icon",iconWrap.innerHTML=kind==="stopped"||kind==="expired"?'<svg viewBox="0 0 24 24" fill="none" stroke="#6b7280" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="6" y="6" width="12" height="12" rx="2"/></svg>':'<svg viewBox="0 0 24 24" fill="none" stroke="#ef4444" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><line x1="12" y1="8" x2="12" y2="12"/><line x1="12" y1="16" x2="12.01" y2="16"/></svg>',card.appendChild(iconWrap);const msg=document.createElement("p");msg.className="mb-adapt__status-text",msg.textContent=text,card.appendChild(msg);const btn=document.createElement("button");btn.className="mb-adapt__status-restart",btn.textContent=this.options.text?.restartButton??"Try again",btn.addEventListener("click",()=>this.newSession()),card.appendChild(btn),this.statusMessageElement.appendChild(card),this.rootElement.appendChild(this.statusMessageElement)}removeStatusMessage(){this.statusMessageElement&&(this.statusMessageElement.remove(),this.statusMessageElement=null)}showErrorStatus(error){const adaptError=this.classifyError(error),overlayKind=adaptError.kind==="expired"?"expired":"error";this.clearState(),this.clearAllForks(),this.showStatusMessage(adaptError.message,overlayKind),this.options.onError?.(adaptError)}isExpiredTokenError(error){return error instanceof ConnectError&&error.code===Code.PermissionDenied&&error.message.toLowerCase().includes("expired")}getErrorMessage(error){const text=this.options.text,fallback=text?.error??"Something went wrong. Please try again later.";if(error instanceof ConnectError){if(this.isExpiredTokenError(error))return text?.sessionExpired??"Your session has expired.";switch(error.code){case Code.ResourceExhausted:return text?.resourceExhausted??"This automation is currently at capacity. Please try again later.";case Code.NotFound:return error.message.toLowerCase().includes("session not found")?text?.sessionNotFound??"This session has timed out or been stopped.":text?.notFound??"This automation could not be found.";case Code.PermissionDenied:case Code.Unauthenticated:return text?.permissionDenied??"You don't have permission to run this automation.";default:return fallback}}return fallback}classifyError(error){const message=this.getErrorMessage(error);if(error instanceof ConnectError){if(this.isExpiredTokenError(error))return{kind:"expired",message,retriable:!1,cause:error};switch(error.code){case Code.ResourceExhausted:return{kind:"capacity",message,retriable:!0,cause:error};case Code.NotFound:return error.message.toLowerCase().includes("session not found")?{kind:"session_not_found",message,retriable:!1,cause:error}:{kind:"not_found",message,retriable:!1,cause:error};case Code.PermissionDenied:case Code.Unauthenticated:return{kind:"auth",message,retriable:!0,cause:error};default:return{kind:"error",message,retriable:!1,cause:error}}}return{kind:"error",message,retriable:!1,cause:error}}};_AdaptWebClient._capWidgetClass=null;let AdaptWebClient=_AdaptWebClient;export{AdaptAutomationElement,AdaptWebClient,FloatingToolbar2 as FloatingToolbar,ForkGroupActions2 as ForkGroupActions,IframePanelComponent2 as IframePanelComponent,MinimizeManager2 as MinimizeManager,PanelManager2 as PanelManager,clearPersistedState,configure,createConnectClient,resetConfig,resolveTheme2 as resolveTheme};