Implement @trigger.dev/nextjs package and make it work with the Next.js 13 app dir
This commit is contained in:
@@ -37,7 +37,7 @@ export class EndpointApi {
|
||||
|
||||
async ping() {
|
||||
const response = await safeFetch(this.#url, {
|
||||
method: "GET",
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
"x-trigger-api-key": this.#apiKey,
|
||||
@@ -68,10 +68,11 @@ export class EndpointApi {
|
||||
|
||||
async getEndpointData() {
|
||||
const response = await safeFetch(this.#url, {
|
||||
method: "GET",
|
||||
method: "POSt",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
Accept: "application/json",
|
||||
"x-trigger-api-key": this.#apiKey,
|
||||
"x-trigger-action": "GET_ENDPOINT_DATA",
|
||||
},
|
||||
});
|
||||
|
||||
@@ -132,7 +133,7 @@ export class EndpointApi {
|
||||
const response = await safeFetch(this.#url, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
"content-type": "application/json",
|
||||
"x-trigger-api-key": this.#apiKey,
|
||||
"x-trigger-action": "EXECUTE_JOB",
|
||||
},
|
||||
|
||||
@@ -159,10 +159,10 @@ export class RegisterJobService {
|
||||
// Upsert the JobVersion
|
||||
const jobVersion = await this.#prismaClient.jobVersion.upsert({
|
||||
where: {
|
||||
jobId_version_endpointId: {
|
||||
jobId_version_environmentId: {
|
||||
jobId: job.id,
|
||||
version: metadata.version,
|
||||
endpointId: endpoint.id,
|
||||
environmentId: environment.id,
|
||||
},
|
||||
},
|
||||
create: {
|
||||
@@ -212,6 +212,11 @@ export class RegisterJobService {
|
||||
id: jobQueue.id,
|
||||
},
|
||||
},
|
||||
endpoint: {
|
||||
connect: {
|
||||
id: endpoint.id,
|
||||
},
|
||||
},
|
||||
},
|
||||
include: {
|
||||
integrations: {
|
||||
|
||||
@@ -383,7 +383,7 @@ export class PerformRunExecutionService {
|
||||
data: {
|
||||
retryCount,
|
||||
retryDelayInMs,
|
||||
error: output,
|
||||
error: JSON.stringify(output),
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@ export class DeliverHttpSourceRequestService {
|
||||
secretReference: true,
|
||||
dynamicTrigger: true,
|
||||
externalAccount: true,
|
||||
apiClient: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
@@ -89,8 +89,8 @@ export class RegisterSourceService {
|
||||
|
||||
const triggerSource = await tx.triggerSource.upsert({
|
||||
where: {
|
||||
key_endpointId: {
|
||||
endpointId: endpoint.id,
|
||||
key_environmentId: {
|
||||
environmentId: environment.id,
|
||||
key,
|
||||
},
|
||||
},
|
||||
@@ -148,7 +148,16 @@ export class RegisterSourceService {
|
||||
},
|
||||
},
|
||||
},
|
||||
update: {},
|
||||
update: {
|
||||
endpoint: {
|
||||
connect: {
|
||||
id: endpoint.id,
|
||||
},
|
||||
},
|
||||
apiClient: apiClient
|
||||
? { connect: { id: apiClient.id } }
|
||||
: undefined,
|
||||
},
|
||||
include: {
|
||||
events: true,
|
||||
secretReference: true,
|
||||
|
||||
@@ -37,8 +37,8 @@ export class UpdateSourceService {
|
||||
const triggerSource =
|
||||
await this.#prismaClient.triggerSource.findUniqueOrThrow({
|
||||
where: {
|
||||
key_endpointId: {
|
||||
endpointId: endpoint.id,
|
||||
key_environmentId: {
|
||||
environmentId: environment.id,
|
||||
key: id,
|
||||
},
|
||||
},
|
||||
@@ -54,6 +54,7 @@ export class UpdateSourceService {
|
||||
data: {
|
||||
active: true,
|
||||
channelData: payload.data as any,
|
||||
endpointId: endpoint.id,
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
/*
|
||||
Warnings:
|
||||
|
||||
- A unique constraint covering the columns `[jobId,version,environmentId]` on the table `JobVersion` will be added. If there are existing duplicate values, this will fail.
|
||||
|
||||
*/
|
||||
-- DropIndex
|
||||
DROP INDEX "JobVersion_jobId_version_endpointId_key";
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "JobVersion_jobId_version_environmentId_key" ON "JobVersion"("jobId", "version", "environmentId");
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
/*
|
||||
Warnings:
|
||||
|
||||
- A unique constraint covering the columns `[key,environmentId]` on the table `TriggerSource` will be added. If there are existing duplicate values, this will fail.
|
||||
|
||||
*/
|
||||
-- DropIndex
|
||||
DROP INDEX "TriggerSource_key_endpointId_key";
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "TriggerSource_key_environmentId_key" ON "TriggerSource"("key", "environmentId");
|
||||
@@ -356,7 +356,7 @@ model JobVersion {
|
||||
integrations JobIntegration[]
|
||||
aliases JobAlias[]
|
||||
|
||||
@@unique([jobId, version, endpointId])
|
||||
@@unique([jobId, version, environmentId])
|
||||
}
|
||||
|
||||
model JobQueue {
|
||||
@@ -738,7 +738,7 @@ model TriggerSource {
|
||||
httpDeliveries HttpSourceRequestDelivery[]
|
||||
registrations DynamicTriggerRegistration[]
|
||||
|
||||
@@unique([key, endpointId])
|
||||
@@unique([key, environmentId])
|
||||
}
|
||||
|
||||
enum TriggerChannel {
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"typescript.tsdk": "../../node_modules/.pnpm/typescript@5.0.4/node_modules/typescript/lib",
|
||||
"typescript.enablePromptUseWorkspaceTsdk": true
|
||||
}
|
||||
@@ -7,4 +7,7 @@ module.exports = {
|
||||
"@trigger.dev/github",
|
||||
"@trigger.dev/internal",
|
||||
],
|
||||
experimental: {
|
||||
appDir: true,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
"dependencies": {
|
||||
"@trigger.dev/sdk": "workspace:*",
|
||||
"@trigger.dev/github": "workspace:*",
|
||||
"@trigger.dev/nextjs": "workspace:*",
|
||||
"@types/node": "18.15.13",
|
||||
"@types/react": "^18.0.21",
|
||||
"@types/react-dom": "^18.0.6",
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
import { github, slack } from "@/trigger";
|
||||
import { events } from "@trigger.dev/github";
|
||||
import { makeAppHandler } from "@trigger.dev/nextjs";
|
||||
import { Job, TriggerClient } from "@trigger.dev/sdk";
|
||||
|
||||
export const client = new TriggerClient({
|
||||
id: "nextjs-appdir-example",
|
||||
url: process.env.VERCEL_URL,
|
||||
apiKey: process.env.TRIGGER_API_KEY,
|
||||
apiUrl: process.env.TRIGGER_API_URL,
|
||||
logLevel: "debug",
|
||||
});
|
||||
|
||||
new Job(client, {
|
||||
id: "appdir-alert-on-new-github-issues",
|
||||
name: "AppDir: Alert on new GitHub issues",
|
||||
version: "0.1.1",
|
||||
enabled: true,
|
||||
integrations: {
|
||||
slack,
|
||||
},
|
||||
trigger: github.triggers.repo({
|
||||
event: events.onIssueOpened,
|
||||
repo: "ericallam/basic-starter-12k",
|
||||
}),
|
||||
run: async (payload, io, ctx) => {
|
||||
await io.wait("wait", 5); // wait for 5 seconds
|
||||
|
||||
await io.logger.info("This is a simple log info message");
|
||||
|
||||
const response = await io.slack.postMessage("Slack 📝", {
|
||||
text: `New Issue opened: ${payload.issue.html_url}`,
|
||||
channel: "C04GWUTDC3W",
|
||||
});
|
||||
|
||||
return response;
|
||||
},
|
||||
});
|
||||
|
||||
export const { POST, dynamic } = makeAppHandler(client, {
|
||||
path: "/api/v2/trigger",
|
||||
});
|
||||
@@ -0,0 +1,20 @@
|
||||
import { Metadata } from "next";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Home",
|
||||
description: "Welcome to Next.js",
|
||||
};
|
||||
|
||||
export default function RootLayout({
|
||||
// Layouts must accept a children prop.
|
||||
// This will be populated with nested layouts or pages
|
||||
children,
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
}) {
|
||||
return (
|
||||
<html lang="en">
|
||||
<body>{children}</body>
|
||||
</html>
|
||||
);
|
||||
}
|
||||
@@ -1,475 +1,10 @@
|
||||
import {
|
||||
cronTrigger,
|
||||
eventTrigger,
|
||||
DynamicSchedule,
|
||||
DynamicTrigger,
|
||||
intervalTrigger,
|
||||
Job,
|
||||
missingConnectionNotification,
|
||||
missingConnectionResolvedNotification,
|
||||
NormalizedRequest,
|
||||
TriggerClient,
|
||||
} from "@trigger.dev/sdk";
|
||||
import { Github, events } from "@trigger.dev/github";
|
||||
import { Slack } from "@trigger.dev/slack";
|
||||
import type { NextApiRequest, NextApiResponse } from "next";
|
||||
import { z } from "zod";
|
||||
import { client } from "@/trigger";
|
||||
import { makeHandler } from "@trigger.dev/nextjs";
|
||||
|
||||
const github = new Github({ id: "github" });
|
||||
const githubUser = new Github({ id: "github-user" });
|
||||
export default makeHandler(client, { path: "/api/trigger" });
|
||||
|
||||
// const githubLocal = new Github({
|
||||
// id: "github-local",
|
||||
// token: process.env.GITHUB_TOKEN,
|
||||
// });
|
||||
|
||||
const slack = new Slack({ id: "my-slack-new" });
|
||||
|
||||
const client = new TriggerClient("nextjs", {
|
||||
apiKey: process.env.TRIGGER_API_KEY,
|
||||
apiUrl: "http://localhost:3000",
|
||||
endpoint: "http://localhost:3001/api/trigger",
|
||||
logLevel: "debug",
|
||||
});
|
||||
|
||||
const dynamicOnIssueOpenedTrigger = new DynamicTrigger(client, {
|
||||
id: "github-issue-opened",
|
||||
event: events.onIssueOpened,
|
||||
source: github.sources.repo,
|
||||
});
|
||||
|
||||
const dynamicUserTrigger = new DynamicTrigger(client, {
|
||||
id: "dynamic-user-trigger",
|
||||
event: events.onIssueOpened,
|
||||
source: githubUser.sources.repo,
|
||||
});
|
||||
|
||||
const dynamicSchedule = new DynamicSchedule(client, {
|
||||
id: "dynamic-interval",
|
||||
});
|
||||
|
||||
const enabled = true;
|
||||
|
||||
new Job(client, {
|
||||
id: "on-missing-auth-connection",
|
||||
name: "On missing auth connection",
|
||||
version: "0.1.1",
|
||||
enabled,
|
||||
trigger: missingConnectionNotification([githubUser]),
|
||||
integrations: {
|
||||
slack,
|
||||
export const config = {
|
||||
api: {
|
||||
bodyParser: false,
|
||||
},
|
||||
run: async (payload, io, ctx) => {
|
||||
switch (payload.type) {
|
||||
case "DEVELOPER": {
|
||||
return await io.slack.postMessage("message", {
|
||||
text: `Missing developer connection: ${JSON.stringify(payload)}`,
|
||||
channel: "C04GWUTDC3W",
|
||||
});
|
||||
}
|
||||
case "EXTERNAL": {
|
||||
return await io.slack.postMessage("message", {
|
||||
text: `Missing external connection: account: ${JSON.stringify(
|
||||
payload.account
|
||||
)}, payload: ${JSON.stringify(payload)}`,
|
||||
channel: "C04GWUTDC3W",
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
new Job(client, {
|
||||
id: "on-missing-auth-connection-resolved",
|
||||
name: "On missing auth connection-resolved",
|
||||
version: "0.1.1",
|
||||
enabled,
|
||||
trigger: missingConnectionResolvedNotification([githubUser]),
|
||||
integrations: {
|
||||
slack,
|
||||
},
|
||||
run: async (payload, io, ctx) => {
|
||||
switch (payload.type) {
|
||||
case "DEVELOPER": {
|
||||
return await io.slack.postMessage("message", {
|
||||
text: `Missing developer connection resolved: ${JSON.stringify(
|
||||
payload
|
||||
)}`,
|
||||
channel: "C04GWUTDC3W",
|
||||
});
|
||||
}
|
||||
case "EXTERNAL": {
|
||||
return await io.slack.postMessage("message", {
|
||||
text: `Missing external connection resolved: ${JSON.stringify(
|
||||
payload
|
||||
)}`,
|
||||
channel: "C04GWUTDC3W",
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
new Job(client, {
|
||||
id: "user-on-issue-opened",
|
||||
name: "user on issue opened",
|
||||
version: "0.1.1",
|
||||
enabled,
|
||||
trigger: dynamicUserTrigger,
|
||||
integrations: {
|
||||
github: githubUser,
|
||||
},
|
||||
run: async (payload, io, ctx) => {
|
||||
return await io.github.getRepo("get.repo", {
|
||||
repo: payload.repository.full_name,
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
new Job(client, {
|
||||
id: "get-user-repo",
|
||||
name: "Get User Repo",
|
||||
version: "0.1.1",
|
||||
enabled,
|
||||
trigger: eventTrigger({
|
||||
name: "get.repo",
|
||||
schema: z.object({
|
||||
repo: z.string(),
|
||||
}),
|
||||
}),
|
||||
integrations: {
|
||||
github: githubUser,
|
||||
},
|
||||
run: async (payload, io, ctx) => {
|
||||
await io.logger.info("This is a log info message", {
|
||||
payload,
|
||||
});
|
||||
|
||||
await io.wait("wait", 1);
|
||||
|
||||
return await io.github.getRepo("get.repo", payload);
|
||||
},
|
||||
});
|
||||
|
||||
new Job(client, {
|
||||
id: "get-user-repo-on-schedule",
|
||||
name: "Get User Repo On Schedule",
|
||||
version: "0.1.1",
|
||||
enabled,
|
||||
trigger: dynamicSchedule,
|
||||
integrations: {
|
||||
github: githubUser,
|
||||
},
|
||||
run: async (payload, io, ctx) => {
|
||||
return await io.github.getRepo("get.repo", {
|
||||
repo: ctx.event.context.source.metadata.repo,
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
new Job(client, {
|
||||
id: "register-dynamic-interval",
|
||||
name: "Register Dynamic Interval",
|
||||
version: "0.1.1",
|
||||
enabled,
|
||||
trigger: eventTrigger({
|
||||
name: "dynamic.interval",
|
||||
schema: z.object({
|
||||
id: z.string(),
|
||||
seconds: z.number().int().positive(),
|
||||
}),
|
||||
}),
|
||||
run: async (payload, io, ctx) => {
|
||||
await io.registerInterval("📆", dynamicSchedule, payload.id, {
|
||||
seconds: payload.seconds,
|
||||
});
|
||||
|
||||
await io.wait("wait", 60);
|
||||
|
||||
await io.unregisterInterval("❌📆", dynamicSchedule, payload.id);
|
||||
},
|
||||
});
|
||||
|
||||
new Job(client, {
|
||||
id: "register-dynamic-cron",
|
||||
name: "Register Dynamic Cron",
|
||||
version: "0.1.1",
|
||||
enabled,
|
||||
trigger: eventTrigger({
|
||||
name: "dynamic.cron",
|
||||
schema: z.object({
|
||||
id: z.string(),
|
||||
cron: z.string(),
|
||||
}),
|
||||
}),
|
||||
run: async (payload, io, ctx) => {
|
||||
await io.registerCron("📆", dynamicSchedule, payload.id, {
|
||||
cron: payload.cron,
|
||||
});
|
||||
|
||||
await io.wait("wait", 60);
|
||||
|
||||
await io.unregisterCron("❌📆", dynamicSchedule, payload.id);
|
||||
},
|
||||
});
|
||||
|
||||
new Job(client, {
|
||||
id: "use-dynamic-interval",
|
||||
name: "Use Dynamic Interval",
|
||||
version: "0.1.1",
|
||||
enabled,
|
||||
trigger: dynamicSchedule,
|
||||
run: async (payload, io, ctx) => {
|
||||
await io.wait("wait", 5); // wait for 5 seconds
|
||||
await io.logger.info("This is a log info message", {
|
||||
payload,
|
||||
});
|
||||
await io.sendEvent("send-event", {
|
||||
name: "custom.event",
|
||||
payload,
|
||||
context: ctx,
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
new Job(client, {
|
||||
id: "scheduled-job-1",
|
||||
name: "Scheduled Job 1",
|
||||
version: "0.1.1",
|
||||
enabled: true,
|
||||
trigger: intervalTrigger({
|
||||
seconds: 60,
|
||||
}),
|
||||
run: async (payload, io, ctx) => {
|
||||
await io.wait("wait", 5); // wait for 5 seconds
|
||||
await io.logger.info("This is a log info message", {
|
||||
payload,
|
||||
});
|
||||
await io.sendEvent("send-event", {
|
||||
name: "custom.event",
|
||||
payload,
|
||||
context: ctx,
|
||||
});
|
||||
|
||||
await io.runTask(
|
||||
"level 1",
|
||||
{
|
||||
name: "Level 1",
|
||||
},
|
||||
async () => {
|
||||
await io.runTask(
|
||||
"level 2",
|
||||
{
|
||||
name: "Level 2",
|
||||
},
|
||||
async () => {
|
||||
await io.runTask(
|
||||
"level 3",
|
||||
{
|
||||
name: "Level 3",
|
||||
},
|
||||
async () => {
|
||||
await io.runTask(
|
||||
"level 4",
|
||||
{
|
||||
name: "Level 4",
|
||||
},
|
||||
async () => {
|
||||
await io.runTask(
|
||||
"level 5",
|
||||
{
|
||||
name: "Level 5",
|
||||
},
|
||||
async () => {}
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
new Job(client, {
|
||||
id: "scheduled-job-2",
|
||||
name: "Scheduled Job 2",
|
||||
version: "0.1.1",
|
||||
enabled,
|
||||
trigger: cronTrigger({
|
||||
cron: "*/5 * * * *", // every 5 minutes
|
||||
}),
|
||||
run: async (payload, io, ctx) => {
|
||||
await io.wait("wait", 5); // wait for 5 seconds
|
||||
await io.logger.info("This is a log info message", {
|
||||
payload,
|
||||
ctx,
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
new Job(client, {
|
||||
id: "test-io-functions",
|
||||
name: "Test IO functions",
|
||||
version: "0.1.1",
|
||||
enabled,
|
||||
trigger: eventTrigger({
|
||||
name: "test.io",
|
||||
}),
|
||||
run: async (payload, io, ctx) => {
|
||||
await io.wait("wait", 5); // wait for 5 seconds
|
||||
await io.logger.info("This is a log info message", {
|
||||
payload,
|
||||
});
|
||||
await io.sendEvent("send-event", {
|
||||
name: "custom.event",
|
||||
payload,
|
||||
context: ctx,
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
new Job(client, {
|
||||
id: "register-dynamic-trigger-on-new-repo",
|
||||
name: "Register dynamic trigger on new repo",
|
||||
version: "0.1.1",
|
||||
enabled,
|
||||
trigger: eventTrigger({
|
||||
name: "new.repo",
|
||||
schema: z.object({ repo: z.string() }),
|
||||
}),
|
||||
run: async (payload, io, ctx) => {
|
||||
return await io.registerTrigger(
|
||||
"register-repo",
|
||||
dynamicOnIssueOpenedTrigger,
|
||||
payload.repo,
|
||||
{
|
||||
repo: payload.repo,
|
||||
}
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
new Job(client, {
|
||||
id: "listen-for-dynamic-trigger",
|
||||
name: "Listen for dynamic trigger",
|
||||
version: "0.1.1",
|
||||
enabled,
|
||||
trigger: dynamicOnIssueOpenedTrigger,
|
||||
integrations: {
|
||||
slack,
|
||||
},
|
||||
run: async (payload, io, ctx) => {
|
||||
await io.slack.postMessage("Slack 📝", {
|
||||
text: `New Issue opened on dynamically triggered repo: ${
|
||||
payload.issue.html_url
|
||||
}. \n\n${JSON.stringify(ctx)}`,
|
||||
channel: "C04GWUTDC3W",
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
new Job(client, {
|
||||
id: "listen-for-dynamic-trigger-2",
|
||||
name: "Listen for dynamic trigger-2",
|
||||
version: "0.1.1",
|
||||
enabled,
|
||||
trigger: dynamicOnIssueOpenedTrigger,
|
||||
integrations: {
|
||||
slack,
|
||||
},
|
||||
run: async (payload, io, ctx) => {
|
||||
await io.slack.postMessage("Slack 📝", {
|
||||
text: `New Issue opened on dynamically triggered repo 2: ${payload.issue.html_url}`,
|
||||
channel: "C04GWUTDC3W",
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
new Job(client, {
|
||||
id: "listen-for-dynamic-trigger-3",
|
||||
name: "Listen for dynamic trigger-3",
|
||||
version: "0.1.1",
|
||||
enabled,
|
||||
trigger: dynamicOnIssueOpenedTrigger,
|
||||
integrations: {
|
||||
slack,
|
||||
},
|
||||
run: async (payload, io, ctx) => {
|
||||
await io.slack.postMessage("Slack 📝", {
|
||||
text: `New Issue opened on dynamically triggered repo 3: ${payload.issue.html_url}`,
|
||||
channel: "C04GWUTDC3W",
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
new Job(client, {
|
||||
id: "alert-on-new-github-issues-6",
|
||||
name: "Alert on new GitHub issues",
|
||||
version: "0.1.1",
|
||||
enabled,
|
||||
integrations: {
|
||||
slack,
|
||||
},
|
||||
trigger: github.triggers.repo({
|
||||
event: events.onIssueOpened,
|
||||
repo: "ericallam/basic-starter-render-test",
|
||||
}),
|
||||
run: async (payload, io, ctx) => {
|
||||
await io.wait("wait", 5); // wait for 5 seconds
|
||||
|
||||
await io.logger.info("This is a simple log info message");
|
||||
|
||||
const response = await io.slack.postMessage("Slack 📝", {
|
||||
text: `New Issue opened: ${payload.issue.html_url}`,
|
||||
channel: "C04GWUTDC3W",
|
||||
});
|
||||
|
||||
return response;
|
||||
},
|
||||
});
|
||||
|
||||
export default async function handler(
|
||||
req: NextApiRequest,
|
||||
res: NextApiResponse
|
||||
) {
|
||||
const normalizedRequest = normalizeRequest(req);
|
||||
|
||||
const response = await client.handleRequest(normalizedRequest);
|
||||
|
||||
if (!response) {
|
||||
res.status(404).json({ error: "Not found" });
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
res.status(response.status).json(response.body);
|
||||
}
|
||||
|
||||
function normalizeRequest(req: NextApiRequest): NormalizedRequest {
|
||||
const normalizedHeaders = Object.entries(req.headers).reduce(
|
||||
(acc, [key, value]) => {
|
||||
acc[key] = value as string;
|
||||
return acc;
|
||||
},
|
||||
{} as Record<string, string>
|
||||
);
|
||||
|
||||
const normalizedQuery = Object.entries(req.query).reduce(
|
||||
(acc, [key, value]) => {
|
||||
acc[key] = value as string;
|
||||
return acc;
|
||||
},
|
||||
{} as Record<string, string>
|
||||
);
|
||||
|
||||
return {
|
||||
body: req.body,
|
||||
headers: normalizedHeaders,
|
||||
method: req.method ?? "GET",
|
||||
query: normalizedQuery,
|
||||
url: req.url ?? "/",
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
@@ -0,0 +1,431 @@
|
||||
import { Github, events } from "@trigger.dev/github";
|
||||
import {
|
||||
DynamicSchedule,
|
||||
DynamicTrigger,
|
||||
Job,
|
||||
TriggerClient,
|
||||
cronTrigger,
|
||||
eventTrigger,
|
||||
intervalTrigger,
|
||||
missingConnectionNotification,
|
||||
missingConnectionResolvedNotification,
|
||||
} from "@trigger.dev/sdk";
|
||||
import { Slack } from "@trigger.dev/slack";
|
||||
import { z } from "zod";
|
||||
|
||||
export const client = new TriggerClient({
|
||||
id: "nextjs-example",
|
||||
url: process.env.VERCEL_URL,
|
||||
apiKey: process.env.TRIGGER_API_KEY,
|
||||
apiUrl: process.env.TRIGGER_API_URL,
|
||||
logLevel: "debug",
|
||||
});
|
||||
|
||||
export const github = new Github({ id: "github" });
|
||||
const githubUser = new Github({ id: "github-user" });
|
||||
|
||||
// const githubLocal = new Github({
|
||||
// id: "github-local",
|
||||
// token: process.env.GITHUB_TOKEN,
|
||||
// });
|
||||
|
||||
export const slack = new Slack({ id: "my-slack-new" });
|
||||
|
||||
const dynamicOnIssueOpenedTrigger = new DynamicTrigger(client, {
|
||||
id: "github-issue-opened",
|
||||
event: events.onIssueOpened,
|
||||
source: github.sources.repo,
|
||||
});
|
||||
|
||||
const dynamicUserTrigger = new DynamicTrigger(client, {
|
||||
id: "dynamic-user-trigger",
|
||||
event: events.onIssueOpened,
|
||||
source: githubUser.sources.repo,
|
||||
});
|
||||
|
||||
const dynamicSchedule = new DynamicSchedule(client, {
|
||||
id: "dynamic-interval",
|
||||
});
|
||||
|
||||
const enabled = true;
|
||||
|
||||
new Job(client, {
|
||||
id: "on-missing-auth-connection",
|
||||
name: "On missing auth connection",
|
||||
version: "0.1.1",
|
||||
enabled,
|
||||
trigger: missingConnectionNotification([githubUser]),
|
||||
integrations: {
|
||||
slack,
|
||||
},
|
||||
run: async (payload, io, ctx) => {
|
||||
switch (payload.type) {
|
||||
case "DEVELOPER": {
|
||||
return await io.slack.postMessage("message", {
|
||||
text: `Missing developer connection: ${JSON.stringify(payload)}`,
|
||||
channel: "C04GWUTDC3W",
|
||||
});
|
||||
}
|
||||
case "EXTERNAL": {
|
||||
return await io.slack.postMessage("message", {
|
||||
text: `Missing external connection: account: ${JSON.stringify(
|
||||
payload.account
|
||||
)}, payload: ${JSON.stringify(payload)}`,
|
||||
channel: "C04GWUTDC3W",
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
new Job(client, {
|
||||
id: "on-missing-auth-connection-resolved",
|
||||
name: "On missing auth connection-resolved",
|
||||
version: "0.1.1",
|
||||
enabled,
|
||||
trigger: missingConnectionResolvedNotification([githubUser]),
|
||||
integrations: {
|
||||
slack,
|
||||
},
|
||||
run: async (payload, io, ctx) => {
|
||||
switch (payload.type) {
|
||||
case "DEVELOPER": {
|
||||
return await io.slack.postMessage("message", {
|
||||
text: `Missing developer connection resolved: ${JSON.stringify(
|
||||
payload
|
||||
)}`,
|
||||
channel: "C04GWUTDC3W",
|
||||
});
|
||||
}
|
||||
case "EXTERNAL": {
|
||||
return await io.slack.postMessage("message", {
|
||||
text: `Missing external connection resolved: ${JSON.stringify(
|
||||
payload
|
||||
)}`,
|
||||
channel: "C04GWUTDC3W",
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
new Job(client, {
|
||||
id: "user-on-issue-opened",
|
||||
name: "user on issue opened",
|
||||
version: "0.1.1",
|
||||
enabled,
|
||||
trigger: dynamicUserTrigger,
|
||||
integrations: {
|
||||
github: githubUser,
|
||||
},
|
||||
run: async (payload, io, ctx) => {
|
||||
return await io.github.getRepo("get.repo", {
|
||||
repo: payload.repository.full_name,
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
new Job(client, {
|
||||
id: "get-user-repo",
|
||||
name: "Get User Repo",
|
||||
version: "0.1.1",
|
||||
enabled,
|
||||
trigger: eventTrigger({
|
||||
name: "get.repo",
|
||||
schema: z.object({
|
||||
repo: z.string(),
|
||||
}),
|
||||
}),
|
||||
integrations: {
|
||||
github: githubUser,
|
||||
},
|
||||
run: async (payload, io, ctx) => {
|
||||
await io.logger.info("This is a log info message", {
|
||||
payload,
|
||||
});
|
||||
|
||||
await io.wait("wait", 1);
|
||||
|
||||
return await io.github.getRepo("get.repo", payload);
|
||||
},
|
||||
});
|
||||
|
||||
new Job(client, {
|
||||
id: "get-user-repo-on-schedule",
|
||||
name: "Get User Repo On Schedule",
|
||||
version: "0.1.1",
|
||||
enabled,
|
||||
trigger: dynamicSchedule,
|
||||
integrations: {
|
||||
github: githubUser,
|
||||
},
|
||||
run: async (payload, io, ctx) => {
|
||||
return await io.github.getRepo("get.repo", {
|
||||
repo: ctx.event.context.source.metadata.repo,
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
new Job(client, {
|
||||
id: "register-dynamic-interval",
|
||||
name: "Register Dynamic Interval",
|
||||
version: "0.1.1",
|
||||
enabled,
|
||||
trigger: eventTrigger({
|
||||
name: "dynamic.interval",
|
||||
schema: z.object({
|
||||
id: z.string(),
|
||||
seconds: z.number().int().positive(),
|
||||
}),
|
||||
}),
|
||||
run: async (payload, io, ctx) => {
|
||||
await io.registerInterval("📆", dynamicSchedule, payload.id, {
|
||||
seconds: payload.seconds,
|
||||
});
|
||||
|
||||
await io.wait("wait", 60);
|
||||
|
||||
await io.unregisterInterval("❌📆", dynamicSchedule, payload.id);
|
||||
},
|
||||
});
|
||||
|
||||
new Job(client, {
|
||||
id: "register-dynamic-cron",
|
||||
name: "Register Dynamic Cron",
|
||||
version: "0.1.1",
|
||||
enabled,
|
||||
trigger: eventTrigger({
|
||||
name: "dynamic.cron",
|
||||
schema: z.object({
|
||||
id: z.string(),
|
||||
cron: z.string(),
|
||||
}),
|
||||
}),
|
||||
run: async (payload, io, ctx) => {
|
||||
await io.registerCron("📆", dynamicSchedule, payload.id, {
|
||||
cron: payload.cron,
|
||||
});
|
||||
|
||||
await io.wait("wait", 60);
|
||||
|
||||
await io.unregisterCron("❌📆", dynamicSchedule, payload.id);
|
||||
},
|
||||
});
|
||||
|
||||
new Job(client, {
|
||||
id: "use-dynamic-interval",
|
||||
name: "Use Dynamic Interval",
|
||||
version: "0.1.1",
|
||||
enabled,
|
||||
trigger: dynamicSchedule,
|
||||
run: async (payload, io, ctx) => {
|
||||
await io.wait("wait", 5); // wait for 5 seconds
|
||||
await io.logger.info("This is a log info message", {
|
||||
payload,
|
||||
});
|
||||
await io.sendEvent("send-event", {
|
||||
name: "custom.event",
|
||||
payload,
|
||||
context: ctx,
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
new Job(client, {
|
||||
id: "scheduled-job-1",
|
||||
name: "Scheduled Job 1",
|
||||
version: "0.1.1",
|
||||
enabled: true,
|
||||
trigger: intervalTrigger({
|
||||
seconds: 60,
|
||||
}),
|
||||
run: async (payload, io, ctx) => {
|
||||
await io.wait("wait", 5); // wait for 5 seconds
|
||||
await io.logger.info("This is a log info message", {
|
||||
payload,
|
||||
});
|
||||
await io.sendEvent("send-event", {
|
||||
name: "custom.event",
|
||||
payload,
|
||||
context: ctx,
|
||||
});
|
||||
|
||||
await io.runTask(
|
||||
"level 1",
|
||||
{
|
||||
name: "Level 1",
|
||||
},
|
||||
async () => {
|
||||
await io.runTask(
|
||||
"level 2",
|
||||
{
|
||||
name: "Level 2",
|
||||
},
|
||||
async () => {
|
||||
await io.runTask(
|
||||
"level 3",
|
||||
{
|
||||
name: "Level 3",
|
||||
},
|
||||
async () => {
|
||||
await io.runTask(
|
||||
"level 4",
|
||||
{
|
||||
name: "Level 4",
|
||||
},
|
||||
async () => {
|
||||
await io.runTask(
|
||||
"level 5",
|
||||
{
|
||||
name: "Level 5",
|
||||
},
|
||||
async () => {}
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
new Job(client, {
|
||||
id: "scheduled-job-2",
|
||||
name: "Scheduled Job 2",
|
||||
version: "0.1.1",
|
||||
enabled,
|
||||
trigger: cronTrigger({
|
||||
cron: "*/5 * * * *", // every 5 minutes
|
||||
}),
|
||||
run: async (payload, io, ctx) => {
|
||||
await io.wait("wait", 5); // wait for 5 seconds
|
||||
await io.logger.info("This is a log info message", {
|
||||
payload,
|
||||
ctx,
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
new Job(client, {
|
||||
id: "test-io-functions",
|
||||
name: "Test IO functions",
|
||||
version: "0.1.1",
|
||||
enabled,
|
||||
trigger: eventTrigger({
|
||||
name: "test.io",
|
||||
}),
|
||||
run: async (payload, io, ctx) => {
|
||||
await io.wait("wait", 5); // wait for 5 seconds
|
||||
await io.logger.info("This is a log info message", {
|
||||
payload,
|
||||
});
|
||||
await io.sendEvent("send-event", {
|
||||
name: "custom.event",
|
||||
payload,
|
||||
context: ctx,
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
new Job(client, {
|
||||
id: "register-dynamic-trigger-on-new-repo",
|
||||
name: "Register dynamic trigger on new repo",
|
||||
version: "0.1.1",
|
||||
enabled,
|
||||
trigger: eventTrigger({
|
||||
name: "new.repo",
|
||||
schema: z.object({ repo: z.string() }),
|
||||
}),
|
||||
run: async (payload, io, ctx) => {
|
||||
return await io.registerTrigger(
|
||||
"register-repo",
|
||||
dynamicOnIssueOpenedTrigger,
|
||||
payload.repo,
|
||||
{
|
||||
repo: payload.repo,
|
||||
}
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
new Job(client, {
|
||||
id: "listen-for-dynamic-trigger",
|
||||
name: "Listen for dynamic trigger",
|
||||
version: "0.1.1",
|
||||
enabled,
|
||||
trigger: dynamicOnIssueOpenedTrigger,
|
||||
integrations: {
|
||||
slack,
|
||||
},
|
||||
run: async (payload, io, ctx) => {
|
||||
await io.slack.postMessage("Slack 📝", {
|
||||
text: `New Issue opened on dynamically triggered repo: ${
|
||||
payload.issue.html_url
|
||||
}. \n\n${JSON.stringify(ctx)}`,
|
||||
channel: "C04GWUTDC3W",
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
new Job(client, {
|
||||
id: "listen-for-dynamic-trigger-2",
|
||||
name: "Listen for dynamic trigger-2",
|
||||
version: "0.1.1",
|
||||
enabled,
|
||||
trigger: dynamicOnIssueOpenedTrigger,
|
||||
integrations: {
|
||||
slack,
|
||||
},
|
||||
run: async (payload, io, ctx) => {
|
||||
await io.slack.postMessage("Slack 📝", {
|
||||
text: `New Issue opened on dynamically triggered repo 2: ${payload.issue.html_url}`,
|
||||
channel: "C04GWUTDC3W",
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
new Job(client, {
|
||||
id: "listen-for-dynamic-trigger-3",
|
||||
name: "Listen for dynamic trigger-3",
|
||||
version: "0.1.1",
|
||||
enabled,
|
||||
trigger: dynamicOnIssueOpenedTrigger,
|
||||
integrations: {
|
||||
slack,
|
||||
},
|
||||
run: async (payload, io, ctx) => {
|
||||
await io.slack.postMessage("Slack 📝", {
|
||||
text: `New Issue opened on dynamically triggered repo 3: ${payload.issue.html_url}`,
|
||||
channel: "C04GWUTDC3W",
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
new Job(client, {
|
||||
id: "alert-on-new-github-issues-3",
|
||||
name: "Alert on new GitHub issues",
|
||||
version: "0.1.1",
|
||||
enabled,
|
||||
integrations: {
|
||||
slack,
|
||||
},
|
||||
trigger: github.triggers.repo({
|
||||
event: events.onIssueOpened,
|
||||
repo: "ericallam/basic-starter-12k",
|
||||
}),
|
||||
run: async (payload, io, ctx) => {
|
||||
await io.wait("wait", 5); // wait for 5 seconds
|
||||
|
||||
await io.logger.info("This is a simple log info message");
|
||||
|
||||
const response = await io.slack.postMessage("Slack 📝", {
|
||||
text: `New Issue opened: ${payload.issue.html_url}`,
|
||||
channel: "C04GWUTDC3W",
|
||||
});
|
||||
|
||||
return response;
|
||||
},
|
||||
});
|
||||
@@ -1,7 +1,11 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "es5",
|
||||
"lib": ["dom", "dom.iterable", "esnext"],
|
||||
"lib": [
|
||||
"dom",
|
||||
"dom.iterable",
|
||||
"esnext"
|
||||
],
|
||||
"allowJs": true,
|
||||
"skipLibCheck": true,
|
||||
"strict": true,
|
||||
@@ -15,17 +19,53 @@
|
||||
"jsx": "preserve",
|
||||
"incremental": true,
|
||||
"paths": {
|
||||
"@/*": ["./src/*"],
|
||||
"@trigger.dev/sdk": ["../../packages/trigger-sdk/src/index"],
|
||||
"@trigger.dev/sdk/*": ["../../packages/trigger-sdk/src/*"],
|
||||
"@trigger.dev/internal": ["../../packages/internal/src/index"],
|
||||
"@trigger.dev/internal/*": ["../../packages/internal/src/*"],
|
||||
"@trigger.dev/github": ["../../integrations/github/src/index"],
|
||||
"@trigger.dev/github/*": ["../../integrations/github/src/*"],
|
||||
"@trigger.dev/slack": ["../../integrations/slack/src/index"],
|
||||
"@trigger.dev/slack/*": ["../../integrations/slack/src/*"]
|
||||
}
|
||||
"@/*": [
|
||||
"./src/*"
|
||||
],
|
||||
"@trigger.dev/sdk": [
|
||||
"../../packages/trigger-sdk/src/index"
|
||||
],
|
||||
"@trigger.dev/sdk/*": [
|
||||
"../../packages/trigger-sdk/src/*"
|
||||
],
|
||||
"@trigger.dev/nextjs": [
|
||||
"../../packages/nextjs/src/index"
|
||||
],
|
||||
"@trigger.dev/nextjs/*": [
|
||||
"../../packages/nextjs/src/*"
|
||||
],
|
||||
"@trigger.dev/internal": [
|
||||
"../../packages/internal/src/index"
|
||||
],
|
||||
"@trigger.dev/internal/*": [
|
||||
"../../packages/internal/src/*"
|
||||
],
|
||||
"@trigger.dev/github": [
|
||||
"../../integrations/github/src/index"
|
||||
],
|
||||
"@trigger.dev/github/*": [
|
||||
"../../integrations/github/src/*"
|
||||
],
|
||||
"@trigger.dev/slack": [
|
||||
"../../integrations/slack/src/index"
|
||||
],
|
||||
"@trigger.dev/slack/*": [
|
||||
"../../integrations/slack/src/*"
|
||||
]
|
||||
},
|
||||
"plugins": [
|
||||
{
|
||||
"name": "next"
|
||||
}
|
||||
]
|
||||
},
|
||||
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
|
||||
"exclude": ["node_modules"]
|
||||
"include": [
|
||||
"next-env.d.ts",
|
||||
"**/*.ts",
|
||||
"**/*.tsx",
|
||||
".next/types/**/*.ts"
|
||||
],
|
||||
"exclude": [
|
||||
"node_modules"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -3,7 +3,9 @@ import {
|
||||
IntegrationClient,
|
||||
ExternalSource,
|
||||
TriggerIntegration,
|
||||
HandlerEvent,
|
||||
} from "@trigger.dev/sdk";
|
||||
import type { Logger } from "@trigger.dev/sdk";
|
||||
import { Octokit } from "octokit";
|
||||
import { z } from "zod";
|
||||
import { tasks } from "./tasks";
|
||||
@@ -47,82 +49,7 @@ export function createRepoEventSource(
|
||||
full_name: [params.repo],
|
||||
},
|
||||
}),
|
||||
handler: async (event, logger) => {
|
||||
logger.debug("[inside github integration] Handling github repo event");
|
||||
|
||||
const { rawEvent: request, source } = event;
|
||||
|
||||
if (!request.rawBody) {
|
||||
logger.debug("[inside github integration] No rawBody found");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const deliveryId = request.headers["x-github-delivery"];
|
||||
const hookId = request.headers["x-github-hook-id"];
|
||||
const signature = request.headers["x-hub-signature-256"];
|
||||
|
||||
if (source.secret && signature) {
|
||||
const githubWebhooks = new Webhooks({
|
||||
secret: source.secret,
|
||||
});
|
||||
|
||||
if (!githubWebhooks.verify(request.rawBody, signature)) {
|
||||
logger.debug(
|
||||
"[inside github integration] Unable to verify the signature of the rawBody",
|
||||
{
|
||||
signature,
|
||||
secret: source.secret,
|
||||
}
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const name = request.headers["x-github-event"];
|
||||
|
||||
const context = omit(request.headers, [
|
||||
"x-github-event",
|
||||
"x-github-delivery",
|
||||
"x-hub-signature-256",
|
||||
"x-hub-signature",
|
||||
"content-type",
|
||||
"content-length",
|
||||
"accept",
|
||||
"accept-encoding",
|
||||
"x-forwarded-proto",
|
||||
]);
|
||||
|
||||
const payload = parseBody(request.rawBody);
|
||||
|
||||
if (!payload) {
|
||||
logger.debug("[inside github integration] Unable to parse the rawBody");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
logger.debug(
|
||||
"[inside github integration] Returning an event for the webhook!",
|
||||
{
|
||||
name,
|
||||
payload,
|
||||
context,
|
||||
}
|
||||
);
|
||||
|
||||
return {
|
||||
events: [
|
||||
{
|
||||
id: [hookId, deliveryId].join(":"),
|
||||
source: "github.com",
|
||||
payload,
|
||||
name,
|
||||
context,
|
||||
},
|
||||
],
|
||||
};
|
||||
},
|
||||
handler: webhookHandler,
|
||||
register: async (event, io, ctx) => {
|
||||
const { params, source: httpSource, events, missingEvents } = event;
|
||||
|
||||
@@ -209,7 +136,7 @@ export function createOrgEventSource(
|
||||
login: [params.org],
|
||||
},
|
||||
}),
|
||||
handler: async (event) => {},
|
||||
handler: webhookHandler,
|
||||
register: async (event, io, ctx) => {
|
||||
const { params, source: httpSource, events, missingEvents } = event;
|
||||
|
||||
@@ -316,3 +243,83 @@ function omit<T extends Record<string, unknown>, K extends keyof T>(
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
async function webhookHandler(event: HandlerEvent<"HTTP">, logger: Logger) {
|
||||
logger.debug("[inside github integration] Handling github repo event");
|
||||
|
||||
const { rawEvent: request, source } = event;
|
||||
|
||||
if (!request.body) {
|
||||
logger.debug("[inside github integration] No body found");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const rawBody = await request.text();
|
||||
|
||||
const deliveryId = request.headers.get("x-github-delivery");
|
||||
const hookId = request.headers.get("x-github-hook-id");
|
||||
const signature = request.headers.get("x-hub-signature-256");
|
||||
|
||||
if (source.secret && signature) {
|
||||
const githubWebhooks = new Webhooks({
|
||||
secret: source.secret,
|
||||
});
|
||||
|
||||
if (!githubWebhooks.verify(rawBody, signature)) {
|
||||
logger.debug(
|
||||
"[inside github integration] Unable to verify the signature of the rawBody",
|
||||
{
|
||||
signature,
|
||||
secret: source.secret,
|
||||
}
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const name = request.headers.get("x-github-event") ?? "unknown";
|
||||
const allHeaders = Object.fromEntries(request.headers.entries());
|
||||
|
||||
const context = omit(allHeaders, [
|
||||
"x-github-event",
|
||||
"x-github-delivery",
|
||||
"x-hub-signature-256",
|
||||
"x-hub-signature",
|
||||
"content-type",
|
||||
"content-length",
|
||||
"accept",
|
||||
"accept-encoding",
|
||||
"x-forwarded-proto",
|
||||
]);
|
||||
|
||||
const payload = parseBody(rawBody);
|
||||
|
||||
if (!payload) {
|
||||
logger.debug("[inside github integration] Unable to parse the rawBody");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
logger.debug(
|
||||
"[inside github integration] Returning an event for the webhook!",
|
||||
{
|
||||
name,
|
||||
payload,
|
||||
context,
|
||||
}
|
||||
);
|
||||
|
||||
return {
|
||||
events: [
|
||||
{
|
||||
id: [hookId, deliveryId].join(":"),
|
||||
source: "github.com",
|
||||
payload,
|
||||
name,
|
||||
context,
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
{
|
||||
"name": "@trigger.dev/nextjs",
|
||||
"version": "0.1.0",
|
||||
"description": "Trigger.dev Next.js integration",
|
||||
"main": "./dist/index.js",
|
||||
"types": "./dist/index.d.ts",
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"files": [
|
||||
"dist"
|
||||
],
|
||||
"exports": {
|
||||
".": {
|
||||
"import": "./dist/index.js",
|
||||
"require": "./dist/index.js"
|
||||
},
|
||||
"./package.json": "./package.json"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@trigger.dev/tsconfig": "workspace:*",
|
||||
"@types/debug": "^4.1.7",
|
||||
"@types/ws": "^8.5.3",
|
||||
"next": "13.3.1",
|
||||
"rimraf": "^3.0.2",
|
||||
"tsup": "^6.5.0",
|
||||
"tsx": "^3.12.1"
|
||||
},
|
||||
"scripts": {
|
||||
"clean": "rimraf dist",
|
||||
"build": "npm run clean && npm run build:tsup",
|
||||
"build:tsup": "tsup"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@trigger.dev/sdk": "workspace:^1.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"debug": "^4.3.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
import type { TriggerClient } from "@trigger.dev/sdk";
|
||||
import type { NextApiRequest, NextApiResponse } from "next";
|
||||
import { NextResponse } from "next/server";
|
||||
|
||||
export type TriggerHandlerOptions = {
|
||||
path: string;
|
||||
};
|
||||
|
||||
export function makeHandler(
|
||||
client: TriggerClient,
|
||||
options: TriggerHandlerOptions
|
||||
) {
|
||||
client.path = options.path;
|
||||
|
||||
return async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
const normalizedRequest = await convertToStandardRequest(client.url, req);
|
||||
|
||||
const response = await client.handleRequest(normalizedRequest);
|
||||
|
||||
if (!response) {
|
||||
res.status(404).json({ error: "Not found" });
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
res.status(response.status).json(response.body);
|
||||
};
|
||||
}
|
||||
|
||||
export function makeAppHandler(
|
||||
client: TriggerClient,
|
||||
options: TriggerHandlerOptions
|
||||
) {
|
||||
client.path = options.path;
|
||||
|
||||
const POST = async function handler(req: Request) {
|
||||
const response = await client.handleRequest(req);
|
||||
|
||||
if (!response) {
|
||||
return NextResponse.json({ error: "Not found" }, { status: 404 });
|
||||
}
|
||||
|
||||
return NextResponse.json(response.body, { status: response.status });
|
||||
};
|
||||
|
||||
return {
|
||||
POST,
|
||||
dynamic: "force-dynamic",
|
||||
runtime: "nodejs",
|
||||
preferredRegion: "auto",
|
||||
};
|
||||
}
|
||||
|
||||
async function convertToStandardRequest(
|
||||
url: string,
|
||||
nextReq: NextApiRequest
|
||||
): Promise<Request> {
|
||||
const { headers: nextHeaders, method } = nextReq;
|
||||
|
||||
const headers = new Headers();
|
||||
|
||||
Object.entries(nextHeaders).forEach(([key, value]) => {
|
||||
headers.set(key, value as string);
|
||||
});
|
||||
|
||||
// Create a new Request object
|
||||
const webReq = new Request(url, {
|
||||
headers,
|
||||
method,
|
||||
// @ts-ignore
|
||||
body: nextReq,
|
||||
});
|
||||
|
||||
return webReq;
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"extends": "@trigger.dev/tsconfig/node18.json",
|
||||
"include": ["./src/**/*.ts", "tsup.config.ts"],
|
||||
"compilerOptions": {
|
||||
"experimentalDecorators": true,
|
||||
"emitDecoratorMetadata": true,
|
||||
"declaration": false,
|
||||
"declarationMap": false,
|
||||
"lib": ["DOM", "DOM.Iterable"],
|
||||
"paths": {
|
||||
"@trigger.dev/sdk": ["../trigger-sdk/src/index"],
|
||||
"@trigger.dev/sdk/*": ["../trigger-sdk/src/*"]
|
||||
}
|
||||
},
|
||||
"exclude": ["node_modules"]
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
import { defineConfig } from "tsup";
|
||||
|
||||
export default defineConfig([
|
||||
{
|
||||
name: "main",
|
||||
entry: ["./src/index.ts"],
|
||||
outDir: "./dist",
|
||||
platform: "node",
|
||||
format: ["cjs"],
|
||||
legacyOutput: true,
|
||||
sourcemap: true,
|
||||
clean: true,
|
||||
bundle: true,
|
||||
splitting: false,
|
||||
dts: true,
|
||||
external: ["http", "https", "util", "events", "tty", "os", "timers"],
|
||||
esbuildPlugins: [],
|
||||
},
|
||||
]);
|
||||
@@ -158,7 +158,7 @@ export class IO {
|
||||
},
|
||||
async (task) => {
|
||||
return await this._apiClient.updateSource(
|
||||
this._triggerClient.name,
|
||||
this._triggerClient.id,
|
||||
options.key,
|
||||
options
|
||||
);
|
||||
|
||||
@@ -46,10 +46,10 @@ const registerSourceEvent: EventSpecification<RegisterSourceEvent> = {
|
||||
};
|
||||
|
||||
export type TriggerClientOptions = {
|
||||
id: string;
|
||||
url?: string;
|
||||
apiKey?: string;
|
||||
apiUrl?: string;
|
||||
endpoint?: string;
|
||||
path?: string;
|
||||
logLevel?: LogLevel;
|
||||
};
|
||||
|
||||
@@ -66,7 +66,7 @@ export class TriggerClient {
|
||||
string,
|
||||
(
|
||||
source: HandleTriggerSource,
|
||||
request: HttpSourceEvent
|
||||
request: Request
|
||||
) => Promise<{
|
||||
events: Array<SendEvent>;
|
||||
response?: NormalizedResponse;
|
||||
@@ -85,21 +85,32 @@ export class TriggerClient {
|
||||
|
||||
#client: ApiClient;
|
||||
#logger: Logger;
|
||||
name: string;
|
||||
endpoint: string;
|
||||
private _url: string;
|
||||
id: string;
|
||||
path?: string;
|
||||
|
||||
constructor(name: string, options: TriggerClientOptions) {
|
||||
this.name = name;
|
||||
this.endpoint = options.endpoint ?? buildEndpointUrl(options.path);
|
||||
constructor(options: TriggerClientOptions) {
|
||||
this.id = options.id;
|
||||
this._url = buildClientUrl(options.url);
|
||||
this.#options = options;
|
||||
this.#client = new ApiClient(this.#options);
|
||||
this.#logger = new Logger("trigger.dev", this.#options.logLevel);
|
||||
}
|
||||
|
||||
async handleRequest(request: NormalizedRequest): Promise<NormalizedResponse> {
|
||||
this.#logger.debug("handling request", { request });
|
||||
get url() {
|
||||
return `${this._url}${
|
||||
this.path ? `${this.path.startsWith("/") ? "" : "/"}${this.path}` : ""
|
||||
}`;
|
||||
}
|
||||
|
||||
const apiKey = request.headers["x-trigger-api-key"];
|
||||
async handleRequest(request: Request): Promise<NormalizedResponse> {
|
||||
this.#logger.debug("handling request", {
|
||||
url: request.url,
|
||||
headers: Object.fromEntries(request.headers.entries()),
|
||||
method: request.method,
|
||||
});
|
||||
|
||||
const apiKey = request.headers.get("x-trigger-api-key");
|
||||
|
||||
if (!this.authorized(apiKey)) {
|
||||
return {
|
||||
@@ -110,10 +121,28 @@ export class TriggerClient {
|
||||
};
|
||||
}
|
||||
|
||||
if (request.method === "GET") {
|
||||
const action = request.headers["x-trigger-action"];
|
||||
if (request.method !== "POST") {
|
||||
return {
|
||||
status: 405,
|
||||
body: {
|
||||
message: "Method not allowed",
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
if (action === "PING") {
|
||||
const action = request.headers.get("x-trigger-action");
|
||||
|
||||
if (!action) {
|
||||
return {
|
||||
status: 400,
|
||||
body: {
|
||||
message: "Missing x-trigger-action header",
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
switch (action) {
|
||||
case "PING": {
|
||||
return {
|
||||
status: 200,
|
||||
body: {
|
||||
@@ -121,10 +150,104 @@ export class TriggerClient {
|
||||
},
|
||||
};
|
||||
}
|
||||
case "GET_ENDPOINT_DATA": {
|
||||
// if the x-trigger-job-id header is set, we return the job with that id
|
||||
const jobId = request.headers.get("x-trigger-job-id");
|
||||
|
||||
// if the x-trigger-job-id header is set, we return the job with that id
|
||||
if (request.headers["x-trigger-job-id"]) {
|
||||
const job = this.#registeredJobs[request.headers["x-trigger-job-id"]];
|
||||
if (jobId) {
|
||||
const job = this.#registeredJobs[jobId];
|
||||
|
||||
if (!job) {
|
||||
return {
|
||||
status: 404,
|
||||
body: {
|
||||
message: "Job not found",
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
status: 200,
|
||||
body: job.toJSON(),
|
||||
};
|
||||
}
|
||||
|
||||
const body: GetEndpointDataResponse = {
|
||||
jobs: Object.values(this.#registeredJobs).map((job) => job.toJSON()),
|
||||
sources: Object.values(this.#registeredSources),
|
||||
dynamicTriggers: Object.values(this.#registeredDynamicTriggers).map(
|
||||
(trigger) => ({
|
||||
id: trigger.id,
|
||||
jobs: this.#jobMetadataByDynamicTriggers[trigger.id] ?? [],
|
||||
})
|
||||
),
|
||||
dynamicSchedules: Object.entries(this.#registeredSchedules).map(
|
||||
([id, jobs]) => ({
|
||||
id,
|
||||
jobs,
|
||||
})
|
||||
),
|
||||
};
|
||||
|
||||
// if the x-trigger-job-id header is not set, we return all jobs
|
||||
return {
|
||||
status: 200,
|
||||
body,
|
||||
};
|
||||
}
|
||||
case "INITIALIZE": {
|
||||
await this.listen();
|
||||
|
||||
return {
|
||||
status: 200,
|
||||
body: {
|
||||
message: "Initialized",
|
||||
},
|
||||
};
|
||||
}
|
||||
case "INITIALIZE_TRIGGER": {
|
||||
const json = await request.json();
|
||||
const body = InitializeTriggerBodySchema.safeParse(json);
|
||||
|
||||
if (!body.success) {
|
||||
return {
|
||||
status: 400,
|
||||
body: {
|
||||
message: "Invalid trigger body",
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
const dynamicTrigger = this.#registeredDynamicTriggers[body.data.id];
|
||||
|
||||
if (!dynamicTrigger) {
|
||||
return {
|
||||
status: 404,
|
||||
body: {
|
||||
message: "Dynamic trigger not found",
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
status: 200,
|
||||
body: dynamicTrigger.registeredTriggerForParams(body.data.params),
|
||||
};
|
||||
}
|
||||
case "EXECUTE_JOB": {
|
||||
const json = await request.json();
|
||||
const execution = RunJobBodySchema.safeParse(json);
|
||||
|
||||
if (!execution.success) {
|
||||
return {
|
||||
status: 400,
|
||||
body: {
|
||||
message: "Invalid execution",
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
const job = this.#registeredJobs[execution.data.job.id];
|
||||
|
||||
if (!job) {
|
||||
return {
|
||||
@@ -135,202 +258,108 @@ export class TriggerClient {
|
||||
};
|
||||
}
|
||||
|
||||
const results = await this.#executeJob(execution.data, job);
|
||||
|
||||
if (results.error) {
|
||||
return {
|
||||
status: 500,
|
||||
body: results.error,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
status: 200,
|
||||
body: job.toJSON(),
|
||||
body: {
|
||||
completed: results.completed,
|
||||
output: results.output,
|
||||
executionId: execution.data.run.id,
|
||||
task: results.task,
|
||||
},
|
||||
};
|
||||
}
|
||||
case "PREPROCESS_RUN": {
|
||||
const json = await request.json();
|
||||
const body = PreprocessRunBodySchema.safeParse(json);
|
||||
|
||||
const body: GetEndpointDataResponse = {
|
||||
jobs: Object.values(this.#registeredJobs).map((job) => job.toJSON()),
|
||||
sources: Object.values(this.#registeredSources),
|
||||
dynamicTriggers: Object.values(this.#registeredDynamicTriggers).map(
|
||||
(trigger) => ({
|
||||
id: trigger.id,
|
||||
jobs: this.#jobMetadataByDynamicTriggers[trigger.id] ?? [],
|
||||
})
|
||||
),
|
||||
dynamicSchedules: Object.entries(this.#registeredSchedules).map(
|
||||
([id, jobs]) => ({
|
||||
id,
|
||||
jobs,
|
||||
})
|
||||
),
|
||||
};
|
||||
|
||||
// if the x-trigger-job-id header is not set, we return all jobs
|
||||
return {
|
||||
status: 200,
|
||||
body,
|
||||
};
|
||||
}
|
||||
|
||||
if (request.method === "POST") {
|
||||
// Get the action from the headers
|
||||
const action = request.headers["x-trigger-action"];
|
||||
|
||||
switch (action) {
|
||||
case "INITIALIZE": {
|
||||
await this.listen();
|
||||
|
||||
if (!body.success) {
|
||||
return {
|
||||
status: 200,
|
||||
status: 400,
|
||||
body: {
|
||||
message: "Initialized",
|
||||
message: "Invalid body",
|
||||
},
|
||||
};
|
||||
}
|
||||
case "INITIALIZE_TRIGGER": {
|
||||
const body = InitializeTriggerBodySchema.safeParse(request.body);
|
||||
|
||||
if (!body.success) {
|
||||
return {
|
||||
status: 400,
|
||||
body: {
|
||||
message: "Invalid trigger body",
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
const dynamicTrigger = this.#registeredDynamicTriggers[body.data.id];
|
||||
|
||||
if (!dynamicTrigger) {
|
||||
return {
|
||||
status: 404,
|
||||
body: {
|
||||
message: "Dynamic trigger not found",
|
||||
},
|
||||
};
|
||||
}
|
||||
const job = this.#registeredJobs[body.data.job.id];
|
||||
|
||||
if (!job) {
|
||||
return {
|
||||
status: 200,
|
||||
body: dynamicTrigger.registeredTriggerForParams(body.data.params),
|
||||
};
|
||||
}
|
||||
case "EXECUTE_JOB": {
|
||||
const execution = RunJobBodySchema.safeParse(request.body);
|
||||
|
||||
if (!execution.success) {
|
||||
return {
|
||||
status: 400,
|
||||
body: {
|
||||
message: "Invalid execution",
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
const job = this.#registeredJobs[execution.data.job.id];
|
||||
|
||||
if (!job) {
|
||||
return {
|
||||
status: 404,
|
||||
body: {
|
||||
message: "Job not found",
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
const results = await this.#executeJob(execution.data, job);
|
||||
|
||||
if (results.error) {
|
||||
return {
|
||||
status: 500,
|
||||
body: results.error,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
status: 200,
|
||||
status: 404,
|
||||
body: {
|
||||
completed: results.completed,
|
||||
output: results.output,
|
||||
executionId: execution.data.run.id,
|
||||
task: results.task,
|
||||
message: "Job not found",
|
||||
},
|
||||
};
|
||||
}
|
||||
case "PREPROCESS_RUN": {
|
||||
const body = PreprocessRunBodySchema.safeParse(request.body);
|
||||
|
||||
if (!body.success) {
|
||||
return {
|
||||
status: 400,
|
||||
body: {
|
||||
message: "Invalid body",
|
||||
},
|
||||
};
|
||||
}
|
||||
const results = await this.#preprocessRun(body.data, job);
|
||||
|
||||
const job = this.#registeredJobs[body.data.job.id];
|
||||
|
||||
if (!job) {
|
||||
return {
|
||||
status: 404,
|
||||
body: {
|
||||
message: "Job not found",
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
const results = await this.#preprocessRun(body.data, job);
|
||||
return {
|
||||
status: 200,
|
||||
body: {
|
||||
abort: results.abort,
|
||||
elements: results.elements,
|
||||
},
|
||||
};
|
||||
}
|
||||
case "DELIVER_HTTP_SOURCE_REQUEST": {
|
||||
const headers = HttpSourceRequestHeadersSchema.safeParse(
|
||||
Object.fromEntries(request.headers.entries())
|
||||
);
|
||||
|
||||
if (!headers.success) {
|
||||
return {
|
||||
status: 200,
|
||||
status: 400,
|
||||
body: {
|
||||
abort: results.abort,
|
||||
elements: results.elements,
|
||||
message: "Invalid headers",
|
||||
},
|
||||
};
|
||||
}
|
||||
case "DELIVER_HTTP_SOURCE_REQUEST": {
|
||||
const headers = HttpSourceRequestHeadersSchema.safeParse(
|
||||
request.headers
|
||||
);
|
||||
|
||||
if (!headers.success) {
|
||||
return {
|
||||
status: 400,
|
||||
body: {
|
||||
message: "Invalid headers",
|
||||
},
|
||||
};
|
||||
}
|
||||
const sourceRequest = new Request(headers.data["x-ts-http-url"], {
|
||||
method: headers.data["x-ts-http-method"],
|
||||
headers: headers.data["x-ts-http-headers"],
|
||||
body:
|
||||
headers.data["x-ts-http-method"] !== "GET"
|
||||
? request.body
|
||||
: undefined,
|
||||
});
|
||||
|
||||
const sourceRequest = {
|
||||
url: headers.data["x-ts-http-url"],
|
||||
method: headers.data["x-ts-http-method"],
|
||||
headers: headers.data["x-ts-http-headers"],
|
||||
rawBody: request.body,
|
||||
};
|
||||
const key = headers.data["x-ts-key"];
|
||||
const dynamicId = headers.data["x-ts-dynamic-id"];
|
||||
const secret = headers.data["x-ts-secret"];
|
||||
const params = headers.data["x-ts-params"];
|
||||
const data = headers.data["x-ts-data"];
|
||||
|
||||
const key = headers.data["x-ts-key"];
|
||||
const dynamicId = headers.data["x-ts-dynamic-id"];
|
||||
const secret = headers.data["x-ts-secret"];
|
||||
const params = headers.data["x-ts-params"];
|
||||
const data = headers.data["x-ts-data"];
|
||||
const source = {
|
||||
key,
|
||||
dynamicId,
|
||||
secret,
|
||||
params,
|
||||
data,
|
||||
};
|
||||
|
||||
const source = {
|
||||
key,
|
||||
dynamicId,
|
||||
secret,
|
||||
params,
|
||||
data,
|
||||
};
|
||||
const { response, events } = await this.#handleHttpSourceRequest(
|
||||
source,
|
||||
sourceRequest
|
||||
);
|
||||
|
||||
const { response, events } = await this.#handleHttpSourceRequest(
|
||||
source,
|
||||
sourceRequest
|
||||
);
|
||||
|
||||
return {
|
||||
status: 200,
|
||||
body: {
|
||||
events,
|
||||
response,
|
||||
},
|
||||
};
|
||||
}
|
||||
return {
|
||||
status: 200,
|
||||
body: {
|
||||
events,
|
||||
response,
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -478,11 +507,11 @@ export class TriggerClient {
|
||||
}
|
||||
|
||||
async registerTrigger(id: string, key: string, options: RegisterTriggerBody) {
|
||||
return this.#client.registerTrigger(this.name, id, key, options);
|
||||
return this.#client.registerTrigger(this.id, id, key, options);
|
||||
}
|
||||
|
||||
async getAuth(id: string) {
|
||||
return this.#client.getAuth(this.name, id);
|
||||
return this.#client.getAuth(this.id, id);
|
||||
}
|
||||
|
||||
async sendEvent(event: SendEvent, options?: SendEventOptions) {
|
||||
@@ -490,14 +519,14 @@ export class TriggerClient {
|
||||
}
|
||||
|
||||
async registerSchedule(id: string, key: string, schedule: ScheduleMetadata) {
|
||||
return this.#client.registerSchedule(this.name, id, key, schedule);
|
||||
return this.#client.registerSchedule(this.id, id, key, schedule);
|
||||
}
|
||||
|
||||
async unregisterSchedule(id: string, key: string) {
|
||||
return this.#client.unregisterSchedule(this.name, id, key);
|
||||
return this.#client.unregisterSchedule(this.id, id, key);
|
||||
}
|
||||
|
||||
authorized(apiKey: string) {
|
||||
authorized(apiKey?: string | null) {
|
||||
const localApiKey = this.#options.apiKey ?? process.env.TRIGGER_API_KEY;
|
||||
|
||||
if (!localApiKey) {
|
||||
@@ -514,8 +543,8 @@ export class TriggerClient {
|
||||
async listen() {
|
||||
// Register the endpoint
|
||||
await this.#client.registerEndpoint({
|
||||
url: this.endpoint,
|
||||
name: this.name,
|
||||
url: this.url,
|
||||
name: this.id,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -635,7 +664,7 @@ export class TriggerClient {
|
||||
data: any;
|
||||
params: any;
|
||||
},
|
||||
sourceRequest: HttpSourceRequest
|
||||
sourceRequest: Request
|
||||
): Promise<{ response: NormalizedResponse; events: SendEvent[] }> {
|
||||
this.#logger.debug("Handling HTTP source request", {
|
||||
source,
|
||||
@@ -733,30 +762,31 @@ export class TriggerClient {
|
||||
}
|
||||
}
|
||||
|
||||
function buildEndpointUrl(path?: string): string {
|
||||
// Try to get the endpoint from the environment
|
||||
const endpoint = process.env.TRIGGER_ENDPOINT;
|
||||
function buildClientUrl(url?: string): string {
|
||||
if (!url) {
|
||||
// Try and get the host from the environment
|
||||
const host =
|
||||
process.env.TRIGGER_CLIENT_HOST ??
|
||||
process.env.HOST ??
|
||||
process.env.HOSTNAME ??
|
||||
process.env.NOW_URL ??
|
||||
process.env.VERCEL_URL;
|
||||
|
||||
// If the endpoint is set, we return it + the path
|
||||
if (endpoint) {
|
||||
return endpoint + (path ?? "");
|
||||
// If the host is set, we return it + the path
|
||||
if (host) {
|
||||
return "https://" + host;
|
||||
}
|
||||
|
||||
// If we can't get the host, we throw an error
|
||||
throw new Error(
|
||||
"Could not determine the url for this TriggerClient. Please set the TRIGGER_CLIENT_HOST environment variable or pass in the `url` option to the TriggerClient constructor."
|
||||
);
|
||||
}
|
||||
|
||||
// Try and get the host from the environment
|
||||
const host =
|
||||
process.env.TRIGGER_HOST ??
|
||||
process.env.HOST ??
|
||||
process.env.HOSTNAME ??
|
||||
process.env.NOW_URL ??
|
||||
process.env.VERCEL_URL;
|
||||
|
||||
// If the host is set, we return it + the path
|
||||
if (host) {
|
||||
return "https://" + host + (path ?? "");
|
||||
// Check to see if url has the protocol, and if it doesn't, add it
|
||||
if (!url.startsWith("http")) {
|
||||
return "https://" + url;
|
||||
}
|
||||
|
||||
// If we can't get the host, we throw an error
|
||||
throw new Error(
|
||||
"Could not determine the endpoint for the trigger client. Please set the TRIGGER_ENDPOINT environment variable."
|
||||
);
|
||||
return url;
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ type SqsSourceEvent = {
|
||||
|
||||
type ExternalSourceChannelMap = {
|
||||
HTTP: {
|
||||
event: HttpSourceEvent;
|
||||
event: Request;
|
||||
register: {
|
||||
url: string;
|
||||
};
|
||||
@@ -85,11 +85,16 @@ type RegisterFunction<
|
||||
ctx: TriggerContext
|
||||
) => Promise<UpdateTriggerSourceBody | undefined>;
|
||||
|
||||
export type HandlerEvent<
|
||||
TChannel extends ChannelNames,
|
||||
TParams extends any = any
|
||||
> = {
|
||||
rawEvent: ExternalSourceChannelMap[TChannel]["event"];
|
||||
source: HandleTriggerSource & { params: TParams };
|
||||
};
|
||||
|
||||
type HandlerFunction<TChannel extends ChannelNames, TParams extends any> = (
|
||||
event: {
|
||||
rawEvent: ExternalSourceChannelMap[TChannel]["event"];
|
||||
source: HandleTriggerSource & { params: TParams };
|
||||
},
|
||||
event: HandlerEvent<TChannel, TParams>,
|
||||
logger: Logger
|
||||
) => Promise<{ events: SendEvent[]; response?: NormalizedResponse } | void>;
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import type {
|
||||
EventFilter,
|
||||
Logger,
|
||||
RuntimeEnvironmentType,
|
||||
SecureString,
|
||||
TriggerMetadata,
|
||||
@@ -8,7 +9,7 @@ import { DisplayElement } from "@trigger.dev/internal";
|
||||
import { Job } from "./job";
|
||||
import { TriggerClient } from "./triggerClient";
|
||||
|
||||
export type { SecureString };
|
||||
export type { SecureString, Logger };
|
||||
|
||||
export interface TriggerContext {
|
||||
job: { id: string; version: string };
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
"experimentalDecorators": true,
|
||||
"emitDecoratorMetadata": true,
|
||||
"paths": {
|
||||
"@trigger.dev/internal/*": ["../common-schemas/src/*"],
|
||||
"@trigger.dev/internal": ["../common-schemas/src/index"]
|
||||
"@trigger.dev/internal/*": ["../internal/src/*"],
|
||||
"@trigger.dev/internal": ["../internal/src/index"]
|
||||
},
|
||||
"lib": ["DOM", "DOM.Iterable"],
|
||||
"declaration": false,
|
||||
|
||||
Generated
+1257
-497
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user