Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion app/services/site/domain-request-service.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import * as domainRequestService from "./domain-request-service";

// Mock the domain import
vi.mock("@/lib/domain", () => ({
RESERVED_SUBDOMAINS: ["app", "www", "blog", "api"]
RESERVED_SUBDOMAINS: ["app", "www", "blog", "api", "sites"]
}));

describe("DomainRequestService", () => {
Expand Down
3 changes: 2 additions & 1 deletion lib/domain.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ export const RESERVED_SUBDOMAINS = [
"settings",
"legal",
"admin",
"studio"
"studio",
"sites"
];

/**
Expand Down
31 changes: 31 additions & 0 deletions middleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { NextResponse } from "next/server";
import { isHomePagePath, isPublicPath } from "./app/services/public-path-service";
import {
getGhUsernameFromRequest,
getHostnameFromRequest,
getReservedSubdomainFromRequest,
isVercelPreview
} from "./app/services/site/domain-request-service";
Expand Down Expand Up @@ -31,12 +32,35 @@ export const config = {
export default withAuth(
async function middleware(req: NextRequestWithAuth) {
const path = req.nextUrl.pathname;
const host = (await getHostnameFromRequest(req))?.toLowerCase();
const sessionUser = req.nextauth.token?.user as SessionUser | undefined;

// Helper constants for domain names, makes it easy to change later
const isDevelopment = process.env.NODE_ENV === "development";
const APP_HOST = isDevelopment ? "app.market.local:3000" : "app.market.dev";
const HOMEPAGE_HOST = isDevelopment ? "studio.market.local:3000" : "studio.market.dev";
const SITES_HOST = isDevelopment ? "sites.market.local:3000" : "sites.market.dev";

if (host === SITES_HOST) {
if (path.startsWith("/api")) {
return NextResponse.next();
}

const segments = path.split("/").filter(Boolean);
const [handle, ...rest] = segments;

if (!handle) {
const redirectUrl = new URL(req.url);
redirectUrl.host = HOMEPAGE_HOST;
redirectUrl.pathname = "/";
return NextResponse.redirect(redirectUrl);
}

const remainingPath = rest.length > 0 ? `/${rest.join("/")}` : "";
const rewritePath = `/maintainer-site/${handle}${remainingPath}${req.nextUrl.search}`;

return NextResponse.rewrite(new URL(rewritePath, req.url));
}

// --- Decision 1: Is this the main "app" subdomain? ---
const reservedSubdomain = await getReservedSubdomainFromRequest(req);
Expand Down Expand Up @@ -135,6 +159,13 @@ export default withAuth(
return true;
}

const currentHost = (await getHostnameFromRequest(req))?.toLowerCase();
const isDevelopment = process.env.NODE_ENV === "development";
const sitesHost = isDevelopment ? "sites.market.local:3000" : "sites.market.dev";
if (currentHost === sitesHost) {
return true;
}

// Check if the path is in the public paths list
if (await isPublicPath(req.nextUrl.pathname)) {
return true;
Expand Down