aboutsummaryrefslogtreecommitdiffstats
path: root/src/types
diff options
context:
space:
mode:
authorArmand Philippot <git@armandphilippot.com>2023-11-24 20:00:08 +0100
committerArmand Philippot <git@armandphilippot.com>2023-11-27 14:47:51 +0100
commitf111685c5886f3e77edfd3621c98d8ac1b9bcce4 (patch)
tree62a541fe3afeb64bf745443706fbfb02e96c5230 /src/types
parentbee515641cb144be9a855ff2cac258d2fedab21d (diff)
refactor(services, types): reorganize GraphQL fetchers and data types
The Typescript mapped types was useful for autocompletion in fetchers but their are harder to maintain. I think it's better to keep each query close to its fetcher to have a better understanding of the fetched data. So I: * colocate queries with their own fetcher * colocate mutations with their own mutator * remove Typescript mapped types for queries and mutations * move data convertors inside graphql services * rename most of data types and fetchers
Diffstat (limited to 'src/types')
-rw-r--r--src/types/app.ts102
-rw-r--r--src/types/data.ts289
-rw-r--r--src/types/gql.ts73
-rw-r--r--src/types/graphql/generics.ts25
-rw-r--r--src/types/graphql/index.ts3
-rw-r--r--src/types/graphql/mutations.ts60
-rw-r--r--src/types/graphql/queries.ts143
-rw-r--r--src/types/index.ts5
-rw-r--r--src/types/mdx.ts22
-rw-r--r--src/types/raw-data.ts111
10 files changed, 364 insertions, 469 deletions
diff --git a/src/types/app.ts b/src/types/app.ts
index b613e6e..218d63b 100644
--- a/src/types/app.ts
+++ b/src/types/app.ts
@@ -28,108 +28,6 @@ export type AppPropsWithLayout = AppProps<CustomPageProps> & {
Component: NextPageWithLayout;
};
-export type ContentKind =
- | 'article'
- | 'comment'
- | 'page'
- | 'project'
- | 'thematic'
- | 'topic';
-
-export type Author<T extends ContentKind> = {
- avatar?: Image;
- description?: T extends 'comment' ? never : string;
- name: string;
- website?: string;
-};
-
-export type CommentMeta = {
- author: Author<'comment'>;
- date: string;
-};
-
-export type SingleComment = {
- approved: boolean;
- content: string;
- id: number;
- meta: CommentMeta;
- parentId?: number;
- replies: SingleComment[];
-};
-
-export type Dates = {
- publication: string;
- update?: string;
-};
-
-export type Image = {
- alt: string;
- height: number;
- src: string;
- title?: string;
- width: number;
-};
-
-export type Repos = {
- github?: string;
- gitlab?: string;
-};
-
-export type SEO = {
- description: string;
- title: string;
-};
-
-export type PageKind = Exclude<ContentKind, 'comment'>;
-
-export type Meta<T extends PageKind> = {
- articles?: T extends 'thematic' | 'topic' ? Article[] : never;
- author?: T extends 'article' | 'page' ? Author<T> : never;
- commentsCount?: T extends 'article' ? number : never;
- cover?: Image;
- dates: Dates;
- license?: T extends 'project' ? string : never;
- repos?: T extends 'project' ? Repos : never;
- seo: SEO;
- tagline?: T extends 'project' ? string : never;
- technologies?: T extends 'project' ? string[] : never;
- thematics?: T extends 'article' | 'topic' ? PageLink[] : never;
- topics?: T extends 'article' | 'thematic' ? PageLink[] : never;
- website?: T extends 'topic' ? string : never;
- wordsCount: number;
-};
-
-export type Page<T extends PageKind> = {
- content: string;
- id: number | string;
- intro: string;
- meta: Meta<T>;
- slug: string;
- title: string;
-};
-
-export type PageLink = {
- id: number;
- logo?: Image;
- name: string;
- url: string;
-};
-
-export type Article = Page<'article'>;
-export type ArticleCard = Pick<Article, 'id' | 'slug' | 'title'> &
- Pick<Meta<'article'>, 'cover' | 'dates'>;
-export type Project = Page<'project'>;
-export type ProjectPreview = Omit<Page<'project'>, 'content'>;
-export type ProjectCard = Pick<Page<'project'>, 'id' | 'slug' | 'title'> & {
- meta: Pick<Meta<'project'>, 'cover' | 'dates' | 'tagline' | 'technologies'>;
-};
-export type Thematic = Page<'thematic'>;
-export type Topic = Page<'topic'>;
-
-export type Slug = {
- slug: string;
-};
-
export type Position = 'bottom' | 'center' | 'left' | 'right' | 'top';
/** Spacing keys defined has CSS variables */
diff --git a/src/types/data.ts b/src/types/data.ts
new file mode 100644
index 0000000..9a6d674
--- /dev/null
+++ b/src/types/data.ts
@@ -0,0 +1,289 @@
+import type { StaticImageData } from 'next/image';
+import type { Nullable } from './generics';
+import type { GraphQLNode } from './gql';
+
+export type SlugNode = {
+ slug: string;
+};
+
+//===========================================================================
+// Data from WordPress
+//===========================================================================
+
+type WPSeo = {
+ metaDesc: string;
+ title: string;
+};
+
+type WPCommentAuthorAvatar = {
+ height: number;
+ url: string;
+ width: number;
+};
+
+type WPCommentAuthor = {
+ avatar: Nullable<WPCommentAuthorAvatar>;
+ name: string;
+ url: Nullable<string>;
+};
+
+export type WPCommentStatus = 'APPROVE' | 'HOLD' | 'SPAM' | 'TRASH';
+
+export type WPComment = {
+ approved: boolean;
+ author: GraphQLNode<WPCommentAuthor>;
+ content: string;
+ databaseId: number;
+ date: string;
+ parentDatabaseId: number;
+ status: WPCommentStatus;
+};
+
+type WPContentParts = {
+ afterMore: string;
+ beforeMore: string;
+};
+
+export type WPImage = {
+ altText: Nullable<string>;
+ mediaDetails: {
+ height: number;
+ width: number;
+ };
+ sourceUrl: string;
+ title: Nullable<string>;
+};
+
+type WPInfo = { wordsCount: number };
+
+type WPContent = {
+ date: string;
+ featuredImage: Nullable<GraphQLNode<WPImage>>;
+ modified: string;
+ seo: WPSeo;
+ slug: string;
+ title: string;
+};
+
+export type WPPage = WPContent & {
+ contentParts: WPContentParts;
+ info: WPInfo;
+};
+
+type WPPostAuthor = { name: string };
+
+type WPAcfPosts = {
+ postsInThematic: Nullable<WPThematicPreview[]>;
+ postsInTopic: Nullable<WPTopicPreview[]>;
+};
+
+export type WPPost = WPContent & {
+ acfPosts: Nullable<Partial<WPAcfPosts>>;
+ author: GraphQLNode<WPPostAuthor>;
+ commentCount: Nullable<number>;
+ contentParts: WPContentParts;
+ databaseId: number;
+ info: WPInfo;
+};
+
+export type WPPostPreview = Pick<
+ WPPost,
+ | 'commentCount'
+ | 'databaseId'
+ | 'date'
+ | 'featuredImage'
+ | 'info'
+ | 'modified'
+ | 'slug'
+ | 'title'
+> & {
+ acfPosts:
+ | Nullable<Pick<WPAcfPosts, 'postsInThematic'>>
+ | Nullable<Pick<WPAcfPosts, 'postsInTopic'>>;
+ contentParts: Pick<WPContentParts, 'beforeMore'>;
+};
+
+export type RecentWPPost = Pick<
+ WPPost,
+ 'date' | 'featuredImage' | 'slug' | 'title'
+> & {
+ databaseId: number;
+};
+
+type WPAcfThematics = {
+ postsInThematic: Nullable<WPPostPreview[]>;
+};
+
+export type WPThematic = WPContent & {
+ acfThematics: Nullable<WPAcfThematics>;
+};
+
+export type WPThematicPreview = Pick<WPThematic, 'slug' | 'title'> & {
+ databaseId: number;
+};
+
+type WPAcfTopics = {
+ officialWebsite: string;
+ postsInTopic: Nullable<WPPostPreview[]>;
+};
+
+export type WPTopic = WPContent & {
+ acfTopics: Nullable<WPAcfTopics>;
+};
+
+export type WPTopicPreview = Pick<
+ WPTopic,
+ 'featuredImage' | 'slug' | 'title'
+> & {
+ databaseId: number;
+};
+
+//===========================================================================
+// Data from MDX files
+//===========================================================================
+
+export type MDXData = {
+ file: string;
+ image: MDXImage;
+};
+
+export type MDXImage = StaticImageData & {
+ alt: string;
+ title?: string;
+};
+
+export type MDXPageMeta = Omit<PageMeta, 'wordsCount'> & {
+ intro: string;
+ title: string;
+};
+
+export type MDXProjectMeta = Omit<ProjectMeta, 'wordsCount'> & {
+ intro: string;
+ title: string;
+};
+
+//===========================================================================
+// Data used in this application
+//===========================================================================
+
+export type Dates = {
+ publication: string;
+ update?: string;
+};
+
+export type SEO = {
+ description: string;
+ title: string;
+};
+
+export type Img = {
+ alt: string;
+ height: number;
+ src: string;
+ title?: string;
+ width: number;
+};
+
+export type CommentAuthor = {
+ avatar?: Omit<Img, 'title'>;
+ name: string;
+ website?: string;
+};
+
+export type CommentMeta = {
+ author: CommentAuthor;
+ date: string;
+};
+
+export type SingleComment = {
+ content: string;
+ id: number;
+ isApproved: boolean;
+ meta: CommentMeta;
+ parentId?: number;
+ replies: SingleComment[];
+};
+
+export type PageMeta = {
+ cover?: Img;
+ dates: Dates;
+ seo: SEO;
+ wordsCount: number;
+};
+
+export type Page = {
+ content: string;
+ intro: string;
+ slug: string;
+ title: string;
+};
+
+export type PageLink = {
+ id: number;
+ logo?: Img;
+ name: string;
+ url: string;
+};
+
+type ArticleMeta = PageMeta & {
+ author?: string;
+ commentsCount?: number;
+ thematics?: PageLink[];
+ topics?: PageLink[];
+};
+
+export type Article = Page & {
+ id: number;
+ meta: ArticleMeta;
+};
+
+export type ArticlePreview = Pick<Article, 'intro' | 'slug' | 'title'> & {
+ id: number;
+ meta: Omit<ArticleMeta, 'author' | 'seo' | 'topics'>;
+};
+
+export type RecentArticle = Pick<Article, 'slug' | 'title'> &
+ Pick<ArticleMeta, 'cover'> & {
+ id: number;
+ publicationDate: string;
+ };
+
+export type Repos = {
+ github?: string;
+ gitlab?: string;
+};
+
+export type ProjectMeta = Omit<PageMeta, 'wordsCount'> & {
+ license?: string;
+ repos?: Repos;
+ tagline?: string;
+ technologies?: string[];
+};
+
+export type Project = Omit<Page, 'content'> & {
+ id: string;
+ meta: ProjectMeta;
+};
+
+export type ProjectPreview = Omit<Project, 'meta'> & {
+ meta: Omit<ProjectMeta, 'license' | 'repos'>;
+};
+
+export type ThematicMeta = PageMeta & {
+ articles?: ArticlePreview[];
+ topics?: PageLink[];
+};
+
+export type Thematic = Page & {
+ meta: ThematicMeta;
+};
+
+export type TopicMeta = PageMeta & {
+ articles?: ArticlePreview[];
+ thematics?: PageLink[];
+ website?: string;
+};
+
+export type Topic = Page & {
+ meta: TopicMeta;
+};
diff --git a/src/types/gql.ts b/src/types/gql.ts
new file mode 100644
index 0000000..cec66c6
--- /dev/null
+++ b/src/types/gql.ts
@@ -0,0 +1,73 @@
+import type { WPCommentStatus } from './data';
+import type { Nullable } from './generics';
+
+export type GraphQLNode<T> = {
+ node: T;
+};
+
+export type GraphQLNodes<T> = {
+ nodes: T[];
+};
+
+export type GraphQLPageInfo = {
+ endCursor: Nullable<string>;
+ hasNextPage: boolean;
+ hasPreviousPage: boolean;
+ startCursor: Nullable<string>;
+ total: number;
+};
+
+export type GraphQLEdge<T> = GraphQLNode<T> & {
+ cursor: string;
+};
+
+export type GraphQLConnection<T> = {
+ edges: GraphQLEdge<T>[];
+ pageInfo: GraphQLPageInfo;
+};
+
+export type GraphQLEdgesInput = {
+ after?: Nullable<string>;
+ before?: Nullable<string>;
+ first?: number;
+ last?: number;
+};
+
+export type GraphQLOrder = 'ASC' | 'DESC';
+
+export type GraphQLCommentWhere = {
+ contentId?: number;
+ contentName?: string;
+ status?: WPCommentStatus;
+};
+
+type GraphQLPostFieldOrder =
+ | 'AUTHOR'
+ | 'COMMENT_COUNT'
+ | 'DATE'
+ | 'MODIFIED'
+ | 'SLUG'
+ | 'TITLE';
+
+export type GraphQLPostOrderBy = {
+ field: GraphQLPostFieldOrder;
+ order: GraphQLOrder;
+};
+
+export type GraphQLPostWhere = {
+ authorName?: string;
+ search?: string;
+ title?: string;
+};
+
+export type GraphQLTaxonomyFieldOrder = 'DATE' | 'MODIFIED' | 'SLUG' | 'TITLE';
+
+export type GraphQLTaxonomyOrderBy = {
+ field: GraphQLTaxonomyFieldOrder;
+ order: GraphQLOrder;
+};
+
+export type GraphQLTaxonomyWhere = {
+ search?: string;
+ title?: string;
+};
diff --git a/src/types/graphql/generics.ts b/src/types/graphql/generics.ts
deleted file mode 100644
index dec5f10..0000000
--- a/src/types/graphql/generics.ts
+++ /dev/null
@@ -1,25 +0,0 @@
-export type GraphQLPageInfo = {
- endCursor: string;
- hasNextPage: boolean;
- total: number;
-};
-
-export type GraphQLEdges<T> = {
- cursor: string;
- node: T;
-};
-
-export type GraphQLEdgesInput = {
- after?: string;
- before?: string;
- first?: number;
- last?: number;
-};
-
-export type GraphQLNode<T> = {
- node: T;
-};
-
-export type GraphQLNodes<T> = {
- nodes: T[];
-};
diff --git a/src/types/graphql/index.ts b/src/types/graphql/index.ts
deleted file mode 100644
index 79eb05e..0000000
--- a/src/types/graphql/index.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-export * from './generics';
-export * from './mutations';
-export * from './queries';
diff --git a/src/types/graphql/mutations.ts b/src/types/graphql/mutations.ts
deleted file mode 100644
index 6ff066c..0000000
--- a/src/types/graphql/mutations.ts
+++ /dev/null
@@ -1,60 +0,0 @@
-import { sendCommentMutation, sendMailMutation } from '../../services/graphql';
-
-//===========================================================================
-// Existing mutations list
-//===========================================================================
-
-export type Mutations = typeof sendMailMutation | typeof sendCommentMutation;
-
-//===========================================================================
-// Mutations response types
-//===========================================================================
-
-export type SendCommentResponse<T> = {
- createComment: T;
-};
-
-export type SendMailResponse<T> = {
- sendEmail: T;
-};
-
-export type MutationsResponseMap<T> = {
- [sendCommentMutation]: SendCommentResponse<T>;
- [sendMailMutation]: SendMailResponse<T>;
-};
-
-export type Approved = {
- approved: boolean;
-};
-
-export type SentComment = {
- clientMutationId: string;
- success: boolean;
- comment: Approved | null;
-};
-
-//===========================================================================
-// Mutations input types
-//===========================================================================
-
-export type SendCommentInput = {
- author: string;
- authorEmail: string;
- authorUrl: string;
- clientMutationId: string;
- commentOn: number;
- content: string;
- parent?: number;
-};
-
-export type SendMailInput = {
- body: string;
- clientMutationId: string;
- replyTo: string;
- subject: string;
-};
-
-export type MutationsInputMap = {
- [sendCommentMutation]: SendCommentInput;
- [sendMailMutation]: SendMailInput;
-};
diff --git a/src/types/graphql/queries.ts b/src/types/graphql/queries.ts
deleted file mode 100644
index 83e9c67..0000000
--- a/src/types/graphql/queries.ts
+++ /dev/null
@@ -1,143 +0,0 @@
-import {
- articleBySlugQuery,
- articlesCardQuery,
- articlesEndCursorQuery,
- articlesQuery,
- articlesSlugQuery,
- commentsQuery,
- thematicBySlugQuery,
- thematicsListQuery,
- thematicsSlugQuery,
- topicBySlugQuery,
- topicsListQuery,
- topicsSlugQuery,
- totalArticlesQuery,
- totalThematicsQuery,
- totalTopicsQuery,
-} from '../../services/graphql';
-import { Slug } from '../app';
-import { RawComment } from '../raw-data';
-import {
- GraphQLEdges,
- GraphQLEdgesInput,
- GraphQLNodes,
- GraphQLPageInfo,
-} from './generics';
-
-//===========================================================================
-// Existing queries list
-//===========================================================================
-
-export type Queries =
- | typeof articlesQuery
- | typeof articleBySlugQuery
- | typeof articlesCardQuery
- | typeof articlesEndCursorQuery
- | typeof articlesSlugQuery
- | typeof commentsQuery
- | typeof thematicBySlugQuery
- | typeof thematicsListQuery
- | typeof thematicsSlugQuery
- | typeof topicBySlugQuery
- | typeof topicsListQuery
- | typeof topicsSlugQuery
- | typeof totalArticlesQuery
- | typeof totalThematicsQuery
- | typeof totalTopicsQuery;
-
-//===========================================================================
-// Queries response types
-//===========================================================================
-
-export type ArticleResponse<T> = {
- post: T;
-};
-
-export type ArticlesResponse<T> = {
- posts: T;
-};
-
-export type CommentsResponse<T> = {
- comments: T;
-};
-
-export type ThematicResponse<T> = {
- thematic: T;
-};
-
-export type ThematicsResponse<T> = {
- thematics: T;
-};
-
-export type TopicResponse<T> = {
- topic: T;
-};
-
-export type TopicsResponse<T> = {
- topics: T;
-};
-
-export type EdgesResponse<T> = {
- edges: GraphQLEdges<T>[];
- pageInfo: GraphQLPageInfo;
-};
-
-export type EndCursorResponse = {
- pageInfo: Pick<GraphQLPageInfo, 'endCursor'>;
-};
-
-export type QueriesResponseMap<T> = {
- [articleBySlugQuery]: ArticleResponse<T>;
- [articlesCardQuery]: ArticlesResponse<GraphQLNodes<T>>;
- [articlesEndCursorQuery]: ArticlesResponse<EndCursorResponse>;
- [articlesQuery]: ArticlesResponse<EdgesResponse<T>>;
- [articlesSlugQuery]: ArticlesResponse<EdgesResponse<T>>;
- [commentsQuery]: CommentsResponse<EdgesResponse<T>>;
- [thematicBySlugQuery]: ThematicResponse<T>;
- [thematicsListQuery]: ThematicsResponse<EdgesResponse<T>>;
- [thematicsSlugQuery]: ThematicsResponse<EdgesResponse<T>>;
- [topicBySlugQuery]: TopicResponse<T>;
- [topicsListQuery]: TopicsResponse<EdgesResponse<T>>;
- [topicsSlugQuery]: TopicsResponse<EdgesResponse<T>>;
- [totalArticlesQuery]: ArticlesResponse<T>;
- [totalThematicsQuery]: ThematicsResponse<T>;
- [totalTopicsQuery]: TopicsResponse<T>;
-};
-
-//===========================================================================
-// Queries input types
-//===========================================================================
-
-export type QueryEdges = Pick<GraphQLEdgesInput, 'after' | 'first'>;
-
-export type ContentId = {
- contentId: number;
-};
-
-export type Search = {
- search?: string;
-};
-
-export type QueriesInputMap = {
- [articleBySlugQuery]: Slug;
- [articlesCardQuery]: QueryEdges & Search;
- [articlesEndCursorQuery]: QueryEdges & Search;
- [articlesQuery]: QueryEdges & Search;
- [articlesSlugQuery]: QueryEdges & Search;
- [commentsQuery]: ContentId & QueryEdges;
- [thematicBySlugQuery]: Slug;
- [thematicsListQuery]: QueryEdges & Search;
- [thematicsSlugQuery]: QueryEdges & Search;
- [topicBySlugQuery]: Slug;
- [topicsListQuery]: QueryEdges & Search;
- [topicsSlugQuery]: QueryEdges & Search;
- [totalArticlesQuery]: Search;
- [totalThematicsQuery]: null;
- [totalTopicsQuery]: null;
-};
-
-export type CommentPage = {
- comments: RawComment[];
- hasNextPage: boolean;
- endCursor: string;
-};
diff --git a/src/types/index.ts b/src/types/index.ts
index e2f0f55..d6e4a6a 100644
--- a/src/types/index.ts
+++ b/src/types/index.ts
@@ -1,6 +1,5 @@
export * from './app';
+export * from './data';
export * from './generics';
-export * from './graphql';
-export * from './mdx';
-export * from './raw-data';
+export * from './gql';
export * from './swr';
diff --git a/src/types/mdx.ts b/src/types/mdx.ts
deleted file mode 100644
index 7645ce6..0000000
--- a/src/types/mdx.ts
+++ /dev/null
@@ -1,22 +0,0 @@
-import { StaticImageData } from 'next/image';
-import { Meta } from './app';
-
-export type MDXData = {
- file: string;
- image: MDXImage;
-};
-
-export type MDXImage = StaticImageData & {
- alt: string;
- title?: string;
-};
-
-export type MDXPageMeta = Pick<Meta<'page'>, 'cover' | 'dates' | 'seo'> & {
- intro: string;
- title: string;
-};
-
-export type MDXProjectMeta = Exclude<Meta<'project'>, 'wordsCount'> & {
- intro: string;
- title: string;
-};
diff --git a/src/types/raw-data.ts b/src/types/raw-data.ts
deleted file mode 100644
index 022016e..0000000
--- a/src/types/raw-data.ts
+++ /dev/null
@@ -1,111 +0,0 @@
-/**
- * Types for raw data coming from GraphQL API.
- */
-
-import { ContentKind } from './app';
-import { GraphQLNode, GraphQLPageInfo } from './graphql/generics';
-
-export type ACFPosts = {
- postsInThematic?: RawThematicPreview[];
- postsInTopic?: RawTopicPreview[];
-};
-
-export type ACFThematics = {
- postsInThematic: RawArticle[];
-};
-
-export type ACFTopics = {
- officialWebsite: string;
- postsInTopic: RawArticle[];
-};
-
-export type ContentParts = {
- afterMore: string;
- beforeMore: string;
-};
-
-export type Info = {
- wordsCount: number;
-};
-
-export type RawAuthor<T extends ContentKind> = {
- description?: T extends 'comment' ? never : string;
- gravatarUrl?: string;
- name: string;
- url?: string;
-};
-
-export type RawComment = {
- approved: boolean;
- author: GraphQLNode<RawAuthor<'comment'>>;
- content: string;
- databaseId: number;
- date: string;
- parentDatabaseId: number;
-};
-
-export type RawCommentsPage = {
- comments: RawComment[];
- hasNextPage: boolean;
- endCursor: string;
-};
-
-export type RawCover = {
- altText: string;
- mediaDetails: {
- width: number;
- height: number;
- };
- sourceUrl: string;
- title?: string;
-};
-
-export type RawArticle = RawPage & {
- acfPosts: ACFPosts;
- commentCount: number | null;
-};
-
-export type RawArticlePreview = Pick<
- RawArticle,
- 'databaseId' | 'date' | 'featuredImage' | 'slug' | 'title'
->;
-
-export type RawPage = {
- author?: GraphQLNode<RawAuthor<'page'>>;
- contentParts: ContentParts;
- databaseId: number;
- date: string;
- featuredImage: GraphQLNode<RawCover> | null;
- info: Info;
- modified: string;
- seo?: RawSEO;
- slug: string;
- title: string;
-};
-
-export type RawSEO = {
- metaDesc: string;
- title: string;
-};
-
-export type RawThematic = RawPage & {
- acfThematics: ACFThematics;
-};
-
-export type RawThematicPreview = Pick<
- RawThematic,
- 'databaseId' | 'featuredImage' | 'slug' | 'title'
->;
-
-export type RawTopic = RawPage & {
- acfTopics: ACFTopics;
-};
-
-export type RawTopicPreview = Pick<
- RawTopic,
- 'databaseId' | 'featuredImage' | 'slug' | 'title'
->;
-
-export type TotalItems = {
- pageInfo: Pick<GraphQLPageInfo, 'total'>;
-};