forked from dubinc/dub
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcron.ts
More file actions
88 lines (81 loc) · 2.42 KB
/
cron.ts
File metadata and controls
88 lines (81 loc) · 2.42 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
import { Client, Receiver } from "@upstash/qstash";
import Bottleneck from "bottleneck";
import { sendEmail } from "emails";
import ClicksExceeded from "emails/clicks-exceeded";
import LinksLimitAlert from "emails/links-limit";
import prisma from "./prisma";
import { WorkspaceProps } from "./types";
export const limiter = new Bottleneck({
maxConcurrent: 1, // maximum concurrent requests
minTime: 100, // minimum time between requests in ms
});
// we're using Upstash's Receiver to verify the request signature
export const receiver = new Receiver({
currentSigningKey: process.env.QSTASH_CURRENT_SIGNING_KEY || "",
nextSigningKey: process.env.QSTASH_NEXT_SIGNING_KEY || "",
});
export const qstash = new Client({
token: process.env.QSTASH_TOKEN || "",
});
export const verifySignature = async (req: Request) => {
const authHeader = req.headers.get("authorization");
// if we're on Vercel and:
// 1. there's no CRON_SECRET env var
// 2. request doesn't have the correct auth header,
// then return false
if (
process.env.VERCEL === "1" &&
(!process.env.CRON_SECRET ||
authHeader !== `Bearer ${process.env.CRON_SECRET}`)
) {
return false;
}
return true;
};
export const sendLimitEmail = async ({
emails,
workspace,
type,
}: {
emails: string[];
workspace: WorkspaceProps;
type:
| "firstUsageLimitEmail"
| "secondUsageLimitEmail"
| "firstLinksLimitEmail"
| "secondLinksLimitEmail";
}) => {
const percentage = Math.round(
(workspace.linksUsage / workspace.linksLimit) * 100,
);
return await Promise.allSettled([
emails.map((email) => {
limiter.schedule(() =>
sendEmail({
subject: type.endsWith("UsageLimitEmail")
? `${process.env.NEXT_PUBLIC_APP_NAME} Alert: Clicks Limit Exceeded`
: `${process.env.NEXT_PUBLIC_APP_NAME} Alert: ${
workspace.name
} has used ${percentage.toString()}% of its links limit for the month.`,
email,
react: type.endsWith("UsageLimitEmail")
? ClicksExceeded({
email,
workspace,
type: type as "firstUsageLimitEmail" | "secondUsageLimitEmail",
})
: LinksLimitAlert({
email,
workspace,
}),
}),
);
}),
prisma.sentEmail.create({
data: {
projectId: workspace.id,
type,
},
}),
]);
};