From a8027e1ad3fee7e9f6cbdce5e620fba996f283d0 Mon Sep 17 00:00:00 2001 From: masterforweb Date: Mon, 22 Dec 2025 10:25:48 +0300 Subject: [PATCH] add all api --- src/lib/api/all.ts | 393 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 393 insertions(+) create mode 100644 src/lib/api/all.ts diff --git a/src/lib/api/all.ts b/src/lib/api/all.ts new file mode 100644 index 0000000..85b551e --- /dev/null +++ b/src/lib/api/all.ts @@ -0,0 +1,393 @@ +import { fetchGraphQL } from './graphql-client'; +import { cache } from '@lib/cache/manager'; +import { CACHE_TTL } from '@lib/cache/cache-ttl'; + +export interface NodeByUriResponse { + nodeByUri: { + __typename: string; + id?: string; + databaseId?: number; + title?: string; + uri?: string; + date?: string; + content?: string; + excerpt?: string; + slug?: string; + name?: string; + description?: string; + count?: number; + featuredImage?: { + node: { + sourceUrl: string; + altText: string; + }; + }; + author?: { + node: { + id: string; + name: string; + firstName: string; + lastName: string; + avatar: { + url: string; + }; + uri: string; + }; + }; + categories?: { + nodes: Array<{ + id: string; + name: string; + slug: string; + uri: string; + databaseId: number; + }>; + }; + tags?: { + nodes: Array<{ + id: string; + name: string; + slug: string; + uri: string; + }>; + }; + ancestors?: { + nodes: Array<{ + id: string; + name: string; + slug: string; + uri: string; + }>; + }; + children?: { + nodes: Array<{ + id: string; + name: string; + slug: string; + uri: string; + count: number; + }>; + }; + } | null; +} + +export async function getNodeByURI(uri: string): Promise { + const normalizedUri = uri.startsWith('/') ? uri : `/${uri}`; + const cacheKey = `node-by-uri:${normalizedUri}`; + + return await cache.wrap( + cacheKey, + async () => { + const query = ` + query GetNodeByURI($uri: String!) { + nodeByUri(uri: $uri) { + __typename + uri + + ... on Category { + id + databaseId + name + slug + description + uri + count + ancestors { + nodes { + id + name + slug + uri + } + } + children { + nodes { + id + name + slug + uri + count + } + } + } + + ... on Tag { + id + databaseId + name + slug + description + uri + count + } + + ... on ProfileArticle { + id + databaseId + title + content + excerpt + date + slug + uri + featuredImage { + node { + sourceUrl(size: LARGE) + altText + } + } + author { + node { + id + name + firstName + lastName + avatar { + url + } + uri + } + } + categories { + nodes { + id + name + slug + uri + databaseId + } + } + tags { + nodes { + id + name + slug + uri + } + } + } + + ... on ANew { + id + databaseId + title + content + excerpt + date + slug + uri + featuredImage { + node { + sourceUrl(size: LARGE) + altText + } + } + author { + node { + id + name + firstName + lastName + avatar { + url + } + uri + } + } + categories { + nodes { + id + name + slug + uri + databaseId + } + } + tags { + nodes { + id + name + slug + uri + } + } + } + + ... on Post { + id + databaseId + title + content + excerpt + date + slug + uri + featuredImage { + node { + sourceUrl(size: LARGE) + altText + } + } + author { + node { + id + name + firstName + lastName + avatar { + url + } + uri + } + } + categories { + nodes { + id + name + slug + uri + databaseId + } + } + tags { + nodes { + id + name + slug + uri + } + } + } + + ... on Page { + id + databaseId + title + content + date + slug + uri + featuredImage { + node { + sourceUrl(size: LARGE) + altText + } + } + } + } + } + `; + + const data = await fetchGraphQL(query, { uri: normalizedUri }); + return data; + }, + { + ttl: CACHE_TTL.POSTS + } + ); +} + +export async function getCategoryPosts( + categoryId: number, + page = 1, + postsPerPage = 12 +) { + const offset = (page - 1) * postsPerPage; + const cacheKey = `category-posts:${categoryId}:${page}:${postsPerPage}`; + + return await cache.wrap( + cacheKey, + async () => { + const query = ` + query GetCategoryPosts($id: Int!, $size: Int!, $offset: Int!) { + category(id: $id, idType: DATABASE_ID) { + posts( + first: $size, + offset: $offset, + where: { orderby: { field: DATE, order: DESC } } + ) { + pageInfo { + offsetPagination { + total + hasMore + hasPrevious + } + } + nodes { + __typename + id + databaseId + title + excerpt + uri + date + featuredImage { + node { + sourceUrl(size: LARGE) + altText + } + } + author { + node { + id + name + firstName + lastName + avatar { + url + } + uri + } + } + categories { + nodes { + id + name + slug + uri + databaseId + } + } + tags { + nodes { + id + name + slug + uri + } + } + } + } + } + } + `; + + const data = await fetchGraphQL(query, { + id: categoryId, + size: postsPerPage, + offset + }); + + return { + posts: data?.category?.posts?.nodes || [], + pageInfo: data?.category?.posts?.pageInfo?.offsetPagination || { + total: 0, + hasMore: false, + hasPrevious: false + } + }; + }, + { ttl: CACHE_TTL.POSTS } + ); +} + +export async function invalidateNodeCache(uri: string): Promise { + const normalizedUri = uri.startsWith('/') ? uri : `/${uri}`; + const cacheKey = `node-by-uri:${normalizedUri}`; + await cache.del(cacheKey); +} + +export async function invalidateCategoryCache(categoryId: number): Promise { + const pattern = `category-posts:${categoryId}:*`; + await cache.delPattern(pattern); +}