sdk-javascript/lib/cloudevent.js

319 lines
8.7 KiB
JavaScript

const Spec1 = require("./bindings/http/v1/spec_1.js");
const Spec03 = require("./bindings/http/v03/spec_0_3.js");
const Formatter = require("./formats/json/formatter.js");
const { SPEC_V1, SPEC_V03 } = require("./bindings/http/constants.js");
const { isBinary } = require("./bindings/http/validation/fun.js");
/**
* An CloudEvent describes event data in common formats to provide
* interoperability across services, platforms and systems.
* @see https://github.com/cloudevents/spec/blob/v1.0/spec.md
*/
class CloudEvent {
/**
* Creates a new CloudEvent instance
* @param {object} options CloudEvent properties as a simple object
* @param {string} options.source Identifies the context in which an event happened as a URI reference
* @param {string} options.type Describes the type of event related to the originating occurrence
* @param {string} [options.id] A unique ID for this event - if not supplied, will be autogenerated
* @param {string} [options.time] A timestamp for this event. May also be provided as a Date
* @param {string} [options.subject] Describes the subject of the event in the context of the event producer
* @param {string} [options.dataContentType] The mime content type for the event data
* @param {string} [options.dataSchema] The URI of the schema that the event data adheres to (v1.0 events)
* @param {string} [options.schemaURL] The URI of the schema that the event data adheres to (v0.3 events)
* @param {string} [options.dataContentEncoding] The content encoding for the event data (v0.3 events)
* @param {string} [options.specversion] The CloudEvent specification version for this event - default: 1.0
* @param {*} [options.data] The event payload
*/
constructor({
id,
source,
type,
dataContentType,
time,
subject,
dataSchema,
schemaURL,
dataContentEncoding,
data,
specversion = SPEC_V1 } = {
id: undefined,
source: undefined,
type: undefined,
dataContentType: undefined,
time: undefined,
subject: undefined,
dataSchema: undefined,
schemaURL: undefined,
dataContentEncoding: undefined,
data: undefined
}) {
if (!type || !source) {
throw new TypeError("event type and source are required");
}
switch (specversion) {
case SPEC_V1:
this.spec = new Spec1();
break;
case SPEC_V03:
this.spec = new Spec03();
break;
default:
throw new TypeError(`unknown specification version ${specversion}`);
}
this.source = source;
this.type = type;
this.dataContentType = dataContentType;
this.data = data;
this.subject = subject;
if (dataSchema) {
this.dataSchema = dataSchema;
}
// TODO: Deprecated in 1.0
if (dataContentEncoding) {
this.dataContentEncoding = dataContentEncoding;
}
// TODO: Deprecated in 1.0
if (schemaURL) {
this.schemaURL = schemaURL;
}
if (id) {
this.id = id;
}
if (time) {
this.time = time;
}
this.formatter = new Formatter();
}
/**
* Gets or sets the event id. Source + id must be unique for each distinct event.
* @see https://github.com/cloudevents/spec/blob/master/spec.md#id
* @type {string}
*/
get id() {
return this.spec.id;
}
set id(id) {
this.spec.id = id;
}
/**
* Gets or sets the origination source of this event as a URI.
* @type {string}
* @see https://github.com/cloudevents/spec/blob/master/spec.md#source-1
*/
get source() {
return this.spec.source;
}
set source(source) {
this.spec.source = source;
}
/**
* Gets the CloudEvent specification version
* @type {string}
* @see https://github.com/cloudevents/spec/blob/master/spec.md#specversion
*/
get specversion() {
return this.spec.specversion;
}
/**
* Gets or sets the event type
* @type {string}
* @see https://github.com/cloudevents/spec/blob/master/spec.md#type
*/
get type() {
return this.spec.type;
}
set type(type) {
this.spec.type = type;
}
/**
* Gets or sets the content type of the data value for this event
* @type {string}
* @see https://github.com/cloudevents/spec/blob/master/spec.md#datacontenttype
*/
get dataContentType() {
return this.spec.dataContentType;
}
set dataContentType(contenttype) {
this.spec.dataContentType = contenttype;
}
/**
* Gets or sets the event's data schema
* @type {string}
* @see https://github.com/cloudevents/spec/blob/v1.0/spec.md#dataschema
*/
get dataSchema() {
if (this.spec instanceof Spec1) {
return this.spec.dataSchema;
}
throw new TypeError("cannot get dataSchema from version 0.3 event");
}
set dataSchema(dataschema) {
if (this.spec instanceof Spec1) {
this.spec.dataSchema = dataschema;
} else {
throw new TypeError("cannot set dataSchema on version 0.3 event");
}
}
/**
* Gets or sets the event's data content encoding
* @type {string}
* @see https://github.com/cloudevents/spec/blob/v0.3/spec.md#datacontentencoding
*/
get dataContentEncoding() {
if (this.spec instanceof Spec03) {
return this.spec.dataContentEncoding;
}
throw new TypeError("cannot get dataContentEncoding from version 1.0 event");
}
set dataContentEncoding(dataContentEncoding) {
if (this.spec instanceof Spec03) {
this.spec.dataContentEncoding = dataContentEncoding;
} else {
throw new TypeError("cannot set dataContentEncoding on version 1.0 event");
}
}
/**
* Gets or sets the event subject
* @type {string}
* @see https://github.com/cloudevents/spec/blob/v1.0/spec.md#subject
*/
get subject() {
return this.spec.subject;
}
set subject(subject) {
this.spec.subject = subject;
}
/**
* Gets or sets the timestamp for this event as an ISO formatted date string
* @type {string}
* @see https://github.com/cloudevents/spec/blob/master/spec.md#time
*/
get time() {
return this.spec.time;
}
set time(time) {
this.spec.time = new Date(time).toISOString();
}
/**
* DEPRECATED: Gets or sets the schema URL for this event. Throws {TypeError}
* if this is a version 1.0 event.
* @type {string}
* @see https://github.com/cloudevents/spec/blob/v0.3/spec.md#schemaurl
*/
get schemaURL() {
if (this.spec instanceof Spec03) {
return this.spec.schemaURL;
}
throw new TypeError("cannot get schemaURL from version 1.0 event");
}
// TODO: Deprecated in 1.0
set schemaURL(schemaurl) {
if (schemaurl && (this.spec instanceof Spec03)) {
this.spec.schemaURL = schemaurl;
} else if (schemaurl) {
throw new TypeError("cannot set schemaURL on version 1.0 event");
}
}
/**
* Gets or sets the data for this event
* @see https://github.com/cloudevents/spec/blob/master/spec.md#event-data
* @type {*}
*/
get data() {
return this.spec.data;
}
set data(data) {
this.spec.data = data;
}
/**
* Formats 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
* @throws {ValidationError} if this event cannot be validated against the specification
*/
format() {
this.spec.check();
const payload = {
data: undefined,
data_base64: undefined,
...this.spec.payload
};
// Handle when is binary, creating the data_base64
if (isBinary(payload.data)) {
// TODO: The call to this.spec.data formats the binary data
// I think having a side effect like this is an anti-pattern.
// FIXIT
payload.data_base64 = this.spec.data;
delete payload.data;
} else {
delete payload.data_base64;
}
return this.formatter.format(payload);
}
/**
* Formats the CloudEvent as JSON. No specification validation is performed.
* @returns {string} the CloudEvent as a JSON string
*/
toString() {
return this.formatter.toString(this.spec.payload);
}
/**
* Adds an extension attribute to this CloudEvent
* @see https://github.com/cloudevents/spec/blob/master/spec.md#extension-context-attributes
* @param {string} key the name of the extension attribute
* @param {*} value the value of the extension attribute
* @returns {void}
*/
addExtension(key, value) {
this.spec.addExtension(key, value);
this.extensions = { [key]: value, ...this.extensions };
}
/**
* 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 {}
*/
getExtensions() {
return this.extensions;
}
}
module.exports = CloudEvent;