Compare commits

..

No commits in common. "main" and "v6.0.0" have entirely different histories.
main ... v6.0.0

37 changed files with 9469 additions and 5302 deletions

View File

@ -8,10 +8,10 @@ jobs:
steps: steps:
- -
name: Checkout name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v2
- -
name: Generate API documentation name: Generate API documentation
run: npm install && npm run build:schema && npm run generate-docs run: npm install && npm run generate-docs
- -
name: Deploy to GitHub Pages name: Deploy to GitHub Pages
if: success() if: success()

View File

@ -15,12 +15,12 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
strategy: strategy:
matrix: matrix:
node-version: [20.x, 22.x, 24.x] node-version: [12.x, 14.x, 16.x]
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v2
- name: Test on Node.js ${{ matrix.node-version }} - name: Test on Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4 uses: actions/setup-node@v1
with: with:
node-version: ${{ matrix.node-version }} node-version: ${{ matrix.node-version }}
- run: npm ci - run: npm ci
@ -31,18 +31,18 @@ jobs:
name: Code coverage name: Code coverage
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v2
with: with:
submodules: true submodules: true
- name: Generate coverage report - name: Generate coverage report
uses: actions/setup-node@v4 uses: actions/setup-node@v1
with: with:
node-version: 22.x node-version: 16.x
- run: npm ci - run: npm ci
- run: npm run build --if-present - run: npm run build --if-present
- run: npm run coverage - run: npm run coverage
- name: Upload coverage report to storage - name: Upload coverage report to storage
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v1
with: with:
name: coverage name: coverage
path: coverage/lcov.info path: coverage/lcov.info
@ -52,15 +52,15 @@ jobs:
needs: coverage needs: coverage
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v2
- name: Download coverage report from storage - name: Download coverage report from storage
uses: actions/download-artifact@v4 uses: actions/download-artifact@v1
with: with:
name: coverage name: coverage
- name: Upload coverage report to codacy - name: Upload coverage report to codacy
uses: actions/setup-node@v4 uses: actions/setup-node@v1
with: with:
node-version: 22.x node-version: 16.x
- run: | - run: |
( [[ "${CODACY_PROJECT_TOKEN}" != "" ]] && npm run coverage-publish ) || echo "Coverage report not published" ( [[ "${CODACY_PROJECT_TOKEN}" != "" ]] && npm run coverage-publish ) || echo "Coverage report not published"
env: env:

View File

@ -1,21 +0,0 @@
name: Publish to npmjs
on:
release:
types: [created]
jobs:
build:
runs-on: ubuntu-latest
permissions:
contents: read
id-token: write
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '22.x'
registry-url: 'https://registry.npmjs.org'
- run: npm install -g npm
- run: npm ci
- run: npm publish --provenance --access public
env:
NODE_AUTH_TOKEN: ${{ secrets.CLOUDEVENTS_PUBLISH }}

View File

@ -7,11 +7,9 @@ jobs:
release-please: release-please:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: GoogleCloudPlatform/release-please-action@v3 - uses: GoogleCloudPlatform/release-please-action@v2.5.5
id: release
with: with:
token: ${{ secrets.CLOUDEVENTS_RELEASES_TOKEN }} token: ${{ secrets.GITHUB_TOKEN }}
release-type: node release-type: node
package-name: cloudevents package-name: cloudevents
signoff: "Lucas Holmquist <lholmqui@redhat.com>"
changelog-types: '[{"type":"feat","section":"Features","hidden":false},{"type":"fix","section":"Bug Fixes","hidden":false},{"type":"docs","section":"Documentation","hidden":false},{"type":"chore","section":"Miscellaneous","hidden":false},{"type":"src","section":"Miscellaneous","hidden":false},{"type":"style","section":"Miscellaneous","hidden":false},{"type":"refactor","section":"Miscellaneous","hidden":false},{"type":"perf","section":"Performance","hidden":false},{"type":"test","section":"Tests","hidden":false}]' changelog-types: '[{"type":"feat","section":"Features","hidden":false},{"type":"fix","section":"Bug Fixes","hidden":false},{"type":"docs","section":"Documentation","hidden":false},{"type":"chore","section":"Miscellaneous","hidden":false},{"type":"src","section":"Miscellaneous","hidden":false},{"type":"style","section":"Miscellaneous","hidden":false},{"type":"refactor","section":"Miscellaneous","hidden":false},{"type":"perf","section":"Performance","hidden":false},{"type":"test","section":"Tests","hidden":false}]'

3
.gitignore vendored
View File

@ -91,6 +91,3 @@ typings/
# Package lock # Package lock
package-lock.json package-lock.json
# Jetbrains IDE directories
.idea

View File

