forked from dubinc/dub
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathupstash.ts
More file actions
114 lines (104 loc) · 2.84 KB
/
upstash.ts
File metadata and controls
114 lines (104 loc) · 2.84 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
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
import { getDomainWithoutWWW, isIframeable } from "@dub/utils";
import { Ratelimit } from "@upstash/ratelimit";
import { Redis } from "@upstash/redis";
import {
DomainProps,
LinkProps,
RedisDomainProps,
RedisLinkProps,
} from "./types";
// Initiate Redis instance by connecting to REST URL
export const redis = new Redis({
url: process.env.UPSTASH_REDIS_REST_URL || "",
token: process.env.UPSTASH_REDIS_REST_TOKEN || "",
});
export const ratelimitRedis = new Redis({
url:
process.env.RATELIMIT_UPSTASH_REDIS_REST_URL ||
process.env.UPSTASH_REDIS_REST_URL ||
"",
token:
process.env.RATELIMIT_UPSTASH_REDIS_REST_TOKEN ||
process.env.UPSTASH_REDIS_REST_TOKEN ||
"",
});
// Create a new ratelimiter, that allows 10 requests per 10 seconds by default
export const ratelimit = (
requests: number = 10,
seconds:
| `${number} ms`
| `${number} s`
| `${number} m`
| `${number} h`
| `${number} d` = "10 s",
) => {
return new Ratelimit({
redis: ratelimitRedis,
limiter: Ratelimit.slidingWindow(requests, seconds),
analytics: true,
prefix: "dub",
});
};
/**
* Recording metatags that were generated via `/api/metatags`
* If there's an error, it will be logged to a separate redis list for debugging
**/
export async function recordMetatags(url: string, error: boolean) {
if (url === "https://github.com/dubinc/dub") {
// don't log metatag generation for default URL
return null;
}
if (error) {
return await ratelimitRedis.zincrby("metatags-error-zset", 1, url);
}
const domain = getDomainWithoutWWW(url);
return await ratelimitRedis.zincrby("metatags-zset", 1, domain);
}
export async function formatRedisLink(
link: LinkProps,
): Promise<RedisLinkProps> {
const {
id,
domain,
url,
password,
proxy,
rewrite,
expiresAt,
ios,
android,
geo,
projectId,
} = link;
const hasPassword = password && password.length > 0 ? true : false;
return {
id,
url,
...(hasPassword && { password: true }),
...(proxy && { proxy: true }),
...(rewrite && {
rewrite: true,
iframeable: await isIframeable({ url, requestDomain: domain }),
}),
...(expiresAt && { expiresAt: new Date(expiresAt) }),
...(ios && { ios }),
...(android && { android }),
...(geo && { geo: geo as object }),
...(projectId && { projectId }), // projectId can be undefined for anonymous links
};
}
export async function formatRedisDomain(
domain: DomainProps,
): Promise<RedisDomainProps> {
const { id, slug, target: url, type, projectId } = domain;
return {
id,
...(url && { url }), // on free plans you cannot set a root domain redirect, hence URL is undefined
...(url &&
type === "rewrite" && {
rewrite: true,
iframeable: await isIframeable({ url, requestDomain: slug }),
}),
projectId,
};
}