diff --git a/README.md b/README.md index 442e5c6..600724a 100644 --- a/README.md +++ b/README.md @@ -1 +1,18 @@ # Custom Domain Ready + +## How to configure the project +1. Create a new storage edge config. +2. Create a new vercel project and import configuration-api. +3. Create a new project and import custom-domain-proxy. +4. Connect the storage to the project custom-domain-proxy. +5. Add the required env vars for the configuration-api + +```bash +VERCEL_CUSTOM_DOMAIN_PROXY_EDGE_CONFIG_ID= # You can find the edge config id when you click on the storage +VERCEL_TEAM_ID= # Your vercel team id +VERCEL_PROJECT_ID= # must be the project id of the custom-domain-proxy +AUTH_BEARER_TOKEN= # create your own bearer token that can access the projects +``` + +6. Add a new domain using the configuration-api +7. Finish the domain configuration \ No newline at end of file diff --git a/apps/configuration-api/.env.local.example b/apps/configuration-api/.env.local.example index a9b50c5..191875f 100644 --- a/apps/configuration-api/.env.local.example +++ b/apps/configuration-api/.env.local.example @@ -1,3 +1,4 @@ VERCEL_CUSTOM_DOMAIN_PROXY_EDGE_CONFIG_ID= VERCEL_TEAM_ID= +VERCEL_PROJECT_ID= AUTH_BEARER_TOKEN= \ No newline at end of file diff --git a/apps/configuration-api/app/api/assign/route.ts b/apps/configuration-api/app/api/assign/route.ts index 14f233b..3318c36 100644 --- a/apps/configuration-api/app/api/assign/route.ts +++ b/apps/configuration-api/app/api/assign/route.ts @@ -1,5 +1,6 @@ -import { addDomainToEdgeConfig, getEdgeconfigItem, updateEdgeConfigItem } from "@customdomainready/sdk"; +import { addDomainToEdgeConfig, getEdgeconfigItem, updateEdgeConfigItem, removeDomainFromEdgeConfig, getAllItemsFromEdgeConfig } from "@customdomainready/sdk"; +import { NextResponse } from "next/server"; import { z } from "zod"; const customDomainSchema = z.object({ @@ -8,6 +9,29 @@ const customDomainSchema = z.object({ destination: z.string() }) +export async function GET( + req: Request, +) { + try { + const response = await getAllItemsFromEdgeConfig(process.env.VERCEL_CUSTOM_DOMAIN_PROXY_EDGE_CONFIG_ID!, process.env.VERCEL_TEAM_ID, process.env.AUTH_BEARER_TOKEN) + console.log(response) + return NextResponse.json({ + response: response.map((item: any) => ({ + id: item.key, + sourceDomain: `https://${item.key.split('-')[0].replace(/_/g, '.')}`, + slug: item.key.split('-').slice(1).join('/').replace(/_/g, '.'), + destinationPath: item.value, + })) + }); + } catch (error) { + console.error(error) + + return new Response("Internal Server Error", { status: 500 }) + } +} + + + export async function PATCH( req: Request ) { @@ -15,18 +39,19 @@ export async function PATCH( const body = await req.json() const payload = customDomainSchema.parse(body) - const sourceURL = new URL(payload.domain, payload.slug) + const domainWithoutProtocol = payload.domain.replace(/^https?:\/\//, ''); + const key = `${domainWithoutProtocol.replace(/\./g, '_')}${payload.slug.replace(/\//g, '-')}`; + console.log(key) // validate if key already exist and if yes update it instead of creating - const existingDomain = await getEdgeconfigItem(sourceURL.toString(), process.env.VERCEL_CUSTOM_DOMAIN_PROXY_EDGE_CONFIG_ID!, process.env.VERCEL_TEAM_ID, process.env.AUTH_BEARER_TOKEN) - console.log(existingDomain) + const existingDomain = await getEdgeconfigItem(key, process.env.VERCEL_CUSTOM_DOMAIN_PROXY_EDGE_CONFIG_ID!, process.env.VERCEL_TEAM_ID, process.env.AUTH_BEARER_TOKEN); if (existingDomain){ - const updateResponse = await updateEdgeConfigItem(sourceURL.toString(), payload.destination, process.env.VERCEL_CUSTOM_DOMAIN_PROXY_EDGE_CONFIG_ID!, process.env.VERCEL_TEAM_ID, process.env.AUTH_BEARER_TOKEN) - console.log(updateResponse) + const updateResponse = await updateEdgeConfigItem(key, payload.destination, process.env.VERCEL_CUSTOM_DOMAIN_PROXY_EDGE_CONFIG_ID!, process.env.VERCEL_TEAM_ID, process.env.AUTH_BEARER_TOKEN); + console.log(updateResponse); } else { - const createResponse = await addDomainToEdgeConfig(sourceURL.toString(), payload.destination, process.env.VERCEL_CUSTOM_DOMAIN_PROXY_EDGE_CONFIG_ID!, process.env.VERCEL_TEAM_ID, process.env.AUTH_BEARER_TOKEN) - console.log(createResponse) + const createResponse = await addDomainToEdgeConfig(key, payload.destination, process.env.VERCEL_CUSTOM_DOMAIN_PROXY_EDGE_CONFIG_ID!, process.env.VERCEL_TEAM_ID, process.env.AUTH_BEARER_TOKEN); + console.log(createResponse); } return new Response('created', { status: 201}) @@ -38,4 +63,38 @@ export async function PATCH( return new Response(null, { status: 500 }) } -} \ No newline at end of file +} + +export async function DELETE( + req: Request +) { + try { + const body = await req.json(); + const payload = customDomainSchema.parse(body); + + + const domainWithoutProtocol = payload.domain.replace(/^https?:\/\//, ''); + const key = `${domainWithoutProtocol.replace(/\./g, '_')}${payload.slug.replace(/\//g, '-')}`; + console.log(key) + + const existingDomain = await getEdgeconfigItem(key, process.env.VERCEL_CUSTOM_DOMAIN_PROXY_EDGE_CONFIG_ID!, process.env.VERCEL_TEAM_ID, process.env.AUTH_BEARER_TOKEN); + + if (existingDomain) { + const deleteResponse = await removeDomainFromEdgeConfig(key, process.env.VERCEL_CUSTOM_DOMAIN_PROXY_EDGE_CONFIG_ID!, process.env.VERCEL_TEAM_ID, process.env.AUTH_BEARER_TOKEN); + console.log(deleteResponse); + return new Response('deleted', { status: 204 }); + } else { + return new Response('Domain not found', { status: 404 }); + } + } catch (error) { + console.log(error); + if (error instanceof z.ZodError) { + return new Response(JSON.stringify(error.issues), { status: 422 }); + } + + return new Response(null, { status: 500 }); + } +} + + + \ No newline at end of file diff --git a/apps/configuration-api/app/api/domain/route.ts b/apps/configuration-api/app/api/domain/route.ts index 31c7923..7280cf1 100644 --- a/apps/configuration-api/app/api/domain/route.ts +++ b/apps/configuration-api/app/api/domain/route.ts @@ -1,4 +1,4 @@ -import { addDomainToVercel } from "@customdomainready/sdk"; +import { addDomainToVercel, getDomains, getAllItemsFromEdgeConfig } from "@customdomainready/sdk"; import { NextResponse } from "next/server"; import * as z from "zod" @@ -17,16 +17,18 @@ export async function POST( const domain = payload.domain; + // Check if the domain already exists + const existingDomains = await getDomains(process.env.VERCEL_PROJECT_ID!, process.env.VERCEL_TEAM_ID, process.env.AUTH_BEARER_TOKEN); + if (existingDomains.domains.some((d: any) => d.name === domain)) { + return new Response("Domain already exists", { status: 200 }); + } + const response = await addDomainToVercel(domain, process.env.VERCEL_PROJECT_ID!, process.env.VERCEL_TEAM_ID, process.env.AUTH_BEARER_TOKEN); if (response.error) { return new Response(response.error.message, { status: 400 }) } - if (response.code === 409) { - return new Response("Domain already exists", { status: 409 }) - } - return NextResponse.json({ response }); @@ -36,3 +38,5 @@ export async function POST( return new Response("Internal Server Error", { status: 500 }) } } + + diff --git a/apps/configuration-api/app/page.tsx b/apps/configuration-api/app/page.tsx index 0560186..a7661f5 100644 --- a/apps/configuration-api/app/page.tsx +++ b/apps/configuration-api/app/page.tsx @@ -3,7 +3,7 @@ import CustomDomainConfig from "@/components/custom-domain-config" export default function Home() { return (