Supabase database webhook example upgrade (#1386)

* Added overview for guides and examples section and split them all out

* New supabase guide wip

* Updated images and improved docs

* Trimmed the supabase prereqs

* Supabase guide wip

* more updates

* Replaced old database webhook guide

* Created one intro page and removed snippets

* Updated guide sidebar titles

* Code updates

* More improvements

* Updates and added images

* Compressed image

* Updated guides descriptions and edge function basic

* Removed bold

* Updated redirects

* Fixed broken links

* Updated intro
This commit is contained in:
Dan
2024-10-08 14:36:03 +01:00
committed by GitHub
parent 07f82eae54
commit fc609470c4
18 changed files with 526 additions and 366 deletions
-20
View File
@@ -1,20 +0,0 @@
---
title: "Introduction"
sidebarTitle: "Introduction"
description: "Get started with Trigger.dev in your favorite framework."
icon: "grid-2"
---
import CardBun from "/snippets/card-bun.mdx";
import CardNodejs from "/snippets/card-nodejs.mdx";
import CardNextjs from "/snippets/card-nextjs.mdx";
import CardRemix from "/snippets/card-remix.mdx";
import CardSupabase from "/snippets/card-supabase.mdx";
<CardGroup cols={3}>
<CardBun />
<CardNodejs />
<CardNextjs />
<CardRemix />
<CardSupabase />
</CardGroup>
+1 -1
View File
@@ -1,6 +1,6 @@
---
title: "Prisma setup guide"
sidebarTitle: "Prisma"
sidebarTitle: "Prisma setup guide"
description: "This guide will show you how to setup Prisma with Trigger.dev"
icon: "Triangle"
---
+114 -101
View File
@@ -1,6 +1,6 @@
---
title: "Sequin database triggers"
sidebarTitle: "Sequin"
sidebarTitle: "Sequin database triggers"
description: "This guide will show you how to trigger tasks from database changes using Sequin"
icon: "database"
---
@@ -22,9 +22,11 @@ As long as you create an HTTP endpoint that Sequin can deliver webhooks to, you
You'll need the following to follow this guide:
- A Next.js project with [Trigger.dev](https://trigger.dev) installed
<Info>
If you don't have one already, follow [Trigger.dev's Next.js setup guide](/guides/frameworks/nextjs) to setup your project. You can return to this guide when you're ready to write your first Trigger.dev task.
</Info>
<Info>
If you don't have one already, follow [Trigger.dev's Next.js setup
guide](/guides/frameworks/nextjs) to setup your project. You can return to this guide when
you're ready to write your first Trigger.dev task.
</Info>
- A [Sequin](https://console.sequinstream.com/register) account
- A Postgres database (Sequin works with any Postgres database version 12 and up) with a `posts` table.
@@ -42,36 +44,36 @@ Start by creating a new Trigger.dev task that takes in a Sequin change event as
import { OpenAI } from "openai";
import { upsertEmbedding } from "../util";
const openai = new OpenAI({
apiKey: process.env.OPENAI_API_KEY,
});
const openai = new OpenAI({
apiKey: process.env.OPENAI_API_KEY,
});
export const createEmbeddingForPost = task({
id: "create-embedding-for-post",
run: async (payload: {
record: {
id: number;
title: string;
body: string;
author: string;
createdAt: string;
embedding: string | null;
},
metadata: {
table_schema: string,
table_name: string,
consumer: {
id: string;
name: string;
};
};
}) => {
// Create an embedding using the title and body of payload.record
const content = `${payload.record.title}\n\n${payload.record.body}`;
const embedding = (await openai.embeddings.create({
model: "text-embedding-ada-002",
input: content,
})).data[0].embedding;
export const createEmbeddingForPost = task({
id: "create-embedding-for-post",
run: async (payload: {
record: {
id: number;
title: string;
body: string;
author: string;
createdAt: string;
embedding: string | null;
},
metadata: {
table_schema: string,
table_name: string,
consumer: {
id: string;
name: string;
};
};
}) => {
// Create an embedding using the title and body of payload.record
const content = `${payload.record.title}\n\n${payload.record.body}`;
const embedding = (await openai.embeddings.create({
model: "text-embedding-ada-002",
input: content,
})).data[0].embedding;
// Upsert the embedding in the database. See utils.ts for the implementation -> ->
await upsertEmbedding(embedding, payload.record.id);
@@ -82,51 +84,55 @@ Start by creating a new Trigger.dev task that takes in a Sequin change event as
embedding: JSON.stringify(embedding),
};
}
});
````
```ts utils.ts
import pg from "pg";
export async function upsertEmbedding(embedding: number[], id: number) {
const client = new pg.Client({
connectionString: process.env.DATABASE_URL,
});
```
await client.connect();
```ts utils.ts
import pg from "pg";
try {
const query = `
INSERT INTO post_embeddings (id, embedding)
VALUES ($2, $1)
ON CONFLICT (id)
DO UPDATE SET embedding = $1
`;
const values = [JSON.stringify(embedding), id];
export async function upsertEmbedding(embedding: number[], id: number) {
const client = new pg.Client({
connectionString: process.env.DATABASE_URL,
});
await client.connect();
const result = await client.query(query, values);
console.log(`Updated record in database. Rows affected: ${result.rowCount}`);
try {
const query = `
INSERT INTO post_embeddings (id, embedding)
VALUES ($2, $1)
ON CONFLICT (id)
DO UPDATE SET embedding = $1
`;
const values = [JSON.stringify(embedding), id];
const result = await client.query(query, values);
console.log(`Updated record in database. Rows affected: ${result.rowCount}`);
return result.rowCount;
} catch (error) {
console.error("Error updating record in database:", error);
throw error;
} finally {
await client.end();
}
return result.rowCount;
} catch (error) {
console.error("Error updating record in database:", error);
throw error;
} finally {
await client.end();
}
```
}
````
</CodeGroup>
This task takes in a Sequin record event, creates an embedding, and then upserts the embedding into a `post_embeddings` table.
This task takes in a Sequin record event, creates an embedding, and then upserts the embedding into a `post_embeddings` table.
</Step>
<Step title="Add the task to your Trigger.dev project">
Register the `create-embedding-for-post` task to your Trigger.dev cloud project by running the following command:
```bash
npx trigger.dev@latest dev
```
```bash
npx trigger.dev@latest dev
```
In the Trigger.dev dashboard, you should now see the `create-embedding-for-post` task:
In the Trigger.dev dashboard, you should now see the `create-embedding-for-post` task:
<Frame>
<img src="/images/sequin-register-task.png" alt="Task added" />
@@ -135,7 +141,8 @@ Start by creating a new Trigger.dev task that takes in a Sequin change event as
</Steps>
<Check>
You've successfully created a Trigger.dev task that will create an embedding for each post in your database. In the next step, you'll create an API endpoint that Sequin can deliver records to.
You've successfully created a Trigger.dev task that will create an embedding for each post in your
database. In the next step, you'll create an API endpoint that Sequin can deliver records to.
</Check>
## Setup API route
@@ -143,55 +150,60 @@ Start by creating a new Trigger.dev task that takes in a Sequin change event as
You'll now create an API endpoint that will receive posts from Sequin and then trigger the `create-embedding-for-post` task.
<Info>
This guide covers how to setup an API endpoint using the Next.js App Router. You can find examples for Next.js Server Actions and Pages Router in the [Trigger.dev documentation](https://trigger.dev/docs/guides/frameworks/nextjs).
This guide covers how to setup an API endpoint using the Next.js App Router. You can find examples
for Next.js Server Actions and Pages Router in the [Trigger.dev
documentation](https://trigger.dev/docs/guides/frameworks/nextjs).
</Info>
<Steps titleSize="h3">
<Step title="Create a route handler">
Add a route handler by creating a new `route.ts` file in a `/app/api/create-embedding-for-post` directory:
```ts app/api/create-embedding-for-post/route.ts
import type { createEmbeddingForPost } from "@/trigger/create-embedding-for-post";
import { tasks } from "@trigger.dev/sdk/v3";
import { NextResponse } from "next/server";
```ts app/api/create-embedding-for-post/route.ts
import type { createEmbeddingForPost } from "@/trigger/create-embedding-for-post";
import { tasks } from "@trigger.dev/sdk/v3";
import { NextResponse } from "next/server";
export async function POST(req: Request) {
const authHeader = req.headers.get('authorization');
if (!authHeader || authHeader !== `Bearer ${process.env.SEQUIN_WEBHOOK_SECRET}`) {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
}
const payload = await req.json();
const handle = await tasks.trigger<typeof createEmbeddingForPost>(
"create-embedding-for-post",
payload
);
return NextResponse.json(handle);
export async function POST(req: Request) {
const authHeader = req.headers.get("authorization");
if (!authHeader || authHeader !== `Bearer ${process.env.SEQUIN_WEBHOOK_SECRET}`) {
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
}
```
const payload = await req.json();
const handle = await tasks.trigger<typeof createEmbeddingForPost>(
"create-embedding-for-post",
payload
);
return NextResponse.json(handle);
}
```
This route handler will receive records from Sequin, parse them, and then trigger the `create-embedding-for-post` task.
This route handler will receive records from Sequin, parse them, and then trigger the `create-embedding-for-post` task.
</Step>
<Step title="Set secret keys">
You'll need to set four secret keys in a `.env.local` file:
```bash
SEQUIN_WEBHOOK_SECRET=your-secret-key
TRIGGER_SECRET_KEY=secret-from-trigger-dev
OPENAI_API_KEY=sk-proj-asdfasdfasdf
DATABASE_URL=postgresql://
```
```bash
SEQUIN_WEBHOOK_SECRET=your-secret-key
TRIGGER_SECRET_KEY=secret-from-trigger-dev
OPENAI_API_KEY=sk-proj-asdfasdfasdf
DATABASE_URL=postgresql://
```
The `SEQUIN_WEBHOOK_SECRET` ensures that only Sequin can access your API endpoint.
The `SEQUIN_WEBHOOK_SECRET` ensures that only Sequin can access your API endpoint.
The `TRIGGER_SECRET_KEY` is used to authenticate requests to Trigger.dev and can be found in the **API keys** tab of the Trigger.dev dashboard.
The `TRIGGER_SECRET_KEY` is used to authenticate requests to Trigger.dev and can be found in the **API keys** tab of the Trigger.dev dashboard.
The `OPENAI_API_KEY` and `DATABASE_URL` are used to create an embedding using OpenAI and connect to your database. Be sure to add these as [environment variables](https://trigger.dev/docs/deploy-environment-variables) in Trigger.dev as well.
The `OPENAI_API_KEY` and `DATABASE_URL` are used to create an embedding using OpenAI and connect to your database. Be sure to add these as [environment variables](https://trigger.dev/docs/deploy-environment-variables) in Trigger.dev as well.
</Step>
</Steps>
<Check>
You've successfully created an API endpoint that can receive record payloads from Sequin and trigger a Trigger.dev task. In the next step, you'll setup Sequin to trigger the endpoint.
You've successfully created an API endpoint that can receive record payloads from Sequin and
trigger a Trigger.dev task. In the next step, you'll setup Sequin to trigger the endpoint.
</Check>
## Create Sequin consumer
@@ -253,11 +265,10 @@ You'll now configure Sequin to send every row in your `posts` table to your Trig
</Frame>
7. Click the **Create Consumer** button.
</Step>
</Steps>
<Check>
Your Sequin consumer is now created and ready to send events to your API endpoint.
</Check>
<Check>Your Sequin consumer is now created and ready to send events to your API endpoint.</Check>
## Test end-to-end
@@ -301,10 +312,12 @@ You'll now configure Sequin to send every row in your `posts` table to your Trig
<img src="/images/sequin-final-run.png" alt="Task run" />
</Frame>
</Step>
</Steps>
<Check>
Every time a post is created or updated, Sequin will deliver the row payload to your API endpoint and Trigger.dev will run the `create-embedding-for-post` task.
Every time a post is created or updated, Sequin will deliver the row payload to your API endpoint
and Trigger.dev will run the `create-embedding-for-post` task.
</Check>
## Next steps
@@ -314,4 +327,4 @@ With Sequin and Trigger.dev, every post in your database will now have an embedd
From here, add error handling and deploy to production:
- Add [retries](/errors-retrying) to your Trigger.dev task to ensure that any errors are captured and logged.
- Deploy to [production](/guides/frameworks/nextjs#deploying-your-task-to-trigger-dev) and update your Sequin consumer to point to your production database and endpoint.
- Deploy to [production](/guides/frameworks/nextjs#deploying-your-task-to-trigger-dev) and update your Sequin consumer to point to your production database and endpoint.
@@ -26,6 +26,7 @@ This guide shows you how to set up and deploy a simple Supabase edge function ex
## Prerequisites
- Ensure you have the [Supabase CLI](https://supabase.com/docs/guides/cli/getting-started) installed
- Since Supabase CLI version 1.123.4, you must have [Docker Desktop installed](https://supabase.com/docs/guides/functions/deploy#deploy-your-edge-functions) to deploy Edge Functions
- Ensure TypeScript is installed
- [Create a Trigger.dev account](https://cloud.trigger.dev)
- [Create a new Trigger.dev project](/guides/dashboard/creating-a-project)
@@ -1,15 +1,11 @@
---
title: "Triggering tasks from Supabase database webhooks"
title: "Triggering tasks from Supabase Database Webhooks"
sidebarTitle: "Database webhooks"
description: "This guide will show you how to trigger a task when a row is added to a table using a Supabase database webhook and edge function."
description: "This guide shows you how to trigger a transcribing task when a row is added to a table in a Supabase database, using a Database Webhook and Edge Function."
---
import Prerequisites from "/snippets/framework-prerequisites.mdx";
import SupabasePrerequisites from "/snippets/supabase-prerequisites.mdx";
import CliInitStep from "/snippets/step-cli-init.mdx";
import CliDevStep from "/snippets/step-cli-dev.mdx";
import CliRunTestStep from "/snippets/step-run-test.mdx";
import CliViewRunStep from "/snippets/step-view-run.mdx";
import UsefulNextSteps from "/snippets/useful-next-steps.mdx";
import TriggerTaskNextjs from "/snippets/trigger-tasks-nextjs.mdx";
import NextjsTroubleshootingMissingApiKey from "/snippets/nextjs-missing-api-key.mdx";
@@ -19,174 +15,260 @@ import SupabaseDocsCards from "/snippets/supabase-docs-cards.mdx";
## Overview
Database webhooks allow you to send realtime data from your database to another system whenever an event occurs in your table e.g. when a row is inserted, updated, or deleted, or when a specific column is updated.
Supabase and Trigger.dev can be used together to create powerful workflows triggered by real-time changes in your database tables:
This guide shows you how to set up a Supabase database webhook and deploy a simple edge function that triggers a "Hello world" task every time a new row is inserted into your table.
- A Supabase Database Webhook triggers an Edge Function when a row including a video URL is inserted into a table
- The Edge Function triggers a Trigger.dev task, passing the `video_url` column data from the new table row as the payload
- The Trigger.dev task then:
- Uses [FFmpeg](https://www.ffmpeg.org/) to extract the audio track from a video URL
- Uses [Deepgram](https://deepgram.com) to transcribe the extracted audio
- Updates the original table row using the `record.id` in Supabase with the new transcription using `update`
## Prerequisites
- Ensure you have the [Supabase CLI](https://supabase.com/docs/guides/cli/getting-started) installed
- Since Supabase CLI version 1.123.4, you must have [Docker Desktop installed](https://supabase.com/docs/guides/functions/deploy#deploy-your-edge-functions) to deploy Edge Functions
- Ensure TypeScript is installed
- [Create a Trigger.dev account](https://cloud.trigger.dev)
- [Create a new Trigger.dev project](/guides/dashboard/creating-a-project)
- [Create a new Deepgram account](https://deepgram.com/) and get your API key from the dashboard
## Initial setup
<Steps>
<SupabasePrerequisites />
<CliInitStep />
<CliDevStep />
<CliRunTestStep />
<CliViewRunStep />
</Steps>
<Step title="Run the CLI `init` command">
## Create and deploy a new Supabase edge function and create a new database webhook
The easiest way to get started is to use the CLI. It will add Trigger.dev to your existing project, create a `/trigger` folder and give you an example task.
<Steps>
Run this command in the root of your project to get started:
<Step title="Add your Trigger.dev prod secret key in Supabase">
<CodeGroup>
First, go to your Trigger.dev [project dashboard](https://cloud.trigger.dev) and copy the `prod` secret key from the API keys page.
![How to find your prod secret key](/images/api-key-prod.png)
Then, in [Supabase](https://supabase.com/dashboard/projects), select the project you want to use, navigate to 'Project settings' <Icon icon="circle-1" iconType="solid" size={20} color="A8FF53" />, click 'Edge functions' <Icon icon="circle-2" iconType="solid" size={20} color="A8FF53" /> in the configurations menu, and then click the 'Add new secret' <Icon icon="circle-3" iconType="solid" size={20} color="A8FF53" /> button.
Add `TRIGGER_SECRET_KEY` <Icon icon="circle-4" iconType="solid" size={20} color="A8FF53" /> with the pasted value of your Trigger.dev `prod` secret key.
![Add secret key in Supabase](/images/supabase-keys-1.png)
</Step>
<Step title="Create a new edge function using the Supabase CLI">
Now create a new edge function using the Supabase CLI. We will call it `database-webhook`.
```bash
supabase functions new database-webhook
```bash npm
npx trigger.dev@latest init
```
```bash pnpm
pnpm dlx trigger.dev@latest init
```
```bash yarn
yarn dlx trigger.dev@latest init
```
</CodeGroup>
It will do a few things:
1. Log you into the CLI if you're not already logged in.
2. Create a `trigger.config.ts` file in the root of your project.
3. Ask where you'd like to create the `/trigger` directory.
4. Create the `/trigger` directory with an example task, `/trigger/example.[ts/js]`.
Choose "None" when prompted to install an example task. We will create a new task for this guide.
</Step>
<Step title="Update the edge function code">
</Steps>
Replace the `database-webhook` placeholder code with the following code:
## Create a new table in your Supabase database
```ts functions/database-webhook/index.ts
import "jsr:@supabase/functions-js/edge-runtime.d.ts";
// Import the Trigger.dev SDK - replace "<your-sdk-version>" with the version of the SDK you are using, e.g. "3.0.0". You can find this in your package.json file.
import { tasks } from "npm:@trigger.dev/sdk@3.0.0/v3";
// Import your task type from your /trigger folder
import type { helloWorldTask } from "../../../src/trigger/example.ts";
// 👆 **type-only** import
First, in the Supabase project dashboard, you'll need to create a new table to store the video URL and transcription.
console.log("Hello from 'database-webhook' function!");
To do this, click on 'Table Editor' <Icon icon="circle-1" iconType="solid" size={20} color="A8FF53" /> in the left-hand menu and create a new table. <Icon icon="circle-2" iconType="solid" size={20} color="A8FF53" />
Deno.serve(async (req) => {
// Listens for incoming JSON requests
const payload = await req.json();
// Triggers the "hello-world" task with the payload
await tasks.trigger<typeof helloWorldTask>(
// Your task id
"hello-world",
// Your task payload. This will be the data you receive from the database webhook
payload
);
return new Response("ok");
![How to create a new Supabase table](/images/supabase-new-table-1.png)
Call your table `video_transcriptions`. <Icon icon="circle-1" iconType="solid" size={20} color="A8FF53" />
Add two new columns, one called `video_url` with the type `text` <Icon icon="circle-2" iconType="solid" size={20} color="A8FF53" />, and another called `transcription`, also with the type `text` <Icon icon="circle-3" iconType="solid" size={20} color="A8FF53" />.
![How to create a new Supabase table 2](/images/supabase-new-table-2.png)
## Create and deploy the Trigger.dev task
### Generate the Database type definitions
To allow you to use TypeScript to interact with your table, you need to [generate the type definitions](https://supabase.com/docs/guides/api/rest/generating-types) for your Supabase table using the Supabase CLI.
```bash
supabase gen types --lang=typescript --project-id <project-ref> --schema public > database.types.ts
```
<Note> Replace `<project-ref>` with your Supabase project reference ID. This can be found in your Supabase project settings under 'General'. </Note>
### Create the transcription task
Create a new task file in your `/trigger` folder. Call it `videoProcessAndUpdate.ts`.
This task takes a video from a public video url, extracts the audio using FFmpeg and transcribes the audio using Deepgram. The transcription summary will then be updated back to the original row in the `video_transcriptions` table in Supabase.
You will need to install some additional dependencies for this task:
<CodeGroup>
```bash npm
npm install @deepgram/sdk @supabase/supabase-js fluent-ffmpeg
```
```bash pnpm
pnpm install @deepgram/sdk @supabase/supabase-js fluent-ffmpeg
```
```bash yarn
yarn install @deepgram/sdk @supabase/supabase-js fluent-ffmpeg
```
</CodeGroup>
These dependencies will allow you to interact with the Deepgram and Supabase APIs and extract audio from a video using FFmpeg.
```ts /trigger/videoProcessAndUpdate.ts
// Install any missing dependencies below
import { createClient as createDeepgramClient } from "@deepgram/sdk";
import { createClient as createSupabaseClient } from "@supabase/supabase-js";
import { logger, task } from "@trigger.dev/sdk/v3";
import ffmpeg from "fluent-ffmpeg";
import fs from "fs";
import { Readable } from "node:stream";
import os from "os";
import path from "path";
import { Database } from "../../database.types";
// Create a single Supabase client for interacting with your database
// 'Database' supplies the type definitions to supabase-js
const supabase = createSupabaseClient<Database>(
// These details can be found in your Supabase project settings under `API`
process.env.SUPABASE_PROJECT_URL as string, // e.g. https://abc123.supabase.co - replace 'abc123' with your project ID
process.env.SUPABASE_SERVICE_ROLE_KEY as string // Your service role secret key
);
// Your DEEPGRAM_SECRET_KEY can be found in your Deepgram dashboard
const deepgram = createDeepgramClient(process.env.DEEPGRAM_SECRET_KEY);
export const videoProcessAndUpdate = task({
id: "video-process-and-update",
run: async (payload: { videoUrl: string; id: number }) => {
const { videoUrl, id } = payload;
logger.log(`Processing video at URL: ${videoUrl}`);
// Generate temporary file names
const tempDirectory = os.tmpdir();
const outputPath = path.join(tempDirectory, `audio_${Date.now()}.wav`);
// Fetch the video
const response = await fetch(videoUrl);
// Extract the audio
await new Promise((resolve, reject) => {
if (!response.body) {
return reject(new Error("Failed to fetch video"));
}
ffmpeg(Readable.from(response.body))
.outputOptions([
"-vn", // Disable video output
"-acodec pcm_s16le", // Use PCM 16-bit little-endian encoding
"-ar 44100", // Set audio sample rate to 44.1 kHz
"-ac 2", // Set audio channels to stereo
])
.output(outputPath)
.on("end", resolve)
.on("error", reject)
.run();
});
logger.log(`Audio extracted from video`, { outputPath });
// Transcribe the audio using Deepgram
const { result, error } = await deepgram.listen.prerecorded.transcribeFile(
fs.readFileSync(outputPath),
{
model: "nova-2", // Use the Nova 2 model
smart_format: true, // Automatically format the transcription
diarize: true, // Enable speaker diarization
}
);
if (error) {
throw error;
}
// Convert the result object to a string
const transcription = result.results.channels[0].alternatives[0].paragraphs?.transcript;
logger.log(`Transcription: ${transcription}`);
// Delete the temporary audio file
fs.unlinkSync(outputPath);
logger.log(`Temporary audio file deleted`, { outputPath });
const { error: updateError } = await supabase
.from("video_transcriptions")
// Set the plan to the new plan and update the timestamp
.update({ transcription: transcription, video_url: videoUrl })
// Find the row by its ID
.eq("id", id);
if (updateError) {
throw new Error(`Failed to update transcription: ${updateError.message}`);
}
return {
message: `Summary of the audio: ${transcription}`,
result,
};
},
});
```
This code sets up a Deno server that listens for incoming JSON requests, triggers a "hello-world" task, logs the received payload, and responds with "ok". This setup is typical for a webhook endpoint that processes incoming data and triggers some action (in this case, the "hello-world" task) based on that data.
<Warning>
When updating your tables from a Trigger.dev task which has been triggered by a database change,
be extremely careful to not cause an infinite loop. Ensure you have the correct conditions in
place to prevent this.
</Warning>
<Note>You can only import the `type` from the task.</Note>
<Note>
Tasks in the `trigger` folder use Node, so they must stay in there or they will not run,
especially if you are using a different runtime like Deno. Also do not add "`npm:`" to imports
inside your task files, for the same reason.
</Note>
### Adding the FFmpeg build extension
</Step>
Before you can deploy the task, you'll need to add the FFmpeg build extension to your `trigger.config.ts` file.
<Step title="Deploy your edge function using the Supabase CLI">
```ts trigger.config.ts
// Add this import
import { ffmpeg } from "@trigger.dev/build/extensions/core";
import { defineConfig } from "@trigger.dev/sdk/v3";
Now deploy your edge function with the following command:
```bash
supabase functions deploy database-webhook
export default defineConfig({
project: "<project ref>", // Replace with your project ref
// Your other config settings...
build: {
// Add the FFmpeg build extension
extensions: [ffmpeg()],
},
});
```
Follow the CLI instructions, selecting the same project you added your `prod` secret key to, and once complete you should see your new edge function deployment in your Supabase edge functions dashboard.
<Note>
[Build extensions](/config/config-file#extensions) allow you to hook into the build system and
customize the build process or the resulting bundle and container image (in the case of
deploying). You can use pre-built extensions or create your own.
</Note>
There will be a link to the dashboard in your terminal output, or you can find it at this URL:
<Note>
You'll also need to add `@trigger.dev/build` to your `package.json` file under `devDependencies`
if you don't already have it there.
</Note>
`https://supabase.com/dashboard/project/<your-project-id>/functions`
### Add your Deepgram and Supabase environment variables to your Trigger.dev project
<Note>Replace `your-project-id` with your actual project ID.</Note>
You will need to add your `DEEPGRAM_SECRET_KEY`, `SUPABASE_PROJECT_URL` and `SUPABASE_SERVICE_ROLE_KEY` as environment variables in your Trigger.dev project. This can be done in the 'Environment Variables' page in your project dashboard.
</Step>
![Adding environment variables](/images/environment-variables-page.jpg)
<Step title="Create a new table">
### Deploying your task
Next, in your Supabase project dashboard, click on 'Table Editor' <Icon icon="circle-1" iconType="solid" size={20} color="A8FF53" /> in the left-hand menu and create a new table. <Icon icon="circle-2" iconType="solid" size={20} color="A8FF53" />
![How to create a new table](/images/supabase-new-table-1.png)
In this example we will call our table `skynet`. <Icon icon="circle-1" iconType="solid" size={20} color="A8FF53" />
Add a new column called `name` with the type `text`. <Icon icon="circle-2" iconType="solid" size={20} color="A8FF53" />
![How to add a new column](/images/supabase-new-table-2.png)
</Step>
<Step title="Configure JWT settings">
By default, Supabase edge functions require a JSON Web Token [JWT](https://supabase.com/docs/guides/auth/jwts) in the authorization header. This is to ensure that only authorized users can access your edge functions.
In your Supabase project dashboard, click 'Project settings' <Icon icon="circle-1" iconType="solid" size={20} color="A8FF53" />, then the 'API' tab <Icon icon="circle-2" iconType="solid" size={20} color="A8FF53" />, and copy the `anon` `public` API key from the table <Icon icon="circle-3" iconType="solid" size={20} color="A8FF53" />.
![How to find your Supabase API keys](/images/supabase-api-key.png)
Then, go to 'Database' <Icon icon="circle-1" iconType="solid" size={20} color="A8FF53" /> click on 'Webhooks' <Icon icon="circle-2" iconType="solid" size={20} color="A8FF53" />, and then click 'Create a new hook' <Icon icon="circle-3" iconType="solid" size={20} color="A8FF53" />.
![How to create a new webhook](/images/supabase-create-webhook-1.png)
<Icon icon="circle-1" iconType="solid" size={20} color="A8FF53" /> Call the hook `edge-function-hook`.
<Icon icon="circle-2" iconType="solid" size={20} color="A8FF53" /> Select the new table you have created:
`public` `skynet`.
<Icon icon="circle-3" iconType="solid" size={20} color="A8FF53" /> Choose the `insert` event.
![How to create a new webhook 2](/images/supabase-create-webhook-2.png)
<Icon icon="circle-4" iconType="solid" size={20} color="A8FF53" /> Under 'Webhook configuration', select
'Supabase Edge functions'{" "}
<Icon icon="circle-5" iconType="solid" size={20} color="A8FF53" /> Under 'Edge function', choose `POST`
and select the edge function you have created: `database-webhook`.{" "}
<Icon icon="circle-6" iconType="solid" size={20} color="A8FF53" /> Under 'HTTP Headers', add a new header with the key `Authorization` and the value `Bearer <your-api-key>` (replace `<your-api-key>` with the `anon` `public` API key you copied earlier).
<Icon icon="circle-7" iconType="solid" size={20} color="A8FF53" /> Click 'Create webhook'.{" "}
![How to create a new webhook 3](/images/supabase-create-webhook-3.png)
Your database webhook is now ready to use.
</Step>
</Steps>
## Deploy your task and trigger it from your new `database-webhook` edge function
<Steps>
<Step title="Deploy your 'Hello World' task">
The next step is to deploy your `hello-world` task to [Trigger.dev cloud](https://cloud.trigger.dev).
To do this, run the following command in the terminal:
Now you can now deploy your task using the following command:
<CodeGroup>
@@ -204,34 +286,131 @@ yarn dlx trigger.dev@latest deploy
</CodeGroup>
</Step>
## Create and deploy the Supabase Edge Function
<Step title="Trigger the task from your edge function">
### Add your Trigger.dev prod secret key to the Supabase dashboard
Your `database-webhook` edge function is now set up to trigger the `hello-world` task every time a new row is inserted into your `skynet` table.
Go to your Trigger.dev [project dashboard](https://cloud.trigger.dev) and copy the `prod` secret key from the API keys page.
To do this, go back to your Supabase project dashboard, click on 'Table Editor' <Icon icon="circle-1" iconType="solid" size={20} color="A8FF53" /> in the left-hand menu, click on the `skynet` table <Icon icon="circle-2" iconType="solid" size={20} color="A8FF53" /> , and then click 'Insert', 'Insert Row' <Icon icon="circle-3" iconType="solid" size={20} color="A8FF53" />.
![How to find your prod secret key](/images/api-key-prod.png)
Then, in [Supabase](https://supabase.com/dashboard/projects), select the project you want to use, navigate to 'Project settings' <Icon icon="circle-1" iconType="solid" size={20} color="A8FF53" />, click 'Edge Functions' <Icon icon="circle-2" iconType="solid" size={20} color="A8FF53" /> in the configurations menu, and then click the 'Add new secret' <Icon icon="circle-3" iconType="solid" size={20} color="A8FF53" /> button.
Add `TRIGGER_SECRET_KEY` <Icon icon="circle-4" iconType="solid" size={20} color="A8FF53" /> with the pasted value of your Trigger.dev `prod` secret key.
![Add secret key in Supabase](/images/supabase-keys-1.png)
### Create a new Edge Function using the Supabase CLI
Now create an Edge Function using the Supabase CLI. Call it `video-processing-handler`. This function will be triggered by the Database Webhook.
```bash
supabase functions new video-processing-handler
```
```ts functions/video-processing-handler/index.ts
// Setup type definitions for built-in Supabase Runtime APIs
import "jsr:@supabase/functions-js/edge-runtime.d.ts";
import { tasks } from "npm:@trigger.dev/sdk@latest/v3";
// Import the videoProcessAndUpdate task from the trigger folder
import type { videoProcessAndUpdate } from "../../../src/trigger/videoProcessAndUpdate.ts";
// 👆 type only import
// Sets up a Deno server that listens for incoming JSON requests
Deno.serve(async (req) => {
const payload = await req.json();
// This payload will contain the video url and id from the new row in the table
const videoUrl = payload.record.video_url;
const id = payload.record.id;
// Trigger the videoProcessAndUpdate task with the videoUrl payload
await tasks.trigger<typeof videoProcessAndUpdate>("video-process-and-update", { videoUrl, id });
console.log(payload ?? "No name provided");
return new Response("ok");
});
```
<Note>
Tasks in the `trigger` folder use Node, so they must stay in there or they will not run,
especially if you are using a different runtime like Deno. Also do not add "`npm:`" to imports
inside your task files, for the same reason.
</Note>
### Deploy the Edge Function
Now deploy your new Edge Function with the following command:
```bash
supabase functions deploy video-processing-handler
```
Follow the CLI instructions, selecting the same project you added your `prod` secret key to, and once complete you should see your new Edge Function deployment in your Supabase Edge Functions dashboard.
There will be a link to the dashboard in your terminal output.
## Create the Database Webhook
In your Supabase project dashboard, click 'Project settings' <Icon icon="circle-1" iconType="solid" size={20} color="A8FF53" />, then the 'API' tab <Icon icon="circle-2" iconType="solid" size={20} color="A8FF53" />, and copy the `anon` `public` API key from the table <Icon icon="circle-3" iconType="solid" size={20} color="A8FF53" />.
![How to find your Supabase API keys](/images/supabase-api-key.png)
Then, go to 'Database' <Icon icon="circle-1" iconType="solid" size={20} color="A8FF53" /> click on 'Webhooks' <Icon icon="circle-2" iconType="solid" size={20} color="A8FF53" />, and then click 'Create a new hook' <Icon icon="circle-3" iconType="solid" size={20} color="A8FF53" />.
![How to create a new webhook](/images/supabase-create-webhook-1.png)
<Icon icon="circle-1" iconType="solid" size={20} color="A8FF53" /> Call the hook `edge-function-hook`.
<Icon icon="circle-2" iconType="solid" size={20} color="A8FF53" /> Select the new table you have created:
`public` `video_transcriptions`.
<Icon icon="circle-3" iconType="solid" size={20} color="A8FF53" /> Choose the `insert` event.
![How to create a new webhook 2](/images/supabase-create-webhook-2.png)
<Icon icon="circle-4" iconType="solid" size={20} color="A8FF53" /> Under 'Webhook configuration', select
'Supabase Edge Functions'{" "}
<Icon icon="circle-5" iconType="solid" size={20} color="A8FF53" /> Under 'Edge Function', choose `POST`
and select the Edge Function you have created: `video-processing-handler`.{" "}
<Icon icon="circle-6" iconType="solid" size={20} color="A8FF53" /> Under 'HTTP Headers', add a new header with the key `Authorization` and the value `Bearer <your-api-key>` (replace `<your-api-key>` with the `anon` `public` API key you copied earlier).
<Info>
Supabase Edge Functions require a JSON Web Token [JWT](https://supabase.com/docs/guides/auth/jwts)
in the authorization header. This is to ensure that only authorized users can access your edge
functions.
</Info>
<Icon icon="circle-7" iconType="solid" size={20} color="A8FF53" /> Click 'Create webhook'.{" "}
![How to create a new webhook 3](/images/supabase-create-webhook-3.png)
Your Database Webhook is now ready to use.
## Triggering the entire workflow
Your `video-processing-handler` Edge Function is now set up to trigger the `videoProcessAndUpdate` task every time a new row is inserted into your `video_transcriptions` table.
To do this, go back to your Supabase project dashboard, click on 'Table Editor' <Icon icon="circle-1" iconType="solid" size={20} color="A8FF53" /> in the left-hand menu, click on the `video_transcriptions` table <Icon icon="circle-2" iconType="solid" size={20} color="A8FF53" /> , and then click 'Insert', 'Insert Row' <Icon icon="circle-3" iconType="solid" size={20} color="A8FF53" />.
![How to insert a new row 1](/images/supabase-new-table-3.png)
Add a new item under `name`, with the value `Sarah Connor` (this can be any string). <Icon icon="circle-1" iconType="solid" size={20} color="A8FF53" />
Add a new item under `video_url`, with a public video url. <Icon icon="circle-1" iconType="solid" size={20} color="A8FF53" />.
You can use the following public video URL for testing: `https://content.trigger.dev/Supabase%20Edge%20Functions%20Quickstart.mp4`.
![How to insert a new row 2](/images/supabase-new-table-4.png)
Go back to your edge function dashboard <Icon icon="circle-1" iconType="solid" size={20} color="A8FF53" /> , and under 'Logs' <Icon icon="circle-2" iconType="solid" size={20} color="A8FF53" /> you should see a new run of your `database-webhook` edge function. <Icon icon="circle-3" iconType="solid" size={20} color="A8FF53" />
Once the new table row has been inserted, check your [cloud.trigger.dev](http://cloud.trigger.dev) project 'Runs' list <Icon icon="circle-1" iconType="solid" size={20} color="A8FF53" /> and you should see a processing `videoProcessAndUpdate` task <Icon icon="circle-2" iconType="solid" size={20} color="A8FF53" /> which has been triggered when you added a new row with the video url to your `video_transcriptions` table.
![How to view the logs](/images/supabase-logs.png)
![Supabase successful run](/images/supabase-run-result.png)
Then, check your [cloud.trigger.dev](http://cloud.trigger.dev) project 'Runs' list <Icon icon="circle-1" iconType="solid" size={20} color="A8FF53" /> and you should see a successful `hello-world` task <Icon icon="circle-2" iconType="solid" size={20} color="A8FF53" /> which has been triggered when you added a new row with the `name` `Sarah Connor` to your `skynet` Supabase table.
Once the run has completed successfully, go back to your Supabase `video_transcriptions` table, and you should see that in the row containing the original video URL, the transcription has now been added to the `transcription` column.
Inside that run you will see the payload that was sent from the database webhook, including the `name` and other table information.
![Supabase successful table update](/images/supabase-table-result.png)
![How to insert a new row 2](/images/supabase-trigger-screenshot.png)
**Congratulations, you have successfully triggered a task from a Supabase edge function using a database webhook!**
</Step>
</Steps>
**Congratulations! You have completed the full workflow from Supabase to Trigger.dev and back again.**
<SupabaseDocsCards />
@@ -1,12 +1,42 @@
---
title: "Introduction"
title: "Frameworks, guides and examples overview"
sidebarTitle: "Introduction"
description: "Learn how to use Trigger.dev with these practical task examples."
description: "An ever growing list of guides and examples to help you get setup with Trigger.dev."
---
import CardBun from "/snippets/card-bun.mdx";
import CardNodejs from "/snippets/card-nodejs.mdx";
import CardNextjs from "/snippets/card-nextjs.mdx";
import CardRemix from "/snippets/card-remix.mdx";
import CardSupabase from "/snippets/card-supabase.mdx";
## Frameworks
<CardGroup cols={3}>
<CardBun />
<CardNodejs />
<CardNextjs />
<CardRemix />
<CardSupabase />
</CardGroup>
## Guides
Get set up fast using our detailed walk-through guides.
| Guide | Description |
| :---------------------------------------------------- | :------------------------------------------------------------------------------- |
| [Prisma](/guides/frameworks/prisma) | This guide will show you how to setup Prisma with Trigger.dev |
| [Sequin database triggers](/guides/frameworks/sequin) | This guide will show you how to trigger tasks from database changes using Sequin |
## Example tasks
Tasks you can copy and paste to get started with Trigger.dev. They can all be extended and customized to fit your needs.
| Example task | Description |
| :---------------------------------------------------------------------------- | :----------------------------------------------------------------------------- |
| [DALL·E 3 image generation](/guides/examples/dall-e3-generate-image) | Use OpenAI's GPT-4o and DALL·E 3 to generate an image and text. |
| [Deepgram audio transcription](/guides/examples/deepgram-transcribe-audio) | Transcribe audio using Deepgram's speech recognition API. |
| [FFmpeg video processing](/guides/examples/ffmpeg-video-processing) | Use FFmpeg to process a video in various ways and save it to Cloudflare R2. |
| [OpenAI with retrying](/guides/examples/open-ai-with-retrying) | Create a reusable OpenAI task with custom retry options. |
| [PDF to image](/guides/examples/pdf-to-image) | Use `MuPDF` to turn a PDF into images and save them to Cloudflare R2. |
Binary file not shown.

Before

Width:  |  Height:  |  Size: 58 KiB

After

Width:  |  Height:  |  Size: 75 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 55 KiB

After

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 51 KiB

After

Width:  |  Height:  |  Size: 137 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 39 KiB

After

Width:  |  Height:  |  Size: 102 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 155 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 37 KiB

+7 -5
View File
@@ -19,16 +19,18 @@ We're [open source](https://github.com/triggerdotdev/trigger.dev) and you can ch
<CardGroup>
<Card title="Quick start guide" icon="person-running-fast" href="/quick-start">
Get started in 3 minutes.
Go from zero to running your first task in 3 minutes.
</Card>
<Card title="Writing tasks" icon="wand-magic-sparkles" href="/tasks/overview">
Tasks are the core of Trigger.dev. Learn what they are and how to write them.
</Card>
<Card title="Framework guides" icon="wand-magic-sparkles" href="/guides/frameworks/introduction">
Get started with Trigger.dev in your existing framework.
<Card title="Walk-through guides" icon="book" href="/guides/introduction">
Detailed guides for setting up Trigger.dev with popular frameworks and services, including
Next.js, Remix, Supabase and more.
</Card>
<Card title="Example tasks" icon="wand-magic-sparkles" href="/guides/examples/intro">
Example tasks to get you started.
<Card title="Example tasks" icon="code" href="/guides/introduction#example-tasks">
Code you can use in your own projects, including OpenAI, Deepgram, FFmpeg, Puppeteer, Stripe,
Supabase and more.
</Card>
</CardGroup>
+33 -62
View File
@@ -1,10 +1,7 @@
{
"$schema": "https://mintlify.com/schema.json",
"name": "Trigger.dev",
"openapi": [
"/openapi.yml",
"/v3-openapi.yaml"
],
"openapi": ["/openapi.yml", "/v3-openapi.yaml"],
"api": {
"playground": {
"mode": "simple"
@@ -91,6 +88,14 @@
"source": "/trigger-config",
"destination": "/config/config-file"
},
{
"source": "/guides/frameworks/introduction",
"destination": "/guides/introduction"
},
{
"source": "/guides/examples/intro",
"destination": "/guides/introduction"
},
{
"source": "/examples/:slug*",
"destination": "/guides/examples/:slug*"
@@ -106,41 +111,26 @@
"navigation": [
{
"group": "Getting Started",
"pages": [
"introduction",
"quick-start",
"how-it-works",
"upgrading-beta",
"limits"
]
"pages": ["introduction", "quick-start", "how-it-works", "upgrading-beta", "limits"]
},
{
"group": "Fundamentals",
"pages": [
{
"group": "Tasks",
"pages": [
"tasks/overview",
"tasks/scheduled"
]
"pages": ["tasks/overview", "tasks/scheduled"]
},
"triggering",
"apikeys",
{
"group": "Configuration",
"pages": [
"config/config-file",
"config/extensions/overview"
]
"pages": ["config/config-file", "config/extensions/overview"]
}
]
},
{
"group": "Development",
"pages": [
"cli-dev",
"run-tests"
]
"pages": ["cli-dev", "run-tests"]
},
{
"group": "Deployment",
@@ -150,9 +140,7 @@
"github-actions",
{
"group": "Deployment integrations",
"pages": [
"vercel-integration"
]
"pages": ["vercel-integration"]
}
]
},
@@ -164,13 +152,7 @@
"errors-retrying",
{
"group": "Wait",
"pages": [
"wait",
"wait-for",
"wait-until",
"wait-for-event",
"wait-for-request"
]
"pages": ["wait", "wait-for", "wait-until", "wait-for-event", "wait-for-request"]
},
"queue-concurrency",
"versioning",
@@ -189,10 +171,7 @@
"management/overview",
{
"group": "Tasks API",
"pages": [
"management/tasks/trigger",
"management/tasks/batch-trigger"
]
"pages": ["management/tasks/trigger", "management/tasks/batch-trigger"]
},
{
"group": "Runs API",
@@ -231,9 +210,7 @@
},
{
"group": "Projects API",
"pages": [
"management/projects/runs"
]
"pages": ["management/projects/runs"]
}
]
},
@@ -279,20 +256,26 @@
},
{
"group": "Help",
"pages": [
"community",
"help-slack",
"help-email"
]
"pages": ["community", "help-slack", "help-email"]
},
{
"group": "",
"pages": ["guides/introduction"]
},
{
"group": "Frameworks",
"pages": [
"guides/frameworks/introduction",
"guides/frameworks/bun",
"guides/frameworks/nextjs",
"guides/frameworks/nodejs",
"guides/frameworks/remix",
"guides/frameworks/remix"
]
},
{
"group": "Guides",
"pages": [
"guides/frameworks/prisma",
"guides/frameworks/sequin",
{
"group": "Supabase",
"icon": "bolt",
@@ -305,17 +288,9 @@
}
]
},
{
"group": "Guides",
"pages": [
"guides/frameworks/prisma",
"guides/frameworks/sequin"
]
},
{
"group": "Example tasks",
"pages": [
"guides/examples/intro",
"guides/examples/dall-e3-generate-image",
"guides/examples/deepgram-transcribe-audio",
"guides/examples/ffmpeg-video-processing",
@@ -333,15 +308,11 @@
},
{
"group": "Dashboard",
"pages": [
"guides/dashboard/creating-a-project"
]
"pages": ["guides/dashboard/creating-a-project"]
},
{
"group": "Migrations",
"pages": [
"guides/use-cases/upgrading-from-v2"
]
"pages": ["guides/use-cases/upgrading-from-v2"]
}
],
"footerSocials": {
@@ -349,4 +320,4 @@
"github": "https://github.com/triggerdotdev",
"linkedin": "https://www.linkedin.com/company/triggerdotdev"
}
}
}
+4 -4
View File
@@ -4,15 +4,15 @@
<CardGroup cols={2}>
<Card
title="Edge function hello world"
icon="bolt"
title="Edge function hello world guide"
icon="book"
href="/guides/frameworks/supabase-edge-functions-basic"
>
Learn how to trigger a task from a Supabase edge function when a URL is visited.
</Card>
<Card
title="Edge function database webhooks"
icon="bolt"
title="Database webhooks guide"
icon="book"
href="/guides/frameworks/supabase-edge-functions-database-webhooks"
>
Learn how to trigger a task from a Supabase edge function when an event occurs in your database.
+5 -21
View File
@@ -15,38 +15,22 @@ supabase init
</Step>
<Step title="Optional step 2: create package.json and tsconfig.json files">
<Step title="Optional step 2: create a package.json file">
If your project does not already have `package.json` or/and `tsconfig.json` files (e.g. if you are using Deno), create them manually and add them to your project root folder.
If your project does not already have `package.json` file (e.g. if you are using Deno), create it manually in your project's root folder.
<Info> If your project has these files you can skip this step.</Info>
<Info> If your project has a `package.json` file you can skip this step.</Info>
Both of these files are required for the Trigger.dev SDK to work correctly.
This is required for the Trigger.dev SDK to work correctly.
```ts package.json
{
"devDependencies": {
// This should be the version of typescript you are using
"typescript": "^5.6.2"
}
}
```
```ts tsconfig.json
{
"compilerOptions": {
"target": "esnext",
"module": "NodeNext",
"moduleResolution": "NodeNext",
"esModuleInterop": true,
"strict": true,
"outDir": "dist",
"skipLibCheck": true,
"lib": ["DOM", "DOM.Iterable"],
"noEmit": true
},
"include": ["./src/**/*.ts", "trigger.config.ts"]
}
```
<Note> Update your Typescript version to the latest version available. </Note>
</Step>