Files
tessera-ctl/apps/web/src/lib/api.ts
T
schalli c42ab5dc6f
Tessera CI/CD / Lint & Type Check (push) Successful in 44s
Tessera CI/CD / Tests (push) Successful in 36s
Tessera CI/CD / Build & Publish Images (push) Successful in 1m33s
fix(web): proxy client API calls through Next.js to fix production connectivity
NEXT_PUBLIC_API_URL was undefined at build time, causing client bundles to
fall back to http://localhost:3001 — unreachable from the browser in prod.

- Add /api-proxy rewrite in next.config.ts (forwards to API_INTERNAL_URL at runtime)
- Bake NEXT_PUBLIC_API_URL=/api-proxy at build time in Dockerfile
- Fix api.ts to prefer API_INTERNAL_URL for server-side calls
- Fix docker-compose.prod.yml: set NEXT_PUBLIC_API_URL=http://api:3001 for runtime server-side code

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-29 15:36:06 +02:00

68 lines
1.6 KiB
TypeScript

/**
* API client utilities for the Tessera frontend.
*
* Provides typed fetch wrappers for common API endpoints.
* All functions accept a cookie string for server-side auth forwarding.
*/
const API_URL = process.env.API_INTERNAL_URL || process.env.NEXT_PUBLIC_API_URL || 'http://localhost:3001';
/**
* Module data shape from the API.
*/
export interface ApiModule {
id: string;
name: string;
slug: string;
category: string;
description: Record<string, string> | string;
icon?: string;
version: string;
isSystem: boolean;
}
/**
* Fetch all active modules for the current tenant.
*
* @param cookie - Cookie header value for auth forwarding
* @returns Array of active modules
*/
export async function getActiveModules(cookie: string): Promise<ApiModule[]> {
const response = await fetch(`${API_URL}/modules/active`, {
headers: { Cookie: cookie },
cache: 'no-store',
});
if (!response.ok) {
return [];
}
return response.json();
}
/**
* Find a specific module by its slug.
*
* Fetches all modules and filters by slug.
*
* @param slug - Module slug (e.g., 'domaincheck')
* @param cookie - Cookie header value for auth forwarding
* @returns The module if found, or null
*/
export async function getModuleBySlug(
slug: string,
cookie: string,
): Promise<ApiModule | null> {
const response = await fetch(`${API_URL}/modules`, {
headers: { Cookie: cookie },
cache: 'no-store',
});
if (!response.ok) {
return null;
}
const modules: ApiModule[] = await response.json();
return modules.find((m) => m.slug === slug) ?? null;
}