🚀 发送新星通知的 4 大方法⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️ TL;DR

2025-05-28

🚀 发送新星通知的 4 大方法⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️

TL;DR

TL;DR

在上一篇文章中,我讨论了如何创建GitHub 星星监控器
在本文中,我将向您展示如何每天获取新星星的信息。
我们将学习:

  • 如何构建通用系统来创建和使用提供程序。
  • 如何使用提供程序发送通知。
  • 使用不同提供商的不同用例。

通知


您的后台工作平台🔌

Trigger.dev 是一个开源库,可让您使用 NextJS、Remix、Astro 等为您的应用程序创建和监控长时间运行的作业!

 

给我们星星

请帮我们点个星🥹。
这有助于我们创作更多类似的文章💖

为 Trigger.dev 仓库加星标⭐️


让我们开始吧🔥

我们将创建不同的提供商,以便在有新星出现时通知我们。我们将设置EmailSMSSlackDiscord通知。

我们的目标是让每个贡献者都能在未来轻松地贡献更多服务。

每个提供商都会有一组不同的参数,有些只有参数API keys,有些只有电话号码,具体取决于提供商。

为了验证这些密钥,让我们安装zod;它是一个定义模式并根据模式检查数据的很棒的库。

您可以通过运行以下命令开始:

npm install zod --save
Enter fullscreen mode Exit fullscreen mode

完成后,创建一个名为 的新文件夹providers,然后在其中创建一个名为 的新文件register.provider.ts

这是该文件的代码:

import {Schema} from "zod";

export function registerProvider<T>(
    name: string,
    options: {active: boolean},
    validation: Schema<T>,
    run: (libName: string, stars: number, values: T) => Promise<void>
) {
    // if not active, we can just pass an empty function, nothing will run
    if (!options.active) {
        return () => {};
    }

    // will validate and remove unnecessary values (Security wise)
    const env = validation.parse(process.env);

    // return the function we will run at the end of the job
    return async (libName: string, stars: number) => {
        console.log(`Running provider ${name}`);
        await run(libName, stars, env as T);
        console.log(`Finished running provider ${name}`);
    }
}
Enter fullscreen mode Exit fullscreen mode

代码并不多,但可能有点复杂。

我们首先创建一个名为 的新函数registerProvider。该函数具有一个泛型类型T,这基本上是我们所需的环境变量。

然后我们还有 4 个参数:

  • 名称 - 可以是TwilioDiscordSlack或 中的任意一个Resend
  • 选项 - 目前,一个参数是提供商是否处于活动状态?
  • 验证 - 在这里,我们zod在 .env 文件中传递所需参数的模式。
  • run - 它实际上用于发送通知。请注意,传递给它的参数是库名称、星数以及我们在validation

然后我们有实际的功能:

首先,我们检查服务提供者是否处于活动状态。如果不是,则发送一个空函数。

然后,我们验证并提取我们在模式中指定的变量。如果变量缺失,zod则会发送错误,并且不会让应用程序运行。

最后,我们返回一个获取库名称和星星数量并触发通知的函数。

在我们的文件夹中providers,创建一个名为的新文件providers.ts并在其中添加以下代码:

export const Providers = [];
Enter fullscreen mode Exit fullscreen mode

稍后,我们将在那里添加所有提供商。


修改 TriggerDev 作业

本文是上一篇关于创建GitHub 星星监视器的文章的延续。

编辑该文件jobs/sync.stars.ts,在文件底部添加如下代码:

const triggerNotification = client.defineJob({
    id: "trigger-notification",
    name: "Trigger Notification",
    version: "0.0.1",
    trigger: invokeTrigger({
      schema: z.object({
        stars: z.number(),
        library: z.string(),
        providerNumber: z.number(),
      })
    }),
    run: async (payload, io, ctx) => {
      await io.runTask("trigger-notification", async () => {
        return Providers[payload.providerNumber](payload.library, payload.stars);
      });
    }
});
Enter fullscreen mode Exit fullscreen mode

此项工作获取星号、库名称和提供商编号,并从先前定义的提供商触发针对特定提供商的通知。

