From ea42d68ae77609239325ddbc44e6652e4b01aab8 Mon Sep 17 00:00:00 2001 From: mwln Date: Fri, 4 Sep 2026 20:59:43 -0300 Subject: [PATCH] fix: detect eve dev-server readiness url --- .changeset/sveltekit-dev-server-ready-line.md | 5 +++ .../src/public/sveltekit/dev-server.test.ts | 42 ++++++++++++++++++- .../eve/src/public/sveltekit/dev-server.ts | 14 +++++-- 3 files changed, 56 insertions(+), 5 deletions(-) create mode 100644 .changeset/sveltekit-dev-server-ready-line.md diff --git a/.changeset/sveltekit-dev-server-ready-line.md b/.changeset/sveltekit-dev-server-ready-line.md new file mode 100644 index 0000000000..ea0665b81b --- /dev/null +++ b/.changeset/sveltekit-dev-server-ready-line.md @@ -0,0 +1,5 @@ +--- +"eve": patch +--- + +The SvelteKit plugin now proxies `/eve/v1/**` to the URL on eve's `server listening at ...` line. Before, it took the first URL in the dev server's output, so a documentation link in a dependency warning could become the proxy target and serve 404s. diff --git a/packages/eve/src/public/sveltekit/dev-server.test.ts b/packages/eve/src/public/sveltekit/dev-server.test.ts index 4f2ad69def..36b56c3beb 100644 --- a/packages/eve/src/public/sveltekit/dev-server.test.ts +++ b/packages/eve/src/public/sveltekit/dev-server.test.ts @@ -1,6 +1,46 @@ import { describe, expect, it } from "vitest"; -import { normalizeDevServerRegistry } from "./dev-server.js"; +import { extractEveDevServerOrigin, normalizeDevServerRegistry } from "./dev-server.js"; + +describe("extractEveDevServerOrigin", () => { + it("returns undefined when the chunk has no readiness line", () => { + expect( + extractEveDevServerOrigin("resolving rolldown... https://rolldown.rs/guide"), + ).toBeUndefined(); + }); + + it("returns the origin from the readiness line", () => { + expect(extractEveDevServerOrigin("[DEV] server listening at http://127.0.0.1:50036/\n")).toBe( + "http://127.0.0.1:50036", + ); + }); + + it("does not depend on the CLI tag", () => { + expect(extractEveDevServerOrigin("server listening at http://127.0.0.1:50036/\n")).toBe( + "http://127.0.0.1:50036", + ); + }); + + it("ignores unrelated URLs that appear before the readiness line", () => { + expect( + extractEveDevServerOrigin( + "warn: https://rolldown.rs/guide\n[DEV] server listening at http://127.0.0.1:50036/\n", + ), + ).toBe("http://127.0.0.1:50036"); + }); + + it("accepts a chunk that ends at the URL without a trailing newline", () => { + expect(extractEveDevServerOrigin("[DEV] server listening at http://127.0.0.1:50036")).toBe( + "http://127.0.0.1:50036", + ); + }); + + it("accepts an IPv6 loopback origin", () => { + expect(extractEveDevServerOrigin("[DEV] server listening at http://[::1]:50036/")).toBe( + "http://[::1]:50036", + ); + }); +}); describe("normalizeDevServerRegistry", () => { it("normalizes a well-formed record and canonicalizes the origin", () => { diff --git a/packages/eve/src/public/sveltekit/dev-server.ts b/packages/eve/src/public/sveltekit/dev-server.ts index 135f463f2f..957f4ac3ef 100644 --- a/packages/eve/src/public/sveltekit/dev-server.ts +++ b/packages/eve/src/public/sveltekit/dev-server.ts @@ -17,7 +17,7 @@ const DEV_SERVER_STALE_LOCK_MS = 30_000; const EVE_CACHE_DIRECTORY_NAME = ".eve"; const EVE_SVELTEKIT_DEV_SERVER_FILE_NAME = "sveltekit-dev-server.json"; const EVE_SVELTEKIT_DEV_SERVER_LOCK_FILE_NAME = "sveltekit-dev-server.lock"; -const LOCAL_SERVER_URL_PATTERN = /https?:\/\/(?:\[[^\]\s]+\]|[^\s/:[\]]+)(?::\d+)?/; +const EVE_DEV_SERVER_READY_PATTERN = /server listening at (https?:\/\/[^\s]+)/; export interface EveProcessHandle { readonly origin: string; @@ -162,6 +162,12 @@ function createEveBinaryPath(): string { return join(resolvePackageRoot(), "bin", "eve.js"); } +export function extractEveDevServerOrigin(chunk: string): string | undefined { + const url = EVE_DEV_SERVER_READY_PATTERN.exec(chunk)?.[1]; + if (url === undefined) return undefined; + return normalizeOrigin(url); +} + function startServerProcess(input: { readonly args: readonly string[]; readonly command: string; @@ -203,11 +209,11 @@ function startServerProcess(input: { let resolved = false; const handleOutput = (chunk: Buffer) => { if (resolved) return; - const match = LOCAL_SERVER_URL_PATTERN.exec(chunk.toString("utf8")); - if (match === null) return; + const origin = extractEveDevServerOrigin(chunk.toString("utf8")); + if (origin === undefined) return; resolved = true; cleanup(); - resolvePromise({ origin: normalizeOrigin(match[0]), process: child }); + resolvePromise({ origin, process: child }); }; child.once("error", handleError);