Files
Hanzo AI b827b3a7bd rebrand: Papermark → Hanzo Dataroom across user-facing surfaces
108 files: README, marketing copy, page titles, meta tags, footer
text, email templates, .env.example, UI strings. URLs swapped
from papermark.com/papermark.io to dataroom.hanzo.ai.

Internal identifiers left intact per repo policy: localStorage
keys (papermark.email/papermark.name/last_papermark_login —
changing them logs users out), type field names
(papermarkUserId), internal helper symbols (PAPERMARK_HEADERS,
PapermarkSparkle component, isPapermarkUrl helper),
internal-only filenames. LLM.md retains 'Upstream: Papermark'
attribution line. Per-locale .po translations regenerate from
source on the next lingui-extract CI run.

DB migrations untouched (append-only history; rewriting them
breaks installed schemas). LICENSE stays AGPL-3.0.
2026-06-07 12:23:40 -07:00

94 lines
2.5 KiB
TypeScript

import { NextFetchEvent, NextRequest, NextResponse } from "next/server";
import AppMiddleware from "@/lib/middleware/app";
import { BLOCKED_PATHNAMES } from "./lib/constants";
import IncomingWebhookMiddleware, {
isWebhookPath,
} from "./lib/middleware/incoming-webhooks";
import InsightsMiddleware from "./lib/middleware/insights";
function isAnalyticsPath(path: string) {
const pattern = /^\/ingest\/.*/;
return pattern.test(path);
}
// App domains that should NOT be treated as custom domains
const APP_DOMAINS = [
"localhost",
"dataroom.hanzo.ai",
"hanzo.ai",
".vercel.app",
];
function isCustomDomain(host: string) {
if (process.env.NODE_ENV === "development") {
return host?.includes(".local") || host?.includes("dataroom.hanzo.dev");
}
return !APP_DOMAINS.some((d) =>
d.startsWith(".") ? host?.endsWith(d) : host?.includes(d),
);
}
export const config = {
matcher: [
/*
* Match all paths except for:
* 1. /api/ routes
* 2. /_next/ (Next.js internals)
* 3. /_static (inside /public)
* 4. /_vercel (Vercel internals)
* 5. /favicon.ico, /sitemap.xml, /robots.txt (static files)
*/
"/((?!api/|_next/|_static|vendor|_icons|_vercel|favicon.ico|sitemap.xml|robots.txt).*)",
],
};
export default async function middleware(req: NextRequest, ev: NextFetchEvent) {
const path = req.nextUrl.pathname;
const host = req.headers.get("host");
if (isAnalyticsPath(path)) {
return InsightsMiddleware(req);
}
// Handle incoming webhooks
if (isWebhookPath(host)) {
return IncomingWebhookMiddleware(req);
}
// For custom domains, rewrite to domain viewer routes
// NOTE: DomainMiddleware is dynamically imported to avoid pulling ioredis
// into the Edge Runtime bundle (Edge Runtime has no TCP/net APIs)
if (isCustomDomain(host || "")) {
const { default: DomainMiddleware } = await import(
"@/lib/middleware/domain"
);
return DomainMiddleware(req);
}
// Handle standard app paths
if (
!path.startsWith("/view/") &&
!path.startsWith("/verify") &&
!path.startsWith("/unsubscribe") &&
!path.startsWith("/notification-preferences") &&
!path.startsWith("/auth/email")
) {
return AppMiddleware(req);
}
// Check for blocked pathnames in view routes
if (
path.startsWith("/view/") &&
(BLOCKED_PATHNAMES.some((blockedPath) => path.includes(blockedPath)) ||
path.includes("."))
) {
const url = req.nextUrl.clone();
url.pathname = "/404";
return NextResponse.rewrite(url, { status: 404 });
}
return NextResponse.next();
}