cloudevent
Advanced tools
Comparing version 0.8.0 to 0.9.0
# Change Log | ||
## [0.9.0](https://github.com/smartiniOnGitHub/cloudevent.js/releases/tag/0.9.0) (2022-04-16) | ||
Summary Changelog: | ||
- Implement the [v1.0.2 - CloudEvents Spec](https://github.com/cloudevents/spec/releases/tag/v1.0.2) | ||
but ensure compatibility with release 1.0 of the spec | ||
- Update dependencies but keep compatibility with Node.js 10 | ||
- Update internals about 'time', to be managed as a string (as in spec); | ||
in costructor now is accepted even as a string (that could be checked later | ||
during validation); added a getter method to get its value as a Date | ||
- Update JSONBatch serialize/deserialize with an additional argument: | ||
a callback function to notify when each item has been processed | ||
(in the right way or not), it could be useful | ||
- General cleanup | ||
- No features implemented as async functions here at the moment | ||
## [0.8.0](https://github.com/smartiniOnGitHub/cloudevent.js/releases/tag/0.8.0) (2021-03-26) | ||
@@ -4,0 +18,0 @@ Summary Changelog: |
/* | ||
* Copyright 2018-2021 the original author or authors. | ||
* Copyright 2018-2022 the original author or authors. | ||
* | ||
@@ -4,0 +4,0 @@ * Licensed under the Apache License, Version 2.0 (the "License"); |
{ | ||
"name": "cloudevent", | ||
"version": "0.8.0", | ||
"version": "0.9.0", | ||
"description": "JavaScript/Node.js implementation of the CloudEvents standard format", | ||
"main": "src/index", | ||
"scripts": { | ||
"cache:cleanup": "npm cache clean --force", | ||
"cache:verify": "npm cache verify", | ||
"clean:install": "rm -rf ./package-lock.json ./node_modules/", | ||
"dependency:log": "npm list > ./temp/dependencies.log", | ||
@@ -11,17 +14,17 @@ "docs:clean": "rm -rf ./docs/*", | ||
"docs": "npm run docs:clean && npm run docs:generate", | ||
"example:debug": "node --inspect-brk example/nodejs-base", | ||
"example": "node example/nodejs-base", | ||
"example:debug": "node --inspect-brk example/nodejs-base", | ||
"lint": "npm run lint:standard", | ||
"license-check:log": "npx legally > ./temp/license-check.log", | ||
"license-check": "npx legally", | ||
"license-checker:log": "npm run license-checker | tee ./temp/license-checker.log", | ||
"license-checker": "npx license-checker --production --onlyAllow='Apache-2.0;BSD-2-Clause;BSD-3-Clause;MIT;ISC'", | ||
"lint:fix": "standard --fix", | ||
"lint:log": "npm run lint > ./temp/lint-standard.log", | ||
"lint:standard": "standard --verbose", | ||
"lint:log": "npm run lint > ./temp/lint-standard.log", | ||
"license-check": "npx legally", | ||
"license-check:log": "npx legally > ./temp/license-check.log", | ||
"license-checker": "npx license-checker --production --onlyAllow='Apache-2.0;BSD-2-Clause;BSD-3-Clause;MIT;ISC'", | ||
"license-checker:log": "npm run license-checker | tee ./temp/license-checker.log", | ||
"lint": "npm run lint:standard", | ||
"test:clean": "rm -rf .nyc_output/* ./coverage/*", | ||
"test:coverage": "npm run test:unit -- --cov --coverage-report=html", | ||
"test:unit": "tap -J --comments --no-esm --strict test/*.test.js", | ||
"test:unit:dev": "tap -J --comments --no-esm --strict --watch test/*.test.js", | ||
"test:unit:debug": "tap -T --node-arg=--inspect-brk --comments --no-esm --strict test/*.test.js", | ||
"test:unit:debug": "tap -T --node-arg=--inspect-brk test/*.test.js", | ||
"test:unit:dev": "tap -J --watch test/*.test.js", | ||
"test:unit": "tap -J test/*.test.js", | ||
"test": "npm run lint && npm run test:unit" | ||
@@ -31,5 +34,5 @@ }, | ||
"devDependencies": { | ||
"jsdoc": "^3.6.6", | ||
"standard": "^16.0.3", | ||
"tap": "^14.11.0" | ||
"jsdoc": "^3.6.10", | ||
"standard": "^16.0.4", | ||
"tap": "^15.2.3" | ||
}, | ||
@@ -53,4 +56,3 @@ "peerDependencies": {}, | ||
"author": "Sandro Martini <sandro.martini@gmail.com>", | ||
"license": "Apache-2.0", | ||
"snyk": true | ||
"license": "Apache-2.0" | ||
} |
@@ -7,4 +7,2 @@ # cloudevent / cloudevent.js | ||
[![Coverage Status](https://coveralls.io/repos/github/smartiniOnGitHub/cloudevent.js/badge.svg?branch=master)](https://coveralls.io/github/smartiniOnGitHub/cloudevent.js/?branch=master) | ||
[![dependencies Status](https://david-dm.org/smartiniOnGitHub/cloudevent.js/status.svg)](https://david-dm.org/smartiniOnGitHub/cloudevent.js) | ||
[![devDependencies Status](https://david-dm.org/smartiniOnGitHub/cloudevent.js/dev-status.svg)](https://david-dm.org/smartiniOnGitHub/cloudevent.js?type=dev) | ||
[![Known Vulnerabilities](https://snyk.io//test/github/smartiniOnGitHub/cloudevent.js/badge.svg?targetFile=package.json)](https://snyk.io//test/github/smartiniOnGitHub/cloudevent.js?targetFile=package.json) | ||
@@ -15,3 +13,3 @@ [![license - APACHE-2.0](https://img.shields.io/npm/l/cloudevent.svg)](http://opensource.org/licenses/APACHE-2.0) | ||
Current release implements the v1.0.1 of the CloudEvents Spec. | ||
Current release implements the v1.0.2 of the CloudEvents Spec. | ||
@@ -248,3 +246,4 @@ The purpose of this library is to create instances of CloudEvents in a simple way | ||
Node.js 10 LTS (but recommended 10.23.1) or later. | ||
Node.js 10 LTS (but recommended 10.24.1) or later | ||
(recommended an active LTS version). | ||
@@ -288,2 +287,4 @@ | ||
Since v1.0.1 of the spec, some properties has been expanded/clarified. | ||
Since v1.0.2 of the spec, the check on 'datacontenttype' if it's JSON-like | ||
has been updated. | ||
@@ -290,0 +291,0 @@ |
/* | ||
* Copyright 2018-2021 the original author or authors. | ||
* Copyright 2018-2022 the original author or authors. | ||
* | ||
@@ -50,3 +50,3 @@ * Licensed under the Apache License, Version 2.0 (the "License"); | ||
* @param {object} [options={}] optional attributes of the event; some has default values chosen here: | ||
* - time (timestamp/date, default now), | ||
* - time (timestamp in string ISO representation, from a date, default now), | ||
* - datainbase64 (string) base64 encoded value for the data (data attribute must not be present when this is defined), | ||
@@ -144,9 +144,11 @@ * - datacontenttype (string, default 'application/json') is the content type of the data attribute, | ||
* The event timestamp. | ||
* Copy the original object to avoid changing objects that could be shared. | ||
* If null, current timestamp will be set. | ||
* Note that here the object will be transformed into string when serialized. | ||
* If null, current timestamp will be set | ||
* but directly transformed into a string representation. | ||
* If a not empty string is passed here, it will be set | ||
* (then later validator could check it). | ||
* See under for more details. | ||
* @type {object} | ||
* @private | ||
*/ | ||
this.time = (!V.isNull(time)) ? new Date(time.valueOf()) : new Date() | ||
this.time = (V.isNull(time)) ? T.timestampToString(new Date()) : null | ||
/** | ||
@@ -159,2 +161,11 @@ * The subject of the event in the context of the event producer. | ||
// set time depending on the given input type, for be safer | ||
if (V.isDate(time)) { | ||
// convert the given timestamp in the right string representation | ||
this.time = T.timestampToString(time) | ||
} else if (V.isStringNotEmpty(time)) { | ||
// assign the value directly, maybe the validator will check later | ||
this.time = time | ||
} | ||
// add strict to extensions, but only when defined | ||
@@ -224,3 +235,4 @@ if (strict === true) { | ||
(event.datacontenttype === CloudEvent.datacontenttypeDefault()) || | ||
(event.datacontenttype.includes('json')) | ||
(event.datacontenttype.endsWith('/json')) || | ||
(event.datacontenttype.endsWith('+json')) | ||
) | ||
@@ -361,5 +373,10 @@ } | ||
* - dataschemavalidator (function(data, dataschema) boolean, optional) a function to validate data of current CloudEvent instance with its dataschema | ||
* - timezoneOffset (number, default 0) to apply a different timezone offset | ||
* @return {object[]} an array of (non null) validation errors, or at least an empty array | ||
*/ | ||
static validateEvent (event, { strict = false, dataschemavalidator = null } = {}) { | ||
static validateEvent (event, { | ||
strict = false, | ||
dataschemavalidator = null, | ||
timezoneOffset = 0 | ||
} = {}) { | ||
if (V.isUndefinedOrNull(event)) { | ||
@@ -418,3 +435,3 @@ return [new Error('CloudEvent undefined or null')] | ||
ve.push(V.ensureIsURI(event.source, null, 'source')) | ||
ve.push(V.ensureIsDatePast(event.time, 'time')) | ||
ve.push(V.ensureIsDatePast(T.timestampFromString(event.time, timezoneOffset), 'time')) | ||
ve.push(V.ensureIsStringNotEmpty(event.datacontenttype, 'datacontenttype')) | ||
@@ -457,6 +474,11 @@ if (V.isDefinedAndNotNull(event.dataschema)) { | ||
* - dataschemavalidator (function(data, dataschema) boolean, optional) a function to validate data of current CloudEvent instance with its dataschema | ||
* - timezoneOffset (number, default 0) to apply a different timezone offset | ||
* @return {boolean} true if valid, otherwise false | ||
*/ | ||
static isValidEvent (event, { strict = false, dataschemavalidator = null } = {}) { | ||
const validationErrors = CloudEvent.validateEvent(event, { strict, dataschemavalidator }) | ||
static isValidEvent (event, { | ||
strict = false, | ||
dataschemavalidator = null, | ||
timezoneOffset = 0 | ||
} = {}) { | ||
const validationErrors = CloudEvent.validateEvent(event, { strict, dataschemavalidator, timezoneOffset }) | ||
const size = V.getSize(validationErrors) | ||
@@ -493,2 +515,3 @@ return (size === 0) | ||
* - onlyIfLessThan64KB (boolean, default false) to return the serialized string only if it's less than 64 KB, | ||
* - timezoneOffset (number, default 0) to apply a different timezone offset | ||
* @return {string} the serialized event, as a string | ||
@@ -499,7 +522,8 @@ * @throws {Error} if event is undefined or null, or an option is undefined/null/wrong | ||
encoder, encodedData, | ||
onlyValid = false, onlyIfLessThan64KB = false | ||
onlyValid = false, onlyIfLessThan64KB = false, | ||
timezoneOffset = 0 | ||
} = {}) { | ||
if (V.isUndefinedOrNull(event)) throw new Error('CloudEvent undefined or null') | ||
if (event.datacontenttype === CloudEvent.datacontenttypeDefault()) { | ||
if ((onlyValid === false) || (onlyValid === true && CloudEvent.isValidEvent(event) === true)) { | ||
if ((onlyValid === false) || (onlyValid === true && CloudEvent.isValidEvent(event, { timezoneOffset }) === true)) { | ||
const ser = JSON.stringify(event, function replacer (key, value) { | ||
@@ -532,3 +556,3 @@ switch (key) { | ||
const newEvent = T.mergeObjects(event, { data: encodedData }) | ||
if ((onlyValid === false) || (onlyValid === true && CloudEvent.isValidEvent(newEvent) === true)) { | ||
if ((onlyValid === false) || (onlyValid === true && CloudEvent.isValidEvent(newEvent, { timezoneOffset }) === true)) { | ||
const ser = JSON.stringify(newEvent) | ||
@@ -579,3 +603,3 @@ if ((onlyIfLessThan64KB === false) || (onlyIfLessThan64KB === true && V.getSizeInBytes(ser) < 65536)) return ser | ||
{ // options | ||
time: T.timestampFromString(parsed.time, timezoneOffset), | ||
time: parsed.time, | ||
datainbase64: parsed.data_base64, | ||
@@ -592,3 +616,3 @@ datacontenttype: parsed.datacontenttype, | ||
// return ce, depending on its validation option | ||
if ((onlyValid === false) || (onlyValid === true && CloudEvent.isValidEvent(ce) === true)) { | ||
if ((onlyValid === false) || (onlyValid === true && CloudEvent.isValidEvent(ce, { timezoneOffset }) === true)) { | ||
if ((onlyIfLessThan64KB === false) || (onlyIfLessThan64KB === true && V.getSizeInBytes(ser) < 65536)) return ce | ||
@@ -614,3 +638,3 @@ else throw new Error('Unable to return a deserialized CloudEvent bigger than 64 KB.') | ||
// return ce, depending on its validation option | ||
if ((onlyValid === false) || (onlyValid === true && CloudEvent.isValidEvent(ce) === true)) { | ||
if ((onlyValid === false) || (onlyValid === true && CloudEvent.isValidEvent(ce, { timezoneOffset }) === true)) { | ||
if ((onlyIfLessThan64KB === false) || (onlyIfLessThan64KB === true && V.getSizeInBytes(ser) < 65536)) return ce | ||
@@ -684,5 +708,2 @@ else throw new Error('Unable to return a deserialized CloudEvent bigger than 64 KB.') | ||
* or when used both data and extensions will be empty in JSON output. | ||
* Note that for time I had to keep its schema definition commented | ||
* or schema validation on object instances would fail (because in the | ||
* object model I store it as a timestamp/date currently and not as a string). | ||
* | ||
@@ -808,6 +829,7 @@ * See JSON Schema. | ||
* - dataschemavalidator (function(data, dataschema) boolean, optional) a function to validate data of current CloudEvent instance with its dataschema | ||
* - timezoneOffset (number, default 0) to apply a different timezone offset | ||
* @return {boolean} true if valid, otherwise false | ||
*/ | ||
isValid ({ strict = false, dataschemavalidator = null } = {}) { | ||
return this.constructor.isValidEvent(this, { strict, dataschemavalidator }) | ||
isValid ({ strict = false, dataschemavalidator = null, timezoneOffset = 0 } = {}) { | ||
return this.constructor.isValidEvent(this, { strict, dataschemavalidator, timezoneOffset }) | ||
} | ||
@@ -850,2 +872,13 @@ | ||
/** | ||
* Getter method to return the CloudEvent time but as a Date object. | ||
* | ||
* See {@link CloudEvent.time}. | ||
* | ||
* @type {Date} | ||
*/ | ||
get timeAsDate () { | ||
return T.timestampFromString(this.time) | ||
} | ||
/** | ||
* Getter method to return a copy of CloudEvent data attribute (or data_base64 if defined), | ||
@@ -931,3 +964,3 @@ * but transformed/decoded if possible. | ||
const payloadDump = T.dumpObject(payload, 'payload') | ||
let payloadSummary = (payloadDump.length < 1024) ? payloadDump : (payloadDump.substr(0, 1020) + '...') | ||
let payloadSummary = (payloadDump.length < 1024) ? payloadDump : (payloadDump.substring(0, 1021) + '...') | ||
if (V.isString(payload)) { | ||
@@ -934,0 +967,0 @@ payloadSummary = payloadSummary + '\'' |
/* | ||
* Copyright 2018-2021 the original author or authors. | ||
* Copyright 2018-2022 the original author or authors. | ||
* | ||
@@ -4,0 +4,0 @@ * Licensed under the Apache License, Version 2.0 (the "License"); |
/* | ||
* Copyright 2018-2021 the original author or authors. | ||
* Copyright 2018-2022 the original author or authors. | ||
* | ||
@@ -219,10 +219,14 @@ * Licensed under the Apache License, Version 2.0 (the "License"); | ||
* - throwError (boolean, default false) to throw serialization errors | ||
* @param {object} callback a callback with usual arguments (err, data) to notify after processing each item | ||
* @return {string} the serialized JSONBatch, as a string | ||
* @throws {Error} if batch is undefined or null, or an option is undefined/null/wrong | ||
* @throws {Error} if batch is undefined or null, or an option is undefined/null/wrong or callback is not a function | ||
* @throws {TypeError} if batch is not a JSONBatch | ||
*/ | ||
static serializeEvents (batch, options = {}) { | ||
static serializeEvents (batch, options = {}, callback) { | ||
if (!JSONBatch.isJSONBatch(batch)) { | ||
throw new TypeError('The given batch is not a JSONBatch') | ||
} | ||
if (V.isDefinedAndNotNull(callback) && !V.isFunction(callback)) { | ||
throw new Error('The given callback is not a function') | ||
} | ||
@@ -238,5 +242,7 @@ let ser = '[' // serialized CloudEvent instances | ||
ser += CloudEvent.serializeEvent(val, options) | ||
if (V.isFunction(callback)) callback(null, { item: val, num }) | ||
num++ | ||
} catch (e) { | ||
ser += 'null' // as a fallback placeholder | ||
if (V.isFunction(callback)) callback(e, { item: null, num }) | ||
if (options.logError === true) { | ||
@@ -274,2 +280,3 @@ console.error(e) | ||
* - throwError (boolean, default false) to throw serialization errors | ||
* @param {object} callback a callback with usual arguments (err, data) to notify after processing each item | ||
* @return {object[]} the deserialized batch as a JSONBatch (so a CloudEvent array instance) | ||
@@ -280,4 +287,7 @@ * @throws {Error} if ser is undefined or null, or an option is undefined/null/wrong | ||
*/ | ||
static deserializeEvents (ser, options = {}) { | ||
static deserializeEvents (ser, options = {}, callback) { | ||
if (!V.isStringNotEmpty(ser)) throw new Error(`Missing or wrong serialized data: '${ser}' must be a string and not a: '${typeof ser}'.`) | ||
if (V.isDefinedAndNotNull(callback) && !V.isFunction(callback)) { | ||
throw new Error('The given callback is not a function') | ||
} | ||
@@ -309,3 +319,3 @@ // first deserialize to normal object instances | ||
const extensions = V.getObjectFilteredProperties(i, CloudEvent.isExtensionProperty) | ||
// note that strict is handleg both as strict and inside extensions, but it's good the same | ||
// note that strict is handled both as strict and inside extensions, but it's good the same | ||
const ce = new CloudEvent(i.id, i.type, i.source, i.data, { | ||
@@ -326,5 +336,7 @@ time: i.time, | ||
batch.push(ce) | ||
if (V.isFunction(callback)) callback(null, { item: ce, num }) | ||
num++ | ||
} | ||
} catch (e) { | ||
if (V.isFunction(callback)) callback(e, { item: null, num }) | ||
if (options.logError === true) { | ||
@@ -331,0 +343,0 @@ console.error(e) |
/* | ||
* Copyright 2018-2021 the original author or authors. | ||
* Copyright 2018-2022 the original author or authors. | ||
* | ||
@@ -4,0 +4,0 @@ * Licensed under the Apache License, Version 2.0 (the "License"); |
/* | ||
* Copyright 2018-2021 the original author or authors. | ||
* Copyright 2018-2022 the original author or authors. | ||
* | ||
@@ -4,0 +4,0 @@ * Licensed under the Apache License, Version 2.0 (the "License"); |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
165401
3027
302