diff --git a/src/event/cloudevent.ts b/src/event/cloudevent.ts index 8c67baa..a8e2580 100644 --- a/src/event/cloudevent.ts +++ b/src/event/cloudevent.ts @@ -133,7 +133,7 @@ See: https://github.com/cloudevents/spec/blob/v1.0/spec.md#type-system`); set data(value: T | undefined) { if (isBinary(value)) { - this.data_base64 = asBase64(value); + this.data_base64 = asBase64(value as unknown as Buffer); } this.#_data = value; } diff --git a/src/event/validation.ts b/src/event/validation.ts index 0b6fbed..1926b24 100644 --- a/src/event/validation.ts +++ b/src/event/validation.ts @@ -5,6 +5,10 @@ import { ErrorObject } from "ajv"; +export type TypeArray = Int8Array | Uint8Array | Int16Array | Uint16Array | + Int32Array | Uint32Array | Uint8ClampedArray | Float32Array | Float64Array; + + /** * An Error class that will be thrown when a CloudEvent * cannot be properly validated against a specification. @@ -36,7 +40,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 +77,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 +86,8 @@ 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 asBase64 = +(value: string | Buffer | TypeArray): string => asBuffer(value).toString("base64"); export const clone = (o: Record): Record => JSON.parse(JSON.stringify(o)); @@ -97,5 +102,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); diff --git a/test/integration/spec_1_tests.ts b/test/integration/spec_1_tests.ts index e2bbd62..7bd2248 100644 --- a/test/integration/spec_1_tests.ts +++ b/test/integration/spec_1_tests.ts @@ -173,14 +173,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); + }); }); }); });