From c99bb85b43ba329377d0def155918cd18ea87870 Mon Sep 17 00:00:00 2001 From: Kevin Mathew Sunny Date: Fri, 15 May 2026 00:19:18 +0530 Subject: [PATCH 1/5] refactor: return early from DateParser on an invalid date Date.parse returns NaN for an unparseable string, so test that directly and return the current time, instead of building a Date and comparing its string form to "Invalid Date". No behavior change. The NaN check is the form blackakula suggested in the review of #646. A comment marks the fallback to the current time as deprecated: the spec requires RFC 3339, and v11 will throw a ValidationError instead. Split from #646. Signed-off-by: Kevin Mathew Sunny --- src/parsers.ts | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/parsers.ts b/src/parsers.ts index 7a050672..90b26e52 100644 --- a/src/parsers.ts +++ b/src/parsers.ts @@ -89,11 +89,13 @@ export interface MappedParser { export class DateParser extends Parser { parse(payload: string): string { - let date = new Date(Date.parse(payload)); - if (date.toString() === "Invalid Date") { - date = new Date(); + const timestamp = Date.parse(payload); + if (isNaN(timestamp)) { + // Deprecated: substituting the current time for an unparseable time hides an + // invalid message. The spec requires RFC 3339, so v11 will throw a ValidationError. + return new Date().toISOString(); } - return date.toISOString(); + return new Date(timestamp).toISOString(); } } From 5471185adcd3787ea573fa99cb90b1ee56c3b2dd Mon Sep 17 00:00:00 2001 From: Kevin Mathew Sunny Date: Fri, 15 May 2026 00:19:18 +0530 Subject: [PATCH 2/5] test: guard the conformance time comparison against a missing time new Date(undefined).toISOString() throws a RangeError, so a scenario without a time attribute crashed the step instead of failing the assertion. Compare ISO strings only when both sides have a time, and compare the raw values otherwise. Split from #646. Signed-off-by: Kevin Mathew Sunny --- test/conformance/steps.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/test/conformance/steps.ts b/test/conformance/steps.ts index 7d53a566..a72203ed 100644 --- a/test/conformance/steps.ts +++ b/test/conformance/steps.ts @@ -71,7 +71,11 @@ Then("the attributes are:", function (attributes: { rawTable: [] }) { assert.equal(this.cloudevent.id, expected.id); assert.equal(this.cloudevent.type, expected.type); assert.equal(this.cloudevent.source, expected.source); - assert.equal(this.cloudevent.time, new Date(expected.time).toISOString()); + if (this.cloudevent.time && expected.time) { + assert.equal(new Date(this.cloudevent.time).toISOString(), new Date(expected.time).toISOString()); + } else { + assert.equal(this.cloudevent.time, expected.time); + } assert.equal(this.cloudevent.specversion, expected.specversion); assert.equal(this.cloudevent.datacontenttype, expected.datacontenttype); return true; From 52ce996c0c2759659eba91d28125547b21aae154 Mon Sep 17 00:00:00 2001 From: Kevin Mathew Sunny Date: Fri, 15 May 2026 00:19:18 +0530 Subject: [PATCH 3/5] style: remove trailing whitespace in validation.ts Split from #646. Signed-off-by: Kevin Mathew Sunny --- src/event/validation.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/event/validation.ts b/src/event/validation.ts index 663e034d..8665304a 100644 --- a/src/event/validation.ts +++ b/src/event/validation.ts @@ -5,7 +5,7 @@ import { ErrorObject } from "ajv"; -export type TypeArray = Int8Array | Uint8Array | Int16Array | Uint16Array | +export type TypeArray = Int8Array | Uint8Array | Int16Array | Uint16Array | Int32Array | Uint32Array | Uint8ClampedArray | Float32Array | Float64Array; const globalThisPolyfill = (function() { @@ -103,7 +103,7 @@ export const base64AsBinary = (base64String: string): Uint8Array => { return Uint8Array.from(toBinaryString(base64String), (c) => c.charCodeAt(0)); }; -export const asBase64 = +export const asBase64 = (value: string | Buffer | TypeArray): string => asBuffer(value).toString("base64"); export const clone = (o: Record): Record => JSON.parse(JSON.stringify(o)); From 566702e5029c488b134718edf24a27d223204499 Mon Sep 17 00:00:00 2001 From: Shiva Date: Fri, 6 Nov 2026 14:33:34 -0700 Subject: [PATCH 4/5] feat: add DateParser tests and enhance JSONParser imports Signed-off-by: Shiva --- test/integration/parser_test.ts | 41 +++++++++++++++++++++++++++++++-- 1 file changed, 39 insertions(+), 2 deletions(-) diff --git a/test/integration/parser_test.ts b/test/integration/parser_test.ts index 5be19b3e..39e72932 100644 --- a/test/integration/parser_test.ts +++ b/test/integration/parser_test.ts @@ -6,8 +6,9 @@ import "mocha"; import { expect } from "chai"; -import { JSONParser as Parser } from "../../src/parsers"; -import { ValidationError } from "../../src/"; +import { DateParser, JSONParser as Parser } from "../../src/parsers"; +import { CloudEvent, ValidationError } from "../../src/"; +import { HTTP } from "../../src/message"; describe("JSON Event Format Parser", () => { it("Throw error when payload is an integer", () => { @@ -79,3 +80,39 @@ describe("JSON Event Format Parser", () => { expect(actual).to.be.an("object"); }); }); + +describe("Date Parser", () => { + const parser = new DateParser(); + + it("Returns an RFC 3339 UTC timestamp unchanged", () => { + expect(parser.parse("2018-04-05T17:31:00.000Z")).to.equal("2018-04-05T17:31:00.000Z"); + }); + + it("Normalizes an RFC 3339 timestamp with an offset to UTC", () => { + expect(parser.parse("2018-04-05T17:31:00+02:00")).to.equal("2018-04-05T15:31:00.000Z"); + }); + + it("Falls back to the current time when the payload is not a date", () => { + const before = Date.now(); + const parsed = Date.parse(parser.parse("not a date")); + const after = Date.now(); + expect(parsed).to.be.at.least(before).and.at.most(after); + }); + + it("Does not throw when a binary message carries an unparseable ce-time header", () => { + const message = { + headers: { + "ce-id": "1234", + "ce-source": "test", + "ce-type": "test.event", + "ce-specversion": "1.0", + "ce-time": "garbage", + "content-type": "application/json", + }, + body: "{}", + }; + const event = HTTP.toEvent(message) as CloudEvent; + expect(Number.isNaN(Date.parse(event.time as string))).to.equal(false); + expect(() => event.validate()).not.to.throw(); + }); +}); From d6abe318ce7a4a3d011ee29be60309abbb70721b Mon Sep 17 00:00:00 2001 From: Shiva Date: Fri, 6 Nov 2026 14:34:12 -0700 Subject: [PATCH 5/5] chore: release 10.1.0 Release-As: 10.1.0 Signed-off-by: Shiva