text: import {devAssert, devAssertString} from '#core/assert';
  import {internalListenImplementation} from '#core/dom/event-helper-listen';
  import {rethrowAsync} from '#core/error';
  import {dict} from '#core/types/object';
  import {tryParseJson} from '#core/types/object/json';
  
  /** @const */
  const AMP_MESSAGE_PREFIX = 'amp-';
  export const CONSTANTS = {
    responseTypeSuffix: '-result',
    messageIdFieldName: 'messageId',
    payloadFieldName: 'payload',
    contentFieldName: 'content',
  };
  
  /** @enum {string} */
  export const MessageType_Enum = {
    // For amp-ad
    SEND_EMBED_STATE: 'send-embed-state',
    EMBED_STATE: 'embed-state',
    SEND_EMBED_CONTEXT: 'send-embed-context',
    EMBED_CONTEXT: 'embed-context',
    SEND_INTERSECTIONS: 'send-intersections',
    INTERSECTION: 'intersection',
    EMBED_SIZE: 'embed-size',
    EMBED_SIZE_CHANGED: 'embed-size-changed',
    EMBED_SIZE_DENIED: 'embed-size-denied',
    NO_CONTENT: 'no-content',
    GET_HTML: 'get-html',
    GET_CONSENT_STATE: 'get-consent-state',
    SIGNAL_INTERACTIVE: 'signal-interactive',
  
    // For the frame to be placed in full overlay mode for lightboxes
    FULL_OVERLAY_FRAME: 'full-overlay-frame',
    FULL_OVERLAY_FRAME_RESPONSE: 'full-overlay-frame-response',
    CANCEL_FULL_OVERLAY_FRAME: 'cancel-full-overlay-frame',
    CANCEL_FULL_OVERLAY_FRAME_RESPONSE: 'cancel-full-overlay-frame-response',
  
    // For amp-inabox
    SEND_POSITIONS: 'send-positions',
    POSITION: 'position',
  
    // For amp-analytics' iframe-transport
    SEND_IFRAME_TRANSPORT_EVENTS: 'send-iframe-transport-events',
    IFRAME_TRANSPORT_EVENTS: 'iframe-transport-events',
    IFRAME_TRANSPORT_RESPONSE: 'iframe-transport-response',
  
    // For user-error-in-iframe
    USER_ERROR_IN_IFRAME: 'user-error-in-iframe',
  
    // For amp-iframe
    SEND_CONSENT_DATA: 'send-consent-data',
    CONSENT_DATA: 'consent-data',
  };
  
  /**
   * Listens for the specified event on the element.
   * @param {!EventTarget} element
   * @param {string} eventType
   * @param {function(!Event)} listener
   * @param {Object=} opt_evtListenerOpts
   * @return {!UnlistenDef}
   */
  export function listen(element, eventType, listener, opt_evtListenerOpts) {
    return internalListenImplementation(
      element,
      eventType,
      listener,
      opt_evtListenerOpts
    );
  }
  
  /**
   * Serialize an AMP post message. Output looks like:
   * 'amp-011481323099490{"type":"position","sentinel":"12345","foo":"bar"}'
   * @param {string} type
   * @param {string} sentinel
   * @param {JsonObject=} data
   * @param {?string=} rtvVersion
   * @return {string}
   */
  export function serializeMessage(
    type,
    sentinel,
    data = dict(),
    rtvVersion = null
  ) {
    // TODO: consider wrap the data in a "data" field. { type, sentinal, data }
    const message = data;
    message['type'] = type;
    message['sentinel'] = sentinel;
    return AMP_MESSAGE_PREFIX + (rtvVersion || '') + JSON.stringify(message);
  }
  
  /**
   * Deserialize an AMP post message.
   * Returns null if it's not valid AMP message format.
   *
   * @param {*} message
   * @return {?JsonObject|undefined}
   */
  export function deserializeMessage(message) {
    if (!isAmpMessage(message)) {
      return null;
    }
    const startPos = devAssertString(message).indexOf('{');
    devAssert(startPos != -1, 'JSON missing in %s', message);
    return tryParseJson(devAssertString(message).substr(startPos), (e) => {
      rethrowAsync(
        new Error(`MESSAGING: Failed to parse message: ${message}\n${e.message}`)
      );
    });
  }
  
  /**
   *  Returns true if message looks like it is an AMP postMessage
   *  @param {*} message
   *  @return {boolean}
   */
  export function isAmpMessage(message) {
    return (
      typeof message == 'string' &&
      message.startsWith(AMP_MESSAGE_PREFIX) &&
      message.indexOf('{') != -1
    );
  }
  
  /** @typedef {{creativeId: string, message: string}} */
  export let IframeTransportEventDef;
  // An event, and the transport ID of the amp-analytics tags that
  // generated it. For instance if the creative with transport
  // ID 2 sends "hi", then an IframeTransportEventDef would look like:
  // { creativeId: "2", message: "hi" }
  // If the creative with transport ID 2 sent that, and also sent "hello",
  // and the creative with transport ID 3 sends "goodbye" then an *array* of 3
  // IframeTransportEventDef would be sent to the 3p frame like so:
  // [
  //   { creativeId: "2", message: "hi" }, // An IframeTransportEventDef
  //   { creativeId: "2", message: "hello" }, // Another
  //   { creativeId: "3", message: "goodbye" } // And another
  // ]
  