{"version":3,"file":"3dsource-metabox-front-api.mjs","sources":["../../../../projects/3dsource/metabox-front-api/src/lib/actions/CommandBase.ts","../../../../projects/3dsource/metabox-front-api/src/lib/actions/fromCommunicatorEvent.ts","../../../../projects/3dsource/metabox-front-api/src/lib/interfaces/ToMetaboxMessagePayloads.ts","../../../../projects/3dsource/metabox-front-api/src/lib/actions/MetaboxConfig.ts","../../../../projects/3dsource/metabox-front-api/src/lib/actions/GetPdf.ts","../../../../projects/3dsource/metabox-front-api/src/lib/actions/GetCallToActionInformation.ts","../../../../projects/3dsource/metabox-front-api/src/lib/actions/GetCamera.ts","../../../../projects/3dsource/metabox-front-api/src/lib/actions/SetCamera.ts","../../../../projects/3dsource/metabox-front-api/src/lib/actions/ResetCamera.ts","../../../../projects/3dsource/metabox-front-api/src/lib/actions/ResetConfiguration.ts","../../../../projects/3dsource/metabox-front-api/src/lib/actions/ApplyZoom.ts","../../../../projects/3dsource/metabox-front-api/src/lib/actions/InitShowcase.ts","../../../../projects/3dsource/metabox-front-api/src/lib/actions/PlayShowcase.ts","../../../../projects/3dsource/metabox-front-api/src/lib/actions/UnrealCommand.ts","../../../../projects/3dsource/metabox-front-api/src/lib/actions/PauseShowcase.ts","../../../../projects/3dsource/metabox-front-api/src/lib/actions/StopShowcase.ts","../../../../projects/3dsource/metabox-front-api/src/lib/actions/GetScreenshot.ts","../../../../projects/3dsource/metabox-front-api/src/lib/actions/SetProduct.ts","../../../../projects/3dsource/metabox-front-api/src/lib/actions/SetProductMaterial.ts","../../../../projects/3dsource/metabox-front-api/src/lib/actions/SetEnvironment.ts","../../../../projects/3dsource/metabox-front-api/src/lib/actions/SetEnvironmentMaterial.ts","../../../../projects/3dsource/metabox-front-api/src/lib/actions/SetMaterials.ts","../../../../projects/3dsource/metabox-front-api/src/lib/actions/ShowEmbeddedMenu.ts","../../../../projects/3dsource/metabox-front-api/src/lib/actions/ShowOverlayInterface.ts","../../../../projects/3dsource/metabox-front-api/src/lib/actions/ShowMeasurement.ts","../../../../projects/3dsource/metabox-front-api/src/lib/actions/HideMeasurement.ts","../../../../projects/3dsource/metabox-front-api/src/lib/actions/ResumeStream.ts","../../../../projects/3dsource/metabox-front-api/src/lib/actions/StopStream.ts","../../../../projects/3dsource/metabox-front-api/src/lib/actions/ResetUserInactivityTimer.ts","../../../../projects/3dsource/metabox-front-api/src/lib/helpers/event-dispatcher.ts","../../../../projects/3dsource/metabox-front-api/src/lib/constants/common.ts","../../../../projects/3dsource/metabox-front-api/src/lib/constants/version.ts","../../../../projects/3dsource/metabox-front-api/src/lib/helpers/message-source.ts","../../../../projects/3dsource/metabox-front-api/src/lib/helpers/communicator.ts","../../../../projects/3dsource/metabox-front-api/src/lib/helpers/prepare-iframe-src.ts","../../../../projects/3dsource/metabox-front-api/src/lib/helpers/integrate-metabox.ts","../../../../projects/3dsource/metabox-front-api/src/lib/helpers/save-image.ts","../../../../projects/3dsource/metabox-front-api/src/lib/helpers/url-utils.ts","../../../../projects/3dsource/metabox-front-api/src/3dsource-metabox-front-api.ts"],"sourcesContent":["import type { ToMetaBoxMessageEnvelope } from '../interfaces';\n\n/**\n * Base class for commands sent to the Metabox API.\n *\n * ### What does it unlock?\n * Base class that all other commands inherit from in a class hierarchy. Provides common properties\n * and methods that are automatically available to all command subclasses.\n *\n * ### Practical Application\n * Base class all commands inherit from. Never instantiate directly — use specific subclasses like\n * SetProduct, SetCamera, etc. All commands are sent via `api.sendCommandToMetabox(new CommandName(...))`.\n *\n * ### AI Coding Best Practices\n * Never construct a generic CommandBase. Always use the specific typed command class. When generating\n * dynamic command dispatch, use a switch/map pattern matching command names to their constructors.\n *\n * @internal\n * @hidden\n */\n\nexport class CommandBase {\n  /** The message envelope populated by subclass constructors and sent via {@link Communicator.sendCommandToMetabox}. */\n  data!: ToMetaBoxMessageEnvelope;\n}\n","import type { Communicator } from '../helpers';\nimport type {\n  FromMetaBoxApiEvents,\n  FromMetaboxMessagePayloads,\n} from '../interfaces';\nimport type { Observable } from 'rxjs';\nimport { fromEvent } from 'rxjs';\n\n/**\n * Wrapper helper function to use with RxJS the same way as `fromEvent`, to listen to events from the Communicator.\n *\n * ### What does it unlock?\n * Function that creates an event listener subscription. Allows developers to subscribe to specific events from the Communicator.\n *\n * ### Practical Application\n * Function that creates event listener subscriptions. Alternative to api.addEventListener() — both subscribe\n * to configurator events. Use to react to state changes, screenshot readiness, viewport loading, showcase status, etc.\n *\n * ### AI Coding Best Practices\n * Prefer api.addEventListener() directly from the Communicator object. If using fromCommunicatorEvent, pass the\n * event name and handler. Key events: configuratorDataUpdated, viewportReady, screenshotReady, showcaseStatusChanged,\n * getCameraResult. Always subscribe BEFORE sending commands that trigger responses.\n *\n * @param {Communicator} target - The Communicator instance to listen on.\n * @param {T} eventName - The event name from {@link FromMetaBoxApiEvents} to subscribe to.\n * @returns An Observable that emits the typed payload each time the event fires.\n * @internal\n */\n\nexport function fromCommunicatorEvent<T extends FromMetaBoxApiEvents>(\n  target: Communicator,\n  eventName: T,\n) {\n  return fromEvent(target, eventName) as Observable<\n    FromMetaboxMessagePayloads[T]\n  >;\n}\n","import type { MimeType } from '../actions';\nimport type { MetaboxHost } from '../constants';\nimport type { MetaboxCommandConfig } from './metabox-config';\n\n/**\n * Registry of all action identifiers that can be sent from the host application to the Metabox Basic Configurator.\n * Each key maps to a string used as the `action` field in the postMessage envelope.\n *\n * ### What does it unlock?\n * Variable containing all available action names. Interface listing all actions that the configurator supports.\n *\n * ### Practical Application\n * Master action registry object — all supported configurator action names. Invaluable reference for building\n * admin dashboards, permission systems, or feature-availability displays.\n *\n * ### AI Coding Best Practices\n * Iterate this object to dynamically build action dropdowns, command palettes, or feature checklists in admin tools.\n * Each key is an action name, value is its description. Excellent reference for AI coding agents to understand\n * the full command vocabulary available.\n */\nexport const MetaboxBasicConfiguratorActions = {\n  metaboxConfig: 'metaboxConfig',\n  resumeStream: 'resumeStream',\n  stopStream: 'stopStream',\n  setEnvironment: 'setEnvironment',\n  setEnvironmentMaterialById: 'setEnvironmentMaterialById',\n  setProduct: 'setProduct',\n  setProductMaterialById: 'setProductMaterialById',\n  setMaterials: 'setMaterials',\n  getPdf: 'getPdf',\n  getCallToActionInformation: 'getCallToActionInformation',\n  getScreenshot: 'getScreenshot',\n  showEmbeddedMenu: 'showEmbeddedMenu',\n  showOverlayInterface: 'showOverlayInterface',\n  getCamera: 'getCamera',\n  setCamera: 'setCamera',\n  resetCamera: 'resetCamera',\n  resetConfiguration: 'resetConfiguration',\n  applyZoom: 'applyZoom',\n  initShowcase: 'initShowcase',\n  playShowcase: 'playShowcase',\n  pauseShowcase: 'pauseShowcase',\n  stopShowcase: 'stopShowcase',\n  sendCommandToUnreal: 'sendCommandToUnreal',\n  showMeasurement: 'showMeasurement',\n  hideMeasurement: 'hideMeasurement',\n  resetUserInactivityTimer: 'resetUserInactivityTimer',\n} as const;\n\n/**\n * Union of all action string literals from {@link MetaboxBasicConfiguratorActions}.\n *\n * ### What does it unlock?\n * Type alias for all actions that can be sent to MetaBox. Defines the complete set of command types available.\n *\n * ### Practical Application\n * Type alias enumerating all available outgoing command types. Master list of everything your app can tell MetaBox to do.\n * Use as a checklist when planning which features to implement.\n *\n * ### AI Coding Best Practices\n * Reference for building command dispatchers or admin tools. Full command set includes all values of\n * MetaboxBasicConfiguratorActions like: \"metaboxConfig\" | \"setEnvironment\" | \"setEnvironmentMaterialById\" | ...\n */\nexport type ToMetaBoxActions =\n  (typeof MetaboxBasicConfiguratorActions)[keyof typeof MetaboxBasicConfiguratorActions];\n\n/**\n * @internal\n * @hidden\n */\nexport type ToMetaboxMessagePayload =\n  ToMetaboxMessagePayloads[keyof ToMetaboxMessagePayloads];\n\n/**\n * Interface for messages sent from the application to the Basic Metabox API.\n *\n * ### What does it unlock?\n * Defines payload structures for different types of outgoing messages to MetaBox. Contains data models for various command parameters.\n *\n * ### Practical Application\n * Payload type definitions for all outgoing command types. Defines required and optional fields per command.\n * Essential TypeScript reference for type-safe command construction.\n *\n * ### AI Coding Best Practices\n * Use as TypeScript type reference for proper typing when building dynamic command dispatchers.\n * Each key corresponds to a command name and its value defines the expected payload structure.\n */\nexport interface ToMetaboxMessagePayloads {\n  [MetaboxBasicConfiguratorActions.metaboxConfig]: {\n    appId: string;\n    config: MetaboxCommandConfig;\n  };\n  [MetaboxBasicConfiguratorActions.setProduct]: { productId: string };\n  [MetaboxBasicConfiguratorActions.setEnvironment]: { id: string };\n  [MetaboxBasicConfiguratorActions.getPdf]: void;\n  [MetaboxBasicConfiguratorActions.getCallToActionInformation]: void;\n  [MetaboxBasicConfiguratorActions.getScreenshot]: {\n    format: MimeType;\n    size?: { x: number; y: number };\n  };\n  [MetaboxBasicConfiguratorActions.setProductMaterialById]: {\n    slotId: string;\n    materialId: string;\n  };\n  [MetaboxBasicConfiguratorActions.setEnvironmentMaterialById]: {\n    slotId: string;\n    materialId: string;\n  };\n  [MetaboxBasicConfiguratorActions.setMaterials]: {\n    materials: MaterialCommandEnvelope[];\n  };\n  [MetaboxBasicConfiguratorActions.showEmbeddedMenu]: { visible: boolean };\n  [MetaboxBasicConfiguratorActions.showOverlayInterface]: { visible: boolean };\n  [MetaboxBasicConfiguratorActions.getCamera]: void;\n  [MetaboxBasicConfiguratorActions.setCamera]: {\n    camera: CameraCommandPayload;\n  };\n  [MetaboxBasicConfiguratorActions.resetCamera]: void;\n  [MetaboxBasicConfiguratorActions.resetConfiguration]: void;\n  [MetaboxBasicConfiguratorActions.applyZoom]: { zoom: number };\n  [MetaboxBasicConfiguratorActions.initShowcase]: void;\n  [MetaboxBasicConfiguratorActions.playShowcase]: void;\n  [MetaboxBasicConfiguratorActions.pauseShowcase]: void;\n  [MetaboxBasicConfiguratorActions.stopShowcase]: void;\n  [MetaboxBasicConfiguratorActions.sendCommandToUnreal]: object;\n  [MetaboxBasicConfiguratorActions.resetUserInactivityTimer]: void;\n  [MetaboxBasicConfiguratorActions.stopStream]: void;\n}\n\n/**\n * One entry of a {@link SetMaterials} batch — the full envelope of a single material command,\n * so each entry stays self-describing about which target it applies to.\n *\n * ### What does it unlock?\n * Union of the material command envelopes accepted inside a batch. Carries the target kind in its\n * `action` field, so one array can mix product and environment materials.\n *\n * ### Practical Application\n * The wire shape of `SetMaterials`. You normally never build these by hand — pass\n * {@link SetProductMaterial} and {@link SetEnvironmentMaterial} instances to `SetMaterials` and it assembles the array.\n *\n * ### AI Coding Best Practices\n * Reference this type when parsing or logging raw postMessage traffic, or when reconstructing a\n * saved configuration. Discriminate on `action` to tell the targets apart.\n */\nexport type MaterialCommandEnvelope =\n  | {\n      action: typeof MetaboxBasicConfiguratorActions.setProductMaterialById;\n      payload: { slotId: string; materialId: string };\n    }\n  | {\n      action: typeof MetaboxBasicConfiguratorActions.setEnvironmentMaterialById;\n      payload: { slotId: string; materialId: string };\n    };\n\n/**\n * Payload for the {@link SetCamera} command describing the desired camera state in the Unreal scene.\n * All fields are optional — only the provided values will be applied.\n *\n * ### What does it unlock?\n * Defines the payload structure for camera commands. Contains camera-related parameters passed to SetCamera command.\n *\n * ### Practical Application\n * Read-only interface defining camera parameters: fov (degrees), mode ('orbit'|'fps'), position ({x,y,z}),\n * rotation ({horizontal: yaw, vertical: pitch}), and restrictions (distance/FOV/rotation limits).\n * Both returned by getCameraResult event and accepted by SetCamera.\n *\n * ### AI Coding Best Practices\n * This interface is bidirectional — returned from GetCamera and accepted by SetCamera.\n * Capture a camera state via getCameraResult and replay it with SetCamera(payload).\n * Only include restriction fields you want to enforce; omitted values keep current settings.\n * In orbit mode, distance limits are relative to the orbit pivot.\n */\nexport interface CameraCommandPayload {\n  /** Field of a view angle in degrees. */\n  fov?: number;\n  /** Camera control mode: `'fps'` for first-person or `'orbit'` for orbital rotation around pivot. */\n  mode?: 'fps' | 'orbit';\n  /** Camera position in 3D world space. */\n  position?: { x: number; y: number; z: number };\n  /** Camera rotation angles in degrees. */\n  rotation?: {\n    horizontal: number;\n    vertical: number;\n  };\n  /** Min/max constraints applied to camera movement, zoom, and rotation. */\n  restrictions?: {\n    maxDistanceToPivot?: number;\n    maxFov?: number;\n    maxHorizontalRotation?: number;\n    maxVerticalRotation?: number;\n    minDistanceToPivot?: number;\n    minFov?: number;\n    minHorizontalRotation?: number;\n    minVerticalRotation?: number;\n  };\n}\n\n/**\n * @internal\n * @hidden\n * Envelope wrapping an action and its payload for host-to-Metabox postMessage communication.\n *\n * ### What does it unlock?\n * Envelope structure for outgoing MetaBox messages. Encapsulates messages with protocol headers for transmission.\n *\n * ### Practical Application\n * Protocol envelope for outgoing messages — adds headers for transmission to MetaBox iframe.\n * Internal to the communication layer, handled automatically by the Communicator.\n *\n * ### AI Coding Best Practices\n * Do not construct manually. The Communicator handles all message wrapping. Only reference this interface\n * if debugging raw postMessage traffic in browser devtools to diagnose why commands aren't being received.\n */\nexport interface ToMetaBoxMessageEnvelope {\n  action: ToMetaBoxActions;\n  payload?: ToMetaboxMessagePayload | never;\n}\n\n/**\n * @internal\n * @hidden\n */\nexport type ToMetaboxTarget = 'metabox' | 'child';\n\n/**\n * @internal\n * @hidden\n * Top-level postMessage structure sent from the host to the Metabox iframe.\n *\n * ### What does it unlock?\n * Message interface for sending data to MetaBox. Wraps outgoing commands with necessary protocol information.\n *\n * ### Practical Application\n * Outgoing message format for commands to MetaBox. Wraps commands with protocol information for postMessage delivery.\n * Handled automatically by Communicator.sendCommandToMetabox() — never construct manually.\n *\n * ### AI Coding Best Practices\n * Do not construct ToMetaBoxMessage objects. Always use `api.sendCommandToMetabox(new CommandName(...))`.\n * The Communicator wraps your command in the correct message format automatically.\n */\nexport interface ToMetaBoxMessage {\n  host: typeof MetaboxHost;\n  envelope: ToMetaBoxMessageEnvelope;\n  /**\n   * @deprecated, use envelope instead of payload\n   */\n  payload: ToMetaBoxMessageEnvelope;\n  target: ToMetaboxTarget;\n  apiVersion: string;\n}\n","import { CommandBase } from './CommandBase';\nimport type { MetaboxCommandConfig } from '../interfaces';\nimport { MetaboxBasicConfiguratorActions } from '../interfaces';\n\n/**\n * Represents a command to send Metabox Config to Metabox Basic Configurator.\n *\n * ### What does it unlock?\n * Configuration object passed to MetaBox during initialization. Specifies domain, host, standalone mode,\n * and other parameters that control how the configurator behaves.\n *\n * ### Practical Application\n * Internal configuration object auto-sent during initialization. Contains appId and config.\n * DO NOT call directly — integrateMetabox() handles this automatically as part of its setup sequence.\n *\n * ### AI Coding Best Practices\n * NEVER instantiate or send MetaboxConfig manually. It is auto-sent by integrateMetabox().\n * Use the IntegrateMetaboxConfig parameter of integrateMetabox() instead for setting domain, standalone,\n * loadingImage, introImage, state, etc.\n *\n * @internal\n * Automatically sent when the Communicator instance is ready.\n *\n * @param {string} appId - The unique identifier for the Communicator Instance\n * @param {MetaboxCommandConfig} config - optional initial config: standalone - if true - disable metabox custom template and all logic\n */\n\nexport class MetaboxConfig extends CommandBase {\n  constructor(appId: string, config: MetaboxCommandConfig) {\n    super();\n    this.data = {\n      action: MetaboxBasicConfiguratorActions.metaboxConfig,\n      payload: { appId, config },\n    };\n  }\n}\n","import { CommandBase } from './CommandBase';\nimport { MetaboxBasicConfiguratorActions } from '../interfaces';\n\n/**\n * Represents a command to get a PDF from Metabox Basic Configurator.\n * This class sends a message to the Metabox API to generate a PDF based on the current configuration.\n * The document is streamed to the browser as a download once it is ready — that path needs no\n * subscription and has not changed.\n *\n * The PDF is not stored anywhere, so there is no document handle to receive. To follow the render\n * rather than just let it land, listen to the 'pdfStatusChanged' event before sending the command:\n * it reports `'started'`, then `'ready'` or `'failed'`.\n *\n * @remarks\n * `pdfStatusChanged` is additive and requires configurator-side support. Where the configurator does\n * not emit it yet, the automatic download remains the only signal — so use the event for progress and\n * error reporting, and never gate the export flow on it alone.\n *\n * ### What does it unlock?\n * Generates a native MetaBox PDF document server-side. The download works on its own;\n * `pdfStatusChanged` additionally makes the render observable — whether it started, finished or failed.\n *\n * ### Practical Application\n * Generates a branded PDF from the current configurator state. Use for B2B quote workflows,\n * downloadable spec sheets, or emailing configured product summaries to prospects. Subscribe to\n * `pdfStatusChanged` to disable the export button while the render runs — it is not instant, and a\n * second click starts a second render — and to surface a failure instead of leaving the user waiting.\n *\n * ### AI Coding Best Practices\n * `api.sendCommandToMetabox(new GetPdf())` takes no parameters. Subscribe to `pdfStatusChanged` BEFORE\n * sending. Do not wait for a file handle: there is none, the browser download is the delivery. Keep a\n * timeout of your own, since a configurator without this event will never report. Failure detail, when\n * available, arrives on `statusMessageChanged`.\n *\n * @example\n * import { GetPdf, Communicator, PdfStatus } from '@3dsource/metabox-front-api';\n * window.env3DSource.apiReady = (api: Communicator) => {\n *\n *     //Subscribe to the event before sending the command to ensure you capture the response\n *     api.addEventListener('pdfStatusChanged', (status: PdfStatus) => {\n *       if (status === 'failed') {\n *         console.warn('PDF render failed');\n *       }\n *       console.log('PDF render:', status);\n *     });\n *\n *     api.sendCommandToMetabox(new GetPdf());\n * };\n */\nexport class GetPdf extends CommandBase {\n  constructor() {\n    super();\n    this.data = { action: MetaboxBasicConfiguratorActions.getPdf };\n  }\n}\n","import { CommandBase } from './CommandBase';\nimport { MetaboxBasicConfiguratorActions } from '../interfaces';\n\n/**\n * Represents a command to get a Call To Action Information from Metabox Basic Configurator.\n * This class sends a message to the Metabox API to generate Call To Action information based on the current\n * configuration and sends it to the endpoint URL from the CTA information.\n *\n * `ecomConfiguratorDataUpdated` is not its reply — that fires once, as the ecom data loads — so\n * subscribe to it from the apiReady callback, not around this call. To follow the workflow itself,\n * listen to 'ctaStatusChanged': it reports `'started'`, then `'ready'` or `'failed'`.\n *\n * @remarks\n * `ctaStatusChanged` is additive and requires configurator-side support. There is no redirect url to\n * receive: MetaBox posts the configuration to the callback URL from admin and navigates to the\n * `redirectUrl` the endpoint returns, reporting an unusable reply in its own UI. On success the user\n * is navigated away, so treat `'started'` and `'failed'` as the load-bearing states.\n *\n * ### What does it unlock?\n * Runs the CTA workflow. The CTA label and callback URL reach the host on the load-time\n * `ecomConfiguratorDataUpdated` event, not from this command.\n *\n * ### Practical Application\n * Triggers the CTA (Call-to-Action) workflow configured in MetaBox admin. The CTA label and callback URL are set in admin.\n * When invoked, MetaBox POSTs the full configuration JSON (including BOM) to your callback URL endpoint, which returns a { redirectUrl }.\n *\n * ### AI Coding Best Practices\n * Call only after user completes configuration. Subscribe to ecomConfiguratorDataUpdated to get CTA label/URL for building\n * custom CTA buttons in your UI. The POST payload includes the full bill of materials — your backend endpoint processes it\n * and returns a redirect URL.\n *\n * @example\n * import { Communicator, CtaStatus, EcomConfigurator,GetCallToActionInformation } from '@3dsource/metabox-front-api';\n * window.env3DSource.apiReady = (api: Communicator) => {\n *\n *     //Subscribe as soon as the api is ready: this event fires once, when the ecom data loads\n *     api.addEventListener('ecomConfiguratorDataUpdated', (data:EcomConfigurator) => {\n *       console.log('Ecom configurator params:', data);\n *     });\n *\n *     Send the command to get Call To Action information from Metabox Basic Configurator\n *     api.sendCommandToMetabox(new GetCallToActionInformation());\n * };\n */\n\nexport class GetCallToActionInformation extends CommandBase {\n  constructor() {\n    super();\n    this.data = {\n      action: MetaboxBasicConfiguratorActions.getCallToActionInformation,\n    };\n  }\n}\n","import { CommandBase } from './CommandBase';\nimport { MetaboxBasicConfiguratorActions } from '../interfaces';\n\n/**\n * Represents a command to get the camera configuration from Unreal.\n * This class sends a message to the Metabox API to get the camera from a scene.\n * To listen for changes after sending this command, listen to the 'getCameraResult' event.\n *\n * ### What does it unlock?\n * Retrieves camera presets for the configurator; allowing extraction and application of saved camera positions.\n *\n * ### Practical Application\n * Requests current camera state — returns asynchronously via the getCameraResult event. Returns a CameraCommandPayload\n * with fov, mode, position, rotation, and restrictions. Use to save camera positions, create shareable view links,\n * or build 'save this angle' features.\n *\n * ### AI Coding Best Practices\n * ALWAYS subscribe to getCameraResult BEFORE calling GetCamera(). Pattern: `api.addEventListener('getCameraResult', handler);`\n * then `api.sendCommandToMetabox(new GetCamera())`. The returned CameraCommandPayload can be fed directly back into\n * SetCamera to restore the view.\n *\n * @example\n * import { Communicator, CameraCommandPayload,GetCamera } from '@3dsource/metabox-front-api';\n * window.env3DSource.apiReady = (api: Communicator) => {\n *\n *     //Subscribe to the event before sending the command to ensure you capture the response\n *     api.addEventListener('getCameraResult', (data:CameraCommandPayload) => {\n *       console.log('Camera params after get camera command:', data);\n *     });\n *\n *     api.sendCommandToMetabox(new GetCamera());\n * };\n */\n\nexport class GetCamera extends CommandBase {\n  constructor() {\n    super();\n    this.data = { action: MetaboxBasicConfiguratorActions.getCamera };\n  }\n}\n","import { CommandBase } from './CommandBase';\nimport type { CameraCommandPayload } from '../interfaces';\nimport { MetaboxBasicConfiguratorActions } from '../interfaces';\n\n/**\n * Represents a command to set the camera configuration.\n * This class sends a message to the Metabox API to set the camera on a scene.\n * **Important**: No need to listen to any events to see changes.\n *\n * ### What does it unlock?\n * Sets camera presets with restriction parameters (FOV, rotation, position).\n *\n * ### Practical Application\n * Sets camera with precise control: fov (degrees), mode ('orbit'|'fps'), position ({x,y,z}),\n * rotation ({horizontal,vertical}), and restrictions (min/max distance, FOV, rotation bounds).\n * Use for guided tours, preset view buttons, or restricting camera to prevent users seeing behind the product.\n *\n * ### AI Coding Best Practices\n * Only include fields you want to change — omitted values keep current settings. Use orbit mode for typical product viewing,\n * fps for walkthrough/room scenes. Apply restrictions to prevent bad angles. Full interface:\n * `{fov?, mode?, position?, rotation?, restrictions?}`.\n *\n * @example\n * import { SetCamera, Communicator } from '@3dsource/metabox-front-api';\n * window.env3DSource.apiReady = (api: Communicator) => {\n *     api.sendCommandToMetabox(new SetCamera({\n *       fov: 45,\n *       mode: 'orbit',\n *       position: { x: 100, y: 100, z: 100 },\n *       rotation: { horizontal: 0, vertical: 0 },\n *       restrictions: {\n *         maxDistanceToPivot: 0,\n *         maxFov: 0,\n *         maxHorizontalRotation: 0,\n *         maxVerticalRotation: 0,\n *         minDistanceToPivot: 0,\n *         minFov: 0,\n *         minHorizontalRotation: 0,\n *         minVerticalRotation: 0,\n *       },\n *     }));\n * };\n *\n * @param {CameraCommandPayload} camera - The camera configuration.\n */\nexport class SetCamera extends CommandBase {\n  constructor(camera: CameraCommandPayload) {\n    super();\n    this.data = {\n      action: MetaboxBasicConfiguratorActions.setCamera,\n      payload: { camera },\n    };\n  }\n}\n","import { CommandBase } from './CommandBase';\nimport { MetaboxBasicConfiguratorActions } from '../interfaces';\n\n/**\n * Represents a command to reset the camera to its initial position.\n * This class sends a message to the Metabox API to reset the camera on a scene.\n *\n * ### What does it unlock?\n * Resets the camera to its default state and position. Used to return camera to initial configuration after user manipulation.\n *\n * ### Practical Application\n * Resets camera to the default position defined in the product/environment template. Essential for 'Reset View' buttons.\n * Also, useful after programmatic camera moves to return to a known starting state.\n *\n * ### AI Coding Best Practices\n * Call `api.sendCommandToMetabox(new ResetCamera())`. No parameters. Restores template defaults — not the last user position.\n * Good practice to call after SetProduct changes that may shift the focal point.\n *\n * @example\n * import { ResetCamera, Communicator } from '@3dsource/metabox-front-api';\n * window.env3DSource.apiReady = (api: Communicator) => {\n *     api.sendCommandToMetabox(new ResetCamera());\n * };\n */\n\nexport class ResetCamera extends CommandBase {\n  constructor() {\n    super();\n    this.data = { action: MetaboxBasicConfiguratorActions.resetCamera };\n  }\n}\n","import { CommandBase } from './CommandBase';\nimport { MetaboxBasicConfiguratorActions } from '../interfaces';\n\n/**\n * Represents a command to reset the configurator state to its defaults.\n * This class sends a message to the Metabox API to restore product, materials,\n * and environment selections to the values defined by the configurator template.\n * To listen for changes after sending this command, listen to the 'configuratorDataUpdated' event.\n *\n * ### What does it unlock?\n * Resets the entire configurator state to defaults — product, product materials, environment, and\n * environment materials all return to the template-defined initial values. Used to give users a clean\n * 'Start Over' affordance without reloading the iframe.\n *\n * ### Practical Application\n * Powers 'Reset to Defaults' / 'Start Over' buttons in product configurators. Unlike ResetCamera (which\n * only touches viewport state), ResetConfiguration wipes all user-applied selections back to template\n * defaults. The configurator responds with a full ConfiguratorEnvelope via configuratorDataUpdated, so\n * UI state derived from the envelope (selected swatches, current product, environment chips) will\n * re-sync automatically.\n *\n * ### AI Coding Best Practices\n * Call `api.sendCommandToMetabox(new ResetConfiguration())`. No parameters. Subscribe to\n * configuratorDataUpdated BEFORE sending so you capture the reset envelope. If your UI maintains local\n * selection state separate from the envelope, clear it in the same handler. Pair with ResetCamera if\n * you also want the viewport returned to its default framing.\n *\n * @example\n * import { ResetConfiguration, Communicator, ConfiguratorEnvelope } from '@3dsource/metabox-front-api';\n * window.env3DSource.apiReady = (api: Communicator) => {\n *\n *     //Subscribe to the event before sending the command to ensure you capture the response\n *     api.addEventListener('configuratorDataUpdated', (data: ConfiguratorEnvelope) => {\n *       console.log('Configurator reset to default state:', data);\n *     });\n *\n *     api.sendCommandToMetabox(new ResetConfiguration());\n * };\n */\n\nexport class ResetConfiguration extends CommandBase {\n  constructor() {\n    super();\n    this.data = { action: MetaboxBasicConfiguratorActions.resetConfiguration };\n  }\n}\n","import { CommandBase } from './CommandBase';\nimport { MetaboxBasicConfiguratorActions } from '../interfaces';\n\n/**\n * Represents a command to apply zoom and change the camera zoom on a scene.\n * This class sends a command to the Metabox API to change zoom on a scene.\n *\n * ### What does it unlock?\n * Controls zoom functionality for the configurator; allowing users to adjust the zoom level of 3D objects and camera presets.\n *\n * ### Practical Application\n * Implements programmatic zoom on the pixel-streamed viewport. Use to build zoom slider controls, pinch-to-zoom on mobile,\n * or 'zoom to detail' buttons. Takes a numeric delta: positive zooms in, negative zooms out\n * (e.g., ApplyZoom(50) zooms in, ApplyZoom(-50) zooms out).\n *\n * ### AI Coding Best Practices\n * Always use numeric delta values, not absolute zoom levels. Pair with a UI slider that sends incremental values.\n * Debounce zoom input to ~100ms intervals to prevent overwhelming the Unreal stream.\n * Pattern: `api.sendCommandToMetabox(new ApplyZoom(50))`.\n *\n * @example\n * import { ApplyZoom, Communicator } from '@3dsource/metabox-front-api';\n * window.env3DSource.apiReady = (api: Communicator) => {\n *     api.sendCommandToMetabox(new ApplyZoom(50));\n * };\n *\n * @param {number} zoom - The zoom value to apply.\n */\n\nexport class ApplyZoom extends CommandBase {\n  constructor(zoom: number) {\n    super();\n    this.data = {\n      action: MetaboxBasicConfiguratorActions.applyZoom,\n      payload: { zoom },\n    };\n  }\n}\n","import { CommandBase } from './CommandBase';\nimport { MetaboxBasicConfiguratorActions } from '../interfaces';\n\n/**\n * @remarks\n * Represents a command to initialize Showcase for a product scene and start a sequence for the product.\n * This class sends a command to the Metabox API to initialize showcase if the product has a sequence.\n * To check this, find the showcase property in the current product and listen to the 'configuratorDataUpdated' event.\n * If this property exists, you can send the init showcase command.\n *\n * To listen for changes after sending this command, listen to the 'showcaseStatusChanged' event.\n *\n * ### What does it unlock?\n * Initializes and displays the showcase/demo view for the configurator. Used when transitioning into presentation or demo mode.\n *\n * ### Practical Application\n * Loads the showcase/animation sequence attached to the current product. Must be called BEFORE PlayShowcase.\n * Use to initialize auto-playing product demos, trade show presentations, or hero section animations on landing pages.\n *\n * ### AI Coding Best Practices\n * ALWAYS call InitShowcase() before PlayShowcase(). Required sequence: InitShowcase → PlayShowcase → PauseShowcase/StopShowcase.\n * Subscribe to showcaseStatusChanged to track playback state ('playing'/'paused'/'stopped').\n *\n * @example\n * import { Communicator,ShowCaseStatus,InitShowcase } from '@3dsource/metabox-front-api';\n * window.env3DSource.apiReady = (api: Communicator) => {\n *     //Subscribe to the event before sending the command to ensure you capture the response\n *     api.addEventListener('showcaseStatusChanged', (data:ShowCaseStatus) => {\n *       console.log('Showcase status value after changed:', data);\n *     });\n *\n *     api.sendCommandToMetabox(new InitShowcase());\n * };\n */\n\nexport class InitShowcase extends CommandBase {\n  constructor() {\n    super();\n    this.data = {\n      action: MetaboxBasicConfiguratorActions.initShowcase,\n    };\n  }\n}\n","import { CommandBase } from './CommandBase';\nimport { MetaboxBasicConfiguratorActions } from '../interfaces';\n\n/**\n * Represents a command to play Showcase for a product when it is already initialized and paused.\n * This class sends a command to the Metabox API to play showcase for a product if it is already initialized and paused.\n *\n * To listen for changes after sending this command, listen to the 'showcaseStatusChanged' event.\n *\n * ### What does it unlock?\n * Starts or resumes the showcase/timeline playback. Executes the internal MetaBox play command internally.\n *\n * ### Practical Application\n * Starts or resumes showcase playback. Use for 'Play Demo' buttons on landing pages, auto-play on page load,\n * or resuming demos after inactivity timeout on kiosk displays.\n *\n * ### AI Coding Best Practices\n * Call `api.sendCommandToMetabox(new PlayShowcase())`. Must call InitShowcase() first or it won't play.\n * Subscribe to showcaseStatusChanged to track state. Auto-play pattern: wait for viewportReady → InitShowcase →\n * PlayShowcase.\n *\n * @example\n * import { Communicator,PlayShowcase } from '@3dsource/metabox-front-api';\n * window.env3DSource.apiReady = (api: Communicator) => {\n *     //Subscribe to the event before sending the command to ensure you capture the response\n *     api.addEventListener('showcaseStatusChanged', (data) => {\n *        console.log('Showcase status value after changed:', data);\n *     });\n *\n *     api.sendCommandToMetabox(new PlayShowcase());\n * };\n */\nexport class PlayShowcase extends CommandBase {\n  constructor() {\n    super();\n    this.data = { action: MetaboxBasicConfiguratorActions.playShowcase };\n  }\n}\n","import { CommandBase } from './CommandBase';\nimport { MetaboxBasicConfiguratorActions } from '../interfaces';\n\n/**\n * @internal\n * @hidden\n * Represents a command to send Unreal command.\n *\n * @param {Object} payload - An raw command that will be sent into MetaBox Unreal Application.\n */\n\nexport class UnrealCommand extends CommandBase {\n  constructor(payload: object) {\n    super();\n    this.data = {\n      action: MetaboxBasicConfiguratorActions.sendCommandToUnreal,\n      payload,\n    };\n  }\n}\n","import { CommandBase } from './CommandBase';\nimport { MetaboxBasicConfiguratorActions } from '../interfaces';\n\n/**\n * Represents a command to pause Showcase for a product when it is already initialized and playing.\n * This class sends a command to the Metabox API to pause showcase for a product if it is already initialized and playing.\n *\n * To listen for changes after sending this command, listen to the 'showcaseStatusChanged' event.\n *\n * ### What does it unlock?\n * Pauses the showcase/timeline playback. Can be called independently without requiring any flag parameters.\n *\n * ### Practical Application\n * Pauses showcase animation playback. The showcase remains initialized and can be resumed with\n * PlayShowcase. Use when you need to temporarily freeze the animation (e.g., on a \"Pause\" button click).\n *\n * ### AI Coding Best Practices\n * Call `api.sendCommandToMetabox(new PauseShowcase())`. No parameters. Subscribe to showcaseStatusChanged\n * to confirm 'pause' state. Use PlayShowcase to resume or StopShowcase to reset.\n *\n * @example\n * import { Communicator,ShowCaseStatus,PauseShowcase } from '@3dsource/metabox-front-api';\n * window.env3DSource.apiReady = (api: Communicator) => {\n *\n *     //Subscribe to the event before sending the command to ensure you capture the response\n *     api.addEventListener('showcaseStatusChanged', (data:ShowCaseStatus) => {\n *       console.log('Showcase status value after changed:', data);\n *     });\n *\n *      api.sendCommandToMetabox(new PauseShowcase());\n * };\n */\nexport class PauseShowcase extends CommandBase {\n  constructor() {\n    super();\n    this.data = { action: MetaboxBasicConfiguratorActions.pauseShowcase };\n  }\n}\n","import { CommandBase } from './CommandBase';\nimport { MetaboxBasicConfiguratorActions } from '../interfaces';\n\n/**\n * Represents a command to stop Showcase for a product when it is already initialized, and you want to destroy it.\n * This class sends a command to the Metabox API to stop showcase for a product if it is already initialized.\n *\n * To listen for changes after sending this command, listen to the 'showcaseStatusChanged' event.\n *\n * ### What does it unlock?\n * Stops the showcase/timeline playback and closes the showcase mode. Returns to normal configurator view.\n *\n * ### Practical Application\n * Stops showcase playback and exits showcase mode entirely. Returns to normal interactive configurator view.\n * Use for 'Exit Demo' buttons or auto-trigger when the user starts actively configuring the product.\n *\n * ### AI Coding Best Practices\n * Call `api.sendCommandToMetabox(new StopShowcase())`. Fully resets the showcase state. Subscribe to\n * showcaseStatusChanged to confirm 'stopped' status. After stopping, the configurator returns to full\n * interactive mode — re-enable configuration controls.\n *\n * @example\n * import { Communicator,ShowCaseStatus } from '@3dsource/metabox-front-api';\n * window.env3DSource.apiReady = (api: Communicator) => {\n *\n *     //Subscribe to the event before sending the command to ensure you capture the response\n *     api.addEventListener('showcaseStatusChanged', (data:ShowCaseStatus) => {\n *       console.log('Showcase status value after changed:', data);\n *     });\n *\n *      api.sendCommandToMetabox(new StopShowcase());\n * };\n */\n\nexport class StopShowcase extends CommandBase {\n  constructor() {\n    super();\n    this.data = { action: MetaboxBasicConfiguratorActions.stopShowcase };\n  }\n}\n","import { CommandBase } from './CommandBase';\nimport { MetaboxBasicConfiguratorActions } from '../interfaces';\n\n/**\n * Image format.\n * This type represents the allowed image formats.\n *\n * ### What does it unlock?\n * Type alias for MIME types used in file/media handling. Defines supported file formats and media types.\n *\n * ### Practical Application\n * Type alias: 'image/png' | 'image/jpeg' | 'image/webp'. Used as the format parameter in GetScreenshot.\n * PNG for quality/transparency, JPEG for smaller files, WebP for modern browser optimization.\n *\n * ### AI Coding Best Practices\n * Pass as first param to GetScreenshot: `new GetScreenshot('image/png', {x:2048, y:2048})`.\n * Use PNG for highest quality and transparency. JPEG for smaller file size. WebP for modern browser optimization.\n * Match the saveImage filename extension to the format.\n */\nexport type MimeType = 'image/png' | 'image/jpeg' | 'image/webp';\n\n/**\n * Represents a command to get a screenshot.\n *\n * To listen for changes after sending this command, listen to the 'screenshotReady' event before command is sent.\n *\n * ### What does it unlock?\n * Takes a screenshot on the server side (Unreal Engine) of the 3D scene. Returns high-quality image.\n * Requires subscription to the screenshotReady event to receive the rendered image.\n *\n * ### Practical Application\n * Renders a high-res screenshot on the Unreal Engine server. Takes format ('image/png'|'image/jpeg'|'image/webp')\n * and optional size ({x, y}). Returns base64 data via screenshotReady event. Use for thumbnails, social sharing,\n * saving config snapshots, or attaching images to quotes.\n *\n * ### AI Coding Best Practices\n * Subscribe to screenshotReady BEFORE sending GetScreenshot. Pattern:\n * `api.addEventListener('screenshotReady', (data) => { if(data) saveImage(data, 'name.png'); })`.\n * Specify size for consistent outputs: `new GetScreenshot('image/png', {x:2048, y:2048})`.\n * Use saveImage() helper to convert base64 to downloadable file.\n *\n * @example\n * import { Communicator,saveImage,GetScreenshot } from '@3dsource/metabox-front-api';\n * window.env3DSource.apiReady = (api: Communicator) => {\n *\n *     //Subscribe to the event before sending the command to ensure you capture the response\n *     api.addEventListener('screenshotReady', (data:string) => {\n *       // The data is a base64 string of the image. You can use it to display the image or save it as a file.\n *       console.log('Get screenshot here:', data);\n *       saveImage(data, 'Render.png');\n *     });\n *\n *     api.sendCommandToMetabox(new GetScreenshot('image/png', { x: 1024, y: 1024 }));\n * };\n *\n * @param {MimeType} mimeType - The output format.\n * @param {{ x: number; y: number }} [size] - Optional size in pixels.\n */\nexport class GetScreenshot extends CommandBase {\n  constructor(mimeType: MimeType, size?: { x: number; y: number }) {\n    super();\n    this.data = {\n      action: MetaboxBasicConfiguratorActions.getScreenshot,\n      payload: { format: mimeType, size },\n    };\n  }\n}\n","import { CommandBase } from './CommandBase';\nimport { MetaboxBasicConfiguratorActions } from '../interfaces';\n\n/**\n * Represents a command to set a product by its ID.\n * This action sends a message to the Metabox API to set a product using the provided product ID.\n * To listen for changes after sending this command, listen to the 'configuratorDataUpdated' event.\n *\n * ### What does it unlock?\n * Sets the active product in the Basic Configurator by its UUID. Triggers a full state update including\n * available materials, slots, showcase data, and environment compatibility.\n *\n * ### Practical Application\n * Selects which product to display in the 3D viewport. Takes a productId (UUID). Use to build product picker UIs,\n * deep-link to specific products, or switch products programmatically based on external catalog selections.\n * The configurator responds with a full ConfiguratorEnvelope via configuratorDataUpdated.\n *\n * ### AI Coding Best Practices\n * Call `api.sendCommandToMetabox(new SetProduct('product-uuid'))`. Get valid product IDs from\n * `configurator.products` in the configuratorDataUpdated envelope. Subscribe to configuratorDataUpdated\n * BEFORE sending the command. After switching products, material and environment selections may reset —\n * re-apply them if needed.\n *\n * @example\n * import { Communicator,ConfiguratorEnvelope } from '@3dsource/metabox-front-api';\n * window.env3DSource.apiReady = (api: Communicator) => {\n *\n *     //Subscribe to the event before sending the command to ensure you capture the response\n *     api.addEventListener('configuratorDataUpdated', (data:ConfiguratorEnvelope) => {\n *       console.log('State updated after applied new product:', data);\n *     });\n *\n *     api.sendCommandToMetabox(new SetProduct(\n *     'ffea6b5c-3a8a-4f56-9417-e605acb5cca3'\n *   ));\n * };\n *\n * @param {string} productId - The product ID.\n */\n\nexport class SetProduct extends CommandBase {\n  constructor(productId: string) {\n    super();\n    this.data = {\n      action: MetaboxBasicConfiguratorActions.setProduct,\n      payload: { productId },\n    };\n  }\n}\n","import { CommandBase } from './CommandBase';\nimport { MetaboxBasicConfiguratorActions } from '../interfaces';\n\n/**\n * Represents a command to set a material by its slot ID and Material ID.\n * To listen for changes after sending this command, listen to the 'configuratorDataUpdated' event.\n *\n * ### What does it unlock?\n * Sets a material variant for a product slot. Simulates selecting a different material/finish from the menu\n * for a specific customizable surface on the product.\n *\n * ### Practical Application\n * Applies a material to a specific slot on the active product. Takes slotId (string) and materialId (UUID).\n * Use to build swatch pickers, apply preset themes/bundles, or sync material selections from an external\n * PIM/ERP system via externalId mapping.\n *\n * ### AI Coding Best Practices\n * Get valid slotId and materialId values from the product's slot definitions in the configuratorDataUpdated envelope —\n * check `product.slots` and each slot's `enabledMaterials` list. Pattern:\n * `new SetProductMaterial('slot-name', 'material-uuid')`. The referenced product must already be set.\n *\n * @example\n * import { Communicator,ConfiguratorEnvelope,SetProductMaterial } from '@3dsource/metabox-front-api';\n * window.env3DSource.apiReady = (api: Communicator) => {\n *\n *    //Subscribe to the event before sending the command to ensure you capture the response\n *     api.addEventListener('configuratorDataUpdated', (data:ConfiguratorEnvelope) => {\n *       console.log('State updated after applied new material:', data);\n *     });\n *\n *     api.sendCommandToMetabox(new SetProductMaterial(\n *     'carpaint',\n *     'dd829d6e-9200-47a7-8d5b-af5df89b7e91',\n *   ));\n * };\n *\n * @param {string} slotId - The slot ID.\n * @param {string} materialId - The material ID.\n */\n\nexport class SetProductMaterial extends CommandBase {\n  constructor(slotId: string, materialId: string) {\n    super();\n    this.data = {\n      action: MetaboxBasicConfiguratorActions.setProductMaterialById,\n      payload: { slotId, materialId },\n    };\n  }\n}\n","import { CommandBase } from './CommandBase';\nimport { MetaboxBasicConfiguratorActions } from '../interfaces';\n\n/**\n * Represents a command to set the environment by its ID.\n * To listen for changes after sending this command, listen to the 'configuratorDataUpdated' event.\n *\n * ### What does it unlock?\n * Sets environmental/lighting settings for the scene. Controls factors like lighting conditions and environmental appearance.\n *\n * ### Practical Application\n * Changes the 3D scene/environment (studio, showroom, outdoor, etc.). Takes an environmentId UUID.\n * Environments include lighting, backdrop, and optionally dynamic sky (udsEnabled) with time-of-day (udsHour) control.\n *\n * ### AI Coding Best Practices\n * Call `api.sendCommandToMetabox(new SetEnvironment('env-uuid'))`. Get valid environment IDs from the configurator\n * definition in configuratorDataUpdated. Set environment after product during initialization. Each environment has\n * its own material slots, thumbnails, and lighting properties.\n *\n * @example\n * import { Communicator,ConfiguratorEnvelope } from '@3dsource/metabox-front-api';\n * window.env3DSource.apiReady = (api: Communicator) => {\n *\n *     //Subscribe to the event before sending the command to ensure you capture the response\n *     api.addEventListener('configuratorDataUpdated', (data:ConfiguratorEnvelope) => {\n *       console.log('State updated after applied new environment:', data);\n *     });\n *\n *     api.sendCommandToMetabox(new SetEnvironment('55555555-1234-1234-1234-01234567890'))\n * };\n *\n * @param {string} environmentId - The environment ID.\n */\nexport class SetEnvironment extends CommandBase {\n  constructor(environmentId: string) {\n    super();\n    this.data = {\n      action: MetaboxBasicConfiguratorActions.setEnvironment,\n      payload: { id: environmentId },\n    };\n  }\n}\n","import { CommandBase } from './CommandBase';\nimport { MetaboxBasicConfiguratorActions } from '../interfaces';\n\n/**\n * Represents a command to set an environment material by its slot ID and Material ID.\n * To listen for changes after sending this command, listen to the 'configuratorDataUpdated' event.\n *\n * ### What does it unlock?\n * Sets environmental material properties such as textures and appearance attributes for the scene environment.\n *\n * ### Practical Application\n * Applies materials to environment slots (floor, walls, backdrop textures). Takes slotId and materialId.\n * Use for scene-based configurators where the environment is also customizable — kitchen visualizers,\n * room planners, trade show booth designers.\n *\n * ### AI Coding Best Practices\n * Pattern: `new SetEnvironmentMaterial('floor-slot-id', 'material-uuid')`. Get valid slot and material IDs from\n * the environment definition's slots array in configuratorDataUpdated. Only useful when the active environment\n * has configurable material slots.\n *\n * @example\n * import { Communicator,ConfiguratorEnvelope } from '@3dsource/metabox-front-api';\n * window.env3DSource.apiReady = (api: Communicator) => {\n *\n *     //Subscribe to the event before sending the command to ensure you capture the response\n *     api.addEventListener('configuratorDataUpdated', (data:ConfiguratorEnvelope) => {\n *       console.log('State updated after applied new environment material:', data);\n *     });\n *\n *     api.sendCommandToMetabox(new SetEnvironmentMaterial(\n *     'carpaint',\n *     'dd829d6e-9200-47a7-8d5b-af5df89b7e91',\n *    ));\n * };\n *\n * @param {string} slotId - The slot ID.\n * @param {string} materialId - The material ID.\n */\n\nexport class SetEnvironmentMaterial extends CommandBase {\n  constructor(slotId: string, materialId: string) {\n    super();\n    this.data = {\n      action: MetaboxBasicConfiguratorActions.setEnvironmentMaterialById,\n      payload: { slotId, materialId },\n    };\n  }\n}\n","import { CommandBase } from './CommandBase';\nimport type { SetEnvironmentMaterial } from './SetEnvironmentMaterial';\nimport type { SetProductMaterial } from './SetProductMaterial';\nimport type { MaterialCommandEnvelope } from '../interfaces';\nimport { MetaboxBasicConfiguratorActions } from '../interfaces';\n\n/**\n * A single material command accepted inside a {@link SetMaterials} batch.\n *\n * ### What does it unlock?\n * Union of the material commands the Basic Configurator can apply — {@link SetProductMaterial} and\n * {@link SetEnvironmentMaterial}. Use it to type an array you build up before sending it as one batch.\n *\n * ### Practical Application\n * Type the array you accumulate while resolving a preset, a saved configuration or a PIM payload,\n * then hand the whole array to `SetMaterials` in one call.\n *\n * ### AI Coding Best Practices\n * `const materials: MaterialCommand[] = []` then `materials.push(new SetProductMaterial(...))`.\n * Components belong to the Modular Configurator, not to this package.\n */\nexport type MaterialCommand = SetProductMaterial | SetEnvironmentMaterial;\n\n/**\n * Represents a command to apply several materials at once.\n * To listen for changes after sending this command, listen to the 'configuratorDataUpdated' event.\n *\n * ### What does it unlock?\n * Applies a whole material set in a single message instead of one command per slot. Simulates picking\n * every swatch of a preset at once, so the scene updates in one pass rather than slot by slot.\n *\n * ### Practical Application\n * Takes an array of {@link SetProductMaterial} and {@link SetEnvironmentMaterial} instances and sends\n * them as one batch, preserving order. Use it to apply presets or themed bundles, to restore a saved\n * configuration, or to sync a full material set from an external PIM/ERP system — instead of firing\n * (and debouncing) N separate commands.\n *\n * ### AI Coding Best Practices\n * Build the entries from the configuratorDataUpdated envelope — `product.slots` and `environment.slots`,\n * each slot's `enabledMaterials`. Pattern: `new SetMaterials([new SetProductMaterial('body', 'uuid'),\n * new SetEnvironmentMaterial('floor', 'uuid')])`. Nothing is validated client-side: entries are sent\n * exactly as given, in order, and the referenced product must already be set. Keep using\n * `SetProductMaterial` on its own for a single swatch click.\n *\n * @example\n * import { Communicator,ConfiguratorEnvelope,SetEnvironmentMaterial,SetMaterials,SetProductMaterial } from '@3dsource/metabox-front-api';\n * window.env3DSource.apiReady = (api: Communicator) => {\n *\n *    //Subscribe to the event before sending the command to ensure you capture the response\n *     api.addEventListener('configuratorDataUpdated', (data:ConfiguratorEnvelope) => {\n *       console.log('State updated after applied new materials:', data);\n *     });\n *\n *     api.sendCommandToMetabox(new SetMaterials([\n *     new SetProductMaterial('carpaint', 'dd829d6e-9200-47a7-8d5b-af5df89b7e91'),\n *     new SetEnvironmentMaterial('floor', '7c1f4b2a-58e3-4a19-9d6c-2b0f83e5a114'),\n *   ]));\n * };\n *\n * @param {MaterialCommand[]} commands - The material commands to apply, in order.\n */\n\nexport class SetMaterials extends CommandBase {\n  constructor(commands: MaterialCommand[]) {\n    super();\n    this.data = {\n      action: MetaboxBasicConfiguratorActions.setMaterials,\n      payload: {\n        // Entries are copied so the batch never aliases the source command's own `data`.\n        // The narrowing is guaranteed by the command classes the constructor accepts.\n        materials: commands.map(({ data }) => {\n          const envelope = data as MaterialCommandEnvelope;\n\n          return { ...envelope, payload: { ...envelope.payload } };\n        }),\n      },\n    };\n  }\n}\n","import { CommandBase } from './CommandBase';\nimport { MetaboxBasicConfiguratorActions } from '../interfaces';\n\n/**\n * Represents a command to toggle the embedded Metabox menu.\n * This command can only be used when using the metabox menu.\n *\n * ### What does it unlock?\n * Shows the embedded menu interface. Only works when using the MetaBox native menu (not in standalone/custom menu\n * mode).\n *\n * ### Practical Application\n * Toggles the native MetaBox right sidebar menu. Takes a boolean parameter. Pass false to hide when building custom UI.\n * In standalone mode, the menu is already hidden — this is only relevant in default (non-standalone) mode.\n *\n * ### AI Coding Best Practices\n * In standalone mode (`{standalone:true}`), this is unnecessary (menu already hidden). In default mode,\n * call `new ShowEmbeddedMenu(false)` early in initialization to hide built-in UI before rendering custom controls.\n * Pattern for custom UI: `ShowEmbeddedMenu(false)` + `ShowOverlayInterface(false)`.\n *\n * @example\n * import { ShowEmbeddedMenu, Communicator } from '@3dsource/metabox-front-api';\n * window.env3DSource.apiReady = (api: Communicator) => {\n *   api.sendCommandToMetabox(new ShowEmbeddedMenu(true));\n * };\n *\n * @param {boolean} visible - A flag indicating whether the embedded menu should be visible.\n */\n\nexport class ShowEmbeddedMenu extends CommandBase {\n  constructor(visible: boolean) {\n    super();\n    this.data = {\n      action: MetaboxBasicConfiguratorActions.showEmbeddedMenu,\n      payload: { visible },\n    };\n  }\n}\n","import { CommandBase } from './CommandBase';\nimport { MetaboxBasicConfiguratorActions } from '../interfaces';\n\n/**\n * Represents a command to toggle the Unreal Overlay Interface Menu.\n * This action sends a message to the Metabox API to toggle the visibility of the Unreal overlay UI.\n *\n * ### What does it unlock?\n * Shows the overlay interface elements. Displays UI controls and buttons overlaid on the 3D scene.\n *\n * ### Practical Application\n * Toggles viewport overlay controls (buttons overlaid on the 3D scene). Takes a boolean.\n * Use `ShowOverlayInterface(false)` alongside `ShowEmbeddedMenu(false)` when building fully custom UI\n * that replaces all native MetaBox controls.\n *\n * ### AI Coding Best Practices\n * In standalone mode, overlays are already hidden. In default mode, call `new ShowOverlayInterface(false)`\n * early in initialization to prevent flash of native UI. Always pair with `ShowEmbeddedMenu(false)` for clean custom UI.\n * Pass true to restore if entering a mode that uses native controls.\n *\n * @example\n * import { ShowOverlayInterface, Communicator } from '@3dsource/metabox-front-api';\n * window.env3DSource.apiReady = (api: Communicator) => {\n *   api.sendCommandToMetabox(new ShowOverlayInterface(true));\n * };\n *\n * @param {boolean} visible - A flag indicating whether the Unreal overlay UI should be visible.\n */\n\nexport class ShowOverlayInterface extends CommandBase {\n  constructor(visible: boolean) {\n    super();\n    this.data = {\n      action: MetaboxBasicConfiguratorActions.showOverlayInterface,\n      payload: { visible },\n    };\n  }\n}\n","import { CommandBase } from './CommandBase';\nimport { MetaboxBasicConfiguratorActions } from '../interfaces';\n\n/**\n * Represents a command to show measurement for a product when it is already loaded.\n * This class sends a command to the Metabox API to show measurement for a product if it is already initialized.\n *\n * ### What does it unlock?\n * Shows the measurement overlay. Works as a toggle with HideMeasurement to control visibility.\n *\n * ### Practical Application\n * Shows the measurement/dimension overlay tools on the 3D viewport. Use for B2B or technical applications\n * where buyers need to verify product dimensions, check fit specifications, or confirm measurements during procurement.\n *\n * ### AI Coding Best Practices\n * Call `api.sendCommandToMetabox(new ShowMeasurement())`. No parameters. Pair with HideMeasurement for toggle behavior.\n * Track visibility state in your app to keep toggle buttons in sync.\n *\n * @example\n * import { ShowMeasurement, Communicator } from '@3dsource/metabox-front-api';\n * window.env3DSource.apiReady = (api: Communicator) => {\n *     api.sendCommandToMetabox(new ShowMeasurement());\n * };\n */\n\nexport class ShowMeasurement extends CommandBase {\n  constructor() {\n    super();\n    this.data = { action: MetaboxBasicConfiguratorActions.showMeasurement };\n  }\n}\n","import { CommandBase } from './CommandBase';\nimport { MetaboxBasicConfiguratorActions } from '../interfaces';\n\n/**\n * Represents a command to hide measurement for a product when it is already loaded.\n * This class sends a command to the Metabox API to hide measurement for a product if it is already initialized.\n *\n * ### What does it unlock?\n * Hides the measurement overlay. Executes unconditionally to hide the UI controls.\n *\n * ### Practical Application\n * Hides the measurement/dimension overlay. Use when transitioning from a technical spec view back to a clean\n * product presentation, or to keep consumer-facing configurators visually clean.\n *\n * ### AI Coding Best Practices\n * Call `api.sendCommandToMetabox(new HideMeasurement())`. No parameters. Pair with ShowMeasurement as a toggle.\n * Track visibility state in your app state to keep toggle buttons in sync.\n *\n * @example\n * import { HideMeasurement, Communicator } from '@3dsource/metabox-front-api';\n * window.env3DSource.apiReady = (api: Communicator) => {\n *     api.sendCommandToMetabox(new HideMeasurement());\n * };\n */\n\nexport class HideMeasurement extends CommandBase {\n  constructor() {\n    super();\n    this.data = { action: MetaboxBasicConfiguratorActions.hideMeasurement };\n  }\n}\n","import { CommandBase } from './CommandBase';\nimport { MetaboxBasicConfiguratorActions } from '../interfaces';\n\n/**\n * Represents a command to resume the pixel streaming session.\n * This class sends a message to the Metabox API to resume a paused or disconnected stream.\n *\n * ### What does it unlock?\n * Resumes the Unreal Engine pixel streaming connection after it has been paused, disconnected, or stopped due to inactivity (AFK timeout).\n *\n * ### Practical Application\n * Used to reconnect the 3D streaming session without a full page reload. Essential for 'Reconnect' or 'Resume' buttons\n * shown when the stream is interrupted, e.g., after an idle timeout or network disruption.\n *\n * ### AI Coding Best Practices\n * Call `api.sendCommandToMetabox(new ResumeStream())`. No parameters. Resumes the existing streaming session —\n * does not reinitialize the configurator or reset product/environment state.\n *\n * @example\n * import { ResumeStream, Communicator } from '@3dsource/metabox-front-api';\n * window.env3DSource.apiReady = (api: Communicator) => {\n *     api.sendCommandToMetabox(new ResumeStream());\n * };\n */\n\nexport class ResumeStream extends CommandBase {\n  constructor() {\n    super();\n    this.data = { action: MetaboxBasicConfiguratorActions.resumeStream };\n  }\n}\n","import { CommandBase } from './CommandBase';\nimport { MetaboxBasicConfiguratorActions } from '../interfaces';\n\n/**\n * Represents a command to stop the pixel streaming session.\n * This class sends a message to the Metabox API to stop the active stream and release its resources.\n *\n * ### What does it unlock?\n * Stops the Unreal Engine pixel streaming connection, terminating the active session and freeing server-side resources.\n *\n * ### Practical Application\n * Used to explicitly end the 3D streaming session — e.g., when the user closes a modal, navigates away, or a\n * custom \"Stop\"/\"Disconnect\" button is pressed. Pair with {@link ResumeStream} to restart the session later\n * without a full page reload.\n *\n * ### AI Coding Best Practices\n * Call `api.sendCommandToMetabox(new StopStream())`. No parameters. Stops the existing streaming session —\n * does not reset product/environment state. Use `ResumeStream` to reconnect afterwards.\n *\n * @example\n * import { StopStream, Communicator } from '@3dsource/metabox-front-api';\n * window.env3DSource.apiReady = (api: Communicator) => {\n *     api.sendCommandToMetabox(new StopStream());\n * };\n */\n\nexport class StopStream extends CommandBase {\n  constructor() {\n    super();\n    this.data = { action: MetaboxBasicConfiguratorActions.stopStream };\n  }\n}\n","import { CommandBase } from './CommandBase';\nimport { MetaboxBasicConfiguratorActions } from '../interfaces';\n\n/**\n * Represents a command to reset the user inactivity (AFK) timer.\n * This class sends a message to the Metabox API to restart the inactivity countdown,\n * keeping the session alive when activity is detected programmatically.\n *\n * ### What does it unlock?\n * Resets the AFK inactivity timer, preventing an imminent disconnect when the countdown is active.\n *\n * ### Practical Application\n * Used to programmatically signal user activity and reset the inactivity countdown.\n * Pair with the `userInactivityDetected` event to show a custom \"Stay connected?\" prompt\n * and call this command when the user confirms, dismissing the countdown.\n *\n * ### AI Coding Best Practices\n * Call `api.sendCommandToMetabox(new ResetUserInactivityTimer())`. No parameters.\n * Typically triggered from a \"Stay connected\" or \"I'm still here\" button rendered when\n * `userInactivityDetected.countdownVisible` is `true`.\n *\n * @example\n * import { ResetUserInactivityTimer, Communicator } from '@3dsource/metabox-front-api';\n * window.env3DSource.apiReady = (api: Communicator) => {\n *     api.addEventListener('userInactivityDetected', ({ countdownVisible }) => {\n *         if (countdownVisible) {\n *             // show custom UI, then on user confirmation:\n *             api.sendCommandToMetabox(new ResetUserInactivityTimer());\n *         }\n *     });\n * };\n */\n\nexport class ResetUserInactivityTimer extends CommandBase {\n  constructor() {\n    super();\n    this.data = {\n      action: MetaboxBasicConfiguratorActions.resetUserInactivityTimer,\n    };\n  }\n}\n","/**\n * Represents a callback listener for specific message types.\n * Used internally by EventDispatcher to store event listeners.\n *\n * ### What does it unlock?\n * Event listener interface. Allows subscription to specific events from the configurator to receive real-time data updates.\n *\n * ### Practical Application\n * Event listener interface. addEventListener() and removeEventListener() on Communicator. Subscribe to real-time\n * configurator events: state changes, viewport readiness, screenshots, showcase status, camera results, resolution changes.\n *\n * ### AI Coding Best Practices\n * Set up listeners BEFORE sending commands that trigger them. Always clean up with removeEventListener on component unmount.\n * Key events: configuratorDataUpdated (every state change), viewportReady (init complete), screenshotReady (captures),\n * getCameraResult (camera queries), showcaseStatusChanged (demo playback).\n *\n * @public\n */\nexport interface Listener {\n  /** The message type this listener is registered for */\n  messageType: string;\n  /** The callback function to execute when a message of the specified type is received */\n  callback: (data: unknown) => void;\n}\n\n/**\n * EventDispatcher is a class that manages event listeners and dispatches events to them.\n *\n * ### What does it unlock?\n * Parent class of Communicator that dispatches commands. Acts as an event dispatcher that routes command messages internally.\n *\n * ### Practical Application\n * Internal event routing layer — parent class of Communicator. Routes postMessage commands between your app\n * and the Unreal Engine pixel stream. Not used directly but understanding it helps debug message delivery issues.\n *\n * ### AI Coding Best Practices\n * Do not reference or extend EventDispatcher in application code. Use only the Communicator interface methods.\n * If debugging communication failures, check browser console for postMessage errors related to this layer.\n */\nexport class EventDispatcher {\n  /**\n   * Storage for callback listeners by message type.\n   */\n  listeners: Listener[] = [];\n\n  /**\n   * Removes all registered listeners. Subclasses override this to perform additional cleanup.\n   * @param key - Instance key (used by subclass overrides for registry cleanup).\n   */\n  // eslint-disable-next-line @typescript-eslint/no-unused-vars\n  destroy(key: string) {\n    this.listeners = [];\n  }\n\n  /**\n   * Adds an event listener for receiving specific types of messages.\n   *\n   * @param {string} messageType - The message type to listen for.\n   * @param callback - The callback function to execute when a message is received.\n   */\n  addEventListener(\n    messageType: string,\n    callback: (data: unknown) => void,\n  ): this {\n    this.listeners.push({ messageType, callback });\n    return this;\n  }\n\n  /**\n   * Dispatches an event to all listeners of a specific message type.\n   *\n   * @param {string} messageType - The message type.\n   * @param data - The data associated with the event.\n   */\n  dispatchEvent(messageType: string, data: unknown): this {\n    // Allocation-free dispatch on the hot message path. The length snapshot\n    // keeps the previous filter-snapshot semantics: listeners added during\n    // dispatch are not invoked for this event, and removeEventListener\n    // reassigns the array so the in-flight loop is unaffected.\n    const listeners = this.listeners;\n    const len = listeners.length;\n    for (let i = 0; i < len; i++) {\n      const listener = listeners[i];\n      if (listener.messageType === messageType) {\n        listener.callback(data);\n      }\n    }\n    return this;\n  }\n\n  /**\n   * Removes an event listener for a specific type of message.\n   *\n   * @param {string} messageType - The message type.\n   * @param callback - The callback function to remove.\n   */\n  removeEventListener(\n    messageType: string,\n    callback: (data: unknown) => void,\n  ): this {\n    this.listeners = this.listeners.filter(\n      (listener) =>\n        !(\n          listener.messageType === messageType && listener.callback === callback\n        ),\n    );\n    return this;\n  }\n}\n","/**\n * @internal\n * @hidden\n * Core constants used for host-to-iframe communication and URL construction.\n */\n\n/**\n * Storage key for the Metabox Communicator instance registry.\n *\n * ### What does it unlock?\n * Constant string identifier for MetaBox version. Used internally to reference the MetaBox system and versioning.\n *\n * ### Practical Application\n * Internal system reference for versioning.\n * Not needed in front-end application code.\n *\n * ### AI Coding Best Practices\n * Skip in application code. This constant is for internal MetaBox system identification only.\n *\n * @internal\n */\nexport const Metabox = 'metabox';\n\n/**\n * Identifier used as the `host` field in postMessage envelopes sent to the iframe.\n *\n * ### What does it unlock?\n * Constant for the MetaBox host connection point. Specifies endpoint for MetaBox connections.\n *\n * ### Practical Application\n * MetaBox endpoint constant. The host the configurator iframe connects to for Unreal Engine pixel streaming.\n * Not needed in front-end application code.\n *\n * ### AI Coding Best Practices\n * Skip in application code. This constant is for internal MetaBox system identification only.\n *\n * @internal\n */\nexport const MetaboxHost = 'metaboxHost';\n\n/**\n * Action string dispatched by the iframe when the configurator app has loaded.\n *\n * ### What does it unlock?\n * Indicates when the application has completed initialization.\n *\n * ### Practical Application\n * App initialization flag variable. Signals when MetaBox has completed loading. Use the viewportReady event\n * (more reliable) to gate your UI rendering — don't show controls until MetaBox confirms it's ready.\n *\n * ### AI Coding Best Practices\n * Prefer the viewportReady event over this variable:\n * `api.addEventListener('viewportReady', (ready) => { if(ready) enableUI(); })`.\n * viewportReady with true value is the reliable signal that MetaBox PixelStreaming is become visible.\n *\n * @internal\n */\nexport const AppLoaded = 'appLoaded';\n\n/**\n * Default production domain for the Metabox Basic Configurator.\n *\n * ### What does it unlock?\n * Constant for the standard default MetaBox domain. Used as the primary domain for connecting to MetaBox server.\n *\n * ### Practical Application\n * The base domain used when no override is specified. Override only via IntegrateMetaboxConfig.domain\n * if connecting to a custom or self-hosted MetaBox instance.\n *\n * ### AI Coding Best Practices\n * Let integrateMetabox() use the default. Override only if needed:\n * `integrateMetabox(id, container, callback, { domain: 'https://custom.domain.com' })`.\n * HTTPS is mandatory — HTTP will be rejected.\n */\n\n/**\n * @deprecated\n */\nexport const Metabox_V3 = 'metabox_v3';\n/**\n * @deprecated\n */\nexport const MetaboxHost_V3 = 'metaboxHost_v3';\n/**\n * @deprecated\n */\nexport const AppLoaded_V3 = 'appLoaded_v3';\n\nexport const MetaboxDomain = 'metabox.3dsource.com';\n\n/**\n * Base route path appended to the domain when building the configurator iframe URL.\n *\n * ### What does it unlock?\n * Base route URL constant used for loading the configurator. Standard path endpoint for accessing the configurator.\n *\n * ### Practical Application\n * The configurator URL format is: `https://{domain}/metabox-configurator/basic/{configuratorId}`.\n * Automatically constructed by integrateMetabox().\n *\n * ### AI Coding Best Practices\n * Let integrateMetabox() handle URL construction. Only reference if building URLs manually\n * (e.g., QR codes, email links, server-side rendering).\n */\nexport const BasicRouteUrl = 'metabox-configurator/basic';\n","export const VERSION = '3.0.32';\n","/**\n * Sender checks for the host↔iframe `postMessage` channel.\n *\n * Deliberately not re-exported from `./index` — `public-api.ts` does\n * `export * from './lib/helpers'`, and these are internal plumbing.\n */\n\nimport type { MetaboxEnvironment } from '../interfaces';\n\n/** Id of the iframe `integrateMetabox` creates; also the hand-rolled-embed contract. */\nexport const EmbeddedContentId = 'embeddedContent';\n\n/** `postMessage` targetOrigin meaning \"any origin, deliver to that window\". */\nexport const AnyOrigin = '*';\n\n/**\n * True iff `origin` can be used as a `postMessage` targetOrigin: a parseable\n * http/https origin *and nothing more*. Excludes `''` and the opaque `'null'`\n * origin (sandboxed frames, `file:`, `data:`), which are not valid targets, and\n * anything carrying a path, query or credentials — every real source here\n * (`URL#origin`, `MessageEvent#origin`) yields a bare origin, so a decorated\n * string means the value did not come from where we think it did.\n *\n * `postMessage` throws a `SyntaxError` on a malformed targetOrigin and silently\n * drops the message on a mismatched one, so this has to be checked up front.\n */\nexport function isTargetableOrigin(\n  origin: string | null | undefined,\n): origin is string {\n  if (!origin || origin === AnyOrigin || origin === 'null') {\n    return false;\n  }\n  let url: URL;\n  try {\n    url = new URL(origin);\n  } catch {\n    return false;\n  }\n  if (url.protocol !== 'https:' && url.protocol !== 'http:') {\n    return false;\n  }\n  // `URL#origin` drops path/query/hash/credentials and normalises the default\n  // port away, so this holds exactly for bare origins.\n  return url.origin === origin;\n}\n\n/**\n * Decides whether an inbound `message` event may drive this Communicator.\n *\n * Before this gate the only check was `event.data.host === 'metabox'`, a string\n * anyone can write. That matters most inside the configurator itself, which runs\n * a Communicator in its own window for the embedded menu: without a sender check\n * the embedding page could forge configurator *events* (screenshots handed to\n * `saveImage`, catalogue/CTA data) that its own inbound guard is built to reject.\n *\n * The discriminator is `environment`, not the DOM: inside the configurator there\n * is no `#embeddedContent` element (it does not embed itself), so a purely\n * DOM-based check would fall through to \"accept anything\" and leave that exact\n * vector open.\n *\n * - `'metabox'` — the peer is the same document, so only this window qualifies.\n *   Nothing here reads the DOM, so renaming an element cannot weaken it.\n * - `'host'` — the peer is our iframe. When we have no handle on one, fall back\n *   to the same-window channel, mirroring `sendCommandToMetabox`, which posts to\n *   this window when it finds no iframe. Accepting that case keeps hand-rolled\n *   embeds working; a hard refusal would silently kill the API on those sites,\n *   which is how a domain allowlist broke this channel once already.\n */\nexport function acceptsMessageFrom(\n  event: Pick<MessageEvent, 'source' | 'origin'>,\n  environment: MetaboxEnvironment,\n  iframe: HTMLIFrameElement | null,\n): boolean {\n  const sameWindow =\n    event.source === window && event.origin === window.location.origin;\n\n  if (environment === 'metabox') {\n    return sameWindow;\n  }\n\n  const own = resolveIframe(iframe)?.contentWindow;\n  if (own) {\n    return event.source === own;\n  }\n\n  // Our frame could not be identified: a hand-rolled embed that neither passed\n  // one in nor uses the contract id. Refusing would kill that integration\n  // silently, so accept any frame of *this* document — which still shuts out an\n  // opener, an ad frame or the parent, and matches the same-window fallback in\n  // `sendCommandToMetabox`.\n  return sameWindow || isFrameOfThisDocument(event.source);\n}\n\n/** Whether `source` is the content window of an iframe in this document. */\nfunction isFrameOfThisDocument(source: MessageEvent['source']): boolean {\n  if (!source) {\n    return false;\n  }\n  return Array.from(document.querySelectorAll('iframe')).some(\n    (frame) => frame.contentWindow === source,\n  );\n}\n\n/**\n * The iframe this Communicator talks to: the one the integration created while\n * it is still in the document, else whatever currently holds the contract id.\n * `isConnected` matters because a superseding `integrateMetabox` call removes the\n * previous iframe, and a detached one would otherwise shadow the live element.\n */\nexport function resolveIframe(\n  iframe: HTMLIFrameElement | null,\n): HTMLIFrameElement | null {\n  if (iframe?.isConnected) {\n    return iframe;\n  }\n  return document.getElementById(EmbeddedContentId) as HTMLIFrameElement | null;\n}\n","import { EventDispatcher } from './event-dispatcher';\nimport type { CommandBase } from '../actions';\nimport { MetaboxConfig } from '../actions';\nimport type {\n  FromMetaBoxApiEvents,\n  FromMetaBoxMessage,\n  FromMetaboxMessagePayloads,\n  MCAppLoaded,\n  MetaboxCommandConfig,\n  MetaboxEnvironment,\n  ToMetaBoxMessage,\n} from '../interfaces';\nimport { AppLoaded, Metabox, MetaboxHost, VERSION } from '../constants';\nimport {\n  acceptsMessageFrom,\n  AnyOrigin,\n  isTargetableOrigin,\n  resolveIframe,\n} from './message-source';\n\nconst communicatorMap = new Map<string, { instance: Communicator }>();\n\n/**\n * What `integrateMetabox` knows about the iframe it created and the origin it\n * pointed that iframe at. Lets the Communicator check who is talking to it and\n * address the configurator by its exact origin instead of broadcasting.\n *\n * @internal\n */\nexport interface CommunicatorConnection {\n  /** The embedded iframe, when we created it ourselves. */\n  iframe: HTMLIFrameElement | null;\n  /** Origin of the configurator document, or `null` when it is not known yet. */\n  origin: string | null;\n}\n\n/**\n * Handles messaging between the host page and embedded Metabox content.\n *\n * ### What does it unlock?\n * Internal class that creates a proxy/communication layer between the API and MetaBox.\n * Handles reading and sending commands through the established connection.\n *\n * ### Practical Application\n * The API handle returned in the integrateMetabox callback. Provides sendCommandToMetabox() to send commands,\n * and addEventListener()/removeEventListener() for event subscriptions. This is your entire interface to\n * the MetaBox Unreal Engine stream.\n *\n * ### AI Coding Best Practices\n * Store the Communicator reference from the apiReadyCallback in a module-scoped variable or state store.\n * NEVER send commands before this callback fires. All commands and event listeners go through this single\n * api object. Clean up listeners with removeEventListener on component unmount.\n *\n * @internal Use {@link Communicator.createInstance} or the {@link integrateMetabox} helper to instantiate.\n */\nexport class Communicator extends EventDispatcher {\n  /**\n   * Singleton reference to the current communicator instance.\n   */\n  public static instance: Communicator | null = null;\n  /**\n   * Bound handler for incoming postMessage events.\n   */\n  private binder = this.handleMessageReceived.bind(this);\n\n  /** Which side of the iframe boundary this instance runs on — see `acceptsMessageFrom`. */\n  private readonly environment: MetaboxEnvironment;\n\n  /** The iframe we drive, when the integration created it. */\n  private readonly iframe: HTMLIFrameElement | null;\n\n  /** Pinned configurator origin; `null` until we learn it. */\n  private readonly targetOrigin: string | null;\n\n  /** Keeps the \"rejected an inbound message\" warning to one per instance. */\n  private senderRejectionReported = false;\n\n  /** Keeps the \"unknown configurator origin\" warning to one per instance. */\n  private wildcardTargetReported = false;\n\n  /** Keeps the \"our iframe left the document\" warning to one per instance. */\n  private staleFrameReported = false;\n\n  /**\n   * Constructs a Communicator, replacing any existing instance, and begins listening for messages.\n   * @internal\n   */\n  constructor(\n    data: MCAppLoaded['payload'],\n    environment: MetaboxEnvironment,\n    config?: Partial<MetaboxCommandConfig>,\n    connection?: CommunicatorConnection,\n  ) {\n    super();\n    // Assigned before the listener goes up: the gate reads all three.\n    this.environment = environment;\n    this.iframe = connection?.iframe ?? null;\n    this.targetOrigin = isTargetableOrigin(connection?.origin)\n      ? connection.origin\n      : null;\n    const { appId = 'unknown', version = VERSION } = data ?? {};\n    const key = `${version}_${environment}_${appId}`;\n    communicatorMap.get(key)?.instance.destroy(key);\n    communicatorMap.set(key, { instance: this });\n    window.addEventListener('message', this.binder);\n    this.sendCommandToMetabox(\n      new MetaboxConfig(appId, {\n        ...config,\n        hostUrl: location.href,\n        apiVersion: VERSION,\n      }),\n    );\n  }\n\n  /**\n   * Listens for Metabox to signal readiness, then initializes communicator.\n   * @param apiReadyCallback - Called with the new Communicator once the Metabox is loaded.\n   * @param {MetaboxEnvironment} environment - The environment in which the Communicator is running.\n   * @param {MetaboxCommandConfig} config - optional initial config: standalone - if true - disable metabox custom template and all logic\n   * @param {CommunicatorConnection} connection - the iframe and origin `integrateMetabox`\n   * built, so the handshake can be attributed and later messages addressed precisely.\n   * Omitted by hand-rolled embeds, which are then identified through the\n   * `embeddedContent` id and the handshake's own origin.\n   * @returns A cancel function that removes the handshake `message` listener.\n   * `integrateMetabox` (the public entry point) calls this automatically when\n   * a new integration supersedes a still-pending one, so direct internal\n   * callers only need it for explicit early teardown. Idempotent.\n   */\n  static createInstance(\n    apiReadyCallback: (api: Communicator) => void,\n    environment: MetaboxEnvironment,\n    config?: Partial<MetaboxCommandConfig>,\n    connection?: CommunicatorConnection,\n  ): () => void {\n    const iframe = connection?.iframe ?? null;\n    // The handshake listener outlives every rejected message, so the report is\n    // kept to one: a page that keeps announcing itself must not flood the\n    // console of the site embedding us.\n    let rejectionReported = false;\n\n    const startHandler = (event: MessageEvent): void => {\n      const message = event.data as FromMetaBoxMessage;\n      if (message?.envelope?.action !== AppLoaded || message.host !== Metabox) {\n        return;\n      }\n      // The handshake decides who we hand the API to and which appId keys the\n      // registry, so it is gated exactly like every later message.\n      if (!acceptsMessageFrom(event, environment, iframe)) {\n        if (!rejectionReported) {\n          rejectionReported = true;\n          console.warn(\n            `Metabox: ignored an \"${AppLoaded}\" handshake from an unexpected sender.`,\n          );\n        }\n        return;\n      }\n\n      apiReadyCallback(\n        new Communicator(message.envelope.payload, environment, config, {\n          iframe,\n          origin: Communicator.resolveHandshakeOrigin(event, connection),\n        }),\n      );\n      window.removeEventListener('message', startHandler);\n    };\n\n    window.addEventListener('message', startHandler);\n    return () => window.removeEventListener('message', startHandler);\n  }\n\n  /**\n   * The origin to address the configurator by, decided once from the handshake.\n   *\n   * Prefers what `integrateMetabox` computed from the iframe URL, but yields to\n   * the origin the handshake actually came from when the two disagree: a redirect\n   * (a `config.domain` override pointing at a host that 30x's elsewhere) would\n   * otherwise pin an origin nothing answers on, and every command would be\n   * dropped silently. The sender already passed the window gate, so this cannot\n   * be steered by an unrelated page.\n   */\n  private static resolveHandshakeOrigin(\n    event: MessageEvent,\n    connection?: CommunicatorConnection,\n  ): string | null {\n    const expected = isTargetableOrigin(connection?.origin)\n      ? connection.origin\n      : null;\n    const actual = isTargetableOrigin(event.origin) ? event.origin : null;\n\n    if (expected && actual && expected !== actual) {\n      console.warn(\n        `Metabox: the configurator answered from ${actual} but was embedded from ${expected}; using ${actual}.`,\n      );\n      return actual;\n    }\n    return expected ?? actual;\n  }\n\n  /**\n   * Cleans up resources and stops listening for messages.\n   */\n  public override destroy(key: string): void {\n    super.destroy(key);\n    window.removeEventListener('message', this.binder);\n  }\n\n  /** Destroys all active Communicator instances and clears the internal registry. */\n  static clearAll() {\n    if (communicatorMap.size === 0) {\n      return;\n    }\n\n    communicatorMap.forEach((value, key) => value.instance.destroy(key));\n    communicatorMap.clear();\n  }\n\n  /**\n   * Retrieves a registered Communicator instance by its key.\n   * @param key - The composite key (`version_environment_appId`) identifying the instance.\n   */\n  static getCommunicator(key: string) {\n    return communicatorMap.get(key);\n  }\n\n  /**\n   * Posts a command to the Metabox iframe.\n   * @param command - An action command containing data to send.\n   */\n  public sendCommandToMetabox<T extends CommandBase>(command: T): void {\n    const { data } = command;\n    const iframe = resolveIframe(this.iframe);\n    this.reportStaleFrame();\n\n    const toMetaboxMessage = {\n      host: MetaboxHost,\n      envelope: { ...data },\n      // Deprecated mirror of `envelope`. Kept as an independent clone so a\n      // receiver mutating one cannot observably change the other.\n      payload: { ...data },\n      target: iframe?.contentWindow ? 'child' : 'metabox',\n      apiVersion: VERSION,\n    } satisfies ToMetaBoxMessage;\n\n    if (!iframe?.contentWindow) {\n      console.warn(\n        'Metabox IFrame not found or not ready. Message sends to the same window',\n      );\n      // Same-window channel. '/' means \"only deliver if the receiver's origin\n      // equals mine\", which is exactly the intent and, unlike\n      // `window.location.origin`, also holds for an opaque origin: a page under\n      // `sandbox=\"allow-scripts\"` reports the origin as the string \"null\",\n      // which is not a valid targetOrigin and makes postMessage throw.\n      window.postMessage(toMetaboxMessage, '/');\n      return;\n    }\n\n    iframe.contentWindow.postMessage(toMetaboxMessage, this.resolveTarget());\n  }\n\n  /**\n   * A superseding `integrateMetabox` call removes the iframe this handle was\n   * built for. Commands then fall through to whatever now holds the contract id,\n   * addressed by the origin pinned for the *old* integration — so if the new one\n   * points at a different origin, the browser drops them without a word. The\n   * handle is stale at that point and should be replaced by the one from the new\n   * integration; say so rather than letting it fail quietly.\n   */\n  private reportStaleFrame(): void {\n    if (!this.iframe || this.iframe.isConnected || this.staleFrameReported) {\n      return;\n    }\n    this.staleFrameReported = true;\n    console.warn(\n      'Metabox: the iframe this API handle was created for has left the document. ' +\n        'Commands are being sent to the current #embeddedContent instead — use the handle ' +\n        'from the latest integrateMetabox() call.',\n    );\n  }\n\n  /**\n   * `targetOrigin` for the iframe. The very first command is `metaboxConfig`,\n   * which carries `hostUrl: location.href` — on a shop page that routinely holds\n   * order ids and session parameters — so it must not be broadcast to whatever\n   * document currently occupies the frame.\n   *\n   * Falls back to a wildcard rather than refusing to send: this leg carries\n   * commands, and a configurator that silently stops responding on a customer\n   * site is worse than the status quo. The fallback is reported once so it does\n   * not pass unnoticed.\n   */\n  private resolveTarget(): string {\n    if (this.targetOrigin) {\n      return this.targetOrigin;\n    }\n    if (!this.wildcardTargetReported) {\n      this.wildcardTargetReported = true;\n      console.warn(\n        'Metabox: the configurator origin is unknown, so commands are broadcast. ' +\n          'Use integrateMetabox() to have it pinned.',\n      );\n    }\n    return AnyOrigin;\n  }\n\n  /**\n   * Registers an event listener for messages dispatched by the Metabox.\n   * @param messageType - The event name to listen for (e.g. `'configuratorDataUpdated'`).\n   * @param callback - Handler invoked with the typed payload when the event fires.\n   * @override\n   */\n  override addEventListener<T extends FromMetaBoxApiEvents>(\n    messageType: T,\n    callback: (data: FromMetaboxMessagePayloads[T]) => void,\n  ) {\n    return super.addEventListener(\n      messageType,\n      callback as (data: unknown) => void,\n    );\n  }\n\n  /**\n   * Dispatches a typed event to all registered listeners.\n   * @param messageType - The event name to dispatch.\n   * @param data - The payload to pass to each listener.\n   * @override\n   */\n  override dispatchEvent<T extends FromMetaBoxApiEvents>(\n    messageType: T,\n    data: FromMetaboxMessagePayloads[T],\n  ) {\n    return super.dispatchEvent(messageType, data);\n  }\n\n  /**\n   * Removes a previously registered event listener.\n   * @param messageType - The event name the listener was registered for.\n   * @param callback - The same function reference that was passed to {@link addEventListener}.\n   * @override\n   */\n  override removeEventListener<T extends FromMetaBoxApiEvents>(\n    messageType: T,\n    callback: (data: FromMetaboxMessagePayloads[T]) => void,\n  ) {\n    return super.removeEventListener(\n      messageType,\n      callback as (data: unknown) => void,\n    );\n  }\n\n  /**\n   * Filters and dispatches incoming messages from the Metabox.\n   * @param {MessageEvent} event - The postMessage event received on a window.\n   */\n  private handleMessageReceived<T extends FromMetaBoxApiEvents>(\n    event: MessageEvent,\n  ): void {\n    if (event.data?.host !== Metabox) {\n      return;\n    }\n    // `host` is a string anyone can write, so it says nothing about who sent\n    // this. Everything below dispatches configurator events to application\n    // listeners — screenshots, catalogue and CTA data — so the sender is checked\n    // before any of it runs.\n    if (!acceptsMessageFrom(event, this.environment, this.iframe)) {\n      if (!this.senderRejectionReported) {\n        this.senderRejectionReported = true;\n        console.warn(\n          `Metabox: ignored a \"${Metabox}\" message from an unexpected sender ` +\n            `(environment: ${this.environment}). Events are only accepted from the configurator.`,\n        );\n      }\n      return;\n    }\n    const data = event.data?.envelope;\n    this.dispatchEvent(data?.eventType as T, data?.payload);\n  }\n}\n","import type { IntegrateMetaboxConfig } from '../interfaces';\nimport { BasicRouteUrl, MetaboxDomain } from '../constants';\n\n/**\n * Constructs the iframe source URL for the Metabox Basic Configurator.\n *\n * ### What does it unlock?\n * Utility function that prepares the iframe source URL. Constructs the proper URL with parameters\n * for loading the MetaBox configurator.\n *\n * ### Practical Application\n * Utility function that constructs the iframe source URL with proper parameters.\n * URL format: `https://{domain}/metabox-configurator/basic/{configuratorId}`.\n * Called internally by integrateMetabox() — use directly only for manual URL construction.\n *\n * ### AI Coding Best Practices\n * Usually called internally. Use directly only for pre-constructing embed URLs (QR codes, email links,\n * preview URLs). Verify output is HTTPS. Remember basic configurators use `/basic/` path.\n *\n * @internal\n * @hidden\n *\n * @param {string} configuratorId - An string identifier for the configurator.\n * @param {IntegrateMetaboxConfig} config - An object containing the configuration options.\n */\nexport const prepareIframeSrc = (\n  configuratorId: string,\n  config?: IntegrateMetaboxConfig,\n) => {\n  const base = `https://${config?.domain || MetaboxDomain}/${BasicRouteUrl}/${configuratorId}`;\n  const params = new URLSearchParams();\n\n  if (config?.introImage) {\n    params.set('introImage', config.introImage);\n  }\n  if (config?.introVideo) {\n    params.set('introVideo', config.introVideo);\n  }\n  if (config?.loadingImage) {\n    params.set('loadingImage', config.loadingImage);\n  }\n  if (config?.state) {\n    params.set('state', decodeURIComponent(config.state));\n  }\n  if (config?.showLoadingProgress !== undefined) {\n    params.set('showLoadingProgress', String(config.showLoadingProgress));\n  }\n  if (config?.showResumeStreamPopup !== undefined) {\n    params.set('showResumeStreamPopup', String(config.showResumeStreamPopup));\n  }\n  if (config?.showUserInactivityTimer !== undefined) {\n    params.set(\n      'showUserInactivityTimer',\n      String(config.showUserInactivityTimer),\n    );\n  }\n  if (config?.userInactivityTimeout !== undefined) {\n    params.set('userInactivityTimeout', String(config.userInactivityTimeout));\n  }\n  if (config?.autoStartStream !== undefined) {\n    params.set('autoStartStream', String(config.autoStartStream));\n  }\n\n  const query = params.toString();\n  return query ? `${base}?${query}` : base;\n};\n","import { Communicator } from './communicator';\nimport type { IntegrateMetaboxConfig } from '../interfaces';\nimport { prepareIframeSrc } from './prepare-iframe-src';\n\n// Cancel for the previous integration's handshake listener while it is still\n// waiting for the iframe to load. A new integrateMetabox call supersedes it —\n// it already replaces the single embedded iframe — so a never-completed\n// handshake (failed load, SPA remount, retry) can't leak a window 'message'\n// listener for the page lifetime. Idempotent, so a completed handshake's\n// cancel is a harmless no-op here.\nlet cancelPendingHandshake: (() => void) | null = null;\n\n/**\n * Integrates the Metabox Basic Configurator into the page by injecting an iframe and\n * initializing a Communicator instance for host-to-iframe messaging.\n *\n * - Builds a secure iframe URL using the provided configuratorId and config options.\n * - Ensures the resulting URL uses HTTPS and that the target container exists.\n * - Removes any previously embedded iframe with id \"embeddedContent\" before inserting a new one.\n *\n * ### What does it unlock?\n * Main initialization function for MetaBox integration. Initializes the configurator, receives an API handle,\n * and sets up all configurations.\n *\n * ### Practical Application\n * is THE entry point function. Creates the configurator iframe, establishes postMessage communication, and returns\n * the Communicator api handle via callback. Call ONCE per configurator. Params: configuratorId (UUID),\n * containerId (DOM element ID, default 'embed3DSource'), apiReadyCallback, config (IntegrateMetaboxConfig).\n *\n * ### AI Coding Best Practices\n * Pattern: `integrateMetabox('uuid', 'div-id', (api) => {\n *  set up listeners, then set product, then environment\n * }, { standalone: true })`.\n * Ensure a container div exists in DOM with non-zero dimensions. HTTPS required.\n * Inside callback: 1) addEventListener for configuratorDataUpdated, 2) SetProduct, 3) SetEnvironment.\n *\n * @param {string} configuratorId - The Basic Configurator ID (not a full URL). It is appended to\n * `https://{domain}/metabox-configurator/basic/{configuratorId}` to form the iframe src.\n *\n * @param {string} containerId - The id of the container element where the iframe will be injected.\n *\n * @param {(api: Communicator) => void} apiReadyCallback - Called when the Communicator instance is created on the host side.\n *\n * @param {IntegrateMetaboxConfig} config - Optional configuration used to build the iframe URL and initialize the communicator.\n * Supported fields:\n *  - standalone?: boolean — if true, disables Metabox custom template and related logic.\n *  - introImage?: string — URL to an image shown on the intro screen (added as ?introImage=...).\n *  - introVideo?: string — URL to a video shown on the intro screen (added as ?introVideo=...).\n *  - loadingImage?: string — URL to an image displayed while loading (added as ?loadingImage=...).\n *  - state?: string — Predefined state for configurator for initial loading (added as ?state=...).\n *  - domain?: string — custom domain for testing (defaults to metabox.3dsource.com). HTTPS is enforced.\n *  - showLoadingProgress?: boolean — if true, shows the loading progress bar (added as ?showLoadingProgress=true).\n *  - showResumeStreamPopup?: boolean — if true, shows the resume stream popup (added as ?showResumeStreamPopup=true).\n *  - showUserInactivityTimer?: boolean — if true, shows the AFK countdown popup (added as ?showUserInactivityTimer=true).\n *  - userInactivityTimeout?: number — inactivity timeout in seconds before disconnect (added as ?userInactivityTimeout=...).\n *  - autoStartStream?: boolean — controls whether the pixel stream starts automatically on load (added as ?autoStartStream=...); set false to start it manually via ResumeStream.\n *\n * @throws Error If configuratorId or containerId are empty strings.\n * @throws Error If the computed iframe URL is invalid or does not use HTTPS.\n * @throws Error If the container element with the provided id cannot be found.\n *\n * @returns A cancel function that stops waiting for the Metabox to load.\n * Calling it is optional — a later `integrateMetabox` call automatically\n * supersedes a still-pending handshake — but it lets you remove the handshake\n * listener immediately on teardown (e.g. SPA route change before\n * `apiReadyCallback` fires). Idempotent.\n *\n * @example\n * import { integrateMetabox } from '@3dsource/metabox-front-api';\n *\n * integrateMetabox('configurator-id',\n *   'embed3DSource',\n *   (api) => {\n *     // Communicator is ready to use\n *   },\n *   {\n *     standalone: false,\n *     introImage: 'https://example.com/intro.png',\n *     loadingImage: 'https://example.com/loading.png',\n *     showLoadingProgress: true,\n *     showResumeStreamPopup: true,\n *     showUserInactivityTimer: true,\n *     userInactivityTimeout: 20,\n *   },\n * );\n */\nexport function integrateMetabox(\n  configuratorId: string,\n  containerId: string,\n  apiReadyCallback: (api: Communicator) => void,\n  config?: IntegrateMetaboxConfig,\n): () => void {\n  if (!configuratorId.trim()) {\n    throw new Error(\n      'integrateMetabox: configuratorId must be a non-empty string',\n    );\n  }\n  const iframeSrc = prepareIframeSrc(configuratorId, config);\n  let parsedUrl: URL;\n  try {\n    parsedUrl = new URL(iframeSrc);\n  } catch {\n    throw new Error('integrateMetabox: Provided iframeSrc is not a valid URL');\n  }\n  if (parsedUrl.protocol !== 'https:') {\n    throw new Error('integrateMetabox: iframeSrc must use HTTPS protocol');\n  }\n  if (!containerId.trim()) {\n    throw new Error('integrateMetabox: containerId must be a non-empty string');\n  }\n\n  const container = document.getElementById(containerId);\n  if (!container) {\n    throw new Error(`Container element with id ${containerId} not found`);\n  }\n\n  const existingIframe = document.getElementById('embeddedContent');\n  if (existingIframe) {\n    existingIframe.remove();\n  }\n\n  // Built before the handshake listener goes up so the Communicator can be told\n  // which frame is ours and which origin to address it by. The element is still\n  // detached here — `contentWindow` only exists once it is in the document, and\n  // by then the handshake it is compared against has not happened yet.\n  const iframe = document.createElement('iframe');\n\n  // Supersede a prior integration still waiting for its handshake.\n  cancelPendingHandshake?.();\n  const cancel = Communicator.createInstance(apiReadyCallback, 'host', config, {\n    iframe,\n    origin: parsedUrl.origin,\n  });\n  cancelPendingHandshake = cancel ?? null;\n\n  // Inject the container rules once per containerId — repeated integrations\n  // were appending identical <style> tags, forcing CSSOM re-parses.\n  const styleId = `metabox-integration-style-${containerId}`;\n  if (!document.getElementById(styleId)) {\n    const style = document.createElement('style');\n    style.id = styleId;\n    style.innerHTML = `\n        #${containerId} {\n          width: 100%;\n          height: 100%;\n          overflow: hidden;\n          position: relative;\n        }\n    `;\n    document.head.appendChild(style);\n  }\n\n  iframe.setAttribute('allow', 'autoplay; fullscreen; encrypted-media');\n  iframe.setAttribute('referrerPolicy', 'no-referrer-when-downgrade');\n  iframe.setAttribute('id', 'embeddedContent');\n  iframe.style.border = '0';\n  iframe.style.width = '100%';\n  iframe.style.height = '100%';\n  iframe.style.overflow = 'hidden';\n  iframe.src = iframeSrc;\n  container.appendChild(iframe);\n\n  return cancel;\n}\n","/**\n * Saves an image by triggering a download.\n *\n * This function creates an anchor element, sets its `href` attribute to the provided image URL,\n * and triggers a click event to initiate a download with the specified filename.\n *\n * ### What does it unlock?\n * Main exported function to save images from the configurator. Converts base64 image data to actual image\n * files and saves them to the local filesystem.\n *\n * ### Practical Application\n * Exported utility function that converts base64 screenshot data (from screenshotReady event) to a downloadable\n * image file. Handles the base64 → blob → browser download flow. Import directly from the API package.\n *\n * ### AI Coding Best Practices\n * Pattern: `api.addEventListener('screenshotReady', (data) => { if(data) saveImage(data, 'config-screenshot.png'); })`.\n * Filename extension should match the MimeType passed to GetScreenshot.\n * Import: `import { saveImage } from '@3dsource/metabox-front-api'`.\n *\n * Only the three data-URL formats the configurator actually produces are\n * accepted (`image/png`, `image/jpeg`, `image/webp`). The documented usage above\n * feeds this an event payload straight off the wire, and the body below sets\n * `href` on an anchor and clicks it — so without the check any `data:` URL that\n * reached a `screenshotReady` listener would land in the user's downloads.\n * Anything else is reported and ignored.\n *\n * @param {string} imageUrl - The URL of the image to save.\n * @param {string} filename - The name of the file to save.\n */\nexport function saveImage(imageUrl: string, filename: string): void {\n  if (!isScreenshotDataUrl(imageUrl)) {\n    console.warn(\n      'Metabox: saveImage ignored a value that is not a configurator screenshot ' +\n        '(expected a base64 data URL of type image/png, image/jpeg or image/webp).',\n    );\n    return;\n  }\n\n  const a = document.createElement('a');\n  a.href = imageUrl;\n  a.download = filename;\n  document.body.appendChild(a);\n  a.click();\n  document.body.removeChild(a);\n}\n\n/**\n * A base64 data URL in one of the formats `GetScreenshot` can ask for. Matched\n * as a whole string rather than parsed: `new URL()` accepts a `data:` URL but\n * exposes nothing useful about its media type, and a prefix check would let\n * anything trail behind the payload.\n */\nfunction isScreenshotDataUrl(value: string): boolean {\n  return /^data:image\\/(?:png|jpeg|webp);base64,[A-Za-z0-9+/]+={0,2}$/i.test(\n    value,\n  );\n}\n","/**\n * Sets the URL parameters based on the provided state.\n *\n * @internal\n * @hidden\n * This function updates the current URL by replacing its search parameters with the key-value pairs from the provided state object.\n *\n * @param {Record<string, string>} state - An object containing key-value pairs to set as URL parameters.\n */\nexport function setUrlParams(state: Record<string, string>): void {\n  const url = new URL(window.location.href);\n  url.search = '';\n  Object.entries(state).forEach(([key, value]) => {\n    url.searchParams.set(key, value);\n  });\n  history.replaceState(null, '', url.toString());\n}\n\n/**\n * Retrieves the URL parameters as an object.\n *\n * @remarks\n * @internal\n * @hidden\n * This function parses the current URL's search parameters and returns them as a key-value object.\n *\n * @returns An object containing the URL parameters.\n */\nexport function getUrlParams(): Record<string, string> {\n  const urlParams = new URLSearchParams(window.location.search);\n  const selections: Record<string, string> = {};\n  urlParams.forEach((value, key) => {\n    selections[key] = value;\n  });\n  return selections;\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":";;AAEA;;;;;;;;;;;;;;;;;AAiBG;MAEU,WAAW,CAAA;AAGvB;;AChBD;;;;;;;;;;;;;;;;;;;AAmBG;AAEG,SAAU,qBAAqB,CACnC,MAAoB,EACpB,SAAY,EAAA;AAEZ,IAAA,OAAO,SAAS,CAAC,MAAM,EAAE,SAAS,CAEjC;AACH;;AChCA;;;;;;;;;;;;;;;AAeG;AACI,MAAM,+BAA+B,GAAG;AAC7C,IAAA,aAAa,EAAE,eAAe;AAC9B,IAAA,YAAY,EAAE,cAAc;AAC5B,IAAA,UAAU,EAAE,YAAY;AACxB,IAAA,cAAc,EAAE,gBAAgB;AAChC,IAAA,0BAA0B,EAAE,4BAA4B;AACxD,IAAA,UAAU,EAAE,YAAY;AACxB,IAAA,sBAAsB,EAAE,wBAAwB;AAChD,IAAA,YAAY,EAAE,cAAc;AAC5B,IAAA,MAAM,EAAE,QAAQ;AAChB,IAAA,0BAA0B,EAAE,4BAA4B;AACxD,IAAA,aAAa,EAAE,eAAe;AAC9B,IAAA,gBAAgB,EAAE,kBAAkB;AACpC,IAAA,oBAAoB,EAAE,sBAAsB;AAC5C,IAAA,SAAS,EAAE,WAAW;AACtB,IAAA,SAAS,EAAE,WAAW;AACtB,IAAA,WAAW,EAAE,aAAa;AAC1B,IAAA,kBAAkB,EAAE,oBAAoB;AACxC,IAAA,SAAS,EAAE,WAAW;AACtB,IAAA,YAAY,EAAE,cAAc;AAC5B,IAAA,YAAY,EAAE,cAAc;AAC5B,IAAA,aAAa,EAAE,eAAe;AAC9B,IAAA,YAAY,EAAE,cAAc;AAC5B,IAAA,mBAAmB,EAAE,qBAAqB;AAC1C,IAAA,eAAe,EAAE,iBAAiB;AAClC,IAAA,eAAe,EAAE,iBAAiB;AAClC,IAAA,wBAAwB,EAAE,0BAA0B;;;AC1CtD;;;;;;;;;;;;;;;;;;;;;AAqBG;AAEG,MAAO,aAAc,SAAQ,WAAW,CAAA;IAC5C,WAAA,CAAY,KAAa,EAAE,MAA4B,EAAA;AACrD,QAAA,KAAK,EAAE;QACP,IAAI,CAAC,IAAI,GAAG;YACV,MAAM,EAAE,+BAA+B,CAAC,aAAa;AACrD,YAAA,OAAO,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE;SAC3B;IACH;AACD;;AChCD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6CG;AACG,MAAO,MAAO,SAAQ,WAAW,CAAA;AACrC,IAAA,WAAA,GAAA;AACE,QAAA,KAAK,EAAE;QACP,IAAI,CAAC,IAAI,GAAG,EAAE,MAAM,EAAE,+BAA+B,CAAC,MAAM,EAAE;IAChE;AACD;;ACnDD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAwCG;AAEG,MAAO,0BAA2B,SAAQ,WAAW,CAAA;AACzD,IAAA,WAAA,GAAA;AACE,QAAA,KAAK,EAAE;QACP,IAAI,CAAC,IAAI,GAAG;YACV,MAAM,EAAE,+BAA+B,CAAC,0BAA0B;SACnE;IACH;AACD;;ACjDD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6BG;AAEG,MAAO,SAAU,SAAQ,WAAW,CAAA;AACxC,IAAA,WAAA,GAAA;AACE,QAAA,KAAK,EAAE;QACP,IAAI,CAAC,IAAI,GAAG,EAAE,MAAM,EAAE,+BAA+B,CAAC,SAAS,EAAE;IACnE;AACD;;ACnCD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAwCG;AACG,MAAO,SAAU,SAAQ,WAAW,CAAA;AACxC,IAAA,WAAA,CAAY,MAA4B,EAAA;AACtC,QAAA,KAAK,EAAE;QACP,IAAI,CAAC,IAAI,GAAG;YACV,MAAM,EAAE,+BAA+B,CAAC,SAAS;YACjD,OAAO,EAAE,EAAE,MAAM,EAAE;SACpB;IACH;AACD;;AClDD;;;;;;;;;;;;;;;;;;;;AAoBG;AAEG,MAAO,WAAY,SAAQ,WAAW,CAAA;AAC1C,IAAA,WAAA,GAAA;AACE,QAAA,KAAK,EAAE;QACP,IAAI,CAAC,IAAI,GAAG,EAAE,MAAM,EAAE,+BAA+B,CAAC,WAAW,EAAE;IACrE;AACD;;AC3BD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAmCG;AAEG,MAAO,kBAAmB,SAAQ,WAAW,CAAA;AACjD,IAAA,WAAA,GAAA;AACE,QAAA,KAAK,EAAE;QACP,IAAI,CAAC,IAAI,GAAG,EAAE,MAAM,EAAE,+BAA+B,CAAC,kBAAkB,EAAE;IAC5E;AACD;;AC1CD;;;;;;;;;;;;;;;;;;;;;;;;AAwBG;AAEG,MAAO,SAAU,SAAQ,WAAW,CAAA;AACxC,IAAA,WAAA,CAAY,IAAY,EAAA;AACtB,QAAA,KAAK,EAAE;QACP,IAAI,CAAC,IAAI,GAAG;YACV,MAAM,EAAE,+BAA+B,CAAC,SAAS;YACjD,OAAO,EAAE,EAAE,IAAI,EAAE;SAClB;IACH;AACD;;AClCD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA8BG;AAEG,MAAO,YAAa,SAAQ,WAAW,CAAA;AAC3C,IAAA,WAAA,GAAA;AACE,QAAA,KAAK,EAAE;QACP,IAAI,CAAC,IAAI,GAAG;YACV,MAAM,EAAE,+BAA+B,CAAC,YAAY;SACrD;IACH;AACD;;ACvCD;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4BG;AACG,MAAO,YAAa,SAAQ,WAAW,CAAA;AAC3C,IAAA,WAAA,GAAA;AACE,QAAA,KAAK,EAAE;QACP,IAAI,CAAC,IAAI,GAAG,EAAE,MAAM,EAAE,+BAA+B,CAAC,YAAY,EAAE;IACtE;AACD;;AClCD;;;;;;AAMG;AAEG,MAAO,aAAc,SAAQ,WAAW,CAAA;AAC5C,IAAA,WAAA,CAAY,OAAe,EAAA;AACzB,QAAA,KAAK,EAAE;QACP,IAAI,CAAC,IAAI,GAAG;YACV,MAAM,EAAE,+BAA+B,CAAC,mBAAmB;YAC3D,OAAO;SACR;IACH;AACD;;AChBD;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4BG;AACG,MAAO,aAAc,SAAQ,WAAW,CAAA;AAC5C,IAAA,WAAA,GAAA;AACE,QAAA,KAAK,EAAE;QACP,IAAI,CAAC,IAAI,GAAG,EAAE,MAAM,EAAE,+BAA+B,CAAC,aAAa,EAAE;IACvE;AACD;;AClCD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6BG;AAEG,MAAO,YAAa,SAAQ,WAAW,CAAA;AAC3C,IAAA,WAAA,GAAA;AACE,QAAA,KAAK,EAAE;QACP,IAAI,CAAC,IAAI,GAAG,EAAE,MAAM,EAAE,+BAA+B,CAAC,YAAY,EAAE;IACtE;AACD;;AClBD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAoCG;AACG,MAAO,aAAc,SAAQ,WAAW,CAAA;IAC5C,WAAA,CAAY,QAAkB,EAAE,IAA+B,EAAA;AAC7D,QAAA,KAAK,EAAE;QACP,IAAI,CAAC,IAAI,GAAG;YACV,MAAM,EAAE,+BAA+B,CAAC,aAAa;AACrD,YAAA,OAAO,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE;SACpC;IACH;AACD;;AC/DD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAmCG;AAEG,MAAO,UAAW,SAAQ,WAAW,CAAA;AACzC,IAAA,WAAA,CAAY,SAAiB,EAAA;AAC3B,QAAA,KAAK,EAAE;QACP,IAAI,CAAC,IAAI,GAAG;YACV,MAAM,EAAE,+BAA+B,CAAC,UAAU;YAClD,OAAO,EAAE,EAAE,SAAS,EAAE;SACvB;IACH;AACD;;AC7CD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAmCG;AAEG,MAAO,kBAAmB,SAAQ,WAAW,CAAA;IACjD,WAAA,CAAY,MAAc,EAAE,UAAkB,EAAA;AAC5C,QAAA,KAAK,EAAE;QACP,IAAI,CAAC,IAAI,GAAG;YACV,MAAM,EAAE,+BAA+B,CAAC,sBAAsB;AAC9D,YAAA,OAAO,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE;SAChC;IACH;AACD;;AC7CD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6BG;AACG,MAAO,cAAe,SAAQ,WAAW,CAAA;AAC7C,IAAA,WAAA,CAAY,aAAqB,EAAA;AAC/B,QAAA,KAAK,EAAE;QACP,IAAI,CAAC,IAAI,GAAG;YACV,MAAM,EAAE,+BAA+B,CAAC,cAAc;AACtD,YAAA,OAAO,EAAE,EAAE,EAAE,EAAE,aAAa,EAAE;SAC/B;IACH;AACD;;ACtCD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAkCG;AAEG,MAAO,sBAAuB,SAAQ,WAAW,CAAA;IACrD,WAAA,CAAY,MAAc,EAAE,UAAkB,EAAA;AAC5C,QAAA,KAAK,EAAE;QACP,IAAI,CAAC,IAAI,GAAG;YACV,MAAM,EAAE,+BAA+B,CAAC,0BAA0B;AAClE,YAAA,OAAO,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE;SAChC;IACH;AACD;;ACxBD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAqCG;AAEG,MAAO,YAAa,SAAQ,WAAW,CAAA;AAC3C,IAAA,WAAA,CAAY,QAA2B,EAAA;AACrC,QAAA,KAAK,EAAE;QACP,IAAI,CAAC,IAAI,GAAG;YACV,MAAM,EAAE,+BAA+B,CAAC,YAAY;AACpD,YAAA,OAAO,EAAE;;;gBAGP,SAAS,EAAE,QAAQ,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,KAAI;oBACnC,MAAM,QAAQ,GAAG,IAA+B;AAEhD,oBAAA,OAAO,EAAE,GAAG,QAAQ,EAAE,OAAO,EAAE,EAAE,GAAG,QAAQ,CAAC,OAAO,EAAE,EAAE;AAC1D,gBAAA,CAAC,CAAC;AACH,aAAA;SACF;IACH;AACD;;AC3ED;;;;;;;;;;;;;;;;;;;;;;;;AAwBG;AAEG,MAAO,gBAAiB,SAAQ,WAAW,CAAA;AAC/C,IAAA,WAAA,CAAY,OAAgB,EAAA;AAC1B,QAAA,KAAK,EAAE;QACP,IAAI,CAAC,IAAI,GAAG;YACV,MAAM,EAAE,+BAA+B,CAAC,gBAAgB;YACxD,OAAO,EAAE,EAAE,OAAO,EAAE;SACrB;IACH;AACD;;AClCD;;;;;;;;;;;;;;;;;;;;;;;;AAwBG;AAEG,MAAO,oBAAqB,SAAQ,WAAW,CAAA;AACnD,IAAA,WAAA,CAAY,OAAgB,EAAA;AAC1B,QAAA,KAAK,EAAE;QACP,IAAI,CAAC,IAAI,GAAG;YACV,MAAM,EAAE,+BAA+B,CAAC,oBAAoB;YAC5D,OAAO,EAAE,EAAE,OAAO,EAAE;SACrB;IACH;AACD;;AClCD;;;;;;;;;;;;;;;;;;;;AAoBG;AAEG,MAAO,eAAgB,SAAQ,WAAW,CAAA;AAC9C,IAAA,WAAA,GAAA;AACE,QAAA,KAAK,EAAE;QACP,IAAI,CAAC,IAAI,GAAG,EAAE,MAAM,EAAE,+BAA+B,CAAC,eAAe,EAAE;IACzE;AACD;;AC3BD;;;;;;;;;;;;;;;;;;;;AAoBG;AAEG,MAAO,eAAgB,SAAQ,WAAW,CAAA;AAC9C,IAAA,WAAA,GAAA;AACE,QAAA,KAAK,EAAE;QACP,IAAI,CAAC,IAAI,GAAG,EAAE,MAAM,EAAE,+BAA+B,CAAC,eAAe,EAAE;IACzE;AACD;;AC3BD;;;;;;;;;;;;;;;;;;;;AAoBG;AAEG,MAAO,YAAa,SAAQ,WAAW,CAAA;AAC3C,IAAA,WAAA,GAAA;AACE,QAAA,KAAK,EAAE;QACP,IAAI,CAAC,IAAI,GAAG,EAAE,MAAM,EAAE,+BAA+B,CAAC,YAAY,EAAE;IACtE;AACD;;AC3BD;;;;;;;;;;;;;;;;;;;;;AAqBG;AAEG,MAAO,UAAW,SAAQ,WAAW,CAAA;AACzC,IAAA,WAAA,GAAA;AACE,QAAA,KAAK,EAAE;QACP,IAAI,CAAC,IAAI,GAAG,EAAE,MAAM,EAAE,+BAA+B,CAAC,UAAU,EAAE;IACpE;AACD;;AC5BD;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4BG;AAEG,MAAO,wBAAyB,SAAQ,WAAW,CAAA;AACvD,IAAA,WAAA,GAAA;AACE,QAAA,KAAK,EAAE;QACP,IAAI,CAAC,IAAI,GAAG;YACV,MAAM,EAAE,+BAA+B,CAAC,wBAAwB;SACjE;IACH;AACD;;ACfD;;;;;;;;;;;;;AAaG;MACU,eAAe,CAAA;AAA5B,IAAA,WAAA,GAAA;AACE;;AAEG;QACH,IAAA,CAAA,SAAS,GAAe,EAAE;IAiE5B;AA/DE;;;AAGG;;AAEH,IAAA,OAAO,CAAC,GAAW,EAAA;AACjB,QAAA,IAAI,CAAC,SAAS,GAAG,EAAE;IACrB;AAEA;;;;;AAKG;IACH,gBAAgB,CACd,WAAmB,EACnB,QAAiC,EAAA;QAEjC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,WAAW,EAAE,QAAQ,EAAE,CAAC;AAC9C,QAAA,OAAO,IAAI;IACb;AAEA;;;;;AAKG;IACH,aAAa,CAAC,WAAmB,EAAE,IAAa,EAAA;;;;;AAK9C,QAAA,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS;AAChC,QAAA,MAAM,GAAG,GAAG,SAAS,CAAC,MAAM;AAC5B,QAAA,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,EAAE,CAAC,EAAE,EAAE;AAC5B,YAAA,MAAM,QAAQ,GAAG,SAAS,CAAC,CAAC,CAAC;AAC7B,YAAA,IAAI,QAAQ,CAAC,WAAW,KAAK,WAAW,EAAE;AACxC,gBAAA,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC;YACzB;QACF;AACA,QAAA,OAAO,IAAI;IACb;AAEA;;;;;AAKG;IACH,mBAAmB,CACjB,WAAmB,EACnB,QAAiC,EAAA;AAEjC,QAAA,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,CACpC,CAAC,QAAQ,KACP,EACE,QAAQ,CAAC,WAAW,KAAK,WAAW,IAAI,QAAQ,CAAC,QAAQ,KAAK,QAAQ,CACvE,CACJ;AACD,QAAA,OAAO,IAAI;IACb;AACD;;AC5GD;;;;AAIG;AAEH;;;;;;;;;;;;;;AAcG;AACI,MAAM,OAAO,GAAG;AAEvB;;;;;;;;;;;;;;AAcG;AACI,MAAM,WAAW,GAAG;AAE3B;;;;;;;;;;;;;;;;AAgBG;AACI,MAAM,SAAS,GAAG;AAEzB;;;;;;;;;;;;;;AAcG;AAEH;;AAEG;AACI,MAAM,UAAU,GAAG;AAC1B;;AAEG;AACI,MAAM,cAAc,GAAG;AAC9B;;AAEG;AACI,MAAM,YAAY,GAAG;AAErB,MAAM,aAAa,GAAG;AAE7B;;;;;;;;;;;;;AAaG;AACI,MAAM,aAAa,GAAG;;ACxGtB,MAAM,OAAO,GAAG;;ACAvB;;;;;AAKG;AAIH;AACO,MAAM,iBAAiB,GAAG,iBAAiB;AAElD;AACO,MAAM,SAAS,GAAG,GAAG;AAE5B;;;;;;;;;;AAUG;AACG,SAAU,kBAAkB,CAChC,MAAiC,EAAA;IAEjC,IAAI,CAAC,MAAM,IAAI,MAAM,KAAK,SAAS,IAAI,MAAM,KAAK,MAAM,EAAE;AACxD,QAAA,OAAO,KAAK;IACd;AACA,IAAA,IAAI,GAAQ;AACZ,IAAA,IAAI;AACF,QAAA,GAAG,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC;IACvB;AAAE,IAAA,MAAM;AACN,QAAA,OAAO,KAAK;IACd;AACA,IAAA,IAAI,GAAG,CAAC,QAAQ,KAAK,QAAQ,IAAI,GAAG,CAAC,QAAQ,KAAK,OAAO,EAAE;AACzD,QAAA,OAAO,KAAK;IACd;;;AAGA,IAAA,OAAO,GAAG,CAAC,MAAM,KAAK,MAAM;AAC9B;AAEA;;;;;;;;;;;;;;;;;;;;;AAqBG;SACa,kBAAkB,CAChC,KAA8C,EAC9C,WAA+B,EAC/B,MAAgC,EAAA;AAEhC,IAAA,MAAM,UAAU,GACd,KAAK,CAAC,MAAM,KAAK,MAAM,IAAI,KAAK,CAAC,MAAM,KAAK,MAAM,CAAC,QAAQ,CAAC,MAAM;AAEpE,IAAA,IAAI,WAAW,KAAK,SAAS,EAAE;AAC7B,QAAA,OAAO,UAAU;IACnB;IAEA,MAAM,GAAG,GAAG,aAAa,CAAC,MAAM,CAAC,EAAE,aAAa;IAChD,IAAI,GAAG,EAAE;AACP,QAAA,OAAO,KAAK,CAAC,MAAM,KAAK,GAAG;IAC7B;;;;;;IAOA,OAAO,UAAU,IAAI,qBAAqB,CAAC,KAAK,CAAC,MAAM,CAAC;AAC1D;AAEA;AACA,SAAS,qBAAqB,CAAC,MAA8B,EAAA;IAC3D,IAAI,CAAC,MAAM,EAAE;AACX,QAAA,OAAO,KAAK;IACd;IACA,OAAO,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,gBAAgB,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CACzD,CAAC,KAAK,KAAK,KAAK,CAAC,aAAa,KAAK,MAAM,CAC1C;AACH;AAEA;;;;;AAKG;AACG,SAAU,aAAa,CAC3B,MAAgC,EAAA;AAEhC,IAAA,IAAI,MAAM,EAAE,WAAW,EAAE;AACvB,QAAA,OAAO,MAAM;IACf;AACA,IAAA,OAAO,QAAQ,CAAC,cAAc,CAAC,iBAAiB,CAA6B;AAC/E;;AChGA,MAAM,eAAe,GAAG,IAAI,GAAG,EAAsC;AAgBrE;;;;;;;;;;;;;;;;;;AAkBG;AACG,MAAO,YAAa,SAAQ,eAAe,CAAA;AAC/C;;AAEG;aACW,IAAA,CAAA,QAAQ,GAAwB,IAAxB,CAA6B;AAwBnD;;;AAGG;AACH,IAAA,WAAA,CACE,IAA4B,EAC5B,WAA+B,EAC/B,MAAsC,EACtC,UAAmC,EAAA;AAEnC,QAAA,KAAK,EAAE;AAjCT;;AAEG;QACK,IAAA,CAAA,MAAM,GAAG,IAAI,CAAC,qBAAqB,CAAC,IAAI,CAAC,IAAI,CAAC;;QAY9C,IAAA,CAAA,uBAAuB,GAAG,KAAK;;QAG/B,IAAA,CAAA,sBAAsB,GAAG,KAAK;;QAG9B,IAAA,CAAA,kBAAkB,GAAG,KAAK;;AAchC,QAAA,IAAI,CAAC,WAAW,GAAG,WAAW;QAC9B,IAAI,CAAC,MAAM,GAAG,UAAU,EAAE,MAAM,IAAI,IAAI;QACxC,IAAI,CAAC,YAAY,GAAG,kBAAkB,CAAC,UAAU,EAAE,MAAM;cACrD,UAAU,CAAC;cACX,IAAI;AACR,QAAA,MAAM,EAAE,KAAK,GAAG,SAAS,EAAE,OAAO,GAAG,OAAO,EAAE,GAAG,IAAI,IAAI,EAAE;QAC3D,MAAM,GAAG,GAAG,CAAA,EAAG,OAAO,IAAI,WAAW,CAAA,CAAA,EAAI,KAAK,CAAA,CAAE;AAChD,QAAA,eAAe,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC;QAC/C,eAAe,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;QAC5C,MAAM,CAAC,gBAAgB,CAAC,SAAS,EAAE,IAAI,CAAC,MAAM,CAAC;AAC/C,QAAA,IAAI,CAAC,oBAAoB,CACvB,IAAI,aAAa,CAAC,KAAK,EAAE;AACvB,YAAA,GAAG,MAAM;YACT,OAAO,EAAE,QAAQ,CAAC,IAAI;AACtB,YAAA,UAAU,EAAE,OAAO;AACpB,SAAA,CAAC,CACH;IACH;AAEA;;;;;;;;;;;;;AAaG;IACH,OAAO,cAAc,CACnB,gBAA6C,EAC7C,WAA+B,EAC/B,MAAsC,EACtC,UAAmC,EAAA;AAEnC,QAAA,MAAM,MAAM,GAAG,UAAU,EAAE,MAAM,IAAI,IAAI;;;;QAIzC,IAAI,iBAAiB,GAAG,KAAK;AAE7B,QAAA,MAAM,YAAY,GAAG,CAAC,KAAmB,KAAU;AACjD,YAAA,MAAM,OAAO,GAAG,KAAK,CAAC,IAA0B;AAChD,YAAA,IAAI,OAAO,EAAE,QAAQ,EAAE,MAAM,KAAK,SAAS,IAAI,OAAO,CAAC,IAAI,KAAK,OAAO,EAAE;gBACvE;YACF;;;YAGA,IAAI,CAAC,kBAAkB,CAAC,KAAK,EAAE,WAAW,EAAE,MAAM,CAAC,EAAE;gBACnD,IAAI,CAAC,iBAAiB,EAAE;oBACtB,iBAAiB,GAAG,IAAI;AACxB,oBAAA,OAAO,CAAC,IAAI,CACV,wBAAwB,SAAS,CAAA,sCAAA,CAAwC,CAC1E;gBACH;gBACA;YACF;AAEA,YAAA,gBAAgB,CACd,IAAI,YAAY,CAAC,OAAO,CAAC,QAAQ,CAAC,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE;gBAC9D,MAAM;gBACN,MAAM,EAAE,YAAY,CAAC,sBAAsB,CAAC,KAAK,EAAE,UAAU,CAAC;AAC/D,aAAA,CAAC,CACH;AACD,YAAA,MAAM,CAAC,mBAAmB,CAAC,SAAS,EAAE,YAAY,CAAC;AACrD,QAAA,CAAC;AAED,QAAA,MAAM,CAAC,gBAAgB,CAAC,SAAS,EAAE,YAAY,CAAC;QAChD,OAAO,MAAM,MAAM,CAAC,mBAAmB,CAAC,SAAS,EAAE,YAAY,CAAC;IAClE;AAEA;;;;;;;;;AASG;AACK,IAAA,OAAO,sBAAsB,CACnC,KAAmB,EACnB,UAAmC,EAAA;AAEnC,QAAA,MAAM,QAAQ,GAAG,kBAAkB,CAAC,UAAU,EAAE,MAAM;cAClD,UAAU,CAAC;cACX,IAAI;AACR,QAAA,MAAM,MAAM,GAAG,kBAAkB,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,KAAK,CAAC,MAAM,GAAG,IAAI;QAErE,IAAI,QAAQ,IAAI,MAAM,IAAI,QAAQ,KAAK,MAAM,EAAE;YAC7C,OAAO,CAAC,IAAI,CACV,CAAA,wCAAA,EAA2C,MAAM,CAAA,uBAAA,EAA0B,QAAQ,CAAA,QAAA,EAAW,MAAM,CAAA,CAAA,CAAG,CACxG;AACD,YAAA,OAAO,MAAM;QACf;QACA,OAAO,QAAQ,IAAI,MAAM;IAC3B;AAEA;;AAEG;AACa,IAAA,OAAO,CAAC,GAAW,EAAA;AACjC,QAAA,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC;QAClB,MAAM,CAAC,mBAAmB,CAAC,SAAS,EAAE,IAAI,CAAC,MAAM,CAAC;IACpD;;AAGA,IAAA,OAAO,QAAQ,GAAA;AACb,QAAA,IAAI,eAAe,CAAC,IAAI,KAAK,CAAC,EAAE;YAC9B;QACF;AAEA,QAAA,eAAe,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,GAAG,KAAK,KAAK,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QACpE,eAAe,CAAC,KAAK,EAAE;IACzB;AAEA;;;AAGG;IACH,OAAO,eAAe,CAAC,GAAW,EAAA;AAChC,QAAA,OAAO,eAAe,CAAC,GAAG,CAAC,GAAG,CAAC;IACjC;AAEA;;;AAGG;AACI,IAAA,oBAAoB,CAAwB,OAAU,EAAA;AAC3D,QAAA,MAAM,EAAE,IAAI,EAAE,GAAG,OAAO;QACxB,MAAM,MAAM,GAAG,aAAa,CAAC,IAAI,CAAC,MAAM,CAAC;QACzC,IAAI,CAAC,gBAAgB,EAAE;AAEvB,QAAA,MAAM,gBAAgB,GAAG;AACvB,YAAA,IAAI,EAAE,WAAW;AACjB,YAAA,QAAQ,EAAE,EAAE,GAAG,IAAI,EAAE;;;AAGrB,YAAA,OAAO,EAAE,EAAE,GAAG,IAAI,EAAE;YACpB,MAAM,EAAE,MAAM,EAAE,aAAa,GAAG,OAAO,GAAG,SAAS;AACnD,YAAA,UAAU,EAAE,OAAO;SACO;AAE5B,QAAA,IAAI,CAAC,MAAM,EAAE,aAAa,EAAE;AAC1B,YAAA,OAAO,CAAC,IAAI,CACV,yEAAyE,CAC1E;;;;;;AAMD,YAAA,MAAM,CAAC,WAAW,CAAC,gBAAgB,EAAE,GAAG,CAAC;YACzC;QACF;AAEA,QAAA,MAAM,CAAC,aAAa,CAAC,WAAW,CAAC,gBAAgB,EAAE,IAAI,CAAC,aAAa,EAAE,CAAC;IAC1E;AAEA;;;;;;;AAOG;IACK,gBAAgB,GAAA;AACtB,QAAA,IAAI,CAAC,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,MAAM,CAAC,WAAW,IAAI,IAAI,CAAC,kBAAkB,EAAE;YACtE;QACF;AACA,QAAA,IAAI,CAAC,kBAAkB,GAAG,IAAI;QAC9B,OAAO,CAAC,IAAI,CACV,6EAA6E;YAC3E,mFAAmF;AACnF,YAAA,0CAA0C,CAC7C;IACH;AAEA;;;;;;;;;;AAUG;IACK,aAAa,GAAA;AACnB,QAAA,IAAI,IAAI,CAAC,YAAY,EAAE;YACrB,OAAO,IAAI,CAAC,YAAY;QAC1B;AACA,QAAA,IAAI,CAAC,IAAI,CAAC,sBAAsB,EAAE;AAChC,YAAA,IAAI,CAAC,sBAAsB,GAAG,IAAI;YAClC,OAAO,CAAC,IAAI,CACV,0EAA0E;AACxE,gBAAA,2CAA2C,CAC9C;QACH;AACA,QAAA,OAAO,SAAS;IAClB;AAEA;;;;;AAKG;IACM,gBAAgB,CACvB,WAAc,EACd,QAAuD,EAAA;QAEvD,OAAO,KAAK,CAAC,gBAAgB,CAC3B,WAAW,EACX,QAAmC,CACpC;IACH;AAEA;;;;;AAKG;IACM,aAAa,CACpB,WAAc,EACd,IAAmC,EAAA;QAEnC,OAAO,KAAK,CAAC,aAAa,CAAC,WAAW,EAAE,IAAI,CAAC;IAC/C;AAEA;;;;;AAKG;IACM,mBAAmB,CAC1B,WAAc,EACd,QAAuD,EAAA;QAEvD,OAAO,KAAK,CAAC,mBAAmB,CAC9B,WAAW,EACX,QAAmC,CACpC;IACH;AAEA;;;AAGG;AACK,IAAA,qBAAqB,CAC3B,KAAmB,EAAA;QAEnB,IAAI,KAAK,CAAC,IAAI,EAAE,IAAI,KAAK,OAAO,EAAE;YAChC;QACF;;;;;AAKA,QAAA,IAAI,CAAC,kBAAkB,CAAC,KAAK,EAAE,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,MAAM,CAAC,EAAE;AAC7D,YAAA,IAAI,CAAC,IAAI,CAAC,uBAAuB,EAAE;AACjC,gBAAA,IAAI,CAAC,uBAAuB,GAAG,IAAI;AACnC,gBAAA,OAAO,CAAC,IAAI,CACV,CAAA,oBAAA,EAAuB,OAAO,CAAA,oCAAA,CAAsC;AAClE,oBAAA,CAAA,cAAA,EAAiB,IAAI,CAAC,WAAW,CAAA,kDAAA,CAAoD,CACxF;YACH;YACA;QACF;AACA,QAAA,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,EAAE,QAAQ;QACjC,IAAI,CAAC,aAAa,CAAC,IAAI,EAAE,SAAc,EAAE,IAAI,EAAE,OAAO,CAAC;IACzD;;;ACpXF;;;;;;;;;;;;;;;;;;;;;AAqBG;MACU,gBAAgB,GAAG,CAC9B,cAAsB,EACtB,MAA+B,KAC7B;AACF,IAAA,MAAM,IAAI,GAAG,CAAA,QAAA,EAAW,MAAM,EAAE,MAAM,IAAI,aAAa,CAAA,CAAA,EAAI,aAAa,CAAA,CAAA,EAAI,cAAc,EAAE;AAC5F,IAAA,MAAM,MAAM,GAAG,IAAI,eAAe,EAAE;AAEpC,IAAA,IAAI,MAAM,EAAE,UAAU,EAAE;QACtB,MAAM,CAAC,GAAG,CAAC,YAAY,EAAE,MAAM,CAAC,UAAU,CAAC;IAC7C;AACA,IAAA,IAAI,MAAM,EAAE,UAAU,EAAE;QACtB,MAAM,CAAC,GAAG,CAAC,YAAY,EAAE,MAAM,CAAC,UAAU,CAAC;IAC7C;AACA,IAAA,IAAI,MAAM,EAAE,YAAY,EAAE;QACxB,MAAM,CAAC,GAAG,CAAC,cAAc,EAAE,MAAM,CAAC,YAAY,CAAC;IACjD;AACA,IAAA,IAAI,MAAM,EAAE,KAAK,EAAE;AACjB,QAAA,MAAM,CAAC,GAAG,CAAC,OAAO,EAAE,kBAAkB,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IACvD;AACA,IAAA,IAAI,MAAM,EAAE,mBAAmB,KAAK,SAAS,EAAE;AAC7C,QAAA,MAAM,CAAC,GAAG,CAAC,qBAAqB,EAAE,MAAM,CAAC,MAAM,CAAC,mBAAmB,CAAC,CAAC;IACvE;AACA,IAAA,IAAI,MAAM,EAAE,qBAAqB,KAAK,SAAS,EAAE;AAC/C,QAAA,MAAM,CAAC,GAAG,CAAC,uBAAuB,EAAE,MAAM,CAAC,MAAM,CAAC,qBAAqB,CAAC,CAAC;IAC3E;AACA,IAAA,IAAI,MAAM,EAAE,uBAAuB,KAAK,SAAS,EAAE;AACjD,QAAA,MAAM,CAAC,GAAG,CACR,yBAAyB,EACzB,MAAM,CAAC,MAAM,CAAC,uBAAuB,CAAC,CACvC;IACH;AACA,IAAA,IAAI,MAAM,EAAE,qBAAqB,KAAK,SAAS,EAAE;AAC/C,QAAA,MAAM,CAAC,GAAG,CAAC,uBAAuB,EAAE,MAAM,CAAC,MAAM,CAAC,qBAAqB,CAAC,CAAC;IAC3E;AACA,IAAA,IAAI,MAAM,EAAE,eAAe,KAAK,SAAS,EAAE;AACzC,QAAA,MAAM,CAAC,GAAG,CAAC,iBAAiB,EAAE,MAAM,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC;IAC/D;AAEA,IAAA,MAAM,KAAK,GAAG,MAAM,CAAC,QAAQ,EAAE;AAC/B,IAAA,OAAO,KAAK,GAAG,CAAA,EAAG,IAAI,CAAA,CAAA,EAAI,KAAK,CAAA,CAAE,GAAG,IAAI;AAC1C;;AC7DA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,sBAAsB,GAAwB,IAAI;AAEtD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAyEG;AACG,SAAU,gBAAgB,CAC9B,cAAsB,EACtB,WAAmB,EACnB,gBAA6C,EAC7C,MAA+B,EAAA;AAE/B,IAAA,IAAI,CAAC,cAAc,CAAC,IAAI,EAAE,EAAE;AAC1B,QAAA,MAAM,IAAI,KAAK,CACb,6DAA6D,CAC9D;IACH;IACA,MAAM,SAAS,GAAG,gBAAgB,CAAC,cAAc,EAAE,MAAM,CAAC;AAC1D,IAAA,IAAI,SAAc;AAClB,IAAA,IAAI;AACF,QAAA,SAAS,GAAG,IAAI,GAAG,CAAC,SAAS,CAAC;IAChC;AAAE,IAAA,MAAM;AACN,QAAA,MAAM,IAAI,KAAK,CAAC,yDAAyD,CAAC;IAC5E;AACA,IAAA,IAAI,SAAS,CAAC,QAAQ,KAAK,QAAQ,EAAE;AACnC,QAAA,MAAM,IAAI,KAAK,CAAC,qDAAqD,CAAC;IACxE;AACA,IAAA,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE,EAAE;AACvB,QAAA,MAAM,IAAI,KAAK,CAAC,0DAA0D,CAAC;IAC7E;IAEA,MAAM,SAAS,GAAG,QAAQ,CAAC,cAAc,CAAC,WAAW,CAAC;IACtD,IAAI,CAAC,SAAS,EAAE;AACd,QAAA,MAAM,IAAI,KAAK,CAAC,6BAA6B,WAAW,CAAA,UAAA,CAAY,CAAC;IACvE;IAEA,MAAM,cAAc,GAAG,QAAQ,CAAC,cAAc,CAAC,iBAAiB,CAAC;IACjE,IAAI,cAAc,EAAE;QAClB,cAAc,CAAC,MAAM,EAAE;IACzB;;;;;IAMA,MAAM,MAAM,GAAG,QAAQ,CAAC,aAAa,CAAC,QAAQ,CAAC;;IAG/C,sBAAsB,IAAI;IAC1B,MAAM,MAAM,GAAG,YAAY,CAAC,cAAc,CAAC,gBAAgB,EAAE,MAAM,EAAE,MAAM,EAAE;QAC3E,MAAM;QACN,MAAM,EAAE,SAAS,CAAC,MAAM;AACzB,KAAA,CAAC;AACF,IAAA,sBAAsB,GAAG,MAAM,IAAI,IAAI;;;AAIvC,IAAA,MAAM,OAAO,GAAG,CAAA,0BAAA,EAA6B,WAAW,EAAE;IAC1D,IAAI,CAAC,QAAQ,CAAC,cAAc,CAAC,OAAO,CAAC,EAAE;QACrC,MAAM,KAAK,GAAG,QAAQ,CAAC,aAAa,CAAC,OAAO,CAAC;AAC7C,QAAA,KAAK,CAAC,EAAE,GAAG,OAAO;QAClB,KAAK,CAAC,SAAS,GAAG;WACX,WAAW,CAAA;;;;;;KAMjB;AACD,QAAA,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC;IAClC;AAEA,IAAA,MAAM,CAAC,YAAY,CAAC,OAAO,EAAE,uCAAuC,CAAC;AACrE,IAAA,MAAM,CAAC,YAAY,CAAC,gBAAgB,EAAE,4BAA4B,CAAC;AACnE,IAAA,MAAM,CAAC,YAAY,CAAC,IAAI,EAAE,iBAAiB,CAAC;AAC5C,IAAA,MAAM,CAAC,KAAK,CAAC,MAAM,GAAG,GAAG;AACzB,IAAA,MAAM,CAAC,KAAK,CAAC,KAAK,GAAG,MAAM;AAC3B,IAAA,MAAM,CAAC,KAAK,CAAC,MAAM,GAAG,MAAM;AAC5B,IAAA,MAAM,CAAC,KAAK,CAAC,QAAQ,GAAG,QAAQ;AAChC,IAAA,MAAM,CAAC,GAAG,GAAG,SAAS;AACtB,IAAA,SAAS,CAAC,WAAW,CAAC,MAAM,CAAC;AAE7B,IAAA,OAAO,MAAM;AACf;;ACnKA;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4BG;AACG,SAAU,SAAS,CAAC,QAAgB,EAAE,QAAgB,EAAA;AAC1D,IAAA,IAAI,CAAC,mBAAmB,CAAC,QAAQ,CAAC,EAAE;QAClC,OAAO,CAAC,IAAI,CACV,2EAA2E;AACzE,YAAA,2EAA2E,CAC9E;QACD;IACF;IAEA,MAAM,CAAC,GAAG,QAAQ,CAAC,aAAa,CAAC,GAAG,CAAC;AACrC,IAAA,CAAC,CAAC,IAAI,GAAG,QAAQ;AACjB,IAAA,CAAC,CAAC,QAAQ,GAAG,QAAQ;AACrB,IAAA,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC;IAC5B,CAAC,CAAC,KAAK,EAAE;AACT,IAAA,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC;AAC9B;AAEA;;;;;AAKG;AACH,SAAS,mBAAmB,CAAC,KAAa,EAAA;AACxC,IAAA,OAAO,8DAA8D,CAAC,IAAI,CACxE,KAAK,CACN;AACH;;ACxDA;;;;;;;;AAQG;AACG,SAAU,YAAY,CAAC,KAA6B,EAAA;IACxD,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC;AACzC,IAAA,GAAG,CAAC,MAAM,GAAG,EAAE;AACf,IAAA,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,KAAI;QAC7C,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC;AAClC,IAAA,CAAC,CAAC;AACF,IAAA,OAAO,CAAC,YAAY,CAAC,IAAI,EAAE,EAAE,EAAE,GAAG,CAAC,QAAQ,EAAE,CAAC;AAChD;AAEA;;;;;;;;;AASG;SACa,YAAY,GAAA;IAC1B,MAAM,SAAS,GAAG,IAAI,eAAe,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC;IAC7D,MAAM,UAAU,GAA2B,EAAE;IAC7C,SAAS,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,GAAG,KAAI;AAC/B,QAAA,UAAU,CAAC,GAAG,CAAC,GAAG,KAAK;AACzB,IAAA,CAAC,CAAC;AACF,IAAA,OAAO,UAAU;AACnB;;ACnCA;;AAEG;;;;"}