From e51caa3355c7ec68b854ad36bdf716e214219131 Mon Sep 17 00:00:00 2001 From: MK Date: Wed, 15 Apr 2026 21:02:00 +0800 Subject: [PATCH] feat: redirect vp-setup.void.app to setup.viteplus.dev Add global Void middleware that 301-redirects requests on the default `vp-setup.void.app` host to the canonical custom domain `setup.viteplus.dev`, preserving path and query. Other hosts (custom domain, localhost, preview subdomains) pass through untouched. --- middleware/01.redirect-to-custom-domain.ts | 16 ++++++++++ tests/redirect.test.ts | 34 ++++++++++++++++++++++ 2 files changed, 50 insertions(+) create mode 100644 middleware/01.redirect-to-custom-domain.ts create mode 100644 tests/redirect.test.ts diff --git a/middleware/01.redirect-to-custom-domain.ts b/middleware/01.redirect-to-custom-domain.ts new file mode 100644 index 0000000..bc3ad16 --- /dev/null +++ b/middleware/01.redirect-to-custom-domain.ts @@ -0,0 +1,16 @@ +import { defineMiddleware } from "void"; + +const LEGACY_HOST = "vp-setup.void.app"; +const CANONICAL_ORIGIN = "https://setup.viteplus.dev"; + +export function buildRedirectTarget(host: string | undefined, requestUrl: string): string | null { + if (host !== LEGACY_HOST) return null; + const url = new URL(requestUrl); + return `${CANONICAL_ORIGIN}${url.pathname}${url.search}`; +} + +export default defineMiddleware(async (c, next) => { + const target = buildRedirectTarget(c.req.header("host"), c.req.url); + if (target) return c.redirect(target, 301); + await next(); +}); diff --git a/tests/redirect.test.ts b/tests/redirect.test.ts new file mode 100644 index 0000000..a7f572a --- /dev/null +++ b/tests/redirect.test.ts @@ -0,0 +1,34 @@ +import { describe, expect, it } from "vite-plus/test"; +import { buildRedirectTarget } from "../middleware/01.redirect-to-custom-domain"; + +describe("buildRedirectTarget", () => { + it("redirects legacy host root to canonical origin", () => { + expect(buildRedirectTarget("vp-setup.void.app", "https://vp-setup.void.app/")).toBe( + "https://setup.viteplus.dev/", + ); + }); + + it("preserves path and query string", () => { + expect( + buildRedirectTarget("vp-setup.void.app", "https://vp-setup.void.app/?tag=v1.2.3&arch=arm64"), + ).toBe("https://setup.viteplus.dev/?tag=v1.2.3&arch=arm64"); + }); + + it("returns null for the custom domain (no redirect)", () => { + expect(buildRedirectTarget("setup.viteplus.dev", "https://setup.viteplus.dev/")).toBeNull(); + }); + + it("returns null for localhost during dev", () => { + expect(buildRedirectTarget("localhost:5173", "http://localhost:5173/")).toBeNull(); + }); + + it("returns null when host header is missing", () => { + expect(buildRedirectTarget(undefined, "https://vp-setup.void.app/")).toBeNull(); + }); + + it("does not match preview/staging subdomains", () => { + expect( + buildRedirectTarget("vp-setup-staging.void.app", "https://vp-setup-staging.void.app/"), + ).toBeNull(); + }); +});