@ -2,160 +2,6 @@
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
## [9.0.0](https://github.com/cloudevents/sdk-javascript/compare/v8.0.3...v9.0.0) (2025-04-03)
### ⚠ BREAKING CHANGES
* remove node 16 ([#610](https://github.com/cloudevents/sdk-javascript/issues/610))
### Features
* remove node 16 ([#610](https://github.com/cloudevents/sdk-javascript/issues/610)) ([3ff6fdd](https://github.com/cloudevents/sdk-javascript/commit/3ff6fdd3bf1a9d77be9cd1d1ed589de47a86f7c1))
## [8.0.3](https://github.com/cloudevents/sdk-javascript/compare/v8.0.2...v8.0.3) (2025-04-02)
### Bug Fixes
* add generics to `Binding` type ([#604](https://github.com/cloudevents/sdk-javascript/issues/604)) ([f475cdf](https://github.com/cloudevents/sdk-javascript/commit/f475cdfd7ee7e80a375b997ba2f41b1655a44a03))
## [8.0.2](https://github.com/cloudevents/sdk-javascript/compare/v8.0.1...v8.0.2) (2024-07-22)
### Bug Fixes
* creating an event does not error when the event attribute name is too long ([#593](https://github.com/cloudevents/sdk-javascript/issues/593)) ([6977113](https://github.com/cloudevents/sdk-javascript/commit/6977113d7b49bd2b702632cc09e29cc0c003e2a1))
## [8.0.1](https://github.com/cloudevents/sdk-javascript/compare/v8.0.0...v8.0.1) (2024-06-12)
### Bug Fixes
* allow Node 22 and use it by default ([#587](https://github.com/cloudevents/sdk-javascript/issues/587)) ([e762607](https://github.com/cloudevents/sdk-javascript/commit/e7626077ed22b2bcbfa71b0403a58ac187c57cba))
### Miscellaneous
* Update compatible node version ([#573](https://github.com/cloudevents/sdk-javascript/issues/573)) ([245bae9](https://github.com/cloudevents/sdk-javascript/commit/245bae92d1c84b4a44fe7aae2f82c5a90818f1c5))
* updated check mark symbol to show some green checkboxes ([#582](https://github.com/cloudevents/sdk-javascript/issues/582)) ([c65afe9](https://github.com/cloudevents/sdk-javascript/commit/c65afe94d2320eae9b8b74de9b1e1bd8793baa6a))
## [8.0.0](https://github.com/cloudevents/sdk-javascript/compare/v7.0.2...v8.0.0) (2023-07-24)
### ⚠ BREAKING CHANGES
* use string instead of enum for Version ([#561](https://github.com/cloudevents/sdk-javascript/issues/561)) ([15f6505](https://github.com/cloudevents/sdk-javascript/commit/15f6505a580b2bbf8d6b2e89feea10cbd40ab827))
TypeScript does not consider enum values equivalent, even if the string
representation is the same. So, when a module imports `cloudevents` and
also has a dependency on `cloudevents` this can cause conflicts where
the `CloudEvent.version` attribute is not considered equal when, in
fact, it is.
### Miscellaneous
* add `npm run build:schema` to the doc generation action ([#557](https://github.com/cloudevents/sdk-javascript/issues/557)) ([fa388f7](https://github.com/cloudevents/sdk-javascript/commit/fa388f7dc65c1739864d7a885d6d28111ce07775))
* modify release-please to use Signed-Off-By on commits ([#559](https://github.com/cloudevents/sdk-javascript/issues/559)) ([089520a](https://github.com/cloudevents/sdk-javascript/commit/089520a4cc8304e39ac9bfccf0ed59c76ea8c11a))
* release 8.0.0 ([#563](https://github.com/cloudevents/sdk-javascript/issues/563)) ([1ed43c8](https://github.com/cloudevents/sdk-javascript/commit/1ed43c84868ccfd18531deaf6cc9d4e4fcb21a08))
## [7.0.2](https://github.com/cloudevents/sdk-javascript/compare/v7.0.1...v7.0.2) (2023-07-05)
### Miscellaneous
* add the provenance flag when publishing to npm ([#556](https://github.com/cloudevents/sdk-javascript/issues/556)) ([a0d8682](https://github.com/cloudevents/sdk-javascript/commit/a0d86826138be31072c9a30edf26f4b91da576ed))
* fix the release-please automation script. ([#554](https://github.com/cloudevents/sdk-javascript/issues/554)) ([023171d](https://github.com/cloudevents/sdk-javascript/commit/023171d9a08484c32e24f8228602ef4d5173c749))
## [7.0.1](https://github.com/cloudevents/sdk-javascript/compare/v7.0.0...v7.0.1) (2023-05-30)
### Bug Fixes
* handle big integers in incoming events ([#495](https://github.com/cloudevents/sdk-javascript/issues/495)) ([43c3584](https://github.com/cloudevents/sdk-javascript/commit/43c3584b984aa170b1c1c4dff7218d027cd28d02))
### Miscellaneous
* add publish automation ([#550](https://github.com/cloudevents/sdk-javascript/issues/550)) ([3931b22](https://github.com/cloudevents/sdk-javascript/commit/3931b224cb3140ad3ba759edcf564621a2e34542))
* remove old Node versions from the readme ([#549](https://github.com/cloudevents/sdk-javascript/issues/549)) ([11442d3](https://github.com/cloudevents/sdk-javascript/commit/11442d32d307a0e8416ed573ce34fc825d3b63c4))
* Update compatible node version ([#552](https://github.com/cloudevents/sdk-javascript/issues/552)) ([f3659eb](https://github.com/cloudevents/sdk-javascript/commit/f3659ebfc6251b4c57997f70709688916a061a2d))
## [7.0.0](https://github.com/cloudevents/sdk-javascript/compare/v6.0.4...v7.0.0) (2023-05-03)
### ⚠ BREAKING CHANGES
* remove node 12 and node 14 ([#545](https://github.com/cloudevents/sdk-javascript/issues/545))
### Features
* remove node 12 and node 14 ([#545](https://github.com/cloudevents/sdk-javascript/issues/545)) ([2cb9364](https://github.com/cloudevents/sdk-javascript/commit/2cb9364a25a5e82f2a68504dbe19839a7fbfd9d4))
### Miscellaneous
* add the build script to the pretest script. ([#539](https://github.com/cloudevents/sdk-javascript/issues/539)) ([c06ffc1](https://github.com/cloudevents/sdk-javascript/commit/c06ffc196389fedd7d5141d69fac3f4d95156193))
* fix release-please-action ([#543](https://github.com/cloudevents/sdk-javascript/issues/543)) ([ec83abc](https://github.com/cloudevents/sdk-javascript/commit/ec83abc82799159aa1f64c791c92e035ef6f42b8))
* release 6.0.5 ([#542](https://github.com/cloudevents/sdk-javascript/issues/542)) ([343382e](https://github.com/cloudevents/sdk-javascript/commit/343382ebdedc9a2efbc5b3ba5cd36e4e069fd38f))
* release 7.0.0 ([#546](https://github.com/cloudevents/sdk-javascript/issues/546)) ([0120d22](https://github.com/cloudevents/sdk-javascript/commit/0120d224ab67e804e201625e0a9d59947a5a212d))
* Update CI action to node 18.x ([#533](https://github.com/cloudevents/sdk-javascript/issues/533)) ([7ff64f8](https://github.com/cloudevents/sdk-javascript/commit/7ff64f8b82e1c5a824bbe985df4948d79e919e8c))
### [6.0.3](https://www.github.com/cloudevents/sdk-javascript/compare/v6.0.2...v6.0.3) (2023-02-16)
### Bug Fixes
* improve validation on extension attribute ([#502](https://www.github.com/cloudevents/sdk-javascript/issues/502)) ([ea94a4d](https://www.github.com/cloudevents/sdk-javascript/commit/ea94a4d779d0744ef40abc81d08ab8b7e93e9133))
* Make CloudEvent data field immutable and enumerable using Object.keys() ([#515](https://www.github.com/cloudevents/sdk-javascript/issues/515)) ([#516](https://www.github.com/cloudevents/sdk-javascript/issues/516)) ([2d5fab1](https://www.github.com/cloudevents/sdk-javascript/commit/2d5fab1b7133241493bb9327aa26e7de4117616d))
* This fixes bug [#525](https://www.github.com/cloudevents/sdk-javascript/issues/525) where the browser version was breaking becuase of process not being found. ([#526](https://www.github.com/cloudevents/sdk-javascript/issues/526)) ([e5ee836](https://www.github.com/cloudevents/sdk-javascript/commit/e5ee8369ba5838aa24c2d99efeb81788757b71d1))
### Miscellaneous
* added the engines property to the package.json ([bc3aaca](https://www.github.com/cloudevents/sdk-javascript/commit/bc3aaca2ef250e4acd72b909488b326233237c83))
* bump cucumber to full release version ([#514](https://www.github.com/cloudevents/sdk-javascript/issues/514)) ([c09a9cc](https://www.github.com/cloudevents/sdk-javascript/commit/c09a9cc20a601ddc36c5c1b56fb52dc9c2161e1b))
* bump mocha to 10.1.0 ([#512](https://www.github.com/cloudevents/sdk-javascript/issues/512)) ([4831e6a](https://www.github.com/cloudevents/sdk-javascript/commit/4831e6a1a5003c4c1c7bcbd5a3a2fc5c48e0ba4c))
* bump webpack to 5.74.0 ([#509](https://www.github.com/cloudevents/sdk-javascript/issues/509)) ([760a024](https://www.github.com/cloudevents/sdk-javascript/commit/760a0240674c79ca6be142ae9f9b242080c4d59d))
* release 6.0.3 ([#503](https://www.github.com/cloudevents/sdk-javascript/issues/503)) ([3619ef2](https://www.github.com/cloudevents/sdk-javascript/commit/3619ef2bbd6e2b3e9e6e5bb5ad904689d40f4b79))
* Typos ([953bc2a](https://www.github.com/cloudevents/sdk-javascript/commit/953bc2a143a66d04d850c727305a5a465e843bff))
* **examples:** add mqtt example ([#523](https://www.github.com/cloudevents/sdk-javascript/issues/523)) ([b374d9a](https://www.github.com/cloudevents/sdk-javascript/commit/b374d9ac3313023e4f8a59cb22785751bbb0f686))
### [6.0.3](https://www.github.com/cloudevents/sdk-javascript/compare/v6.0.2...v6.0.3) (2022-11-01)
### Bug Fixes
* improve validation on extension attribute ([#502](https://www.github.com/cloudevents/sdk-javascript/issues/502)) ([ea94a4d](https://www.github.com/cloudevents/sdk-javascript/commit/ea94a4d779d0744ef40abc81d08ab8b7e93e9133))
* Make CloudEvent data field immutable and enumerable using Object.keys() ([#515](https://www.github.com/cloudevents/sdk-javascript/issues/515)) ([#516](https://www.github.com/cloudevents/sdk-javascript/issues/516)) ([2d5fab1](https://www.github.com/cloudevents/sdk-javascript/commit/2d5fab1b7133241493bb9327aa26e7de4117616d))
### Miscellaneous
* bump cucumber to full release version ([#514](https://www.github.com/cloudevents/sdk-javascript/issues/514)) ([c09a9cc](https://www.github.com/cloudevents/sdk-javascript/commit/c09a9cc20a601ddc36c5c1b56fb52dc9c2161e1b))
* bump mocha to 10.1.0 ([#512](https://www.github.com/cloudevents/sdk-javascript/issues/512)) ([4831e6a](https://www.github.com/cloudevents/sdk-javascript/commit/4831e6a1a5003c4c1c7bcbd5a3a2fc5c48e0ba4c))
* bump webpack to 5.74.0 ([#509](https://www.github.com/cloudevents/sdk-javascript/issues/509)) ([760a024](https://www.github.com/cloudevents/sdk-javascript/commit/760a0240674c79ca6be142ae9f9b242080c4d59d))
### [6.0.2](https://www.github.com/cloudevents/sdk-javascript/compare/v6.0.1...v6.0.2) (2022-06-21)
### Bug Fixes
* allow `TypedArray` for binary data ([#494](https://www.github.com/cloudevents/sdk-javascript/issues/494)) ([921e273](https://www.github.com/cloudevents/sdk-javascript/commit/921e273ede100ab9a262fdfa1f3d6561d3fab0f9))
* HTTP headers for extensions with false values ([#493](https://www.github.com/cloudevents/sdk-javascript/issues/493)) ([d6f52ca](https://www.github.com/cloudevents/sdk-javascript/commit/d6f52ca65f893fdb581bf06b2ff97b3d6eeeb744))
* package.json & package-lock.json to reduce vulnerabilities ([ed63f14](https://www.github.com/cloudevents/sdk-javascript/commit/ed63f14339fb7774bff865726370fe72a49abca3))
### Miscellaneous
* bump ajv and remove old dep dependency ([#496](https://www.github.com/cloudevents/sdk-javascript/issues/496)) ([ce02e0a](https://www.github.com/cloudevents/sdk-javascript/commit/ce02e0a1f3b24624bd8ba443c744b4a6c0cfcb44))
* update owners ([#499](https://www.github.com/cloudevents/sdk-javascript/issues/499)) ([a62eb44](https://www.github.com/cloudevents/sdk-javascript/commit/a62eb4466985972cd3112e6f8e3e0b62cb01c1c1))
### [6.0.1](https://www.github.com/cloudevents/sdk-javascript/compare/v6.0.0...v6.0.1) (2022-03-21)
### Miscellaneous
* update dependencies to inlude ajv-formats ([#484](https://www.github.com/cloudevents/sdk-javascript/issues/484)) ([c0b1f77](https://www.github.com/cloudevents/sdk-javascript/commit/c0b1f7705a448dda3e6292d872a5bf435d26fab4)), closes [/github.com/cloudevents/sdk-javascript/pull/471/files#diff-7ae45ad102eab3b6d7e7896acd08c427a9b25b346470d7bc6507b6481575d519R128](https://www.github.com/cloudevents//github.com/cloudevents/sdk-javascript/pull/471/files/issues/diff-7ae45ad102eab3b6d7e7896acd08c427a9b25b346470d7bc6507b6481575d519R128)
## [6.0.0](https://www.github.com/cloudevents/sdk-javascript/compare/v5.3.2...v6.0.0) (2022-03-21) ## [6.0.0](https://www.github.com/cloudevents/sdk-javascript/compare/v5.3.2...v6.0.0) (2022-03-21)

View File

@ -1,9 +0,0 @@
# Maintainers
Current active maintainers of this SDK:
- [Lance Ball](https://github.com/lance)
- [Daniel Bevenius](https://github.com/danbev)
- [Lucas Holmquist](https://github.com/lholmquist)
- [Fabio Jose](https://github.com/fabiojose)
- [Helio Frota](https://github.com/helio-frota)

View File

@ -12,14 +12,14 @@ The CloudEvents SDK for JavaScript.
- Represent CloudEvents in memory - Represent CloudEvents in memory
- Serialize and deserialize CloudEvents in different [event formats](https://github.com/cloudevents/spec/blob/v1.0/spec.md#event-format). - Serialize and deserialize CloudEvents in different [event formats](https://github.com/cloudevents/spec/blob/v1.0/spec.md#event-format).
- Send and receive CloudEvents with via different [protocol bindings](https://github.com/cloudevents/spec/blob/v1.0/spec.md#protocol-binding). - Send and recieve CloudEvents with via different [protocol bindings](https://github.com/cloudevents/spec/blob/v1.0/spec.md#protocol-binding).
_Note:_ Supports CloudEvent version 1.0 _Note:_ Supports CloudEvent version 1.0
## Installation ## Installation
The CloudEvents SDK requires a current LTS version of Node.js. At the moment The CloudEvents SDK requires a current LTS version of Node.js. At the moment
those are Node.js 16.x, and Node.js 18.x. To install in your Node.js project: those are Node.js 12.x, Node.js 14.x and Node.js 16.x. To install in your Node.js project:
```console ```console
npm install cloudevents npm install cloudevents
@ -51,7 +51,7 @@ The easiest way to send events is to use the built-in HTTP emitter.
```js ```js
const { httpTransport, emitterFor, CloudEvent } = require("cloudevents"); const { httpTransport, emitterFor, CloudEvent } = require("cloudevents");
// Create an emitter to send events to a receiver // Create an emitter to send events to an to a reciever
const emit = emitterFor(httpTransport("https://my.receiver.com/endpoint")); const emit = emitterFor(httpTransport("https://my.receiver.com/endpoint"));
// Create a new CloudEvent // Create a new CloudEvent
@ -162,20 +162,6 @@ const event3 = new CloudEvent({
}); });
``` ```
### A Note About Big Integers
When parsing JSON data, if a JSON field value is a number, and that number
is really big, JavaScript loses precision. For example, the Twitter API exposes
the Tweet ID. This is a large number that exceeds the integer space of `Number`.
In order to address this situation, you can set the environment variable
`CE_USE_BIG_INT` to the string value `"true"` to enable the use of the
[`json-bigint`](https://www.npmjs.com/package/json-bigint) package. This
package is not used by default due to the resulting slowdown in parse speed
by a factor of 7x.
See for more information: https://github.com/cloudevents/sdk-javascript/issues/489
### Example Applications ### Example Applications
There are a few trivial example applications in There are a few trivial example applications in
@ -191,37 +177,37 @@ There you will find Express.js, TypeScript and Websocket examples.
| Core Specification | [v0.3](https://github.com/cloudevents/spec/blob/v0.3/spec.md) | [v1.0](https://github.com/cloudevents/spec/blob/v1.0/spec.md) | | Core Specification | [v0.3](https://github.com/cloudevents/spec/blob/v0.3/spec.md) | [v1.0](https://github.com/cloudevents/spec/blob/v1.0/spec.md) |
| ------------------ | ------------------------------------------------------------- | ------------------------------------------------------------- | | ------------------ | ------------------------------------------------------------- | ------------------------------------------------------------- |
| CloudEvents Core | :white_check_mark: | :white_check_mark: | | CloudEvents Core | :heavy_check_mark: | :heavy_check_mark: |
--- ---
| Event Formats | [v0.3](https://github.com/cloudevents/spec/tree/v0.3) | [v1.0](https://github.com/cloudevents/spec/blob/v1.0/spec.md#event-format) | | Event Formats | [v0.3](https://github.com/cloudevents/spec/tree/v0.3) | [v1.0](https://github.com/cloudevents/spec/blob/v1.0/spec.md#event-format) |
| ----------------- | ----------------------------------------------------- | ----------------------------------------------------- | | ----------------- | ----------------------------------------------------- | ----------------------------------------------------- |
| AVRO Event Format | :x: | :x: | | AVRO Event Format | :x: | :x: |
| JSON Event Format | :white_check_mark: | :white_check_mark: | | JSON Event Format | :heavy_check_mark: | :heavy_check_mark: |
--- ---
| Protocol Bindings | [v0.3](https://github.com/cloudevents/spec/tree/v0.3) | [v1.0](https://github.com/cloudevents/spec/blob/v1.0/spec.md#protocol-binding) | | Protocol Bindings | [v0.3](https://github.com/cloudevents/spec/tree/v0.3) | [v1.0](https://github.com/cloudevents/spec/blob/v1.0/spec.md#protocol-binding) |
| ---------------------- | ----------------------------------------------------- | ----------------------------------------------------- | | ---------------------- | ----------------------------------------------------- | ----------------------------------------------------- |
| AMQP Protocol Binding | :x: | :x: | | AMQP Protocol Binding | :x: | :x: |
| HTTP Protocol Binding | :white_check_mark: | :white_check_mark: | | HTTP Protocol Binding | :heavy_check_mark: | :heavy_check_mark: |
| Kafka Protocol Binding | :x: | :white_check_mark: | | Kafka Protocol Binding | :x: | :heavy_check_mark: |
| MQTT Protocol Binding | :white_check_mark: | :x: | | MQTT Protocol Binding | :heavy_check_mark: | :x: |
| NATS Protocol Binding | :x: | :x: | | NATS Protocol Binding | :x: | :x: |
--- ---
| Content Modes | [v0.3](https://github.com/cloudevents/spec/tree/v0.3) | [v1.0](https://github.com/cloudevents/spec/blob/v1.0/http-protocol-binding.md#13-content-modes) | | Content Modes | [v0.3](https://github.com/cloudevents/spec/tree/v0.3) | [v1.0](https://github.com/cloudevents/spec/blob/v1.0/http-protocol-binding.md#13-content-modes) |
| ---------------------- | ----------------------------------------------------- | ----------------------------------------------------- | | ---------------------- | ----------------------------------------------------- | ----------------------------------------------------- |
| HTTP Binary | :white_check_mark: | :white_check_mark: | | HTTP Binary | :heavy_check_mark: | :heavy_check_mark: |
| HTTP Structured | :white_check_mark: | :white_check_mark: | | HTTP Structured | :heavy_check_mark: | :heavy_check_mark: |
| HTTP Batch | :white_check_mark: | :white_check_mark: | | HTTP Batch | :heavy_check_mark: | :heavy_check_mark: |
| Kafka Binary | :white_check_mark: | :white_check_mark: | | Kafka Binary | :heavy_check_mark: | :heavy_check_mark: |
| Kafka Structured | :white_check_mark: | :white_check_mark: | | Kafka Structured | :heavy_check_mark: | :heavy_check_mark: |
| Kafka Batch | :white_check_mark: | :white_check_mark: | Kafka Batch | :heavy_check_mark: | :heavy_check_mark:
| MQTT Binary | :white_check_mark: | :white_check_mark: | | MQTT Binary | :heavy_check_mark: | :heavy_check_mark: |
| MQTT Structured | :white_check_mark: | :white_check_mark: | | MQTT Structured | :heavy_check_mark: | :heavy_check_mark: |
## Community ## Community
@ -241,6 +227,7 @@ Currently active maintainers who may be found in the CNCF Slack.
- Lance Ball (@lance) - Lance Ball (@lance)
- Lucas Holmquist (@lholmquist) - Lucas Holmquist (@lholmquist)
- Grant Timmerman (@grant)
## Contributing ## Contributing
@ -258,14 +245,3 @@ how SDK projects are
for how PR reviews and approval, and our for how PR reviews and approval, and our
[Code of Conduct](https://github.com/cloudevents/spec/blob/master/community/GOVERNANCE.md#additional-information) [Code of Conduct](https://github.com/cloudevents/spec/blob/master/community/GOVERNANCE.md#additional-information)
information. information.
If there is a security concern with one of the CloudEvents specifications, or
with one of the project's SDKs, please send an email to
[cncf-cloudevents-security@lists.cncf.io](mailto:cncf-cloudevents-security@lists.cncf.io).
## Additional SDK Resources
- [List of current active maintainers](MAINTAINERS.md)
- [How to contribute to the project](CONTRIBUTING.md)
- [SDK's License](LICENSE)
- [SDK's Release process](RELEASING.md)

View File

@ -28,11 +28,11 @@ app.post("/", (req, res) => {
const responseEventMessage = new CloudEvent({ const responseEventMessage = new CloudEvent({
source: '/', source: '/',
type: 'event:response', type: 'event:response',
...event, ...event
data: {
hello: 'world'
}
}); });
responseEventMessage.data = {
hello: 'world'
};
// const message = HTTP.binary(responseEventMessage) // const message = HTTP.binary(responseEventMessage)
const message = HTTP.structured(responseEventMessage) const message = HTTP.structured(responseEventMessage)

View File

@ -1,24 +0,0 @@
# MQTT Example
The MQTT message protocol are available since v5.3.0
## How To Start
Install and compile:
```bash
npm install
npm run compile
```
Start a MQTT broker using Docker:
```bash
docker run -it -d -p 1883:1883 eclipse-mosquitto:2.0 mosquitto -c /mosquitto-no-auth.conf
```
Then, start
```bash
npm start
```

View File

@ -1,35 +0,0 @@
{
"name": "mqtt-ex",
"version": "1.0.0",
"description": "Simple mqtt example using CloudEvents types",
"repository": "https://github.com/cloudevents/sdk-javascript.git",
"main": "build/src/index.js",
"types": "build/src/index.d.ts",
"files": [
"build/src"
],
"license": "Apache-2.0",
"keywords": [],
"scripts": {
"start": "node build/index.js",
"test": "echo \"Error: no test specified\" && exit 1",
"check": "gts check",
"clean": "gts clean",
"compile": "tsc -p .",
"watch": "tsc -p . --watch",
"fix": "gts fix",
"prepare": "npm run compile",
"pretest": "npm run compile",
"posttest": "npm run check"
},
"devDependencies": {
"@types/node": "^14.14.10",
"@types/ws": "^8.5.4",
"gts": "^3.0.3",
"typescript": "~4.1.3"
},
"dependencies": {
"cloudevents": "^6.0.3",
"mqtt": "^4.3.7"
}
}

View File

@ -1,35 +0,0 @@
/* eslint-disable */
import { CloudEvent, MQTT } from "cloudevents";
import * as mqtt from "mqtt";
const client = mqtt.connect("mqtt://localhost:1883");
client.on("connect", function () {
client.subscribe("presence", function (err) {
if (err) return;
const event = new CloudEvent({
source: "presence",
type: "presence.event",
datacontenttype: "application/json",
data: {
hello: "world",
},
});
const { body, headers } = MQTT.binary(event);
client.publish("presence", JSON.stringify(body), {
properties: {
userProperties: headers as mqtt.UserProperties,
},
});
});
});
client.on("message", function (topic, message, packet) {
const event = MQTT.toEvent({
body: JSON.parse(message.toString()),
headers: packet.properties?.userProperties || {},
});
console.log(event);
client.end();
});

View File

@ -1,16 +0,0 @@
{
"extends": "./node_modules/gts/tsconfig-google.json",
"compilerOptions": {
"rootDir": "./src",
"outDir": "./build/",
"lib": [
"es6",
"dom"
]
},
"include": [
"src/**/*.ts",
"test/**/*.ts"
],
"allowJs": true
}

13845
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
{ {
"name": "cloudevents", "name": "cloudevents",
"version": "9.0.0", "version": "6.0.0",
"description": "CloudEvents SDK for JavaScript", "description": "CloudEvents SDK for JavaScript",
"main": "dist/index.js", "main": "dist/index.js",
"scripts": { "scripts": {
@ -13,7 +13,7 @@
"lint:js": "eslint 'src/**/*.{js,ts}' 'test/**/*.{js,ts}' cucumber.js", "lint:js": "eslint 'src/**/*.{js,ts}' 'test/**/*.{js,ts}' cucumber.js",
"lint:md": "remark .", "lint:md": "remark .",
"lint:fix": "eslint 'src/**/*.{js,ts}' 'test/**/*.{js,ts}' --fix", "lint:fix": "eslint 'src/**/*.{js,ts}' 'test/**/*.{js,ts}' --fix",
"pretest": "npm run lint && npm run build && npm run conformance", "pretest": "npm run lint && npm run conformance",
"test": "mocha --require ts-node/register ./test/integration/**/*.ts", "test": "mocha --require ts-node/register ./test/integration/**/*.ts",
"test:one": "mocha --require ts-node/register", "test:one": "mocha --require ts-node/register",
"conformance": "cucumber-js ./conformance/features/*-protocol-binding.feature -p default", "conformance": "cucumber-js ./conformance/features/*-protocol-binding.feature -p default",
@ -110,19 +110,15 @@
}, },
"homepage": "https://github.com/cloudevents/sdk-javascript#readme", "homepage": "https://github.com/cloudevents/sdk-javascript#readme",
"dependencies": { "dependencies": {
"ajv": "^8.11.0", "ajv": "^8.6.3",
"ajv-formats": "^2.1.1",
"process": "^0.11.10",
"json-bigint": "^1.0.0",
"util": "^0.12.4", "util": "^0.12.4",
"uuid": "^8.3.2" "uuid": "^8.3.2"
}, },
"devDependencies": { "devDependencies": {
"@cucumber/cucumber": "^8.0.0", "@cucumber/cucumber": "^8.0.0-rc.1",
"@types/chai": "^4.2.11", "@types/chai": "^4.2.11",
"@types/cucumber": "^6.0.1", "@types/cucumber": "^6.0.1",
"@types/got": "^9.6.11", "@types/got": "^9.6.11",
"@types/json-bigint": "^1.0.1",
"@types/mocha": "^7.0.2", "@types/mocha": "^7.0.2",
"@types/node": "^14.14.10", "@types/node": "^14.14.10",
"@types/superagent": "^4.1.10", "@types/superagent": "^4.1.10",
@ -130,6 +126,7 @@
"@typescript-eslint/eslint-plugin": "^4.29.0", "@typescript-eslint/eslint-plugin": "^4.29.0",
"@typescript-eslint/parser": "^4.29.0", "@typescript-eslint/parser": "^4.29.0",
"ajv-cli": "^5.0.0", "ajv-cli": "^5.0.0",
"ajv-formats": "^2.1.1",
"axios": "^0.26.1", "axios": "^0.26.1",
"chai": "~4.2.0", "chai": "~4.2.0",
"eslint": "^7.32.0", "eslint": "^7.32.0",
@ -138,9 +135,9 @@
"eslint-plugin-import": "^2.23.4", "eslint-plugin-import": "^2.23.4",
"eslint-plugin-node": "^11.1.0", "eslint-plugin-node": "^11.1.0",
"eslint-plugin-promise": "^5.1.0", "eslint-plugin-promise": "^5.1.0",
"got": "^11.8.5", "got": "^11.7.0",
"http-parser-js": "^0.5.2", "http-parser-js": "^0.5.2",
"mocha": "^10.1.0", "mocha": "~9.2.0",
"nock": "~12.0.3", "nock": "~12.0.3",
"nyc": "~15.0.0", "nyc": "~15.0.0",
"prettier": "^2.0.5", "prettier": "^2.0.5",
@ -149,17 +146,14 @@
"remark-lint-list-item-indent": "^2.0.1", "remark-lint-list-item-indent": "^2.0.1",
"remark-preset-lint-recommended": "^5.0.0", "remark-preset-lint-recommended": "^5.0.0",
"superagent": "^7.1.1", "superagent": "^7.1.1",
"ts-node": "^10.8.1", "ts-node": "^8.10.2",
"typedoc": "^0.22.11", "typedoc": "^0.22.11",
"typescript": "^4.3.5", "typescript": "^4.3.5",
"webpack": "^5.76.0", "webpack": "^5.1.1",
"webpack-cli": "^4.10.0" "webpack-cli": "^4.0.0"
}, },
"publishConfig": { "publishConfig": {
"access": "public" "access": "public"
}, },
"types": "./dist/index.d.ts", "types": "./dist/index.d.ts"
"engines": {
"node": ">=20 <=24"
}
} }

View File

@ -54,7 +54,6 @@ const CONSTANTS = Object.freeze({
DATA_SCHEMA: "dataschema", DATA_SCHEMA: "dataschema",
DATA_BASE64: "data_base64", DATA_BASE64: "data_base64",
}, },
USE_BIG_INT_ENV: "CE_USE_BIG_INT"
} as const); } as const);
export default CONSTANTS; export default CONSTANTS;

View File

@ -9,13 +9,15 @@ import { Emitter } from "..";
import { CloudEventV1 } from "./interfaces"; import { CloudEventV1 } from "./interfaces";
import { validateCloudEvent } from "./spec"; import { validateCloudEvent } from "./spec";
import { ValidationError, isBinary, asBase64, isValidType, base64AsBinary } from "./validation"; import { ValidationError, isBinary, asBase64, isValidType } from "./validation";
/** /**
* Constants representing the CloudEvent specification version * An enum representing the CloudEvent specification version
*/ */
export const V1 = "1.0"; export const enum Version {
export const V03 = "0.3"; V1 = "1.0",
V03 = "0.3",
}
/** /**
* A CloudEvent describes event data in common formats to provide * A CloudEvent describes event data in common formats to provide
@ -26,12 +28,12 @@ export class CloudEvent<T = undefined> implements CloudEventV1<T> {
id: string; id: string;
type: string; type: string;
source: string; source: string;
specversion: string; specversion: Version;
datacontenttype?: string; datacontenttype?: string;
dataschema?: string; dataschema?: string;
subject?: string; subject?: string;
time?: string; time?: string;
data?: T; #_data?: T;
data_base64?: string; data_base64?: string;
// Extensions should not exist as it's own object, but instead // Extensions should not exist as it's own object, but instead
@ -67,7 +69,7 @@ export class CloudEvent<T = undefined> implements CloudEventV1<T> {
this.source = properties.source as string; this.source = properties.source as string;
delete (properties as any).source; delete (properties as any).source;
this.specversion = (properties.specversion) || V1; this.specversion = (properties.specversion as Version) || Version.V1;
delete properties.specversion; delete properties.specversion;
this.datacontenttype = properties.datacontenttype; this.datacontenttype = properties.datacontenttype;
@ -83,35 +85,26 @@ export class CloudEvent<T = undefined> implements CloudEventV1<T> {
delete properties.dataschema; delete properties.dataschema;
this.data_base64 = properties.data_base64 as string; this.data_base64 = properties.data_base64 as string;
if (this.data_base64) {
this.data = base64AsBinary(this.data_base64) as unknown as T;
}
delete properties.data_base64; delete properties.data_base64;
this.schemaurl = properties.schemaurl as string; this.schemaurl = properties.schemaurl as string;
delete properties.schemaurl; delete properties.schemaurl;
if (isBinary(properties.data)) { this.data = properties.data;
this.data_base64 = asBase64(properties.data as unknown as Buffer);
}
this.data = typeof properties.data !== "undefined" ? properties.data : this.data;
delete properties.data; delete properties.data;
// sanity checking // sanity checking
if (this.specversion === V1 && this.schemaurl) { if (this.specversion === Version.V1 && this.schemaurl) {
throw new TypeError("cannot set schemaurl on version 1.0 event"); throw new TypeError("cannot set schemaurl on version 1.0 event");
} else if (this.specversion === V03 && this.dataschema) { } else if (this.specversion === Version.V03 && this.dataschema) {
throw new TypeError("cannot set dataschema on version 0.3 event"); throw new TypeError("cannot set dataschema on version 0.3 event");
} }
// finally process any remaining properties - these are extensions // finally process any remaining properties - these are extensions
for (const [key, value] of Object.entries(properties)) { for (const [key, value] of Object.entries(properties)) {
// Extension names must only allow lowercase a-z and 0-9 in the name // Extension names should only allow lowercase a-z and 0-9 in the name
// names should not exceed 20 characters in length // names should not exceed 20 characters in length
if (!key.match(/^[a-z0-9]+$/) && strict) { if (!key.match(/^[a-z0-9]{1,20}$/) && strict) {
throw new ValidationError(`invalid extension name: ${key} throw new ValidationError(`invalid extension name: ${key}
CloudEvents attribute names MUST consist of lower-case letters ('a' to 'z') CloudEvents attribute names MUST consist of lower-case letters ('a' to 'z')
or digits ('0' to '9') from the ASCII character set. Attribute names SHOULD or digits ('0' to '9') from the ASCII character set. Attribute names SHOULD
@ -134,6 +127,17 @@ See: https://github.com/cloudevents/spec/blob/v1.0/spec.md#type-system`);
Object.freeze(this); Object.freeze(this);
} }
get data(): T | undefined {
return this.#_data;
}
set data(value: T | undefined) {
if (isBinary(value)) {
this.data_base64 = asBase64(value);
}
this.#_data = value;
}
/** /**
* Used by JSON.stringify(). The name is confusing, but this method is called by * Used by JSON.stringify(). The name is confusing, but this method is called by
* JSON.stringify() when converting this object to JSON. * JSON.stringify() when converting this object to JSON.
@ -143,11 +147,7 @@ See: https://github.com/cloudevents/spec/blob/v1.0/spec.md#type-system`);
toJSON(): Record<string, unknown> { toJSON(): Record<string, unknown> {
const event = { ...this }; const event = { ...this };
event.time = new Date(this.time as string).toISOString(); event.time = new Date(this.time as string).toISOString();
event.data = this.#_data;
if (event.data_base64 && event.data) {
delete event.data;
}
return event; return event;
} }
@ -230,6 +230,9 @@ See: https://github.com/cloudevents/spec/blob/v1.0/spec.md#type-system`);
event: CloudEventV1<any>, event: CloudEventV1<any>,
options: Partial<CloudEventV1<any>>, options: Partial<CloudEventV1<any>>,
strict = true): CloudEvent<any> { strict = true): CloudEvent<any> {
if (event instanceof CloudEvent) {
event = event.toJSON() as CloudEventV1<any>;
}
return new CloudEvent(Object.assign({}, event, options), strict); return new CloudEvent(Object.assign({}, event, options), strict);
} }
} }

View File

@ -6,23 +6,22 @@
import { ValidationError } from "./validation"; import { ValidationError } from "./validation";
import { CloudEventV1 } from "./interfaces"; import { CloudEventV1 } from "./interfaces";
import { V1 } from "./cloudevent"; import { Version } from "./cloudevent";
import validate from "../schema/v1"; import validate from "../schema/v1";
export function validateCloudEvent<T>(event: CloudEventV1<T>): boolean { export function validateCloudEvent<T>(event: CloudEventV1<T>): boolean {
if (event.specversion === V1) { if (event.specversion === Version.V1) {
if (!validate(event)) { if (!validate(event)) {
throw new ValidationError("invalid payload", (validate as any).errors); throw new ValidationError("invalid payload", (validate as any).errors);
} }
} else { } else {
return false; return false;
} }
// attribute names must all be [a-z|0-9] // attribute names must all be lowercase
const validation = /^[a-z0-9]+$/;
for (const key in event) { for (const key in event) {
if (validation.test(key) === false && key !== "data_base64") { if (key !== key.toLowerCase()) {
throw new ValidationError(`invalid attribute name: "${key}"`); throw new ValidationError(`invalid attribute name: ${key}`);
} }
} }
return true; return true;

View File

@ -5,23 +5,6 @@
import { ErrorObject } from "ajv"; import { ErrorObject } from "ajv";
export type TypeArray = Int8Array | Uint8Array | Int16Array | Uint16Array |
Int32Array | Uint32Array | Uint8ClampedArray | Float32Array | Float64Array;
const globalThisPolyfill = (function() {
try {
return globalThis;
}
catch (e) {
try {
return self;
}
catch (e) {
return global;
}
}
}());
/** /**
* An Error class that will be thrown when a CloudEvent * An Error class that will be thrown when a CloudEvent
* cannot be properly validated against a specification. * cannot be properly validated against a specification.
@ -53,7 +36,7 @@ export const isDefined = (v: unknown): boolean => v !== null && typeof v !== "un
export const isBoolean = (v: unknown): boolean => typeof v === "boolean"; export const isBoolean = (v: unknown): boolean => typeof v === "boolean";
export const isInteger = (v: unknown): boolean => Number.isInteger(v as number); export const isInteger = (v: unknown): boolean => Number.isInteger(v as number);
export const isDate = (v: unknown): v is Date => v instanceof Date; export const isDate = (v: unknown): v is Date => v instanceof Date;
export const isBinary = (v: unknown): boolean => ArrayBuffer.isView(v); export const isBinary = (v: unknown): v is Uint32Array => v instanceof Uint32Array;
export const isStringOrThrow = (v: unknown, t: Error): boolean => export const isStringOrThrow = (v: unknown, t: Error): boolean =>
isString(v) isString(v)
@ -90,7 +73,7 @@ export const isBase64 = (value: unknown): boolean =>
export const isBuffer = (value: unknown): boolean => value instanceof Buffer; export const isBuffer = (value: unknown): boolean => value instanceof Buffer;
export const asBuffer = (value: string | Buffer | TypeArray): Buffer => export const asBuffer = (value: string | Buffer | Uint32Array): Buffer =>
isBinary(value) isBinary(value)
? Buffer.from((value as unknown) as string) ? Buffer.from((value as unknown) as string)
: isBuffer(value) : isBuffer(value)
@ -99,16 +82,7 @@ export const asBuffer = (value: string | Buffer | TypeArray): Buffer =>
throw new TypeError("is not buffer or a valid binary"); throw new TypeError("is not buffer or a valid binary");
})(); })();
export const base64AsBinary = (base64String: string): Uint8Array => { export const asBase64 = (value: string | Buffer | Uint32Array): string => asBuffer(value).toString("base64");
const toBinaryString = (base64Str: string): string => globalThisPolyfill.atob
? globalThisPolyfill.atob(base64Str)
: Buffer.from(base64Str, "base64").toString("binary");
return Uint8Array.from(toBinaryString(base64String), (c) => c.charCodeAt(0));
};
export const asBase64 =
(value: string | Buffer | TypeArray): string => asBuffer(value).toString("base64");
export const clone = (o: Record<string, unknown>): Record<string, unknown> => JSON.parse(JSON.stringify(o)); export const clone = (o: Record<string, unknown>): Record<string, unknown> => JSON.parse(JSON.stringify(o));
@ -123,5 +97,5 @@ export const asData = (data: unknown, contentType: string): string => {
return isBinary(maybeJson) ? asBase64(maybeJson) : maybeJson; return isBinary(maybeJson) ? asBase64(maybeJson) : maybeJson;
}; };
export const isValidType = (v: boolean | number | string | Date | TypeArray | unknown): boolean => export const isValidType = (v: boolean | number | string | Date | Uint32Array | unknown): boolean =>
isBoolean(v) || isInteger(v) || isString(v) || isDate(v) || isBinary(v) || isObject(v); isBoolean(v) || isInteger(v) || isString(v) || isDate(v) || isBinary(v) || isObject(v);

View File

@ -3,7 +3,7 @@
SPDX-License-Identifier: Apache-2.0 SPDX-License-Identifier: Apache-2.0
*/ */
import { CloudEvent, V1, V03 } from "./event/cloudevent"; import { CloudEvent, Version } from "./event/cloudevent";
import { ValidationError } from "./event/validation"; import { ValidationError } from "./event/validation";
import { CloudEventV1, CloudEventV1Attributes } from "./event/interfaces"; import { CloudEventV1, CloudEventV1Attributes } from "./event/interfaces";
@ -18,8 +18,7 @@ import CONSTANTS from "./constants";
export { export {
// From event // From event
CloudEvent, CloudEvent,
V1, Version,
V03,
ValidationError, ValidationError,
Mode, Mode,
HTTP, HTTP,

View File

@ -6,7 +6,7 @@
import { PassThroughParser, DateParser, MappedParser } from "../../parsers"; import { PassThroughParser, DateParser, MappedParser } from "../../parsers";
import { CloudEventV1 } from "../.."; import { CloudEventV1 } from "../..";
import { Headers } from "../"; import { Headers } from "../";
import { V1 } from "../../event/cloudevent"; import { Version } from "../../event/cloudevent";
import CONSTANTS from "../../constants"; import CONSTANTS from "../../constants";
export const allowedContentTypes = [CONSTANTS.DEFAULT_CONTENT_TYPE, CONSTANTS.MIME_JSON, CONSTANTS.MIME_OCTET_STREAM]; export const allowedContentTypes = [CONSTANTS.DEFAULT_CONTENT_TYPE, CONSTANTS.MIME_JSON, CONSTANTS.MIME_OCTET_STREAM];
@ -27,7 +27,7 @@ export const requiredHeaders = [
export function headersFor<T>(event: CloudEventV1<T>): Headers { export function headersFor<T>(event: CloudEventV1<T>): Headers {
const headers: Headers = {}; const headers: Headers = {};
let headerMap: Readonly<{ [key: string]: MappedParser }>; let headerMap: Readonly<{ [key: string]: MappedParser }>;
if (event.specversion === V1) { if (event.specversion === Version.V1) {
headerMap = v1headerMap; headerMap = v1headerMap;
} else { } else {
headerMap = v03headerMap; headerMap = v03headerMap;
@ -36,7 +36,7 @@ export function headersFor<T>(event: CloudEventV1<T>): Headers {
// iterate over the event properties - generate a header for each // iterate over the event properties - generate a header for each
Object.getOwnPropertyNames(event).forEach((property) => { Object.getOwnPropertyNames(event).forEach((property) => {
const value = event[property]; const value = event[property];
if (value !== undefined) { if (value) {
const map: MappedParser | undefined = headerMap[property] as MappedParser; const map: MappedParser | undefined = headerMap[property] as MappedParser;
if (map) { if (map) {
headers[map.name] = map.parser.parse(value as string) as string; headers[map.name] = map.parser.parse(value as string) as string;

View File

@ -5,7 +5,7 @@
import { types } from "util"; import { types } from "util";
import { CloudEvent, CloudEventV1, CONSTANTS, Mode, V1, V03 } from "../.."; import { CloudEvent, CloudEventV1, CONSTANTS, Mode, Version } from "../..";
import { Message, Headers, Binding } from ".."; import { Message, Headers, Binding } from "..";
import { import {
@ -147,7 +147,7 @@ function getVersion(mode: Mode, headers: Headers, body: string | Record<string,
return (body as Record<string, string>).specversion; return (body as Record<string, string>).specversion;
} }
} }
return V1; return Version.V1;
} }
/** /**
@ -155,11 +155,11 @@ function getVersion(mode: Mode, headers: Headers, body: string | Record<string,
* instance if it conforms to the Cloud Event specification for this receiver. * instance if it conforms to the Cloud Event specification for this receiver.
* *
* @param {Message} message the incoming HTTP Message * @param {Message} message the incoming HTTP Message
* @param {string} version the spec version of the incoming event * @param {Version} version the spec version of the incoming event
* @returns {CloudEvent} an instance of CloudEvent representing the incoming request * @returns {CloudEvent} an instance of CloudEvent representing the incoming request
* @throws {ValidationError} of the event does not conform to the spec * @throws {ValidationError} of the event does not conform to the spec
*/ */
function parseBinary<T>(message: Message, version: string): CloudEvent<T> { function parseBinary<T>(message: Message, version: Version): CloudEvent<T> {
const headers = { ...message.headers }; const headers = { ...message.headers };
let body = message.body; let body = message.body;
@ -169,7 +169,7 @@ function parseBinary<T>(message: Message, version: string): CloudEvent<T> {
const sanitizedHeaders = sanitize(headers); const sanitizedHeaders = sanitize(headers);
const eventObj: { [key: string]: unknown | string | Record<string, unknown> } = {}; const eventObj: { [key: string]: unknown | string | Record<string, unknown> } = {};
const parserMap: Record<string, MappedParser> = version === V03 ? v03binaryParsers : v1binaryParsers; const parserMap: Record<string, MappedParser> = version === Version.V03 ? v03binaryParsers : v1binaryParsers;
for (const header in parserMap) { for (const header in parserMap) {
if (sanitizedHeaders[header]) { if (sanitizedHeaders[header]) {
@ -206,11 +206,11 @@ function parseBinary<T>(message: Message, version: string): CloudEvent<T> {
* Creates a new CloudEvent instance based on the provided payload and headers. * Creates a new CloudEvent instance based on the provided payload and headers.
* *
* @param {Message} message the incoming Message * @param {Message} message the incoming Message
* @param {string} version the spec version of this message (v1 or v03) * @param {Version} version the spec version of this message (v1 or v03)
* @returns {CloudEvent} a new CloudEvent instance for the provided headers and payload * @returns {CloudEvent} a new CloudEvent instance for the provided headers and payload
* @throws {ValidationError} if the payload and header combination do not conform to the spec * @throws {ValidationError} if the payload and header combination do not conform to the spec
*/ */
function parseStructured<T>(message: Message, version: string): CloudEvent<T> { function parseStructured<T>(message: Message, version: Version): CloudEvent<T> {
const payload = message.body; const payload = message.body;
const headers = message.headers; const headers = message.headers;
@ -227,7 +227,7 @@ function parseStructured<T>(message: Message, version: string): CloudEvent<T> {
const incoming = { ...(parser.parse(payload as string) as Record<string, unknown>) }; const incoming = { ...(parser.parse(payload as string) as Record<string, unknown>) };
const eventObj: { [key: string]: unknown } = {}; const eventObj: { [key: string]: unknown } = {};
const parserMap: Record<string, MappedParser> = version === V03 ? v03structuredParsers : v1structuredParsers; const parserMap: Record<string, MappedParser> = version === Version.V03 ? v03structuredParsers : v1structuredParsers;
for (const key in parserMap) { for (const key in parserMap) {
const property = incoming[key]; const property = incoming[key];

View File

@ -22,9 +22,9 @@ export * from "./mqtt";
* @property {@link Deserializer} `toEvent` - converts a Message into a CloudEvent * @property {@link Deserializer} `toEvent` - converts a Message into a CloudEvent
* @property {@link Detector} `isEvent` - determines if a Message can be converted to a CloudEvent * @property {@link Detector} `isEvent` - determines if a Message can be converted to a CloudEvent
*/ */
export interface Binding<B extends Message = Message, S extends Message = Message> { export interface Binding {
binary: Serializer<B>; binary: Serializer;
structured: Serializer<S>; structured: Serializer;
toEvent: Deserializer; toEvent: Deserializer;
isEvent: Detector; isEvent: Detector;
} }
@ -65,8 +65,8 @@ export enum Mode {
* CloudEvent into a Message. * CloudEvent into a Message.
* @interface * @interface
*/ */
export interface Serializer<M extends Message> { export interface Serializer {
<T>(event: CloudEventV1<T>): M; <T>(event: CloudEventV1<T>): Message;
} }
/** /**

View File

@ -22,7 +22,7 @@ export type {
* Bindings for Kafka transport * Bindings for Kafka transport
* @implements {@linkcode Binding} * @implements {@linkcode Binding}
*/ */
const Kafka: Binding<KafkaMessage<unknown>, KafkaMessage<string>> = { const Kafka: Binding = {
binary: toBinaryKafkaMessage, binary: toBinaryKafkaMessage,
structured: toStructuredKafkaMessage, structured: toStructuredKafkaMessage,
toEvent: deserializeKafkaMessage, toEvent: deserializeKafkaMessage,
@ -35,9 +35,9 @@ type Key = string | Buffer;
* Extends the base Message type to include * Extends the base Message type to include
* Kafka-specific fields * Kafka-specific fields
*/ */
interface KafkaMessage<T = string | Buffer | unknown> extends Message { interface KafkaMessage<T = string> extends Message {
key: Key key: Key
value: T value: T | string | Buffer | unknown
timestamp?: string timestamp?: string
} }
@ -61,7 +61,7 @@ interface KafkaEvent<T> extends CloudEventV1<T> {
* @param {KafkaEvent<T>} event The event to serialize * @param {KafkaEvent<T>} event The event to serialize
* @returns {KafkaMessage<T>} a KafkaMessage instance * @returns {KafkaMessage<T>} a KafkaMessage instance
*/ */
function toBinaryKafkaMessage<T>(event: CloudEventV1<T>): KafkaMessage<T | undefined> { function toBinaryKafkaMessage<T>(event: CloudEventV1<T>): KafkaMessage<T> {
// 3.2.1. Content Type // 3.2.1. Content Type
// For the binary mode, the header content-type property MUST be mapped directly // For the binary mode, the header content-type property MUST be mapped directly
// to the CloudEvents datacontenttype attribute. // to the CloudEvents datacontenttype attribute.
@ -86,7 +86,7 @@ function toBinaryKafkaMessage<T>(event: CloudEventV1<T>): KafkaMessage<T | undef
* @param {CloudEvent<T>} event the CloudEvent to be serialized * @param {CloudEvent<T>} event the CloudEvent to be serialized
* @returns {KafkaMessage<T>} a KafkaMessage instance * @returns {KafkaMessage<T>} a KafkaMessage instance
*/ */
function toStructuredKafkaMessage<T>(event: CloudEventV1<T>): KafkaMessage<string> { function toStructuredKafkaMessage<T>(event: CloudEventV1<T>): KafkaMessage<T> {
if ((event instanceof CloudEvent) && event.data_base64) { if ((event instanceof CloudEvent) && event.data_base64) {
// The event's data is binary - delete it // The event's data is binary - delete it
event = event.cloneWith({ data: undefined }); event = event.cloneWith({ data: undefined });
@ -130,9 +130,9 @@ function deserializeKafkaMessage<T>(message: Message): CloudEvent<T> | CloudEven
case Mode.BINARY: case Mode.BINARY:
return parseBinary(m); return parseBinary(m);
case Mode.STRUCTURED: case Mode.STRUCTURED:
return parseStructured(m as unknown as KafkaMessage<string>); return parseStructured(m);
case Mode.BATCH: case Mode.BATCH:
return parseBatched(m as unknown as KafkaMessage<string>); return parseBatched(m);
default: default:
throw new ValidationError("Unknown Message mode"); throw new ValidationError("Unknown Message mode");
} }
@ -212,14 +212,14 @@ function parseBinary<T>(message: KafkaMessage<T>): CloudEvent<T> {
* @param {KafkaMessage<T>} message the message * @param {KafkaMessage<T>} message the message
* @returns {CloudEvent<T>} a KafkaEvent<T> * @returns {CloudEvent<T>} a KafkaEvent<T>
*/ */
function parseStructured<T>(message: KafkaMessage<string>): CloudEvent<T> { function parseStructured<T>(message: KafkaMessage<T>): CloudEvent<T> {
// Although the format of a structured encoded event could be something // Although the format of a structured encoded event could be something
// other than JSON, e.g. XML, we currently only support JSON // other than JSON, e.g. XML, we currently only support JSON
// encoded structured events. // encoded structured events.
if (!message.headers[CONSTANTS.HEADER_CONTENT_TYPE]?.startsWith(CONSTANTS.MIME_CE_JSON)) { if (!message.headers[CONSTANTS.HEADER_CONTENT_TYPE]?.startsWith(CONSTANTS.MIME_CE_JSON)) {
throw new ValidationError(`Unsupported event encoding ${message.headers[CONSTANTS.HEADER_CONTENT_TYPE]}`); throw new ValidationError(`Unsupported event encoding ${message.headers[CONSTANTS.HEADER_CONTENT_TYPE]}`);
} }
const eventObj = JSON.parse(message.value); const eventObj = JSON.parse(message.value as string);
eventObj.time = new Date(eventObj.time).toISOString(); eventObj.time = new Date(eventObj.time).toISOString();
return new CloudEvent({ return new CloudEvent({
...eventObj, ...eventObj,
@ -232,14 +232,14 @@ function parseStructured<T>(message: KafkaMessage<string>): CloudEvent<T> {
* @param {KafkaMessage<T>} message the message * @param {KafkaMessage<T>} message the message
* @returns {CloudEvent<T>[]} an array of KafkaEvent<T> * @returns {CloudEvent<T>[]} an array of KafkaEvent<T>
*/ */
function parseBatched<T>(message: KafkaMessage<string>): CloudEvent<T>[] { function parseBatched<T>(message: KafkaMessage<T>): CloudEvent<T>[] {
// Although the format of batch encoded events could be something // Although the format of batch encoded events could be something
// other than JSON, e.g. XML, we currently only support JSON // other than JSON, e.g. XML, we currently only support JSON
// encoded structured events. // encoded structured events.
if (!message.headers[CONSTANTS.HEADER_CONTENT_TYPE]?.startsWith(CONSTANTS.MIME_CE_BATCH)) { if (!message.headers[CONSTANTS.HEADER_CONTENT_TYPE]?.startsWith(CONSTANTS.MIME_CE_BATCH)) {
throw new ValidationError(`Unsupported event encoding ${message.headers[CONSTANTS.HEADER_CONTENT_TYPE]}`); throw new ValidationError(`Unsupported event encoding ${message.headers[CONSTANTS.HEADER_CONTENT_TYPE]}`);
} }
const events = JSON.parse(message.value) as Record<string, unknown>[]; const events = JSON.parse(message.value as string) as Record<string, unknown>[];
return events.map((e) => new CloudEvent({ ...e, partitionkey: message.key }, false)); return events.map((e) => new CloudEvent({ ...e, partitionkey: message.key }, false));
} }

View File

@ -4,7 +4,6 @@
*/ */
import { Binding, Deserializer, CloudEvent, CloudEventV1, CONSTANTS, Message, ValidationError, Headers } from "../.."; import { Binding, Deserializer, CloudEvent, CloudEventV1, CONSTANTS, Message, ValidationError, Headers } from "../..";
import { base64AsBinary } from "../../event/validation";
export { export {
MQTT, MQTTMessageFactory MQTT, MQTTMessageFactory
@ -15,7 +14,7 @@ export type { MQTTMessage };
* Extends the base {@linkcode Message} interface to include MQTT attributes, some of which * Extends the base {@linkcode Message} interface to include MQTT attributes, some of which
* are aliases of the {Message} attributes. * are aliases of the {Message} attributes.
*/ */
interface MQTTMessage<T = unknown> extends Message<T> { interface MQTTMessage<T> extends Message<T> {
/** /**
* Identifies this message as a PUBLISH packet. MQTTMessages created with * Identifies this message as a PUBLISH packet. MQTTMessages created with
* the `binary` and `structured` Serializers will contain a "Content Type" * the `binary` and `structured` Serializers will contain a "Content Type"
@ -37,7 +36,7 @@ interface MQTTMessage<T = unknown> extends Message<T> {
* Binding for MQTT transport support * Binding for MQTT transport support
* @implements @linkcode Binding * @implements @linkcode Binding
*/ */
const MQTT: Binding<MQTTMessage, MQTTMessage> = { const MQTT: Binding = {
binary, binary,
structured, structured,
toEvent: toEvent as Deserializer, toEvent: toEvent as Deserializer,
@ -51,16 +50,14 @@ const MQTT: Binding<MQTTMessage, MQTTMessage> = {
* @implements {Serializer} * @implements {Serializer}
*/ */
function binary<T>(event: CloudEventV1<T>): MQTTMessage<T> { function binary<T>(event: CloudEventV1<T>): MQTTMessage<T> {
const properties = { ...event }; let properties;
if (event instanceof CloudEvent) {
let body = properties.data as T; properties = event.toJSON();
} else {
if (!body && properties.data_base64) { properties = event;
body = base64AsBinary(properties.data_base64) as unknown as T;
} }
const body = properties.data as T;
delete properties.data; delete properties.data;
delete properties.data_base64;
return MQTTMessageFactory(event.datacontenttype as string, properties, body); return MQTTMessageFactory(event.datacontenttype as string, properties, body);
} }

View File

@ -3,11 +3,9 @@
SPDX-License-Identifier: Apache-2.0 SPDX-License-Identifier: Apache-2.0
*/ */
import JSONbig from "json-bigint";
import CONSTANTS from "./constants"; import CONSTANTS from "./constants";
import { isString, isDefinedOrThrow, isStringOrObjectOrThrow, ValidationError } from "./event/validation"; import { isString, isDefinedOrThrow, isStringOrObjectOrThrow, ValidationError } from "./event/validation";
const __JSON = JSON;
export abstract class Parser { export abstract class Parser {
abstract parse(payload: Record<string, unknown> | string | string[] | undefined): unknown; abstract parse(payload: Record<string, unknown> | string | string[] | undefined): unknown;
} }
@ -38,13 +36,6 @@ export class JSONParser implements Parser {
isDefinedOrThrow(payload, new ValidationError("null or undefined payload")); isDefinedOrThrow(payload, new ValidationError("null or undefined payload"));
isStringOrObjectOrThrow(payload, new ValidationError("invalid payload type, allowed are: string or object")); isStringOrObjectOrThrow(payload, new ValidationError("invalid payload type, allowed are: string or object"));
if (process.env[CONSTANTS.USE_BIG_INT_ENV] === "true") {
JSON = JSONbig(({ useNativeBigInt: true })) as JSON;
} else {
JSON = __JSON;
}
const parseJSON = (v: Record<string, unknown> | string): string => (isString(v) ? JSON.parse(v as string) : v); const parseJSON = (v: Record<string, unknown> | string): string => (isString(v) ? JSON.parse(v as string) : v);
return parseJSON(payload); return parseJSON(payload);
} }

View File

@ -7,39 +7,24 @@ import path from "path";
import fs from "fs"; import fs from "fs";
import { expect } from "chai"; import { expect } from "chai";
import { CloudEvent, CloudEventV1, ValidationError, V1 } from "../../src"; import { CloudEvent, ValidationError, Version } from "../../src";
import { asBase64 } from "../../src/event/validation"; import { asBase64 } from "../../src/event/validation";
const type = "org.cncf.cloudevents.example"; const type = "org.cncf.cloudevents.example";
const source = "http://unit.test"; const source = "http://unit.test";
const id = "b46cf653-d48a-4b90-8dfa-355c01061361"; const id = "b46cf653-d48a-4b90-8dfa-355c01061361";
const fixture = Object.freeze({ const fixture = {
id, id,
specversion: V1, specversion: Version.V1,
source, source,
type, type,
data: `"some data"` data: `"some data"`,
}); };
const imageData = new Uint32Array(fs.readFileSync(path.join(process.cwd(), "test", "integration", "ce.png"))); const imageData = new Uint32Array(fs.readFileSync(path.join(process.cwd(), "test", "integration", "ce.png")));
const image_base64 = asBase64(imageData); const image_base64 = asBase64(imageData);
// Do not replace this with the assignment of a class instance
// as we just want to test if we can enumerate all explicitly defined fields!
const cloudEventV1InterfaceFields: (keyof CloudEventV1<unknown>)[] = Object.keys({
id: "",
type: "",
data: undefined,
data_base64: "",
source: "",
time: "",
datacontenttype: "",
dataschema: "",
specversion: "",
subject: ""
} as Required<CloudEventV1<unknown>>);
describe("A CloudEvent", () => { describe("A CloudEvent", () => {
it("Can be constructed with a typed Message", () => { it("Can be constructed with a typed Message", () => {
const ce = new CloudEvent(fixture); const ce = new CloudEvent(fixture);
@ -82,10 +67,10 @@ describe("A CloudEvent", () => {
}).throw("invalid extension name"); }).throw("invalid extension name");
}); });
it("Not throw a validation error for invalid extension names, more than 20 chars", () => { it("Throw a validation error for invalid extension names, more than 20 chars", () => {
expect(() => { expect(() => {
new CloudEvent({ "123456789012345678901": "extension1", ...fixture }); new CloudEvent({ "123456789012345678901": "extension1", ...fixture });
}).not.throw("invalid extension name"); }).throw("invalid extension name");
}); });
it("Throws a validation error for invalid uppercase extension names", () => { it("Throws a validation error for invalid uppercase extension names", () => {
@ -93,58 +78,6 @@ describe("A CloudEvent", () => {
new CloudEvent({ ExtensionWithCaps: "extension value", ...fixture }); new CloudEvent({ ExtensionWithCaps: "extension value", ...fixture });
}).throw("invalid extension name"); }).throw("invalid extension name");
}); });
it("CloudEventV1 interface fields should be enumerable", () => {
const classInstanceKeys = Object.keys(new CloudEvent({ ...fixture }));
for (const key of cloudEventV1InterfaceFields) {
expect(classInstanceKeys).to.contain(key);
}
});
it("throws TypeError on trying to set any field value", () => {
const ce = new CloudEvent({
...fixture,
mycustomfield: "initialValue"
});
const keySet = new Set([...cloudEventV1InterfaceFields, ...Object.keys(ce)]);
expect(keySet).not.to.be.empty;
for (const cloudEventKey of keySet) {
let threw = false;
try {
ce[cloudEventKey] = "newValue";
} catch (err) {
threw = true;
expect(err).to.be.instanceOf(TypeError);
expect((err as TypeError).message).to.include("Cannot assign to read only property");
}
if (!threw) {
expect.fail(`Assigning a value to ${cloudEventKey} did not throw`);
}
}
});
describe("toJSON()", () => {
it("does not return data field if data_base64 field is set to comply with JSON format spec 3.1.1", () => {
const binaryData = new Uint8Array([1,2,3]);
const ce = new CloudEvent({
...fixture,
data: binaryData
});
expect(ce.data).to.be.equal(binaryData);
const json = ce.toJSON();
expect(json.data).to.not.exist;
expect(json.data_base64).to.be.equal("AQID");
});
});
}); });
describe("A 1.0 CloudEvent", () => { describe("A 1.0 CloudEvent", () => {
@ -165,7 +98,7 @@ describe("A 1.0 CloudEvent", () => {
}); });
it("can be constructed with an ID", () => { it("can be constructed with an ID", () => {
const ce = new CloudEvent({ id: "1234", specversion: V1, source, type }); const ce = new CloudEvent({ id: "1234", specversion: Version.V1, source, type });
expect(ce.id).to.equal("1234"); expect(ce.id).to.equal("1234");
}); });
@ -280,7 +213,7 @@ describe("A 1.0 CloudEvent", () => {
const obj = JSON.parse(json as string); const obj = JSON.parse(json as string);
expect(obj.type).to.equal(type); expect(obj.type).to.equal(type);
expect(obj.source).to.equal(source); expect(obj.source).to.equal(source);
expect(obj.specversion).to.equal(V1); expect(obj.specversion).to.equal(Version.V1);
}); });
it("throws if the provded source is empty string", () => { it("throws if the provded source is empty string", () => {

View File

@ -26,7 +26,7 @@ describe("Emitter Singleton", () => {
if (typeof body === "string") { if (typeof body === "string") {
body = JSON.parse(body); body = JSON.parse(body);
} }
assertStructured({ ...(body as any), ...(msg as Message).headers }); assertStructured({ ...(<any>body), ...(msg as Message).headers });
}); });
it("emit a Node.js 'cloudevent' event as an EventEmitter with ensureDelivery", async () => { it("emit a Node.js 'cloudevent' event as an EventEmitter with ensureDelivery", async () => {
@ -41,7 +41,7 @@ describe("Emitter Singleton", () => {
if (typeof body === "string") { if (typeof body === "string") {
body = JSON.parse(body); body = JSON.parse(body);
} }
assertStructured({ ...(body as any), ...(msg as Message).headers }); assertStructured({ ...(<any>body), ...(msg as Message).headers });
}); });
it("emit a Node.js 'cloudevent' event as an EventEmitter with ensureDelivery Error", async () => { it("emit a Node.js 'cloudevent' event as an EventEmitter with ensureDelivery Error", async () => {

View File

@ -7,7 +7,7 @@ import path from "path";
import fs from "fs"; import fs from "fs";
import { expect } from "chai"; import { expect } from "chai";
import { CloudEvent, CONSTANTS, V1 } from "../../src"; import { CloudEvent, CONSTANTS, Version } from "../../src";
import { asBase64 } from "../../src/event/validation"; import { asBase64 } from "../../src/event/validation";
import { Message, Kafka, KafkaMessage, KafkaEvent } from "../../src/message"; import { Message, Kafka, KafkaMessage, KafkaEvent } from "../../src/message";
import { KAFKA_CE_HEADERS } from "../../src/message/kafka/headers"; import { KAFKA_CE_HEADERS } from "../../src/message/kafka/headers";
@ -43,7 +43,7 @@ const imageData = new Uint32Array(fs.readFileSync(path.join(process.cwd(), "test
const image_base64 = asBase64(imageData); const image_base64 = asBase64(imageData);
const fixture = new CloudEvent({ const fixture = new CloudEvent({
specversion: V1, specversion: Version.V1,
id, id,
type, type,
source, source,
@ -131,7 +131,7 @@ describe("Kafka transport", () => {
expect(event.LUNCH).to.equal("tacos"); expect(event.LUNCH).to.equal("tacos");
expect(function () { expect(function () {
event.validate(); event.validate();
}).to.throw("invalid attribute name: \"LUNCH\""); }).to.throw("invalid attribute name: LUNCH");
}); });
it("Can detect CloudEvent binary Messages with weird versions", () => { it("Can detect CloudEvent binary Messages with weird versions", () => {
@ -233,7 +233,7 @@ describe("Kafka transport", () => {
expect(message.body).to.equal(data); expect(message.body).to.equal(data);
// validate all headers // validate all headers
expect(message.headers[CONSTANTS.HEADER_CONTENT_TYPE]).to.equal(datacontenttype); expect(message.headers[CONSTANTS.HEADER_CONTENT_TYPE]).to.equal(datacontenttype);
expect(message.headers[KAFKA_CE_HEADERS.SPEC_VERSION]).to.equal(V1); expect(message.headers[KAFKA_CE_HEADERS.SPEC_VERSION]).to.equal(Version.V1);
expect(message.headers[KAFKA_CE_HEADERS.ID]).to.equal(id); expect(message.headers[KAFKA_CE_HEADERS.ID]).to.equal(id);
expect(message.headers[KAFKA_CE_HEADERS.TYPE]).to.equal(type); expect(message.headers[KAFKA_CE_HEADERS.TYPE]).to.equal(type);
expect(message.headers[KAFKA_CE_HEADERS.SOURCE]).to.equal(source); expect(message.headers[KAFKA_CE_HEADERS.SOURCE]).to.equal(source);
@ -249,7 +249,7 @@ describe("Kafka transport", () => {
expect(message.headers[CONSTANTS.HEADER_CONTENT_TYPE]).to.equal(CONSTANTS.DEFAULT_CE_CONTENT_TYPE); expect(message.headers[CONSTANTS.HEADER_CONTENT_TYPE]).to.equal(CONSTANTS.DEFAULT_CE_CONTENT_TYPE);
// Parse the message body as JSON, then validate the attributes // Parse the message body as JSON, then validate the attributes
const body = JSON.parse(message.body as string); const body = JSON.parse(message.body as string);
expect(body[CONSTANTS.CE_ATTRIBUTES.SPEC_VERSION]).to.equal(V1); expect(body[CONSTANTS.CE_ATTRIBUTES.SPEC_VERSION]).to.equal(Version.V1);
expect(body[CONSTANTS.CE_ATTRIBUTES.ID]).to.equal(id); expect(body[CONSTANTS.CE_ATTRIBUTES.ID]).to.equal(id);
expect(body[CONSTANTS.CE_ATTRIBUTES.TYPE]).to.equal(type); expect(body[CONSTANTS.CE_ATTRIBUTES.TYPE]).to.equal(type);
expect(body[CONSTANTS.CE_ATTRIBUTES.SOURCE]).to.equal(source); expect(body[CONSTANTS.CE_ATTRIBUTES.SOURCE]).to.equal(source);

View File

@ -8,7 +8,7 @@ import fs from "fs";
import { expect } from "chai"; import { expect } from "chai";
import { IncomingHttpHeaders } from "http"; import { IncomingHttpHeaders } from "http";
import { CloudEvent, CONSTANTS, V1, V03 } from "../../src"; import { CloudEvent, CONSTANTS, Version } from "../../src";
import { asBase64 } from "../../src/event/validation"; import { asBase64 } from "../../src/event/validation";
import { Message, HTTP } from "../../src/message"; import { Message, HTTP } from "../../src/message";
@ -41,60 +41,6 @@ const imageData = new Uint32Array(fs.readFileSync(path.join(process.cwd(), "test
const image_base64 = asBase64(imageData); const image_base64 = asBase64(imageData);
describe("HTTP transport", () => { describe("HTTP transport", () => {
it("validates extension attribute names for incoming messages", () => {
// create a new Message
const msg: Message = {
headers: {
"ce-id": "213",
"ce-source": "test",
"ce-type": "test",
"ce-bad-extension": "value"
},
body: undefined
};
const evt = HTTP.toEvent(msg) as CloudEvent;
expect(() => evt.validate()).to.throw(TypeError);
});
it("Includes extensions in binary mode when type is 'boolean' with a false value", () => {
const evt = new CloudEvent({ source: "test", type: "test", extboolean: false });
expect(evt.hasOwnProperty("extboolean")).to.equal(true);
expect(evt["extboolean"]).to.equal(false);
const message = HTTP.binary(evt);
expect(message.headers.hasOwnProperty("ce-extboolean")).to.equal(true);
expect(message.headers["ce-extboolean"]).to.equal(false);
});
it("Includes extensions in structured when type is 'boolean' with a false value", () => {
const evt = new CloudEvent({ source: "test", type: "test", extboolean: false });
expect(evt.hasOwnProperty("extboolean")).to.equal(true);
expect(evt["extboolean"]).to.equal(false);
const message = HTTP.structured(evt);
const body = JSON.parse(message.body as string);
expect(body.hasOwnProperty("extboolean")).to.equal(true);
expect(body.extboolean).to.equal(false);
});
it("Handles big integers in structured mode", () => {
process.env[CONSTANTS.USE_BIG_INT_ENV] = "true";
const ce = HTTP.toEvent({
headers: { "content-type": "application/cloudevents+json" },
body: `{"data": 1524831183200260097}`
}) as CloudEvent;
expect(ce.data).to.equal(1524831183200260097n);
process.env[CONSTANTS.USE_BIG_INT_ENV] = undefined;
});
it("Handles big integers in binary mode", () => {
process.env[CONSTANTS.USE_BIG_INT_ENV] = "true";
const ce = HTTP.toEvent({
headers: { "content-type": "application/json", "ce-id": "1234" },
body: `{"data": 1524831183200260097}`
}) as CloudEvent<Record<string, never>>;
expect((ce.data as Record<string, never>).data).to.equal(1524831183200260097n);
process.env[CONSTANTS.USE_BIG_INT_ENV] = undefined;
});
it("Handles events with no content-type and no datacontenttype", () => { it("Handles events with no content-type and no datacontenttype", () => {
const body = "{Something[Not:valid}JSON"; const body = "{Something[Not:valid}JSON";
const message: Message<undefined> = { const message: Message<undefined> = {
@ -154,7 +100,7 @@ describe("HTTP transport", () => {
[CONSTANTS.CE_HEADERS.ID]: "1234", [CONSTANTS.CE_HEADERS.ID]: "1234",
[CONSTANTS.CE_HEADERS.SOURCE]: "test", [CONSTANTS.CE_HEADERS.SOURCE]: "test",
[CONSTANTS.CE_HEADERS.TYPE]: "test.event", [CONSTANTS.CE_HEADERS.TYPE]: "test.event",
[CONSTANTS.CE_HEADERS.SPEC_VERSION]: V1, [CONSTANTS.CE_HEADERS.SPEC_VERSION]: Version.V1,
"ce-LUNCH": "tacos", "ce-LUNCH": "tacos",
}, },
}; };
@ -163,7 +109,7 @@ describe("HTTP transport", () => {
expect(event.LUNCH).to.equal("tacos"); expect(event.LUNCH).to.equal("tacos");
expect(function () { expect(function () {
event.validate(); event.validate();
}).to.throw("invalid attribute name: \"LUNCH\""); }).to.throw("invalid attribute name: LUNCH");
}); });
it("Can detect CloudEvent binary Messages with weird versions", () => { it("Can detect CloudEvent binary Messages with weird versions", () => {
@ -237,7 +183,7 @@ describe("HTTP transport", () => {
id, id,
type, type,
source, source,
specversion: V1, specversion: Version.V1,
data: { lunch: "tacos" }, data: { lunch: "tacos" },
}); });
const message: Message<undefined> = { const message: Message<undefined> = {
@ -250,7 +196,7 @@ describe("HTTP transport", () => {
describe("Specification version V1", () => { describe("Specification version V1", () => {
const fixture = new CloudEvent({ const fixture = new CloudEvent({
specversion: V1, specversion: Version.V1,
id, id,
type, type,
source, source,
@ -268,7 +214,7 @@ describe("HTTP transport", () => {
expect(message.body).to.equal(JSON.stringify(data)); expect(message.body).to.equal(JSON.stringify(data));
// validate all headers // validate all headers
expect(message.headers[CONSTANTS.HEADER_CONTENT_TYPE]).to.equal(datacontenttype); expect(message.headers[CONSTANTS.HEADER_CONTENT_TYPE]).to.equal(datacontenttype);
expect(message.headers[CONSTANTS.CE_HEADERS.SPEC_VERSION]).to.equal(V1); expect(message.headers[CONSTANTS.CE_HEADERS.SPEC_VERSION]).to.equal(Version.V1);
expect(message.headers[CONSTANTS.CE_HEADERS.ID]).to.equal(id); expect(message.headers[CONSTANTS.CE_HEADERS.ID]).to.equal(id);
expect(message.headers[CONSTANTS.CE_HEADERS.TYPE]).to.equal(type); expect(message.headers[CONSTANTS.CE_HEADERS.TYPE]).to.equal(type);
expect(message.headers[CONSTANTS.CE_HEADERS.SOURCE]).to.equal(source); expect(message.headers[CONSTANTS.CE_HEADERS.SOURCE]).to.equal(source);
@ -284,7 +230,7 @@ describe("HTTP transport", () => {
expect(message.headers[CONSTANTS.HEADER_CONTENT_TYPE]).to.equal(CONSTANTS.DEFAULT_CE_CONTENT_TYPE); expect(message.headers[CONSTANTS.HEADER_CONTENT_TYPE]).to.equal(CONSTANTS.DEFAULT_CE_CONTENT_TYPE);
// Parse the message body as JSON, then validate the attributes // Parse the message body as JSON, then validate the attributes
const body = JSON.parse(message.body as string); const body = JSON.parse(message.body as string);
expect(body[CONSTANTS.CE_ATTRIBUTES.SPEC_VERSION]).to.equal(V1); expect(body[CONSTANTS.CE_ATTRIBUTES.SPEC_VERSION]).to.equal(Version.V1);
expect(body[CONSTANTS.CE_ATTRIBUTES.ID]).to.equal(id); expect(body[CONSTANTS.CE_ATTRIBUTES.ID]).to.equal(id);
expect(body[CONSTANTS.CE_ATTRIBUTES.TYPE]).to.equal(type); expect(body[CONSTANTS.CE_ATTRIBUTES.TYPE]).to.equal(type);
expect(body[CONSTANTS.CE_ATTRIBUTES.SOURCE]).to.equal(source); expect(body[CONSTANTS.CE_ATTRIBUTES.SOURCE]).to.equal(source);
@ -353,7 +299,7 @@ describe("HTTP transport", () => {
describe("Specification version V03", () => { describe("Specification version V03", () => {
const fixture = new CloudEvent({ const fixture = new CloudEvent({
specversion: V03, specversion: Version.V03,
id, id,
type, type,
source, source,
@ -371,7 +317,7 @@ describe("HTTP transport", () => {
expect(message.body).to.equal(JSON.stringify(data)); expect(message.body).to.equal(JSON.stringify(data));
// validate all headers // validate all headers
expect(message.headers[CONSTANTS.HEADER_CONTENT_TYPE]).to.equal(datacontenttype); expect(message.headers[CONSTANTS.HEADER_CONTENT_TYPE]).to.equal(datacontenttype);
expect(message.headers[CONSTANTS.CE_HEADERS.SPEC_VERSION]).to.equal(V03); expect(message.headers[CONSTANTS.CE_HEADERS.SPEC_VERSION]).to.equal(Version.V03);
expect(message.headers[CONSTANTS.CE_HEADERS.ID]).to.equal(id); expect(message.headers[CONSTANTS.CE_HEADERS.ID]).to.equal(id);
expect(message.headers[CONSTANTS.CE_HEADERS.TYPE]).to.equal(type); expect(message.headers[CONSTANTS.CE_HEADERS.TYPE]).to.equal(type);
expect(message.headers[CONSTANTS.CE_HEADERS.SOURCE]).to.equal(source); expect(message.headers[CONSTANTS.CE_HEADERS.SOURCE]).to.equal(source);
@ -387,7 +333,7 @@ describe("HTTP transport", () => {
expect(message.headers[CONSTANTS.HEADER_CONTENT_TYPE]).to.equal(CONSTANTS.DEFAULT_CE_CONTENT_TYPE); expect(message.headers[CONSTANTS.HEADER_CONTENT_TYPE]).to.equal(CONSTANTS.DEFAULT_CE_CONTENT_TYPE);
// Parse the message body as JSON, then validate the attributes // Parse the message body as JSON, then validate the attributes
const body = JSON.parse(message.body as string); const body = JSON.parse(message.body as string);
expect(body[CONSTANTS.CE_ATTRIBUTES.SPEC_VERSION]).to.equal(V03); expect(body[CONSTANTS.CE_ATTRIBUTES.SPEC_VERSION]).to.equal(Version.V03);
expect(body[CONSTANTS.CE_ATTRIBUTES.ID]).to.equal(id); expect(body[CONSTANTS.CE_ATTRIBUTES.ID]).to.equal(id);
expect(body[CONSTANTS.CE_ATTRIBUTES.TYPE]).to.equal(type); expect(body[CONSTANTS.CE_ATTRIBUTES.TYPE]).to.equal(type);
expect(body[CONSTANTS.CE_ATTRIBUTES.SOURCE]).to.equal(source); expect(body[CONSTANTS.CE_ATTRIBUTES.SOURCE]).to.equal(source);

View File

@ -7,7 +7,7 @@ import path from "path";
import fs from "fs"; import fs from "fs";
import { expect } from "chai"; import { expect } from "chai";
import { CloudEvent, CONSTANTS, V1, Headers } from "../../src"; import { CloudEvent, CONSTANTS, Version, Headers } from "../../src";
import { asBase64 } from "../../src/event/validation"; import { asBase64 } from "../../src/event/validation";
import { Message, MQTT, MQTTMessage } from "../../src/message"; import { Message, MQTT, MQTTMessage } from "../../src/message";
@ -32,18 +32,18 @@ const ext2Name = "extension2";
const ext2Value = "acme"; const ext2Value = "acme";
// Binary data as base64 // Binary data as base64
const dataBinary = Uint8Array.from(JSON.stringify(data), (c) => c.codePointAt(0) as number); const dataBinary = Uint32Array.from(JSON.stringify(data), (c) => c.codePointAt(0) as number);
const data_base64 = asBase64(dataBinary); const data_base64 = asBase64(dataBinary);
// Since the above is a special case (string as binary), let's test // Since the above is a special case (string as binary), let's test
// with a real binary file one is likely to encounter in the wild // with a real binary file one is likely to encounter in the wild
const imageData = new Uint8Array(fs.readFileSync(path.join(process.cwd(), "test", "integration", "ce.png"))); const imageData = new Uint32Array(fs.readFileSync(path.join(process.cwd(), "test", "integration", "ce.png")));
const image_base64 = asBase64(imageData); const image_base64 = asBase64(imageData);
const PUBLISH = {"Content Type": "application/json; charset=utf-8"}; const PUBLISH = {"Content Type": "application/json; charset=utf-8"};
const fixture = new CloudEvent({ const fixture = new CloudEvent({
specversion: V1, specversion: Version.V1,
id, id,
type, type,
source, source,
@ -134,7 +134,7 @@ describe("MQTT transport", () => {
expect(event.LUNCH).to.equal("tacos"); expect(event.LUNCH).to.equal("tacos");
expect(function () { expect(function () {
event.validate(); event.validate();
}).to.throw("invalid attribute name: \"LUNCH\""); }).to.throw("invalid attribute name: LUNCH");
}); });
it("Can detect CloudEvent binary Messages with weird versions", () => { it("Can detect CloudEvent binary Messages with weird versions", () => {
@ -216,7 +216,7 @@ describe("MQTT transport", () => {
expect(message.body).to.equal(data); expect(message.body).to.equal(data);
// validate all headers // validate all headers
expect(message.headers.datacontenttype).to.equal(datacontenttype); expect(message.headers.datacontenttype).to.equal(datacontenttype);
expect(message.headers.specversion).to.equal(V1); expect(message.headers.specversion).to.equal(Version.V1);
expect(message.headers.id).to.equal(id); expect(message.headers.id).to.equal(id);
expect(message.headers.type).to.equal(type); expect(message.headers.type).to.equal(type);
expect(message.headers.source).to.equal(source); expect(message.headers.source).to.equal(source);
@ -232,7 +232,7 @@ describe("MQTT transport", () => {
expect(message.body).to.equal(data); expect(message.body).to.equal(data);
// validate all headers // validate all headers
expect(message["User Properties"]?.datacontenttype).to.equal(datacontenttype); expect(message["User Properties"]?.datacontenttype).to.equal(datacontenttype);
expect(message["User Properties"]?.specversion).to.equal(V1); expect(message["User Properties"]?.specversion).to.equal(Version.V1);
expect(message["User Properties"]?.id).to.equal(id); expect(message["User Properties"]?.id).to.equal(id);
expect(message["User Properties"]?.type).to.equal(type); expect(message["User Properties"]?.type).to.equal(type);
expect(message["User Properties"]?.source).to.equal(source); expect(message["User Properties"]?.source).to.equal(source);
@ -249,7 +249,7 @@ describe("MQTT transport", () => {
expect(message.body).to.deep.equal(message.payload); expect(message.body).to.deep.equal(message.payload);
expect(message.payload).to.deep.equal(fixture.toJSON()); expect(message.payload).to.deep.equal(fixture.toJSON());
const body = message.body as Record<string, string>; const body = message.body as Record<string, string>;
expect(body[CONSTANTS.CE_ATTRIBUTES.SPEC_VERSION]).to.equal(V1); expect(body[CONSTANTS.CE_ATTRIBUTES.SPEC_VERSION]).to.equal(Version.V1);
expect(body[CONSTANTS.CE_ATTRIBUTES.ID]).to.equal(id); expect(body[CONSTANTS.CE_ATTRIBUTES.ID]).to.equal(id);
expect(body[CONSTANTS.CE_ATTRIBUTES.TYPE]).to.equal(type); expect(body[CONSTANTS.CE_ATTRIBUTES.TYPE]).to.equal(type);
expect(body[CONSTANTS.CE_ATTRIBUTES.SOURCE]).to.equal(source); expect(body[CONSTANTS.CE_ATTRIBUTES.SOURCE]).to.equal(source);
@ -281,14 +281,14 @@ describe("MQTT transport", () => {
it("Converts base64 encoded data to binary when deserializing structured messages", () => { it("Converts base64 encoded data to binary when deserializing structured messages", () => {
const message = MQTT.structured(fixture.cloneWith({ data: imageData, datacontenttype: "image/png" })); const message = MQTT.structured(fixture.cloneWith({ data: imageData, datacontenttype: "image/png" }));
const eventDeserialized = MQTT.toEvent(message) as CloudEvent<Uint8Array>; const eventDeserialized = MQTT.toEvent(message) as CloudEvent<Uint32Array>;
expect(eventDeserialized.data).to.deep.equal(imageData); expect(eventDeserialized.data).to.deep.equal(imageData);
expect(eventDeserialized.data_base64).to.equal(image_base64); expect(eventDeserialized.data_base64).to.equal(image_base64);
}); });
it("Converts base64 encoded data to binary when deserializing binary messages", () => { it("Converts base64 encoded data to binary when deserializing binary messages", () => {
const message = MQTT.binary(fixture.cloneWith({ data: imageData, datacontenttype: "image/png" })); const message = MQTT.binary(fixture.cloneWith({ data: imageData, datacontenttype: "image/png" }));
const eventDeserialized = MQTT.toEvent(message) as CloudEvent<Uint8Array>; const eventDeserialized = MQTT.toEvent(message) as CloudEvent<Uint32Array>;
expect(eventDeserialized.data).to.deep.equal(imageData); expect(eventDeserialized.data).to.deep.equal(imageData);
expect(eventDeserialized.data_base64).to.equal(image_base64); expect(eventDeserialized.data_base64).to.equal(image_base64);
}); });
@ -302,7 +302,7 @@ describe("MQTT transport", () => {
it("Does not parse binary data from binary messages with content type application/json", () => { it("Does not parse binary data from binary messages with content type application/json", () => {
const message = MQTT.binary(fixture.cloneWith({ data: dataBinary })); const message = MQTT.binary(fixture.cloneWith({ data: dataBinary }));
const eventDeserialized = MQTT.toEvent(message) as CloudEvent<Uint8Array>; const eventDeserialized = MQTT.toEvent(message) as CloudEvent<Uint32Array>;
expect(eventDeserialized.data).to.deep.equal(dataBinary); expect(eventDeserialized.data).to.deep.equal(dataBinary);
expect(eventDeserialized.data_base64).to.equal(data_base64); expect(eventDeserialized.data_base64).to.equal(data_base64);
}); });

View File

@ -56,7 +56,7 @@ describe("JSON Event Format Parser", () => {
const parser = new Parser(); const parser = new Parser();
// TODO: Should the parser catch the SyntaxError and re-throw a ValidationError? // TODO: Should the parser catch the SyntaxError and re-throw a ValidationError?
expect(parser.parse.bind(parser, payload)).to.throw(SyntaxError); expect(parser.parse.bind(parser, payload)).to.throw(SyntaxError, "Unexpected token g in JSON at position 1");
}); });
it("Accepts a string as valid JSON", () => { it("Accepts a string as valid JSON", () => {

View File

@ -5,13 +5,13 @@
import "mocha"; import "mocha";
import { expect } from "chai"; import { expect } from "chai";
import { CloudEvent, CloudEventV1, V1, V03 } from "../../src"; import { CloudEvent, CloudEventV1, Version } from "../../src";
const fixture: CloudEventV1<undefined> = { const fixture: CloudEventV1<undefined> = {
id: "123", id: "123",
type: "org.cloudevents.test", type: "org.cloudevents.test",
source: "http://cloudevents.io", source: "http://cloudevents.io",
specversion: V1, specversion: Version.V1,
}; };
describe("The SDK Requirements", () => { describe("The SDK Requirements", () => {
@ -25,15 +25,15 @@ describe("The SDK Requirements", () => {
expect( expect(
new CloudEvent({ new CloudEvent({
...fixture, ...fixture,
specversion: V03, specversion: Version.V03,
}, false).specversion, }, false).specversion,
).to.equal(V03); ).to.equal(Version.V03);
}); });
}); });
describe("v1.0", () => { describe("v1.0", () => {
it("should create an event using the right spec version", () => { it("should create an event using the right spec version", () => {
expect(new CloudEvent(fixture).specversion).to.equal(V1); expect(new CloudEvent(fixture).specversion).to.equal(Version.V1);
}); });
}); });

View File

@ -5,7 +5,7 @@
import "mocha"; import "mocha";
import { expect } from "chai"; import { expect } from "chai";
import { CloudEvent, V1, ValidationError } from "../../src"; import { CloudEvent, Version, ValidationError } from "../../src";
import { asBase64 } from "../../src/event/validation"; import { asBase64 } from "../../src/event/validation";
import Constants from "../../src/constants"; import Constants from "../../src/constants";
@ -19,8 +19,8 @@ const data = {
}; };
const subject = "subject-x0"; const subject = "subject-x0";
const cloudevent = new CloudEvent({ let cloudevent = new CloudEvent({
specversion: V1, specversion: Version.V1,
id, id,
source, source,
type, type,
@ -99,16 +99,6 @@ describe("CloudEvents Spec v1.0", () => {
it("should be ok when the type is an string converted from an object", () => { it("should be ok when the type is an string converted from an object", () => {
expect(cloudevent.cloneWith({ objectextension: JSON.stringify({ some: "object" }) }).validate()).to.equal(true); expect(cloudevent.cloneWith({ objectextension: JSON.stringify({ some: "object" }) }).validate()).to.equal(true);
}); });
it("should only allow a-z|0-9 in the attribute names", () => {
const testCases = [
"an extension", "an_extension", "an-extension", "an.extension", "an+extension"
];
testCases.forEach((testCase) => {
const evt = cloudevent.cloneWith({ [testCase]: "a value"}, false);
expect(() => evt.validate()).to.throw(ValidationError);
});
});
}); });
describe("The Constraints check", () => { describe("The Constraints check", () => {
@ -120,8 +110,8 @@ describe("CloudEvents Spec v1.0", () => {
}); });
it("defaut ID create when an empty string", () => { it("defaut ID create when an empty string", () => {
const testEvent = cloudevent.cloneWith({ id: "" }); cloudevent = cloudevent.cloneWith({ id: "" });
expect(testEvent.id.length).to.be.greaterThan(0); expect(cloudevent.id.length).to.be.greaterThan(0);
}); });
}); });
@ -160,11 +150,11 @@ describe("CloudEvents Spec v1.0", () => {
describe("'time'", () => { describe("'time'", () => {
it("must adhere to the format specified in RFC 3339", () => { it("must adhere to the format specified in RFC 3339", () => {
const d = new Date(); const d = new Date();
const testEvent = cloudevent.cloneWith({ time: d.toString() }, false); cloudevent = cloudevent.cloneWith({ time: d.toString() }, false);
// ensure that we always get back the same thing we passed in // ensure that we always get back the same thing we passed in
expect(testEvent.time).to.equal(d.toString()); expect(cloudevent.time).to.equal(d.toString());
// ensure that when stringified, the timestamp is in RFC3339 format // ensure that when stringified, the timestamp is in RFC3339 format
expect(JSON.parse(JSON.stringify(testEvent)).time).to.equal(new Date(d.toString()).toISOString()); expect(JSON.parse(JSON.stringify(cloudevent)).time).to.equal(new Date(d.toString()).toISOString());
}); });
}); });
}); });
@ -183,60 +173,14 @@ describe("CloudEvents Spec v1.0", () => {
expect(typeof ce.data).to.equal("string"); expect(typeof ce.data).to.equal("string");
}); });
it("should be ok when type is 'Uint32Array' for 'Binary'", () => {
const dataString = ")(*~^my data for ce#@#$%"; const dataString = ")(*~^my data for ce#@#$%";
const testCases = [
{
type: Int8Array,
data: Int8Array.from(dataString, (c) => c.codePointAt(0) as number),
expected: asBase64(Int8Array.from(dataString, (c) => c.codePointAt(0) as number))
},
{
type: Uint8Array,
data: Uint8Array.from(dataString, (c) => c.codePointAt(0) as number),
expected: asBase64(Uint8Array.from(dataString, (c) => c.codePointAt(0) as number))
},
{
type: Int16Array,
data: Int16Array.from(dataString, (c) => c.codePointAt(0) as number),
expected: asBase64(Int16Array.from(dataString, (c) => c.codePointAt(0) as number))
},
{
type: Uint16Array,
data: Uint16Array.from(dataString, (c) => c.codePointAt(0) as number),
expected: asBase64(Uint16Array.from(dataString, (c) => c.codePointAt(0) as number))
},
{
type: Int32Array,
data: Int32Array.from(dataString, (c) => c.codePointAt(0) as number),
expected: asBase64(Int32Array.from(dataString, (c) => c.codePointAt(0) as number))
},
{
type: Uint32Array,
data: Uint32Array.from(dataString, (c) => c.codePointAt(0) as number),
expected: asBase64(Uint32Array.from(dataString, (c) => c.codePointAt(0) as number))
},
{
type: Uint8ClampedArray,
data: Uint8ClampedArray.from(dataString, (c) => c.codePointAt(0) as number),
expected: asBase64(Uint8ClampedArray.from(dataString, (c) => c.codePointAt(0) as number))
},
{
type: Float32Array,
data: Float32Array.from(dataString, (c) => c.codePointAt(0) as number),
expected: asBase64(Float32Array.from(dataString, (c) => c.codePointAt(0) as number))
},
{
type: Float64Array,
data: Float64Array.from(dataString, (c) => c.codePointAt(0) as number),
expected: asBase64(Float64Array.from(dataString, (c) => c.codePointAt(0) as number))
},
];
testCases.forEach((test) => { const dataBinary = Uint32Array.from(dataString, (c) => c.codePointAt(0) as number);
it(`should be ok when type is '${test.type.name}' for 'Binary'`, () => { const expected = asBase64(dataBinary);
const ce = cloudevent.cloneWith({ datacontenttype: "text/plain", data: test.data });
expect(ce.data_base64).to.equal(test.expected); const ce = cloudevent.cloneWith({ datacontenttype: "text/plain", data: dataBinary });
}); expect(ce.data_base64).to.equal(expected);
}); });
}); });
}); });

View File

@ -1,6 +1,6 @@
{ {
"compilerOptions": { "compilerOptions": {
"target": "ES2020", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */ "target": "ES2016", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */
"module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */ "module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */
"allowJs": true, /* Allow javascript files to be compiled. */ "allowJs": true, /* Allow javascript files to be compiled. */
"checkJs": false, /* Report errors in .js files. */ "checkJs": false, /* Report errors in .js files. */

View File

@ -1,5 +1,4 @@
const path = require("path"); const path = require("path");
const webpack = require("webpack");
module.exports = { module.exports = {
entry: { entry: {
@ -12,11 +11,6 @@ module.exports = {
https: false https: false
}, },
}, },
plugins: [
new webpack.ProvidePlugin({
process: 'process/browser'
})
],
output: { output: {
path: path.resolve(__dirname, "bundles"), path: path.resolve(__dirname, "bundles"),
filename: "[name].js", filename: "[name].js",