From d46859c1778988310c6f88c507de1eb363f0e872 Mon Sep 17 00:00:00 2001 From: Tim Holm Date: Thu, 27 Apr 2023 09:11:41 +1000 Subject: [PATCH 1/2] allow simple payload for events. --- src/api/events/v0/events.test.ts | 16 +++------- src/api/events/v0/events.ts | 25 ++++++++------- src/faas/v0/handler.ts | 4 +-- src/resources/topic.ts | 4 +-- src/types.ts | 52 ++++++++++++++++++++------------ 5 files changed, 54 insertions(+), 47 deletions(-) diff --git a/src/api/events/v0/events.test.ts b/src/api/events/v0/events.test.ts index 9fc33d72..ae889008 100644 --- a/src/api/events/v0/events.test.ts +++ b/src/api/events/v0/events.test.ts @@ -22,6 +22,7 @@ import { TopicServiceClient as GrpcTopicServiceClient, } from '@nitric/api/proto/event/v1/event_grpc_pb'; import { UnimplementedError } from '../../errors'; +import { NitricEvent } from '@nitric/sdk/types'; describe('Event Client Tests', () => { describe('Given nitric.interfaces.event.EventServiceClient.publish throws an error', () => { @@ -84,19 +85,10 @@ describe('Event Client Tests', () => { test('Then Eventing.publish should resolve with the provided id', async () => { const client = new Eventing(); + const event = new NitricEvent({test: "test"}, 'test', 'Test Payload'); await expect( - client.topic('test').publish({ - id: 'test', - payloadType: 'Test Payload', - payload: { - test: 'test', - }, - }) - ).resolves.toStrictEqual({ - id: 'test', - payload: { test: 'test' }, - payloadType: 'Test Payload', - }); + client.topic('test').publish(new NitricEvent({test: "test"}, 'test', 'Test Payload')) + ).resolves.toStrictEqual(event); }); test('The Grpc client for Eventing.publish should have been called exactly once', () => { diff --git a/src/api/events/v0/events.ts b/src/api/events/v0/events.ts index 96c83418..6809f5f7 100644 --- a/src/api/events/v0/events.ts +++ b/src/api/events/v0/events.ts @@ -22,7 +22,7 @@ import { } from '@nitric/api/proto/event/v1/event_pb'; import { Struct } from 'google-protobuf/google/protobuf/struct_pb'; import * as grpc from '@grpc/grpc-js'; -import type { NitricEvent } from '../../../types'; +import { NitricEvent } from '../../../types'; import { fromGrpcError, InvalidArgumentError } from '../../errors'; /** @@ -51,7 +51,7 @@ const DEFAULT_PUBLISH_OPTS: PublishOptions = { delay: 0, }; -export class Topic { +export class Topic = Record> { eventing: Eventing; name: string; @@ -90,10 +90,13 @@ export class Topic { * ``` */ async publish( - event: T, + event: T | NitricEvent, opts: PublishOptions = DEFAULT_PUBLISH_OPTS - ): Promise { - const { id, payloadType = 'none', payload } = event; + ): Promise> { + const nitricEvent = event instanceof NitricEvent + ? event + : new NitricEvent(event); + const publishOpts = { ...DEFAULT_PUBLISH_OPTS, ...opts, @@ -101,20 +104,20 @@ export class Topic { const request = new EventPublishRequest(); const evt = new PbEvent(); - evt.setId(id); - evt.setPayload(Struct.fromJavaScript(payload)); - evt.setPayloadType(payloadType); + evt.setId(nitricEvent.id); + evt.setPayload(Struct.fromJavaScript(nitricEvent.payload)); + evt.setPayloadType(nitricEvent.payloadType); request.setTopic(this.name); request.setEvent(evt); request.setDelay(publishOpts.delay); - return new Promise((resolve, reject) => { + return new Promise>((resolve, reject) => { this.eventing.EventServiceClient.publish(request, (error, response) => { if (error) { reject(fromGrpcError(error)); } else { - resolve({ ...event, id: response.getId() }); + resolve(new NitricEvent(nitricEvent.payload, response.getId(), nitricEvent.payloadType)); } }); }); @@ -167,7 +170,7 @@ export class Eventing { * const topic = eventing.topic('notifications'); * ``` */ - public topic(name: string): Topic { + public topic = Record>(name: string): Topic { if (!name) { throw new InvalidArgumentError('A topic name is needed to use a Topic.'); } diff --git a/src/faas/v0/handler.ts b/src/faas/v0/handler.ts index 352953d7..56dd911d 100644 --- a/src/faas/v0/handler.ts +++ b/src/faas/v0/handler.ts @@ -29,8 +29,8 @@ export type GenericMiddleware = ( export type TriggerMiddleware = GenericMiddleware; export type HttpMiddleware = GenericMiddleware; -export type EventMiddleware = - GenericMiddleware>; +export type EventMiddleware = Record> = + GenericMiddleware>>; export type ScheduleMiddleware = GenericMiddleware>; /** diff --git a/src/resources/topic.ts b/src/resources/topic.ts index 581c4bcb..9121f439 100644 --- a/src/resources/topic.ts +++ b/src/resources/topic.ts @@ -38,7 +38,7 @@ export class SubscriptionWorkerOptions { /** * Creates a subscription worker */ -class Subscription { +class Subscription = Record> { private readonly faas: Faas; constructor(name: string, ...mw: EventMiddleware[]) { @@ -55,7 +55,7 @@ class Subscription { * Topic resource for pub/sub async messaging. */ export class TopicResource< - T extends NitricEvent = NitricEvent + T extends Record = Record > extends SecureResource { /** * Register this topic as a required resource for the calling function/container diff --git a/src/types.ts b/src/types.ts index a381fa92..b8790b05 100644 --- a/src/types.ts +++ b/src/types.ts @@ -11,26 +11,38 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. -export interface NitricEvent< - T extends Record = Record -> { - /** - * Uniquely identifies the event. - * - * Within your app you must ensure the ID is unique. - * Subscribers can assume events with the same ID are duplicates and avoid reprocessing them - */ - id?: string; - /** - * An optional description of the event type. - * - * Can be useful for de-serialization, routing or observability. The format of this value is determined by the producer. - */ - payloadType?: string; - /** - * The event's payload data, with details of the event. - */ - payload: T; +// export interface NitricEvent< +// T extends Record = Record +// > { +// /** +// * Uniquely identifies the event. +// * +// * Within your app you must ensure the ID is unique. +// * Subscribers can assume events with the same ID are duplicates and avoid reprocessing them +// */ +// id?: string; +// /** +// * An optional description of the event type. +// * +// * Can be useful for de-serialization, routing or observability. The format of this value is determined by the producer. +// */ +// payloadType?: string; +// /** +// * The event's payload data, with details of the event. +// */ +// payload: T; +// } + +export class NitricEvent = Record> { + public readonly payload: T; + public readonly id?: string; + public readonly payloadType: string; + + constructor(payload: T, id?: string, payloadType?: string) { + this.payload = payload; + this.id = id; + this.payloadType = payloadType || 'none'; + } } export interface Task = Record> { From b23bf81db9d8bbb22842525e12901c66b9fca902 Mon Sep 17 00:00:00 2001 From: Tim Holm Date: Fri, 28 Apr 2023 12:22:15 +1000 Subject: [PATCH 2/2] prettier. --- src/api/events/v0/events.test.ts | 6 ++++-- src/api/events/v0/events.ts | 17 ++++++++++++----- src/faas/v0/handler.ts | 5 +++-- 3 files changed, 19 insertions(+), 9 deletions(-) diff --git a/src/api/events/v0/events.test.ts b/src/api/events/v0/events.test.ts index ae889008..e53c3304 100644 --- a/src/api/events/v0/events.test.ts +++ b/src/api/events/v0/events.test.ts @@ -85,9 +85,11 @@ describe('Event Client Tests', () => { test('Then Eventing.publish should resolve with the provided id', async () => { const client = new Eventing(); - const event = new NitricEvent({test: "test"}, 'test', 'Test Payload'); + const event = new NitricEvent({ test: 'test' }, 'test', 'Test Payload'); await expect( - client.topic('test').publish(new NitricEvent({test: "test"}, 'test', 'Test Payload')) + client + .topic('test') + .publish(new NitricEvent({ test: 'test' }, 'test', 'Test Payload')) ).resolves.toStrictEqual(event); }); diff --git a/src/api/events/v0/events.ts b/src/api/events/v0/events.ts index 6809f5f7..ff634673 100644 --- a/src/api/events/v0/events.ts +++ b/src/api/events/v0/events.ts @@ -93,9 +93,8 @@ export class Topic = Record> { event: T | NitricEvent, opts: PublishOptions = DEFAULT_PUBLISH_OPTS ): Promise> { - const nitricEvent = event instanceof NitricEvent - ? event - : new NitricEvent(event); + const nitricEvent = + event instanceof NitricEvent ? event : new NitricEvent(event); const publishOpts = { ...DEFAULT_PUBLISH_OPTS, @@ -117,7 +116,13 @@ export class Topic = Record> { if (error) { reject(fromGrpcError(error)); } else { - resolve(new NitricEvent(nitricEvent.payload, response.getId(), nitricEvent.payloadType)); + resolve( + new NitricEvent( + nitricEvent.payload, + response.getId(), + nitricEvent.payloadType + ) + ); } }); }); @@ -170,7 +175,9 @@ export class Eventing { * const topic = eventing.topic('notifications'); * ``` */ - public topic = Record>(name: string): Topic { + public topic = Record>( + name: string + ): Topic { if (!name) { throw new InvalidArgumentError('A topic name is needed to use a Topic.'); } diff --git a/src/faas/v0/handler.ts b/src/faas/v0/handler.ts index 56dd911d..efce4dbf 100644 --- a/src/faas/v0/handler.ts +++ b/src/faas/v0/handler.ts @@ -29,8 +29,9 @@ export type GenericMiddleware = ( export type TriggerMiddleware = GenericMiddleware; export type HttpMiddleware = GenericMiddleware; -export type EventMiddleware = Record> = - GenericMiddleware>>; +export type EventMiddleware< + T extends Record = Record +> = GenericMiddleware>>; export type ScheduleMiddleware = GenericMiddleware>; /**