现在,让我们继续修改,getStars在函数末尾添加以下代码:

for (let i = 0; i < Providers.length; i++) {
      await triggerNotification.invoke(payload.name + '-' + i, {
          library: payload.name,
          stars: stargazers_count - payload.previousStarCount,
          providerNumber: i,
      });
  }
Enter fullscreen mode Exit fullscreen mode

这将触发每个图书馆的通知。

完整页面代码:

import { cronTrigger, invokeTrigger } from "@trigger.dev/sdk";
import { client } from "@/trigger";
import { prisma } from "../../helper/prisma";
import axios from "axios";
import { z } from "zod";
import {Providers} from "@/providers/providers";

// Your first job
// This Job will be triggered by an event, log a joke to the console, and then wait 5 seconds before logging the punchline.
client.defineJob({
  id: "sync-stars",
  name: "Sync Stars Daily",
  version: "0.0.1",
  // Run a cron every day at 23:00 AM
  trigger: cronTrigger({
    cron: "0 23 * * *",
  }),
  run: async (payload, io, ctx) => {
    const repos = await io.runTask("get-stars", async () => {
      // get all libraries and current amount of stars
      return await prisma.repository.groupBy({
        by: ["name"],
        _sum: {
          stars: true,
        },
      });
    });

    //loop through all repos and invoke the Job that gets the latest stars
    for (const repo of repos) {
      await getStars.invoke(repo.name, {
        name: repo.name,
        previousStarCount: repo?._sum?.stars || 0,
      });
    }
  },
});

const getStars = client.defineJob({
  id: "get-latest-stars",
  name: "Get latest stars",
  version: "0.0.1",
  // Run a cron every day at 23:00 AM
  trigger: invokeTrigger({
    schema: z.object({
      name: z.string(),
      previousStarCount: z.number(),
    }),
  }),
  run: async (payload, io, ctx) => {
    const stargazers_count = await io.runTask("get-stars", async () => {
      const {data} = await axios.get(`https://api.github.com/repos/${payload.name}`, {
        headers: {
          authorization: `token ${process.env.TOKEN}`,
        },
      });
      return data.stargazers_count as number;
    });

    await io.runTask("upsert-stars", async () => {
      await prisma.repository.upsert({
        where: {
          name_day_month_year: {
            name: payload.name, month: new Date().getMonth() + 1, year: new Date().getFullYear(), day: new Date().getDate(),
          },
        }, update: {
          stars: stargazers_count - payload.previousStarCount,
        }, create: {
          name: payload.name, stars: stargazers_count - payload.previousStarCount, month: new Date().getMonth() + 1, year: new Date().getFullYear(), day: new Date().getDate(),
        },
      });
    });

    for (let i = 0; i < Providers.length; i++) {
        await triggerNotification.invoke(payload.name + '-' + i, {
            library: payload.name,
            stars: stargazers_count - payload.previousStarCount,
            providerNumber: i,
        });
    }
  },
});

const triggerNotification = client.defineJob({
    id: "trigger-notification",
    name: "Trigger Notification",
    version: "0.0.1",
    trigger: invokeTrigger({
      schema: z.object({
        stars: z.number(),
        library: z.string(),
        providerNumber: z.number(),
      })
    }),
    run: async (payload, io, ctx) => {
      await io.runTask("trigger-notification", async () => {
        return Providers[payload.providerNumber](payload.library, payload.stars);
      });
    }
});
Enter fullscreen mode Exit fullscreen mode

现在,有趣的部分🎉

让我们继续创建我们的提供商!

首先创建一个名为providers/lists


1. Discord

不和谐

创建一个名为的新文件discord.provider.ts并添加以下代码:

import {object, string} from "zod";
import {registerProvider} from "@/providers/register.provider";
import axios from "axios";

export const DiscordProvider = registerProvider(
    "discord",
    {active: true},
    object({
        DISCORD_WEBHOOK_URL: string(),
    }),
    async (libName, stars, values) => {
        await axios.post(values.DISCORD_WEBHOOK_URL, {content: `The library ${libName} has ${stars} new stars!`});
    }
);
Enter fullscreen mode Exit fullscreen mode

