mirror of
https://github.com/stack-auth/stack.git
synced 2026-07-20 21:29:36 +08:00
Fix Elysia production compatibility
This commit is contained in:
parent
f33cb4cbc5
commit
6f3960e076
@ -5,6 +5,7 @@ export const config = {
|
||||
maxDuration: 60,
|
||||
};
|
||||
|
||||
export default function handler(request: Request): Response | Promise<Response> {
|
||||
return app.handle(request);
|
||||
}
|
||||
// Vercel treats a default-exported function as the legacy Node.js `(request,
|
||||
// response)` handler contract. Export the Elysia app itself so Vercel detects
|
||||
// its Web-standard `fetch` handler and forwards the returned Response.
|
||||
export default app;
|
||||
|
||||
@ -4,6 +4,7 @@ import { NextNotFoundError } from "@/lib/runtime/navigation";
|
||||
import { parseCookieHeader, requestContextALS, type RequestContext } from "@/lib/runtime/request-context";
|
||||
import { node } from "@elysiajs/node";
|
||||
import { getEnvVariable, getNodeEnvironment } from "@hexclave/shared/dist/utils/env";
|
||||
import { captureError } from "@hexclave/shared/dist/utils/errors";
|
||||
import { Elysia } from "elysia";
|
||||
import { runRequestPipeline } from "./middleware";
|
||||
import { createBackendRequest } from "./backend-request";
|
||||
@ -39,6 +40,13 @@ export const app = new Elysia({
|
||||
const pathname = new URL(request.url).pathname;
|
||||
console.log(`[Elysia] ${request.method} ${pathname} ${set.status} ${elapsedMilliseconds}ms`);
|
||||
})
|
||||
.onError(({ error }) => {
|
||||
// Smart route handlers sanitize their own errors. This is the final boundary
|
||||
// for errors from raw routes and framework code, which Elysia would otherwise
|
||||
// return to the client verbatim.
|
||||
captureError("elysia-request-handler", error);
|
||||
return internalServerErrorResponse();
|
||||
})
|
||||
.get("/", () => htmlResponse(homeHtml()))
|
||||
.get("/dev-stats", () => htmlResponse(devStatsHtml()))
|
||||
.get("/health/error-handler-debug", () => htmlResponse(errorHandlerDebugHtml()))
|
||||
@ -132,9 +140,6 @@ export async function dispatch(request: Request) {
|
||||
finalResponse.headers.set(key, value);
|
||||
}
|
||||
}
|
||||
if (pipeline.middlewareRewrite != null) {
|
||||
finalResponse.headers.set("x-middleware-rewrite", pipeline.middlewareRewrite);
|
||||
}
|
||||
return withGlobalHeaders(finalResponse);
|
||||
}
|
||||
|
||||
@ -164,6 +169,38 @@ function htmlResponse(body: string, status = 200) {
|
||||
}));
|
||||
}
|
||||
|
||||
function internalServerErrorResponse() {
|
||||
return withGlobalHeaders(new Response("Internal Server Error", {
|
||||
status: 500,
|
||||
headers: {
|
||||
"content-type": "text/plain; charset=utf-8",
|
||||
},
|
||||
}));
|
||||
}
|
||||
|
||||
import.meta.vitest?.test("unhandled errors do not expose their message", async ({ expect }) => {
|
||||
const response = internalServerErrorResponse();
|
||||
|
||||
expect(response.status).toBe(500);
|
||||
expect(await response.text()).toBe("Internal Server Error");
|
||||
expect(response.headers.get("x-content-type-options")).toBe("nosniff");
|
||||
});
|
||||
|
||||
import.meta.vitest?.test("API version migrations do not expose their internal rewrite", async ({ expect }) => {
|
||||
const { vi } = import.meta.vitest!;
|
||||
vi.stubEnv("HEXCLAVE_ARTIFICIAL_DEVELOPMENT_DELAY_MS", "0");
|
||||
vi.stubEnv("STACK_ARTIFICIAL_DEVELOPMENT_DELAY_MS", "0");
|
||||
|
||||
try {
|
||||
const response = await app.handle(new Request("http://localhost/api/v2beta1/migration-tests/smart-route-handler"));
|
||||
|
||||
expect(response.status).toBe(200);
|
||||
expect(response.headers.get("x-middleware-rewrite")).toBeNull();
|
||||
} finally {
|
||||
vi.unstubAllEnvs();
|
||||
}
|
||||
});
|
||||
|
||||
function homeHtml() {
|
||||
const devStatsLink = getNodeEnvironment() === "development"
|
||||
? `<br><a href="/dev-stats">Dev Stats</a><br>`
|
||||
|
||||
@ -51,7 +51,6 @@ export type PipelineResult = {
|
||||
corsHeadersInit?: HeadersInit,
|
||||
dispatchPath: string,
|
||||
mergedHeaders: Headers,
|
||||
middlewareRewrite?: string,
|
||||
originalUrl: string,
|
||||
shortCircuitResponse?: Response,
|
||||
};
|
||||
@ -133,7 +132,6 @@ export async function runRequestPipeline(request: Request): Promise<PipelineResu
|
||||
corsHeadersInit,
|
||||
dispatchPath,
|
||||
mergedHeaders,
|
||||
middlewareRewrite: dispatchPath === url.pathname ? undefined : dispatchPath,
|
||||
originalUrl: request.url,
|
||||
};
|
||||
}
|
||||
|
||||
@ -52,7 +52,10 @@ describe("SmartRouteHandler", () => {
|
||||
"headers": Headers { <some fields may have been hidden> },
|
||||
}
|
||||
`);
|
||||
expect(response.headers.get("x-middleware-rewrite")).toBe(`/api/migrations/v2beta2/migration-tests/smart-route-handler`);
|
||||
// The version migration is internal routing state. Next.js strips this
|
||||
// implementation header in production, so the Elysia transport must not
|
||||
// expose the rewritten path either.
|
||||
expect(response.headers.get("x-middleware-rewrite")).toBeNull();
|
||||
});
|
||||
|
||||
it("should return 200 with queryParam", async ({ expect }) => {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user