1import { matchers, routes, type Transform, type VercelConfig } from "@vercel/config/v1";
2
3const ROUTER_HOST = "app.t3.codes";
4const HOSTED_WEB_CHANNEL_COOKIE = "t3code_web_channel";
5const LATEST_ORIGIN = "https://latest.app.t3.codes";
6const NIGHTLY_ORIGIN = "https://nightly.app.t3.codes";
7const CLEAN_CHANNEL_QUERY_TRANSFORMS = [
8 {
9 type: "request.query",
10 op: "delete",
11 target: { key: "channel" },
12 },
13] satisfies Transform[];
14
15function channelCookie(channel: "latest" | "nightly"): string {
16 return [
17 `${HOSTED_WEB_CHANNEL_COOKIE}=${channel}`,
18 "Path=/",
19 "Max-Age=31536000",
20 "HttpOnly",
21 "Secure",
22 "SameSite=Lax",
23 ].join("; ");
24}
25
26export const config: VercelConfig = {
27 buildCommand:
28 'vp run --filter @t3tools/web build && node ../../scripts/apply-web-brand-assets.ts --channel "${VITE_HOSTED_APP_CHANNEL:-latest}"',
29 git: {
30 deploymentEnabled: false,
31 },
32 installCommand:
33 "npm install -g vite-plus && vp install --ignore-scripts --filter '@t3tools/scripts...' --filter '@t3tools/web...'",
34 routes: [
35 {
36 src: "/__t3code/channel",
37 has: [matchers.query("channel", "nightly")],
38 transforms: CLEAN_CHANNEL_QUERY_TRANSFORMS,
39 headers: {
40 Location: "/",
41 "Set-Cookie": channelCookie("nightly"),
42 },
43 status: 302,
44 },
45 {
46 src: "/__t3code/channel",
47 transforms: CLEAN_CHANNEL_QUERY_TRANSFORMS,
48 headers: {
49 Location: "/",
50 "Set-Cookie": channelCookie("latest"),
51 },
52 status: 302,
53 },
54 {
55 src: "/(.*)",
56 has: [matchers.host(ROUTER_HOST), matchers.cookie(HOSTED_WEB_CHANNEL_COOKIE, "nightly")],
57 dest: `${NIGHTLY_ORIGIN}/$1`,
58 },
59 {
60 src: "/(.*)",
61 has: [matchers.host(ROUTER_HOST)],
62 dest: `${LATEST_ORIGIN}/$1`,
63 },
64 ],
65 rewrites: [routes.rewrite("/(.*)", "/index.html")],
66};