All files / elements/EventStream EventStream.element.js

96.36% Statements 53/55
90% Branches 18/20
100% Functions 10/10
95.91% Lines 47/49

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132        19x   38x         19x 19x 19x 19x 19x     19x           1x 19x             15x 15x 13x   15x 12x 3x 2x   2x   1x     15x 15x 15x 15x 13x 13x             3x 1x   2x 1x 1x 1x                     13x       13x             15x   15x 2x 1x 1x               1x   1x   1x 1x   1x           1x   1x                   200x 200x            
/**
 * @param {import('./types').ElementImports} $inject
 */
function eventStream_injector($inject) {
  const { appConfig, HTMLElement, logger, document, window } = $inject;
 
  return class MastercardEventStream extends HTMLElement {
    /**
     * @constructor
     * @type {import('./types').ElementExports['constructor']}
     */
    constructor() {
      super();
      this.eventStreamId = null;
      this.formId = null;
      this.events = new EventTarget();
    }
    // - Static methods
    /**
     * @static
     * @type {import('./types').ElementExports['observedAttributes']}
     */
    static get observedAttributes() {
      // @ts-ignore
      return ['event-stream-id', 'form-id'];
    }
 
    // - Lifecycle Events
    /**
     * @type {import('./types').ElementExports['connectedCallback']}
     */
    connectedCallback() {
      const $elem = this;
      if (!this.eventStreamId) {
        this.eventStreamId = $elem.getAttribute('event-stream-id');
      }
      if (!this.formId && $elem.getAttribute('form-id')) {
        this.formId = $elem.getAttribute('form-id');
      } else if (!this.formId) {
        try {
          // This doesn't exist in the oauth rediretion flow
          this.formId = $elem.closest('mastercard-form').getAttribute('id');
        } catch (err) {
          this.formId = 'default';
        }
      }
      this.iframe = document.createElement('iframe');
      $elem.append(this.iframe);
      $elem.style.display = 'none';
      if (this.eventStreamId) {
        this._bindFrameSource();
        this._registerEventListener();
      }
    }
    /**
     * @type {import('./types').ElementExports['attributeChangedCallback']}
     */
    attributeChangedCallback(name, _oldValue, newValue) {
      if (!this.isConnected) {
        return;
      }
      if (name === 'event-stream-id') {
        this.eventStreamId = newValue;
        this._bindFrameSource();
        this._registerEventListener();
      }
    }
 
    // - Custom Methods
 
    /**
     * @access private
     * @type {import('./types').ElementExports['_bindFrameSource']}
     */
    _bindFrameSource() {
      const frameSource = `${appConfig.getSDKBase()}/frames/parent/forms/event-stream.html?event-stream-id=${
        this.eventStreamId
      }&form-id=${this.formId}`;
      // @ts-ignore
      this.iframe.setAttribute('src', frameSource);
    }
 
    /**
     * @access private
     * @type {import('./types').ElementExports['_registerEventListener']}
     */
    _registerEventListener() {
      // @ts-ignore
      window.addEventListener('message', (event) => {
        if (event.origin !== appConfig.getFrameOrigin()) {
          logger.warn(`Skipping message from ${event.origin}`);
          return;
        }
        /*
        There is some conversion that needs to happen here to make this event not look really messy.
        First, we create a local event (instead of an SSE event), then we use the eventType from the
        payload to determine the kind of event to send. Then we add the id of the event. Then we clear
        out the payload of those values so we don't have duplicates
        */
        const newEvent = new Event(event.data.eventType);
        // @ts-ignore
        newEvent.data = (event.data || {}).data;
        // @ts-ignore
        newEvent.id = (event.data || {}).id;
        try {
          // @ts-ignore
          delete newEvent.data.isPublic;
          // @ts-ignore
          delete newEvent.data.eventType;
          // @ts-ignore
          delete newEvent.data.id;
        } catch (err) {
          logger.warn(err);
        }
        this.events.dispatchEvent(newEvent);
      });
    }
 
    /**
     * @method
     * @type {import('./types').ElementExports['_isValidEventStreamId']}
     */
    _isValidEventStreamId(id) {
      const isValid =
        /^[0-9a-f]{8}-[0-9a-f]{4}-[0-5][0-9a-f]{3}-[089ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
      return isValid.test(id);
    }
  };
}
 
export { eventStream_injector };