From 3d50d97c40444dcd6118c631b5b6da2d0d602524 Mon Sep 17 00:00:00 2001 From: D-K-P <8297864+D-K-P@users.noreply.github.com> Date: Fri, 20 Sep 2024 15:37:06 +0100 Subject: [PATCH 01/10] Added supabase storage basic example and updated ffmpeg instructions --- docs/examples/ffmpeg-video-processing.mdx | 6 +- docs/examples/supabase-storage-upload.mdx | 86 +++++++++++++++++++++++ docs/mint.json | 1 + 3 files changed, 90 insertions(+), 3 deletions(-) create mode 100644 docs/examples/supabase-storage-upload.mdx diff --git a/docs/examples/ffmpeg-video-processing.mdx b/docs/examples/ffmpeg-video-processing.mdx index a5a33a0100..bd65c7a230 100644 --- a/docs/examples/ffmpeg-video-processing.mdx +++ b/docs/examples/ffmpeg-video-processing.mdx @@ -136,7 +136,7 @@ To test this task, use this payload structure: ```json { - "videoUrl": "" + "videoUrl": "" // Replace with the URL of the video you want to upload } ``` @@ -250,7 +250,7 @@ To test this task, use this payload structure: ```json { - "videoUrl": "" + "videoUrl": "" // Replace with the URL of the video you want to upload } ``` @@ -355,6 +355,6 @@ To test this task in the dashboard, you can use the following payload: ```json { - "videoUrl": "" + "videoUrl": "" // Replace with the URL of the video you want to upload } ``` diff --git a/docs/examples/supabase-storage-upload.mdx b/docs/examples/supabase-storage-upload.mdx new file mode 100644 index 0000000000..edbc9ac634 --- /dev/null +++ b/docs/examples/supabase-storage-upload.mdx @@ -0,0 +1,86 @@ +--- +title: "Upload a video to Supabase Storage" +sidebarTitle: "Supabase Storage upload" +description: "This example demonstrates how to download a video from a URL and upload it to Supabase Storage using Trigger.dev." +--- + +## Overview + +This task downloads a video from a provided URL, saves it to a temporary file, and then uploads the video file to Supabase Storage. + +## Key features + +- Fetches a video from a provided URL +- Uploads the video file to Supabase Storage + +## Task code + +```ts trigger/supabase-storage-upload.ts +import { PutObjectCommand, S3Client } from "@aws-sdk/client-s3"; +import { logger, task } from "@trigger.dev/sdk/v3"; +import fs from "fs/promises"; +import fetch from "node-fetch"; +import os from "os"; +import path from "path"; + +// Initialize S3 client for Supabase Storage +// Update your .env file, and environment variables in the dashboard as instructed below +const s3Client = new S3Client({ + region: process.env.SUPABASE_REGION, // Your Supabase project's region e.g. "us-east-1" + endpoint: `https://${process.env.SUPABASE_PROJECT_ID}.supabase.co/storage/v1/s3`, // Your Supabase project ID + credentials: { + // These credentials can be found in your supabase storage settings, under 'S3 access keys' + accessKeyId: process.env.SUPABASE_S3_ACCESS_KEY_ID ?? "", // Access key ID + secretAccessKey: process.env.SUPABASE_S3__SECRET_ACCESS_KEY ?? "", // Access key + }, +}); + +export const supabaseStorageUpload = task({ + id: "supabase-storage-upload", + run: async (payload: { videoUrl: string }) => { + const { videoUrl } = payload; + + // Generate temporary file path + const tempDirectory = os.tmpdir(); + const outputPath = path.join(tempDirectory, `video_${Date.now()}.mp4`); + + // Fetch the video and save it to a temporary file + const response = await fetch(videoUrl); + const videoBuffer = await response.arrayBuffer(); + await fs.writeFile(outputPath, Buffer.from(videoBuffer)); + + const videoFile = await fs.readFile(outputPath); // Read the video file + const bucket = "my_bucket"; // Replace "my_bucket" with your bucket name + + // Upload the video to Supabase Storage + const objectKey = path.basename(outputPath); + await s3Client.send( + new PutObjectCommand({ + Bucket: bucket, + Key: objectKey, // The key is the file name + Body: videoFile, // The body is the video file + }) + ); + logger.log(`Video uploaded to Supabase Storage bucket`, { objectKey }); + + // Delete the temporary video file + await fs.unlink(outputPath); + + // Return the video object key + return { + objectKey, + bucket: bucket, + }; + }, +}); +``` + +## Testing your task + +To test this task in the dashboard, you can use the following payload: + +```json +{ + "videoUrl": "" // Replace with the URL of the video you want to upload +} +``` diff --git a/docs/mint.json b/docs/mint.json index 1c7c35cb53..c60d59ae6a 100644 --- a/docs/mint.json +++ b/docs/mint.json @@ -279,6 +279,7 @@ "examples/open-ai-with-retrying", "examples/pdf-to-image", "examples/sharp-image-processing", + "examples/supabase-storage-upload", "examples/react-pdf", "examples/resend-email-sequence", "examples/vercel-ai-sdk" From 9bc830e497632e97867d31fea41d668e5c6d01ee Mon Sep 17 00:00:00 2001 From: D-K-P <8297864+D-K-P@users.noreply.github.com> Date: Mon, 23 Sep 2024 15:10:32 +0100 Subject: [PATCH 02/10] Added stripe webhook example --- docs/examples/stripe-webhook.mdx | 144 ++++++++++++++++++++++ docs/examples/supabase-storage-upload.mdx | 4 +- docs/mint.json | 1 + 3 files changed, 147 insertions(+), 2 deletions(-) create mode 100644 docs/examples/stripe-webhook.mdx diff --git a/docs/examples/stripe-webhook.mdx b/docs/examples/stripe-webhook.mdx new file mode 100644 index 0000000000..65b81fa56c --- /dev/null +++ b/docs/examples/stripe-webhook.mdx @@ -0,0 +1,144 @@ +--- +title: "Trigger a task from a Stripe webhook events" +sidebarTitle: "Stripe webhook" +description: "This example demonstrates how to handle Stripe webhook events using Trigger.dev." +--- + +## Overview + +We will set up a webhook handler for incoming Stripe events. When a Stripe event is received, the handler will trigger a task that can perform an action based on the event type. + +## Key features + +- Handles Stripe webhook events +- Performs actions based on the event type (e.g., "checkout.session.completed") + +## Environment variables + +You'll need to configure the following environment variables for this example: + +- `STRIPE_WEBHOOK_SECRET` The secret key used to verify the Stripe webhook signature. +- `TRIGGER_API_URL` Your Trigger.dev API url: `https://api.trigger.dev` +- `TRIGGER_API_SECRET` Your Trigger.dev API secret. + +## Setting up a Stripe webhook handler + +To set up your endpoint, you'll need to create a webhook handler route that listens for POST requests and verifies the Stripe signature. + +Here are examples of how you can set up a handler using different frameworks: + + + +```ts Remix +// app/webhooks/stripe.ts +import { type ActionFunctionArgs, json } from "@remix-run/node"; +import type { stripeWebhook } from "src/trigger/stripe-webhook"; +import { tasks } from "@trigger.dev/sdk/v3"; +import stripe from "stripe"; + +export async function action({ request, params }: ActionFunctionArgs) { + if (request.method !== "POST") { + return json({ error: "Method not allowed" }, { status: 405 }); + } + + const signature = request.headers.get("stripe-signature"); + const payload = await request.text(); + + if (!signature || !payload) { + return json({ error: "Invalid Stripe payload/signature" }, { status: 400 }); + } + + try { + // Construct the Stripe event using the payload, signature, and webhook secret + const event = stripe.webhooks.constructEvent( + payload, + signature, + process.env.STRIPE_WEBHOOK_SECRET as string + ); + + console.log("Received Stripe event:", event); + + // Trigger the 'stripe-webhook' task with the constructed event + const { id } = await tasks.trigger("stripe-webhook", event); + + // Return a JSON response with the run ID of the triggered task + return json({ runId: id }); + } catch (e) { + console.error("Error processing Stripe webhook:", e); + return json({ error: e instanceof Error ? e.message : JSON.stringify(e) }, { status: 400 }); + } +} +``` + +```ts Nextjs +// app/api/stripe-webhook/route.ts +import { NextResponse } from "next/server"; +import { tasks } from "@trigger.dev/sdk/v3"; +import Stripe from "stripe"; +import { stripeWebhook } from "../../../trigger/stripe-webhook"; + +export async function POST(request: Request) { + const signature = request.headers.get("stripe-signature"); + const payload = await request.text(); + + if (!signature || !payload) { + return NextResponse.json( + { error: "Invalid Stripe payload/signature" }, + { + status: 400, + } + ); + } + + try { + const event = Stripe.webhooks.constructEvent( + payload, + signature, + process.env.STRIPE_WEBHOOK_SECRET as string + ); + + const { id } = await tasks.trigger("stripe-webhook", event); + + return NextResponse.json({ runId: id }); + } catch (e) { + console.error("Error processing Stripe webhook:", e); + return NextResponse.json( + { error: e instanceof Error ? e.message : JSON.stringify(e) }, + { status: 400 } + ); + } +} +``` + + + +## Task code + +This task listens for Stripe events and performs actions based on the `checkout.session.completed` event type: + +```ts trigger/stripe-webhook.ts +import { task } from "@trigger.dev/sdk/v3"; +import type stripe from "stripe"; + +export const stripeWebhook = task({ + id: "stripe-webhook", + run: async (payload: stripe.Event, { ctx }) => { + switch (payload.type) { + case "checkout.session.completed": { + //do stuff + } + } + }, +}); +``` + +## Testing your task locally + +To test everything is working you can use the Stripe CLI to send test events to your endpoint: + +1. Install the [Stripe CLI](https://stripe.com/docs/stripe-cli#install), and login +2. Follow the instructions to [test your handler](https://docs.stripe.com/webhooks#test-webhook). This will include a temporary `STRIPE_WEBHOOK_SECRET` that you can use to test your endpoint. +3. If your endpoint is set up correctly, you should see the Stripe events logged in your console with a status of 200. +4. Then, check the [Trigger.dev](https://cloud.trigger.dev) dashboard and you should see the successful run of the `stripe-webhook` task. + +For more information on setting up and testing Stripe webhooks, refer to the [Stripe Webhook Documentation](https://stripe.com/docs/webhooks). diff --git a/docs/examples/supabase-storage-upload.mdx b/docs/examples/supabase-storage-upload.mdx index edbc9ac634..de69960c29 100644 --- a/docs/examples/supabase-storage-upload.mdx +++ b/docs/examples/supabase-storage-upload.mdx @@ -57,8 +57,8 @@ export const supabaseStorageUpload = task({ await s3Client.send( new PutObjectCommand({ Bucket: bucket, - Key: objectKey, // The key is the file name - Body: videoFile, // The body is the video file + Key: objectKey, + Body: videoFile, }) ); logger.log(`Video uploaded to Supabase Storage bucket`, { objectKey }); diff --git a/docs/mint.json b/docs/mint.json index c60d59ae6a..5cb03ebcd1 100644 --- a/docs/mint.json +++ b/docs/mint.json @@ -279,6 +279,7 @@ "examples/open-ai-with-retrying", "examples/pdf-to-image", "examples/sharp-image-processing", + "examples/stripe-webhook", "examples/supabase-storage-upload", "examples/react-pdf", "examples/resend-email-sequence", From c998c60382d39e4c0c00d5a388e0d6934692ba17 Mon Sep 17 00:00:00 2001 From: D-K-P <8297864+D-K-P@users.noreply.github.com> Date: Mon, 23 Sep 2024 15:21:54 +0100 Subject: [PATCH 03/10] Copy tweaks --- docs/examples/supabase-storage-upload.mdx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/examples/supabase-storage-upload.mdx b/docs/examples/supabase-storage-upload.mdx index de69960c29..7277b25db2 100644 --- a/docs/examples/supabase-storage-upload.mdx +++ b/docs/examples/supabase-storage-upload.mdx @@ -1,12 +1,12 @@ --- -title: "Upload a video to Supabase Storage" +title: "Upload a video to Supabase Storage using S3" sidebarTitle: "Supabase Storage upload" description: "This example demonstrates how to download a video from a URL and upload it to Supabase Storage using Trigger.dev." --- ## Overview -This task downloads a video from a provided URL, saves it to a temporary file, and then uploads the video file to Supabase Storage. +This task downloads a video from a provided URL, saves it to a temporary file, and then uploads the video file to Supabase Storage using S3. ## Key features From 20cc1fd90383f079db51bb5ef1661fd9e394f0e4 Mon Sep 17 00:00:00 2001 From: D-K-P <8297864+D-K-P@users.noreply.github.com> Date: Mon, 23 Sep 2024 15:26:46 +0100 Subject: [PATCH 04/10] Typos --- docs/examples/stripe-webhook.mdx | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/examples/stripe-webhook.mdx b/docs/examples/stripe-webhook.mdx index 65b81fa56c..446ebbc0ec 100644 --- a/docs/examples/stripe-webhook.mdx +++ b/docs/examples/stripe-webhook.mdx @@ -1,17 +1,17 @@ --- -title: "Trigger a task from a Stripe webhook events" +title: "Trigger a task from Stripe webhook events" sidebarTitle: "Stripe webhook" description: "This example demonstrates how to handle Stripe webhook events using Trigger.dev." --- ## Overview -We will set up a webhook handler for incoming Stripe events. When a Stripe event is received, the handler will trigger a task that can perform an action based on the event type. +We will set up a webhook handler for incoming Stripe events. When an event is received, the handler will trigger a task that can perform an action based on the event type. ## Key features - Handles Stripe webhook events -- Performs actions based on the event type (e.g., "checkout.session.completed") +- Performs actions based on the event type (e.g. `checkout.session.completed`) ## Environment variables @@ -23,7 +23,7 @@ You'll need to configure the following environment variables for this example: ## Setting up a Stripe webhook handler -To set up your endpoint, you'll need to create a webhook handler route that listens for POST requests and verifies the Stripe signature. +First you'll need to create a webhook handler route that listens for POST requests and verifies the Stripe signature. Here are examples of how you can set up a handler using different frameworks: @@ -70,7 +70,7 @@ export async function action({ request, params }: ActionFunctionArgs) { } ``` -```ts Nextjs +```ts Next.js // app/api/stripe-webhook/route.ts import { NextResponse } from "next/server"; import { tasks } from "@trigger.dev/sdk/v3"; @@ -137,8 +137,8 @@ export const stripeWebhook = task({ To test everything is working you can use the Stripe CLI to send test events to your endpoint: 1. Install the [Stripe CLI](https://stripe.com/docs/stripe-cli#install), and login -2. Follow the instructions to [test your handler](https://docs.stripe.com/webhooks#test-webhook). This will include a temporary `STRIPE_WEBHOOK_SECRET` that you can use to test your endpoint. -3. If your endpoint is set up correctly, you should see the Stripe events logged in your console with a status of 200. +2. Follow the instructions to [test your handler](https://docs.stripe.com/webhooks#test-webhook). This will include a temporary `STRIPE_WEBHOOK_SECRET` that you can use for testing. +3. If your endpoint is set up correctly, you should see the Stripe events logged in your console with a status of `200`. 4. Then, check the [Trigger.dev](https://cloud.trigger.dev) dashboard and you should see the successful run of the `stripe-webhook` task. For more information on setting up and testing Stripe webhooks, refer to the [Stripe Webhook Documentation](https://stripe.com/docs/webhooks). From 09b0c9fbd6586f4059b50d984f4e0a130b62b9d7 Mon Sep 17 00:00:00 2001 From: D-K-P <8297864+D-K-P@users.noreply.github.com> Date: Mon, 23 Sep 2024 17:08:10 +0100 Subject: [PATCH 05/10] Updated stripe example to check for a specific event before triggering the task --- docs/examples/stripe-webhook.mdx | 147 ++++++++++++++++--------------- 1 file changed, 76 insertions(+), 71 deletions(-) diff --git a/docs/examples/stripe-webhook.mdx b/docs/examples/stripe-webhook.mdx index 446ebbc0ec..ccf688c540 100644 --- a/docs/examples/stripe-webhook.mdx +++ b/docs/examples/stripe-webhook.mdx @@ -6,76 +6,36 @@ description: "This example demonstrates how to handle Stripe webhook events usin ## Overview -We will set up a webhook handler for incoming Stripe events. When an event is received, the handler will trigger a task that can perform an action based on the event type. +This example shows how to set up a webhook handler for incoming Stripe events. The handler triggers a task when a `checkout.session.completed` event is received. This is easily customisable to handle other Stripe events. ## Key features -- Handles Stripe webhook events -- Performs actions based on the event type (e.g. `checkout.session.completed`) +- Shows how to create a Stripe webhook handler +- Triggers a task when a `checkout.session.completed` event is received ## Environment variables -You'll need to configure the following environment variables for this example: +You'll need to configure the following environment variables for this example to work: - `STRIPE_WEBHOOK_SECRET` The secret key used to verify the Stripe webhook signature. - `TRIGGER_API_URL` Your Trigger.dev API url: `https://api.trigger.dev` - `TRIGGER_API_SECRET` Your Trigger.dev API secret. -## Setting up a Stripe webhook handler +## Setting up the Stripe webhook handler -First you'll need to create a webhook handler route that listens for POST requests and verifies the Stripe signature. +First you'll need to create a [Stripe webhook](https://stripe.com/docs/webhooks) handler route that listens for POST requests and verifies the Stripe signature. Here are examples of how you can set up a handler using different frameworks: -```ts Remix -// app/webhooks/stripe.ts -import { type ActionFunctionArgs, json } from "@remix-run/node"; -import type { stripeWebhook } from "src/trigger/stripe-webhook"; -import { tasks } from "@trigger.dev/sdk/v3"; -import stripe from "stripe"; - -export async function action({ request, params }: ActionFunctionArgs) { - if (request.method !== "POST") { - return json({ error: "Method not allowed" }, { status: 405 }); - } - - const signature = request.headers.get("stripe-signature"); - const payload = await request.text(); - - if (!signature || !payload) { - return json({ error: "Invalid Stripe payload/signature" }, { status: 400 }); - } - - try { - // Construct the Stripe event using the payload, signature, and webhook secret - const event = stripe.webhooks.constructEvent( - payload, - signature, - process.env.STRIPE_WEBHOOK_SECRET as string - ); - - console.log("Received Stripe event:", event); - - // Trigger the 'stripe-webhook' task with the constructed event - const { id } = await tasks.trigger("stripe-webhook", event); - - // Return a JSON response with the run ID of the triggered task - return json({ runId: id }); - } catch (e) { - console.error("Error processing Stripe webhook:", e); - return json({ error: e instanceof Error ? e.message : JSON.stringify(e) }, { status: 400 }); - } -} -``` - ```ts Next.js // app/api/stripe-webhook/route.ts import { NextResponse } from "next/server"; import { tasks } from "@trigger.dev/sdk/v3"; import Stripe from "stripe"; -import { stripeWebhook } from "../../../trigger/stripe-webhook"; +import type { stripeCheckoutCompleted } from "@/trigger/stripe-checkout-completed"; +// 👆 **type-only** import export async function POST(request: Request) { const signature = request.headers.get("stripe-signature"); @@ -90,22 +50,71 @@ export async function POST(request: Request) { ); } - try { - const event = Stripe.webhooks.constructEvent( - payload, - signature, - process.env.STRIPE_WEBHOOK_SECRET as string - ); + const event = Stripe.webhooks.constructEvent( + payload, + signature, + process.env.STRIPE_WEBHOOK_SECRET as string + ); + + // Perform the check based on the event type + switch (event.type) { + case "checkout.session.completed": { + // Trigger the task only if the event type is "checkout.session.completed" + const { id } = await tasks.trigger( + "stripe-checkout-completed", + event + ); + return NextResponse.json({ runId: id }); + } + default: { + // Return a response indicating that the event is not handled + return NextResponse.json( + { message: "Event not handled" }, + { + status: 200, + } + ); + } + } +} +``` - const { id } = await tasks.trigger("stripe-webhook", event); +```ts Remix +// app/webhooks/stripe.ts +import { type ActionFunctionArgs, json } from "@remix-run/node"; +import type { stripeCheckoutCompleted } from "src/trigger/stripe-webhook"; +import { tasks } from "@trigger.dev/sdk/v3"; +import Stripe from "stripe"; - return NextResponse.json({ runId: id }); - } catch (e) { - console.error("Error processing Stripe webhook:", e); - return NextResponse.json( - { error: e instanceof Error ? e.message : JSON.stringify(e) }, - { status: 400 } - ); +export async function action({ request }: ActionFunctionArgs) { + // Validate the Stripe webhook payload + const signature = request.headers.get("stripe-signature"); + const payload = await request.text(); + + if (!signature || !payload) { + return json({ error: "Invalid Stripe payload/signature" }, { status: 400 }); + } + + const event = Stripe.webhooks.constructEvent( + payload, + signature, + process.env.STRIPE_WEBHOOK_SECRET as string + ); + + // Perform the check based on the event type + switch (event.type) { + case "checkout.session.completed": { + // Trigger the task only if the event type is "checkout.session.completed" + const { id } = await tasks.trigger( + "stripe-checkout-completed", + event + ); + return json({ runId: id }); + } + default: { + // Return a response indicating that the event is not handled + return json({ message: "Event not handled" }, { status: 200 }); + } } } ``` @@ -114,20 +123,16 @@ export async function POST(request: Request) { ## Task code -This task listens for Stripe events and performs actions based on the `checkout.session.completed` event type: +This task is triggered when a `checkout.session.completed` event is received from Stripe. ```ts trigger/stripe-webhook.ts import { task } from "@trigger.dev/sdk/v3"; import type stripe from "stripe"; -export const stripeWebhook = task({ - id: "stripe-webhook", - run: async (payload: stripe.Event, { ctx }) => { - switch (payload.type) { - case "checkout.session.completed": { - //do stuff - } - } +export const stripeCheckoutCompleted = task({ + id: "stripe-checkout-completed", + run: async (payload: stripe.Event, {}) => { + // Add your custom logic for handling the checkout.session.completed event here }, }); ``` From e1ae35347719c734441e5c17fba00d0991c9db0c Mon Sep 17 00:00:00 2001 From: D-K-P <8297864+D-K-P@users.noreply.github.com> Date: Mon, 23 Sep 2024 17:08:18 +0100 Subject: [PATCH 06/10] Simplified the storage example --- docs/examples/supabase-storage-upload.mdx | 30 +++++++---------------- 1 file changed, 9 insertions(+), 21 deletions(-) diff --git a/docs/examples/supabase-storage-upload.mdx b/docs/examples/supabase-storage-upload.mdx index 7277b25db2..c570c96a4d 100644 --- a/docs/examples/supabase-storage-upload.mdx +++ b/docs/examples/supabase-storage-upload.mdx @@ -18,20 +18,16 @@ This task downloads a video from a provided URL, saves it to a temporary file, a ```ts trigger/supabase-storage-upload.ts import { PutObjectCommand, S3Client } from "@aws-sdk/client-s3"; import { logger, task } from "@trigger.dev/sdk/v3"; -import fs from "fs/promises"; import fetch from "node-fetch"; -import os from "os"; -import path from "path"; // Initialize S3 client for Supabase Storage -// Update your .env file, and environment variables in the dashboard as instructed below const s3Client = new S3Client({ region: process.env.SUPABASE_REGION, // Your Supabase project's region e.g. "us-east-1" - endpoint: `https://${process.env.SUPABASE_PROJECT_ID}.supabase.co/storage/v1/s3`, // Your Supabase project ID + endpoint: `https://${process.env.SUPABASE_PROJECT_ID}.supabase.co/storage/v1/s3`, credentials: { // These credentials can be found in your supabase storage settings, under 'S3 access keys' - accessKeyId: process.env.SUPABASE_S3_ACCESS_KEY_ID ?? "", // Access key ID - secretAccessKey: process.env.SUPABASE_S3__SECRET_ACCESS_KEY ?? "", // Access key + accessKeyId: process.env.SUPABASE_ACCESS_KEY_ID ?? "", + secretAccessKey: process.env.SUPABASE_SECRET_ACCESS_KEY ?? "", }, }); @@ -40,32 +36,24 @@ export const supabaseStorageUpload = task({ run: async (payload: { videoUrl: string }) => { const { videoUrl } = payload; - // Generate temporary file path - const tempDirectory = os.tmpdir(); - const outputPath = path.join(tempDirectory, `video_${Date.now()}.mp4`); - - // Fetch the video and save it to a temporary file + // Fetch the video as an ArrayBuffer const response = await fetch(videoUrl); - const videoBuffer = await response.arrayBuffer(); - await fs.writeFile(outputPath, Buffer.from(videoBuffer)); + const videoArrayBuffer = await response.arrayBuffer(); + const videoBuffer = Buffer.from(videoArrayBuffer); - const videoFile = await fs.readFile(outputPath); // Read the video file const bucket = "my_bucket"; // Replace "my_bucket" with your bucket name + const objectKey = `video_${Date.now()}.mp4`; - // Upload the video to Supabase Storage - const objectKey = path.basename(outputPath); + // Upload the video directly to Supabase Storage await s3Client.send( new PutObjectCommand({ Bucket: bucket, Key: objectKey, - Body: videoFile, + Body: videoBuffer, }) ); logger.log(`Video uploaded to Supabase Storage bucket`, { objectKey }); - // Delete the temporary video file - await fs.unlink(outputPath); - // Return the video object key return { objectKey, From ff87911832ea086d2382ba1ab1c7e2dfb0906ac1 Mon Sep 17 00:00:00 2001 From: D-K-P <8297864+D-K-P@users.noreply.github.com> Date: Mon, 23 Sep 2024 17:08:24 +0100 Subject: [PATCH 07/10] Added examples to intro page --- docs/examples/intro.mdx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/examples/intro.mdx b/docs/examples/intro.mdx index 7de0967a27..ee1a2844b1 100644 --- a/docs/examples/intro.mdx +++ b/docs/examples/intro.mdx @@ -13,4 +13,6 @@ description: "Learn how to use Trigger.dev with these practical task examples." | [React to PDF](/examples/react-pdf) | Use `react-pdf` to generate a PDF and save it to Cloudflare R2. | | [Resend email sequence](/examples/resend-email-sequence) | Send a sequence of emails over several days using Resend with Trigger.dev. | | [Sharp image processing](/examples/sharp-image-processing) | Use Sharp to process an image and save it to Cloudflare R2. | +| [Stripe webhook](/examples/stripe-webhook) | Trigger a task from Stripe webhook events. | +| [Supabase Storage upload](/examples/supabase-storage-upload) | Download a video from a URL and upload it to Supabase Storage using S3. | | [Vercel AI SDK](/examples/vercel-ai-sdk) | Use Vercel AI SDK to generate text using OpenAI. | From e52a2727bcc2e7c0a97d8be0039c5a3c435bb64c Mon Sep 17 00:00:00 2001 From: D-K-P <8297864+D-K-P@users.noreply.github.com> Date: Mon, 23 Sep 2024 17:17:06 +0100 Subject: [PATCH 08/10] Added further instructions --- docs/examples/stripe-webhook.mdx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/examples/stripe-webhook.mdx b/docs/examples/stripe-webhook.mdx index ccf688c540..04fd1810cc 100644 --- a/docs/examples/stripe-webhook.mdx +++ b/docs/examples/stripe-webhook.mdx @@ -143,7 +143,8 @@ To test everything is working you can use the Stripe CLI to send test events to 1. Install the [Stripe CLI](https://stripe.com/docs/stripe-cli#install), and login 2. Follow the instructions to [test your handler](https://docs.stripe.com/webhooks#test-webhook). This will include a temporary `STRIPE_WEBHOOK_SECRET` that you can use for testing. -3. If your endpoint is set up correctly, you should see the Stripe events logged in your console with a status of `200`. -4. Then, check the [Trigger.dev](https://cloud.trigger.dev) dashboard and you should see the successful run of the `stripe-webhook` task. +3. When triggering the event, use the `checkout.session.completed` event type. With the Stripe CLI: `stripe trigger checkout.session.completed` +4. If your endpoint is set up correctly, you should see the Stripe events logged in your console with a status of `200`. +5. Then, check the [Trigger.dev](https://cloud.trigger.dev) dashboard and you should see the successful run of the `stripe-webhook` task. For more information on setting up and testing Stripe webhooks, refer to the [Stripe Webhook Documentation](https://stripe.com/docs/webhooks). From f5d342930c5463afb3ca48926554fdb4cc88dacb Mon Sep 17 00:00:00 2001 From: D-K-P <8297864+D-K-P@users.noreply.github.com> Date: Mon, 23 Sep 2024 17:29:59 +0100 Subject: [PATCH 09/10] Code improvements --- docs/examples/stripe-webhook.mdx | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/examples/stripe-webhook.mdx b/docs/examples/stripe-webhook.mdx index 04fd1810cc..c6f6b32622 100644 --- a/docs/examples/stripe-webhook.mdx +++ b/docs/examples/stripe-webhook.mdx @@ -19,7 +19,7 @@ You'll need to configure the following environment variables for this example to - `STRIPE_WEBHOOK_SECRET` The secret key used to verify the Stripe webhook signature. - `TRIGGER_API_URL` Your Trigger.dev API url: `https://api.trigger.dev` -- `TRIGGER_API_SECRET` Your Trigger.dev API secret. +- `TRIGGER_SECRET_KEY` Your Trigger.dev secret key ## Setting up the Stripe webhook handler @@ -62,7 +62,7 @@ export async function POST(request: Request) { // Trigger the task only if the event type is "checkout.session.completed" const { id } = await tasks.trigger( "stripe-checkout-completed", - event + event.data.object ); return NextResponse.json({ runId: id }); } @@ -80,7 +80,7 @@ export async function POST(request: Request) { ``` ```ts Remix -// app/webhooks/stripe.ts +// app/webhooks.stripe.ts import { type ActionFunctionArgs, json } from "@remix-run/node"; import type { stripeCheckoutCompleted } from "src/trigger/stripe-webhook"; import { tasks } from "@trigger.dev/sdk/v3"; @@ -107,7 +107,7 @@ export async function action({ request }: ActionFunctionArgs) { // Trigger the task only if the event type is "checkout.session.completed" const { id } = await tasks.trigger( "stripe-checkout-completed", - event + event.data.object ); return json({ runId: id }); } @@ -125,13 +125,13 @@ export async function action({ request }: ActionFunctionArgs) { This task is triggered when a `checkout.session.completed` event is received from Stripe. -```ts trigger/stripe-webhook.ts +```ts trigger/stripe-checkout-completed.ts import { task } from "@trigger.dev/sdk/v3"; import type stripe from "stripe"; export const stripeCheckoutCompleted = task({ id: "stripe-checkout-completed", - run: async (payload: stripe.Event, {}) => { + run: async (payload: stripe.Checkout.Session) => { // Add your custom logic for handling the checkout.session.completed event here }, }); From 0b2b961ae23b3e7b109bf4f3ed08ec1dc86b0f06 Mon Sep 17 00:00:00 2001 From: D-K-P <8297864+D-K-P@users.noreply.github.com> Date: Mon, 23 Sep 2024 17:35:49 +0100 Subject: [PATCH 10/10] Final tweaks --- docs/examples/stripe-webhook.mdx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/examples/stripe-webhook.mdx b/docs/examples/stripe-webhook.mdx index c6f6b32622..437ee52a5b 100644 --- a/docs/examples/stripe-webhook.mdx +++ b/docs/examples/stripe-webhook.mdx @@ -11,7 +11,7 @@ This example shows how to set up a webhook handler for incoming Stripe events. T ## Key features - Shows how to create a Stripe webhook handler -- Triggers a task when a `checkout.session.completed` event is received +- Triggers a task from your backend when a `checkout.session.completed` event is received ## Environment variables @@ -83,6 +83,7 @@ export async function POST(request: Request) { // app/webhooks.stripe.ts import { type ActionFunctionArgs, json } from "@remix-run/node"; import type { stripeCheckoutCompleted } from "src/trigger/stripe-webhook"; +// 👆 **type-only** import import { tasks } from "@trigger.dev/sdk/v3"; import Stripe from "stripe";