cloudevent.js

const Spec = require("./specs/spec_1.js");
const Formatter = require("./formats/json/formatter.js");

/**
 * An instance of a CloudEvent.
 */
class CloudEvent {
  /**
   * Creates a new CloudEvent instance
   * @param {Spec} [UserSpec] A CloudEvent version specification
   * @param {Formatter} [UserFormatter] Converts the event into a readable string
   */
  constructor(UserSpec, UserFormatter) {
    this.spec = (UserSpec) ? new UserSpec(CloudEvent) : new Spec(CloudEvent);
    this.formatter = (UserFormatter) ? new UserFormatter() : new Formatter();

    // The map of extensions
    this.extensions = {};
  }

  /**
   * Get the formatters available to this CloudEvent
   * @returns {Object} a JSON formatter
   */
  getFormats() {
    return { json: Formatter };
  }

  /**
   * Format the CloudEvent as JSON. Validates the event according
   * to the CloudEvent specification and throws an exception if
   * it's invalid.
   * @returns {JSON} the CloudEvent in JSON form
   */
  format() {
    // Check the constraints
    this.spec.check();

    // To run asData()
    this.getData();

    // Then, format
    return this.formatter.format(this.spec.payload);
  }

  /**
   * Formats the CLoudEvent as JSON. No specification validation
   * is performed.
   * @returns {JSON} the CloudEvent in JSON form
   */
  toString() {
    return this.formatter.toString(this.spec.payload);
  }

  /**
   * Sets the event type
   * @see https://github.com/cloudevents/spec/blob/master/spec.md#type
   * @param {string} type the type of event related to the originating source
   * @returns {CloudEvent} this CloudEvent
   */
  type(type) {
    this.spec.type(type);
    return this;
  }

  /**
   * Gets the event type
   * @see https://github.com/cloudevents/spec/blob/master/spec.md#type
   * @returns {String} the type of event related to the originating source
   */
  getType() {
    return this.spec.getType();
  }

  // TODO: The fact that this is exposed is problematic, given that it's
  // immutable and this method will have no effect. The specification
  // version is determined via the constructor - specifically the use
  // of cloud event creator functions in /v03 and /v1. By default this
  // object is created as a version 1.0 CloudEvent. Not documenting.
  specversion(version) {
    return this.spec.specversion(version);
  }

  /**
   * Gets the CloudEvent specification version
   * @see https://github.com/cloudevents/spec/blob/master/spec.md#specversion
   * @returns {string} The CloudEvent version that this event adheres to
   */
  getSpecversion() {
    return this.spec.getSpecversion();
  }

  /**
   * Sets the origination source of this event.
   * @see https://github.com/cloudevents/spec/blob/master/spec.md#source-1
   * @param {URI} source the context in which the event happened
   * @returns {CloudEvent} this CloudEvent instance
   */
  source(source) {
    this.spec.source(source);
    return this;
  }

  /**
   * Gets the origination source of this event.
   * @see https://github.com/cloudevents/spec/blob/master/spec.md#source-1
   * @returns {string} the event source
   */
  getSource() {
    return this.spec.getSource();
  }

  /**
   * Sets the event id. Source + id must be unique for each distinct event.
   * @see https://github.com/cloudevents/spec/blob/master/spec.md#id
   * @param {string} id source+id must be unique for each distinct event
   * @returns {CloudEvent} this CloudEvent instance
   */
  id(id) {
    this.spec.id(id);
    return this;
  }

  /**
   * Gets the event id.
   * @returns {string} the event id
   */
  getId() {
    return this.spec.getId();
  }

  /**
   * Sets the timestamp for this event
   * @see https://github.com/cloudevents/spec/blob/master/spec.md#time
   * @param {Date} time timestamp when the event occurred
   * @returns {CloudEvent} this CloudEvent instance
   */
  time(time) {
    // TODO: Ensure that this is represented as a Date internally,
    // or update the JSDoc
    this.spec.time(time);
    return this;
  }

  /**
   * Gets the timestamp for this event
   * @see https://github.com/cloudevents/spec/blob/master/spec.md#time
   * @returns {Date} the timestamp for this event
   */
  getTime() {
    // TODO: Ensure that this is represented as a Date internally,
    // or update the JSDoc
    return this.spec.getTime();
  }

  // TODO: Deprecated in 1.0
  schemaurl(schemaurl) {
    this.spec.schemaurl(schemaurl);
    return this;
  }

  // TODO: Deprecated in 1.0
  getSchemaurl() {
    return this.spec.getSchemaurl();
  }

  /**
   * Sets the content type of the data value for this event
   * @see https://github.com/cloudevents/spec/blob/master/spec.md#datacontenttype
   * @param {string} contenttype per https://tools.ietf.org/html/rfc2046
   * @returns {CloudEvent} this CloudEvent instance
   */
  dataContenttype(contenttype) {
    this.spec.dataContenttype(contenttype);
    return this;
  }

  /**
   * Gets the content type of the data value for this event
   * @see https://github.com/cloudevents/spec/blob/master/spec.md#datacontenttype
   * @returns {string} the content type for the data in this event
   */
  getDataContenttype() {
    return this.spec.getDataContenttype();
  }

  /**
   * Sets the data for this event
   * @see https://github.com/cloudevents/spec/blob/master/spec.md#event-data
   * @param {*} data any data associated with this event
   * @returns {CloudEvent} this CloudEvent instance
   */
  data(data) {
    this.spec.data(data);
    return this;
  }

  /**
   * Gets any data that has been set for this event
   * @see https://github.com/cloudevents/spec/blob/master/spec.md#event-data
   * @returns {*} any data set for this event
   */
  getData() {
    return this.spec.getData();
  }

  /**
   * Adds an extension attribute to this CloudEvent
   * @see https://github.com/cloudevents/spec/blob/master/spec.md#extension-context-attributes
   * @param {*} key the name of the exteneion attribute
   * @param {*} value the value of the extension attribute
   * @returns {CloudEvent} this CloudEvent instance
   */
  addExtension(key, value) {
    this.spec.addExtension(key, value);

    // Stores locally
    this.extensions[key] = value;

    return this;
  }

  /**
   * Gets the extension attributes, if any, associated with this event
   * @see https://github.com/cloudevents/spec/blob/master/spec.md#extension-context-attributes
   * @returns {Object} the extensions attributes - if none exist will will be {}
   * // TODO - this should return null or undefined if no extensions
   */
  getExtensions() {
    return this.extensions;
  }
}

module.exports = CloudEvent;