Skip to content

Commit

Permalink
Merge branch 'main' into utm-templates
Browse files Browse the repository at this point in the history
  • Loading branch information
steven-tey authored Oct 14, 2024
2 parents 98a78c7 + c3722c8 commit e5e0927
Show file tree
Hide file tree
Showing 17 changed files with 342 additions and 113 deletions.
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
import { getDomainViaEdge } from "@/lib/planetscale/get-domain-via-edge";
import { Background, Footer, Nav, NavMobile } from "@dub/ui";
import { constructMetadata } from "@dub/utils";
import { redirect } from "next/navigation";

export const runtime = "edge";

Expand All @@ -12,17 +10,7 @@ export const metadata = constructMetadata({
noIndex: true,
});

export default async function NotFoundLinkPage({
params,
}: {
params: { domain: string };
}) {
const domain = await getDomainViaEdge(params.domain);

if (domain?.notFoundUrl) {
redirect(domain.notFoundUrl);
}

export default async function NotFoundLinkPage() {
return (
<main className="flex min-h-screen flex-col justify-between">
<NavMobile />
Expand Down
20 changes: 15 additions & 5 deletions apps/web/lib/middleware/link.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import {
userAgent,
} from "next/server";
import { getLinkViaEdge } from "../planetscale";
import { getDomainViaEdge } from "../planetscale/get-domain-via-edge";
import { RedisLinkProps } from "../types";

export default async function LinkMiddleware(
Expand Down Expand Up @@ -56,11 +57,20 @@ export default async function LinkMiddleware(
const linkData = await getLinkViaEdge(domain, key);

if (!linkData) {
// short link not found, rewrite to not-found page
// TODO: log 404s (https://github.com/dubinc/dub/issues/559)
return NextResponse.rewrite(new URL(`/not-found/${domain}`, req.url), {
headers: DUB_HEADERS,
});
// check if domain has notFoundUrl configured
const domainData = await getDomainViaEdge(domain);
if (domainData?.notFoundUrl) {
return NextResponse.redirect(domainData.notFoundUrl, {
headers: {
...DUB_HEADERS,
"X-Robots-Tag": "googlebot: noindex",
},
});
} else {
return NextResponse.rewrite(new URL("/notfoundlink", req.url), {
headers: DUB_HEADERS,
});
}
}

// format link to fit the RedisLinkProps interface
Expand Down
71 changes: 71 additions & 0 deletions apps/web/scripts/update-not-found.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import { prisma } from "@/lib/prisma";
import "dotenv-flow/config";

async function main() {
const domains = await prisma.domain.findMany({
where: {
notFoundUrl: null,
project: {
plan: {
not: "free",
},
},
links: {
some: {
key: "_root",
url: {
not: "",
},
},
},
},
select: {
id: true,
slug: true,
notFoundUrl: true,
project: {
select: {
slug: true,
plan: true,
},
},
links: {
select: {
key: true,
url: true,
},
where: {
key: "_root",
},
},
},
take: 10,
orderBy: {
createdAt: "asc",
},
});

const updatedDomains = await Promise.all(
domains.map((domain) => {
return prisma.domain.update({
where: { id: domain.id },
data: { notFoundUrl: domain.links[0].url },
select: {
id: true,
slug: true,
notFoundUrl: true,
project: {
select: {
slug: true,
plan: true,
},
},
},
});
}),
);

console.table(updatedDomains);
}

main();
2 changes: 1 addition & 1 deletion packages/cli/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ https://github.com/user-attachments/assets/2ce9fe51-68ab-4e6d-b08d-4da09c17f90e

| Command | Description |
| ------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `dub login [key]` | Configure your workspace API key |
| `dub login` | Log into the DUB platform |
| `dub config` | See your configured workspace credentials |
| `dub domains` | Configure your workspace domain |
| `dub shorten [url] [key]` | Create a short link. You can preemptively pass the URL and the generated short link key, or go through the CLI prompts. |
Expand Down
2 changes: 2 additions & 0 deletions packages/cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
"start": "node dist/index.js "
},
"dependencies": {
"@badgateway/oauth2-client": "^2.4.2",
"chalk": "^5.3.0",
"commander": "^11.1.0",
"configstore": "^6.0.0",
Expand All @@ -48,6 +49,7 @@
"json-colorizer": "^2.2.2",
"nanoid": "^5.0.7",
"node-fetch": "^3.3.2",
"open": "^10.1.0",
"ora": "^7.0.1",
"package-json": "^8.1.1",
"prompts": "^2.4.2",
Expand Down
86 changes: 86 additions & 0 deletions packages/cli/src/api/callback.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import { DubConfig } from "@/types";
import { setConfig } from "@/utils/config";
import { logger } from "@/utils/logger";
import { OAuth2Client } from "@badgateway/oauth2-client";
import chalk from "chalk";
import * as http from "http";
import { Ora } from "ora";
import * as url from "url";

interface OAuthCallbackServerProps {
oauthClient: OAuth2Client;
redirectUri: string;
spinner: Ora;
codeVerifier: string;
}

export function oauthCallbackServer({
oauthClient,
redirectUri,
codeVerifier,
spinner,
}: OAuthCallbackServerProps) {
const server = http.createServer(async (req, res) => {
const reqUrl = url.parse(req.url || "", true);

if (reqUrl.pathname !== "/callback" || req.method !== "GET") {
res.writeHead(404);
res.end("Not found");
return;
}

const code = reqUrl.query.code as string;

if (!code) {
res.writeHead(400);
res.end(
"Authorization code not found. Please start the login process again.",
);

return;
}

try {
spinner.text = "Verifying";

const { accessToken, refreshToken, expiresAt } =
await oauthClient.authorizationCode.getToken({
code,
redirectUri,
codeVerifier,
});

spinner.text = "Configuring";

const configInfo: DubConfig = {
access_token: accessToken.trim(),
refresh_token: refreshToken,
expires_at: expiresAt ? Date.now() + expiresAt * 1000 : null,
domain: "dub.sh",
};

await setConfig(configInfo);
spinner.succeed("Configuration completed");

logger.info("");
logger.info(chalk.green("Logged in successfully!"));
logger.info("");

res.writeHead(200, { "Content-Type": "text/html" });
res.end("Authentication successful! You can close this window.");
} catch (error) {
res.writeHead(500, { "Content-Type": "text/html" });
res.end("An error occurred during authentication. Please try again.");
} finally {
server.close();
process.exit(0);
}
});

setTimeout(() => {
server.close();
process.exit(0);
}, 300000);

server.listen(4587);
}
4 changes: 2 additions & 2 deletions packages/cli/src/api/domains.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export async function getDomains() {
const config = await getConfig();

const dub = new Dub({
token: config.key,
token: config.access_token,
});

const [{ result: domainsResponse }, defaultDomainsResponse] =
Expand All @@ -16,7 +16,7 @@ export async function getDomains() {
fetch("https://api.dub.co/domains/default", {
method: "GET",
headers: {
Authorization: `Bearer ${config.key}`,
Authorization: `Bearer ${config.access_token}`,
"Content-Type": "application/json",
},
}),
Expand Down
2 changes: 1 addition & 1 deletion packages/cli/src/api/links.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ export async function createLink({ url, key }: { url: string; key: string }) {
const config = await getConfig();

const dub = new Dub({
token: config.key,
token: config.access_token,
});

return await dub.links.create({
Expand Down
5 changes: 2 additions & 3 deletions packages/cli/src/commands/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,12 @@ import ora from "ora";

export const config = new Command()
.name("config")
.description("See your configured workspace credentials")
.description("See your configured credentials")
.action(async () => {
const spinner = ora("Getting config file").start();
const spinner = ora("Getting config").start();

try {
const configInfo = await getConfig();

spinner.succeed("Configuration file successfully retrieved");

logger.info("");
Expand Down
7 changes: 3 additions & 4 deletions packages/cli/src/commands/domains.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { getDomains } from "@/api/domains";
import { setConfig } from "@/utils/config";
import { handleError } from "@/utils/handle-error";
import { logger } from "@/utils/logger";
import chalk from "chalk";
import { Command } from "commander";
import Configstore from "configstore";
import ora from "ora";
import prompts from "prompts";
import { z } from "zod";
Expand Down Expand Up @@ -56,10 +56,9 @@ export const domains = new Command()
},
);

const getconfig = new Configstore("dub-cli");
getconfig.set("domain", options.domain);

setConfig({ domain: options.domain });
spinner.succeed("Done");

logger.info("");
logger.info(`${chalk.green("Success!")} Configuration updated.`);
logger.info("");
Expand Down
5 changes: 3 additions & 2 deletions packages/cli/src/commands/links.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import ora from "ora";

export const links = new Command()
.command("links")
.description("Search for links in your Dub workspace.")
.description("Search for links in your Dub workspace")
.option("-s, --search [search]", "Search term to filter links by")
.option("-l, --limit [limit]", "Number of links to fetch")
.action(async ({ search, limit }) => {
Expand All @@ -16,13 +16,14 @@ export const links = new Command()
const spinner = ora("Fetching links").start();

const dub = new Dub({
token: config.key,
token: config.access_token,
});

const links = await dub.links.list({
search,
pageSize: limit ? parseInt(limit) : 10,
});

spinner.stop();

const formattedLinks = links.result.map((link) => ({
Expand Down
Loading

0 comments on commit e5e0927

Please sign in to comment.