Files
klz-cables.com/lib/directus.ts
Marc Mintel 7ad5b5696d
Some checks failed
Build & Deploy / 🔍 Prepare (push) Successful in 8s
Build & Deploy / 🧪 QA (push) Failing after 1m16s
Build & Deploy / 🏗️ Build (push) Failing after 3m33s
Build & Deploy / 🚀 Deploy (push) Has been skipped
Build & Deploy / 🔔 Notify (push) Successful in 2s
refactor: standardize env and directus logic using enhanced @mintel/next-utils
2026-02-10 23:47:09 +01:00

181 lines
5.8 KiB
TypeScript

import { readItems, readCollections } from '@directus/sdk';
import { createMintelDirectusClient, ensureDirectusAuthenticated } from '@mintel/next-utils';
import { config } from './config';
import { getServerAppServices } from './services/create-services.server';
// Initialize client using Mintel standards (environment-aware)
const client = createMintelDirectusClient();
/**
* 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.';
}
export async function ensureAuthenticated() {
try {
await ensureDirectusAuthenticated(client);
} catch (e: any) {
if (typeof window === 'undefined') {
getServerAppServices().errors.captureException(e, { part: 'directus_auth' });
}
console.error(`Failed to authenticate with Directus:`, e.message);
throw e;
}
}
/**
* 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 standardized proxy path for assets to avoid CORS
data_sheet_url: item.data_sheet ? `/api/directus/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 or collection-read failed during health check:', e);
return {
status: 'error',
message: shouldShowDevErrors
? `Directus Health Error: ${e.message || 'Unknown'}`
: 'CMS is currently unavailable due to an internal authentication or connection error.',
code: e.code || 'HEALTH_AUTH_FAILED',
details: shouldShowDevErrors
? { message: e.message, code: e.code, errors: e.errors }
: 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;