如您所见,我们正在使用registerProvider来创建一个名为 DiscordProvider 的新提供程序

  • 我们将名称设置为discord
  • 我们将其设置为活跃
  • 我们指定我们需要一个名为的环境变量DISCORD_WEBHOOK_URL
  • 我们使用 Axios 的简单 post 命令将信息添加到检查中。

要得到DISCORD_WEBHOOK_URL

  1. 前往您的 Discord 服务器
  2. 点击其中一个频道的编辑
  3. 前往Integrations
  4. 点击Create Webhook
  5. 点击创建的 webhook,然后点击Copy webhook URL

编辑我们.env的根项目上的文件并添加

SLACK_WEBHOOK_URL=<your copied url>
Enter fullscreen mode Exit fullscreen mode

蜘蛛侠


2. Slack

松弛

创建一个名为的新文件slack.provider.ts并添加以下代码:

import {object, string} from "zod";
import {registerProvider} from "@/providers/register.provider";
import axios from "axios";

export const SlackProvider = registerProvider(
    "slack",
    {active: true},
    object({
        SLACK_WEBHOOK_URL: string(),
    }),
    async (libName, stars, values) => {
        await axios.post(values.SLACK_WEBHOOK_URL, {text: `The library ${libName} has ${stars} new stars!`});
    }
);
Enter fullscreen mode Exit fullscreen mode

如您所见,我们正在使用registerProvider来创建一个名为 SlackProvider 的新提供程序

  • 我们将名称设置为slack
  • 我们将其设置为活跃
  • 我们指定我们需要一个名为的环境变量SLACK_WEBHOOK_URL
  • 我们使用 Axios 的简单 post 命令将信息添加到检查中。

要得到SLACK_WEBHOOK_URL

  1. 使用以下 URL 创建一个新的 Slack 应用程序:https://api.slack.com/apps? new_app=1
  2. 选择第一个选项:“从头开始”
  3. 输入一个应用程序名称(任意),并在 Slack 中指定您想要添加通知的工作区。点击Create App
  4. 在“添加特性和功能”中,点击Incoming hook
  5. 在激活传入 Webhook 中,将其更改为“开”。
  6. 点击“将新的 Webhook 添加到工作区”。
  7. 选择您想要的频道并点击“允许”。
  8. 复制 webhook URL。

编辑我们.env的根项目上的文件并添加

SLACK_WEBHOOK_URL=<your copied url>
Enter fullscreen mode Exit fullscreen mode

SlackBot


3. 电子邮件

电子邮件

您可以使用不同类型的电子邮件提供商。例如,我们将使用Resend来发送电子邮件。

为此,让我们在项目上安装重新发送:

npm install resend --save
Enter fullscreen mode Exit fullscreen mode

创建一个名为的新文件resend.provider.ts并添加以下代码:

import {object, string} from "zod";
import {registerProvider} from "@/providers/register.provider";
import axios from "axios";
import { Resend } from 'resend';

export const ResendProvider = registerProvider(
    "resend",
    {active: true},
    object({
        RESEND_API_KEY: string(),
    }),
    async (libName, stars, values) => {
        const resend = new Resend(values.RESEND_API_KEY);
        await resend.emails.send({
            from: "Eric Allam <eric@trigger.dev>",
            to: ['eric@trigger.dev'],
            subject: 'New GitHub stars',
            html: `The library ${libName} has ${stars} new stars!`,
        });
    }
);
Enter fullscreen mode Exit fullscreen mode

如您所见,我们正在使用registerProvider创建一个名为 ResendProvider 的新提供程序

  • 我们将名称设置为resend
  • 我们将其设置为活跃
  • 我们指定我们需要一个名为的环境变量RESEND_API_KEY
  • 我们使用 Resend 库向我们自己发送一封包含新星星数量的电子邮件。

要得到RESEND_API_KEY

  1. 在以下网址创建新帐户:https://resend.com
  2. 转到API Keys或使用此 URL https://resend.com/api-keys
  3. 点击“+ 创建 API 密钥”,添加密钥名称,选择“发送访问权限”,并使用默认的“所有域”。点击“添加”。
  4. 复制 API 密钥。

