diff --git a/apollo.config.js b/apollo.config.js index ac6f8a0..dc86a90 100644 --- a/apollo.config.js +++ b/apollo.config.js @@ -2,10 +2,9 @@ module.exports = { client: { includes: ['src/**/*.{ts,tsx}'], service: { - name: 'unbody-graphql', + name: 'strapi-graphql', localSchemaFile: [ - './src/lib/unbody/unbody.graphql', - './src/lib/unbody/unbody.extend.graphql', + './src/lib/strapi/strapi.graphql', ], // how to configure to multiple schemas? }, }, diff --git a/codegen.ts b/codegen.ts index 093d429..be2bb61 100644 --- a/codegen.ts +++ b/codegen.ts @@ -1,8 +1,7 @@ import { CodegenConfig } from '@graphql-codegen/cli' -const graphqlEndpoint = 'https://graphql.unbody.io' -const projectId = process.env.UNBODY_PROJECT_ID || '' -const authorization = process.env.UNBODY_API_KEY || '' +const graphqlEndpoint = process.env.STRAPI_GRAPHQL_URL || '' +const token = process.env.STRAPI_API_KEY || '' const config: CodegenConfig = { overwrite: true, @@ -10,21 +9,19 @@ const config: CodegenConfig = { { [graphqlEndpoint]: { headers: { - authorization, - 'x-project-id': projectId, + authorization: token, 'Content-Type': 'application/json', Accept: 'application/json', }, }, }, - 'src/lib/unbody/unbody.extend.graphql', ], - documents: ['src/**/*.{ts,tsx}'], + documents: ['src/services/strapi/*.{ts,tsx}'], generates: { - 'src/lib/unbody/unbody.graphql': { + 'src/lib/strapi/strapi.graphql': { plugins: ['schema-ast'], }, - 'src/lib/unbody/unbody.generated.ts': { + 'src/lib/strapi/strapi.generated.ts': { plugins: ['typescript', 'typescript-operations', 'typed-document-node'], presetConfig: { fragmentMasking: false, diff --git a/next.config.js b/next.config.js index ffcdf44..743b7a5 100644 --- a/next.config.js +++ b/next.config.js @@ -3,12 +3,11 @@ const nextConfig = { reactStrictMode: true, images: { domains: [ - 'images.cdn.unbody.io', + 'localhost', + '127.0.0.1', 'image.simplecastcdn.com', 'img.youtube.com', ], - // loader: 'imgix', - // path: 'https://images.cdn.unbody.io', }, } diff --git a/package.json b/package.json index 127d411..760a59c 100644 --- a/package.json +++ b/package.json @@ -51,6 +51,7 @@ "next": "13.3.0", "next-query-params": "^4.2.3", "nextjs-progressbar": "^0.0.16", + "node-html-parser": "^6.1.12", "odoo-await": "^3.4.1", "react": "18.2.0", "react-blurhash": "^0.3.0", @@ -59,6 +60,7 @@ "react-player": "^2.12.0", "react-quick-pinch-zoom": "^4.9.0", "react-use": "^17.4.0", + "slugify": "^1.6.6", "typescript": "5.0.4", "use-query-params": "^2.2.1", "yup": "^1.3.2" diff --git a/src/components/Article/Article.Block.tsx b/src/components/Article/Article.Block.tsx index 051ce69..45d2fd6 100644 --- a/src/components/Article/Article.Block.tsx +++ b/src/components/Article/Article.Block.tsx @@ -39,6 +39,17 @@ export const RenderArticleBlock = ({ case 'h6': { return } + case 'blockquote': + return ( + + + + ) case 'p': { const isIframe = block.embed && block.labels.includes('embed') if (block.embed && isIframe) { @@ -56,22 +67,6 @@ export const RenderArticleBlock = ({ ) } - if ( - block.classNames.includes('subtitle') && - block.classNames.includes('u-with-margin-left') - ) { - return ( - - - - ) - } - return ( { return ( - + diff --git a/src/components/Article/Header/Article.Header.tsx b/src/components/Article/Header/Article.Header.tsx index b6b3fec..2ba200e 100644 --- a/src/components/Article/Header/Article.Header.tsx +++ b/src/components/Article/Header/Article.Header.tsx @@ -15,6 +15,7 @@ import ArticleSummary from './Article.Summary' export type ArticleHeaderProps = LPE.Article.Data const ArticleHeader = ({ + title, summary, subtitle, authors, @@ -33,19 +34,15 @@ const ArticleHeader = ({ date={modifiedAt ? new Date(modifiedAt) : null} readingLength={readingTime} /> - - block.labels.includes(LPE.Article.ContentBlockLabels.Title), - ) as LPE.Article.TextBlock - } - typographyProps={{ - variant: 'h1', - genericFontFamily: 'serif', - component: 'h1', + { + headingElementsRef.current['h-0'] = ref as HTMLHeadingElement }} - headingElementsRef={headingElementsRef} - /> + > + + {title} + {subtitle && ( )} - + tag.name)} + className={'articleTags'} + /> @@ -65,7 +65,9 @@ const ArticleHeader = ({ order={ArticleBlocksOrders.cover} /> )} - + {summary && summary.length > 0 && ( + + )} ) } diff --git a/src/components/Episode/Episode.Transcript.tsx b/src/components/Episode/Episode.Transcript.tsx index 2c58238..85634d9 100644 --- a/src/components/Episode/Episode.Transcript.tsx +++ b/src/components/Episode/Episode.Transcript.tsx @@ -4,6 +4,8 @@ import { LPE } from '../../types/lpe.types' import EpisodeBlocks from './Episode.Blocks' const EpisodeTranscript = ({ episode }: { episode: LPE.Podcast.Document }) => { + if (episode.content.length === 0) return <> + return ( diff --git a/src/components/Episode/Footer/Episode.Credits.tsx b/src/components/Episode/Footer/Episode.Credits.tsx index 12f1064..021508b 100644 --- a/src/components/Episode/Footer/Episode.Credits.tsx +++ b/src/components/Episode/Footer/Episode.Credits.tsx @@ -24,9 +24,8 @@ const EpisodeCredits = ({ component="p" variant="label1" id={credit.id.replace('#', '')} - > - {credit.text} - </Typography> + dangerouslySetInnerHTML={{ __html: credit.html }} + /> </Credit> ))} </Credits> diff --git a/src/components/Episode/Footer/Episode.Footer.tsx b/src/components/Episode/Footer/Episode.Footer.tsx index b0acc5e..531fd8f 100644 --- a/src/components/Episode/Footer/Episode.Footer.tsx +++ b/src/components/Episode/Footer/Episode.Footer.tsx @@ -26,7 +26,7 @@ const EpisodeFooter = ({ episode, relatedEpisodes }: Props) => { <EpisodeFooterContainer> {!!episode?.credits && <EpisodeCredits credits={episode.credits} />} {!!footnotes && <EpisodeFootnotes footnotes={footnotes} />} - {!!relatedEpisodes && ( + {!!relatedEpisodes && relatedEpisodes.length > 0 && ( <RelatedEpisodes podcastSlug={episode.show?.slug as string} relatedEpisodes={relatedEpisodes} diff --git a/src/components/Episode/Header/Episode.Header.tsx b/src/components/Episode/Header/Episode.Header.tsx index 7f5af37..9584e51 100644 --- a/src/components/Episode/Header/Episode.Header.tsx +++ b/src/components/Episode/Header/Episode.Header.tsx @@ -54,7 +54,7 @@ const EpisodeHeader = ({ </Show> </CustomLink> )} - <TagsAndSocial tags={tags} /> + <TagsAndSocial tags={tags.map((tag) => tag.name)} /> {channels && <EpisodeChannels channels={channels} />} {description && ( <ArticleSummary summary={description} showLabel={false} /> diff --git a/src/components/GlobalAudioPlayer/episode.state.ts b/src/components/GlobalAudioPlayer/episode.state.ts index 6d5799a..23f6ffb 100644 --- a/src/components/GlobalAudioPlayer/episode.state.ts +++ b/src/components/GlobalAudioPlayer/episode.state.ts @@ -5,7 +5,7 @@ export type EpisodeState = { title: string podcast: string url: string - coverImage: LPE.Post.ImageBlock | null + coverImage: LPE.Image.Document | null path: string } diff --git a/src/components/PostCard/PostCard.tsx b/src/components/PostCard/PostCard.tsx index be0b5cf..ca0e042 100644 --- a/src/components/PostCard/PostCard.tsx +++ b/src/components/PostCard/PostCard.tsx @@ -156,7 +156,7 @@ PostCard.toData = (post: LPE.Post.Document, shows: LPE.Podcast.Show[] = []) => { authors: post.type === 'article' ? post.authors : [], coverImage: post.coverImage, subtitle: (post.type === 'article' && post.subtitle) || '', - tags: post.tags, + tags: post.tags.map((tag) => tag.name), ...(post.type === 'podcast' && show ? { podcastShowDetails: { diff --git a/src/components/PostList/PostList.tsx b/src/components/PostList/PostList.tsx index e030f53..581de95 100644 --- a/src/components/PostList/PostList.tsx +++ b/src/components/PostList/PostList.tsx @@ -67,7 +67,7 @@ export const PostsList = (props: Props) => { title: post.title, subtitle: post.subtitle, coverImage: post.coverImage, - tags: post.tags, + tags: post.tags.map((tag) => tag.name), }} contentType={PostTypes.Article} /> diff --git a/src/containers/HomePage/HomePage.tsx b/src/containers/HomePage/HomePage.tsx index 550947c..deb1b4e 100644 --- a/src/containers/HomePage/HomePage.tsx +++ b/src/containers/HomePage/HomePage.tsx @@ -41,6 +41,7 @@ export const HomePage: React.FC<HomePageProps> = ({ <Container> <div> <PostsGrid + shows={shows} posts={highlighted.slice(0, 1)} pattern={[{ cols: 1, size: 'large' }]} breakpoints={[ @@ -56,6 +57,7 @@ export const HomePage: React.FC<HomePageProps> = ({ /> <Section title="Latest posts"> <PostsGrid + shows={shows} pattern={[{ cols: 4, size: 'small' }]} breakpoints={[ { @@ -103,11 +105,11 @@ export const HomePage: React.FC<HomePageProps> = ({ </div> <Grid xs={{ cols: 1 }} sm={{ cols: 4 }}> {tags.map((tag) => ( - <GridItem key={tag.value} cols={1}> + <GridItem key={tag.name} cols={1}> <TagCard - href={`/search?topic=${tag.value}`} - name={formatTagText(tag.value)} - count={tag.count} + href={`/search?topic=${tag.name}`} + name={formatTagText(tag.name)} + count={tag.postsCount} /> </GridItem> ))} diff --git a/src/containers/StaticPage/StaticPage.tsx b/src/containers/StaticPage/StaticPage.tsx index dc45cda..55b10bb 100644 --- a/src/containers/StaticPage/StaticPage.tsx +++ b/src/containers/StaticPage/StaticPage.tsx @@ -18,22 +18,12 @@ export const StaticPage: React.FC<StaticPageProps> = ({ data: { page }, ...props }) => { - const titleBlock = data.page.content.find((block) => { - return ( - block.type === LPE.Post.ContentBlockTypes.Text && - block.classNames && - block.classNames.includes('title') - ) - }) as LPE.Post.TextBlock | undefined - return ( <Root {...props}> <article> - {titleBlock && ( - <Typography variant={'h1'} genericFontFamily={'serif'}> - {titleBlock.text} - </Typography> - )} + <Typography variant={'h1'} genericFontFamily={'serif'}> + {page.title} + </Typography> {data.page.content.map((block, idx) => ( <RenderArticleBlock block={block} activeId={null} key={idx} /> ))} diff --git a/src/lib/TransformPipeline/TransformPipeline.ts b/src/lib/TransformPipeline/TransformPipeline.ts new file mode 100644 index 0000000..6202f26 --- /dev/null +++ b/src/lib/TransformPipeline/TransformPipeline.ts @@ -0,0 +1,87 @@ +import { Helpers, Transformer } from './types' + +export class TransformPipeline { + private transformers: Transformer[] = [] + private helpers: Helpers + + constructor(transformers: Transformer<any>[]) { + this.transformers = transformers + + this.helpers = { + transformers: this, + } + } + + getOne = ({ + key, + classes, + objectType, + }: { + key?: string + classes?: string | string[] + objectType?: string + }) => { + let transformers = this.transformers + + if (key) { + return transformers.find((doc) => doc.key === key) + } + + return this.get({ classes, objectType })[0] + } + + get = ({ + classes: _classes, + objectType, + }: { + classes?: string | string[] + objectType?: string + }) => { + let transformers = this.transformers + + if (objectType) + transformers = transformers.filter( + (dataType) => dataType.objectType === objectType, + ) + + const classes = !_classes + ? [] + : Array.isArray(_classes) + ? _classes + : [_classes] + if (classes.length > 0) + transformers = transformers.filter((dataType) => + classes.every((cls) => dataType.classes.includes(cls)), + ) + + return transformers + } + + transform = async <O = any, T = any>( + pipeline: Transformer[], + data: T, + root?: any, + context?: any, + ): Promise<O> => { + let obj = data + + for (const dataType of pipeline) { + if (dataType.isMatch(this.helpers, obj, data, root, context)) { + obj = await dataType.transform(this.helpers, obj, data, root, context) + } + } + + return obj as O | Promise<O> + } + + transformMany = async <O = any, T = any>( + pipeline: Transformer[], + data: T[], + root?: any, + context?: any, + ): Promise<O[]> => { + return Promise.all( + data.map((d) => this.transform<O, T>(pipeline, d, root, context)), + ) + } +} diff --git a/src/lib/TransformPipeline/types.ts b/src/lib/TransformPipeline/types.ts new file mode 100644 index 0000000..4920f97 --- /dev/null +++ b/src/lib/TransformPipeline/types.ts @@ -0,0 +1,27 @@ +import { TransformPipeline } from './TransformPipeline' + +export type Transformer<D = any, T = any, O = any, R = any, C = any> = { + key: string + classes: string[] + objectType: string + + isMatch: ( + helpers: Helpers, + object: D, + original: O, + root: R | undefined, + context: C, + ) => boolean + + transform: ( + helpers: Helpers, + object: D, + original: O, + root: R | undefined, + context: C, + ) => T | Promise<T> +} + +export type Helpers = { + transformers: TransformPipeline +} diff --git a/src/lib/strapi/strapi.generated.ts b/src/lib/strapi/strapi.generated.ts new file mode 100644 index 0000000..1b7d421 --- /dev/null +++ b/src/lib/strapi/strapi.generated.ts @@ -0,0 +1,3129 @@ +import { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core' +export type Maybe<T> = T +export type InputMaybe<T> = T +export type Exact<T extends { [key: string]: unknown }> = { + [K in keyof T]: T[K] +} +export type MakeOptional<T, K extends keyof T> = Omit<T, K> & { + [SubKey in K]?: Maybe<T[SubKey]> +} +export type MakeMaybe<T, K extends keyof T> = Omit<T, K> & { + [SubKey in K]: Maybe<T[SubKey]> +} +export type MakeEmpty< + T extends { [key: string]: unknown }, + K extends keyof T, +> = { [_ in K]?: never } +export type Incremental<T> = + | T + | { + [P in keyof T]?: P extends ' $fragmentName' | '__typename' ? T[P] : never + } +/** All built-in and custom scalars, mapped to their actual values */ +export type Scalars = { + ID: { input: string; output: string } + String: { input: string; output: string } + Boolean: { input: boolean; output: boolean } + Int: { input: number; output: number } + Float: { input: number; output: number } + Date: { input: any; output: any } + DateTime: { input: any; output: any } + JSON: { input: any; output: any } + Upload: { input: any; output: any } +} + +export type Author = { + __typename?: 'Author' + avatar: Maybe<UploadFileEntityResponse> + createdAt: Maybe<Scalars['DateTime']['output']> + email_address: Maybe<Scalars['String']['output']> + name: Scalars['String']['output'] + updatedAt: Maybe<Scalars['DateTime']['output']> +} + +export type AuthorEntity = { + __typename?: 'AuthorEntity' + attributes: Maybe<Author> + id: Maybe<Scalars['ID']['output']> +} + +export type AuthorEntityResponse = { + __typename?: 'AuthorEntityResponse' + data: Maybe<AuthorEntity> +} + +export type AuthorEntityResponseCollection = { + __typename?: 'AuthorEntityResponseCollection' + data: Array<AuthorEntity> + meta: ResponseCollectionMeta +} + +export type AuthorFiltersInput = { + and?: InputMaybe<Array<InputMaybe<AuthorFiltersInput>>> + createdAt?: InputMaybe<DateTimeFilterInput> + email_address?: InputMaybe<StringFilterInput> + id?: InputMaybe<IdFilterInput> + name?: InputMaybe<StringFilterInput> + not?: InputMaybe<AuthorFiltersInput> + or?: InputMaybe<Array<InputMaybe<AuthorFiltersInput>>> + updatedAt?: InputMaybe<DateTimeFilterInput> +} + +export type AuthorInput = { + avatar?: InputMaybe<Scalars['ID']['input']> + email_address?: InputMaybe<Scalars['String']['input']> + name?: InputMaybe<Scalars['String']['input']> +} + +export type AuthorRelationResponseCollection = { + __typename?: 'AuthorRelationResponseCollection' + data: Array<AuthorEntity> +} + +export type BooleanFilterInput = { + and?: InputMaybe<Array<InputMaybe<Scalars['Boolean']['input']>>> + between?: InputMaybe<Array<InputMaybe<Scalars['Boolean']['input']>>> + contains?: InputMaybe<Scalars['Boolean']['input']> + containsi?: InputMaybe<Scalars['Boolean']['input']> + endsWith?: InputMaybe<Scalars['Boolean']['input']> + eq?: InputMaybe<Scalars['Boolean']['input']> + eqi?: InputMaybe<Scalars['Boolean']['input']> + gt?: InputMaybe<Scalars['Boolean']['input']> + gte?: InputMaybe<Scalars['Boolean']['input']> + in?: InputMaybe<Array<InputMaybe<Scalars['Boolean']['input']>>> + lt?: InputMaybe<Scalars['Boolean']['input']> + lte?: InputMaybe<Scalars['Boolean']['input']> + ne?: InputMaybe<Scalars['Boolean']['input']> + nei?: InputMaybe<Scalars['Boolean']['input']> + not?: InputMaybe<BooleanFilterInput> + notContains?: InputMaybe<Scalars['Boolean']['input']> + notContainsi?: InputMaybe<Scalars['Boolean']['input']> + notIn?: InputMaybe<Array<InputMaybe<Scalars['Boolean']['input']>>> + notNull?: InputMaybe<Scalars['Boolean']['input']> + null?: InputMaybe<Scalars['Boolean']['input']> + or?: InputMaybe<Array<InputMaybe<Scalars['Boolean']['input']>>> + startsWith?: InputMaybe<Scalars['Boolean']['input']> +} + +export type ComponentCatChannel = { + __typename?: 'ComponentCatChannel' + channel: Maybe<Enum_Componentcatchannel_Channel> + id: Scalars['ID']['output'] + link: Scalars['String']['output'] +} + +export type ComponentCatChannelFiltersInput = { + and?: InputMaybe<Array<InputMaybe<ComponentCatChannelFiltersInput>>> + channel?: InputMaybe<StringFilterInput> + link?: InputMaybe<StringFilterInput> + not?: InputMaybe<ComponentCatChannelFiltersInput> + or?: InputMaybe<Array<InputMaybe<ComponentCatChannelFiltersInput>>> +} + +export type ComponentCatChannelInput = { + channel?: InputMaybe<Enum_Componentcatchannel_Channel> + id?: InputMaybe<Scalars['ID']['input']> + link?: InputMaybe<Scalars['String']['input']> +} + +export type ContentReleasesRelease = { + __typename?: 'ContentReleasesRelease' + actions: Maybe<ContentReleasesReleaseActionRelationResponseCollection> + createdAt: Maybe<Scalars['DateTime']['output']> + name: Scalars['String']['output'] + releasedAt: Maybe<Scalars['DateTime']['output']> + updatedAt: Maybe<Scalars['DateTime']['output']> +} + +export type ContentReleasesReleaseActionsArgs = { + filters?: InputMaybe<ContentReleasesReleaseActionFiltersInput> + pagination?: InputMaybe<PaginationArg> + sort?: InputMaybe<Array<InputMaybe<Scalars['String']['input']>>> +} + +export type ContentReleasesReleaseAction = { + __typename?: 'ContentReleasesReleaseAction' + contentType: Scalars['String']['output'] + createdAt: Maybe<Scalars['DateTime']['output']> + entry: Maybe<GenericMorph> + release: Maybe<ContentReleasesReleaseEntityResponse> + type: Enum_Contentreleasesreleaseaction_Type + updatedAt: Maybe<Scalars['DateTime']['output']> +} + +export type ContentReleasesReleaseActionEntity = { + __typename?: 'ContentReleasesReleaseActionEntity' + attributes: Maybe<ContentReleasesReleaseAction> + id: Maybe<Scalars['ID']['output']> +} + +export type ContentReleasesReleaseActionEntityResponse = { + __typename?: 'ContentReleasesReleaseActionEntityResponse' + data: Maybe<ContentReleasesReleaseActionEntity> +} + +export type ContentReleasesReleaseActionEntityResponseCollection = { + __typename?: 'ContentReleasesReleaseActionEntityResponseCollection' + data: Array<ContentReleasesReleaseActionEntity> + meta: ResponseCollectionMeta +} + +export type ContentReleasesReleaseActionFiltersInput = { + and?: InputMaybe<Array<InputMaybe<ContentReleasesReleaseActionFiltersInput>>> + contentType?: InputMaybe<StringFilterInput> + createdAt?: InputMaybe<DateTimeFilterInput> + id?: InputMaybe<IdFilterInput> + not?: InputMaybe<ContentReleasesReleaseActionFiltersInput> + or?: InputMaybe<Array<InputMaybe<ContentReleasesReleaseActionFiltersInput>>> + release?: InputMaybe<ContentReleasesReleaseFiltersInput> + type?: InputMaybe<StringFilterInput> + updatedAt?: InputMaybe<DateTimeFilterInput> +} + +export type ContentReleasesReleaseActionInput = { + contentType?: InputMaybe<Scalars['String']['input']> + release?: InputMaybe<Scalars['ID']['input']> + type?: InputMaybe<Enum_Contentreleasesreleaseaction_Type> +} + +export type ContentReleasesReleaseActionRelationResponseCollection = { + __typename?: 'ContentReleasesReleaseActionRelationResponseCollection' + data: Array<ContentReleasesReleaseActionEntity> +} + +export type ContentReleasesReleaseEntity = { + __typename?: 'ContentReleasesReleaseEntity' + attributes: Maybe<ContentReleasesRelease> + id: Maybe<Scalars['ID']['output']> +} + +export type ContentReleasesReleaseEntityResponse = { + __typename?: 'ContentReleasesReleaseEntityResponse' + data: Maybe<ContentReleasesReleaseEntity> +} + +export type ContentReleasesReleaseEntityResponseCollection = { + __typename?: 'ContentReleasesReleaseEntityResponseCollection' + data: Array<ContentReleasesReleaseEntity> + meta: ResponseCollectionMeta +} + +export type ContentReleasesReleaseFiltersInput = { + actions?: InputMaybe<ContentReleasesReleaseActionFiltersInput> + and?: InputMaybe<Array<InputMaybe<ContentReleasesReleaseFiltersInput>>> + createdAt?: InputMaybe<DateTimeFilterInput> + id?: InputMaybe<IdFilterInput> + name?: InputMaybe<StringFilterInput> + not?: InputMaybe<ContentReleasesReleaseFiltersInput> + or?: InputMaybe<Array<InputMaybe<ContentReleasesReleaseFiltersInput>>> + releasedAt?: InputMaybe<DateTimeFilterInput> + updatedAt?: InputMaybe<DateTimeFilterInput> +} + +export type ContentReleasesReleaseInput = { + actions?: InputMaybe<Array<InputMaybe<Scalars['ID']['input']>>> + name?: InputMaybe<Scalars['String']['input']> + releasedAt?: InputMaybe<Scalars['DateTime']['input']> +} + +export type DateFilterInput = { + and?: InputMaybe<Array<InputMaybe<Scalars['Date']['input']>>> + between?: InputMaybe<Array<InputMaybe<Scalars['Date']['input']>>> + contains?: InputMaybe<Scalars['Date']['input']> + containsi?: InputMaybe<Scalars['Date']['input']> + endsWith?: InputMaybe<Scalars['Date']['input']> + eq?: InputMaybe<Scalars['Date']['input']> + eqi?: InputMaybe<Scalars['Date']['input']> + gt?: InputMaybe<Scalars['Date']['input']> + gte?: InputMaybe<Scalars['Date']['input']> + in?: InputMaybe<Array<InputMaybe<Scalars['Date']['input']>>> + lt?: InputMaybe<Scalars['Date']['input']> + lte?: InputMaybe<Scalars['Date']['input']> + ne?: InputMaybe<Scalars['Date']['input']> + nei?: InputMaybe<Scalars['Date']['input']> + not?: InputMaybe<DateFilterInput> + notContains?: InputMaybe<Scalars['Date']['input']> + notContainsi?: InputMaybe<Scalars['Date']['input']> + notIn?: InputMaybe<Array<InputMaybe<Scalars['Date']['input']>>> + notNull?: InputMaybe<Scalars['Boolean']['input']> + null?: InputMaybe<Scalars['Boolean']['input']> + or?: InputMaybe<Array<InputMaybe<Scalars['Date']['input']>>> + startsWith?: InputMaybe<Scalars['Date']['input']> +} + +export type DateTimeFilterInput = { + and?: InputMaybe<Array<InputMaybe<Scalars['DateTime']['input']>>> + between?: InputMaybe<Array<InputMaybe<Scalars['DateTime']['input']>>> + contains?: InputMaybe<Scalars['DateTime']['input']> + containsi?: InputMaybe<Scalars['DateTime']['input']> + endsWith?: InputMaybe<Scalars['DateTime']['input']> + eq?: InputMaybe<Scalars['DateTime']['input']> + eqi?: InputMaybe<Scalars['DateTime']['input']> + gt?: InputMaybe<Scalars['DateTime']['input']> + gte?: InputMaybe<Scalars['DateTime']['input']> + in?: InputMaybe<Array<InputMaybe<Scalars['DateTime']['input']>>> + lt?: InputMaybe<Scalars['DateTime']['input']> + lte?: InputMaybe<Scalars['DateTime']['input']> + ne?: InputMaybe<Scalars['DateTime']['input']> + nei?: InputMaybe<Scalars['DateTime']['input']> + not?: InputMaybe<DateTimeFilterInput> + notContains?: InputMaybe<Scalars['DateTime']['input']> + notContainsi?: InputMaybe<Scalars['DateTime']['input']> + notIn?: InputMaybe<Array<InputMaybe<Scalars['DateTime']['input']>>> + notNull?: InputMaybe<Scalars['Boolean']['input']> + null?: InputMaybe<Scalars['Boolean']['input']> + or?: InputMaybe<Array<InputMaybe<Scalars['DateTime']['input']>>> + startsWith?: InputMaybe<Scalars['DateTime']['input']> +} + +export type Enum_Componentcatchannel_Channel = + | 'Apple_Podcasts' + | 'Google_Podcasts' + | 'Simplecast' + | 'Spotify' + | 'Youtube' + +export type Enum_Contentreleasesreleaseaction_Type = 'publish' | 'unpublish' + +export type Enum_Post_Type = 'Article' | 'Episode' + +export type FileInfoInput = { + alternativeText?: InputMaybe<Scalars['String']['input']> + caption?: InputMaybe<Scalars['String']['input']> + name?: InputMaybe<Scalars['String']['input']> +} + +export type FloatFilterInput = { + and?: InputMaybe<Array<InputMaybe<Scalars['Float']['input']>>> + between?: InputMaybe<Array<InputMaybe<Scalars['Float']['input']>>> + contains?: InputMaybe<Scalars['Float']['input']> + containsi?: InputMaybe<Scalars['Float']['input']> + endsWith?: InputMaybe<Scalars['Float']['input']> + eq?: InputMaybe<Scalars['Float']['input']> + eqi?: InputMaybe<Scalars['Float']['input']> + gt?: InputMaybe<Scalars['Float']['input']> + gte?: InputMaybe<Scalars['Float']['input']> + in?: InputMaybe<Array<InputMaybe<Scalars['Float']['input']>>> + lt?: InputMaybe<Scalars['Float']['input']> + lte?: InputMaybe<Scalars['Float']['input']> + ne?: InputMaybe<Scalars['Float']['input']> + nei?: InputMaybe<Scalars['Float']['input']> + not?: InputMaybe<FloatFilterInput> + notContains?: InputMaybe<Scalars['Float']['input']> + notContainsi?: InputMaybe<Scalars['Float']['input']> + notIn?: InputMaybe<Array<InputMaybe<Scalars['Float']['input']>>> + notNull?: InputMaybe<Scalars['Boolean']['input']> + null?: InputMaybe<Scalars['Boolean']['input']> + or?: InputMaybe<Array<InputMaybe<Scalars['Float']['input']>>> + startsWith?: InputMaybe<Scalars['Float']['input']> +} + +export type GenericMorph = + | Author + | ComponentCatChannel + | ContentReleasesRelease + | ContentReleasesReleaseAction + | I18NLocale + | Page + | PodcastShow + | Post + | Tag + | UploadFile + | UploadFolder + | UsersPermissionsPermission + | UsersPermissionsRole + | UsersPermissionsUser + +export type I18NLocale = { + __typename?: 'I18NLocale' + code: Maybe<Scalars['String']['output']> + createdAt: Maybe<Scalars['DateTime']['output']> + name: Maybe<Scalars['String']['output']> + updatedAt: Maybe<Scalars['DateTime']['output']> +} + +export type I18NLocaleEntity = { + __typename?: 'I18NLocaleEntity' + attributes: Maybe<I18NLocale> + id: Maybe<Scalars['ID']['output']> +} + +export type I18NLocaleEntityResponse = { + __typename?: 'I18NLocaleEntityResponse' + data: Maybe<I18NLocaleEntity> +} + +export type I18NLocaleEntityResponseCollection = { + __typename?: 'I18NLocaleEntityResponseCollection' + data: Array<I18NLocaleEntity> + meta: ResponseCollectionMeta +} + +export type I18NLocaleFiltersInput = { + and?: InputMaybe<Array<InputMaybe<I18NLocaleFiltersInput>>> + code?: InputMaybe<StringFilterInput> + createdAt?: InputMaybe<DateTimeFilterInput> + id?: InputMaybe<IdFilterInput> + name?: InputMaybe<StringFilterInput> + not?: InputMaybe<I18NLocaleFiltersInput> + or?: InputMaybe<Array<InputMaybe<I18NLocaleFiltersInput>>> + updatedAt?: InputMaybe<DateTimeFilterInput> +} + +export type IdFilterInput = { + and?: InputMaybe<Array<InputMaybe<Scalars['ID']['input']>>> + between?: InputMaybe<Array<InputMaybe<Scalars['ID']['input']>>> + contains?: InputMaybe<Scalars['ID']['input']> + containsi?: InputMaybe<Scalars['ID']['input']> + endsWith?: InputMaybe<Scalars['ID']['input']> + eq?: InputMaybe<Scalars['ID']['input']> + eqi?: InputMaybe<Scalars['ID']['input']> + gt?: InputMaybe<Scalars['ID']['input']> + gte?: InputMaybe<Scalars['ID']['input']> + in?: InputMaybe<Array<InputMaybe<Scalars['ID']['input']>>> + lt?: InputMaybe<Scalars['ID']['input']> + lte?: InputMaybe<Scalars['ID']['input']> + ne?: InputMaybe<Scalars['ID']['input']> + nei?: InputMaybe<Scalars['ID']['input']> + not?: InputMaybe<IdFilterInput> + notContains?: InputMaybe<Scalars['ID']['input']> + notContainsi?: InputMaybe<Scalars['ID']['input']> + notIn?: InputMaybe<Array<InputMaybe<Scalars['ID']['input']>>> + notNull?: InputMaybe<Scalars['Boolean']['input']> + null?: InputMaybe<Scalars['Boolean']['input']> + or?: InputMaybe<Array<InputMaybe<Scalars['ID']['input']>>> + startsWith?: InputMaybe<Scalars['ID']['input']> +} + +export type IntFilterInput = { + and?: InputMaybe<Array<InputMaybe<Scalars['Int']['input']>>> + between?: InputMaybe<Array<InputMaybe<Scalars['Int']['input']>>> + contains?: InputMaybe<Scalars['Int']['input']> + containsi?: InputMaybe<Scalars['Int']['input']> + endsWith?: InputMaybe<Scalars['Int']['input']> + eq?: InputMaybe<Scalars['Int']['input']> + eqi?: InputMaybe<Scalars['Int']['input']> + gt?: InputMaybe<Scalars['Int']['input']> + gte?: InputMaybe<Scalars['Int']['input']> + in?: InputMaybe<Array<InputMaybe<Scalars['Int']['input']>>> + lt?: InputMaybe<Scalars['Int']['input']> + lte?: InputMaybe<Scalars['Int']['input']> + ne?: InputMaybe<Scalars['Int']['input']> + nei?: InputMaybe<Scalars['Int']['input']> + not?: InputMaybe<IntFilterInput> + notContains?: InputMaybe<Scalars['Int']['input']> + notContainsi?: InputMaybe<Scalars['Int']['input']> + notIn?: InputMaybe<Array<InputMaybe<Scalars['Int']['input']>>> + notNull?: InputMaybe<Scalars['Boolean']['input']> + null?: InputMaybe<Scalars['Boolean']['input']> + or?: InputMaybe<Array<InputMaybe<Scalars['Int']['input']>>> + startsWith?: InputMaybe<Scalars['Int']['input']> +} + +export type JsonFilterInput = { + and?: InputMaybe<Array<InputMaybe<Scalars['JSON']['input']>>> + between?: InputMaybe<Array<InputMaybe<Scalars['JSON']['input']>>> + contains?: InputMaybe<Scalars['JSON']['input']> + containsi?: InputMaybe<Scalars['JSON']['input']> + endsWith?: InputMaybe<Scalars['JSON']['input']> + eq?: InputMaybe<Scalars['JSON']['input']> + eqi?: InputMaybe<Scalars['JSON']['input']> + gt?: InputMaybe<Scalars['JSON']['input']> + gte?: InputMaybe<Scalars['JSON']['input']> + in?: InputMaybe<Array<InputMaybe<Scalars['JSON']['input']>>> + lt?: InputMaybe<Scalars['JSON']['input']> + lte?: InputMaybe<Scalars['JSON']['input']> + ne?: InputMaybe<Scalars['JSON']['input']> + nei?: InputMaybe<Scalars['JSON']['input']> + not?: InputMaybe<JsonFilterInput> + notContains?: InputMaybe<Scalars['JSON']['input']> + notContainsi?: InputMaybe<Scalars['JSON']['input']> + notIn?: InputMaybe<Array<InputMaybe<Scalars['JSON']['input']>>> + notNull?: InputMaybe<Scalars['Boolean']['input']> + null?: InputMaybe<Scalars['Boolean']['input']> + or?: InputMaybe<Array<InputMaybe<Scalars['JSON']['input']>>> + startsWith?: InputMaybe<Scalars['JSON']['input']> +} + +export type Mutation = { + __typename?: 'Mutation' + /** Change user password. Confirm with the current password. */ + changePassword: Maybe<UsersPermissionsLoginPayload> + createAuthor: Maybe<AuthorEntityResponse> + createContentReleasesRelease: Maybe<ContentReleasesReleaseEntityResponse> + createContentReleasesReleaseAction: Maybe<ContentReleasesReleaseActionEntityResponse> + createPage: Maybe<PageEntityResponse> + createPodcastShow: Maybe<PodcastShowEntityResponse> + createPost: Maybe<PostEntityResponse> + createTag: Maybe<TagEntityResponse> + createUploadFile: Maybe<UploadFileEntityResponse> + createUploadFolder: Maybe<UploadFolderEntityResponse> + /** Create a new role */ + createUsersPermissionsRole: Maybe<UsersPermissionsCreateRolePayload> + /** Create a new user */ + createUsersPermissionsUser: UsersPermissionsUserEntityResponse + deleteAuthor: Maybe<AuthorEntityResponse> + deleteContentReleasesRelease: Maybe<ContentReleasesReleaseEntityResponse> + deleteContentReleasesReleaseAction: Maybe<ContentReleasesReleaseActionEntityResponse> + deletePage: Maybe<PageEntityResponse> + deletePodcastShow: Maybe<PodcastShowEntityResponse> + deletePost: Maybe<PostEntityResponse> + deleteTag: Maybe<TagEntityResponse> + deleteUploadFile: Maybe<UploadFileEntityResponse> + deleteUploadFolder: Maybe<UploadFolderEntityResponse> + /** Delete an existing role */ + deleteUsersPermissionsRole: Maybe<UsersPermissionsDeleteRolePayload> + /** Delete an existing user */ + deleteUsersPermissionsUser: UsersPermissionsUserEntityResponse + /** Confirm an email users email address */ + emailConfirmation: Maybe<UsersPermissionsLoginPayload> + /** Request a reset password token */ + forgotPassword: Maybe<UsersPermissionsPasswordPayload> + login: UsersPermissionsLoginPayload + multipleUpload: Array<Maybe<UploadFileEntityResponse>> + /** Register a user */ + register: UsersPermissionsLoginPayload + removeFile: Maybe<UploadFileEntityResponse> + /** Reset user password. Confirm with a code (resetToken from forgotPassword) */ + resetPassword: Maybe<UsersPermissionsLoginPayload> + updateAuthor: Maybe<AuthorEntityResponse> + updateContentReleasesRelease: Maybe<ContentReleasesReleaseEntityResponse> + updateContentReleasesReleaseAction: Maybe<ContentReleasesReleaseActionEntityResponse> + updateFileInfo: UploadFileEntityResponse + updatePage: Maybe<PageEntityResponse> + updatePodcastShow: Maybe<PodcastShowEntityResponse> + updatePost: Maybe<PostEntityResponse> + updateTag: Maybe<TagEntityResponse> + updateUploadFile: Maybe<UploadFileEntityResponse> + updateUploadFolder: Maybe<UploadFolderEntityResponse> + /** Update an existing role */ + updateUsersPermissionsRole: Maybe<UsersPermissionsUpdateRolePayload> + /** Update an existing user */ + updateUsersPermissionsUser: UsersPermissionsUserEntityResponse + upload: UploadFileEntityResponse +} + +export type MutationChangePasswordArgs = { + currentPassword: Scalars['String']['input'] + password: Scalars['String']['input'] + passwordConfirmation: Scalars['String']['input'] +} + +export type MutationCreateAuthorArgs = { + data: AuthorInput +} + +export type MutationCreateContentReleasesReleaseArgs = { + data: ContentReleasesReleaseInput +} + +export type MutationCreateContentReleasesReleaseActionArgs = { + data: ContentReleasesReleaseActionInput +} + +export type MutationCreatePageArgs = { + data: PageInput +} + +export type MutationCreatePodcastShowArgs = { + data: PodcastShowInput +} + +export type MutationCreatePostArgs = { + data: PostInput +} + +export type MutationCreateTagArgs = { + data: TagInput +} + +export type MutationCreateUploadFileArgs = { + data: UploadFileInput +} + +export type MutationCreateUploadFolderArgs = { + data: UploadFolderInput +} + +export type MutationCreateUsersPermissionsRoleArgs = { + data: UsersPermissionsRoleInput +} + +export type MutationCreateUsersPermissionsUserArgs = { + data: UsersPermissionsUserInput +} + +export type MutationDeleteAuthorArgs = { + id: Scalars['ID']['input'] +} + +export type MutationDeleteContentReleasesReleaseArgs = { + id: Scalars['ID']['input'] +} + +export type MutationDeleteContentReleasesReleaseActionArgs = { + id: Scalars['ID']['input'] +} + +export type MutationDeletePageArgs = { + id: Scalars['ID']['input'] +} + +export type MutationDeletePodcastShowArgs = { + id: Scalars['ID']['input'] +} + +export type MutationDeletePostArgs = { + id: Scalars['ID']['input'] +} + +export type MutationDeleteTagArgs = { + id: Scalars['ID']['input'] +} + +export type MutationDeleteUploadFileArgs = { + id: Scalars['ID']['input'] +} + +export type MutationDeleteUploadFolderArgs = { + id: Scalars['ID']['input'] +} + +export type MutationDeleteUsersPermissionsRoleArgs = { + id: Scalars['ID']['input'] +} + +export type MutationDeleteUsersPermissionsUserArgs = { + id: Scalars['ID']['input'] +} + +export type MutationEmailConfirmationArgs = { + confirmation: Scalars['String']['input'] +} + +export type MutationForgotPasswordArgs = { + email: Scalars['String']['input'] +} + +export type MutationLoginArgs = { + input: UsersPermissionsLoginInput +} + +export type MutationMultipleUploadArgs = { + field?: InputMaybe<Scalars['String']['input']> + files: Array<InputMaybe<Scalars['Upload']['input']>> + ref?: InputMaybe<Scalars['String']['input']> + refId?: InputMaybe<Scalars['ID']['input']> +} + +export type MutationRegisterArgs = { + input: UsersPermissionsRegisterInput +} + +export type MutationRemoveFileArgs = { + id: Scalars['ID']['input'] +} + +export type MutationResetPasswordArgs = { + code: Scalars['String']['input'] + password: Scalars['String']['input'] + passwordConfirmation: Scalars['String']['input'] +} + +export type MutationUpdateAuthorArgs = { + data: AuthorInput + id: Scalars['ID']['input'] +} + +export type MutationUpdateContentReleasesReleaseArgs = { + data: ContentReleasesReleaseInput + id: Scalars['ID']['input'] +} + +export type MutationUpdateContentReleasesReleaseActionArgs = { + data: ContentReleasesReleaseActionInput + id: Scalars['ID']['input'] +} + +export type MutationUpdateFileInfoArgs = { + id: Scalars['ID']['input'] + info?: InputMaybe<FileInfoInput> +} + +export type MutationUpdatePageArgs = { + data: PageInput + id: Scalars['ID']['input'] +} + +export type MutationUpdatePodcastShowArgs = { + data: PodcastShowInput + id: Scalars['ID']['input'] +} + +export type MutationUpdatePostArgs = { + data: PostInput + id: Scalars['ID']['input'] +} + +export type MutationUpdateTagArgs = { + data: TagInput + id: Scalars['ID']['input'] +} + +export type MutationUpdateUploadFileArgs = { + data: UploadFileInput + id: Scalars['ID']['input'] +} + +export type MutationUpdateUploadFolderArgs = { + data: UploadFolderInput + id: Scalars['ID']['input'] +} + +export type MutationUpdateUsersPermissionsRoleArgs = { + data: UsersPermissionsRoleInput + id: Scalars['ID']['input'] +} + +export type MutationUpdateUsersPermissionsUserArgs = { + data: UsersPermissionsUserInput + id: Scalars['ID']['input'] +} + +export type MutationUploadArgs = { + field?: InputMaybe<Scalars['String']['input']> + file: Scalars['Upload']['input'] + info?: InputMaybe<FileInfoInput> + ref?: InputMaybe<Scalars['String']['input']> + refId?: InputMaybe<Scalars['ID']['input']> +} + +export type Page = { + __typename?: 'Page' + body: Maybe<Scalars['String']['output']> + createdAt: Maybe<Scalars['DateTime']['output']> + description: Maybe<Scalars['String']['output']> + publishedAt: Maybe<Scalars['DateTime']['output']> + slug: Maybe<Scalars['String']['output']> + subtitle: Maybe<Scalars['String']['output']> + title: Maybe<Scalars['String']['output']> + updatedAt: Maybe<Scalars['DateTime']['output']> +} + +export type PageEntity = { + __typename?: 'PageEntity' + attributes: Maybe<Page> + id: Maybe<Scalars['ID']['output']> +} + +export type PageEntityResponse = { + __typename?: 'PageEntityResponse' + data: Maybe<PageEntity> +} + +export type PageEntityResponseCollection = { + __typename?: 'PageEntityResponseCollection' + data: Array<PageEntity> + meta: ResponseCollectionMeta +} + +export type PageFiltersInput = { + and?: InputMaybe<Array<InputMaybe<PageFiltersInput>>> + body?: InputMaybe<StringFilterInput> + createdAt?: InputMaybe<DateTimeFilterInput> + description?: InputMaybe<StringFilterInput> + id?: InputMaybe<IdFilterInput> + not?: InputMaybe<PageFiltersInput> + or?: InputMaybe<Array<InputMaybe<PageFiltersInput>>> + publishedAt?: InputMaybe<DateTimeFilterInput> + slug?: InputMaybe<StringFilterInput> + subtitle?: InputMaybe<StringFilterInput> + title?: InputMaybe<StringFilterInput> + updatedAt?: InputMaybe<DateTimeFilterInput> +} + +export type PageInput = { + body?: InputMaybe<Scalars['String']['input']> + description?: InputMaybe<Scalars['String']['input']> + publishedAt?: InputMaybe<Scalars['DateTime']['input']> + slug?: InputMaybe<Scalars['String']['input']> + subtitle?: InputMaybe<Scalars['String']['input']> + title?: InputMaybe<Scalars['String']['input']> +} + +export type Pagination = { + __typename?: 'Pagination' + page: Scalars['Int']['output'] + pageCount: Scalars['Int']['output'] + pageSize: Scalars['Int']['output'] + total: Scalars['Int']['output'] +} + +export type PaginationArg = { + limit?: InputMaybe<Scalars['Int']['input']> + page?: InputMaybe<Scalars['Int']['input']> + pageSize?: InputMaybe<Scalars['Int']['input']> + start?: InputMaybe<Scalars['Int']['input']> +} + +export type PodcastShow = { + __typename?: 'PodcastShow' + createdAt: Maybe<Scalars['DateTime']['output']> + description: Maybe<Scalars['String']['output']> + hosts: Maybe<AuthorRelationResponseCollection> + logo: Maybe<UploadFileEntityResponse> + name: Scalars['String']['output'] + posts: Maybe<PostRelationResponseCollection> + publishedAt: Maybe<Scalars['DateTime']['output']> + slug: Maybe<Scalars['String']['output']> + updatedAt: Maybe<Scalars['DateTime']['output']> +} + +export type PodcastShowHostsArgs = { + filters?: InputMaybe<AuthorFiltersInput> + pagination?: InputMaybe<PaginationArg> + sort?: InputMaybe<Array<InputMaybe<Scalars['String']['input']>>> +} + +export type PodcastShowPostsArgs = { + filters?: InputMaybe<PostFiltersInput> + pagination?: InputMaybe<PaginationArg> + publicationState?: InputMaybe<PublicationState> + sort?: InputMaybe<Array<InputMaybe<Scalars['String']['input']>>> +} + +export type PodcastShowEntity = { + __typename?: 'PodcastShowEntity' + attributes: Maybe<PodcastShow> + id: Maybe<Scalars['ID']['output']> +} + +export type PodcastShowEntityResponse = { + __typename?: 'PodcastShowEntityResponse' + data: Maybe<PodcastShowEntity> +} + +export type PodcastShowEntityResponseCollection = { + __typename?: 'PodcastShowEntityResponseCollection' + data: Array<PodcastShowEntity> + meta: ResponseCollectionMeta +} + +export type PodcastShowFiltersInput = { + and?: InputMaybe<Array<InputMaybe<PodcastShowFiltersInput>>> + createdAt?: InputMaybe<DateTimeFilterInput> + description?: InputMaybe<StringFilterInput> + hosts?: InputMaybe<AuthorFiltersInput> + id?: InputMaybe<IdFilterInput> + name?: InputMaybe<StringFilterInput> + not?: InputMaybe<PodcastShowFiltersInput> + or?: InputMaybe<Array<InputMaybe<PodcastShowFiltersInput>>> + posts?: InputMaybe<PostFiltersInput> + publishedAt?: InputMaybe<DateTimeFilterInput> + slug?: InputMaybe<StringFilterInput> + updatedAt?: InputMaybe<DateTimeFilterInput> +} + +export type PodcastShowInput = { + description?: InputMaybe<Scalars['String']['input']> + hosts?: InputMaybe<Array<InputMaybe<Scalars['ID']['input']>>> + logo?: InputMaybe<Scalars['ID']['input']> + name?: InputMaybe<Scalars['String']['input']> + posts?: InputMaybe<Array<InputMaybe<Scalars['ID']['input']>>> + publishedAt?: InputMaybe<Scalars['DateTime']['input']> + slug?: InputMaybe<Scalars['String']['input']> +} + +export type Post = { + __typename?: 'Post' + authors: Maybe<AuthorRelationResponseCollection> + body: Maybe<Scalars['String']['output']> + channel: Maybe<Array<Maybe<ComponentCatChannel>>> + cover_image: Maybe<UploadFileEntityResponse> + createdAt: Maybe<Scalars['DateTime']['output']> + credits: Maybe<Scalars['String']['output']> + episode_number: Maybe<Scalars['Int']['output']> + featured: Maybe<Scalars['Boolean']['output']> + podcast_show: Maybe<PodcastShowEntityResponse> + publish_date: Maybe<Scalars['Date']['output']> + publishedAt: Maybe<Scalars['DateTime']['output']> + related_posts: Maybe<PostRelationResponseCollection> + slug: Maybe<Scalars['String']['output']> + subtitle: Maybe<Scalars['String']['output']> + summary: Maybe<Scalars['String']['output']> + tags: Maybe<TagRelationResponseCollection> + title: Maybe<Scalars['String']['output']> + type: Maybe<Enum_Post_Type> + updatedAt: Maybe<Scalars['DateTime']['output']> +} + +export type PostAuthorsArgs = { + filters?: InputMaybe<AuthorFiltersInput> + pagination?: InputMaybe<PaginationArg> + sort?: InputMaybe<Array<InputMaybe<Scalars['String']['input']>>> +} + +export type PostChannelArgs = { + filters?: InputMaybe<ComponentCatChannelFiltersInput> + pagination?: InputMaybe<PaginationArg> + sort?: InputMaybe<Array<InputMaybe<Scalars['String']['input']>>> +} + +export type PostRelated_PostsArgs = { + filters?: InputMaybe<PostFiltersInput> + pagination?: InputMaybe<PaginationArg> + publicationState?: InputMaybe<PublicationState> + sort?: InputMaybe<Array<InputMaybe<Scalars['String']['input']>>> +} + +export type PostTagsArgs = { + filters?: InputMaybe<TagFiltersInput> + pagination?: InputMaybe<PaginationArg> + sort?: InputMaybe<Array<InputMaybe<Scalars['String']['input']>>> +} + +export type PostEntity = { + __typename?: 'PostEntity' + attributes: Maybe<Post> + id: Maybe<Scalars['ID']['output']> +} + +export type PostEntityResponse = { + __typename?: 'PostEntityResponse' + data: Maybe<PostEntity> +} + +export type PostEntityResponseCollection = { + __typename?: 'PostEntityResponseCollection' + data: Array<PostEntity> + meta: ResponseCollectionMeta +} + +export type PostFiltersInput = { + and?: InputMaybe<Array<InputMaybe<PostFiltersInput>>> + authors?: InputMaybe<AuthorFiltersInput> + body?: InputMaybe<StringFilterInput> + channel?: InputMaybe<ComponentCatChannelFiltersInput> + createdAt?: InputMaybe<DateTimeFilterInput> + credits?: InputMaybe<StringFilterInput> + episode_number?: InputMaybe<IntFilterInput> + featured?: InputMaybe<BooleanFilterInput> + id?: InputMaybe<IdFilterInput> + not?: InputMaybe<PostFiltersInput> + or?: InputMaybe<Array<InputMaybe<PostFiltersInput>>> + podcast_show?: InputMaybe<PodcastShowFiltersInput> + publish_date?: InputMaybe<DateFilterInput> + publishedAt?: InputMaybe<DateTimeFilterInput> + related_posts?: InputMaybe<PostFiltersInput> + slug?: InputMaybe<StringFilterInput> + subtitle?: InputMaybe<StringFilterInput> + summary?: InputMaybe<StringFilterInput> + tags?: InputMaybe<TagFiltersInput> + title?: InputMaybe<StringFilterInput> + type?: InputMaybe<StringFilterInput> + updatedAt?: InputMaybe<DateTimeFilterInput> +} + +export type PostInput = { + authors?: InputMaybe<Array<InputMaybe<Scalars['ID']['input']>>> + body?: InputMaybe<Scalars['String']['input']> + channel?: InputMaybe<Array<InputMaybe<ComponentCatChannelInput>>> + cover_image?: InputMaybe<Scalars['ID']['input']> + credits?: InputMaybe<Scalars['String']['input']> + episode_number?: InputMaybe<Scalars['Int']['input']> + featured?: InputMaybe<Scalars['Boolean']['input']> + podcast_show?: InputMaybe<Scalars['ID']['input']> + publish_date?: InputMaybe<Scalars['Date']['input']> + publishedAt?: InputMaybe<Scalars['DateTime']['input']> + related_posts?: InputMaybe<Array<InputMaybe<Scalars['ID']['input']>>> + slug?: InputMaybe<Scalars['String']['input']> + subtitle?: InputMaybe<Scalars['String']['input']> + summary?: InputMaybe<Scalars['String']['input']> + tags?: InputMaybe<Array<InputMaybe<Scalars['ID']['input']>>> + title?: InputMaybe<Scalars['String']['input']> + type?: InputMaybe<Enum_Post_Type> +} + +export type PostRelationResponseCollection = { + __typename?: 'PostRelationResponseCollection' + data: Array<PostEntity> +} + +export type PublicationState = 'LIVE' | 'PREVIEW' + +export type Query = { + __typename?: 'Query' + author: Maybe<AuthorEntityResponse> + authors: Maybe<AuthorEntityResponseCollection> + contentReleasesRelease: Maybe<ContentReleasesReleaseEntityResponse> + contentReleasesReleaseAction: Maybe<ContentReleasesReleaseActionEntityResponse> + contentReleasesReleaseActions: Maybe<ContentReleasesReleaseActionEntityResponseCollection> + contentReleasesReleases: Maybe<ContentReleasesReleaseEntityResponseCollection> + i18NLocale: Maybe<I18NLocaleEntityResponse> + i18NLocales: Maybe<I18NLocaleEntityResponseCollection> + me: Maybe<UsersPermissionsMe> + page: Maybe<PageEntityResponse> + pages: Maybe<PageEntityResponseCollection> + podcastShow: Maybe<PodcastShowEntityResponse> + podcastShows: Maybe<PodcastShowEntityResponseCollection> + post: Maybe<PostEntityResponse> + posts: Maybe<PostEntityResponseCollection> + tag: Maybe<TagEntityResponse> + tags: Maybe<TagEntityResponseCollection> + uploadFile: Maybe<UploadFileEntityResponse> + uploadFiles: Maybe<UploadFileEntityResponseCollection> + uploadFolder: Maybe<UploadFolderEntityResponse> + uploadFolders: Maybe<UploadFolderEntityResponseCollection> + usersPermissionsRole: Maybe<UsersPermissionsRoleEntityResponse> + usersPermissionsRoles: Maybe<UsersPermissionsRoleEntityResponseCollection> + usersPermissionsUser: Maybe<UsersPermissionsUserEntityResponse> + usersPermissionsUsers: Maybe<UsersPermissionsUserEntityResponseCollection> +} + +export type QueryAuthorArgs = { + id?: InputMaybe<Scalars['ID']['input']> +} + +export type QueryAuthorsArgs = { + filters?: InputMaybe<AuthorFiltersInput> + pagination?: InputMaybe<PaginationArg> + sort?: InputMaybe<Array<InputMaybe<Scalars['String']['input']>>> +} + +export type QueryContentReleasesReleaseArgs = { + id?: InputMaybe<Scalars['ID']['input']> +} + +export type QueryContentReleasesReleaseActionArgs = { + id?: InputMaybe<Scalars['ID']['input']> +} + +export type QueryContentReleasesReleaseActionsArgs = { + filters?: InputMaybe<ContentReleasesReleaseActionFiltersInput> + pagination?: InputMaybe<PaginationArg> + sort?: InputMaybe<Array<InputMaybe<Scalars['String']['input']>>> +} + +export type QueryContentReleasesReleasesArgs = { + filters?: InputMaybe<ContentReleasesReleaseFiltersInput> + pagination?: InputMaybe<PaginationArg> + sort?: InputMaybe<Array<InputMaybe<Scalars['String']['input']>>> +} + +export type QueryI18NLocaleArgs = { + id?: InputMaybe<Scalars['ID']['input']> +} + +export type QueryI18NLocalesArgs = { + filters?: InputMaybe<I18NLocaleFiltersInput> + pagination?: InputMaybe<PaginationArg> + sort?: InputMaybe<Array<InputMaybe<Scalars['String']['input']>>> +} + +export type QueryPageArgs = { + id?: InputMaybe<Scalars['ID']['input']> +} + +export type QueryPagesArgs = { + filters?: InputMaybe<PageFiltersInput> + pagination?: InputMaybe<PaginationArg> + publicationState?: InputMaybe<PublicationState> + sort?: InputMaybe<Array<InputMaybe<Scalars['String']['input']>>> +} + +export type QueryPodcastShowArgs = { + id?: InputMaybe<Scalars['ID']['input']> +} + +export type QueryPodcastShowsArgs = { + filters?: InputMaybe<PodcastShowFiltersInput> + pagination?: InputMaybe<PaginationArg> + publicationState?: InputMaybe<PublicationState> + sort?: InputMaybe<Array<InputMaybe<Scalars['String']['input']>>> +} + +export type QueryPostArgs = { + id?: InputMaybe<Scalars['ID']['input']> +} + +export type QueryPostsArgs = { + filters?: InputMaybe<PostFiltersInput> + pagination?: InputMaybe<PaginationArg> + publicationState?: InputMaybe<PublicationState> + sort?: InputMaybe<Array<InputMaybe<Scalars['String']['input']>>> +} + +export type QueryTagArgs = { + id?: InputMaybe<Scalars['ID']['input']> +} + +export type QueryTagsArgs = { + filters?: InputMaybe<TagFiltersInput> + pagination?: InputMaybe<PaginationArg> + sort?: InputMaybe<Array<InputMaybe<Scalars['String']['input']>>> +} + +export type QueryUploadFileArgs = { + id?: InputMaybe<Scalars['ID']['input']> +} + +export type QueryUploadFilesArgs = { + filters?: InputMaybe<UploadFileFiltersInput> + pagination?: InputMaybe<PaginationArg> + sort?: InputMaybe<Array<InputMaybe<Scalars['String']['input']>>> +} + +export type QueryUploadFolderArgs = { + id?: InputMaybe<Scalars['ID']['input']> +} + +export type QueryUploadFoldersArgs = { + filters?: InputMaybe<UploadFolderFiltersInput> + pagination?: InputMaybe<PaginationArg> + sort?: InputMaybe<Array<InputMaybe<Scalars['String']['input']>>> +} + +export type QueryUsersPermissionsRoleArgs = { + id?: InputMaybe<Scalars['ID']['input']> +} + +export type QueryUsersPermissionsRolesArgs = { + filters?: InputMaybe<UsersPermissionsRoleFiltersInput> + pagination?: InputMaybe<PaginationArg> + sort?: InputMaybe<Array<InputMaybe<Scalars['String']['input']>>> +} + +export type QueryUsersPermissionsUserArgs = { + id?: InputMaybe<Scalars['ID']['input']> +} + +export type QueryUsersPermissionsUsersArgs = { + filters?: InputMaybe<UsersPermissionsUserFiltersInput> + pagination?: InputMaybe<PaginationArg> + sort?: InputMaybe<Array<InputMaybe<Scalars['String']['input']>>> +} + +export type ResponseCollectionMeta = { + __typename?: 'ResponseCollectionMeta' + pagination: Pagination +} + +export type StringFilterInput = { + and?: InputMaybe<Array<InputMaybe<Scalars['String']['input']>>> + between?: InputMaybe<Array<InputMaybe<Scalars['String']['input']>>> + contains?: InputMaybe<Scalars['String']['input']> + containsi?: InputMaybe<Scalars['String']['input']> + endsWith?: InputMaybe<Scalars['String']['input']> + eq?: InputMaybe<Scalars['String']['input']> + eqi?: InputMaybe<Scalars['String']['input']> + gt?: InputMaybe<Scalars['String']['input']> + gte?: InputMaybe<Scalars['String']['input']> + in?: InputMaybe<Array<InputMaybe<Scalars['String']['input']>>> + lt?: InputMaybe<Scalars['String']['input']> + lte?: InputMaybe<Scalars['String']['input']> + ne?: InputMaybe<Scalars['String']['input']> + nei?: InputMaybe<Scalars['String']['input']> + not?: InputMaybe<StringFilterInput> + notContains?: InputMaybe<Scalars['String']['input']> + notContainsi?: InputMaybe<Scalars['String']['input']> + notIn?: InputMaybe<Array<InputMaybe<Scalars['String']['input']>>> + notNull?: InputMaybe<Scalars['Boolean']['input']> + null?: InputMaybe<Scalars['Boolean']['input']> + or?: InputMaybe<Array<InputMaybe<Scalars['String']['input']>>> + startsWith?: InputMaybe<Scalars['String']['input']> +} + +export type Tag = { + __typename?: 'Tag' + createdAt: Maybe<Scalars['DateTime']['output']> + name: Maybe<Scalars['String']['output']> + posts: Maybe<PostRelationResponseCollection> + updatedAt: Maybe<Scalars['DateTime']['output']> +} + +export type TagPostsArgs = { + filters?: InputMaybe<PostFiltersInput> + pagination?: InputMaybe<PaginationArg> + publicationState?: InputMaybe<PublicationState> + sort?: InputMaybe<Array<InputMaybe<Scalars['String']['input']>>> +} + +export type TagEntity = { + __typename?: 'TagEntity' + attributes: Maybe<Tag> + id: Maybe<Scalars['ID']['output']> +} + +export type TagEntityResponse = { + __typename?: 'TagEntityResponse' + data: Maybe<TagEntity> +} + +export type TagEntityResponseCollection = { + __typename?: 'TagEntityResponseCollection' + data: Array<TagEntity> + meta: ResponseCollectionMeta +} + +export type TagFiltersInput = { + and?: InputMaybe<Array<InputMaybe<TagFiltersInput>>> + createdAt?: InputMaybe<DateTimeFilterInput> + id?: InputMaybe<IdFilterInput> + name?: InputMaybe<StringFilterInput> + not?: InputMaybe<TagFiltersInput> + or?: InputMaybe<Array<InputMaybe<TagFiltersInput>>> + posts?: InputMaybe<PostFiltersInput> + updatedAt?: InputMaybe<DateTimeFilterInput> +} + +export type TagInput = { + name?: InputMaybe<Scalars['String']['input']> + posts?: InputMaybe<Array<InputMaybe<Scalars['ID']['input']>>> +} + +export type TagRelationResponseCollection = { + __typename?: 'TagRelationResponseCollection' + data: Array<TagEntity> +} + +export type UploadFile = { + __typename?: 'UploadFile' + alternativeText: Maybe<Scalars['String']['output']> + caption: Maybe<Scalars['String']['output']> + createdAt: Maybe<Scalars['DateTime']['output']> + ext: Maybe<Scalars['String']['output']> + formats: Maybe<Scalars['JSON']['output']> + hash: Scalars['String']['output'] + height: Maybe<Scalars['Int']['output']> + mime: Scalars['String']['output'] + name: Scalars['String']['output'] + previewUrl: Maybe<Scalars['String']['output']> + provider: Scalars['String']['output'] + provider_metadata: Maybe<Scalars['JSON']['output']> + related: Maybe<Array<Maybe<GenericMorph>>> + size: Scalars['Float']['output'] + updatedAt: Maybe<Scalars['DateTime']['output']> + url: Scalars['String']['output'] + width: Maybe<Scalars['Int']['output']> +} + +export type UploadFileEntity = { + __typename?: 'UploadFileEntity' + attributes: Maybe<UploadFile> + id: Maybe<Scalars['ID']['output']> +} + +export type UploadFileEntityResponse = { + __typename?: 'UploadFileEntityResponse' + data: Maybe<UploadFileEntity> +} + +export type UploadFileEntityResponseCollection = { + __typename?: 'UploadFileEntityResponseCollection' + data: Array<UploadFileEntity> + meta: ResponseCollectionMeta +} + +export type UploadFileFiltersInput = { + alternativeText?: InputMaybe<StringFilterInput> + and?: InputMaybe<Array<InputMaybe<UploadFileFiltersInput>>> + caption?: InputMaybe<StringFilterInput> + createdAt?: InputMaybe<DateTimeFilterInput> + ext?: InputMaybe<StringFilterInput> + folder?: InputMaybe<UploadFolderFiltersInput> + folderPath?: InputMaybe<StringFilterInput> + formats?: InputMaybe<JsonFilterInput> + hash?: InputMaybe<StringFilterInput> + height?: InputMaybe<IntFilterInput> + id?: InputMaybe<IdFilterInput> + mime?: InputMaybe<StringFilterInput> + name?: InputMaybe<StringFilterInput> + not?: InputMaybe<UploadFileFiltersInput> + or?: InputMaybe<Array<InputMaybe<UploadFileFiltersInput>>> + previewUrl?: InputMaybe<StringFilterInput> + provider?: InputMaybe<StringFilterInput> + provider_metadata?: InputMaybe<JsonFilterInput> + size?: InputMaybe<FloatFilterInput> + updatedAt?: InputMaybe<DateTimeFilterInput> + url?: InputMaybe<StringFilterInput> + width?: InputMaybe<IntFilterInput> +} + +export type UploadFileInput = { + alternativeText?: InputMaybe<Scalars['String']['input']> + caption?: InputMaybe<Scalars['String']['input']> + ext?: InputMaybe<Scalars['String']['input']> + folder?: InputMaybe<Scalars['ID']['input']> + folderPath?: InputMaybe<Scalars['String']['input']> + formats?: InputMaybe<Scalars['JSON']['input']> + hash?: InputMaybe<Scalars['String']['input']> + height?: InputMaybe<Scalars['Int']['input']> + mime?: InputMaybe<Scalars['String']['input']> + name?: InputMaybe<Scalars['String']['input']> + previewUrl?: InputMaybe<Scalars['String']['input']> + provider?: InputMaybe<Scalars['String']['input']> + provider_metadata?: InputMaybe<Scalars['JSON']['input']> + size?: InputMaybe<Scalars['Float']['input']> + url?: InputMaybe<Scalars['String']['input']> + width?: InputMaybe<Scalars['Int']['input']> +} + +export type UploadFileRelationResponseCollection = { + __typename?: 'UploadFileRelationResponseCollection' + data: Array<UploadFileEntity> +} + +export type UploadFolder = { + __typename?: 'UploadFolder' + children: Maybe<UploadFolderRelationResponseCollection> + createdAt: Maybe<Scalars['DateTime']['output']> + files: Maybe<UploadFileRelationResponseCollection> + name: Scalars['String']['output'] + parent: Maybe<UploadFolderEntityResponse> + path: Scalars['String']['output'] + pathId: Scalars['Int']['output'] + updatedAt: Maybe<Scalars['DateTime']['output']> +} + +export type UploadFolderChildrenArgs = { + filters?: InputMaybe<UploadFolderFiltersInput> + pagination?: InputMaybe<PaginationArg> + sort?: InputMaybe<Array<InputMaybe<Scalars['String']['input']>>> +} + +export type UploadFolderFilesArgs = { + filters?: InputMaybe<UploadFileFiltersInput> + pagination?: InputMaybe<PaginationArg> + sort?: InputMaybe<Array<InputMaybe<Scalars['String']['input']>>> +} + +export type UploadFolderEntity = { + __typename?: 'UploadFolderEntity' + attributes: Maybe<UploadFolder> + id: Maybe<Scalars['ID']['output']> +} + +export type UploadFolderEntityResponse = { + __typename?: 'UploadFolderEntityResponse' + data: Maybe<UploadFolderEntity> +} + +export type UploadFolderEntityResponseCollection = { + __typename?: 'UploadFolderEntityResponseCollection' + data: Array<UploadFolderEntity> + meta: ResponseCollectionMeta +} + +export type UploadFolderFiltersInput = { + and?: InputMaybe<Array<InputMaybe<UploadFolderFiltersInput>>> + children?: InputMaybe<UploadFolderFiltersInput> + createdAt?: InputMaybe<DateTimeFilterInput> + files?: InputMaybe<UploadFileFiltersInput> + id?: InputMaybe<IdFilterInput> + name?: InputMaybe<StringFilterInput> + not?: InputMaybe<UploadFolderFiltersInput> + or?: InputMaybe<Array<InputMaybe<UploadFolderFiltersInput>>> + parent?: InputMaybe<UploadFolderFiltersInput> + path?: InputMaybe<StringFilterInput> + pathId?: InputMaybe<IntFilterInput> + updatedAt?: InputMaybe<DateTimeFilterInput> +} + +export type UploadFolderInput = { + children?: InputMaybe<Array<InputMaybe<Scalars['ID']['input']>>> + files?: InputMaybe<Array<InputMaybe<Scalars['ID']['input']>>> + name?: InputMaybe<Scalars['String']['input']> + parent?: InputMaybe<Scalars['ID']['input']> + path?: InputMaybe<Scalars['String']['input']> + pathId?: InputMaybe<Scalars['Int']['input']> +} + +export type UploadFolderRelationResponseCollection = { + __typename?: 'UploadFolderRelationResponseCollection' + data: Array<UploadFolderEntity> +} + +export type UsersPermissionsCreateRolePayload = { + __typename?: 'UsersPermissionsCreateRolePayload' + ok: Scalars['Boolean']['output'] +} + +export type UsersPermissionsDeleteRolePayload = { + __typename?: 'UsersPermissionsDeleteRolePayload' + ok: Scalars['Boolean']['output'] +} + +export type UsersPermissionsLoginInput = { + identifier: Scalars['String']['input'] + password: Scalars['String']['input'] + provider?: Scalars['String']['input'] +} + +export type UsersPermissionsLoginPayload = { + __typename?: 'UsersPermissionsLoginPayload' + jwt: Maybe<Scalars['String']['output']> + user: UsersPermissionsMe +} + +export type UsersPermissionsMe = { + __typename?: 'UsersPermissionsMe' + blocked: Maybe<Scalars['Boolean']['output']> + confirmed: Maybe<Scalars['Boolean']['output']> + email: Maybe<Scalars['String']['output']> + id: Scalars['ID']['output'] + role: Maybe<UsersPermissionsMeRole> + username: Scalars['String']['output'] +} + +export type UsersPermissionsMeRole = { + __typename?: 'UsersPermissionsMeRole' + description: Maybe<Scalars['String']['output']> + id: Scalars['ID']['output'] + name: Scalars['String']['output'] + type: Maybe<Scalars['String']['output']> +} + +export type UsersPermissionsPasswordPayload = { + __typename?: 'UsersPermissionsPasswordPayload' + ok: Scalars['Boolean']['output'] +} + +export type UsersPermissionsPermission = { + __typename?: 'UsersPermissionsPermission' + action: Scalars['String']['output'] + createdAt: Maybe<Scalars['DateTime']['output']> + role: Maybe<UsersPermissionsRoleEntityResponse> + updatedAt: Maybe<Scalars['DateTime']['output']> +} + +export type UsersPermissionsPermissionEntity = { + __typename?: 'UsersPermissionsPermissionEntity' + attributes: Maybe<UsersPermissionsPermission> + id: Maybe<Scalars['ID']['output']> +} + +export type UsersPermissionsPermissionFiltersInput = { + action?: InputMaybe<StringFilterInput> + and?: InputMaybe<Array<InputMaybe<UsersPermissionsPermissionFiltersInput>>> + createdAt?: InputMaybe<DateTimeFilterInput> + id?: InputMaybe<IdFilterInput> + not?: InputMaybe<UsersPermissionsPermissionFiltersInput> + or?: InputMaybe<Array<InputMaybe<UsersPermissionsPermissionFiltersInput>>> + role?: InputMaybe<UsersPermissionsRoleFiltersInput> + updatedAt?: InputMaybe<DateTimeFilterInput> +} + +export type UsersPermissionsPermissionRelationResponseCollection = { + __typename?: 'UsersPermissionsPermissionRelationResponseCollection' + data: Array<UsersPermissionsPermissionEntity> +} + +export type UsersPermissionsRegisterInput = { + email: Scalars['String']['input'] + password: Scalars['String']['input'] + username: Scalars['String']['input'] +} + +export type UsersPermissionsRole = { + __typename?: 'UsersPermissionsRole' + createdAt: Maybe<Scalars['DateTime']['output']> + description: Maybe<Scalars['String']['output']> + name: Scalars['String']['output'] + permissions: Maybe<UsersPermissionsPermissionRelationResponseCollection> + type: Maybe<Scalars['String']['output']> + updatedAt: Maybe<Scalars['DateTime']['output']> + users: Maybe<UsersPermissionsUserRelationResponseCollection> +} + +export type UsersPermissionsRolePermissionsArgs = { + filters?: InputMaybe<UsersPermissionsPermissionFiltersInput> + pagination?: InputMaybe<PaginationArg> + sort?: InputMaybe<Array<InputMaybe<Scalars['String']['input']>>> +} + +export type UsersPermissionsRoleUsersArgs = { + filters?: InputMaybe<UsersPermissionsUserFiltersInput> + pagination?: InputMaybe<PaginationArg> + sort?: InputMaybe<Array<InputMaybe<Scalars['String']['input']>>> +} + +export type UsersPermissionsRoleEntity = { + __typename?: 'UsersPermissionsRoleEntity' + attributes: Maybe<UsersPermissionsRole> + id: Maybe<Scalars['ID']['output']> +} + +export type UsersPermissionsRoleEntityResponse = { + __typename?: 'UsersPermissionsRoleEntityResponse' + data: Maybe<UsersPermissionsRoleEntity> +} + +export type UsersPermissionsRoleEntityResponseCollection = { + __typename?: 'UsersPermissionsRoleEntityResponseCollection' + data: Array<UsersPermissionsRoleEntity> + meta: ResponseCollectionMeta +} + +export type UsersPermissionsRoleFiltersInput = { + and?: InputMaybe<Array<InputMaybe<UsersPermissionsRoleFiltersInput>>> + createdAt?: InputMaybe<DateTimeFilterInput> + description?: InputMaybe<StringFilterInput> + id?: InputMaybe<IdFilterInput> + name?: InputMaybe<StringFilterInput> + not?: InputMaybe<UsersPermissionsRoleFiltersInput> + or?: InputMaybe<Array<InputMaybe<UsersPermissionsRoleFiltersInput>>> + permissions?: InputMaybe<UsersPermissionsPermissionFiltersInput> + type?: InputMaybe<StringFilterInput> + updatedAt?: InputMaybe<DateTimeFilterInput> + users?: InputMaybe<UsersPermissionsUserFiltersInput> +} + +export type UsersPermissionsRoleInput = { + description?: InputMaybe<Scalars['String']['input']> + name?: InputMaybe<Scalars['String']['input']> + permissions?: InputMaybe<Array<InputMaybe<Scalars['ID']['input']>>> + type?: InputMaybe<Scalars['String']['input']> + users?: InputMaybe<Array<InputMaybe<Scalars['ID']['input']>>> +} + +export type UsersPermissionsUpdateRolePayload = { + __typename?: 'UsersPermissionsUpdateRolePayload' + ok: Scalars['Boolean']['output'] +} + +export type UsersPermissionsUser = { + __typename?: 'UsersPermissionsUser' + blocked: Maybe<Scalars['Boolean']['output']> + confirmed: Maybe<Scalars['Boolean']['output']> + createdAt: Maybe<Scalars['DateTime']['output']> + email: Scalars['String']['output'] + provider: Maybe<Scalars['String']['output']> + role: Maybe<UsersPermissionsRoleEntityResponse> + updatedAt: Maybe<Scalars['DateTime']['output']> + username: Scalars['String']['output'] +} + +export type UsersPermissionsUserEntity = { + __typename?: 'UsersPermissionsUserEntity' + attributes: Maybe<UsersPermissionsUser> + id: Maybe<Scalars['ID']['output']> +} + +export type UsersPermissionsUserEntityResponse = { + __typename?: 'UsersPermissionsUserEntityResponse' + data: Maybe<UsersPermissionsUserEntity> +} + +export type UsersPermissionsUserEntityResponseCollection = { + __typename?: 'UsersPermissionsUserEntityResponseCollection' + data: Array<UsersPermissionsUserEntity> + meta: ResponseCollectionMeta +} + +export type UsersPermissionsUserFiltersInput = { + and?: InputMaybe<Array<InputMaybe<UsersPermissionsUserFiltersInput>>> + blocked?: InputMaybe<BooleanFilterInput> + confirmationToken?: InputMaybe<StringFilterInput> + confirmed?: InputMaybe<BooleanFilterInput> + createdAt?: InputMaybe<DateTimeFilterInput> + email?: InputMaybe<StringFilterInput> + id?: InputMaybe<IdFilterInput> + not?: InputMaybe<UsersPermissionsUserFiltersInput> + or?: InputMaybe<Array<InputMaybe<UsersPermissionsUserFiltersInput>>> + password?: InputMaybe<StringFilterInput> + provider?: InputMaybe<StringFilterInput> + resetPasswordToken?: InputMaybe<StringFilterInput> + role?: InputMaybe<UsersPermissionsRoleFiltersInput> + updatedAt?: InputMaybe<DateTimeFilterInput> + username?: InputMaybe<StringFilterInput> +} + +export type UsersPermissionsUserInput = { + blocked?: InputMaybe<Scalars['Boolean']['input']> + confirmationToken?: InputMaybe<Scalars['String']['input']> + confirmed?: InputMaybe<Scalars['Boolean']['input']> + email?: InputMaybe<Scalars['String']['input']> + password?: InputMaybe<Scalars['String']['input']> + provider?: InputMaybe<Scalars['String']['input']> + resetPasswordToken?: InputMaybe<Scalars['String']['input']> + role?: InputMaybe<Scalars['ID']['input']> + username?: InputMaybe<Scalars['String']['input']> +} + +export type UsersPermissionsUserRelationResponseCollection = { + __typename?: 'UsersPermissionsUserRelationResponseCollection' + data: Array<UsersPermissionsUserEntity> +} + +export type PostCommonAttributesFragment = { + __typename?: 'Post' + type: Enum_Post_Type + title: string + subtitle: string + summary: string + slug: string + featured: boolean + episode_number: number + publish_date: any + publishedAt: any + podcast_show: { + __typename?: 'PodcastShowEntityResponse' + data: { __typename?: 'PodcastShowEntity'; id: string } + } + cover_image: { + __typename?: 'UploadFileEntityResponse' + data: { + __typename?: 'UploadFileEntity' + attributes: { + __typename?: 'UploadFile' + url: string + width: number + height: number + caption: string + } + } + } + authors: { + __typename?: 'AuthorRelationResponseCollection' + data: Array<{ + __typename?: 'AuthorEntity' + id: string + attributes: { __typename?: 'Author'; name: string; email_address: string } + }> + } + tags: { + __typename?: 'TagRelationResponseCollection' + data: Array<{ + __typename?: 'TagEntity' + id: string + attributes: { __typename?: 'Tag'; name: string } + }> + } +} + +export type GetPodcastShowsQueryVariables = Exact<{ + filters?: InputMaybe<PodcastShowFiltersInput> + pagination?: InputMaybe<PaginationArg> + sort?: InputMaybe< + | Array<InputMaybe<Scalars['String']['input']>> + | InputMaybe<Scalars['String']['input']> + > + publicationState?: InputMaybe<PublicationState> +}> + +export type GetPodcastShowsQuery = { + __typename?: 'Query' + podcastShows: { + __typename?: 'PodcastShowEntityResponseCollection' + data: Array<{ + __typename?: 'PodcastShowEntity' + id: string + attributes: { + __typename?: 'PodcastShow' + name: string + slug: string + description: string + hosts: { + __typename?: 'AuthorRelationResponseCollection' + data: Array<{ + __typename?: 'AuthorEntity' + attributes: { + __typename?: 'Author' + name: string + email_address: string + } + }> + } + logo: { + __typename?: 'UploadFileEntityResponse' + data: { + __typename?: 'UploadFileEntity' + attributes: { + __typename?: 'UploadFile' + url: string + width: number + height: number + } + } + } + } + }> + } +} + +export type GetPostsQueryVariables = Exact<{ + filters?: InputMaybe<PostFiltersInput> + pagination?: InputMaybe<PaginationArg> + sort?: InputMaybe< + | Array<InputMaybe<Scalars['String']['input']>> + | InputMaybe<Scalars['String']['input']> + > + publicationState?: InputMaybe<PublicationState> + withContent?: InputMaybe<Scalars['Boolean']['input']> +}> + +export type GetPostsQuery = { + __typename?: 'Query' + posts: { + __typename?: 'PostEntityResponseCollection' + meta: { + __typename?: 'ResponseCollectionMeta' + pagination: { + __typename?: 'Pagination' + total: number + page: number + pageSize: number + pageCount: number + } + } + data: Array<{ + __typename?: 'PostEntity' + id: string + attributes: { + __typename?: 'Post' + body?: string + credits?: string + type: Enum_Post_Type + title: string + subtitle: string + summary: string + slug: string + featured: boolean + episode_number: number + publish_date: any + publishedAt: any + channel?: Array<{ + __typename?: 'ComponentCatChannel' + channel: Enum_Componentcatchannel_Channel + link: string + }> + podcast_show: { + __typename?: 'PodcastShowEntityResponse' + data: { __typename?: 'PodcastShowEntity'; id: string } + } + cover_image: { + __typename?: 'UploadFileEntityResponse' + data: { + __typename?: 'UploadFileEntity' + attributes: { + __typename?: 'UploadFile' + url: string + width: number + height: number + caption: string + } + } + } + authors: { + __typename?: 'AuthorRelationResponseCollection' + data: Array<{ + __typename?: 'AuthorEntity' + id: string + attributes: { + __typename?: 'Author' + name: string + email_address: string + } + }> + } + tags: { + __typename?: 'TagRelationResponseCollection' + data: Array<{ + __typename?: 'TagEntity' + id: string + attributes: { __typename?: 'Tag'; name: string } + }> + } + } + }> + } +} + +export type GetRelatedPostsQueryVariables = Exact<{ + id: Scalars['ID']['input'] + type: Scalars['String']['input'] +}> + +export type GetRelatedPostsQuery = { + __typename?: 'Query' + post: { + __typename?: 'PostEntityResponse' + data: { + __typename?: 'PostEntity' + attributes: { + __typename?: 'Post' + related_posts: { + __typename?: 'PostRelationResponseCollection' + data: Array<{ + __typename?: 'PostEntity' + id: string + attributes: { + __typename?: 'Post' + type: Enum_Post_Type + title: string + subtitle: string + summary: string + slug: string + featured: boolean + episode_number: number + publish_date: any + publishedAt: any + podcast_show: { + __typename?: 'PodcastShowEntityResponse' + data: { __typename?: 'PodcastShowEntity'; id: string } + } + cover_image: { + __typename?: 'UploadFileEntityResponse' + data: { + __typename?: 'UploadFileEntity' + attributes: { + __typename?: 'UploadFile' + url: string + width: number + height: number + caption: string + } + } + } + authors: { + __typename?: 'AuthorRelationResponseCollection' + data: Array<{ + __typename?: 'AuthorEntity' + id: string + attributes: { + __typename?: 'Author' + name: string + email_address: string + } + }> + } + tags: { + __typename?: 'TagRelationResponseCollection' + data: Array<{ + __typename?: 'TagEntity' + id: string + attributes: { __typename?: 'Tag'; name: string } + }> + } + } + }> + } + } + } + } +} + +export type GetStaticPagesQueryVariables = Exact<{ + filters?: InputMaybe<PageFiltersInput> + pagination?: InputMaybe<PaginationArg> + sort?: InputMaybe< + | Array<InputMaybe<Scalars['String']['input']>> + | InputMaybe<Scalars['String']['input']> + > + publicationState?: InputMaybe<PublicationState> + withContent?: InputMaybe<Scalars['Boolean']['input']> +}> + +export type GetStaticPagesQuery = { + __typename?: 'Query' + pages: { + __typename?: 'PageEntityResponseCollection' + data: Array<{ + __typename?: 'PageEntity' + id: string + attributes: { + __typename?: 'Page' + slug: string + title: string + subtitle: string + description: string + publishedAt: any + body?: string + } + }> + } +} + +export const PostCommonAttributesFragmentDoc = { + kind: 'Document', + definitions: [ + { + kind: 'FragmentDefinition', + name: { kind: 'Name', value: 'PostCommonAttributes' }, + typeCondition: { + kind: 'NamedType', + name: { kind: 'Name', value: 'Post' }, + }, + selectionSet: { + kind: 'SelectionSet', + selections: [ + { kind: 'Field', name: { kind: 'Name', value: 'type' } }, + { kind: 'Field', name: { kind: 'Name', value: 'title' } }, + { kind: 'Field', name: { kind: 'Name', value: 'subtitle' } }, + { kind: 'Field', name: { kind: 'Name', value: 'summary' } }, + { kind: 'Field', name: { kind: 'Name', value: 'slug' } }, + { kind: 'Field', name: { kind: 'Name', value: 'featured' } }, + { kind: 'Field', name: { kind: 'Name', value: 'episode_number' } }, + { + kind: 'Field', + name: { kind: 'Name', value: 'podcast_show' }, + selectionSet: { + kind: 'SelectionSet', + selections: [ + { + kind: 'Field', + name: { kind: 'Name', value: 'data' }, + selectionSet: { + kind: 'SelectionSet', + selections: [ + { kind: 'Field', name: { kind: 'Name', value: 'id' } }, + ], + }, + }, + ], + }, + }, + { + kind: 'Field', + name: { kind: 'Name', value: 'cover_image' }, + selectionSet: { + kind: 'SelectionSet', + selections: [ + { + kind: 'Field', + name: { kind: 'Name', value: 'data' }, + selectionSet: { + kind: 'SelectionSet', + selections: [ + { + kind: 'Field', + name: { kind: 'Name', value: 'attributes' }, + selectionSet: { + kind: 'SelectionSet', + selections: [ + { + kind: 'Field', + name: { kind: 'Name', value: 'url' }, + }, + { + kind: 'Field', + name: { kind: 'Name', value: 'width' }, + }, + { + kind: 'Field', + name: { kind: 'Name', value: 'height' }, + }, + { + kind: 'Field', + name: { kind: 'Name', value: 'caption' }, + }, + ], + }, + }, + ], + }, + }, + ], + }, + }, + { + kind: 'Field', + name: { kind: 'Name', value: 'authors' }, + selectionSet: { + kind: 'SelectionSet', + selections: [ + { + kind: 'Field', + name: { kind: 'Name', value: 'data' }, + selectionSet: { + kind: 'SelectionSet', + selections: [ + { kind: 'Field', name: { kind: 'Name', value: 'id' } }, + { + kind: 'Field', + name: { kind: 'Name', value: 'attributes' }, + selectionSet: { + kind: 'SelectionSet', + selections: [ + { + kind: 'Field', + name: { kind: 'Name', value: 'name' }, + }, + { + kind: 'Field', + name: { kind: 'Name', value: 'email_address' }, + }, + ], + }, + }, + ], + }, + }, + ], + }, + }, + { kind: 'Field', name: { kind: 'Name', value: 'publish_date' } }, + { kind: 'Field', name: { kind: 'Name', value: 'publishedAt' } }, + { + kind: 'Field', + name: { kind: 'Name', value: 'tags' }, + selectionSet: { + kind: 'SelectionSet', + selections: [ + { + kind: 'Field', + name: { kind: 'Name', value: 'data' }, + selectionSet: { + kind: 'SelectionSet', + selections: [ + { kind: 'Field', name: { kind: 'Name', value: 'id' } }, + { + kind: 'Field', + name: { kind: 'Name', value: 'attributes' }, + selectionSet: { + kind: 'SelectionSet', + selections: [ + { + kind: 'Field', + name: { kind: 'Name', value: 'name' }, + }, + ], + }, + }, + ], + }, + }, + ], + }, + }, + ], + }, + }, + ], +} as unknown as DocumentNode<PostCommonAttributesFragment, unknown> +export const GetPodcastShowsDocument = { + kind: 'Document', + definitions: [ + { + kind: 'OperationDefinition', + operation: 'query', + name: { kind: 'Name', value: 'GetPodcastShows' }, + variableDefinitions: [ + { + kind: 'VariableDefinition', + variable: { + kind: 'Variable', + name: { kind: 'Name', value: 'filters' }, + }, + type: { + kind: 'NamedType', + name: { kind: 'Name', value: 'PodcastShowFiltersInput' }, + }, + }, + { + kind: 'VariableDefinition', + variable: { + kind: 'Variable', + name: { kind: 'Name', value: 'pagination' }, + }, + type: { + kind: 'NamedType', + name: { kind: 'Name', value: 'PaginationArg' }, + }, + }, + { + kind: 'VariableDefinition', + variable: { kind: 'Variable', name: { kind: 'Name', value: 'sort' } }, + type: { + kind: 'ListType', + type: { + kind: 'NamedType', + name: { kind: 'Name', value: 'String' }, + }, + }, + }, + { + kind: 'VariableDefinition', + variable: { + kind: 'Variable', + name: { kind: 'Name', value: 'publicationState' }, + }, + type: { + kind: 'NamedType', + name: { kind: 'Name', value: 'PublicationState' }, + }, + }, + ], + selectionSet: { + kind: 'SelectionSet', + selections: [ + { + kind: 'Field', + name: { kind: 'Name', value: 'podcastShows' }, + arguments: [ + { + kind: 'Argument', + name: { kind: 'Name', value: 'filters' }, + value: { + kind: 'Variable', + name: { kind: 'Name', value: 'filters' }, + }, + }, + { + kind: 'Argument', + name: { kind: 'Name', value: 'pagination' }, + value: { + kind: 'Variable', + name: { kind: 'Name', value: 'pagination' }, + }, + }, + { + kind: 'Argument', + name: { kind: 'Name', value: 'sort' }, + value: { + kind: 'Variable', + name: { kind: 'Name', value: 'sort' }, + }, + }, + { + kind: 'Argument', + name: { kind: 'Name', value: 'publicationState' }, + value: { + kind: 'Variable', + name: { kind: 'Name', value: 'publicationState' }, + }, + }, + ], + selectionSet: { + kind: 'SelectionSet', + selections: [ + { + kind: 'Field', + name: { kind: 'Name', value: 'data' }, + selectionSet: { + kind: 'SelectionSet', + selections: [ + { kind: 'Field', name: { kind: 'Name', value: 'id' } }, + { + kind: 'Field', + name: { kind: 'Name', value: 'attributes' }, + selectionSet: { + kind: 'SelectionSet', + selections: [ + { + kind: 'Field', + name: { kind: 'Name', value: 'name' }, + }, + { + kind: 'Field', + name: { kind: 'Name', value: 'slug' }, + }, + { + kind: 'Field', + name: { kind: 'Name', value: 'description' }, + }, + { + kind: 'Field', + name: { kind: 'Name', value: 'hosts' }, + selectionSet: { + kind: 'SelectionSet', + selections: [ + { + kind: 'Field', + name: { kind: 'Name', value: 'data' }, + selectionSet: { + kind: 'SelectionSet', + selections: [ + { + kind: 'Field', + name: { + kind: 'Name', + value: 'attributes', + }, + selectionSet: { + kind: 'SelectionSet', + selections: [ + { + kind: 'Field', + name: { + kind: 'Name', + value: 'name', + }, + }, + { + kind: 'Field', + name: { + kind: 'Name', + value: 'email_address', + }, + }, + ], + }, + }, + ], + }, + }, + ], + }, + }, + { + kind: 'Field', + name: { kind: 'Name', value: 'logo' }, + selectionSet: { + kind: 'SelectionSet', + selections: [ + { + kind: 'Field', + name: { kind: 'Name', value: 'data' }, + selectionSet: { + kind: 'SelectionSet', + selections: [ + { + kind: 'Field', + name: { + kind: 'Name', + value: 'attributes', + }, + selectionSet: { + kind: 'SelectionSet', + selections: [ + { + kind: 'Field', + name: { + kind: 'Name', + value: 'url', + }, + }, + { + kind: 'Field', + name: { + kind: 'Name', + value: 'width', + }, + }, + { + kind: 'Field', + name: { + kind: 'Name', + value: 'height', + }, + }, + ], + }, + }, + ], + }, + }, + ], + }, + }, + ], + }, + }, + ], + }, + }, + ], + }, + }, + ], + }, + }, + ], +} as unknown as DocumentNode< + GetPodcastShowsQuery, + GetPodcastShowsQueryVariables +> +export const GetPostsDocument = { + kind: 'Document', + definitions: [ + { + kind: 'OperationDefinition', + operation: 'query', + name: { kind: 'Name', value: 'GetPosts' }, + variableDefinitions: [ + { + kind: 'VariableDefinition', + variable: { + kind: 'Variable', + name: { kind: 'Name', value: 'filters' }, + }, + type: { + kind: 'NamedType', + name: { kind: 'Name', value: 'PostFiltersInput' }, + }, + }, + { + kind: 'VariableDefinition', + variable: { + kind: 'Variable', + name: { kind: 'Name', value: 'pagination' }, + }, + type: { + kind: 'NamedType', + name: { kind: 'Name', value: 'PaginationArg' }, + }, + }, + { + kind: 'VariableDefinition', + variable: { kind: 'Variable', name: { kind: 'Name', value: 'sort' } }, + type: { + kind: 'ListType', + type: { + kind: 'NamedType', + name: { kind: 'Name', value: 'String' }, + }, + }, + }, + { + kind: 'VariableDefinition', + variable: { + kind: 'Variable', + name: { kind: 'Name', value: 'publicationState' }, + }, + type: { + kind: 'NamedType', + name: { kind: 'Name', value: 'PublicationState' }, + }, + }, + { + kind: 'VariableDefinition', + variable: { + kind: 'Variable', + name: { kind: 'Name', value: 'withContent' }, + }, + type: { kind: 'NamedType', name: { kind: 'Name', value: 'Boolean' } }, + defaultValue: { kind: 'BooleanValue', value: false }, + }, + ], + selectionSet: { + kind: 'SelectionSet', + selections: [ + { + kind: 'Field', + name: { kind: 'Name', value: 'posts' }, + arguments: [ + { + kind: 'Argument', + name: { kind: 'Name', value: 'filters' }, + value: { + kind: 'Variable', + name: { kind: 'Name', value: 'filters' }, + }, + }, + { + kind: 'Argument', + name: { kind: 'Name', value: 'pagination' }, + value: { + kind: 'Variable', + name: { kind: 'Name', value: 'pagination' }, + }, + }, + { + kind: 'Argument', + name: { kind: 'Name', value: 'sort' }, + value: { + kind: 'Variable', + name: { kind: 'Name', value: 'sort' }, + }, + }, + { + kind: 'Argument', + name: { kind: 'Name', value: 'publicationState' }, + value: { + kind: 'Variable', + name: { kind: 'Name', value: 'publicationState' }, + }, + }, + ], + selectionSet: { + kind: 'SelectionSet', + selections: [ + { + kind: 'Field', + name: { kind: 'Name', value: 'meta' }, + selectionSet: { + kind: 'SelectionSet', + selections: [ + { + kind: 'Field', + name: { kind: 'Name', value: 'pagination' }, + selectionSet: { + kind: 'SelectionSet', + selections: [ + { + kind: 'Field', + name: { kind: 'Name', value: 'total' }, + }, + { + kind: 'Field', + name: { kind: 'Name', value: 'page' }, + }, + { + kind: 'Field', + name: { kind: 'Name', value: 'pageSize' }, + }, + { + kind: 'Field', + name: { kind: 'Name', value: 'pageCount' }, + }, + ], + }, + }, + ], + }, + }, + { + kind: 'Field', + name: { kind: 'Name', value: 'data' }, + selectionSet: { + kind: 'SelectionSet', + selections: [ + { kind: 'Field', name: { kind: 'Name', value: 'id' } }, + { + kind: 'Field', + name: { kind: 'Name', value: 'attributes' }, + selectionSet: { + kind: 'SelectionSet', + selections: [ + { + kind: 'FragmentSpread', + name: { + kind: 'Name', + value: 'PostCommonAttributes', + }, + }, + { + kind: 'Field', + name: { kind: 'Name', value: 'body' }, + directives: [ + { + kind: 'Directive', + name: { kind: 'Name', value: 'include' }, + arguments: [ + { + kind: 'Argument', + name: { kind: 'Name', value: 'if' }, + value: { + kind: 'Variable', + name: { + kind: 'Name', + value: 'withContent', + }, + }, + }, + ], + }, + ], + }, + { + kind: 'Field', + name: { kind: 'Name', value: 'credits' }, + directives: [ + { + kind: 'Directive', + name: { kind: 'Name', value: 'include' }, + arguments: [ + { + kind: 'Argument', + name: { kind: 'Name', value: 'if' }, + value: { + kind: 'Variable', + name: { + kind: 'Name', + value: 'withContent', + }, + }, + }, + ], + }, + ], + }, + { + kind: 'Field', + name: { kind: 'Name', value: 'channel' }, + directives: [ + { + kind: 'Directive', + name: { kind: 'Name', value: 'include' }, + arguments: [ + { + kind: 'Argument', + name: { kind: 'Name', value: 'if' }, + value: { + kind: 'Variable', + name: { + kind: 'Name', + value: 'withContent', + }, + }, + }, + ], + }, + ], + selectionSet: { + kind: 'SelectionSet', + selections: [ + { + kind: 'Field', + name: { kind: 'Name', value: 'channel' }, + }, + { + kind: 'Field', + name: { kind: 'Name', value: 'link' }, + }, + ], + }, + }, + ], + }, + }, + ], + }, + }, + ], + }, + }, + ], + }, + }, + { + kind: 'FragmentDefinition', + name: { kind: 'Name', value: 'PostCommonAttributes' }, + typeCondition: { + kind: 'NamedType', + name: { kind: 'Name', value: 'Post' }, + }, + selectionSet: { + kind: 'SelectionSet', + selections: [ + { kind: 'Field', name: { kind: 'Name', value: 'type' } }, + { kind: 'Field', name: { kind: 'Name', value: 'title' } }, + { kind: 'Field', name: { kind: 'Name', value: 'subtitle' } }, + { kind: 'Field', name: { kind: 'Name', value: 'summary' } }, + { kind: 'Field', name: { kind: 'Name', value: 'slug' } }, + { kind: 'Field', name: { kind: 'Name', value: 'featured' } }, + { kind: 'Field', name: { kind: 'Name', value: 'episode_number' } }, + { + kind: 'Field', + name: { kind: 'Name', value: 'podcast_show' }, + selectionSet: { + kind: 'SelectionSet', + selections: [ + { + kind: 'Field', + name: { kind: 'Name', value: 'data' }, + selectionSet: { + kind: 'SelectionSet', + selections: [ + { kind: 'Field', name: { kind: 'Name', value: 'id' } }, + ], + }, + }, + ], + }, + }, + { + kind: 'Field', + name: { kind: 'Name', value: 'cover_image' }, + selectionSet: { + kind: 'SelectionSet', + selections: [ + { + kind: 'Field', + name: { kind: 'Name', value: 'data' }, + selectionSet: { + kind: 'SelectionSet', + selections: [ + { + kind: 'Field', + name: { kind: 'Name', value: 'attributes' }, + selectionSet: { + kind: 'SelectionSet', + selections: [ + { + kind: 'Field', + name: { kind: 'Name', value: 'url' }, + }, + { + kind: 'Field', + name: { kind: 'Name', value: 'width' }, + }, + { + kind: 'Field', + name: { kind: 'Name', value: 'height' }, + }, + { + kind: 'Field', + name: { kind: 'Name', value: 'caption' }, + }, + ], + }, + }, + ], + }, + }, + ], + }, + }, + { + kind: 'Field', + name: { kind: 'Name', value: 'authors' }, + selectionSet: { + kind: 'SelectionSet', + selections: [ + { + kind: 'Field', + name: { kind: 'Name', value: 'data' }, + selectionSet: { + kind: 'SelectionSet', + selections: [ + { kind: 'Field', name: { kind: 'Name', value: 'id' } }, + { + kind: 'Field', + name: { kind: 'Name', value: 'attributes' }, + selectionSet: { + kind: 'SelectionSet', + selections: [ + { + kind: 'Field', + name: { kind: 'Name', value: 'name' }, + }, + { + kind: 'Field', + name: { kind: 'Name', value: 'email_address' }, + }, + ], + }, + }, + ], + }, + }, + ], + }, + }, + { kind: 'Field', name: { kind: 'Name', value: 'publish_date' } }, + { kind: 'Field', name: { kind: 'Name', value: 'publishedAt' } }, + { + kind: 'Field', + name: { kind: 'Name', value: 'tags' }, + selectionSet: { + kind: 'SelectionSet', + selections: [ + { + kind: 'Field', + name: { kind: 'Name', value: 'data' }, + selectionSet: { + kind: 'SelectionSet', + selections: [ + { kind: 'Field', name: { kind: 'Name', value: 'id' } }, + { + kind: 'Field', + name: { kind: 'Name', value: 'attributes' }, + selectionSet: { + kind: 'SelectionSet', + selections: [ + { + kind: 'Field', + name: { kind: 'Name', value: 'name' }, + }, + ], + }, + }, + ], + }, + }, + ], + }, + }, + ], + }, + }, + ], +} as unknown as DocumentNode<GetPostsQuery, GetPostsQueryVariables> +export const GetRelatedPostsDocument = { + kind: 'Document', + definitions: [ + { + kind: 'OperationDefinition', + operation: 'query', + name: { kind: 'Name', value: 'GetRelatedPosts' }, + variableDefinitions: [ + { + kind: 'VariableDefinition', + variable: { kind: 'Variable', name: { kind: 'Name', value: 'id' } }, + type: { + kind: 'NonNullType', + type: { kind: 'NamedType', name: { kind: 'Name', value: 'ID' } }, + }, + }, + { + kind: 'VariableDefinition', + variable: { kind: 'Variable', name: { kind: 'Name', value: 'type' } }, + type: { + kind: 'NonNullType', + type: { + kind: 'NamedType', + name: { kind: 'Name', value: 'String' }, + }, + }, + }, + ], + selectionSet: { + kind: 'SelectionSet', + selections: [ + { + kind: 'Field', + name: { kind: 'Name', value: 'post' }, + arguments: [ + { + kind: 'Argument', + name: { kind: 'Name', value: 'id' }, + value: { + kind: 'Variable', + name: { kind: 'Name', value: 'id' }, + }, + }, + ], + selectionSet: { + kind: 'SelectionSet', + selections: [ + { + kind: 'Field', + name: { kind: 'Name', value: 'data' }, + selectionSet: { + kind: 'SelectionSet', + selections: [ + { + kind: 'Field', + name: { kind: 'Name', value: 'attributes' }, + selectionSet: { + kind: 'SelectionSet', + selections: [ + { + kind: 'Field', + name: { kind: 'Name', value: 'related_posts' }, + arguments: [ + { + kind: 'Argument', + name: { + kind: 'Name', + value: 'publicationState', + }, + value: { kind: 'EnumValue', value: 'LIVE' }, + }, + { + kind: 'Argument', + name: { kind: 'Name', value: 'filters' }, + value: { + kind: 'ObjectValue', + fields: [ + { + kind: 'ObjectField', + name: { kind: 'Name', value: 'type' }, + value: { + kind: 'ObjectValue', + fields: [ + { + kind: 'ObjectField', + name: { + kind: 'Name', + value: 'eq', + }, + value: { + kind: 'Variable', + name: { + kind: 'Name', + value: 'type', + }, + }, + }, + ], + }, + }, + ], + }, + }, + ], + selectionSet: { + kind: 'SelectionSet', + selections: [ + { + kind: 'Field', + name: { kind: 'Name', value: 'data' }, + selectionSet: { + kind: 'SelectionSet', + selections: [ + { + kind: 'Field', + name: { kind: 'Name', value: 'id' }, + }, + { + kind: 'Field', + name: { + kind: 'Name', + value: 'attributes', + }, + selectionSet: { + kind: 'SelectionSet', + selections: [ + { + kind: 'FragmentSpread', + name: { + kind: 'Name', + value: 'PostCommonAttributes', + }, + }, + ], + }, + }, + ], + }, + }, + ], + }, + }, + ], + }, + }, + ], + }, + }, + ], + }, + }, + ], + }, + }, + { + kind: 'FragmentDefinition', + name: { kind: 'Name', value: 'PostCommonAttributes' }, + typeCondition: { + kind: 'NamedType', + name: { kind: 'Name', value: 'Post' }, + }, + selectionSet: { + kind: 'SelectionSet', + selections: [ + { kind: 'Field', name: { kind: 'Name', value: 'type' } }, + { kind: 'Field', name: { kind: 'Name', value: 'title' } }, + { kind: 'Field', name: { kind: 'Name', value: 'subtitle' } }, + { kind: 'Field', name: { kind: 'Name', value: 'summary' } }, + { kind: 'Field', name: { kind: 'Name', value: 'slug' } }, + { kind: 'Field', name: { kind: 'Name', value: 'featured' } }, + { kind: 'Field', name: { kind: 'Name', value: 'episode_number' } }, + { + kind: 'Field', + name: { kind: 'Name', value: 'podcast_show' }, + selectionSet: { + kind: 'SelectionSet', + selections: [ + { + kind: 'Field', + name: { kind: 'Name', value: 'data' }, + selectionSet: { + kind: 'SelectionSet', + selections: [ + { kind: 'Field', name: { kind: 'Name', value: 'id' } }, + ], + }, + }, + ], + }, + }, + { + kind: 'Field', + name: { kind: 'Name', value: 'cover_image' }, + selectionSet: { + kind: 'SelectionSet', + selections: [ + { + kind: 'Field', + name: { kind: 'Name', value: 'data' }, + selectionSet: { + kind: 'SelectionSet', + selections: [ + { + kind: 'Field', + name: { kind: 'Name', value: 'attributes' }, + selectionSet: { + kind: 'SelectionSet', + selections: [ + { + kind: 'Field', + name: { kind: 'Name', value: 'url' }, + }, + { + kind: 'Field', + name: { kind: 'Name', value: 'width' }, + }, + { + kind: 'Field', + name: { kind: 'Name', value: 'height' }, + }, + { + kind: 'Field', + name: { kind: 'Name', value: 'caption' }, + }, + ], + }, + }, + ], + }, + }, + ], + }, + }, + { + kind: 'Field', + name: { kind: 'Name', value: 'authors' }, + selectionSet: { + kind: 'SelectionSet', + selections: [ + { + kind: 'Field', + name: { kind: 'Name', value: 'data' }, + selectionSet: { + kind: 'SelectionSet', + selections: [ + { kind: 'Field', name: { kind: 'Name', value: 'id' } }, + { + kind: 'Field', + name: { kind: 'Name', value: 'attributes' }, + selectionSet: { + kind: 'SelectionSet', + selections: [ + { + kind: 'Field', + name: { kind: 'Name', value: 'name' }, + }, + { + kind: 'Field', + name: { kind: 'Name', value: 'email_address' }, + }, + ], + }, + }, + ], + }, + }, + ], + }, + }, + { kind: 'Field', name: { kind: 'Name', value: 'publish_date' } }, + { kind: 'Field', name: { kind: 'Name', value: 'publishedAt' } }, + { + kind: 'Field', + name: { kind: 'Name', value: 'tags' }, + selectionSet: { + kind: 'SelectionSet', + selections: [ + { + kind: 'Field', + name: { kind: 'Name', value: 'data' }, + selectionSet: { + kind: 'SelectionSet', + selections: [ + { kind: 'Field', name: { kind: 'Name', value: 'id' } }, + { + kind: 'Field', + name: { kind: 'Name', value: 'attributes' }, + selectionSet: { + kind: 'SelectionSet', + selections: [ + { + kind: 'Field', + name: { kind: 'Name', value: 'name' }, + }, + ], + }, + }, + ], + }, + }, + ], + }, + }, + ], + }, + }, + ], +} as unknown as DocumentNode< + GetRelatedPostsQuery, + GetRelatedPostsQueryVariables +> +export const GetStaticPagesDocument = { + kind: 'Document', + definitions: [ + { + kind: 'OperationDefinition', + operation: 'query', + name: { kind: 'Name', value: 'GetStaticPages' }, + variableDefinitions: [ + { + kind: 'VariableDefinition', + variable: { + kind: 'Variable', + name: { kind: 'Name', value: 'filters' }, + }, + type: { + kind: 'NamedType', + name: { kind: 'Name', value: 'PageFiltersInput' }, + }, + }, + { + kind: 'VariableDefinition', + variable: { + kind: 'Variable', + name: { kind: 'Name', value: 'pagination' }, + }, + type: { + kind: 'NamedType', + name: { kind: 'Name', value: 'PaginationArg' }, + }, + }, + { + kind: 'VariableDefinition', + variable: { kind: 'Variable', name: { kind: 'Name', value: 'sort' } }, + type: { + kind: 'ListType', + type: { + kind: 'NamedType', + name: { kind: 'Name', value: 'String' }, + }, + }, + }, + { + kind: 'VariableDefinition', + variable: { + kind: 'Variable', + name: { kind: 'Name', value: 'publicationState' }, + }, + type: { + kind: 'NamedType', + name: { kind: 'Name', value: 'PublicationState' }, + }, + }, + { + kind: 'VariableDefinition', + variable: { + kind: 'Variable', + name: { kind: 'Name', value: 'withContent' }, + }, + type: { kind: 'NamedType', name: { kind: 'Name', value: 'Boolean' } }, + defaultValue: { kind: 'BooleanValue', value: false }, + }, + ], + selectionSet: { + kind: 'SelectionSet', + selections: [ + { + kind: 'Field', + name: { kind: 'Name', value: 'pages' }, + arguments: [ + { + kind: 'Argument', + name: { kind: 'Name', value: 'sort' }, + value: { + kind: 'Variable', + name: { kind: 'Name', value: 'sort' }, + }, + }, + { + kind: 'Argument', + name: { kind: 'Name', value: 'filters' }, + value: { + kind: 'Variable', + name: { kind: 'Name', value: 'filters' }, + }, + }, + { + kind: 'Argument', + name: { kind: 'Name', value: 'pagination' }, + value: { + kind: 'Variable', + name: { kind: 'Name', value: 'pagination' }, + }, + }, + { + kind: 'Argument', + name: { kind: 'Name', value: 'publicationState' }, + value: { + kind: 'Variable', + name: { kind: 'Name', value: 'publicationState' }, + }, + }, + ], + selectionSet: { + kind: 'SelectionSet', + selections: [ + { + kind: 'Field', + name: { kind: 'Name', value: 'data' }, + selectionSet: { + kind: 'SelectionSet', + selections: [ + { kind: 'Field', name: { kind: 'Name', value: 'id' } }, + { + kind: 'Field', + name: { kind: 'Name', value: 'attributes' }, + selectionSet: { + kind: 'SelectionSet', + selections: [ + { + kind: 'Field', + name: { kind: 'Name', value: 'slug' }, + }, + { + kind: 'Field', + name: { kind: 'Name', value: 'title' }, + }, + { + kind: 'Field', + name: { kind: 'Name', value: 'subtitle' }, + }, + { + kind: 'Field', + name: { kind: 'Name', value: 'description' }, + }, + { + kind: 'Field', + name: { kind: 'Name', value: 'publishedAt' }, + }, + { + kind: 'Field', + name: { kind: 'Name', value: 'body' }, + directives: [ + { + kind: 'Directive', + name: { kind: 'Name', value: 'include' }, + arguments: [ + { + kind: 'Argument', + name: { kind: 'Name', value: 'if' }, + value: { + kind: 'Variable', + name: { + kind: 'Name', + value: 'withContent', + }, + }, + }, + ], + }, + ], + }, + ], + }, + }, + ], + }, + }, + ], + }, + }, + ], + }, + }, + ], +} as unknown as DocumentNode<GetStaticPagesQuery, GetStaticPagesQueryVariables> diff --git a/src/lib/strapi/strapi.graphql b/src/lib/strapi/strapi.graphql new file mode 100644 index 0000000..9099fd2 --- /dev/null +++ b/src/lib/strapi/strapi.graphql @@ -0,0 +1,1085 @@ +type Author { + avatar: UploadFileEntityResponse + createdAt: DateTime + email_address: String + name: String! + updatedAt: DateTime +} + +type AuthorEntity { + attributes: Author + id: ID +} + +type AuthorEntityResponse { + data: AuthorEntity +} + +type AuthorEntityResponseCollection { + data: [AuthorEntity!]! + meta: ResponseCollectionMeta! +} + +input AuthorFiltersInput { + and: [AuthorFiltersInput] + createdAt: DateTimeFilterInput + email_address: StringFilterInput + id: IDFilterInput + name: StringFilterInput + not: AuthorFiltersInput + or: [AuthorFiltersInput] + updatedAt: DateTimeFilterInput +} + +input AuthorInput { + avatar: ID + email_address: String + name: String +} + +type AuthorRelationResponseCollection { + data: [AuthorEntity!]! +} + +input BooleanFilterInput { + and: [Boolean] + between: [Boolean] + contains: Boolean + containsi: Boolean + endsWith: Boolean + eq: Boolean + eqi: Boolean + gt: Boolean + gte: Boolean + in: [Boolean] + lt: Boolean + lte: Boolean + ne: Boolean + nei: Boolean + not: BooleanFilterInput + notContains: Boolean + notContainsi: Boolean + notIn: [Boolean] + notNull: Boolean + null: Boolean + or: [Boolean] + startsWith: Boolean +} + +type ComponentCatChannel { + channel: ENUM_COMPONENTCATCHANNEL_CHANNEL + id: ID! + link: String! +} + +input ComponentCatChannelFiltersInput { + and: [ComponentCatChannelFiltersInput] + channel: StringFilterInput + link: StringFilterInput + not: ComponentCatChannelFiltersInput + or: [ComponentCatChannelFiltersInput] +} + +input ComponentCatChannelInput { + channel: ENUM_COMPONENTCATCHANNEL_CHANNEL + id: ID + link: String +} + +type ContentReleasesRelease { + actions(filters: ContentReleasesReleaseActionFiltersInput, pagination: PaginationArg = {}, sort: [String] = []): ContentReleasesReleaseActionRelationResponseCollection + createdAt: DateTime + name: String! + releasedAt: DateTime + updatedAt: DateTime +} + +type ContentReleasesReleaseAction { + contentType: String! + createdAt: DateTime + entry: GenericMorph + release: ContentReleasesReleaseEntityResponse + type: ENUM_CONTENTRELEASESRELEASEACTION_TYPE! + updatedAt: DateTime +} + +type ContentReleasesReleaseActionEntity { + attributes: ContentReleasesReleaseAction + id: ID +} + +type ContentReleasesReleaseActionEntityResponse { + data: ContentReleasesReleaseActionEntity +} + +type ContentReleasesReleaseActionEntityResponseCollection { + data: [ContentReleasesReleaseActionEntity!]! + meta: ResponseCollectionMeta! +} + +input ContentReleasesReleaseActionFiltersInput { + and: [ContentReleasesReleaseActionFiltersInput] + contentType: StringFilterInput + createdAt: DateTimeFilterInput + id: IDFilterInput + not: ContentReleasesReleaseActionFiltersInput + or: [ContentReleasesReleaseActionFiltersInput] + release: ContentReleasesReleaseFiltersInput + type: StringFilterInput + updatedAt: DateTimeFilterInput +} + +input ContentReleasesReleaseActionInput { + contentType: String + release: ID + type: ENUM_CONTENTRELEASESRELEASEACTION_TYPE +} + +type ContentReleasesReleaseActionRelationResponseCollection { + data: [ContentReleasesReleaseActionEntity!]! +} + +type ContentReleasesReleaseEntity { + attributes: ContentReleasesRelease + id: ID +} + +type ContentReleasesReleaseEntityResponse { + data: ContentReleasesReleaseEntity +} + +type ContentReleasesReleaseEntityResponseCollection { + data: [ContentReleasesReleaseEntity!]! + meta: ResponseCollectionMeta! +} + +input ContentReleasesReleaseFiltersInput { + actions: ContentReleasesReleaseActionFiltersInput + and: [ContentReleasesReleaseFiltersInput] + createdAt: DateTimeFilterInput + id: IDFilterInput + name: StringFilterInput + not: ContentReleasesReleaseFiltersInput + or: [ContentReleasesReleaseFiltersInput] + releasedAt: DateTimeFilterInput + updatedAt: DateTimeFilterInput +} + +input ContentReleasesReleaseInput { + actions: [ID] + name: String + releasedAt: DateTime +} + +""" +A date string, such as 2007-12-03, compliant with the `full-date` format outlined in section 5.6 of the RFC 3339 profile of the ISO 8601 standard for representation of dates and times using the Gregorian calendar. +""" +scalar Date + +input DateFilterInput { + and: [Date] + between: [Date] + contains: Date + containsi: Date + endsWith: Date + eq: Date + eqi: Date + gt: Date + gte: Date + in: [Date] + lt: Date + lte: Date + ne: Date + nei: Date + not: DateFilterInput + notContains: Date + notContainsi: Date + notIn: [Date] + notNull: Boolean + null: Boolean + or: [Date] + startsWith: Date +} + +""" +A date-time string at UTC, such as 2007-12-03T10:15:30Z, compliant with the `date-time` format outlined in section 5.6 of the RFC 3339 profile of the ISO 8601 standard for representation of dates and times using the Gregorian calendar. +""" +scalar DateTime + +input DateTimeFilterInput { + and: [DateTime] + between: [DateTime] + contains: DateTime + containsi: DateTime + endsWith: DateTime + eq: DateTime + eqi: DateTime + gt: DateTime + gte: DateTime + in: [DateTime] + lt: DateTime + lte: DateTime + ne: DateTime + nei: DateTime + not: DateTimeFilterInput + notContains: DateTime + notContainsi: DateTime + notIn: [DateTime] + notNull: Boolean + null: Boolean + or: [DateTime] + startsWith: DateTime +} + +enum ENUM_COMPONENTCATCHANNEL_CHANNEL { + Apple_Podcasts + Google_Podcasts + Simplecast + Spotify + Youtube +} + +enum ENUM_CONTENTRELEASESRELEASEACTION_TYPE { + publish + unpublish +} + +enum ENUM_POST_TYPE { + Article + Episode +} + +input FileInfoInput { + alternativeText: String + caption: String + name: String +} + +input FloatFilterInput { + and: [Float] + between: [Float] + contains: Float + containsi: Float + endsWith: Float + eq: Float + eqi: Float + gt: Float + gte: Float + in: [Float] + lt: Float + lte: Float + ne: Float + nei: Float + not: FloatFilterInput + notContains: Float + notContainsi: Float + notIn: [Float] + notNull: Boolean + null: Boolean + or: [Float] + startsWith: Float +} + +union GenericMorph = Author | ComponentCatChannel | ContentReleasesRelease | ContentReleasesReleaseAction | I18NLocale | Page | PodcastShow | Post | Tag | UploadFile | UploadFolder | UsersPermissionsPermission | UsersPermissionsRole | UsersPermissionsUser + +type I18NLocale { + code: String + createdAt: DateTime + name: String + updatedAt: DateTime +} + +type I18NLocaleEntity { + attributes: I18NLocale + id: ID +} + +type I18NLocaleEntityResponse { + data: I18NLocaleEntity +} + +type I18NLocaleEntityResponseCollection { + data: [I18NLocaleEntity!]! + meta: ResponseCollectionMeta! +} + +input I18NLocaleFiltersInput { + and: [I18NLocaleFiltersInput] + code: StringFilterInput + createdAt: DateTimeFilterInput + id: IDFilterInput + name: StringFilterInput + not: I18NLocaleFiltersInput + or: [I18NLocaleFiltersInput] + updatedAt: DateTimeFilterInput +} + +input IDFilterInput { + and: [ID] + between: [ID] + contains: ID + containsi: ID + endsWith: ID + eq: ID + eqi: ID + gt: ID + gte: ID + in: [ID] + lt: ID + lte: ID + ne: ID + nei: ID + not: IDFilterInput + notContains: ID + notContainsi: ID + notIn: [ID] + notNull: Boolean + null: Boolean + or: [ID] + startsWith: ID +} + +input IntFilterInput { + and: [Int] + between: [Int] + contains: Int + containsi: Int + endsWith: Int + eq: Int + eqi: Int + gt: Int + gte: Int + in: [Int] + lt: Int + lte: Int + ne: Int + nei: Int + not: IntFilterInput + notContains: Int + notContainsi: Int + notIn: [Int] + notNull: Boolean + null: Boolean + or: [Int] + startsWith: Int +} + +""" +The `JSON` scalar type represents JSON values as specified by [ECMA-404](http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf). +""" +scalar JSON + +input JSONFilterInput { + and: [JSON] + between: [JSON] + contains: JSON + containsi: JSON + endsWith: JSON + eq: JSON + eqi: JSON + gt: JSON + gte: JSON + in: [JSON] + lt: JSON + lte: JSON + ne: JSON + nei: JSON + not: JSONFilterInput + notContains: JSON + notContainsi: JSON + notIn: [JSON] + notNull: Boolean + null: Boolean + or: [JSON] + startsWith: JSON +} + +type Mutation { + """Change user password. Confirm with the current password.""" + changePassword(currentPassword: String!, password: String!, passwordConfirmation: String!): UsersPermissionsLoginPayload + createAuthor(data: AuthorInput!): AuthorEntityResponse + createContentReleasesRelease(data: ContentReleasesReleaseInput!): ContentReleasesReleaseEntityResponse + createContentReleasesReleaseAction(data: ContentReleasesReleaseActionInput!): ContentReleasesReleaseActionEntityResponse + createPage(data: PageInput!): PageEntityResponse + createPodcastShow(data: PodcastShowInput!): PodcastShowEntityResponse + createPost(data: PostInput!): PostEntityResponse + createTag(data: TagInput!): TagEntityResponse + createUploadFile(data: UploadFileInput!): UploadFileEntityResponse + createUploadFolder(data: UploadFolderInput!): UploadFolderEntityResponse + + """Create a new role""" + createUsersPermissionsRole(data: UsersPermissionsRoleInput!): UsersPermissionsCreateRolePayload + + """Create a new user""" + createUsersPermissionsUser(data: UsersPermissionsUserInput!): UsersPermissionsUserEntityResponse! + deleteAuthor(id: ID!): AuthorEntityResponse + deleteContentReleasesRelease(id: ID!): ContentReleasesReleaseEntityResponse + deleteContentReleasesReleaseAction(id: ID!): ContentReleasesReleaseActionEntityResponse + deletePage(id: ID!): PageEntityResponse + deletePodcastShow(id: ID!): PodcastShowEntityResponse + deletePost(id: ID!): PostEntityResponse + deleteTag(id: ID!): TagEntityResponse + deleteUploadFile(id: ID!): UploadFileEntityResponse + deleteUploadFolder(id: ID!): UploadFolderEntityResponse + + """Delete an existing role""" + deleteUsersPermissionsRole(id: ID!): UsersPermissionsDeleteRolePayload + + """Delete an existing user""" + deleteUsersPermissionsUser(id: ID!): UsersPermissionsUserEntityResponse! + + """Confirm an email users email address""" + emailConfirmation(confirmation: String!): UsersPermissionsLoginPayload + + """Request a reset password token""" + forgotPassword(email: String!): UsersPermissionsPasswordPayload + login(input: UsersPermissionsLoginInput!): UsersPermissionsLoginPayload! + multipleUpload(field: String, files: [Upload]!, ref: String, refId: ID): [UploadFileEntityResponse]! + + """Register a user""" + register(input: UsersPermissionsRegisterInput!): UsersPermissionsLoginPayload! + removeFile(id: ID!): UploadFileEntityResponse + + """ + Reset user password. Confirm with a code (resetToken from forgotPassword) + """ + resetPassword(code: String!, password: String!, passwordConfirmation: String!): UsersPermissionsLoginPayload + updateAuthor(data: AuthorInput!, id: ID!): AuthorEntityResponse + updateContentReleasesRelease(data: ContentReleasesReleaseInput!, id: ID!): ContentReleasesReleaseEntityResponse + updateContentReleasesReleaseAction(data: ContentReleasesReleaseActionInput!, id: ID!): ContentReleasesReleaseActionEntityResponse + updateFileInfo(id: ID!, info: FileInfoInput): UploadFileEntityResponse! + updatePage(data: PageInput!, id: ID!): PageEntityResponse + updatePodcastShow(data: PodcastShowInput!, id: ID!): PodcastShowEntityResponse + updatePost(data: PostInput!, id: ID!): PostEntityResponse + updateTag(data: TagInput!, id: ID!): TagEntityResponse + updateUploadFile(data: UploadFileInput!, id: ID!): UploadFileEntityResponse + updateUploadFolder(data: UploadFolderInput!, id: ID!): UploadFolderEntityResponse + + """Update an existing role""" + updateUsersPermissionsRole(data: UsersPermissionsRoleInput!, id: ID!): UsersPermissionsUpdateRolePayload + + """Update an existing user""" + updateUsersPermissionsUser(data: UsersPermissionsUserInput!, id: ID!): UsersPermissionsUserEntityResponse! + upload(field: String, file: Upload!, info: FileInfoInput, ref: String, refId: ID): UploadFileEntityResponse! +} + +type Page { + body: String + createdAt: DateTime + description: String + publishedAt: DateTime + slug: String + subtitle: String + title: String + updatedAt: DateTime +} + +type PageEntity { + attributes: Page + id: ID +} + +type PageEntityResponse { + data: PageEntity +} + +type PageEntityResponseCollection { + data: [PageEntity!]! + meta: ResponseCollectionMeta! +} + +input PageFiltersInput { + and: [PageFiltersInput] + body: StringFilterInput + createdAt: DateTimeFilterInput + description: StringFilterInput + id: IDFilterInput + not: PageFiltersInput + or: [PageFiltersInput] + publishedAt: DateTimeFilterInput + slug: StringFilterInput + subtitle: StringFilterInput + title: StringFilterInput + updatedAt: DateTimeFilterInput +} + +input PageInput { + body: String + description: String + publishedAt: DateTime + slug: String + subtitle: String + title: String +} + +type Pagination { + page: Int! + pageCount: Int! + pageSize: Int! + total: Int! +} + +input PaginationArg { + limit: Int + page: Int + pageSize: Int + start: Int +} + +type PodcastShow { + createdAt: DateTime + description: String + hosts(filters: AuthorFiltersInput, pagination: PaginationArg = {}, sort: [String] = []): AuthorRelationResponseCollection + logo: UploadFileEntityResponse + name: String! + posts(filters: PostFiltersInput, pagination: PaginationArg = {}, publicationState: PublicationState = LIVE, sort: [String] = []): PostRelationResponseCollection + publishedAt: DateTime + slug: String + updatedAt: DateTime +} + +type PodcastShowEntity { + attributes: PodcastShow + id: ID +} + +type PodcastShowEntityResponse { + data: PodcastShowEntity +} + +type PodcastShowEntityResponseCollection { + data: [PodcastShowEntity!]! + meta: ResponseCollectionMeta! +} + +input PodcastShowFiltersInput { + and: [PodcastShowFiltersInput] + createdAt: DateTimeFilterInput + description: StringFilterInput + hosts: AuthorFiltersInput + id: IDFilterInput + name: StringFilterInput + not: PodcastShowFiltersInput + or: [PodcastShowFiltersInput] + posts: PostFiltersInput + publishedAt: DateTimeFilterInput + slug: StringFilterInput + updatedAt: DateTimeFilterInput +} + +input PodcastShowInput { + description: String + hosts: [ID] + logo: ID + name: String + posts: [ID] + publishedAt: DateTime + slug: String +} + +type Post { + authors(filters: AuthorFiltersInput, pagination: PaginationArg = {}, sort: [String] = []): AuthorRelationResponseCollection + body: String + channel(filters: ComponentCatChannelFiltersInput, pagination: PaginationArg = {}, sort: [String] = []): [ComponentCatChannel] + cover_image: UploadFileEntityResponse + createdAt: DateTime + credits: String + episode_number: Int + featured: Boolean + podcast_show: PodcastShowEntityResponse + publish_date: Date + publishedAt: DateTime + related_posts(filters: PostFiltersInput, pagination: PaginationArg = {}, publicationState: PublicationState = LIVE, sort: [String] = []): PostRelationResponseCollection + slug: String + subtitle: String + summary: String + tags(filters: TagFiltersInput, pagination: PaginationArg = {}, sort: [String] = []): TagRelationResponseCollection + title: String + type: ENUM_POST_TYPE + updatedAt: DateTime +} + +type PostEntity { + attributes: Post + id: ID +} + +type PostEntityResponse { + data: PostEntity +} + +type PostEntityResponseCollection { + data: [PostEntity!]! + meta: ResponseCollectionMeta! +} + +input PostFiltersInput { + and: [PostFiltersInput] + authors: AuthorFiltersInput + body: StringFilterInput + channel: ComponentCatChannelFiltersInput + createdAt: DateTimeFilterInput + credits: StringFilterInput + episode_number: IntFilterInput + featured: BooleanFilterInput + id: IDFilterInput + not: PostFiltersInput + or: [PostFiltersInput] + podcast_show: PodcastShowFiltersInput + publish_date: DateFilterInput + publishedAt: DateTimeFilterInput + related_posts: PostFiltersInput + slug: StringFilterInput + subtitle: StringFilterInput + summary: StringFilterInput + tags: TagFiltersInput + title: StringFilterInput + type: StringFilterInput + updatedAt: DateTimeFilterInput +} + +input PostInput { + authors: [ID] + body: String + channel: [ComponentCatChannelInput] + cover_image: ID + credits: String + episode_number: Int + featured: Boolean + podcast_show: ID + publish_date: Date + publishedAt: DateTime + related_posts: [ID] + slug: String + subtitle: String + summary: String + tags: [ID] + title: String + type: ENUM_POST_TYPE +} + +type PostRelationResponseCollection { + data: [PostEntity!]! +} + +enum PublicationState { + LIVE + PREVIEW +} + +type Query { + author(id: ID): AuthorEntityResponse + authors(filters: AuthorFiltersInput, pagination: PaginationArg = {}, sort: [String] = []): AuthorEntityResponseCollection + contentReleasesRelease(id: ID): ContentReleasesReleaseEntityResponse + contentReleasesReleaseAction(id: ID): ContentReleasesReleaseActionEntityResponse + contentReleasesReleaseActions(filters: ContentReleasesReleaseActionFiltersInput, pagination: PaginationArg = {}, sort: [String] = []): ContentReleasesReleaseActionEntityResponseCollection + contentReleasesReleases(filters: ContentReleasesReleaseFiltersInput, pagination: PaginationArg = {}, sort: [String] = []): ContentReleasesReleaseEntityResponseCollection + i18NLocale(id: ID): I18NLocaleEntityResponse + i18NLocales(filters: I18NLocaleFiltersInput, pagination: PaginationArg = {}, sort: [String] = []): I18NLocaleEntityResponseCollection + me: UsersPermissionsMe + page(id: ID): PageEntityResponse + pages(filters: PageFiltersInput, pagination: PaginationArg = {}, publicationState: PublicationState = LIVE, sort: [String] = []): PageEntityResponseCollection + podcastShow(id: ID): PodcastShowEntityResponse + podcastShows(filters: PodcastShowFiltersInput, pagination: PaginationArg = {}, publicationState: PublicationState = LIVE, sort: [String] = []): PodcastShowEntityResponseCollection + post(id: ID): PostEntityResponse + posts(filters: PostFiltersInput, pagination: PaginationArg = {}, publicationState: PublicationState = LIVE, sort: [String] = []): PostEntityResponseCollection + tag(id: ID): TagEntityResponse + tags(filters: TagFiltersInput, pagination: PaginationArg = {}, sort: [String] = []): TagEntityResponseCollection + uploadFile(id: ID): UploadFileEntityResponse + uploadFiles(filters: UploadFileFiltersInput, pagination: PaginationArg = {}, sort: [String] = []): UploadFileEntityResponseCollection + uploadFolder(id: ID): UploadFolderEntityResponse + uploadFolders(filters: UploadFolderFiltersInput, pagination: PaginationArg = {}, sort: [String] = []): UploadFolderEntityResponseCollection + usersPermissionsRole(id: ID): UsersPermissionsRoleEntityResponse + usersPermissionsRoles(filters: UsersPermissionsRoleFiltersInput, pagination: PaginationArg = {}, sort: [String] = []): UsersPermissionsRoleEntityResponseCollection + usersPermissionsUser(id: ID): UsersPermissionsUserEntityResponse + usersPermissionsUsers(filters: UsersPermissionsUserFiltersInput, pagination: PaginationArg = {}, sort: [String] = []): UsersPermissionsUserEntityResponseCollection +} + +type ResponseCollectionMeta { + pagination: Pagination! +} + +input StringFilterInput { + and: [String] + between: [String] + contains: String + containsi: String + endsWith: String + eq: String + eqi: String + gt: String + gte: String + in: [String] + lt: String + lte: String + ne: String + nei: String + not: StringFilterInput + notContains: String + notContainsi: String + notIn: [String] + notNull: Boolean + null: Boolean + or: [String] + startsWith: String +} + +type Tag { + createdAt: DateTime + name: String + posts(filters: PostFiltersInput, pagination: PaginationArg = {}, publicationState: PublicationState = LIVE, sort: [String] = []): PostRelationResponseCollection + updatedAt: DateTime +} + +type TagEntity { + attributes: Tag + id: ID +} + +type TagEntityResponse { + data: TagEntity +} + +type TagEntityResponseCollection { + data: [TagEntity!]! + meta: ResponseCollectionMeta! +} + +input TagFiltersInput { + and: [TagFiltersInput] + createdAt: DateTimeFilterInput + id: IDFilterInput + name: StringFilterInput + not: TagFiltersInput + or: [TagFiltersInput] + posts: PostFiltersInput + updatedAt: DateTimeFilterInput +} + +input TagInput { + name: String + posts: [ID] +} + +type TagRelationResponseCollection { + data: [TagEntity!]! +} + +"""The `Upload` scalar type represents a file upload.""" +scalar Upload + +type UploadFile { + alternativeText: String + caption: String + createdAt: DateTime + ext: String + formats: JSON + hash: String! + height: Int + mime: String! + name: String! + previewUrl: String + provider: String! + provider_metadata: JSON + related: [GenericMorph] + size: Float! + updatedAt: DateTime + url: String! + width: Int +} + +type UploadFileEntity { + attributes: UploadFile + id: ID +} + +type UploadFileEntityResponse { + data: UploadFileEntity +} + +type UploadFileEntityResponseCollection { + data: [UploadFileEntity!]! + meta: ResponseCollectionMeta! +} + +input UploadFileFiltersInput { + alternativeText: StringFilterInput + and: [UploadFileFiltersInput] + caption: StringFilterInput + createdAt: DateTimeFilterInput + ext: StringFilterInput + folder: UploadFolderFiltersInput + folderPath: StringFilterInput + formats: JSONFilterInput + hash: StringFilterInput + height: IntFilterInput + id: IDFilterInput + mime: StringFilterInput + name: StringFilterInput + not: UploadFileFiltersInput + or: [UploadFileFiltersInput] + previewUrl: StringFilterInput + provider: StringFilterInput + provider_metadata: JSONFilterInput + size: FloatFilterInput + updatedAt: DateTimeFilterInput + url: StringFilterInput + width: IntFilterInput +} + +input UploadFileInput { + alternativeText: String + caption: String + ext: String + folder: ID + folderPath: String + formats: JSON + hash: String + height: Int + mime: String + name: String + previewUrl: String + provider: String + provider_metadata: JSON + size: Float + url: String + width: Int +} + +type UploadFileRelationResponseCollection { + data: [UploadFileEntity!]! +} + +type UploadFolder { + children(filters: UploadFolderFiltersInput, pagination: PaginationArg = {}, sort: [String] = []): UploadFolderRelationResponseCollection + createdAt: DateTime + files(filters: UploadFileFiltersInput, pagination: PaginationArg = {}, sort: [String] = []): UploadFileRelationResponseCollection + name: String! + parent: UploadFolderEntityResponse + path: String! + pathId: Int! + updatedAt: DateTime +} + +type UploadFolderEntity { + attributes: UploadFolder + id: ID +} + +type UploadFolderEntityResponse { + data: UploadFolderEntity +} + +type UploadFolderEntityResponseCollection { + data: [UploadFolderEntity!]! + meta: ResponseCollectionMeta! +} + +input UploadFolderFiltersInput { + and: [UploadFolderFiltersInput] + children: UploadFolderFiltersInput + createdAt: DateTimeFilterInput + files: UploadFileFiltersInput + id: IDFilterInput + name: StringFilterInput + not: UploadFolderFiltersInput + or: [UploadFolderFiltersInput] + parent: UploadFolderFiltersInput + path: StringFilterInput + pathId: IntFilterInput + updatedAt: DateTimeFilterInput +} + +input UploadFolderInput { + children: [ID] + files: [ID] + name: String + parent: ID + path: String + pathId: Int +} + +type UploadFolderRelationResponseCollection { + data: [UploadFolderEntity!]! +} + +type UsersPermissionsCreateRolePayload { + ok: Boolean! +} + +type UsersPermissionsDeleteRolePayload { + ok: Boolean! +} + +input UsersPermissionsLoginInput { + identifier: String! + password: String! + provider: String! = "local" +} + +type UsersPermissionsLoginPayload { + jwt: String + user: UsersPermissionsMe! +} + +type UsersPermissionsMe { + blocked: Boolean + confirmed: Boolean + email: String + id: ID! + role: UsersPermissionsMeRole + username: String! +} + +type UsersPermissionsMeRole { + description: String + id: ID! + name: String! + type: String +} + +type UsersPermissionsPasswordPayload { + ok: Boolean! +} + +type UsersPermissionsPermission { + action: String! + createdAt: DateTime + role: UsersPermissionsRoleEntityResponse + updatedAt: DateTime +} + +type UsersPermissionsPermissionEntity { + attributes: UsersPermissionsPermission + id: ID +} + +input UsersPermissionsPermissionFiltersInput { + action: StringFilterInput + and: [UsersPermissionsPermissionFiltersInput] + createdAt: DateTimeFilterInput + id: IDFilterInput + not: UsersPermissionsPermissionFiltersInput + or: [UsersPermissionsPermissionFiltersInput] + role: UsersPermissionsRoleFiltersInput + updatedAt: DateTimeFilterInput +} + +type UsersPermissionsPermissionRelationResponseCollection { + data: [UsersPermissionsPermissionEntity!]! +} + +input UsersPermissionsRegisterInput { + email: String! + password: String! + username: String! +} + +type UsersPermissionsRole { + createdAt: DateTime + description: String + name: String! + permissions(filters: UsersPermissionsPermissionFiltersInput, pagination: PaginationArg = {}, sort: [String] = []): UsersPermissionsPermissionRelationResponseCollection + type: String + updatedAt: DateTime + users(filters: UsersPermissionsUserFiltersInput, pagination: PaginationArg = {}, sort: [String] = []): UsersPermissionsUserRelationResponseCollection +} + +type UsersPermissionsRoleEntity { + attributes: UsersPermissionsRole + id: ID +} + +type UsersPermissionsRoleEntityResponse { + data: UsersPermissionsRoleEntity +} + +type UsersPermissionsRoleEntityResponseCollection { + data: [UsersPermissionsRoleEntity!]! + meta: ResponseCollectionMeta! +} + +input UsersPermissionsRoleFiltersInput { + and: [UsersPermissionsRoleFiltersInput] + createdAt: DateTimeFilterInput + description: StringFilterInput + id: IDFilterInput + name: StringFilterInput + not: UsersPermissionsRoleFiltersInput + or: [UsersPermissionsRoleFiltersInput] + permissions: UsersPermissionsPermissionFiltersInput + type: StringFilterInput + updatedAt: DateTimeFilterInput + users: UsersPermissionsUserFiltersInput +} + +input UsersPermissionsRoleInput { + description: String + name: String + permissions: [ID] + type: String + users: [ID] +} + +type UsersPermissionsUpdateRolePayload { + ok: Boolean! +} + +type UsersPermissionsUser { + blocked: Boolean + confirmed: Boolean + createdAt: DateTime + email: String! + provider: String + role: UsersPermissionsRoleEntityResponse + updatedAt: DateTime + username: String! +} + +type UsersPermissionsUserEntity { + attributes: UsersPermissionsUser + id: ID +} + +type UsersPermissionsUserEntityResponse { + data: UsersPermissionsUserEntity +} + +type UsersPermissionsUserEntityResponseCollection { + data: [UsersPermissionsUserEntity!]! + meta: ResponseCollectionMeta! +} + +input UsersPermissionsUserFiltersInput { + and: [UsersPermissionsUserFiltersInput] + blocked: BooleanFilterInput + confirmationToken: StringFilterInput + confirmed: BooleanFilterInput + createdAt: DateTimeFilterInput + email: StringFilterInput + id: IDFilterInput + not: UsersPermissionsUserFiltersInput + or: [UsersPermissionsUserFiltersInput] + password: StringFilterInput + provider: StringFilterInput + resetPasswordToken: StringFilterInput + role: UsersPermissionsRoleFiltersInput + updatedAt: DateTimeFilterInput + username: StringFilterInput +} + +input UsersPermissionsUserInput { + blocked: Boolean + confirmationToken: String + confirmed: Boolean + email: String + password: String + provider: String + resetPasswordToken: String + role: ID + username: String +} + +type UsersPermissionsUserRelationResponseCollection { + data: [UsersPermissionsUserEntity!]! +} \ No newline at end of file diff --git a/src/pages/[...path].tsx b/src/pages/[...path].tsx index dd31915..ae89d0f 100644 --- a/src/pages/[...path].tsx +++ b/src/pages/[...path].tsx @@ -2,7 +2,7 @@ import { CustomNextPage, GetStaticPaths, GetStaticProps } from 'next' import Error from 'next/error' import SEO from '../components/SEO/SEO' import { StaticPage, StaticPageProps } from '../containers/StaticPage' -import unbodyApi from '../services/unbody/unbody.service' +import { strapiApi } from '../services/strapi' type PageProps = Partial<Pick<StaticPageProps, 'data'>> & { error?: string @@ -37,7 +37,8 @@ const Page: CustomNextPage<PageProps> = ({ } export const getStaticPaths: GetStaticPaths = async () => { - const { data } = await unbodyApi.getStaticPages() + const { data } = await strapiApi.getStaticPages({}) + return { paths: data.map((page) => ({ params: { @@ -59,17 +60,18 @@ export const getStaticProps: GetStaticProps<PageProps> = async (ctx) => { } } - const { data, errors } = await unbodyApi.getStaticPage({ + const { data, errors } = await strapiApi.getStaticPages({ + parseContent: true, slug: slug as string, ...(id ? { id, - includeDrafts: true, + published: false, } : {}), }) - if (!data) { + if (!data || data.length === 0) { if (errors && typeof errors === 'string' && errors.includes('not found')) { return { notFound: true, @@ -93,7 +95,7 @@ export const getStaticProps: GetStaticProps<PageProps> = async (ctx) => { return { props: { data: { - page: data, + page: data[0], }, }, notFound: false, diff --git a/src/pages/api/podcasts/[showSlug]/episodes/index.ts b/src/pages/api/podcasts/[showSlug]/episodes/index.ts index 574163d..79e12a2 100644 --- a/src/pages/api/podcasts/[showSlug]/episodes/index.ts +++ b/src/pages/api/podcasts/[showSlug]/episodes/index.ts @@ -1,5 +1,5 @@ import type { NextApiRequest, NextApiResponse } from 'next' -import unbodyApi from '../../../../../services/unbody/unbody.service' +import { strapiApi } from '../../../../../services/strapi' import { parseInt } from '../../../../../utils/data.utils' export default async function handler( @@ -10,7 +10,8 @@ export default async function handler( query: { skip = 0, limit = 10, showSlug }, } = req - const response = await unbodyApi.getLatestEpisodes({ + const response = await strapiApi.getLatestEpisodes({ + highlighted: 'exclude', skip: parseInt(skip, 0), limit: parseInt(limit, 10), showSlug: Array.isArray(showSlug) ? showSlug[0] : showSlug, diff --git a/src/pages/api/posts/index.ts b/src/pages/api/posts/index.ts index 15d38dd..67a48e0 100644 --- a/src/pages/api/posts/index.ts +++ b/src/pages/api/posts/index.ts @@ -1,5 +1,5 @@ import type { NextApiRequest, NextApiResponse } from 'next' -import unbodyApi from '../../../services/unbody/unbody.service' +import { strapiApi } from '../../../services/strapi' import { parseInt } from '../../../utils/data.utils' export default async function handler( @@ -10,9 +10,10 @@ export default async function handler( query: { skip = 0, limit = 10 }, } = req - const response = await unbodyApi.getRecentPosts({ - skip: parseInt(skip, 0), - limit: parseInt(limit, 10), + const response = await strapiApi.getRecentPosts({ + skip: parseInt(skip as string, 0), + limit: parseInt(limit as string, 10), + highlighted: 'exclude', }) res.status(200).json(response) diff --git a/src/pages/api/search/index.ts b/src/pages/api/search/index.ts index 990d444..5c7ea28 100644 --- a/src/pages/api/search/index.ts +++ b/src/pages/api/search/index.ts @@ -1,7 +1,5 @@ import type { NextApiRequest, NextApiResponse } from 'next' -import unbodyApi from '../../../services/unbody/unbody.service' import { LPE } from '../../../types/lpe.types' -import { parseInt } from '../../../utils/data.utils' export default async function handler( req: NextApiRequest, @@ -61,31 +59,39 @@ export default async function handler( } if (postTypes.length > 0) { - const response = await unbodyApi.searchPosts({ - tags, - query: Array.isArray(q) ? q.join(' ').trim() : q.trim(), + // const response = await unbodyApi.searchPosts({ + // tags, + // query: Array.isArray(q) ? q.join(' ').trim() : q.trim(), - type: postTypes as LPE.PostType[], + // type: postTypes as LPE.PostType[], - limit: parseInt(limit, 50), - skip: parseInt(skip, 0), - }) + // limit: parseInt(limit, 50), + // skip: parseInt(skip, 0), + // }) + + const response = { + data: [], + } result.posts.push(...response.data) } if (blockTypes.length > 0) { - const response = await unbodyApi.searchPostBlocks({ - tags, - query: Array.isArray(q) ? q.join(' ') : q, + // const response = await unbodyApi.searchPostBlocks({ + // tags, + // query: Array.isArray(q) ? q.join(' ') : q, - postType: postTypes as LPE.PostType[], - type: blockTypes as LPE.Post.ContentBlockType[], + // postType: postTypes as LPE.PostType[], + // type: blockTypes as LPE.Post.ContentBlockType[], - method: 'hybrid', - limit: parseInt(limit, 50), - skip: parseInt(skip, 0), - }) + // method: 'hybrid', + // limit: parseInt(limit, 50), + // skip: parseInt(skip, 0), + // }) + + const response = { + data: [], + } result.blocks.push(...response.data) } diff --git a/src/pages/api/search/post/[id].ts b/src/pages/api/search/post/[id].ts index 2039c95..6b6f4cd 100644 --- a/src/pages/api/search/post/[id].ts +++ b/src/pages/api/search/post/[id].ts @@ -1,7 +1,5 @@ import type { NextApiRequest, NextApiResponse } from 'next' -import unbodyApi from '../../../../services/unbody/unbody.service' import { LPE } from '../../../../types/lpe.types' -import { parseInt } from '../../../../utils/data.utils' export default async function handler( req: NextApiRequest, @@ -27,26 +25,26 @@ export default async function handler( blocks: [], } - const query: Parameters<(typeof unbodyApi)['searchPostBlocks']>[0] = { - tags, - type: ['text', 'image'], - postId: Array.isArray(id) ? id[0] : id, - query: Array.isArray(q) ? q.join(' ') : q, - method: 'nearText', - certainty: 0.85, + // const query: Parameters<(typeof unbodyApi)['searchPostBlocks']>[0] = { + // tags, + // type: ['text', 'image'], + // postId: Array.isArray(id) ? id[0] : id, + // query: Array.isArray(q) ? q.join(' ') : q, + // method: 'nearText', + // certainty: 0.85, - limit: parseInt(limit, 50), - skip: parseInt(skip, 0), - } + // limit: parseInt(limit, 50), + // skip: parseInt(skip, 0), + // } - result.blocks = await unbodyApi - .searchPostBlocks(query) - .then((res) => res.data) + // result.blocks = await unbodyApi + // .searchPostBlocks(query) + // .then((res) => res.data) - if (result.blocks.length === 0) - result.blocks = await unbodyApi - .searchPostBlocks({ ...query, method: 'hybrid' }) - .then((res) => res.data) + // if (result.blocks.length === 0) + // result.blocks = await unbodyApi + // .searchPostBlocks({ ...query, method: 'hybrid' }) + // .then((res) => res.data) res.status(200).json({ data: result, diff --git a/src/pages/article/[...path].tsx b/src/pages/article/[...path].tsx index f4a7e7a..6b5891c 100644 --- a/src/pages/article/[...path].tsx +++ b/src/pages/article/[...path].tsx @@ -1,7 +1,7 @@ import { SEO } from '@/components/SEO' import ArticleContainer from '@/containers/ArticleContainer' import { GetStaticPropsContext } from 'next' -import unbodyApi from '../../services/unbody/unbody.service' +import { strapiApi } from '../../services/strapi' import { LPE } from '../../types/lpe.types' type ArticleProps = { @@ -24,7 +24,7 @@ const ArticlePage = ({ data, errors, why }: ArticleProps) => { pagePath={`/article/${data.data.slug}`} date={data.data.createdAt} tags={[ - ...data.data.tags, + ...data.data.tags.map((tag) => tag.name), ...data.data.authors.map((author) => author.name), ]} contentType={LPE.PostTypes.Article} @@ -35,17 +35,18 @@ const ArticlePage = ({ data, errors, why }: ArticleProps) => { } export async function getStaticPaths() { - const { data: posts, errors } = await unbodyApi.getArticles({ + const { data, errors } = await strapiApi.getPosts({ skip: 0, limit: 50, - includeDrafts: false, highlighted: 'include', + parseContent: false, + published: true, }) return { paths: errors ? [] - : posts.map((post) => ({ params: { path: [post.slug] } })), + : data.data.map((post) => ({ params: { path: [post.slug] } })), fallback: true, } } @@ -68,13 +69,15 @@ export const getStaticProps = async ({ params }: GetStaticPropsContext) => { } } - const { data, errors } = await unbodyApi.getArticle({ + const { data: res, errors } = await strapiApi.getPosts({ parseContent: true, slug: slug as string, - ...(id ? { id, includeDrafts: true } : {}), + highlighted: 'include', + published: true, + ...(id ? { id, published: false } : {}), }) - if (!data) { + if (!res?.data || res.data.length === 0) { return { notFound: true, props: { why: 'no article' }, @@ -82,22 +85,26 @@ export const getStaticProps = async ({ params }: GetStaticPropsContext) => { } } - const { data: relatedArticles } = await unbodyApi.getRelatedArticles({ - id: data.id, + const article = res.data[0] + + const { data: relatedArticles } = await strapiApi.getRelatedPosts({ + id: article.id, + type: 'article', }) const { data: articlesFromSameAuthors } = - await unbodyApi.getArticlesFromSameAuthors({ - slug: slug as string, - authors: data.authors.map((author) => author.name), + await strapiApi.getPostsFromSameAuthors({ + type: 'article', + excludeId: article.id, + authors: article.authors.map((author) => author.id), }) return { props: { data: { - data, - relatedArticles, - articlesFromSameAuthors, + data: article, + relatedArticles: relatedArticles, + articlesFromSameAuthors: articlesFromSameAuthors.data, }, error: JSON.stringify(errors), }, diff --git a/src/pages/index.tsx b/src/pages/index.tsx index 5e2bc63..89e59d9 100644 --- a/src/pages/index.tsx +++ b/src/pages/index.tsx @@ -2,7 +2,7 @@ import { CustomNextPage, GetStaticProps } from 'next' import SEO from '../components/SEO/SEO' import { HomePage, HomePageProps } from '../containers/HomePage' import { DefaultLayout } from '../layouts/DefaultLayout' -import unbodyApi from '../services/unbody/unbody.service' +import { strapiApi } from '../services/strapi' type PageProps = Pick<HomePageProps, 'data'> @@ -27,19 +27,26 @@ Page.getLayout = function getLayout(page: React.ReactNode) { } export const getStaticProps: GetStaticProps<PageProps> = async () => { - const { data: tags = [] } = await unbodyApi.getTopics(true) - const { data: highlighted } = await unbodyApi.getHighlightedPosts() - const { data: latest } = await unbodyApi.getRecentPosts({ - skip: 0, - limit: 12, + // const { data: tags = [] } = await unbodyApi.getTopics(true) + // const { data: highlighted } = await unbodyApi.getHighlightedPosts() + // const { data: latest } = await unbodyApi.getRecentPosts({ + // skip: 0, + // limit: 15, + // }) + const { data: latest } = await strapiApi.getRecentPosts({ + highlighted: 'exclude', + limit: 15, }) - const { data: _shows = [] } = await unbodyApi.getPodcastShows({ + const { data: highlighted } = await strapiApi.getHighlightedPosts() + const { data: _shows = [] } = await strapiApi.getPodcastShows({ populateEpisodes: true, episodesLimit: 10, }) - const shows = [..._shows].sort((a, b) => (a.title > b.title ? -1 : 1)) + const shows = [...(_shows ?? [])].sort((a, b) => (a.title > b.title ? -1 : 1)) + + const { data: tags = [] } = await strapiApi.getTopics() return { props: { diff --git a/src/pages/podcasts/[showSlug]/[...path].tsx b/src/pages/podcasts/[showSlug]/[...path].tsx index 84714f4..a88773f 100644 --- a/src/pages/podcasts/[showSlug]/[...path].tsx +++ b/src/pages/podcasts/[showSlug]/[...path].tsx @@ -3,7 +3,7 @@ import EpisodeContainer from '@/containers/EpisodeContainer' import { GetStaticPropsContext } from 'next' import { LPE } from '../../../types/lpe.types' -import unbodyApi from '@/services/unbody/unbody.service' +import { strapiApi } from '../../../services/strapi' import { getPostLink } from '../../../utils/route.utils' type EpisodeProps = { @@ -29,7 +29,7 @@ const EpisodePage = ({ episode, relatedEpisodes, errors }: EpisodeProps) => { postSlug: episode.slug as string, })} tags={[ - ...episode.tags, + ...episode.tags.map((tag) => tag.name), ...episode.authors.map((author) => author.name), ]} contentType={LPE.PostTypes.Podcast} @@ -40,7 +40,7 @@ const EpisodePage = ({ episode, relatedEpisodes, errors }: EpisodeProps) => { } export async function getStaticPaths() { - const { data } = await unbodyApi.getPodcastShows({ populateEpisodes: true }) + const { data } = await strapiApi.getPodcastShows({ populateEpisodes: true }) const paths = data.flatMap((show) => { return ( @@ -81,25 +81,36 @@ export const getStaticProps = async ({ params }: GetStaticPropsContext) => { } // TODO : error handling - const { data: episode, errors: episodeErros } = - await unbodyApi.getPodcastEpisode({ - showSlug: showSlug as string, - slug: epSlug as string, - textBlocks: true, - ...(id - ? { - id: id as string, - includeDraft: true, - } - : {}), - }) + const { data: episode, errors: episodeErros } = await strapiApi.getEpisode({ + showSlug: showSlug as string, + slug: epSlug as string, + published: true, + ...(id + ? { + id: id as string, + published: false, + } + : {}), + }) + + const { data: shows } = await strapiApi.getPodcastShows({}) // TODO : error handlings const { data: relatedEpisodes, errors: relatedEpisodesErros } = - await unbodyApi.getRelatedEpisodes({ - showSlug: showSlug as string, - id: episode?.id as string, - }) + await strapiApi + .getRelatedPosts({ + id: episode?.id as string, + type: LPE.PostTypes.Podcast, + }) + .then((data) => ({ + ...data, + data: data.data.map((post) => ({ + ...post, + show: shows.find( + (show) => show.id === (post as LPE.Podcast.Document).showId, + ), + })), + })) if (!episode) { return { @@ -112,7 +123,7 @@ export const getStaticProps = async ({ params }: GetStaticPropsContext) => { return { props: { episode, - relatedEpisodes, + relatedEpisodes: relatedEpisodes, }, revalidate: 10, } diff --git a/src/pages/podcasts/[showSlug]/index.tsx b/src/pages/podcasts/[showSlug]/index.tsx index 16200fe..cd2baa6 100644 --- a/src/pages/podcasts/[showSlug]/index.tsx +++ b/src/pages/podcasts/[showSlug]/index.tsx @@ -1,10 +1,10 @@ import { SEO } from '@/components/SEO' import PodcastShowContainer from '@/containers/PodcastShowContainer' -import unbodyApi from '@/services/unbody/unbody.service' import { GetStaticPropsContext } from 'next' import { useRouter } from 'next/router' import { ReactNode } from 'react' import { DefaultLayout } from '../../../layouts/DefaultLayout' +import { strapiApi } from '../../../services/strapi' import { ApiPaginatedPayload } from '../../../types/data.types' import { LPE } from '../../../types/lpe.types' import { getPostLink } from '../../../utils/route.utils' @@ -48,7 +48,7 @@ const PodcastShowPage = ({ } export async function getStaticPaths() { - const { data } = await unbodyApi.getPodcastShows({ populateEpisodes: false }) + const { data } = await strapiApi.getPodcastShows({ populateEpisodes: false }) const paths = data.map((show) => { return { @@ -76,30 +76,31 @@ export const getStaticProps = async ({ params }: GetStaticPropsContext) => { } // TODO : error handling - const { data: show, errors: podcastShowDataErrors } = - await unbodyApi.getPodcastShow({ - showSlug: showSlug as string, + const { data: shows, errors: podcastShowDataErrors } = + await strapiApi.getPodcastShows({ + slug: showSlug as string, }) // TODO : error handling const { data: latestEpisodes, errors: latestEpisodesErros } = - await unbodyApi.getLatestEpisodes({ + await strapiApi.getLatestEpisodes({ showSlug: showSlug as string, limit: 8, }) // TODO : error handling const { data: highlightedEpisodes, errors: highlightedEpisodesErrors } = - await unbodyApi.getHighlightedEpisodes({ - showSlug: showSlug as string, + await strapiApi.getLatestEpisodes({ + highlighted: 'only', limit: 2, + showSlug: showSlug as string, }) return { props: { - show, + show: shows[0], latestEpisodes, - highlightedEpisodes, + highlightedEpisodes: highlightedEpisodes.data, }, revalidate: 10, } diff --git a/src/pages/podcasts/index.tsx b/src/pages/podcasts/index.tsx index 8d90882..6965065 100644 --- a/src/pages/podcasts/index.tsx +++ b/src/pages/podcasts/index.tsx @@ -1,9 +1,9 @@ import { SEO } from '@/components/SEO' import PodcastsContainer from '@/containers/PodcastsContainer' -import unbodyApi from '@/services/unbody/unbody.service' import { GetStaticPropsContext } from 'next' import { ReactNode } from 'react' import { DefaultLayout } from '../../layouts/DefaultLayout' +import { strapiApi } from '../../services/strapi' import { LPE } from '../../types/lpe.types' import { getPostLink } from '../../utils/route.utils' @@ -43,18 +43,17 @@ const PodcastShowPage = ({ export const getStaticProps = async ({ params }: GetStaticPropsContext) => { // TODO : error handling const { data: podcastShows, errors: podcastShowsErrors } = - await unbodyApi.getPodcastShows({ + await strapiApi.getPodcastShows({ populateEpisodes: true, episodesLimit: 6, }) // TODO : error handling const { data: highlightedEpisodes, errors: highlightedEpisodesErrors } = - await unbodyApi.getHighlightedEpisodes({}) + await strapiApi.getLatestEpisodes({ highlighted: 'only' }) - const { data: latestEpisodes } = await unbodyApi.getPodcastEpisodes({ + const { data: latestEpisodes } = await strapiApi.getLatestEpisodes({ limit: 10, - populateShow: true, highlighted: 'exclude', }) @@ -65,20 +64,11 @@ export const getStaticProps = async ({ params }: GetStaticPropsContext) => { } } - const latestEps = podcastShows - .flatMap((show) => show.episodes) - .sort((a, b) => { - const aDate = new Date(a!.publishedAt) - const bDate = new Date(b!.publishedAt) - return aDate > bDate ? -1 : 1 - }) - .filter((p) => p?.highlighted !== true) - return { props: { shows: podcastShows, - highlightedEpisodes, - latestEpisodes: latestEps, + latestEpisodes: latestEpisodes.data, + highlightedEpisodes: highlightedEpisodes.data, // errors, }, revalidate: 10, diff --git a/src/pages/preview.tsx b/src/pages/preview.tsx index 01ac20d..62526c6 100644 --- a/src/pages/preview.tsx +++ b/src/pages/preview.tsx @@ -1,6 +1,5 @@ import { CustomNextPage, GetServerSideProps } from 'next' import SEO from '../components/SEO/SEO' -import unbodyApi from '../services/unbody/unbody.service' import { getPostLink } from '../utils/route.utils' type PageProps = {} @@ -20,10 +19,13 @@ export const getServerSideProps: GetServerSideProps = async (ctx) => { notFound: true, } - const { data, errors } = await unbodyApi.getDocById({ - id, - includeDrafts: true, - }) + // const { data, errors } = await unbodyApi.getDocById({ + // id, + // includeDrafts: true, + // }) + + const data = undefined as any + const errors = '' as string if (!data || errors) { return { diff --git a/src/pages/search.tsx b/src/pages/search.tsx index aae20d7..97f7741 100644 --- a/src/pages/search.tsx +++ b/src/pages/search.tsx @@ -12,7 +12,6 @@ import { copyConfigs } from '../configs/copy.configs' import { GlobalSearchBox } from '../containers/GlobalSearchBox/GlobalSearchBox' import { DefaultLayout } from '../layouts/DefaultLayout' import { api } from '../services/api.service' -import unbodyApi from '../services/unbody/unbody.service' interface SearchPageProps { topics: string[] @@ -118,11 +117,14 @@ SearchPage.getLayout = (page: ReactNode) => ( ) export async function getStaticProps() { - const { data: topics, errors: topicErrors } = await unbodyApi.getTopics() - const { data: shows = [] } = await unbodyApi.getPodcastShows({ - populateEpisodes: true, - episodesLimit: 10, - }) + // const { data: topics, errors: topicErrors } = await unbodyApi.getTopics() + // const { data: shows = [] } = await unbodyApi.getPodcastShows({ + // populateEpisodes: true, + // episodesLimit: 10, + // }) + + const topics = [] as any + const shows = [] as any return { props: { diff --git a/src/queries/useRecentPosts.query.ts b/src/queries/useRecentPosts.query.ts index 330e3d2..cc58471 100644 --- a/src/queries/useRecentPosts.query.ts +++ b/src/queries/useRecentPosts.query.ts @@ -44,7 +44,8 @@ export const useRecentPosts = ({ ) const posts = useMemo( - () => (query.data?.pages || []).flatMap((page) => page.posts), + () => + (query.data?.pages || []).flatMap((page) => page.posts).filter(Boolean), [query.data], ) diff --git a/src/services/strapi/index.ts b/src/services/strapi/index.ts new file mode 100644 index 0000000..ed02131 --- /dev/null +++ b/src/services/strapi/index.ts @@ -0,0 +1 @@ +export * from './strapi.service' diff --git a/src/services/strapi/strapi.operators.ts b/src/services/strapi/strapi.operators.ts new file mode 100644 index 0000000..d69fdf1 --- /dev/null +++ b/src/services/strapi/strapi.operators.ts @@ -0,0 +1,182 @@ +import { gql } from '@apollo/client' + +const POST_COMMON_ATTRIBUTES = gql` + fragment PostCommonAttributes on Post { + type + title + subtitle + summary + slug + featured + episode_number + podcast_show { + data { + id + } + } + cover_image { + data { + attributes { + url + width + height + caption + } + } + } + authors { + data { + id + attributes { + name + email_address + } + } + } + publish_date + publishedAt + tags { + data { + id + attributes { + name + } + } + } + } +` + +export const GET_PODCAST_SHOWS = gql` + query GetPodcastShows( + $filters: PodcastShowFiltersInput + $pagination: PaginationArg + $sort: [String] + $publicationState: PublicationState + ) { + podcastShows( + filters: $filters + pagination: $pagination + sort: $sort + publicationState: $publicationState + ) { + data { + id + attributes { + name + slug + description + hosts { + data { + attributes { + name + email_address + } + } + } + logo { + data { + attributes { + url + width + height + } + } + } + } + } + } + } +` + +export const GET_POSTS_QUERY = gql` + ${POST_COMMON_ATTRIBUTES} + + query GetPosts( + $filters: PostFiltersInput + $pagination: PaginationArg + $sort: [String] + $publicationState: PublicationState + $withContent: Boolean = false + ) { + posts( + filters: $filters + pagination: $pagination + sort: $sort + publicationState: $publicationState + ) { + meta { + pagination { + total + page + pageSize + pageCount + } + } + data { + id + attributes { + ...PostCommonAttributes + body @include(if: $withContent) + credits @include(if: $withContent) + channel @include(if: $withContent) { + channel + link + } + } + } + } + } +` + +export const GET_RELATED_POSTS_QUERY = gql` + ${POST_COMMON_ATTRIBUTES} + + query GetRelatedPosts($id: ID!, $type: String!) { + post(id: $id) { + data { + attributes { + related_posts( + publicationState: LIVE + filters: { type: { eq: $type } } + ) { + data { + id + attributes { + ...PostCommonAttributes + } + } + } + } + } + } + } +` + +export const GET_STATIC_PAGES = gql` + query GetStaticPages( + $filters: PageFiltersInput + $pagination: PaginationArg + $sort: [String] + $publicationState: PublicationState + $withContent: Boolean = false + ) { + pages( + sort: $sort + filters: $filters + pagination: $pagination + publicationState: $publicationState + ) { + data { + id + attributes { + slug + title + subtitle + description + publishedAt + body @include(if: $withContent) + } + } + } + } +` diff --git a/src/services/strapi/strapi.service.ts b/src/services/strapi/strapi.service.ts new file mode 100644 index 0000000..b306fff --- /dev/null +++ b/src/services/strapi/strapi.service.ts @@ -0,0 +1,502 @@ +import { ApolloClient, InMemoryCache } from '@apollo/client' +import axios, { Axios } from 'axios' +import { + Enum_Post_Type, + GetPodcastShowsDocument, + GetPostsDocument, + GetRelatedPostsDocument, + GetStaticPagesDocument, + PodcastShowFiltersInput, + PostFiltersInput, +} from '../../lib/strapi/strapi.generated' +import { ApiResponse } from '../../types/data.types' +import { LPE } from '../../types/lpe.types' +import { settle } from '../../utils/promise.utils' +import { strapiTransformers } from './transformers/strapi.transformers' + +export class StrapiService { + client: ApolloClient<any> = null as any + axios: Axios = null as any + + constructor(apiUrl: string, graphqlUrl: string, apiKey: string) { + this.axios = axios.create({ + baseURL: apiUrl, + headers: { + Authorization: `Bearer ${apiKey}`, + }, + }) + + const cache = new InMemoryCache({ + typePolicies: { + Query: { + fields: { + podcast_shows: { + merge(existing = {}, incoming) { + return { + ...existing, + ...incoming, + } + }, + }, + pages: { + merge(existing = {}, incoming) { + return { + ...existing, + ...incoming, + } + }, + }, + posts: { + merge(existing = {}, incoming) { + return { + ...existing, + ...incoming, + } + }, + }, + }, + }, + }, + }) + + this.client = new ApolloClient({ + cache, + uri: graphqlUrl, + ssrMode: true, + headers: { + Authorization: `Bearer ${apiKey}`, + }, + }) + } + + handleResponse = <T>( + data: T | null = null, + errors: any = null, + ): ApiResponse<T> => { + if (errors) console.error(errors) + if (errors || !data) { + return { + data: data as any, + errors: JSON.stringify(errors), + } + } + return { + data, + errors, + } + } + + handleRequest = async <T = any>( + handler: () => T | Promise<T>, + defaultValue?: T, + ): Promise<ApiResponse<T>> => { + const [res, err] = await settle<T>(handler) + if (err) return this.handleResponse(defaultValue || null, err) + return this.handleResponse(res) + } + + getStaticPages = async ({ + skip = 0, + limit = 10, + sort = ['publishedAt:desc'], + filters = {}, + id, + slug, + published = true, + parseContent = false, + }: { + skip?: number + limit?: number + sort?: string[] + id?: string + slug?: string + filters?: PostFiltersInput + published?: boolean + parseContent?: boolean + }) => + this.handleRequest<LPE.StaticPage.Document[]>(async () => { + const result: LPE.StaticPage.Document[] = [] + + const { + data: { + pages: { data }, + }, + } = await this.client.query({ + query: GetStaticPagesDocument, + variables: { + pagination: { + start: skip, + limit: limit, + }, + filters: { + and: [ + ...(filters ? [filters] : []), + ...(slug ? [{ slug: { eq: slug } }] : []), + ...(id ? [{ id: { eq: id } }] : []), + ], + }, + sort, + withContent: parseContent, + publicationState: published ? 'LIVE' : 'PREVIEW', + }, + }) + + result.push( + ...(await strapiTransformers.transformMany( + strapiTransformers.get({}), + data, + undefined, + undefined, + )), + ) + + return result + }) + + getPosts = async ({ + skip = 0, + limit = 10, + sort = ['publish_date:desc'], + filters = {}, + id, + slug, + published = true, + highlighted = 'include', + parseContent = false, + }: { + skip?: number + limit?: number + sort?: string[] + id?: string + slug?: string + filters?: PostFiltersInput + published?: boolean + highlighted?: 'only' | 'include' | 'exclude' + parseContent?: boolean + }) => + this.handleRequest(async () => { + const result: LPE.Post.Document[] = [] + + const { + data: { + posts: { data, meta }, + }, + } = await this.client.query({ + query: GetPostsDocument, + variables: { + pagination: { + start: skip, + limit: limit, + }, + filters: { + and: [ + ...(filters ? [filters] : []), + ...(slug ? [{ slug: { eq: slug } }] : []), + ...(id ? [{ id: { eq: id } }] : []), + ...(highlighted === 'only' + ? [ + { + featured: { + eq: true, + }, + } as PostFiltersInput, + ] + : highlighted === 'exclude' + ? [ + { + or: [ + { + featured: { + eq: false, + }, + }, + { + featured: { + null: true, + }, + }, + ], + } as PostFiltersInput, + ] + : []), + ], + }, + sort, + withContent: parseContent, + publicationState: published ? 'LIVE' : 'PREVIEW', + }, + }) + + result.push( + ...(await strapiTransformers.transformMany( + strapiTransformers.get({}), + data, + undefined, + undefined, + )), + ) + + return { + data: result, + total: meta.pagination.total, + hasMore: meta.pagination.page < meta.pagination.pageCount, + } + }) + + getPodcastShows = async ({ + skip = 0, + limit = 10, + sort = ['createdAt:desc'], + filters = {}, + slug, + published = true, + populateEpisodes = false, + episodesLimit = 10, + }: { + skip?: number + limit?: number + sort?: string[] + slug?: string + filters?: PodcastShowFiltersInput + published?: boolean + populateEpisodes?: boolean + episodesLimit?: number + }) => + this.handleRequest<LPE.Podcast.Show[]>(async () => { + const result: LPE.Podcast.Show[] = [] + + const { + data: { + podcastShows: { data }, + }, + } = await this.client.query({ + query: GetPodcastShowsDocument, + variables: { + pagination: { + start: skip, + limit: limit, + }, + filters: { + and: [ + ...(filters ? [filters] : []), + ...(slug ? [{ slug: { eq: slug } }] : []), + ], + }, + sort, + publicationState: published ? 'LIVE' : 'PREVIEW', + }, + }) + + result.push( + ...(await strapiTransformers.transformMany( + strapiTransformers.get({}), + data, + undefined, + undefined, + )), + ) + + for (const show of result) { + const { data } = await this.getPosts({ + filters: { + podcast_show: { + id: { + eq: show.id, + }, + }, + }, + limit: episodesLimit, + highlighted: 'include', + parseContent: false, + published: true, + }) + + if (populateEpisodes) + show.episodes = data.data as LPE.Podcast.Document[] + + show.numberOfEpisodes = data.total + } + + return result + }) + + getRecentPosts = async ({ + skip = 0, + limit = 10, + highlighted = 'exclude', + }: { + limit?: number + skip?: number + highlighted?: 'only' | 'include' | 'exclude' + }) => + this.handleRequest(async () => { + const posts = await this.getPosts({ + limit, + skip, + highlighted, + parseContent: false, + published: true, + }) + + return posts.data + }) + + getHighlightedPosts = async () => + this.handleRequest(async () => { + const posts = await this.getPosts({ + limit: 10, + highlighted: 'only', + parseContent: false, + published: true, + }) + + return posts.data.data + }) + + getLatestEpisodes = async ({ + showSlug, + limit = 10, + skip = 0, + highlighted = 'include', + }: { + showSlug?: string + limit?: number + skip?: number + highlighted?: 'only' | 'include' | 'exclude' + }) => + this.getPosts({ + limit, + skip, + highlighted, + parseContent: false, + published: true, + filters: { + ...(showSlug + ? { + podcast_show: { + slug: { + eq: showSlug, + }, + }, + } + : {}), + type: { + eq: 'Episode' as Enum_Post_Type, + }, + }, + }) + + getEpisode = async ({ + id, + slug, + showSlug, + published = true, + }: { + showSlug: string + slug?: string + id?: string + published?: boolean + }) => + this.getPosts({ + limit: 1, + highlighted: 'include', + parseContent: true, + published, + id, + slug, + filters: { + ...(showSlug + ? { + podcast_show: { + slug: { + eq: showSlug, + }, + }, + } + : {}), + type: { + eq: 'Episode' as Enum_Post_Type, + }, + }, + }).then((res) => ({ + ...res, + data: res.data.data[0] as LPE.Podcast.Document, + })) + + getPostsFromSameAuthors = async ({ + type, + authors, + excludeId, + }: { + authors: string[] + excludeId?: string + type: LPE.PostType + }) => + this.getPosts({ + limit: 10, + highlighted: 'include', + parseContent: false, + filters: { + and: [ + { + authors: { + id: { + in: authors, + }, + }, + }, + { + type: { + eq: type === 'article' ? 'Article' : 'Podcast', + }, + }, + ...(excludeId + ? [ + { + id: { + ne: excludeId, + }, + }, + ] + : []), + ], + }, + }) + + getRelatedPosts = async ({ id, type }: { id: string; type: LPE.PostType }) => + this.handleRequest<LPE.Post.Document[]>(async () => { + const { data } = await this.client.query({ + query: GetRelatedPostsDocument, + variables: { + id, + type: + type === 'article' + ? ('Article' as Enum_Post_Type) + : ('Episode' as Enum_Post_Type), + }, + }) + + return strapiTransformers.transformMany( + strapiTransformers.get({}), + data.post.data.attributes.related_posts.data, + undefined, + undefined, + ) + }) + + getTopics = async () => + this.handleRequest<LPE.Tag.Document[]>(async () => { + const { data } = await this.axios.get('/tags/getAll') + return data.map((tag: any) => ({ + id: tag.id, + name: tag.name, + postsCount: tag.posts?.count ?? 0, + })) + }) +} + +export const strapiApi = new StrapiService( + process.env.STRAPI_API_URL || '', + process.env.STRAPI_GRAPHQL_URL || '', + process.env.STRAPI_API_KEY || '', +) diff --git a/src/services/strapi/strapi.types.ts b/src/services/strapi/strapi.types.ts new file mode 100644 index 0000000..f6161e3 --- /dev/null +++ b/src/services/strapi/strapi.types.ts @@ -0,0 +1,10 @@ +import { + GetPodcastShowsQuery, + GetPostsQuery, + GetStaticPagesQuery, +} from '../../lib/strapi/strapi.generated' + +export type StrapiPostData = GetPostsQuery['posts']['data'][number] +export type StrapiPodcastShowData = + GetPodcastShowsQuery['podcastShows']['data'][number] +export type StrapiStaticPageData = GetStaticPagesQuery['pages']['data'][number] diff --git a/src/services/strapi/transformers/Episode.transformer.ts b/src/services/strapi/transformers/Episode.transformer.ts new file mode 100644 index 0000000..c18a5e6 --- /dev/null +++ b/src/services/strapi/transformers/Episode.transformer.ts @@ -0,0 +1,104 @@ +import { Transformer } from '../../../lib/TransformPipeline/types' +import { LPE } from '../../../types/lpe.types' +import { settle } from '../../../utils/promise.utils' +import { simplecastApi } from '../../simplecast.service' +import { StrapiPostData } from '../strapi.types' +import { transformStrapiHtmlContent } from './utils' + +export const episodeTransformer: Transformer< + LPE.Podcast.Document, + LPE.Podcast.Document, + StrapiPostData, + undefined, + undefined +> = { + key: 'EpisodeTransformer', + classes: ['episode'], + objectType: 'Post', + isMatch: (helpers, object) => object.type === LPE.PostTypes.Podcast, + transform: async (helpers, data, original, root, ctx) => { + return { + ...data, + credits: transformStrapiHtmlContent({ + html: original.attributes.credits || '', + }).blocks as LPE.Post.TextBlock[], + channels: original.attributes.channel + ? await transformChannels(original.attributes.channel) + : [], + } + }, +} + +const transformChannels = async ( + channels: StrapiPostData['attributes']['channel'] = [], +) => { + const transformed: LPE.Podcast.Content['channels'] = [] + + for (const channel of channels) { + const { channel: name, link } = channel + + switch (name) { + case 'Apple_Podcasts': + transformed.push({ + name: LPE.Podcast.ChannelNames.ApplePodcasts, + url: link, + }) + break + + case 'Google_Podcasts': { + transformed.push({ + name: LPE.Podcast.ChannelNames.GooglePodcasts, + url: link, + }) + break + } + + case 'Spotify': { + transformed.push({ + name: LPE.Podcast.ChannelNames.Spotify, + url: link, + }) + break + } + + case 'Youtube': { + transformed.push({ + name: LPE.Podcast.ChannelNames.Youtube, + url: link, + }) + break + } + + case 'Simplecast': { + const episodeId = simplecastApi.extractEpisodeIdFromUrl(link) + + if (!episodeId) { + console.error('invalid Simplecast player url!') + continue + } + + const [res, err] = await settle(() => + simplecastApi.getEpisode({ id: episodeId }), + ) + + if (err) { + console.error('failed to fetch Simplecast episode ', link) + console.error(err) + continue + } + + transformed.push({ + name: LPE.Podcast.ChannelNames.Simplecast, + url: link, + data: { + duration: res.duration, + audioFileUrl: res.ad_free_audio_file_url ?? res.audio_file?.url, + }, + }) + break + } + } + } + + return transformed +} diff --git a/src/services/strapi/transformers/PodcastShow.transformer.ts b/src/services/strapi/transformers/PodcastShow.transformer.ts new file mode 100644 index 0000000..514b5ca --- /dev/null +++ b/src/services/strapi/transformers/PodcastShow.transformer.ts @@ -0,0 +1,39 @@ +import { Transformer } from '../../../lib/TransformPipeline/types' +import { LPE } from '../../../types/lpe.types' +import { getPostLink } from '../../../utils/route.utils' +import { StrapiPodcastShowData } from '../strapi.types' +import { transformStrapiHtmlContent, transformStrapiImageData } from './utils' + +export const podcastShowTransformer: Transformer< + StrapiPodcastShowData, + LPE.Podcast.Show, + StrapiPodcastShowData, + undefined, + undefined +> = { + key: 'PodcastShowTransformer', + classes: ['podcast'], + objectType: 'PodcastShow', + isMatch: (helpers, object) => object.__typename === 'PodcastShowEntity', + transform: (helpers, data, original, root, ctx) => { + const { id, attributes } = data + + return { + id, + slug: attributes.slug, + title: attributes.name, + numberOfEpisodes: 0, + url: getPostLink('podcast', { showSlug: attributes.slug }), + description: attributes.description, + descriptionText: transformStrapiHtmlContent({ + html: attributes.description || '', + }).text, + hosts: attributes.hosts.data.map((host) => ({ + id: '', + name: host.attributes.name, + emailAddress: host.attributes.email_address, + })), + logo: transformStrapiImageData(attributes.logo), + } + }, +} diff --git a/src/services/strapi/transformers/Post.transformer.ts b/src/services/strapi/transformers/Post.transformer.ts new file mode 100644 index 0000000..03226b1 --- /dev/null +++ b/src/services/strapi/transformers/Post.transformer.ts @@ -0,0 +1,109 @@ +import { Transformer } from '../../../lib/TransformPipeline/types' +import { LPE } from '../../../types/lpe.types' +import { calcReadingTime } from '../../../utils/string.utils' +import { StrapiPostData } from '../strapi.types' +import { transformStrapiHtmlContent, transformStrapiImageData } from './utils' + +export const postTransformer: Transformer< + StrapiPostData, + LPE.Post.Document, + StrapiPostData, + undefined, + undefined +> = { + key: 'PostTransformer', + classes: ['post'], + objectType: 'Post', + isMatch: (helpers, object) => object.__typename === 'PostEntity', + transform: (helpers, data, original, root, ctx) => { + const { id, attributes } = data + + const type = attributes.type + const title = attributes.title + const subtitle = attributes.subtitle + const slug = attributes.slug + const publishedAt = attributes.publish_date + const isHighlighted = attributes.featured + const isDraft = !attributes.publishedAt + const coverImage: LPE.Post.Document['coverImage'] = + transformStrapiImageData(attributes.cover_image) + const tags: LPE.Tag.Document[] = attributes.tags.data.map((tag) => ({ + id: tag.id, + name: tag.attributes.name, + })) + + const authors = attributes.authors.data.map((author) => ({ + id: author.id, + name: author.attributes.name, + emailAddress: author.attributes.email_address, + })) + + const summary = transformStrapiHtmlContent({ + html: attributes.summary || '', + }).text + + const { + blocks: content, + toc, + text, + } = transformStrapiHtmlContent({ + html: attributes.body || '', + }) + + // add the title as the first toc item + { + toc.unshift({ + href: '#title-anchor', + blockIndex: -1, + level: 0, + tag: 'h1', + title, + }) + } + + if (type === 'Article') { + return { + id, + title, + subtitle, + slug, + modifiedAt: publishedAt, + createdAt: publishedAt, + coverImage, + tags, + content, + summary, + readingTime: calcReadingTime(text), + toc, + type: 'article', + authors, + highlighted: isHighlighted, + isDraft, + } as LPE.Article.Data + } else { + return { + id, + title, + subtitle, + slug, + publishedAt: publishedAt, + createdAt: publishedAt, + coverImage, + tags, + channels: [], + description: summary, + type: 'podcast', + isDraft, + highlighted: isHighlighted, + authors, + content, + episodeNumber: attributes.episode_number, + showId: attributes.podcast_show.data?.id || null, + modifiedAt: publishedAt, + // will be filled in later + credits: [], + transcription: [], + } as LPE.Podcast.Document + } + }, +} diff --git a/src/services/strapi/transformers/StaticPage.transformer.ts b/src/services/strapi/transformers/StaticPage.transformer.ts new file mode 100644 index 0000000..204bbdf --- /dev/null +++ b/src/services/strapi/transformers/StaticPage.transformer.ts @@ -0,0 +1,42 @@ +import { Transformer } from '../../../lib/TransformPipeline/types' +import { LPE } from '../../../types/lpe.types' +import { StrapiStaticPageData } from '../strapi.types' +import { transformStrapiHtmlContent } from './utils' + +export const staticPageTransformer: Transformer< + StrapiStaticPageData, + LPE.StaticPage.Document, + StrapiStaticPageData, + undefined, + undefined +> = { + key: 'StaticPageTransformer', + classes: ['static_page'], + objectType: 'StaticPage', + isMatch: (helpers, object) => object.__typename === 'PageEntity', + transform: (helpers, data, original, root, ctx) => { + const { id, attributes } = data + + const title = attributes.title + const subtitle = attributes.subtitle + const slug = attributes.slug + const description = attributes.description + + const { blocks: content } = transformStrapiHtmlContent({ + html: attributes.body || '', + }) + + return { + id, + slug, + title, + subtitle, + content, + summary: description, + createdAt: attributes.publishedAt, + modifiedAt: attributes.publishedAt, + isDraft: !attributes.publishedAt, + type: 'static_page', + } + }, +} diff --git a/src/services/strapi/transformers/strapi.transformers.ts b/src/services/strapi/transformers/strapi.transformers.ts new file mode 100644 index 0000000..ebe7e09 --- /dev/null +++ b/src/services/strapi/transformers/strapi.transformers.ts @@ -0,0 +1,12 @@ +import { TransformPipeline } from '../../../lib/TransformPipeline/TransformPipeline' +import { episodeTransformer } from './Episode.transformer' +import { podcastShowTransformer } from './PodcastShow.transformer' +import { postTransformer } from './Post.transformer' +import { staticPageTransformer } from './StaticPage.transformer' + +export const strapiTransformers = new TransformPipeline([ + podcastShowTransformer, + staticPageTransformer, + postTransformer, + episodeTransformer, +]) diff --git a/src/services/strapi/transformers/utils.ts b/src/services/strapi/transformers/utils.ts new file mode 100644 index 0000000..a6b6c98 --- /dev/null +++ b/src/services/strapi/transformers/utils.ts @@ -0,0 +1,187 @@ +import * as htmlParser from 'node-html-parser' +import slugify from 'slugify' +import { UploadFileEntity } from '../../../lib/strapi/strapi.generated' +import { LPE } from '../../../types/lpe.types' +import { convertToIframe } from '../../../utils/string.utils' + +let assetsBaseUrl = process.env.NEXT_PUBLIC_ASSETS_BASE_URL ?? '' +if (assetsBaseUrl.endsWith('/')) assetsBaseUrl = assetsBaseUrl.slice(1) + +export const transformStrapiImageUrl = (url: string): string => + assetsBaseUrl + url + +export const transformStrapiImageData = ( + image: + | Pick<UploadFileEntity, 'attributes'> + | { + data: { + attributes: Partial<UploadFileEntity['attributes']> + } + }, +): LPE.Image.Document => { + const attributes = 'data' in image ? image.data.attributes : image.attributes + + return { + height: attributes.height || 0, + width: attributes.width || 0, + caption: attributes.caption || '', + alt: attributes.caption || attributes.alternativeText || '', + url: attributes.url ? transformStrapiImageUrl(attributes.url) : '', + } +} + +export const transformStrapiHtmlContent = ({ + html, +}: { + html: string +}): { + toc: LPE.Post.TocItem[] + blocks: LPE.Post.ContentBlock[] + html: string + text: string +} => { + const toc: LPE.Post.TocItem[] = [] + const blocks: LPE.Post.ContentBlock[] = [] + + // split paragraphs with <br> into multiple paragraphs + html = html.replaceAll( + /<p(\s+[^>]*)?>(.*?)<br>(.*?)<\/p>/g, + (match, p1, p2, p3) => + [p2, p3] + .join('<br>') + .split('<br>') + .map((p) => `<p${p1 || ''}>${p}</p>`) + .join(''), + ) + + let root = htmlParser.parse(html, { parseNoneClosedTags: true }) + + let blockIndex = -1 + + for (const child of root.childNodes) { + if (!(child instanceof htmlParser.HTMLElement)) { + continue + } + + const tagName = child.tagName.toLowerCase() + const isFigure = tagName === 'figure' + const isMedia = isFigure && !!child.querySelector('oembed') + const isImage = isFigure && !isMedia && !!child.querySelector('img') + const empty = child.text.length === 0 + + if (!isFigure && empty) continue + + blockIndex++ + + if (isImage) { + const image = child.querySelector('img') + if (!image) { + blockIndex-- + continue + } + + const caption = child.textContent || '' + const alt = image.getAttribute('alt') || '' + const url = image.getAttribute('src') || '' + const width = parseInt(image.getAttribute('width') || '0', 10) + const height = parseInt(image.getAttribute('height') || '0', 10) + + blocks.push({ + id: '', + caption, + type: 'image', + width, + height, + alt: alt || caption, + labels: [], + order: blockIndex, + url: url.startsWith('/') ? transformStrapiImageUrl(url) : url, + }) + + continue + } + + if (isMedia) { + const labels: LPE.Post.ContentBlockLabel[] = ['embed'] + + const oembed = child.querySelector('oembed') + const url = oembed?.getAttribute('url') || '' + if (!url) { + blockIndex-- + + continue + } + + const youtube = html.match( + /(https?\:\/\/)?((www\.)?youtube\.com|youtu\.?be)\/[^ "]+/gi, + ) + + const simplecast = html.match( + /(https?\:\/\/)?((player\.)?simplecast\.com)\/[^ "]+/gi, + ) + + const label = youtube?.[0] + ? LPE.Post.ContentBlockLabels.YoutubeEmbed + : LPE.Post.ContentBlockLabels.SimplecastEmbed + + const src = youtube?.[0] || simplecast?.[0] + if (src && src.length > 0) { + labels.push(label) + labels.push(LPE.Post.ContentBlockLabels.Embed) + } + + blocks.push({ + id: `p-${blockIndex}`, + order: 0, + type: 'text', + classNames: [], + footnotes: [], + html: child.outerHTML, + labels, + tagName: 'p', + text: url, + embed: { + src: url, + html: convertToIframe(url), + }, + }) + } + + const text = child.text || '' + const isHeading = tagName.startsWith('h') + const id = + child.id || + (isHeading && slugify(text, { lower: true, trim: true })) || + `p-${blockIndex}` + child.setAttribute('id', id) + + if (isHeading) { + toc.push({ + blockIndex, + href: `#${id}`, + level: parseInt(tagName[1], 10), + tag: tagName, + title: text.trim(), + }) + } + + blocks.push({ + id: '', + footnotes: [], + html: child.outerHTML, + labels: [], + tagName, + text, + order: blockIndex, + classNames: Array.from(child.classList.values()), + type: 'text', + } as LPE.Post.TextBlock) + } + + return { + toc, + blocks, + text: root.text, + html: root.innerHTML, + } +} diff --git a/src/services/unbody/dataTypes/ArticleDocument.dataType.ts b/src/services/unbody/dataTypes/ArticleDocument.dataType.ts index f944817..35027fb 100644 --- a/src/services/unbody/dataTypes/ArticleDocument.dataType.ts +++ b/src/services/unbody/dataTypes/ArticleDocument.dataType.ts @@ -65,6 +65,6 @@ export const ArticleDataType: UnbodyDataTypeConfig< highlighted: data.path.includes('highlighted'), isDraft: data.path.includes('draft'), type: LPE.PostTypes.Article, - } + } as any }, } diff --git a/src/services/unbody/unbody.service.ts b/src/services/unbody/unbody.service.ts index cd22bb2..b5af1d7 100644 --- a/src/services/unbody/unbody.service.ts +++ b/src/services/unbody/unbody.service.ts @@ -1798,8 +1798,8 @@ unbodyApi.onChange(async (oldData, data, changes, firstLoad) => { ...post.tags.map( (tag) => ({ - name: formatTagText(tag), - domain: formatTagText(tag), + name: formatTagText(tag.name), + domain: formatTagText(tag.name), } as Category), ), ], diff --git a/src/types/lpe.types.ts b/src/types/lpe.types.ts index f54d47a..62f576f 100644 --- a/src/types/lpe.types.ts +++ b/src/types/lpe.types.ts @@ -8,17 +8,27 @@ export namespace LPE { export type PostType = DictValues<typeof PostTypes> + export namespace Tag { + export type Document = { + id: string + name: string + postsCount?: number + } + } + export namespace Image { export type Document = { url: string alt: string width: number height: number + caption?: string } } export namespace Author { export type Document = { + id: string name: string emailAddress?: string } @@ -153,7 +163,7 @@ export namespace LPE { summary: string subtitle: string authors: Author.Document[] - tags: string[] + tags: Tag.Document[] highlighted?: boolean isDraft?: boolean @@ -220,7 +230,7 @@ export namespace LPE { id: string slug: string title: string - tags: string[] + tags: Tag.Document[] description: string authors: Author.Document[] publishedAt: string @@ -229,7 +239,7 @@ export namespace LPE { showId?: string highlighted?: boolean isDraft?: boolean - coverImage?: Post.ImageBlock + coverImage?: Image.Document show?: Show type: typeof LPE.PostTypes.Podcast } diff --git a/yarn.lock b/yarn.lock index c335483..0022828 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2070,6 +2070,11 @@ bl@^4.1.0: inherits "^2.0.4" readable-stream "^3.4.0" +boolbase@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e" + integrity sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww== + brace-expansion@^1.1.7: version "1.1.11" resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" @@ -2447,6 +2452,17 @@ css-in-js-utils@^3.1.0: dependencies: hyphenate-style-name "^1.0.3" +css-select@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/css-select/-/css-select-5.1.0.tgz#b8ebd6554c3637ccc76688804ad3f6a6fdaea8a6" + integrity sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg== + dependencies: + boolbase "^1.0.0" + css-what "^6.1.0" + domhandler "^5.0.2" + domutils "^3.0.1" + nth-check "^2.0.1" + css-to-react-native@^3.0.0: version "3.2.0" resolved "https://registry.yarnpkg.com/css-to-react-native/-/css-to-react-native-3.2.0.tgz#cdd8099f71024e149e4f6fe17a7d46ecd55f1e32" @@ -2464,6 +2480,11 @@ css-tree@^1.1.2: mdn-data "2.0.14" source-map "^0.6.1" +css-what@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/css-what/-/css-what-6.1.0.tgz#fb5effcf76f1ddea2c81bdfaa4de44e79bac70f4" + integrity sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw== + csstype@^3.0.2, csstype@^3.0.6: version "3.1.2" resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.2.tgz#1d4bf9d572f11c14031f0436e1c10bc1f571f50b" @@ -2629,6 +2650,36 @@ doctrine@^3.0.0: dependencies: esutils "^2.0.2" +dom-serializer@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-2.0.0.tgz#e41b802e1eedf9f6cae183ce5e622d789d7d8e53" + integrity sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg== + dependencies: + domelementtype "^2.3.0" + domhandler "^5.0.2" + entities "^4.2.0" + +domelementtype@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-2.3.0.tgz#5c45e8e869952626331d7aab326d01daf65d589d" + integrity sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw== + +domhandler@^5.0.2, domhandler@^5.0.3: + version "5.0.3" + resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-5.0.3.tgz#cc385f7f751f1d1fc650c21374804254538c7d31" + integrity sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w== + dependencies: + domelementtype "^2.3.0" + +domutils@^3.0.1: + version "3.1.0" + resolved "https://registry.yarnpkg.com/domutils/-/domutils-3.1.0.tgz#c47f551278d3dc4b0b1ab8cbb42d751a6f0d824e" + integrity sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA== + dependencies: + dom-serializer "^2.0.0" + domelementtype "^2.3.0" + domhandler "^5.0.3" + dot-case@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/dot-case/-/dot-case-3.0.4.tgz#9b2b670d00a431667a8a75ba29cd1b98809ce751" @@ -2695,6 +2746,11 @@ enhanced-resolve@^5.12.0: graceful-fs "^4.2.4" tapable "^2.2.0" +entities@^4.2.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/entities/-/entities-4.5.0.tgz#5d268ea5e7113ec74c4d033b79ea5a35a488fb48" + integrity sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw== + error-ex@^1.3.1: version "1.3.2" resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" @@ -3493,6 +3549,11 @@ has@^1.0.3: dependencies: function-bind "^1.1.1" +he@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" + integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== + header-case@^2.0.4: version "2.0.4" resolved "https://registry.yarnpkg.com/header-case/-/header-case-2.0.4.tgz#5a42e63b55177349cf405beb8d775acabb92c063" @@ -4376,6 +4437,14 @@ node-fetch@^2.6.1, node-fetch@^2.6.12: dependencies: whatwg-url "^5.0.0" +node-html-parser@^6.1.12: + version "6.1.12" + resolved "https://registry.yarnpkg.com/node-html-parser/-/node-html-parser-6.1.12.tgz#6138f805d0ad7a6b5ef415bcd91bca07374bf575" + integrity sha512-/bT/Ncmv+fbMGX96XG9g05vFt43m/+SYKIs9oAemQVYyVcZmDAI2Xq/SbNcpOA35eF0Zk2av3Ksf+Xk8Vt8abA== + dependencies: + css-select "^5.1.0" + he "1.2.0" + node-int64@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" @@ -4410,6 +4479,13 @@ nprogress@^0.2.0: resolved "https://registry.yarnpkg.com/nprogress/-/nprogress-0.2.0.tgz#cb8f34c53213d895723fcbab907e9422adbcafb1" integrity sha512-I19aIingLgR1fmhftnbWWO3dXc0hSxqHQHQb3H8m+K3TnEn/iSeTZZOyvKXWqQESMwuUVnatlCnZdLBZZt2VSA== +nth-check@^2.0.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-2.1.1.tgz#c9eab428effce36cd6b92c924bdb000ef1f1ed1d" + integrity sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w== + dependencies: + boolbase "^1.0.0" + nullthrows@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/nullthrows/-/nullthrows-1.1.1.tgz#7818258843856ae971eae4208ad7d7eb19a431b1" @@ -5250,6 +5326,11 @@ slice-ansi@^5.0.0: ansi-styles "^6.0.0" is-fullwidth-code-point "^4.0.0" +slugify@^1.6.6: + version "1.6.6" + resolved "https://registry.yarnpkg.com/slugify/-/slugify-1.6.6.tgz#2d4ac0eacb47add6af9e04d3be79319cbcc7924b" + integrity sha512-h+z7HKHYXj6wJU+AnS/+IH8Uh9fdcX1Lrhg1/VMdf9PwoBQXFcXiAdsy2tSK0P6gKwJLXp02r90ahUCqHk9rrw== + snake-case@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/snake-case/-/snake-case-3.0.4.tgz#4f2bbd568e9935abdfd593f34c691dadb49c452c"