import { createDirectus, rest, authentication, readItems, readCollections } from '@directus/sdk'; import { config } from './config'; import { getServerAppServices } from './services/create-services.server'; const { url, adminEmail, password, token, proxyPath, internalUrl } = config.directus; // Use internal URL if on server to bypass Gatekeeper/Auth // Use proxy path in browser to stay on the same origin const effectiveUrl = typeof window === 'undefined' ? internalUrl || url : typeof window !== 'undefined' ? `${window.location.origin}${proxyPath}` : proxyPath; const client = createDirectus(effectiveUrl).with(rest()).with(authentication()); /** * Helper to determine if we should show detailed errors */ const shouldShowDevErrors = config.isTesting || config.isDevelopment; /** * Genericizes error messages for production/staging */ function formatError(error: any) { if (shouldShowDevErrors) { return error.errors?.[0]?.message || error.message || 'An unexpected error occurred.'; } return 'A system error occurred. Our team has been notified.'; } let authPromise: Promise | null = null; export async function ensureAuthenticated() { if (token) { client.setToken(token); return; } // Check if we already have a valid session token in memory const existingToken = await client.getToken(); if (existingToken) { return; } if (adminEmail && password) { if (authPromise) { return authPromise; } authPromise = (async () => { try { client.setToken(null as any); await client.login(adminEmail, password); console.log(`✅ Directus: Authenticated successfully as ${adminEmail}`); } catch (e: any) { if (typeof window === 'undefined') { getServerAppServices().errors.captureException(e, { part: 'directus_auth' }); } console.error(`Failed to authenticate with Directus (${adminEmail}):`, e.message); if (shouldShowDevErrors && e.errors) { console.error('Directus Auth Details:', JSON.stringify(e.errors, null, 2)); } // Clear the promise on failure (especially on invalid credentials) // so we can retry on next request if credentials were updated authPromise = null; throw e; } })(); return authPromise; } else if (shouldShowDevErrors && !adminEmail && !password && !token) { console.warn('Directus: No token or admin credentials provided.'); } } /** * Maps the new translation-based schema back to the application's Product interface */ function mapDirectusProduct(item: any, locale: string): any { const langCode = locale === 'en' ? 'en-US' : 'de-DE'; const translation = item.translations?.find((t: any) => t.languages_code === langCode) || item.translations?.[0] || {}; return { id: item.id, sku: item.sku, title: translation.name || '', description: translation.description || '', content: translation.content || '', technicalData: { technicalItems: translation.technical_items || [], voltageTables: translation.voltage_tables || [], }, locale: locale, // Use proxy URL for assets to avoid CORS and handle internal/external issues data_sheet_url: item.data_sheet ? `${proxyPath}/assets/${item.data_sheet}` : null, categories: (item.categories_link || []) .map((c: any) => c.categories_id?.translations?.[0]?.name) .filter(Boolean), }; } export async function getProducts(locale: string = 'de') { await ensureAuthenticated(); try { const items = await client.request( readItems('products', { fields: ['*', 'translations.*', 'categories_link.categories_id.translations.name'], }), ); return items.map((item) => mapDirectusProduct(item, locale)); } catch (error) { if (typeof window === 'undefined') { getServerAppServices().errors.captureException(error, { part: 'directus_get_products' }); } console.error('Error fetching products:', error); return []; } } export async function getProductBySlug(slug: string, locale: string = 'de') { await ensureAuthenticated(); const langCode = locale === 'en' ? 'en-US' : 'de-DE'; try { const items = await client.request( readItems('products', { filter: { translations: { slug: { _eq: slug }, languages_code: { _eq: langCode }, }, }, fields: ['*', 'translations.*', 'categories_link.categories_id.translations.name'], limit: 1, }), ); if (!items || items.length === 0) return null; return mapDirectusProduct(items[0], locale); } catch (error) { if (typeof window === 'undefined') { getServerAppServices().errors.captureException(error, { part: 'directus_get_product_by_slug', slug, }); } console.error(`Error fetching product ${slug}:`, error); return null; } } export async function checkHealth() { try { // 1. Connectivity & Auth Check try { await ensureAuthenticated(); await client.request(readCollections()); } catch (e: any) { if (typeof window === 'undefined') { getServerAppServices().errors.captureException(e, { part: 'directus_health_auth' }); } console.error('Directus authentication failed during health check:', e); return { status: 'error', message: shouldShowDevErrors ? 'Authentication failed. Check your DIRECTUS_ADMIN_EMAIL and DIRECTUS_ADMIN_PASSWORD.' : 'CMS is currently unavailable due to an internal authentication error.', code: 'AUTH_FAILED', details: shouldShowDevErrors ? e.message : undefined, }; } // 2. Schema check (does the contact_submissions table exist?) try { await client.request(readItems('contact_submissions', { limit: 1 })); } catch (e: any) { if (typeof window === 'undefined') { getServerAppServices().errors.captureException(e, { part: 'directus_health_schema' }); } if ( e.message?.includes('does not exist') || e.code === 'INVALID_PAYLOAD' || e.status === 404 ) { return { status: 'error', message: shouldShowDevErrors ? `The "contact_submissions" collection is missing or inaccessible. Error: ${e.message || 'Unknown'}` : 'Required data structures are currently unavailable.', code: 'SCHEMA_MISSING', }; } return { status: 'error', message: shouldShowDevErrors ? `Schema error: ${e.errors?.[0]?.message || e.message || 'Unknown error'}` : 'The data schema is currently misconfigured.', code: 'SCHEMA_ERROR', }; } return { status: 'ok', message: 'Directus is reachable and responding.' }; } catch (error: any) { if (typeof window === 'undefined') { getServerAppServices().errors.captureException(error, { part: 'directus_health_critical' }); } console.error('Directus health check failed with unexpected error:', error); return { status: 'error', message: formatError(error), code: error.code || 'UNKNOWN', }; } } export default client; (async () => { try { await ensureAuthenticated(); console.log('Auth test successful'); } catch (e) { console.error('Auth test failed:', e.message); } })();