diff --git a/middleware/02.redirect-vite-plus.ts b/middleware/02.redirect-vite-plus.ts new file mode 100644 index 0000000..5431dff --- /dev/null +++ b/middleware/02.redirect-vite-plus.ts @@ -0,0 +1,20 @@ +import { defineMiddleware } from "void"; + +// The vite.plus vanity domain exists purely as an installer entry point: +// curl https://vite.plus | sh -> shell installer +// irm https://vite.plus/ps1 | iex -> PowerShell installer +const INSTALL_HOST = "vite.plus"; +const INSTALL_SH = "https://viteplus.dev/install.sh"; +const INSTALL_PS1 = "https://viteplus.dev/install.ps1"; + +export function buildViteplusRedirect(host: string | undefined, requestUrl: string): string | null { + if (host !== INSTALL_HOST) return null; + const path = new URL(requestUrl).pathname.replace(/\/+$/, ""); + return path === "/ps1" ? INSTALL_PS1 : INSTALL_SH; +} + +export default defineMiddleware(async (c, next) => { + const target = buildViteplusRedirect(c.req.header("host"), c.req.url); + if (target) return c.redirect(target, 302); + await next(); +}); diff --git a/tests/redirect-vite-plus.test.ts b/tests/redirect-vite-plus.test.ts new file mode 100644 index 0000000..d602e98 --- /dev/null +++ b/tests/redirect-vite-plus.test.ts @@ -0,0 +1,50 @@ +import { describe, expect, it } from "vite-plus/test"; +import { buildViteplusRedirect } from "../middleware/02.redirect-vite-plus"; + +describe("buildViteplusRedirect", () => { + it("redirects the bare domain to the shell installer", () => { + expect(buildViteplusRedirect("vite.plus", "https://vite.plus/")).toBe( + "https://viteplus.dev/install.sh", + ); + }); + + it("redirects /ps1 to the PowerShell installer", () => { + expect(buildViteplusRedirect("vite.plus", "https://vite.plus/ps1")).toBe( + "https://viteplus.dev/install.ps1", + ); + }); + + it("tolerates a trailing slash on /ps1", () => { + expect(buildViteplusRedirect("vite.plus", "https://vite.plus/ps1/")).toBe( + "https://viteplus.dev/install.ps1", + ); + }); + + it("redirects any other path to the shell installer", () => { + expect(buildViteplusRedirect("vite.plus", "https://vite.plus/anything")).toBe( + "https://viteplus.dev/install.sh", + ); + }); + + it("ignores query strings when picking the target", () => { + expect(buildViteplusRedirect("vite.plus", "https://vite.plus/?ref=docs")).toBe( + "https://viteplus.dev/install.sh", + ); + }); + + it("returns null for the canonical download host", () => { + expect(buildViteplusRedirect("setup.viteplus.dev", "https://setup.viteplus.dev/")).toBeNull(); + }); + + it("returns null for the legacy host (handled by its own middleware)", () => { + expect(buildViteplusRedirect("vp-setup.void.app", "https://vp-setup.void.app/")).toBeNull(); + }); + + it("returns null for localhost during dev", () => { + expect(buildViteplusRedirect("localhost:5173", "http://localhost:5173/ps1")).toBeNull(); + }); + + it("returns null when the host header is missing", () => { + expect(buildViteplusRedirect(undefined, "https://vite.plus/")).toBeNull(); + }); +});