From 3fb476a8ff6abd1462acfbf9f95943d4ded86bd3 Mon Sep 17 00:00:00 2001 From: Matt Aitken Date: Fri, 20 Oct 2023 16:52:16 +0100 Subject: [PATCH] Initial httpTrigger types working --- packages/core/src/schemas/requestFilter.ts | 17 ++++++++- packages/trigger-sdk/src/triggerClient.ts | 4 +- .../trigger-sdk/src/triggers/httpTrigger.ts | 37 +++++++++++++++---- references/job-catalog/src/httpTrigger.ts | 22 +++++++++-- 4 files changed, 64 insertions(+), 16 deletions(-) diff --git a/packages/core/src/schemas/requestFilter.ts b/packages/core/src/schemas/requestFilter.ts index 34425472a..4723c59c7 100644 --- a/packages/core/src/schemas/requestFilter.ts +++ b/packages/core/src/schemas/requestFilter.ts @@ -7,8 +7,21 @@ const StringMatchSchema = z.union([ z.array(z.union(stringPatternMatchers)), ]); +export const HTTPMethodUnionSchema = z.union([ + z.literal("GET"), + z.literal("POST"), + z.literal("PUT"), + z.literal("PATCH"), + z.literal("DELETE"), + z.literal("HEAD"), + z.literal("OPTIONS"), +]); + export const RequestFilterSchema = z.object({ - headers: z.record(StringMatchSchema), - query: z.record(StringMatchSchema), + method: z.array(HTTPMethodUnionSchema).optional(), + headers: z.record(StringMatchSchema).optional(), + query: z.record(StringMatchSchema).optional(), body: EventFilterSchema.optional(), }); + +export type RequestFilter = z.infer; diff --git a/packages/trigger-sdk/src/triggerClient.ts b/packages/trigger-sdk/src/triggerClient.ts index 2b9896c4d..94384f5d5 100644 --- a/packages/trigger-sdk/src/triggerClient.ts +++ b/packages/trigger-sdk/src/triggerClient.ts @@ -47,7 +47,7 @@ import { runLocalStorage } from "./runLocalStorage"; import { DynamicTrigger, DynamicTriggerOptions } from "./triggers/dynamic"; import { EventTrigger } from "./triggers/eventTrigger"; import { ExternalSource } from "./triggers/externalSource"; -import { HttpTriggerOptions, httpTrigger } from "./triggers/httpTrigger"; +import { HttpTriggerOptions, RequestData, httpTrigger } from "./triggers/httpTrigger"; import { DynamicIntervalOptions, DynamicSchedule } from "./triggers/scheduled"; import type { EventSpecification, @@ -472,7 +472,7 @@ export class TriggerClient { return new DynamicTrigger(this, options); } - defineHttpTrigger(options: HttpTriggerOptions) { + defineHttpTrigger(options: HttpTriggerOptions) { return httpTrigger(options); } diff --git a/packages/trigger-sdk/src/triggers/httpTrigger.ts b/packages/trigger-sdk/src/triggers/httpTrigger.ts index e7d620093..e85e50ca4 100644 --- a/packages/trigger-sdk/src/triggers/httpTrigger.ts +++ b/packages/trigger-sdk/src/triggers/httpTrigger.ts @@ -1,9 +1,16 @@ -import { EventFilter, TriggerMetadata, deepMergeFilters } from "@trigger.dev/core"; +import { + DisplayProperty, + EventFilter, + RequestFilter, + TriggerMetadata, + deepMergeFilters, +} from "@trigger.dev/core"; import { Job } from "../job"; import { TriggerClient } from "../triggerClient"; import { EventSpecification, EventSpecificationExample, SchemaParser, Trigger } from "../types"; import { formatSchemaErrors } from "../utils/formatSchemaErrors"; import { ParsedPayloadSchemaError } from "../errors"; +import { z } from "zod"; type Options> = { id: string; @@ -37,13 +44,26 @@ export class HttpTrigger> } } +type RequestContext = { + secret: string | undefined; +}; + /** Configuration options for an EventTrigger */ export type HttpTriggerOptions = { id: string; - schema?: SchemaParser; - source?: string; + /** The hostname of the webhook, e.g. whatsapp.com */ + hostname: string; + title?: string; + icon?: string; + bodySchema?: SchemaParser; filter?: EventFilter; examples?: EventSpecificationExample[]; + properties?: DisplayProperty[]; + verify?: { + requestFilter: RequestFilter; + onRequest: (request: Request, context: RequestContext) => Promise; + }; + transform?: (request: Request) => Promise; }; /** `eventTrigger()` is set as a [Job's trigger](https://trigger.dev/docs/sdk/job) to subscribe to an event a Job from [a sent event](https://trigger.dev/docs/sdk/triggerclient/instancemethods/sendevent) @@ -56,13 +76,14 @@ export function httpTrigger( id: options.id, event: { name: options.id, - title: "Event", - source: options.source ?? "trigger.dev", - icon: "custom-event", + title: options.title ?? "HTTP Trigger", + source: options.hostname, + icon: options.icon ?? "world-www", + properties: options.properties, examples: options.examples, parsePayload: (rawPayload: any) => { - if (options.schema) { - const results = options.schema.safeParse(rawPayload); + if (options.bodySchema) { + const results = options.bodySchema.safeParse(rawPayload.body); if (!results.success) { throw new ParsedPayloadSchemaError(formatSchemaErrors(results.error.issues)); diff --git a/references/job-catalog/src/httpTrigger.ts b/references/job-catalog/src/httpTrigger.ts index 92cb9365b..8a1a831d7 100644 --- a/references/job-catalog/src/httpTrigger.ts +++ b/references/job-catalog/src/httpTrigger.ts @@ -12,9 +12,23 @@ export const client = new TriggerClient({ const whatsApp = client.defineHttpTrigger({ id: "whatsapp", - schema: z.object({ - message: z.string(), - }), + hostname: "whatsapp.com", + // bodySchema: z.object({ + // mesaaaasage: z.string(), + // }), + verify: { + requestFilter: { + method: ["GET"], + }, + onRequest: async (request, context) => { + const searchParams = new URL(request.url).searchParams; + if (searchParams.get("verify_token") !== context.secret) { + return new Response("Unauthorized", { status: 401 }); + } + + return new Response(searchParams.get("challenge") ?? "OK", { status: 200 }); + }, + }, }); client.defineJob({ @@ -24,7 +38,7 @@ client.defineJob({ enabled: true, trigger: whatsApp, run: async (payload, io, ctx) => { - // ^? + // ^? }, });