mosaicmap/lib/fetchers.ts
2025-08-25 00:35:25 +08:00

149 lines
4.4 KiB
TypeScript

import { gql, GraphQLClient } from "graphql-request";
import type { PageData } from "@/types/page";
import { getBaseUrl } from "./gr-client";
// import * as Sentry from "@sentry/nextjs";
const PageQuery = gql/* GraphQL */ `
query PageQuery($slug: String!) {
pageBySlug(slug: $slug) {
id
title
description
}
}
`;
const BlockQuery = gql/* GraphQL */ `
query BlockQuery($pageId: String!) {
pageBlocks(pageId: $pageId) {
__typename
... on TextBlockType { id markdown }
... on ChartBlockType { id title series { x y } }
... on SettingsBlockType { id category editable }
... on HeroBlockType { id title subtitle backgroundImage ctaText ctaLink }
}
}
`;
export async function fetchPage(slug: string, jwt?: string): Promise<PageData | null> {
// return Sentry.startSpan(
// {
// op: "http.client",
// name: `GraphQL fetchPage: ${slug}`,
// },
// async (span) => {
// span.setAttribute("page.slug", slug);
// span.setAttribute("auth.hasJwt", !!jwt);
const client = new GraphQLClient(getBaseUrl());
if (jwt) {
client.setHeader('Authorization', `Bearer ${jwt}`);
}
try {
// 获取页面基本信息
const pageResponse: any = await client.request(PageQuery, { slug });
// const pageResponse: any = await Sentry.startSpan(
// {
// op: "http.client",
// name: "GraphQL PageQuery",
// },
// () => client.request(PageQuery, { slug })
// );
if (!pageResponse?.pageBySlug) {
throw new Error('Page not found');
}
// 获取页面块数据
const blocksResponse: any = await client.request(BlockQuery, {
pageId: pageResponse.pageBySlug.id
});
// const blocksResponse: any = await Sentry.startSpan(
// {
// op: "http.client",
// name: "GraphQL BlockQuery",
// },
// () => client.request(BlockQuery, {
// pageId: pageResponse.pageBySlug.id
// })
// );
if (!blocksResponse?.pageBlocks) {
throw new Error('Failed to fetch page blocks');
}
// span.setAttribute("page.blocksCount", blocksResponse.pageBlocks.length);
// 合并数据
return {
...pageResponse.pageBySlug,
blocks: blocksResponse.pageBlocks,
};
} catch (error) {
// Sentry.captureException(error, {
// tags: { operation: 'fetchPage' },
// extra: { slug, hasJwt: !!jwt }
// });
console.error('Failed to fetch page:', error);
return null;
}
// }
// );
}
export async function getSiteConfigs() {
// return Sentry.startSpan(
// {
// op: "http.client",
// name: "Fetch Site Configs",
// },
// async (span) => {
try {
const baseUrl = process.env.NEXTAUTH_URL || 'http://localhost:3000';
// span.setAttribute("api.baseUrl", baseUrl);
const siteConfigs = await fetch(`${baseUrl}/api/site`, {
headers: {
'Content-Type': 'application/json',
},
// Add timeout to prevent hanging during build
signal: AbortSignal.timeout(5000)
});
// span.setAttribute("http.status_code", siteConfigs.status);
if (!siteConfigs.ok) {
const error = new Error(`Failed to fetch site configs: ${siteConfigs.status} ${siteConfigs.statusText}`);
// Sentry.captureException(error, {
// tags: { operation: 'getSiteConfigs' },
// extra: { status: siteConfigs.status, statusText: siteConfigs.statusText }
// });
console.warn(`Failed to fetch site configs: ${siteConfigs.status} ${siteConfigs.statusText}`);
return getDefaultSiteConfigs();
}
const data = await siteConfigs.json();
// span.setAttribute("configs.count", data.length);
return data;
} catch (error) {
// Sentry.captureException(error, {
// tags: { operation: 'getSiteConfigs' }
// });
console.warn('Failed to fetch site configs, using defaults:', error);
return getDefaultSiteConfigs();
}
// }
// );
}
function getDefaultSiteConfigs() {
return [
{ key: 'site.name', value: 'MosaicMap' },
{ key: 'site.description', value: 'Interactive map visualization with custom WebGL timeline' }
];
}