编辑我们.env的根项目上的文件并添加

RESEND_API_KEY=<your API key>
Enter fullscreen mode Exit fullscreen mode

埃里克·阿拉姆


4. 短信

Twilio

SMS 稍微复杂一些,因为它们需要多个变量。

为此,让我们在项目上安装 Twilio:

npm install twilio --save
Enter fullscreen mode Exit fullscreen mode

创建一个名为的新文件twilio.provider.ts并添加以下代码:

import {object, string} from "zod";
import {registerProvider} from "@/providers/register.provider";
import axios from "axios";
import client from 'twilio';

export const TwilioProvider = registerProvider(
    "twilio",
    {active: true},
    object({
        TWILIO_SID: string(),
        TWILIO_AUTH_TOKEN: string(),
        TWILIO_FROM_NUMBER: string(),
        TWILIO_TO_NUMBER: string(),
    }),
    async (libName, stars, values) => {
        const twilio = client(values.TWILIO_SID, values.TWILIO_AUTH_TOKEN);
        await twilio.messages.create({
            body: `The library ${libName} has ${stars} new stars!`,
            from: values.TWILIO_FROM_NUMBER,
            to: values.TWILIO_TO_NUMBER,
        });
    }
);
Enter fullscreen mode Exit fullscreen mode

如您所见,我们正在使用registerProvider来创建一个名为 TwilioProvider 的新提供程序

  • 我们将名称设置为twilio
  • 我们将其设置为活跃
  • 我们指定需要的环境变量TWILIO_SID、、TWILIO_AUTH_TOKENTWILIO_FROM_NUMBERTWILIO_TO_NUMBER
  • 我们使用 Twiliocreate功能发送短信。

得到TWILIO_SIDTWILIO_AUTH_TOKENTWILIO_FROM_NUMBERTWILIO_TO_NUMBER

  1. 在https://twilio.com创建新帐户
  2. 标记您想使用它来发送短信。
  3. 点击“获取电话号码”
  4. 复制“帐户 SID”、“授权令牌”和“我的 Twilio 电话号码”

编辑我们.env的根项目上的文件并添加

TWILIO_SID=<your SID key>
TWILIO_AUTH_TOKEN=<your AUTH TOKEN key>
TWILIO_FROM_NUMBER=<your FROM number>
TWILIO_TO_NUMBER=<your TO number>
Enter fullscreen mode Exit fullscreen mode

Twilio短信


创建新的提供商

如您所见,现在创建提供程序非常容易。

您还可以使用开源社区来创建新的提供商,因为他们只需要在providers/list目录中创建一个新文件。

最后要做的是编辑您的providers.ts文件并添加所有提供商。

import {DiscordProvider} from "@/providers/list/discord.provider";
import {ResendProvider} from "@/providers/list/resend.provider";
import {SlackProvider} from "@/providers/list/slack.provider";
import {TwilioProvider} from "@/providers/list/twilio.provider";

export const Providers = [
    DiscordProvider,
    ResendProvider,
    SlackProvider,
    TwilioProvider,
];
Enter fullscreen mode Exit fullscreen mode

随意创建更多推送通知、网络推送通知、应用内通知等提供程序。

你就完成了🥳


让我们联系吧!🔌

作为开源开发者,我们诚邀您加入我们的 社区 ,贡献力量并与维护人员互动。欢迎访问我们的 GitHub 代码库 ,贡献代码并创建与 Trigger.dev 相关的问题。

本教程的源代码可以在这里找到:

https://github.com/triggerdotdev/blog/tree/main/stars-monitor-notifications

感谢您的阅读!

文章来源:https://dev.to/triggerdotdev/top-4-ways-to-send-notifications-about-new-stars-1cgb
PREV
🚀 使用 NextJS、Replicate 和 Trigger.dev 将您的脸变成超级英雄🦸🏻‍♂️ TL;DR
NEXT
🔥 将 NextJS 提升到新的水平:创建 GitHub 星星监视器 🤯