Also fixes the case where UPPERCASED extension names were silently changed
to lowercase and then set as undefined. Even though uppercased extension
names are invalid, we should still accept them in incoming messsages and
only throw when validating the event.
Fixes: https://github.com/cloudevents/sdk-javascript/issues/380
Signed-off-by: Lance Ball <lball@redhat.com>
* src: be more forgiving parsing JSON as a string
A simple string is considered valid JSON. However, our parsers do
not accept that unless the string has quotation marks. This commit
modifies the parser to look for strings declared as application/json
which do not begin with '[' '{' or '"' and surrounds them with
quotes.
Signed-off-by: Lance Ball <lball@redhat.com>
The `HTTP.isEvent()` and `HTTP.toEvent()` functions both had some validation
code that violated the principle of loose validation when receiving an
event over HTTP. As discussed, the validation should be managed by the
receiver in this case with `event.validate()`
Signed-off-by: Lance Ball <lball@redhat.com>
* feat!: remove all 4.0 deprecation.
* This removes all the APIs that were deprecated in the 3.x releases and marked as "remove in 4.0".
* Also removes any tests associated with those API's
* squash: remove axios as a dependecy
Signed-off-by: Lucas Holmquist <lholmqui@redhat.com>
This commit extends Node.js IncomingHttpHeaders in our Headers type.
Changes the Headers type to make it more compatible with Node.js TypeScript projects.
Signed-off-by: Lance Ball <lball@redhat.com>
* fix: do not alter an event's data attribute
When setting an event's data attribute we were trying to be really clever
and this is problematic. Instead, keep the data attribute unchanged. Per
the 1.0 specification, the data attribute is still inspected to determine
if it is binary, and if so, a data_base64 attribute is added with the
contents of the data property encoded as base64.
Fixes: https://github.com/cloudevents/sdk-javascript/issues/343
Signed-off-by: Lance Ball <lball@redhat.com>
* feat: add emitterFactory and friends
This commit adds an emitterFactory function that returns an EmitterFunction
object. The EmitterFunction may be used to emit events over a supported
network transport layer. Currently, only HTTP is supported.
Parameters provided to the emitterFactory are the transport Binding (only
HTTP supported), the encoding mode (Mode.BINARY or Mode.STRUCTURED), and
a TransportFunction.
The implementation for emitBinary and emitStructured has been replaced
with this simple pattern and those two functions have been removed.
Example:
```js
// The endpoint URL that will receive the event
const sink = 'https://my-event-sink';
// A function that uses Axios to send a message over HTTP
function axiosEmitter(message: Message, options?: Options): Promise<unknown> {
return axios.post(sink, message.body, { headers: message.headers, ...options });
}
// Create an event emitter
const emit = emitterFactory(HTTP, Mode.BINARY, axiosEmitter);
// Emit an event, sending it to the endpoint URL
emit(new CloudEvent{ source: '/example', type: 'example' });
```
Signed-off-by: Lance Ball <lball@redhat.com>
* feat: add a constructor parameter for loose validation
This commit adds a second, optional boolean parameter to the `CloudEvent`
constructor. When `false` is provided, the event constructor will not
perform validation of the event properties, values and extension names.
This commit also modifies the ValidationError class so that the error message
string includes the JSON.stringified version of any schema validation
errors. It also makes the HTTP.toEvent() function create CloudEvent
objects with loose/no validation.
Incorporates comments from https://github.com/cloudevents/sdk-javascript/pull/328
Fixes: https://github.com/cloudevents/sdk-javascript/issues/325
Signed-off-by: Lance Ball <lball@redhat.com>
Previously, the event's `time` property could be either a string or a date.
this commit modifies that to ensure that the object can only be created with
a timestamp in string format. As long as the string is a valid date, that
can be parsed by `new Date(Date.parse(str))` then whenever the event is
serialized as JSON, the `time` attribute will be formatted as per RFC 3339.
Fixes: https://github.com/cloudevents/sdk-javascript/issues/326
Signed-off-by: Lance Ball <lball@redhat.com>
* lib(messages): Implement a 4.0 Messages and other supporting interfaces
This commit introduces the Message, Serializer and Deserializer, and Binding
interfaces used to convert a CloudEvent into a Message that can be sent across
a transport protocol. The first protocol implemented for this is HTTP, and some
of the functionality formerly in src/transport/http has been simplified,
reduced and/or moved to /src/messages/http.
Test for V1 and V3 events are in place. Conformance tests have been modified to use
these new interfaces vs. the HTTP Receiver class.
Signed-off-by: Lance Ball <lball@redhat.com>
This commit implements 4 of the 6 pending tests that were not completed
during the TypeScript rewrite. The two tests that were not implemented
were (one for each of v1 and v03):
```
it("returns a JSON string even if format is invalid");
```
I don't really know what that's supposed to be/mean, so I removed them.
Fixes: https://github.com/cloudevents/sdk-javascript/issues/232
Signed-off-by: Lance Ball <lball@redhat.com>
* Constants can now be accessed more easily from the top level import/require
users can now do `const { CONSTANTS } = require('cloudevents')`
fixes#298
Signed-off-by: Lucas Holmquist <lholmqui@redhat.com>
The schema incorrectly limits data values to only object and string. This is
incorrect, since JSON can be an array, boolean, a single number or null as well.
This commit modifies the schema to allow for array, boolean and null, and adds
tests.
Fixes: https://github.com/cloudevents/sdk-javascript/issues/280
Signed-off-by: Lance Ball <lball@redhat.com>
This commit modifies the HTTP receivers/parsers to allow for the incoming body
of an HTTP request to be empty if the event message is sent using the binary
mode. In structured mode, a `ValidationError` will still be thrown, since the
entire event must be encoded in the HTTP body.
Signed-off-by: Lance Ball <lball@redhat.com>
BREAKING CHANGE:
* Extension names are now validated during object creation. The values are defined by the specification, and can be lowercase(a-z) or digits(0-9) and must be no longer that 20 characters
Signed-off-by: Lucas Holmquist <lholmqui@redhat.com>
BREAKING CHANGE:
* This change makes the CloudEvent Read-only and validates the input during object creation.
* To augment an already created CloudEvent object, we have added a `cloneWith` method that takes attributes to add/update.
Signed-off-by: Lucas Holmquist <lholmqui@redhat.com>
Even though the underlying structured and binary receivers already sanitize
the headers, this needs to be done at the receiver.accept() level since
the headers are inspected there to determine what mode the event is being
sent as.
Signed-off-by: Lance Ball <lball@redhat.com>
This is a major rewrite of the entire codebase into TypeScript. Nearly
all tests have been retained except where behavior is significantly
different. Some highlights of these changes:
* lowercase all CloudEvent properties and fix base64 encoded data
Previously there was a format() function that would convert a CloudEvent
object into JSON with all of the properties lowercased. With this rewrite
a CloudEvent object can be converted to JSON simply with JSON.stringify().
However, in order to be compliant with the JSON representation outlined in
the spec here https://github.com/cloudevents/spec/blob/v1.0/json-format.md
all of the event properties must be all lowercase.
* lib(transport): make transport mode an Enum
* src: allow custom headers (#1)
* lib(exports): export explicitly versioned names where appropriate
* lib(cloudevent): modify ctor to accept extensions inline
* lib(cloudevent): make extensions a part of the event object
* test: convert all tests to typescript
* examples: update all examples with latest API changes
* docs: update README with latest API changes
* src: add prettier for code style and fix a lot of linting errors
* lib: move data decoding to occur within the CloudEvent object
Signed-off-by: Lance Ball <lball@redhat.com>
This commit modifies the existing TypeScript files with improved
(read: functional) typings for function parameters. This became an
issue when trying to use the module in an existing TypeScript module.
Tests for the TypeScript files have been moved to a new test folder
specifically for testing TypeScript usage via ts-node.
Signed-off-by: Lance Ball <lball@redhat.com>
This extracts all of the attributes from a `CloudEventVX` that
are not generated by the constructor (id and specversion) into their
own `CloudEventVXAttributes` interface which the `CloudEventVX`
interface extends. This allows TS devs to optionally provide `id`
and `specversion` with proper autocompletion.
Additionally, I have added a union type, `CE` in `cloudevent.ts` which
represents any of `CloudEventV1`, `CloudEventv03`, `CloudEventV1Attributes`
and `CloudEventV03Attributes` interfaces.
Finally, this commit changes all of the user facing API to be `.ts` instead
of `.js` files.
The existing documentation in `./docs` was removed. It should be replaced with generated
HTML from tsdocs, pending some other method of publishing API documentation. That will
come as a separate, docs-only PR.
Fixes: https://github.com/cloudevents/skd-javascript/issues/188
Signed-off-by: Lance Ball <lball@redhat.com>
This commit makes a substantial change to the API, changing the CloudEvent class
to accept properties as an object in the constructor. For example:
```js
const CloudEvent = require('cloudevents-sdk');
// all event properties except extensions may be set in the constructor
const event = new CloudEvent({
source: 'http://my.event.source',
type: 'test-event-type'
});
// get and set all properties standard property notation
console.log(event.time); // the event timestamp
event.subject = 'my event subject';
```
Signed-off-by: Lance Ball <lball@redhat.com>
This is a breaking change.
This commit makes a number of changes to the HTTP bindings code in an attempt
to simplify its usage and implementation. From a very high level, this inverts
the existing dependencies.
As an example, consider `lib/bindings/http/receiver_structured_1.js`.
https://github.com/cloudevents/sdk-javascript/blob/v1.0.0/lib/bindings/http/receiver_structured_0_3.js
This class instantiates `lib/bindings/http/receiver_structured.js` and delegates
its function invokations to it. This had the effect of requiring a user to know what
event versions they would be receiving. And for me personally was a little confusing
as a maintainer.
The change introduced here reverses that logic, so that the version agnostic receiver
is what the user instantiates. It instantiates the approrpiate version of a specific
receiever and delegates to it - reversing the dependencies.
I've also moved all of the top level directories related to HTTP versions into
`lib/bindings/http/v1` and `lib/bindings/http/v03` and generally done some rearranging
to make the repository structure cleaner and more organized.
Signed-off-by: Lance Ball <lball@redhat.com>
This commit pulls the constants up from the lib/bindings/http/constants.js
and exports them in the top level index.js. There are some elements of the API
where we expect users to provide constant values, and this makes it easier for
them to be sure the values they provide are what is expected.
I've also added two new constants: `BINARY` and `STRUCTURED`.
Signed-off-by: Lance Ball <lball@redhat.com>
* feat!: expose a version agnostic event emitter
This is a breaking change.
This commit exposes an HTTP based event emitter that simplifes the API.
To use it, simply import the SDK and start emitting. The default spec
version is 1.0, but you can use 0.3 by supplying that to the constructor.
By default, CloudEvents are emitted in binary mode, but this can be changed
by providing the "structured" parameter to the `send()` function.
This commit also eliminates the version specific emitters and receivers
from the `v1` and `v03` exports, and eliminates the explicit usage of
versioned emitters from `lib/bindings/http`.
Finally, the CE headers can be retrieved from the emitter for a given
event by passing the event to the `headers()` function.
Fixes: https://github.com/cloudevents/sdk-javascript/issues/124
Fixes: https://github.com/cloudevents/sdk-javascript/issues/149
Signed-off-by: Lance Ball <lball@redhat.com>
This change adds a `ValidationError` type that extends `TypeError`. Any time a `CloudEvent` cannot be received and created with the given input, this error will be thrown. Tests have all
been updated to check for the error type.
Signed-off-by: Lance Ball <lball@redhat.com>
This commit removes the require of uuid from this test and uses a
hardcoded value for the 'id' constant instead.
The motivation for this is that the value for 'id' does not need to be
generated for each test run, and fewer requires helps readabilitly I
find.
Signed-off-by: Daniel Bevenius <daniel.bevenius@gmail.com>
This commit changes the event mode detection in `HTTPReceiver` so that it will
throw a TypeError if the event mode can't be detected per the spec.
Signed-off-by: Lance Ball <lball@redhat.com>
* fix: ensure binary events can handle no content-type header
The fix provided in https://github.com/cloudevents/sdk-javascript/pull/118
only included tests for `receiver.check()`, and the change in that
case was to add the `application/json` content type to the cleansed
headers if to type was specified.
However, `receiver.parse()` did not receive the benefit of this change. It
calls `this.check()` but then sanitizes the original headers again, and the
missing content-type was not re-inserted into the newly sanitized headers.
This commit, modifies the code so that `receiver.check()` does not insert
the content-type, but does allow the validation check to pass if no
content-type header exists. When `receiver.parse()` is called, and the
headers are sanitized again - and this time used to look up parser implementation,
the default `application/json` content-is applied if no content-type header
exists.
I've also removed a redundant call to `receiver.check()` in receiver_binary_1.js
and simplified the usage of `Constants` in the test.
Signed-off-by: Lance Ball <lball@redhat.com>
* chore: clean up header sniffing
Signed-off-by: Lance Ball <lball@redhat.com>
This commit removes the unnecessary use of Promises in the 0.3 unmarshaller.
There was actually no asynchronous activity happening in that function, so
there was no need to deal with Promises, and as a result testing was made
much more difficult.
Fixes: https://github.com/cloudevents/sdk-javascript/pull/95
Signed-off-by: Lance Ball <lball@redhat.com>
Event receivers in the wild may not always know what version or mode an
incoming event is. Instead of requiring developers to inspect the headers
themselves, the SDK should provide an HTTP receiver that is capable of
figuring out what the version and mode (structured/binary) of an incoming
event is and handle it appropriately.
In determining the best way to expose this, I chose to modify the API a
little bit. Now, instead of `const CloudEvent = require('cloudevents-sdk');`
users need to destructure it.
```js
const { HTTPReceiver, CloudEvent } = require('cloudevents-sdk');
```
This change should not be backported to 1.x.
Fixes: https://github.com/cloudevents/sdk-javascript/issues/93
Signed-off-by: Lance Ball <lball@redhat.com>