From a65ad428e634909b7a2fed65c1f9391a7a4d3d2d Mon Sep 17 00:00:00 2001 From: Julian Cuni Date: Sat, 2 May 2026 17:50:13 +0200 Subject: [PATCH] fix(auth): resolve relative directus URL against window origin The runtime config supports relative paths like /api so the SPA can run same-origin in dev (Vite proxy) and stage/prod (Traefik). createDirectus from @directus/sdk calls new URL(...) internally, which throws on relative URLs. Resolve in toAbsoluteUrl() before handing to the SDK: '/api' -> 'http://localhost:5173/api' (dev) 'https://api.example.com' -> passes through unchanged Caught at runtime; typecheck/build don't surface this since the SDK treats its url arg as a string. --- src/auth/client.ts | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/auth/client.ts b/src/auth/client.ts index 6447cd9..130a43a 100644 --- a/src/auth/client.ts +++ b/src/auth/client.ts @@ -25,8 +25,23 @@ export type Schema = {}; type DirectusClient = ReturnType; +/** + * Resolve a (possibly relative) URL against the current page origin. + * + * Runtime config supports relative paths like `/api` because the SPA always + * runs same-origin to its backends. The Directus SDK, however, calls + * `new URL(...)` internally and requires an absolute URL — so we resolve + * before handing it over. + * + * - `'/api'` → `'http://localhost:5173/api'` (in dev) + * - `'https://api.example.com'` → `'https://api.example.com/'` (passes through) + */ +function toAbsoluteUrl(maybeRelative: string): string { + return new URL(maybeRelative, window.location.origin).toString(); +} + function buildClient(directusUrl: string) { - return createDirectus(directusUrl) + return createDirectus(toAbsoluteUrl(directusUrl)) .with(authentication('cookie', { credentials: 'include', autoRefresh: true })) .with(rest({ credentials: 'include' })); }