Skip to content

src!: remove support for 0.3 events #425

New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Merged
merged 1 commit into from
Aug 27, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

21 changes: 4 additions & 17 deletions src/event/cloudevent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,7 @@
import { v4 as uuidv4 } from "uuid";
import { Emitter } from "..";

import {
CloudEventV03,
CloudEventV03Attributes,
CloudEventV03OptionalAttributes,
CloudEventV1,
CloudEventV1Attributes,
CloudEventV1OptionalAttributes,
} from "./interfaces";
import { CloudEventV1, CloudEventV1Attributes, CloudEventV1OptionalAttributes } from "./interfaces";
import { validateCloudEvent } from "./spec";
import { ValidationError, isBinary, asBase64, isValidType } from "./validation";

Expand All @@ -30,7 +23,7 @@ export const enum Version {
* interoperability across services, platforms and systems.
* @see https://github.com/cloudevents/spec/blob/v1.0/spec.md
*/
export class CloudEvent implements CloudEventV1, CloudEventV03 {
export class CloudEvent implements CloudEventV1 {
id: string;
type: string;
source: string;
Expand Down Expand Up @@ -58,7 +51,7 @@ export class CloudEvent implements CloudEventV1, CloudEventV03 {
* @param {object} event the event properties
* @param {boolean?} strict whether to perform event validation when creating the object - default: true
*/
constructor(event: CloudEventV1 | CloudEventV1Attributes | CloudEventV03 | CloudEventV03Attributes, strict = true) {
constructor(event: CloudEventV1 | CloudEventV1Attributes, strict = true) {
// copy the incoming event so that we can delete properties as we go
// everything left after we have deleted know properties becomes an extension
const properties = { ...event };
Expand Down Expand Up @@ -197,13 +190,7 @@ See: https://github.com/cloudevents/spec/blob/v1.0/spec.md#type-system`);
* @return {CloudEvent} returns a new CloudEvent
*/
public cloneWith(
options:
| CloudEventV1
| CloudEventV1Attributes
| CloudEventV1OptionalAttributes
| CloudEventV03
| CloudEventV03Attributes
| CloudEventV03OptionalAttributes,
options: CloudEventV1 | CloudEventV1Attributes | CloudEventV1OptionalAttributes,
strict = true,
): CloudEvent {
return new CloudEvent(Object.assign({}, this.toJSON(), options) as CloudEvent, strict);
Expand Down
136 changes: 0 additions & 136 deletions src/event/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -140,139 +140,3 @@ export interface CloudEventV1OptionalAttributes {
*/
[key: string]: unknown;
}

/**
* The object interface for CloudEvents 0.3.
* @see https://github.com/cloudevents/spec/blob/v0.3/spec.md
*/

export interface CloudEventV03 extends CloudEventV03Attributes {
// REQUIRED Attributes
/**
* [REQUIRED] Identifies the event. Producers MUST ensure that `source` + `id`
* is unique for each distinct event. If a duplicate event is re-sent (e.g. due
* to a network error) it MAY have the same `id`. Consumers MAY assume that
* Events with identical `source` and `id` are duplicates.
* @required Non-empty string. Unique within producer.
* @example An event counter maintained by the producer
* @example A UUID
*/
id: string;
/**
* [REQUIRED] The version of the CloudEvents specification which the event
* uses. This enables the interpretation of the context. Compliant event
* producers MUST use a value of `1.0` when referring to this version of the
* specification.
* @required MUST be a non-empty string.
*/
specversion: string;
}

export interface CloudEventV03Attributes extends CloudEventV03OptionalAttributes {
/**
* [REQUIRED] Identifies the context in which an event happened. Often this
* will include information such as the type of the event source, the
* organization publishing the event or the process that produced the event. The
* exact syntax and semantics behind the data encoded in the URI is defined by
* the event producer.
* Producers MUST ensure that `source` + `id` is unique for each distinct event.
* An application MAY assign a unique `source` to each distinct producer, which
* makes it easy to produce unique IDs since no other producer will have the same
* source. The application MAY use UUIDs, URNs, DNS authorities or an
* application-specific scheme to create unique `source` identifiers.
* A source MAY include more than one producer. In that case the producers MUST
* collaborate to ensure that `source` + `id` is unique for each distinct event.
* @required Non-empty URI-reference
*/
source: string;
/**
* [REQUIRED] This attribute contains a value describing the type of event
* related to the originating occurrence. Often this attribute is used for
* routing, observability, policy enforcement, etc. The format of this is
* producer defined and might include information such as the version of the
* `type` - see
* [Versioning of Attributes in the Primer](primer.md#versioning-of-attributes)
* for more information.
* @required MUST be a non-empty string
* @should SHOULD be prefixed with a reverse-DNS name. The prefixed domain dictates the
* organization which defines the semantics of this event type.
* @example com.github.pull.create
* @example com.example.object.delete.v2
*/
type: string;
}

export interface CloudEventV03OptionalAttributes {
/**
* The following fields are optional.
*/

/**
* [OPTIONAL] Describes the content encoding for the data attribute for when the
* data field MUST be encoded as a string, like with structured transport binding
* modes using the JSON event format, but the datacontenttype indicates a non-string
* media type. When the data field's effective data type is not String, this attribute
* MUST NOT be set and MUST be ignored when set.
*/
datacontentencoding?: string;

/**
* [OPTIONAL] Content type of `data` value. This attribute enables `data` to
* carry any type of content, whereby format and encoding might differ from that
* of the chosen event format. For example, an event rendered using the
* [JSON envelope](./json-format.md#3-envelope) format might carry an XML payload
* in `data`, and the consumer is informed by this attribute being set to
* "application/xml". The rules for how `data` content is rendered for different
* `datacontenttype` values are defined in the event format specifications; for
* example, the JSON event format defines the relationship in
* [section 3.1](./json-format.md#31-handling-of-data).
*/
datacontenttype?: string;
/**
* [OPTIONAL] A link to the schema that the data attribute adheres to.
* Incompatible changes to the schema SHOULD be reflected by a different URL.
* If present, MUST be a non-empty URI.
*/
schemaurl?: string;
/**
* [OPTIONAL] This describes the subject of the event in the context of the
* event producer (identified by `source`). In publish-subscribe scenarios, a
* subscriber will typically subscribe to events emitted by a `source`, but the
* `source` identifier alone might not be sufficient as a qualifier for any
* specific event if the `source` context has internal sub-structure.
*
* Identifying the subject of the event in context metadata (opposed to only in
* the `data` payload) is particularly helpful in generic subscription filtering
* scenarios where middleware is unable to interpret the `data` content. In the
* above example, the subscriber might only be interested in blobs with names
* ending with '.jpg' or '.jpeg' and the `subject` attribute allows for
* constructing a simple and efficient string-suffix filter for that subset of
* events.
*
* If present, MUST be a non-empty string.
* @example "https://example.com/storage/tenant/container"
* @example "mynewfile.jpg"
*/
subject?: string;
/**
* [OPTIONAL] Timestamp of when the occurrence happened. If the time of the
* occurrence cannot be determined then this attribute MAY be set to some other
* time (such as the current time) by the CloudEvents producer, however all
* producers for the same `source` MUST be consistent in this respect. In other
* words, either they all use the actual time of the occurrence or they all use
* the same algorithm to determine the value used.
* @example "2020-08-08T14:48:09.769Z"
*/
time?: string;
/**
* [OPTIONAL] The event payload. This specification does not place any restriction
* on the type of this information. It is encoded into a media format which is
* specified by the datacontenttype attribute (e.g. application/json), and adheres
* to the dataschema format when those respective attributes are present.
*/
data?: Record<string, unknown | string | number | boolean> | string | number | boolean | null | unknown;
/**
* [OPTIONAL] CloudEvents extension attributes.
*/
[key: string]: unknown;
}
73 changes: 0 additions & 73 deletions src/event/schemas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,76 +83,3 @@ export const schemaV1 = {
},
type: "object",
};

export const schemaV03 = {
$ref: "#/definitions/event",
definitions: {
specversion: {
const: "0.3",
},
datacontenttype: {
type: "string",
},
data: {
type: ["object", "string", "array", "number", "boolean", "null"],
},
event: {
properties: {
specversion: {
$ref: "#/definitions/specversion",
},
datacontenttype: {
$ref: "#/definitions/datacontenttype",
},
data: {
$ref: "#/definitions/data",
},
id: {
$ref: "#/definitions/id",
},
time: {
$ref: "#/definitions/time",
},
schemaurl: {
$ref: "#/definitions/schemaurl",
},
subject: {
$ref: "#/definitions/subject",
},
type: {
$ref: "#/definitions/type",
},
source: {
$ref: "#/definitions/source",
},
},
required: ["specversion", "id", "type", "source"],
type: "object",
},
id: {
type: "string",
minLength: 1,
},
time: {
format: "js-date-time",
type: "string",
},
schemaurl: {
type: "string",
format: "uri-reference",
},
subject: {
type: "string",
minLength: 1,
},
type: {
type: "string",
minLength: 1,
},
source: {
format: "uri-reference",
type: "string",
},
},
type: "object",
};
34 changes: 6 additions & 28 deletions src/event/spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,14 @@
SPDX-License-Identifier: Apache-2.0
*/

import Ajv from "ajv";
import { ValidationError, isBase64 } from "./validation";
import Ajv, { Options } from "ajv";
import { ValidationError } from "./validation";

import { CloudEventV1, CloudEventV03 } from "./interfaces";
import { schemaV03, schemaV1 } from "./schemas";
import { CloudEventV1 } from "./interfaces";
import { schemaV1 } from "./schemas";
import { Version } from "./cloudevent";
import CONSTANTS from "../constants";

const ajv = new Ajv({ extendRefs: true });
const ajv = new Ajv({ extendRefs: true } as Options);

// handle date-time format specially because a user could pass
// Date().toString(), which is not spec compliant date-time format
Expand All @@ -21,18 +20,12 @@ ajv.addFormat("js-date-time", function (dateTimeString) {
});

const isValidAgainstSchemaV1 = ajv.compile(schemaV1);
const isValidAgainstSchemaV03 = ajv.compile(schemaV03);

export function validateCloudEvent(event: CloudEventV03 | CloudEventV1): boolean {
export function validateCloudEvent(event: CloudEventV1): boolean {
if (event.specversion === Version.V1) {
if (!isValidAgainstSchemaV1(event)) {
throw new ValidationError("invalid payload", isValidAgainstSchemaV1.errors);
}
} else if (event.specversion === Version.V03) {
if (!isValidAgainstSchemaV03(event)) {
throw new ValidationError("invalid payload", isValidAgainstSchemaV03.errors);
}
checkDataContentEncoding(event);
} else {
return false;
}
Expand All @@ -44,18 +37,3 @@ export function validateCloudEvent(event: CloudEventV03 | CloudEventV1): boolean
}
return true;
}

function checkDataContentEncoding(event: CloudEventV03): boolean {
if (event.datacontentencoding) {
// we only support base64
const encoding = event.datacontentencoding.toLocaleLowerCase();
if (encoding !== CONSTANTS.ENCODING_BASE64) {
throw new ValidationError("invalid payload", [`Unsupported content encoding: ${encoding}`]);
} else {
if (!isBase64(event.data)) {
throw new ValidationError("invalid payload", [`Invalid content encoding of data: ${event.data}`]);
}
}
}
return true;
}
4 changes: 1 addition & 3 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

import { CloudEvent, Version } from "./event/cloudevent";
import { ValidationError } from "./event/validation";
import { CloudEventV03, CloudEventV03Attributes, CloudEventV1, CloudEventV1Attributes } from "./event/interfaces";
import { CloudEventV1, CloudEventV1Attributes } from "./event/interfaces";

import { Options, TransportFunction, EmitterFunction, emitterFor, Emitter } from "./transport/emitter";
import { Headers, Mode, Binding, HTTP, Message, Serializer, Deserializer } from "./message";
Expand All @@ -15,8 +15,6 @@ import CONSTANTS from "./constants";
export {
// From event
CloudEvent,
CloudEventV03,
CloudEventV03Attributes,
CloudEventV1,
CloudEventV1Attributes,
Version,
Expand Down
6 changes: 3 additions & 3 deletions src/message/http/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
SPDX-License-Identifier: Apache-2.0
*/

import { CloudEvent, CloudEventV03, CloudEventV1, CONSTANTS, Mode, Version } from "../..";
import { CloudEvent, CloudEventV1, CONSTANTS, Mode, Version } from "../..";
import { Message, Headers } from "..";

import {
Expand Down Expand Up @@ -187,7 +187,7 @@ function parseBinary(message: Message, version: Version): CloudEvent {
delete eventObj.datacontentencoding;
}

return new CloudEvent({ ...eventObj, data: body } as CloudEventV1 | CloudEventV03, false);
return new CloudEvent({ ...eventObj, data: body } as CloudEventV1, false);
}

/**
Expand Down Expand Up @@ -240,5 +240,5 @@ function parseStructured(message: Message, version: Version): CloudEvent {
delete eventObj.data_base64;
delete eventObj.datacontentencoding;
}
return new CloudEvent(eventObj as CloudEventV1 | CloudEventV03, false);
return new CloudEvent(eventObj as CloudEventV1, false);
}
Loading