diff --git a/docs/guides/frameworks/introduction.mdx b/docs/guides/frameworks/introduction.mdx deleted file mode 100644 index eb74771e78..0000000000 --- a/docs/guides/frameworks/introduction.mdx +++ /dev/null @@ -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"; - - - - - - - - diff --git a/docs/guides/frameworks/prisma.mdx b/docs/guides/frameworks/prisma.mdx index fbe495b3d5..c337d06c2b 100644 --- a/docs/guides/frameworks/prisma.mdx +++ b/docs/guides/frameworks/prisma.mdx @@ -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" --- diff --git a/docs/guides/frameworks/sequin.mdx b/docs/guides/frameworks/sequin.mdx index 40abec0483..986cd6f133 100644 --- a/docs/guides/frameworks/sequin.mdx +++ b/docs/guides/frameworks/sequin.mdx @@ -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 - -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. - + + 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. + - 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, - }); - - 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; +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; // 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, }); - ``` - - ```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(); - - 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(); - } + await client.connect(); + + 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(); } - ``` +} +```` + - 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. + 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: Task added @@ -135,7 +141,8 @@ Start by creating a new Trigger.dev task that takes in a Sequin change event as - 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. ## 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. -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). 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"; - - 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( - "create-embedding-for-post", - payload - ); +```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"; - 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( + "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. 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. - 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. ## Create Sequin consumer @@ -253,11 +265,10 @@ You'll now configure Sequin to send every row in your `posts` table to your Trig 7. Click the **Create Consumer** button. + - - Your Sequin consumer is now created and ready to send events to your API endpoint. - +Your Sequin consumer is now created and ready to send events to your API endpoint. ## Test end-to-end @@ -301,10 +312,12 @@ You'll now configure Sequin to send every row in your `posts` table to your Trig Task run + - 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. ## 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. \ No newline at end of file +- 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. diff --git a/docs/guides/frameworks/supabase-edge-functions-basic.mdx b/docs/guides/frameworks/supabase-edge-functions-basic.mdx index 9cf2749485..fecd5f0eb3 100644 --- a/docs/guides/frameworks/supabase-edge-functions-basic.mdx +++ b/docs/guides/frameworks/supabase-edge-functions-basic.mdx @@ -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) diff --git a/docs/guides/frameworks/supabase-edge-functions-database-webhooks.mdx b/docs/guides/frameworks/supabase-edge-functions-database-webhooks.mdx index a9986a576c..1060c419db 100644 --- a/docs/guides/frameworks/supabase-edge-functions-database-webhooks.mdx +++ b/docs/guides/frameworks/supabase-edge-functions-database-webhooks.mdx @@ -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,219 +15,402 @@ 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 - - - - - + -## 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. - +Run this command in the root of your project to get started: - + -First, go to your Trigger.dev [project dashboard](https://cloud.trigger.dev) and copy the `prod` secret key from the API keys page. +```bash npm +npx trigger.dev@latest init +``` -![How to find your prod secret key](/images/api-key-prod.png) +```bash pnpm +pnpm dlx trigger.dev@latest init +``` -Then, in [Supabase](https://supabase.com/dashboard/projects), select the project you want to use, navigate to 'Project settings' , click 'Edge functions' in the configurations menu, and then click the 'Add new secret' button. +```bash yarn +yarn dlx trigger.dev@latest init +``` -Add `TRIGGER_SECRET_KEY` with the pasted value of your Trigger.dev `prod` secret key. + -![Add secret key in Supabase](/images/supabase-keys-1.png) +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. - + + +## Create a new table in your Supabase database -Now create a new edge function using the Supabase CLI. We will call it `database-webhook`. +First, in the Supabase project dashboard, you'll need to create a new table to store the video URL and transcription. + +To do this, click on 'Table Editor' in the left-hand menu and create a new table. + +![How to create a new Supabase table](/images/supabase-new-table-1.png) + +Call your table `video_transcriptions`. + +Add two new columns, one called `video_url` with the type `text` , and another called `transcription`, also with the type `text` . + +![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 functions new database-webhook +supabase gen types --lang=typescript --project-id --schema public > database.types.ts ``` - + Replace `` with your Supabase project reference ID. This can be found in your Supabase project settings under 'General'. - +### Create the transcription task -Replace the `database-webhook` placeholder code with the following code: +Create a new task file in your `/trigger` folder. Call it `videoProcessAndUpdate.ts`. -```ts functions/database-webhook/index.ts -import "jsr:@supabase/functions-js/edge-runtime.d.ts"; -// Import the Trigger.dev SDK - replace "" 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 +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. -console.log("Hello from 'database-webhook' function!"); +You will need to install some additional dependencies for this task: -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( - // Your task id - "hello-world", - // Your task payload. This will be the data you receive from the database webhook - payload - ); - return new Response("ok"); + + +```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 +``` + + + +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( + // 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. + + 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. + + +### Adding the FFmpeg build extension + +Before you can deploy the task, you'll need to add the FFmpeg build extension to your `trigger.config.ts` file. + +```ts trigger.config.ts +// Add this import +import { ffmpeg } from "@trigger.dev/build/extensions/core"; +import { defineConfig } from "@trigger.dev/sdk/v3"; + +export default defineConfig({ + project: "", // Replace with your project ref + // Your other config settings... + build: { + // Add the FFmpeg build extension + extensions: [ffmpeg()], + }, +}); +``` -You can only import the `type` from the task. - 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. + [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. - + + You'll also need to add `@trigger.dev/build` to your `package.json` file under `devDependencies` + if you don't already have it there. + - +### Add your Deepgram and Supabase environment variables to your Trigger.dev project -Now deploy your edge function with the following command: +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. -```bash -supabase functions deploy database-webhook -``` +![Adding environment variables](/images/environment-variables-page.jpg) -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. +### Deploying your task -There will be a link to the dashboard in your terminal output, or you can find it at this URL: +Now you can now deploy your task using the following command: + + -`https://supabase.com/dashboard/project//functions` +```bash npm +npx trigger.dev@latest deploy +``` -Replace `your-project-id` with your actual project ID. +```bash pnpm +pnpm dlx trigger.dev@latest deploy +``` - +```bash yarn +yarn dlx trigger.dev@latest deploy +``` - + -Next, in your Supabase project dashboard, click on 'Table Editor' in the left-hand menu and create a new table. +## Create and deploy the Supabase Edge Function -![How to create a new table](/images/supabase-new-table-1.png) +### Add your Trigger.dev prod secret key to the Supabase dashboard -In this example we will call our table `skynet`. +Go to your Trigger.dev [project dashboard](https://cloud.trigger.dev) and copy the `prod` secret key from the API keys page. -Add a new column called `name` with the type `text`. +![How to find your prod secret key](/images/api-key-prod.png) -![How to add a new column](/images/supabase-new-table-2.png) +Then, in [Supabase](https://supabase.com/dashboard/projects), select the project you want to use, navigate to 'Project settings' , click 'Edge Functions' in the configurations menu, and then click the 'Add new secret' button. - +Add `TRIGGER_SECRET_KEY` with the pasted value of your Trigger.dev `prod` secret key. - +![Add secret key in Supabase](/images/supabase-keys-1.png) -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. +### Create a new Edge Function using the Supabase CLI -In your Supabase project dashboard, click 'Project settings' , then the 'API' tab , and copy the `anon` `public` API key from the table . +Now create an Edge Function using the Supabase CLI. Call it `video-processing-handler`. This function will be triggered by the Database Webhook. -![How to find your Supabase API keys](/images/supabase-api-key.png) +```bash +supabase functions new video-processing-handler +``` -Then, go to 'Database' click on 'Webhooks' , and then click 'Create a new hook' . +```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 -![How to create a new webhook](/images/supabase-create-webhook-1.png) +// Sets up a Deno server that listens for incoming JSON requests +Deno.serve(async (req) => { + const payload = await req.json(); - Call the hook `edge-function-hook`. + // 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; - Select the new table you have created: -`public` `skynet`. + // Trigger the videoProcessAndUpdate task with the videoUrl payload + await tasks.trigger("video-process-and-update", { videoUrl, id }); + console.log(payload ?? "No name provided"); - Choose the `insert` event. + return new Response("ok"); +}); +``` -![How to create a new webhook 2](/images/supabase-create-webhook-2.png) + + 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. + - Under 'Webhook configuration', select -'Supabase Edge functions'{" "} +### Deploy the Edge Function - Under 'Edge function', choose `POST` -and select the edge function you have created: `database-webhook`.{" "} +Now deploy your new Edge Function with the following command: - Under 'HTTP Headers', add a new header with the key `Authorization` and the value `Bearer ` (replace `` with the `anon` `public` API key you copied earlier). +```bash +supabase functions deploy video-processing-handler +``` - Click 'Create webhook'.{" "} +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. -![How to create a new webhook 3](/images/supabase-create-webhook-3.png) +There will be a link to the dashboard in your terminal output. -Your database webhook is now ready to use. +## Create the Database Webhook - +In your Supabase project dashboard, click 'Project settings' , then the 'API' tab , and copy the `anon` `public` API key from the table . - +![How to find your Supabase API keys](/images/supabase-api-key.png) -## Deploy your task and trigger it from your new `database-webhook` edge function +Then, go to 'Database' click on 'Webhooks' , and then click 'Create a new hook' . - +![How to create a new webhook](/images/supabase-create-webhook-1.png) - + Call the hook `edge-function-hook`. -The next step is to deploy your `hello-world` task to [Trigger.dev cloud](https://cloud.trigger.dev). + Select the new table you have created: +`public` `video_transcriptions`. -To do this, run the following command in the terminal: + Choose the `insert` event. - +![How to create a new webhook 2](/images/supabase-create-webhook-2.png) -```bash npm -npx trigger.dev@latest deploy -``` + Under 'Webhook configuration', select +'Supabase Edge Functions'{" "} -```bash pnpm -pnpm dlx trigger.dev@latest deploy -``` + Under 'Edge Function', choose `POST` +and select the Edge Function you have created: `video-processing-handler`.{" "} -```bash yarn -yarn dlx trigger.dev@latest deploy -``` + Under 'HTTP Headers', add a new header with the key `Authorization` and the value `Bearer ` (replace `` with the `anon` `public` API key you copied earlier). - + + 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. + - + Click 'Create webhook'.{" "} - +![How to create a new webhook 3](/images/supabase-create-webhook-3.png) -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. +Your Database Webhook is now ready to use. -To do this, go back to your Supabase project dashboard, click on 'Table Editor' in the left-hand menu, click on the `skynet` table , and then click 'Insert', 'Insert Row' . +## Triggering the entire workflow -![How to insert a new row 1](/images/supabase-new-table-3.png) +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. -Add a new item under `name`, with the value `Sarah Connor` (this can be any string). +To do this, go back to your Supabase project dashboard, click on 'Table Editor' in the left-hand menu, click on the `video_transcriptions` table , and then click 'Insert', 'Insert Row' . -![How to insert a new row 2](/images/supabase-new-table-4.png) +![How to insert a new row 1](/images/supabase-new-table-3.png) -Go back to your edge function dashboard , and under 'Logs' you should see a new run of your `database-webhook` edge function. +Add a new item under `video_url`, with a public video url. . -![How to view the logs](/images/supabase-logs.png) +You can use the following public video URL for testing: `https://content.trigger.dev/Supabase%20Edge%20Functions%20Quickstart.mp4`. -Then, check your [cloud.trigger.dev](http://cloud.trigger.dev) project 'Runs' list and you should see a successful `hello-world` task which has been triggered when you added a new row with the `name` `Sarah Connor` to your `skynet` Supabase table. +![How to insert a new row 2](/images/supabase-new-table-4.png) -Inside that run you will see the payload that was sent from the database webhook, including the `name` and other table information. +Once the new table row has been inserted, check your [cloud.trigger.dev](http://cloud.trigger.dev) project 'Runs' list and you should see a processing `videoProcessAndUpdate` task which has been triggered when you added a new row with the video url to your `video_transcriptions` table. -![How to insert a new row 2](/images/supabase-trigger-screenshot.png) +![Supabase successful run](/images/supabase-run-result.png) -**Congratulations, you have successfully triggered a task from a Supabase edge function using a database webhook!** +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. - +![Supabase successful table update](/images/supabase-table-result.png) - +**Congratulations! You have completed the full workflow from Supabase to Trigger.dev and back again.** diff --git a/docs/guides/examples/intro.mdx b/docs/guides/introduction.mdx similarity index 61% rename from docs/guides/examples/intro.mdx rename to docs/guides/introduction.mdx index fe41b1f3bb..7e41b7b853 100644 --- a/docs/guides/examples/intro.mdx +++ b/docs/guides/introduction.mdx @@ -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 + + + + + + + + + +## 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. | diff --git a/docs/images/supabase-create-webhook-2.png b/docs/images/supabase-create-webhook-2.png index 18ab7195c6..0c21b485ec 100644 Binary files a/docs/images/supabase-create-webhook-2.png and b/docs/images/supabase-create-webhook-2.png differ diff --git a/docs/images/supabase-create-webhook-3.png b/docs/images/supabase-create-webhook-3.png index cfe3065108..269ab65bec 100644 Binary files a/docs/images/supabase-create-webhook-3.png and b/docs/images/supabase-create-webhook-3.png differ diff --git a/docs/images/supabase-new-table-2.png b/docs/images/supabase-new-table-2.png index ffe336bdc1..7947becdfc 100644 Binary files a/docs/images/supabase-new-table-2.png and b/docs/images/supabase-new-table-2.png differ diff --git a/docs/images/supabase-new-table-3.png b/docs/images/supabase-new-table-3.png index 4baed1fc7b..3729529c4a 100644 Binary files a/docs/images/supabase-new-table-3.png and b/docs/images/supabase-new-table-3.png differ diff --git a/docs/images/supabase-new-table-4.png b/docs/images/supabase-new-table-4.png index 03dad93f11..eb0dc29f98 100644 Binary files a/docs/images/supabase-new-table-4.png and b/docs/images/supabase-new-table-4.png differ diff --git a/docs/images/supabase-run-result.png b/docs/images/supabase-run-result.png new file mode 100644 index 0000000000..2e29f79393 Binary files /dev/null and b/docs/images/supabase-run-result.png differ diff --git a/docs/images/supabase-table-result.png b/docs/images/supabase-table-result.png new file mode 100644 index 0000000000..848d9ae67a Binary files /dev/null and b/docs/images/supabase-table-result.png differ diff --git a/docs/images/supabase-trigger-screenshot.png b/docs/images/supabase-trigger-screenshot.png index 13905dc8dd..46c7ac124d 100644 Binary files a/docs/images/supabase-trigger-screenshot.png and b/docs/images/supabase-trigger-screenshot.png differ diff --git a/docs/introduction.mdx b/docs/introduction.mdx index bc40cd3f8f..bf6d632845 100644 --- a/docs/introduction.mdx +++ b/docs/introduction.mdx @@ -19,16 +19,18 @@ We're [open source](https://github.com/triggerdotdev/trigger.dev) and you can ch - Get started in 3 minutes. + Go from zero to running your first task in 3 minutes. Tasks are the core of Trigger.dev. Learn what they are and how to write them. - - Get started with Trigger.dev in your existing framework. + + Detailed guides for setting up Trigger.dev with popular frameworks and services, including + Next.js, Remix, Supabase and more. - - Example tasks to get you started. + + Code you can use in your own projects, including OpenAI, Deepgram, FFmpeg, Puppeteer, Stripe, + Supabase and more. diff --git a/docs/mint.json b/docs/mint.json index 6e02c96d68..8b133ac790 100644 --- a/docs/mint.json +++ b/docs/mint.json @@ -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" } -} \ No newline at end of file +} diff --git a/docs/snippets/supabase-docs-cards.mdx b/docs/snippets/supabase-docs-cards.mdx index 857b39f0c1..a5e7011d3b 100644 --- a/docs/snippets/supabase-docs-cards.mdx +++ b/docs/snippets/supabase-docs-cards.mdx @@ -4,15 +4,15 @@ Learn how to trigger a task from a Supabase edge function when a URL is visited. Learn how to trigger a task from a Supabase edge function when an event occurs in your database. diff --git a/docs/snippets/supabase-prerequisites.mdx b/docs/snippets/supabase-prerequisites.mdx index 1d52649f88..1e5c003d94 100644 --- a/docs/snippets/supabase-prerequisites.mdx +++ b/docs/snippets/supabase-prerequisites.mdx @@ -15,38 +15,22 @@ supabase init - + -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. - If your project has these files you can skip this step. + If your project has a `package.json` file you can skip this step. -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"] -} -``` + Update your Typescript version to the latest version available.