diff --git a/src/api/events/v0/events.ts b/src/api/events/v0/events.ts index 8761246f..96c83418 100644 --- a/src/api/events/v0/events.ts +++ b/src/api/events/v0/events.ts @@ -51,7 +51,7 @@ const DEFAULT_PUBLISH_OPTS: PublishOptions = { delay: 0, }; -export class Topic { +export class Topic { eventing: Eventing; name: string; @@ -90,9 +90,9 @@ export class Topic { * ``` */ async publish( - event: NitricEvent, + event: T, opts: PublishOptions = DEFAULT_PUBLISH_OPTS - ): Promise { + ): Promise { const { id, payloadType = 'none', payload } = event; const publishOpts = { ...DEFAULT_PUBLISH_OPTS, @@ -109,7 +109,7 @@ export class Topic { 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)); @@ -167,7 +167,7 @@ export class Eventing { * const topic = eventing.topic('notifications'); * ``` */ - public topic(name: string): Topic { + public topic(name: string): Topic { if (!name) { throw new InvalidArgumentError('A topic name is needed to use a Topic.'); } diff --git a/src/faas/v0/context.ts b/src/faas/v0/context.ts index c7ef68f2..aa716e28 100644 --- a/src/faas/v0/context.ts +++ b/src/faas/v0/context.ts @@ -43,7 +43,7 @@ export abstract class TriggerContext< * * @returns undefined */ - public get event(): EventContext | undefined { + public get event(): EventContext | undefined { return undefined; } @@ -89,7 +89,11 @@ export abstract class TriggerContext< } } -export abstract class AbstractRequest { +export type JSONTypes = Record | Array | string; + +export abstract class AbstractRequest< + JSONT extends JSONTypes = Record +> { readonly data: string | Uint8Array; readonly traceContext: api.Context; @@ -107,7 +111,7 @@ export abstract class AbstractRequest { return stringPayload; } - json(): Record { + json(): JSONT { // attempt to deserialize as a JSON object return this.text() ? JSON.parse(this.text()) : {}; } @@ -184,7 +188,7 @@ export class HttpResponse { } } -export class EventRequest extends AbstractRequest { +export class EventRequest extends AbstractRequest { public readonly topic: string; constructor( @@ -355,12 +359,17 @@ export class HttpContext extends TriggerContext { } } -export class EventContext extends TriggerContext { - public get event(): EventContext { +export class EventContext extends TriggerContext< + EventRequest, + EventResponse +> { + public get event(): EventContext { return this; } - static fromGrpcTriggerRequest(trigger: TriggerRequest): EventContext { + static fromGrpcTriggerRequest( + trigger: TriggerRequest + ): EventContext { const topic = trigger.getTopic(); const ctx = new EventContext(); diff --git a/src/faas/v0/handler.ts b/src/faas/v0/handler.ts index 5e18330c..352953d7 100644 --- a/src/faas/v0/handler.ts +++ b/src/faas/v0/handler.ts @@ -11,13 +11,16 @@ // 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. +import { NitricEvent } from '../../types'; import { TriggerContext, HttpContext, EventContext } from '.'; export type GenericHandler = (ctx: Ctx) => Promise | Ctx; export type TriggerHandler = GenericHandler; export type HttpHandler = GenericHandler; -export type EventHandler = GenericHandler; +export type EventHandler = GenericHandler< + EventContext +>; export type GenericMiddleware = ( ctx: Ctx, @@ -26,7 +29,9 @@ export type GenericMiddleware = ( export type TriggerMiddleware = GenericMiddleware; export type HttpMiddleware = GenericMiddleware; -export type EventMiddleware = GenericMiddleware; +export type EventMiddleware = + GenericMiddleware>; +export type ScheduleMiddleware = GenericMiddleware>; /** * createHandler diff --git a/src/faas/v0/start.ts b/src/faas/v0/start.ts index 310e3d9a..937aca9a 100644 --- a/src/faas/v0/start.ts +++ b/src/faas/v0/start.ts @@ -36,6 +36,7 @@ import { EventMiddleware, GenericMiddleware, HttpMiddleware, + ScheduleMiddleware, TriggerContext, TriggerMiddleware, } from '.'; @@ -64,7 +65,7 @@ type FaasClientOptions = */ export class Faas { private httpHandler?: HttpMiddleware; - private eventHandler?: EventMiddleware; + private eventHandler?: EventMiddleware | ScheduleMiddleware; private anyHandler?: TriggerMiddleware; private readonly options: FaasClientOptions; @@ -78,8 +79,8 @@ export class Faas { * @param handlers the functions to call to respond to events * @returns self */ - event(...handlers: EventMiddleware[]): Faas { - this.eventHandler = createHandler(...handlers); + event(...handlers: EventMiddleware[] | ScheduleMiddleware[]): Faas { + this.eventHandler = createHandler(...handlers); return this; } diff --git a/src/faas/v0/traceProvider.ts b/src/faas/v0/traceProvider.ts index e44db5fe..9e7f1db6 100644 --- a/src/faas/v0/traceProvider.ts +++ b/src/faas/v0/traceProvider.ts @@ -27,6 +27,7 @@ import { TraceIdRatioBasedSampler } from '@opentelemetry/sdk-trace-node'; /** * Creates a new node tracer provider * If it is a local run, it will output to the console. If it is run on the cloud it will output to localhost:4317 + * * @returns a tracer provider */ const newTracerProvider = (): NodeTracerProvider => { diff --git a/src/resources/schedule.ts b/src/resources/schedule.ts index 4a257371..95c104e4 100644 --- a/src/resources/schedule.ts +++ b/src/resources/schedule.ts @@ -11,7 +11,7 @@ // 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. -import { EventMiddleware, Faas } from '../faas'; +import { EventMiddleware, Faas, ScheduleMiddleware } from '../faas'; type Frequency = 'days' | 'hours' | 'minutes'; @@ -48,7 +48,7 @@ class Rate { public readonly schedule: Schedule; private readonly faas: Faas; - constructor(schedule: Schedule, rate: string, ...mw: EventMiddleware[]) { + constructor(schedule: Schedule, rate: string, ...mw: ScheduleMiddleware[]) { const [, frequency] = rate.split(' '); const normalizedFrequency = frequency.toLocaleLowerCase() as Frequency; @@ -90,7 +90,7 @@ class Cron { public readonly schedule: Schedule; private readonly faas: Faas; - constructor(schedule: Schedule, cron: string, ...mw: EventMiddleware[]) { + constructor(schedule: Schedule, cron: string, ...mw: ScheduleMiddleware[]) { this.schedule = schedule; this.faas = new Faas(new CronWorkerOptions(schedule['description'], cron)); this.faas.event(...mw); @@ -118,7 +118,7 @@ class Schedule { * @param mw the handler/middleware to run on a schedule * @returns A promise that resolves when the schedule worker stops running. */ - every = (rate: string, ...mw: EventMiddleware[]): Promise => { + every = (rate: string, ...mw: ScheduleMiddleware[]): Promise => { // handle singular frequencies. e.g. schedule('something').every('day') if (FREQUENCIES.indexOf(`${rate}s` as Frequency) !== -1) { rate = `1 ${rate}s`; // 'day' becomes '1 days' @@ -129,7 +129,7 @@ class Schedule { return r['start'](); }; - cron = (expression: string, ...mw: EventMiddleware[]): Promise => { + cron = (expression: string, ...mw: ScheduleMiddleware[]): Promise => { const r = new Cron(this, expression, ...mw); // Start the new cron immediately return r['start'](); diff --git a/src/resources/topic.ts b/src/resources/topic.ts index 81b441cc..581c4bcb 100644 --- a/src/resources/topic.ts +++ b/src/resources/topic.ts @@ -23,6 +23,7 @@ import { } from '@nitric/api/proto/resource/v1/resource_pb'; import { ActionsList, make, SecureResource } from './common'; import { fromGrpcError } from '../api/errors'; +import { NitricEvent } from '../types'; type TopicPermission = 'publishing'; @@ -37,10 +38,10 @@ export class SubscriptionWorkerOptions { /** * Creates a subscription worker */ -class Subscription { +class Subscription { private readonly faas: Faas; - constructor(name: string, ...mw: EventMiddleware[]) { + constructor(name: string, ...mw: EventMiddleware[]) { this.faas = new Faas(new SubscriptionWorkerOptions(name)); this.faas.event(...mw); } @@ -53,7 +54,9 @@ class Subscription { /** * Topic resource for pub/sub async messaging. */ -export class TopicResource extends SecureResource { +export class TopicResource< + T extends NitricEvent = NitricEvent +> extends SecureResource { /** * Register this topic as a required resource for the calling function/container * @@ -105,8 +108,8 @@ export class TopicResource extends SecureResource { * @param mw handler middleware which will be run for every incoming event * @returns Promise which resolves when the handler server terminates */ - subscribe(...mw: EventMiddleware[]): Promise { - const sub = new Subscription(this.name, ...mw); + subscribe(...mw: EventMiddleware[]): Promise { + const sub = new Subscription(this.name, ...mw); return sub['start'](); } @@ -133,10 +136,14 @@ export class TopicResource extends SecureResource { * @param perms the required permission set * @returns a usable topic reference */ - public for(...perms: TopicPermission[]): Topic { + public for(...perms: TopicPermission[]): Topic { this.registerPolicy(...perms); return events().topic(this.name); } } -export const topic = make(TopicResource); +export const topic = make(TopicResource) as < + T extends Record = Record +>( + name: string +) => TopicResource>; diff --git a/src/types.ts b/src/types.ts index 490e97ff..a381fa92 100644 --- a/src/types.ts +++ b/src/types.ts @@ -11,7 +11,9 @@ // 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 { +export interface NitricEvent< + T extends Record = Record +> { /** * Uniquely identifies the event. * @@ -28,10 +30,10 @@ export interface NitricEvent { /** * The event's payload data, with details of the event. */ - payload: Record; + payload: T; } -export interface Task { +export interface Task = Record> { /** * Uniquely identifies the task. *