Compare commits
64 Commits
Author | SHA1 | Date |
---|---|---|
|
3c8819e2bc | |
|
beac7356a7 | |
|
fc760976bf | |
|
3ff6fdd3bf | |
|
c07afa9b77 | |
|
f475cdfd7e | |
|
8357719bab | |
|
6977113d7b | |
|
154e913717 | |
|
e7626077ed | |
|
c65afe94d2 | |
|
245bae92d1 | |
|
f93f896002 | |
|
16d0c0f91f | |
|
db60220762 | |
|
1ed43c8486 | |
|
df059e9696 | |
|
15f6505a58 | |
|
089520a4cc | |
|
fa388f7dc6 | |
|
0d923a4f92 | |
|
a0d8682613 | |
|
023171d9a0 | |
|
3d961371da | |
|
f3659ebfc6 | |
|
11442d32d3 | |
|
3931b224cb | |
|
43c3584b98 | |
|
1995b5778e | |
|
0120d224ab | |
|
2cb9364a25 | |
|
4626529d56 | |
|
ec83abc827 | |
|
1cf8f8acae | |
|
343382ebde | |
|
c06ffc1963 | |
|
7ff64f8b82 | |
|
870d2118cd | |
|
78b8e0a372 | |
|
953bc2a143 | |
|
bc3aaca2ef | |
|
e5ee8369ba | |
|
b374d9ac33 | |
|
64e527c120 | |
|
1b449c4c9a | |
|
eccc00ee67 | |
|
94f1a3d470 | |
|
3619ef2bbd | |
|
2d5fab1b71 | |
|
c09a9cc20a | |
|
4831e6a1a5 | |
|
760a024067 | |
|
c282922ef9 | |
|
ea94a4d779 | |
|
847f6bfcc7 | |
|
ed63f14339 | |
|
921e273ede | |
|
a62eb44669 | |
|
d6f52ca65f | |
|
ce02e0a1f3 | |
|
d9ee0e05d1 | |
|
addbd9acf1 | |
|
a512aad5d5 | |
|
c0b1f7705a |
|
@ -8,10 +8,10 @@ jobs:
|
|||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v4
|
||||
-
|
||||
name: Generate API documentation
|
||||
run: npm install && npm run generate-docs
|
||||
run: npm install && npm run build:schema && npm run generate-docs
|
||||
-
|
||||
name: Deploy to GitHub Pages
|
||||
if: success()
|
||||
|
|
|
@ -15,12 +15,12 @@ jobs:
|
|||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: [12.x, 14.x, 16.x]
|
||||
node-version: [20.x, 22.x, 24.x]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v4
|
||||
- name: Test on Node.js ${{ matrix.node-version }}
|
||||
uses: actions/setup-node@v1
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
- run: npm ci
|
||||
|
@ -31,18 +31,18 @@ jobs:
|
|||
name: Code coverage
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: true
|
||||
- name: Generate coverage report
|
||||
uses: actions/setup-node@v1
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 16.x
|
||||
node-version: 22.x
|
||||
- run: npm ci
|
||||
- run: npm run build --if-present
|
||||
- run: npm run coverage
|
||||
- name: Upload coverage report to storage
|
||||
uses: actions/upload-artifact@v1
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: coverage
|
||||
path: coverage/lcov.info
|
||||
|
@ -52,15 +52,15 @@ jobs:
|
|||
needs: coverage
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v4
|
||||
- name: Download coverage report from storage
|
||||
uses: actions/download-artifact@v1
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: coverage
|
||||
- name: Upload coverage report to codacy
|
||||
uses: actions/setup-node@v1
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 16.x
|
||||
node-version: 22.x
|
||||
- run: |
|
||||
( [[ "${CODACY_PROJECT_TOKEN}" != "" ]] && npm run coverage-publish ) || echo "Coverage report not published"
|
||||
env:
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
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 }}
|
|
@ -7,9 +7,11 @@ jobs:
|
|||
release-please:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: GoogleCloudPlatform/release-please-action@v2.5.5
|
||||
- uses: GoogleCloudPlatform/release-please-action@v3
|
||||
id: release
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
token: ${{ secrets.CLOUDEVENTS_RELEASES_TOKEN }}
|
||||
release-type: node
|
||||
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}]'
|
||||
|
|
|
@ -91,3 +91,6 @@ typings/
|
|||
|
||||
# Package lock
|
||||
package-lock.json
|
||||
|
||||
# Jetbrains IDE directories
|
||||
.idea
|
||||
|
|
154
CHANGELOG.md
154
CHANGELOG.md
|
@ -2,6 +2,160 @@
|
|||
|
||||
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)
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
# 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)
|
58
README.md
58
README.md
|
@ -12,14 +12,14 @@ The CloudEvents SDK for JavaScript.
|
|||
|
||||
- Represent CloudEvents in memory
|
||||
- Serialize and deserialize CloudEvents in different [event formats](https://github.com/cloudevents/spec/blob/v1.0/spec.md#event-format).
|
||||
- Send and recieve CloudEvents with via different [protocol bindings](https://github.com/cloudevents/spec/blob/v1.0/spec.md#protocol-binding).
|
||||
- Send and receive CloudEvents with via different [protocol bindings](https://github.com/cloudevents/spec/blob/v1.0/spec.md#protocol-binding).
|
||||
|
||||
_Note:_ Supports CloudEvent version 1.0
|
||||
|
||||
## Installation
|
||||
|
||||
The CloudEvents SDK requires a current LTS version of Node.js. At the moment
|
||||
those are Node.js 12.x, Node.js 14.x and Node.js 16.x. To install in your Node.js project:
|
||||
those are Node.js 16.x, and Node.js 18.x. To install in your Node.js project:
|
||||
|
||||
```console
|
||||
npm install cloudevents
|
||||
|
@ -51,7 +51,7 @@ The easiest way to send events is to use the built-in HTTP emitter.
|
|||
```js
|
||||
const { httpTransport, emitterFor, CloudEvent } = require("cloudevents");
|
||||
|
||||
// Create an emitter to send events to an to a reciever
|
||||
// Create an emitter to send events to a receiver
|
||||
const emit = emitterFor(httpTransport("https://my.receiver.com/endpoint"));
|
||||
|
||||
// Create a new CloudEvent
|
||||
|
@ -162,6 +162,20 @@ 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
|
||||
|
||||
There are a few trivial example applications in
|
||||
|
@ -177,37 +191,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) |
|
||||
| ------------------ | ------------------------------------------------------------- | ------------------------------------------------------------- |
|
||||
| CloudEvents Core | :heavy_check_mark: | :heavy_check_mark: |
|
||||
| CloudEvents Core | :white_check_mark: | :white_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) |
|
||||
| ----------------- | ----------------------------------------------------- | ----------------------------------------------------- |
|
||||
| AVRO Event Format | :x: | :x: |
|
||||
| JSON Event Format | :heavy_check_mark: | :heavy_check_mark: |
|
||||
| JSON Event Format | :white_check_mark: | :white_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) |
|
||||
| ---------------------- | ----------------------------------------------------- | ----------------------------------------------------- |
|
||||
| AMQP Protocol Binding | :x: | :x: |
|
||||
| HTTP Protocol Binding | :heavy_check_mark: | :heavy_check_mark: |
|
||||
| Kafka Protocol Binding | :x: | :heavy_check_mark: |
|
||||
| MQTT Protocol Binding | :heavy_check_mark: | :x: |
|
||||
| HTTP Protocol Binding | :white_check_mark: | :white_check_mark: |
|
||||
| Kafka Protocol Binding | :x: | :white_check_mark: |
|
||||
| MQTT Protocol Binding | :white_check_mark: | :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) |
|
||||
| ---------------------- | ----------------------------------------------------- | ----------------------------------------------------- |
|
||||
| HTTP Binary | :heavy_check_mark: | :heavy_check_mark: |
|
||||
| HTTP Structured | :heavy_check_mark: | :heavy_check_mark: |
|
||||
| HTTP Batch | :heavy_check_mark: | :heavy_check_mark: |
|
||||
| Kafka Binary | :heavy_check_mark: | :heavy_check_mark: |
|
||||
| Kafka Structured | :heavy_check_mark: | :heavy_check_mark: |
|
||||
| Kafka Batch | :heavy_check_mark: | :heavy_check_mark:
|
||||
| MQTT Binary | :heavy_check_mark: | :heavy_check_mark: |
|
||||
| MQTT Structured | :heavy_check_mark: | :heavy_check_mark: |
|
||||
| HTTP Binary | :white_check_mark: | :white_check_mark: |
|
||||
| HTTP Structured | :white_check_mark: | :white_check_mark: |
|
||||
| HTTP Batch | :white_check_mark: | :white_check_mark: |
|
||||
| Kafka Binary | :white_check_mark: | :white_check_mark: |
|
||||
| Kafka Structured | :white_check_mark: | :white_check_mark: |
|
||||
| Kafka Batch | :white_check_mark: | :white_check_mark:
|
||||
| MQTT Binary | :white_check_mark: | :white_check_mark: |
|
||||
| MQTT Structured | :white_check_mark: | :white_check_mark: |
|
||||
|
||||
## Community
|
||||
|
||||
|
@ -227,7 +241,6 @@ Currently active maintainers who may be found in the CNCF Slack.
|
|||
|
||||
- Lance Ball (@lance)
|
||||
- Lucas Holmquist (@lholmquist)
|
||||
- Grant Timmerman (@grant)
|
||||
|
||||
## Contributing
|
||||
|
||||
|
@ -245,3 +258,14 @@ how SDK projects are
|
|||
for how PR reviews and approval, and our
|
||||
[Code of Conduct](https://github.com/cloudevents/spec/blob/master/community/GOVERNANCE.md#additional-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)
|
||||
|
|
|
@ -28,11 +28,11 @@ app.post("/", (req, res) => {
|
|||
const responseEventMessage = new CloudEvent({
|
||||
source: '/',
|
||||
type: 'event:response',
|
||||
...event
|
||||
...event,
|
||||
data: {
|
||||
hello: 'world'
|
||||
}
|
||||
});
|
||||
responseEventMessage.data = {
|
||||
hello: 'world'
|
||||
};
|
||||
|
||||
// const message = HTTP.binary(responseEventMessage)
|
||||
const message = HTTP.structured(responseEventMessage)
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
# 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
|
||||
```
|
|
@ -0,0 +1,35 @@
|
|||
{
|
||||
"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"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
/* 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();
|
||||
});
|
|
@ -0,0 +1,16 @@
|
|||
{
|
||||
"extends": "./node_modules/gts/tsconfig-google.json",
|
||||
"compilerOptions": {
|
||||
"rootDir": "./src",
|
||||
"outDir": "./build/",
|
||||
"lib": [
|
||||
"es6",
|
||||
"dom"
|
||||
]
|
||||
},
|
||||
"include": [
|
||||
"src/**/*.ts",
|
||||
"test/**/*.ts"
|
||||
],
|
||||
"allowJs": true
|
||||
}
|
File diff suppressed because it is too large
Load Diff
28
package.json
28
package.json
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "cloudevents",
|
||||
"version": "6.0.0",
|
||||
"version": "9.0.0",
|
||||
"description": "CloudEvents SDK for JavaScript",
|
||||
"main": "dist/index.js",
|
||||
"scripts": {
|
||||
|
@ -13,7 +13,7 @@
|
|||
"lint:js": "eslint 'src/**/*.{js,ts}' 'test/**/*.{js,ts}' cucumber.js",
|
||||
"lint:md": "remark .",
|
||||
"lint:fix": "eslint 'src/**/*.{js,ts}' 'test/**/*.{js,ts}' --fix",
|
||||
"pretest": "npm run lint && npm run conformance",
|
||||
"pretest": "npm run lint && npm run build && npm run conformance",
|
||||
"test": "mocha --require ts-node/register ./test/integration/**/*.ts",
|
||||
"test:one": "mocha --require ts-node/register",
|
||||
"conformance": "cucumber-js ./conformance/features/*-protocol-binding.feature -p default",
|
||||
|
@ -110,15 +110,19 @@
|
|||
},
|
||||
"homepage": "https://github.com/cloudevents/sdk-javascript#readme",
|
||||
"dependencies": {
|
||||
"ajv": "^8.6.3",
|
||||
"ajv": "^8.11.0",
|
||||
"ajv-formats": "^2.1.1",
|
||||
"process": "^0.11.10",
|
||||
"json-bigint": "^1.0.0",
|
||||
"util": "^0.12.4",
|
||||
"uuid": "^8.3.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@cucumber/cucumber": "^8.0.0-rc.1",
|
||||
"@cucumber/cucumber": "^8.0.0",
|
||||
"@types/chai": "^4.2.11",
|
||||
"@types/cucumber": "^6.0.1",
|
||||
"@types/got": "^9.6.11",
|
||||
"@types/json-bigint": "^1.0.1",
|
||||
"@types/mocha": "^7.0.2",
|
||||
"@types/node": "^14.14.10",
|
||||
"@types/superagent": "^4.1.10",
|
||||
|
@ -126,7 +130,6 @@
|
|||
"@typescript-eslint/eslint-plugin": "^4.29.0",
|
||||
"@typescript-eslint/parser": "^4.29.0",
|
||||
"ajv-cli": "^5.0.0",
|
||||
"ajv-formats": "^2.1.1",
|
||||
"axios": "^0.26.1",
|
||||
"chai": "~4.2.0",
|
||||
"eslint": "^7.32.0",
|
||||
|
@ -135,9 +138,9 @@
|
|||
"eslint-plugin-import": "^2.23.4",
|
||||
"eslint-plugin-node": "^11.1.0",
|
||||
"eslint-plugin-promise": "^5.1.0",
|
||||
"got": "^11.7.0",
|
||||
"got": "^11.8.5",
|
||||
"http-parser-js": "^0.5.2",
|
||||
"mocha": "~9.2.0",
|
||||
"mocha": "^10.1.0",
|
||||
"nock": "~12.0.3",
|
||||
"nyc": "~15.0.0",
|
||||
"prettier": "^2.0.5",
|
||||
|
@ -146,14 +149,17 @@
|
|||
"remark-lint-list-item-indent": "^2.0.1",
|
||||
"remark-preset-lint-recommended": "^5.0.0",
|
||||
"superagent": "^7.1.1",
|
||||
"ts-node": "^8.10.2",
|
||||
"ts-node": "^10.8.1",
|
||||
"typedoc": "^0.22.11",
|
||||
"typescript": "^4.3.5",
|
||||
"webpack": "^5.1.1",
|
||||
"webpack-cli": "^4.0.0"
|
||||
"webpack": "^5.76.0",
|
||||
"webpack-cli": "^4.10.0"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"types": "./dist/index.d.ts"
|
||||
"types": "./dist/index.d.ts",
|
||||
"engines": {
|
||||
"node": ">=20 <=24"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -54,6 +54,7 @@ const CONSTANTS = Object.freeze({
|
|||
DATA_SCHEMA: "dataschema",
|
||||
DATA_BASE64: "data_base64",
|
||||
},
|
||||
USE_BIG_INT_ENV: "CE_USE_BIG_INT"
|
||||
} as const);
|
||||
|
||||
export default CONSTANTS;
|
||||
|
|
|
@ -9,15 +9,13 @@ import { Emitter } from "..";
|
|||
|
||||
import { CloudEventV1 } from "./interfaces";
|
||||
import { validateCloudEvent } from "./spec";
|
||||
import { ValidationError, isBinary, asBase64, isValidType } from "./validation";
|
||||
import { ValidationError, isBinary, asBase64, isValidType, base64AsBinary } from "./validation";
|
||||
|
||||
/**
|
||||
* An enum representing the CloudEvent specification version
|
||||
* Constants representing the CloudEvent specification version
|
||||
*/
|
||||
export const enum Version {
|
||||
V1 = "1.0",
|
||||
V03 = "0.3",
|
||||
}
|
||||
export const V1 = "1.0";
|
||||
export const V03 = "0.3";
|
||||
|
||||
/**
|
||||
* A CloudEvent describes event data in common formats to provide
|
||||
|
@ -28,12 +26,12 @@ export class CloudEvent<T = undefined> implements CloudEventV1<T> {
|
|||
id: string;
|
||||
type: string;
|
||||
source: string;
|
||||
specversion: Version;
|
||||
specversion: string;
|
||||
datacontenttype?: string;
|
||||
dataschema?: string;
|
||||
subject?: string;
|
||||
time?: string;
|
||||
#_data?: T;
|
||||
data?: T;
|
||||
data_base64?: string;
|
||||
|
||||
// Extensions should not exist as it's own object, but instead
|
||||
|
@ -69,7 +67,7 @@ export class CloudEvent<T = undefined> implements CloudEventV1<T> {
|
|||
this.source = properties.source as string;
|
||||
delete (properties as any).source;
|
||||
|
||||
this.specversion = (properties.specversion as Version) || Version.V1;
|
||||
this.specversion = (properties.specversion) || V1;
|
||||
delete properties.specversion;
|
||||
|
||||
this.datacontenttype = properties.datacontenttype;
|
||||
|
@ -85,26 +83,35 @@ export class CloudEvent<T = undefined> implements CloudEventV1<T> {
|
|||
delete properties.dataschema;
|
||||
|
||||
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;
|
||||
|
||||
this.schemaurl = properties.schemaurl as string;
|
||||
delete properties.schemaurl;
|
||||
|
||||
this.data = properties.data;
|
||||
if (isBinary(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;
|
||||
|
||||
// sanity checking
|
||||
if (this.specversion === Version.V1 && this.schemaurl) {
|
||||
if (this.specversion === V1 && this.schemaurl) {
|
||||
throw new TypeError("cannot set schemaurl on version 1.0 event");
|
||||
} else if (this.specversion === Version.V03 && this.dataschema) {
|
||||
} else if (this.specversion === V03 && this.dataschema) {
|
||||
throw new TypeError("cannot set dataschema on version 0.3 event");
|
||||
}
|
||||
|
||||
// finally process any remaining properties - these are extensions
|
||||
for (const [key, value] of Object.entries(properties)) {
|
||||
// Extension names should only allow lowercase a-z and 0-9 in the name
|
||||
// Extension names must only allow lowercase a-z and 0-9 in the name
|
||||
// names should not exceed 20 characters in length
|
||||
if (!key.match(/^[a-z0-9]{1,20}$/) && strict) {
|
||||
if (!key.match(/^[a-z0-9]+$/) && strict) {
|
||||
throw new ValidationError(`invalid extension name: ${key}
|
||||
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
|
||||
|
@ -127,17 +134,6 @@ See: https://github.com/cloudevents/spec/blob/v1.0/spec.md#type-system`);
|
|||
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
|
||||
* JSON.stringify() when converting this object to JSON.
|
||||
|
@ -147,7 +143,11 @@ See: https://github.com/cloudevents/spec/blob/v1.0/spec.md#type-system`);
|
|||
toJSON(): Record<string, unknown> {
|
||||
const event = { ...this };
|
||||
event.time = new Date(this.time as string).toISOString();
|
||||
event.data = this.#_data;
|
||||
|
||||
if (event.data_base64 && event.data) {
|
||||
delete event.data;
|
||||
}
|
||||
|
||||
return event;
|
||||
}
|
||||
|
||||
|
@ -230,9 +230,6 @@ See: https://github.com/cloudevents/spec/blob/v1.0/spec.md#type-system`);
|
|||
event: CloudEventV1<any>,
|
||||
options: Partial<CloudEventV1<any>>,
|
||||
strict = true): CloudEvent<any> {
|
||||
if (event instanceof CloudEvent) {
|
||||
event = event.toJSON() as CloudEventV1<any>;
|
||||
}
|
||||
return new CloudEvent(Object.assign({}, event, options), strict);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,22 +6,23 @@
|
|||
import { ValidationError } from "./validation";
|
||||
|
||||
import { CloudEventV1 } from "./interfaces";
|
||||
import { Version } from "./cloudevent";
|
||||
import { V1 } from "./cloudevent";
|
||||
import validate from "../schema/v1";
|
||||
|
||||
|
||||
export function validateCloudEvent<T>(event: CloudEventV1<T>): boolean {
|
||||
if (event.specversion === Version.V1) {
|
||||
if (event.specversion === V1) {
|
||||
if (!validate(event)) {
|
||||
throw new ValidationError("invalid payload", (validate as any).errors);
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
// attribute names must all be lowercase
|
||||
// attribute names must all be [a-z|0-9]
|
||||
const validation = /^[a-z0-9]+$/;
|
||||
for (const key in event) {
|
||||
if (key !== key.toLowerCase()) {
|
||||
throw new ValidationError(`invalid attribute name: ${key}`);
|
||||
if (validation.test(key) === false && key !== "data_base64") {
|
||||
throw new ValidationError(`invalid attribute name: "${key}"`);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
|
|
@ -5,6 +5,23 @@
|
|||
|
||||
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
|
||||
* cannot be properly validated against a specification.
|
||||
|
@ -36,7 +53,7 @@ export const isDefined = (v: unknown): boolean => v !== null && typeof v !== "un
|
|||
export const isBoolean = (v: unknown): boolean => typeof v === "boolean";
|
||||
export const isInteger = (v: unknown): boolean => Number.isInteger(v as number);
|
||||
export const isDate = (v: unknown): v is Date => v instanceof Date;
|
||||
export const isBinary = (v: unknown): v is Uint32Array => v instanceof Uint32Array;
|
||||
export const isBinary = (v: unknown): boolean => ArrayBuffer.isView(v);
|
||||
|
||||
export const isStringOrThrow = (v: unknown, t: Error): boolean =>
|
||||
isString(v)
|
||||
|
@ -73,7 +90,7 @@ export const isBase64 = (value: unknown): boolean =>
|
|||
|
||||
export const isBuffer = (value: unknown): boolean => value instanceof Buffer;
|
||||
|
||||
export const asBuffer = (value: string | Buffer | Uint32Array): Buffer =>
|
||||
export const asBuffer = (value: string | Buffer | TypeArray): Buffer =>
|
||||
isBinary(value)
|
||||
? Buffer.from((value as unknown) as string)
|
||||
: isBuffer(value)
|
||||
|
@ -82,7 +99,16 @@ export const asBuffer = (value: string | Buffer | Uint32Array): Buffer =>
|
|||
throw new TypeError("is not buffer or a valid binary");
|
||||
})();
|
||||
|
||||
export const asBase64 = (value: string | Buffer | Uint32Array): string => asBuffer(value).toString("base64");
|
||||
export const base64AsBinary = (base64String: string): Uint8Array => {
|
||||
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));
|
||||
|
||||
|
@ -97,5 +123,5 @@ export const asData = (data: unknown, contentType: string): string => {
|
|||
return isBinary(maybeJson) ? asBase64(maybeJson) : maybeJson;
|
||||
};
|
||||
|
||||
export const isValidType = (v: boolean | number | string | Date | Uint32Array | unknown): boolean =>
|
||||
export const isValidType = (v: boolean | number | string | Date | TypeArray | unknown): boolean =>
|
||||
isBoolean(v) || isInteger(v) || isString(v) || isDate(v) || isBinary(v) || isObject(v);
|
||||
|
|
|
@ -3,13 +3,13 @@
|
|||
SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import { CloudEvent, Version } from "./event/cloudevent";
|
||||
import { CloudEvent, V1, V03 } from "./event/cloudevent";
|
||||
import { ValidationError } from "./event/validation";
|
||||
import { CloudEventV1, CloudEventV1Attributes } from "./event/interfaces";
|
||||
|
||||
import { Options, TransportFunction, EmitterFunction, emitterFor, Emitter } from "./transport/emitter";
|
||||
import { httpTransport } from "./transport/http";
|
||||
import {
|
||||
import {
|
||||
Headers, Mode, Binding, HTTP, Kafka, KafkaEvent, KafkaMessage, Message, MQTT, MQTTMessage, MQTTMessageFactory,
|
||||
Serializer, Deserializer } from "./message";
|
||||
|
||||
|
@ -18,7 +18,8 @@ import CONSTANTS from "./constants";
|
|||
export {
|
||||
// From event
|
||||
CloudEvent,
|
||||
Version,
|
||||
V1,
|
||||
V03,
|
||||
ValidationError,
|
||||
Mode,
|
||||
HTTP,
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
import { PassThroughParser, DateParser, MappedParser } from "../../parsers";
|
||||
import { CloudEventV1 } from "../..";
|
||||
import { Headers } from "../";
|
||||
import { Version } from "../../event/cloudevent";
|
||||
import { V1 } from "../../event/cloudevent";
|
||||
import CONSTANTS from "../../constants";
|
||||
|
||||
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 {
|
||||
const headers: Headers = {};
|
||||
let headerMap: Readonly<{ [key: string]: MappedParser }>;
|
||||
if (event.specversion === Version.V1) {
|
||||
if (event.specversion === V1) {
|
||||
headerMap = v1headerMap;
|
||||
} else {
|
||||
headerMap = v03headerMap;
|
||||
|
@ -36,7 +36,7 @@ export function headersFor<T>(event: CloudEventV1<T>): Headers {
|
|||
// iterate over the event properties - generate a header for each
|
||||
Object.getOwnPropertyNames(event).forEach((property) => {
|
||||
const value = event[property];
|
||||
if (value) {
|
||||
if (value !== undefined) {
|
||||
const map: MappedParser | undefined = headerMap[property] as MappedParser;
|
||||
if (map) {
|
||||
headers[map.name] = map.parser.parse(value as string) as string;
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
import { types } from "util";
|
||||
|
||||
import { CloudEvent, CloudEventV1, CONSTANTS, Mode, Version } from "../..";
|
||||
import { CloudEvent, CloudEventV1, CONSTANTS, Mode, V1, V03 } from "../..";
|
||||
import { Message, Headers, Binding } from "..";
|
||||
|
||||
import {
|
||||
|
@ -147,7 +147,7 @@ function getVersion(mode: Mode, headers: Headers, body: string | Record<string,
|
|||
return (body as Record<string, string>).specversion;
|
||||
}
|
||||
}
|
||||
return Version.V1;
|
||||
return 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.
|
||||
*
|
||||
* @param {Message} message the incoming HTTP Message
|
||||
* @param {Version} version the spec version of the incoming event
|
||||
* @param {string} version the spec version of the incoming event
|
||||
* @returns {CloudEvent} an instance of CloudEvent representing the incoming request
|
||||
* @throws {ValidationError} of the event does not conform to the spec
|
||||
*/
|
||||
function parseBinary<T>(message: Message, version: Version): CloudEvent<T> {
|
||||
function parseBinary<T>(message: Message, version: string): CloudEvent<T> {
|
||||
const headers = { ...message.headers };
|
||||
let body = message.body;
|
||||
|
||||
|
@ -169,7 +169,7 @@ function parseBinary<T>(message: Message, version: Version): CloudEvent<T> {
|
|||
const sanitizedHeaders = sanitize(headers);
|
||||
|
||||
const eventObj: { [key: string]: unknown | string | Record<string, unknown> } = {};
|
||||
const parserMap: Record<string, MappedParser> = version === Version.V03 ? v03binaryParsers : v1binaryParsers;
|
||||
const parserMap: Record<string, MappedParser> = version === V03 ? v03binaryParsers : v1binaryParsers;
|
||||
|
||||
for (const header in parserMap) {
|
||||
if (sanitizedHeaders[header]) {
|
||||
|
@ -206,11 +206,11 @@ function parseBinary<T>(message: Message, version: Version): CloudEvent<T> {
|
|||
* Creates a new CloudEvent instance based on the provided payload and headers.
|
||||
*
|
||||
* @param {Message} message the incoming Message
|
||||
* @param {Version} version the spec version of this message (v1 or v03)
|
||||
* @param {string} version the spec version of this message (v1 or v03)
|
||||
* @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
|
||||
*/
|
||||
function parseStructured<T>(message: Message, version: Version): CloudEvent<T> {
|
||||
function parseStructured<T>(message: Message, version: string): CloudEvent<T> {
|
||||
const payload = message.body;
|
||||
const headers = message.headers;
|
||||
|
||||
|
@ -227,7 +227,7 @@ function parseStructured<T>(message: Message, version: Version): CloudEvent<T> {
|
|||
const incoming = { ...(parser.parse(payload as string) as Record<string, unknown>) };
|
||||
|
||||
const eventObj: { [key: string]: unknown } = {};
|
||||
const parserMap: Record<string, MappedParser> = version === Version.V03 ? v03structuredParsers : v1structuredParsers;
|
||||
const parserMap: Record<string, MappedParser> = version === V03 ? v03structuredParsers : v1structuredParsers;
|
||||
|
||||
for (const key in parserMap) {
|
||||
const property = incoming[key];
|
||||
|
|
|
@ -22,9 +22,9 @@ export * from "./mqtt";
|
|||
* @property {@link Deserializer} `toEvent` - converts a Message into a CloudEvent
|
||||
* @property {@link Detector} `isEvent` - determines if a Message can be converted to a CloudEvent
|
||||
*/
|
||||
export interface Binding {
|
||||
binary: Serializer;
|
||||
structured: Serializer;
|
||||
export interface Binding<B extends Message = Message, S extends Message = Message> {
|
||||
binary: Serializer<B>;
|
||||
structured: Serializer<S>;
|
||||
toEvent: Deserializer;
|
||||
isEvent: Detector;
|
||||
}
|
||||
|
@ -65,8 +65,8 @@ export enum Mode {
|
|||
* CloudEvent into a Message.
|
||||
* @interface
|
||||
*/
|
||||
export interface Serializer {
|
||||
<T>(event: CloudEventV1<T>): Message;
|
||||
export interface Serializer<M extends Message> {
|
||||
<T>(event: CloudEventV1<T>): M;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -22,7 +22,7 @@ export type {
|
|||
* Bindings for Kafka transport
|
||||
* @implements {@linkcode Binding}
|
||||
*/
|
||||
const Kafka: Binding = {
|
||||
const Kafka: Binding<KafkaMessage<unknown>, KafkaMessage<string>> = {
|
||||
binary: toBinaryKafkaMessage,
|
||||
structured: toStructuredKafkaMessage,
|
||||
toEvent: deserializeKafkaMessage,
|
||||
|
@ -35,9 +35,9 @@ type Key = string | Buffer;
|
|||
* Extends the base Message type to include
|
||||
* Kafka-specific fields
|
||||
*/
|
||||
interface KafkaMessage<T = string> extends Message {
|
||||
interface KafkaMessage<T = string | Buffer | unknown> extends Message {
|
||||
key: Key
|
||||
value: T | string | Buffer | unknown
|
||||
value: T
|
||||
timestamp?: string
|
||||
}
|
||||
|
||||
|
@ -61,7 +61,7 @@ interface KafkaEvent<T> extends CloudEventV1<T> {
|
|||
* @param {KafkaEvent<T>} event The event to serialize
|
||||
* @returns {KafkaMessage<T>} a KafkaMessage instance
|
||||
*/
|
||||
function toBinaryKafkaMessage<T>(event: CloudEventV1<T>): KafkaMessage<T> {
|
||||
function toBinaryKafkaMessage<T>(event: CloudEventV1<T>): KafkaMessage<T | undefined> {
|
||||
// 3.2.1. Content Type
|
||||
// For the binary mode, the header content-type property MUST be mapped directly
|
||||
// to the CloudEvents datacontenttype attribute.
|
||||
|
@ -86,7 +86,7 @@ function toBinaryKafkaMessage<T>(event: CloudEventV1<T>): KafkaMessage<T> {
|
|||
* @param {CloudEvent<T>} event the CloudEvent to be serialized
|
||||
* @returns {KafkaMessage<T>} a KafkaMessage instance
|
||||
*/
|
||||
function toStructuredKafkaMessage<T>(event: CloudEventV1<T>): KafkaMessage<T> {
|
||||
function toStructuredKafkaMessage<T>(event: CloudEventV1<T>): KafkaMessage<string> {
|
||||
if ((event instanceof CloudEvent) && event.data_base64) {
|
||||
// The event's data is binary - delete it
|
||||
event = event.cloneWith({ data: undefined });
|
||||
|
@ -130,9 +130,9 @@ function deserializeKafkaMessage<T>(message: Message): CloudEvent<T> | CloudEven
|
|||
case Mode.BINARY:
|
||||
return parseBinary(m);
|
||||
case Mode.STRUCTURED:
|
||||
return parseStructured(m);
|
||||
return parseStructured(m as unknown as KafkaMessage<string>);
|
||||
case Mode.BATCH:
|
||||
return parseBatched(m);
|
||||
return parseBatched(m as unknown as KafkaMessage<string>);
|
||||
default:
|
||||
throw new ValidationError("Unknown Message mode");
|
||||
}
|
||||
|
@ -212,14 +212,14 @@ function parseBinary<T>(message: KafkaMessage<T>): CloudEvent<T> {
|
|||
* @param {KafkaMessage<T>} message the message
|
||||
* @returns {CloudEvent<T>} a KafkaEvent<T>
|
||||
*/
|
||||
function parseStructured<T>(message: KafkaMessage<T>): CloudEvent<T> {
|
||||
function parseStructured<T>(message: KafkaMessage<string>): CloudEvent<T> {
|
||||
// Although the format of a structured encoded event could be something
|
||||
// other than JSON, e.g. XML, we currently only support JSON
|
||||
// encoded structured events.
|
||||
if (!message.headers[CONSTANTS.HEADER_CONTENT_TYPE]?.startsWith(CONSTANTS.MIME_CE_JSON)) {
|
||||
throw new ValidationError(`Unsupported event encoding ${message.headers[CONSTANTS.HEADER_CONTENT_TYPE]}`);
|
||||
}
|
||||
const eventObj = JSON.parse(message.value as string);
|
||||
const eventObj = JSON.parse(message.value);
|
||||
eventObj.time = new Date(eventObj.time).toISOString();
|
||||
return new CloudEvent({
|
||||
...eventObj,
|
||||
|
@ -232,14 +232,14 @@ function parseStructured<T>(message: KafkaMessage<T>): CloudEvent<T> {
|
|||
* @param {KafkaMessage<T>} message the message
|
||||
* @returns {CloudEvent<T>[]} an array of KafkaEvent<T>
|
||||
*/
|
||||
function parseBatched<T>(message: KafkaMessage<T>): CloudEvent<T>[] {
|
||||
function parseBatched<T>(message: KafkaMessage<string>): CloudEvent<T>[] {
|
||||
// Although the format of batch encoded events could be something
|
||||
// other than JSON, e.g. XML, we currently only support JSON
|
||||
// encoded structured events.
|
||||
if (!message.headers[CONSTANTS.HEADER_CONTENT_TYPE]?.startsWith(CONSTANTS.MIME_CE_BATCH)) {
|
||||
throw new ValidationError(`Unsupported event encoding ${message.headers[CONSTANTS.HEADER_CONTENT_TYPE]}`);
|
||||
}
|
||||
const events = JSON.parse(message.value as string) as Record<string, unknown>[];
|
||||
const events = JSON.parse(message.value) as Record<string, unknown>[];
|
||||
return events.map((e) => new CloudEvent({ ...e, partitionkey: message.key }, false));
|
||||
}
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
*/
|
||||
|
||||
import { Binding, Deserializer, CloudEvent, CloudEventV1, CONSTANTS, Message, ValidationError, Headers } from "../..";
|
||||
import { base64AsBinary } from "../../event/validation";
|
||||
|
||||
export {
|
||||
MQTT, MQTTMessageFactory
|
||||
|
@ -14,7 +15,7 @@ export type { MQTTMessage };
|
|||
* Extends the base {@linkcode Message} interface to include MQTT attributes, some of which
|
||||
* are aliases of the {Message} attributes.
|
||||
*/
|
||||
interface MQTTMessage<T> extends Message<T> {
|
||||
interface MQTTMessage<T = unknown> extends Message<T> {
|
||||
/**
|
||||
* Identifies this message as a PUBLISH packet. MQTTMessages created with
|
||||
* the `binary` and `structured` Serializers will contain a "Content Type"
|
||||
|
@ -36,7 +37,7 @@ interface MQTTMessage<T> extends Message<T> {
|
|||
* Binding for MQTT transport support
|
||||
* @implements @linkcode Binding
|
||||
*/
|
||||
const MQTT: Binding = {
|
||||
const MQTT: Binding<MQTTMessage, MQTTMessage> = {
|
||||
binary,
|
||||
structured,
|
||||
toEvent: toEvent as Deserializer,
|
||||
|
@ -50,14 +51,16 @@ const MQTT: Binding = {
|
|||
* @implements {Serializer}
|
||||
*/
|
||||
function binary<T>(event: CloudEventV1<T>): MQTTMessage<T> {
|
||||
let properties;
|
||||
if (event instanceof CloudEvent) {
|
||||
properties = event.toJSON();
|
||||
} else {
|
||||
properties = event;
|
||||
const properties = { ...event };
|
||||
|
||||
let body = properties.data as T;
|
||||
|
||||
if (!body && properties.data_base64) {
|
||||
body = base64AsBinary(properties.data_base64) as unknown as T;
|
||||
}
|
||||
const body = properties.data as T;
|
||||
|
||||
delete properties.data;
|
||||
delete properties.data_base64;
|
||||
|
||||
return MQTTMessageFactory(event.datacontenttype as string, properties, body);
|
||||
}
|
||||
|
|
|
@ -3,9 +3,11 @@
|
|||
SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import JSONbig from "json-bigint";
|
||||
import CONSTANTS from "./constants";
|
||||
import { isString, isDefinedOrThrow, isStringOrObjectOrThrow, ValidationError } from "./event/validation";
|
||||
|
||||
const __JSON = JSON;
|
||||
export abstract class Parser {
|
||||
abstract parse(payload: Record<string, unknown> | string | string[] | undefined): unknown;
|
||||
}
|
||||
|
@ -36,6 +38,13 @@ export class JSONParser implements Parser {
|
|||
|
||||
isDefinedOrThrow(payload, new ValidationError("null or undefined payload"));
|
||||
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);
|
||||
return parseJSON(payload);
|
||||
}
|
||||
|
|
|
@ -7,24 +7,39 @@ import path from "path";
|
|||
import fs from "fs";
|
||||
|
||||
import { expect } from "chai";
|
||||
import { CloudEvent, ValidationError, Version } from "../../src";
|
||||
import { CloudEvent, CloudEventV1, ValidationError, V1 } from "../../src";
|
||||
import { asBase64 } from "../../src/event/validation";
|
||||
|
||||
const type = "org.cncf.cloudevents.example";
|
||||
const source = "http://unit.test";
|
||||
const id = "b46cf653-d48a-4b90-8dfa-355c01061361";
|
||||
|
||||
const fixture = {
|
||||
const fixture = Object.freeze({
|
||||
id,
|
||||
specversion: Version.V1,
|
||||
specversion: V1,
|
||||
source,
|
||||
type,
|
||||
data: `"some data"`,
|
||||
};
|
||||
data: `"some data"`
|
||||
});
|
||||
|
||||
const imageData = new Uint32Array(fs.readFileSync(path.join(process.cwd(), "test", "integration", "ce.png")));
|
||||
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", () => {
|
||||
it("Can be constructed with a typed Message", () => {
|
||||
const ce = new CloudEvent(fixture);
|
||||
|
@ -67,10 +82,10 @@ describe("A CloudEvent", () => {
|
|||
}).throw("invalid extension name");
|
||||
});
|
||||
|
||||
it("Throw a validation error for invalid extension names, more than 20 chars", () => {
|
||||
it("Not throw a validation error for invalid extension names, more than 20 chars", () => {
|
||||
expect(() => {
|
||||
new CloudEvent({ "123456789012345678901": "extension1", ...fixture });
|
||||
}).throw("invalid extension name");
|
||||
}).not.throw("invalid extension name");
|
||||
});
|
||||
|
||||
it("Throws a validation error for invalid uppercase extension names", () => {
|
||||
|
@ -78,6 +93,58 @@ describe("A CloudEvent", () => {
|
|||
new CloudEvent({ ExtensionWithCaps: "extension value", ...fixture });
|
||||
}).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", () => {
|
||||
|
@ -98,7 +165,7 @@ describe("A 1.0 CloudEvent", () => {
|
|||
});
|
||||
|
||||
it("can be constructed with an ID", () => {
|
||||
const ce = new CloudEvent({ id: "1234", specversion: Version.V1, source, type });
|
||||
const ce = new CloudEvent({ id: "1234", specversion: V1, source, type });
|
||||
expect(ce.id).to.equal("1234");
|
||||
});
|
||||
|
||||
|
@ -213,7 +280,7 @@ describe("A 1.0 CloudEvent", () => {
|
|||
const obj = JSON.parse(json as string);
|
||||
expect(obj.type).to.equal(type);
|
||||
expect(obj.source).to.equal(source);
|
||||
expect(obj.specversion).to.equal(Version.V1);
|
||||
expect(obj.specversion).to.equal(V1);
|
||||
});
|
||||
|
||||
it("throws if the provded source is empty string", () => {
|
||||
|
|
|
@ -26,7 +26,7 @@ describe("Emitter Singleton", () => {
|
|||
if (typeof body === "string") {
|
||||
body = JSON.parse(body);
|
||||
}
|
||||
assertStructured({ ...(<any>body), ...(msg as Message).headers });
|
||||
assertStructured({ ...(body as any), ...(msg as Message).headers });
|
||||
});
|
||||
|
||||
it("emit a Node.js 'cloudevent' event as an EventEmitter with ensureDelivery", async () => {
|
||||
|
@ -41,7 +41,7 @@ describe("Emitter Singleton", () => {
|
|||
if (typeof body === "string") {
|
||||
body = JSON.parse(body);
|
||||
}
|
||||
assertStructured({ ...(<any>body), ...(msg as Message).headers });
|
||||
assertStructured({ ...(body as any), ...(msg as Message).headers });
|
||||
});
|
||||
|
||||
it("emit a Node.js 'cloudevent' event as an EventEmitter with ensureDelivery Error", async () => {
|
||||
|
|
|
@ -7,7 +7,7 @@ import path from "path";
|
|||
import fs from "fs";
|
||||
|
||||
import { expect } from "chai";
|
||||
import { CloudEvent, CONSTANTS, Version } from "../../src";
|
||||
import { CloudEvent, CONSTANTS, V1 } from "../../src";
|
||||
import { asBase64 } from "../../src/event/validation";
|
||||
import { Message, Kafka, KafkaMessage, KafkaEvent } from "../../src/message";
|
||||
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 fixture = new CloudEvent({
|
||||
specversion: Version.V1,
|
||||
specversion: V1,
|
||||
id,
|
||||
type,
|
||||
source,
|
||||
|
@ -131,7 +131,7 @@ describe("Kafka transport", () => {
|
|||
expect(event.LUNCH).to.equal("tacos");
|
||||
expect(function () {
|
||||
event.validate();
|
||||
}).to.throw("invalid attribute name: LUNCH");
|
||||
}).to.throw("invalid attribute name: \"LUNCH\"");
|
||||
});
|
||||
|
||||
it("Can detect CloudEvent binary Messages with weird versions", () => {
|
||||
|
@ -233,7 +233,7 @@ describe("Kafka transport", () => {
|
|||
expect(message.body).to.equal(data);
|
||||
// validate all headers
|
||||
expect(message.headers[CONSTANTS.HEADER_CONTENT_TYPE]).to.equal(datacontenttype);
|
||||
expect(message.headers[KAFKA_CE_HEADERS.SPEC_VERSION]).to.equal(Version.V1);
|
||||
expect(message.headers[KAFKA_CE_HEADERS.SPEC_VERSION]).to.equal(V1);
|
||||
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.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);
|
||||
// Parse the message body as JSON, then validate the attributes
|
||||
const body = JSON.parse(message.body as string);
|
||||
expect(body[CONSTANTS.CE_ATTRIBUTES.SPEC_VERSION]).to.equal(Version.V1);
|
||||
expect(body[CONSTANTS.CE_ATTRIBUTES.SPEC_VERSION]).to.equal(V1);
|
||||
expect(body[CONSTANTS.CE_ATTRIBUTES.ID]).to.equal(id);
|
||||
expect(body[CONSTANTS.CE_ATTRIBUTES.TYPE]).to.equal(type);
|
||||
expect(body[CONSTANTS.CE_ATTRIBUTES.SOURCE]).to.equal(source);
|
||||
|
|
|
@ -8,7 +8,7 @@ import fs from "fs";
|
|||
|
||||
import { expect } from "chai";
|
||||
import { IncomingHttpHeaders } from "http";
|
||||
import { CloudEvent, CONSTANTS, Version } from "../../src";
|
||||
import { CloudEvent, CONSTANTS, V1, V03 } from "../../src";
|
||||
import { asBase64 } from "../../src/event/validation";
|
||||
import { Message, HTTP } from "../../src/message";
|
||||
|
||||
|
@ -41,6 +41,60 @@ const imageData = new Uint32Array(fs.readFileSync(path.join(process.cwd(), "test
|
|||
const image_base64 = asBase64(imageData);
|
||||
|
||||
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", () => {
|
||||
const body = "{Something[Not:valid}JSON";
|
||||
const message: Message<undefined> = {
|
||||
|
@ -100,7 +154,7 @@ describe("HTTP transport", () => {
|
|||
[CONSTANTS.CE_HEADERS.ID]: "1234",
|
||||
[CONSTANTS.CE_HEADERS.SOURCE]: "test",
|
||||
[CONSTANTS.CE_HEADERS.TYPE]: "test.event",
|
||||
[CONSTANTS.CE_HEADERS.SPEC_VERSION]: Version.V1,
|
||||
[CONSTANTS.CE_HEADERS.SPEC_VERSION]: V1,
|
||||
"ce-LUNCH": "tacos",
|
||||
},
|
||||
};
|
||||
|
@ -109,7 +163,7 @@ describe("HTTP transport", () => {
|
|||
expect(event.LUNCH).to.equal("tacos");
|
||||
expect(function () {
|
||||
event.validate();
|
||||
}).to.throw("invalid attribute name: LUNCH");
|
||||
}).to.throw("invalid attribute name: \"LUNCH\"");
|
||||
});
|
||||
|
||||
it("Can detect CloudEvent binary Messages with weird versions", () => {
|
||||
|
@ -183,7 +237,7 @@ describe("HTTP transport", () => {
|
|||
id,
|
||||
type,
|
||||
source,
|
||||
specversion: Version.V1,
|
||||
specversion: V1,
|
||||
data: { lunch: "tacos" },
|
||||
});
|
||||
const message: Message<undefined> = {
|
||||
|
@ -196,7 +250,7 @@ describe("HTTP transport", () => {
|
|||
|
||||
describe("Specification version V1", () => {
|
||||
const fixture = new CloudEvent({
|
||||
specversion: Version.V1,
|
||||
specversion: V1,
|
||||
id,
|
||||
type,
|
||||
source,
|
||||
|
@ -214,7 +268,7 @@ describe("HTTP transport", () => {
|
|||
expect(message.body).to.equal(JSON.stringify(data));
|
||||
// validate all headers
|
||||
expect(message.headers[CONSTANTS.HEADER_CONTENT_TYPE]).to.equal(datacontenttype);
|
||||
expect(message.headers[CONSTANTS.CE_HEADERS.SPEC_VERSION]).to.equal(Version.V1);
|
||||
expect(message.headers[CONSTANTS.CE_HEADERS.SPEC_VERSION]).to.equal(V1);
|
||||
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.SOURCE]).to.equal(source);
|
||||
|
@ -230,7 +284,7 @@ describe("HTTP transport", () => {
|
|||
expect(message.headers[CONSTANTS.HEADER_CONTENT_TYPE]).to.equal(CONSTANTS.DEFAULT_CE_CONTENT_TYPE);
|
||||
// Parse the message body as JSON, then validate the attributes
|
||||
const body = JSON.parse(message.body as string);
|
||||
expect(body[CONSTANTS.CE_ATTRIBUTES.SPEC_VERSION]).to.equal(Version.V1);
|
||||
expect(body[CONSTANTS.CE_ATTRIBUTES.SPEC_VERSION]).to.equal(V1);
|
||||
expect(body[CONSTANTS.CE_ATTRIBUTES.ID]).to.equal(id);
|
||||
expect(body[CONSTANTS.CE_ATTRIBUTES.TYPE]).to.equal(type);
|
||||
expect(body[CONSTANTS.CE_ATTRIBUTES.SOURCE]).to.equal(source);
|
||||
|
@ -299,7 +353,7 @@ describe("HTTP transport", () => {
|
|||
|
||||
describe("Specification version V03", () => {
|
||||
const fixture = new CloudEvent({
|
||||
specversion: Version.V03,
|
||||
specversion: V03,
|
||||
id,
|
||||
type,
|
||||
source,
|
||||
|
@ -317,7 +371,7 @@ describe("HTTP transport", () => {
|
|||
expect(message.body).to.equal(JSON.stringify(data));
|
||||
// validate all headers
|
||||
expect(message.headers[CONSTANTS.HEADER_CONTENT_TYPE]).to.equal(datacontenttype);
|
||||
expect(message.headers[CONSTANTS.CE_HEADERS.SPEC_VERSION]).to.equal(Version.V03);
|
||||
expect(message.headers[CONSTANTS.CE_HEADERS.SPEC_VERSION]).to.equal(V03);
|
||||
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.SOURCE]).to.equal(source);
|
||||
|
@ -333,7 +387,7 @@ describe("HTTP transport", () => {
|
|||
expect(message.headers[CONSTANTS.HEADER_CONTENT_TYPE]).to.equal(CONSTANTS.DEFAULT_CE_CONTENT_TYPE);
|
||||
// Parse the message body as JSON, then validate the attributes
|
||||
const body = JSON.parse(message.body as string);
|
||||
expect(body[CONSTANTS.CE_ATTRIBUTES.SPEC_VERSION]).to.equal(Version.V03);
|
||||
expect(body[CONSTANTS.CE_ATTRIBUTES.SPEC_VERSION]).to.equal(V03);
|
||||
expect(body[CONSTANTS.CE_ATTRIBUTES.ID]).to.equal(id);
|
||||
expect(body[CONSTANTS.CE_ATTRIBUTES.TYPE]).to.equal(type);
|
||||
expect(body[CONSTANTS.CE_ATTRIBUTES.SOURCE]).to.equal(source);
|
||||
|
|
|
@ -7,7 +7,7 @@ import path from "path";
|
|||
import fs from "fs";
|
||||
|
||||
import { expect } from "chai";
|
||||
import { CloudEvent, CONSTANTS, Version, Headers } from "../../src";
|
||||
import { CloudEvent, CONSTANTS, V1, Headers } from "../../src";
|
||||
import { asBase64 } from "../../src/event/validation";
|
||||
import { Message, MQTT, MQTTMessage } from "../../src/message";
|
||||
|
||||
|
@ -32,18 +32,18 @@ const ext2Name = "extension2";
|
|||
const ext2Value = "acme";
|
||||
|
||||
// Binary data as base64
|
||||
const dataBinary = Uint32Array.from(JSON.stringify(data), (c) => c.codePointAt(0) as number);
|
||||
const dataBinary = Uint8Array.from(JSON.stringify(data), (c) => c.codePointAt(0) as number);
|
||||
const data_base64 = asBase64(dataBinary);
|
||||
|
||||
// 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
|
||||
const imageData = new Uint32Array(fs.readFileSync(path.join(process.cwd(), "test", "integration", "ce.png")));
|
||||
const imageData = new Uint8Array(fs.readFileSync(path.join(process.cwd(), "test", "integration", "ce.png")));
|
||||
const image_base64 = asBase64(imageData);
|
||||
|
||||
const PUBLISH = {"Content Type": "application/json; charset=utf-8"};
|
||||
|
||||
const fixture = new CloudEvent({
|
||||
specversion: Version.V1,
|
||||
specversion: V1,
|
||||
id,
|
||||
type,
|
||||
source,
|
||||
|
@ -134,7 +134,7 @@ describe("MQTT transport", () => {
|
|||
expect(event.LUNCH).to.equal("tacos");
|
||||
expect(function () {
|
||||
event.validate();
|
||||
}).to.throw("invalid attribute name: LUNCH");
|
||||
}).to.throw("invalid attribute name: \"LUNCH\"");
|
||||
});
|
||||
|
||||
it("Can detect CloudEvent binary Messages with weird versions", () => {
|
||||
|
@ -216,7 +216,7 @@ describe("MQTT transport", () => {
|
|||
expect(message.body).to.equal(data);
|
||||
// validate all headers
|
||||
expect(message.headers.datacontenttype).to.equal(datacontenttype);
|
||||
expect(message.headers.specversion).to.equal(Version.V1);
|
||||
expect(message.headers.specversion).to.equal(V1);
|
||||
expect(message.headers.id).to.equal(id);
|
||||
expect(message.headers.type).to.equal(type);
|
||||
expect(message.headers.source).to.equal(source);
|
||||
|
@ -232,7 +232,7 @@ describe("MQTT transport", () => {
|
|||
expect(message.body).to.equal(data);
|
||||
// validate all headers
|
||||
expect(message["User Properties"]?.datacontenttype).to.equal(datacontenttype);
|
||||
expect(message["User Properties"]?.specversion).to.equal(Version.V1);
|
||||
expect(message["User Properties"]?.specversion).to.equal(V1);
|
||||
expect(message["User Properties"]?.id).to.equal(id);
|
||||
expect(message["User Properties"]?.type).to.equal(type);
|
||||
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.payload).to.deep.equal(fixture.toJSON());
|
||||
const body = message.body as Record<string, string>;
|
||||
expect(body[CONSTANTS.CE_ATTRIBUTES.SPEC_VERSION]).to.equal(Version.V1);
|
||||
expect(body[CONSTANTS.CE_ATTRIBUTES.SPEC_VERSION]).to.equal(V1);
|
||||
expect(body[CONSTANTS.CE_ATTRIBUTES.ID]).to.equal(id);
|
||||
expect(body[CONSTANTS.CE_ATTRIBUTES.TYPE]).to.equal(type);
|
||||
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", () => {
|
||||
const message = MQTT.structured(fixture.cloneWith({ data: imageData, datacontenttype: "image/png" }));
|
||||
const eventDeserialized = MQTT.toEvent(message) as CloudEvent<Uint32Array>;
|
||||
const eventDeserialized = MQTT.toEvent(message) as CloudEvent<Uint8Array>;
|
||||
expect(eventDeserialized.data).to.deep.equal(imageData);
|
||||
expect(eventDeserialized.data_base64).to.equal(image_base64);
|
||||
});
|
||||
|
||||
it("Converts base64 encoded data to binary when deserializing binary messages", () => {
|
||||
const message = MQTT.binary(fixture.cloneWith({ data: imageData, datacontenttype: "image/png" }));
|
||||
const eventDeserialized = MQTT.toEvent(message) as CloudEvent<Uint32Array>;
|
||||
const eventDeserialized = MQTT.toEvent(message) as CloudEvent<Uint8Array>;
|
||||
expect(eventDeserialized.data).to.deep.equal(imageData);
|
||||
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", () => {
|
||||
const message = MQTT.binary(fixture.cloneWith({ data: dataBinary }));
|
||||
const eventDeserialized = MQTT.toEvent(message) as CloudEvent<Uint32Array>;
|
||||
const eventDeserialized = MQTT.toEvent(message) as CloudEvent<Uint8Array>;
|
||||
expect(eventDeserialized.data).to.deep.equal(dataBinary);
|
||||
expect(eventDeserialized.data_base64).to.equal(data_base64);
|
||||
});
|
||||
|
|
|
@ -56,7 +56,7 @@ describe("JSON Event Format Parser", () => {
|
|||
const parser = new Parser();
|
||||
|
||||
// TODO: Should the parser catch the SyntaxError and re-throw a ValidationError?
|
||||
expect(parser.parse.bind(parser, payload)).to.throw(SyntaxError, "Unexpected token g in JSON at position 1");
|
||||
expect(parser.parse.bind(parser, payload)).to.throw(SyntaxError);
|
||||
});
|
||||
|
||||
it("Accepts a string as valid JSON", () => {
|
||||
|
|
|
@ -5,13 +5,13 @@
|
|||
|
||||
import "mocha";
|
||||
import { expect } from "chai";
|
||||
import { CloudEvent, CloudEventV1, Version } from "../../src";
|
||||
import { CloudEvent, CloudEventV1, V1, V03 } from "../../src";
|
||||
|
||||
const fixture: CloudEventV1<undefined> = {
|
||||
id: "123",
|
||||
type: "org.cloudevents.test",
|
||||
source: "http://cloudevents.io",
|
||||
specversion: Version.V1,
|
||||
specversion: V1,
|
||||
};
|
||||
|
||||
describe("The SDK Requirements", () => {
|
||||
|
@ -25,15 +25,15 @@ describe("The SDK Requirements", () => {
|
|||
expect(
|
||||
new CloudEvent({
|
||||
...fixture,
|
||||
specversion: Version.V03,
|
||||
specversion: V03,
|
||||
}, false).specversion,
|
||||
).to.equal(Version.V03);
|
||||
).to.equal(V03);
|
||||
});
|
||||
});
|
||||
|
||||
describe("v1.0", () => {
|
||||
it("should create an event using the right spec version", () => {
|
||||
expect(new CloudEvent(fixture).specversion).to.equal(Version.V1);
|
||||
expect(new CloudEvent(fixture).specversion).to.equal(V1);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
import "mocha";
|
||||
import { expect } from "chai";
|
||||
import { CloudEvent, Version, ValidationError } from "../../src";
|
||||
import { CloudEvent, V1, ValidationError } from "../../src";
|
||||
import { asBase64 } from "../../src/event/validation";
|
||||
import Constants from "../../src/constants";
|
||||
|
||||
|
@ -19,8 +19,8 @@ const data = {
|
|||
};
|
||||
const subject = "subject-x0";
|
||||
|
||||
let cloudevent = new CloudEvent({
|
||||
specversion: Version.V1,
|
||||
const cloudevent = new CloudEvent({
|
||||
specversion: V1,
|
||||
id,
|
||||
source,
|
||||
type,
|
||||
|
@ -99,6 +99,16 @@ describe("CloudEvents Spec v1.0", () => {
|
|||
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);
|
||||
});
|
||||
|
||||
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", () => {
|
||||
|
@ -110,8 +120,8 @@ describe("CloudEvents Spec v1.0", () => {
|
|||
});
|
||||
|
||||
it("defaut ID create when an empty string", () => {
|
||||
cloudevent = cloudevent.cloneWith({ id: "" });
|
||||
expect(cloudevent.id.length).to.be.greaterThan(0);
|
||||
const testEvent = cloudevent.cloneWith({ id: "" });
|
||||
expect(testEvent.id.length).to.be.greaterThan(0);
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -150,11 +160,11 @@ describe("CloudEvents Spec v1.0", () => {
|
|||
describe("'time'", () => {
|
||||
it("must adhere to the format specified in RFC 3339", () => {
|
||||
const d = new Date();
|
||||
cloudevent = cloudevent.cloneWith({ time: d.toString() }, false);
|
||||
const testEvent = cloudevent.cloneWith({ time: d.toString() }, false);
|
||||
// ensure that we always get back the same thing we passed in
|
||||
expect(cloudevent.time).to.equal(d.toString());
|
||||
expect(testEvent.time).to.equal(d.toString());
|
||||
// ensure that when stringified, the timestamp is in RFC3339 format
|
||||
expect(JSON.parse(JSON.stringify(cloudevent)).time).to.equal(new Date(d.toString()).toISOString());
|
||||
expect(JSON.parse(JSON.stringify(testEvent)).time).to.equal(new Date(d.toString()).toISOString());
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -173,14 +183,60 @@ describe("CloudEvents Spec v1.0", () => {
|
|||
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))
|
||||
},
|
||||
];
|
||||
|
||||
const dataBinary = Uint32Array.from(dataString, (c) => c.codePointAt(0) as number);
|
||||
const expected = asBase64(dataBinary);
|
||||
|
||||
const ce = cloudevent.cloneWith({ datacontenttype: "text/plain", data: dataBinary });
|
||||
expect(ce.data_base64).to.equal(expected);
|
||||
testCases.forEach((test) => {
|
||||
it(`should be ok when type is '${test.type.name}' for 'Binary'`, () => {
|
||||
const ce = cloudevent.cloneWith({ datacontenttype: "text/plain", data: test.data });
|
||||
expect(ce.data_base64).to.equal(test.expected);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2016", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */
|
||||
"target": "ES2020", /* 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'. */
|
||||
"allowJs": true, /* Allow javascript files to be compiled. */
|
||||
"checkJs": false, /* Report errors in .js files. */
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
const path = require("path");
|
||||
const webpack = require("webpack");
|
||||
|
||||
module.exports = {
|
||||
entry: {
|
||||
|
@ -11,6 +12,11 @@ module.exports = {
|
|||
https: false
|
||||
},
|
||||
},
|
||||
plugins: [
|
||||
new webpack.ProvidePlugin({
|
||||
process: 'process/browser'
|
||||
})
|
||||
],
|
||||
output: {
|
||||
path: path.resolve(__dirname, "bundles"),
|
||||
filename: "[name].js",
|
||||
|
|
Loading…
Reference in New Issue