From 585e343d9a717c1059da7a211e47f7f0c14ea258 Mon Sep 17 00:00:00 2001 From: Klink <85062+dogmar@users.noreply.github.com> Date: Mon, 13 Nov 2023 15:01:47 -0800 Subject: [PATCH] Ensure serializability of errors passed by getStaticProps --- pages/applications/[repo].tsx | 15 ++++++++------- pages/careers/hire/[job].tsx | 3 ++- pages/careers/index.tsx | 3 ++- pages/community.tsx | 21 +++++++++++++++------ pages/index.tsx | 7 ++----- pages/legal/[legal].tsx | 3 ++- pages/marketplace.tsx | 7 ++----- pages/plural-stacks/[stack].tsx | 15 ++++++++------- pages/pricing.tsx | 6 ++---- pages/product.tsx | 3 ++- pages/solutions/[solution].tsx | 8 ++------ src/utils/combineErrors.tsx | 29 +++++++++++++++++++++++++++++ src/utils/getGlobalProps.tsx | 4 +++- src/utils/isNonNullable.ts | 5 +++++ 14 files changed, 84 insertions(+), 45 deletions(-) create mode 100644 src/utils/combineErrors.tsx create mode 100644 src/utils/isNonNullable.ts diff --git a/pages/applications/[repo].tsx b/pages/applications/[repo].tsx index 8a2063c6..0c6529ec 100644 --- a/pages/applications/[repo].tsx +++ b/pages/applications/[repo].tsx @@ -75,6 +75,7 @@ import { type RecipesQuery, type RecipesQueryVariables, } from '@src/generated/graphqlPlural' +import { combineErrors } from '@src/utils/combineErrors' import { type GlobalProps, propsWithGlobalSettings, @@ -478,12 +479,12 @@ export const getStaticProps: GetStaticProps = async (context) => { (appExtras.case_study?.stack_apps as string[]) || [] ), footerVariant: FooterVariant.kitchenSink, - errors: [ - ...(reposError ? [reposError] : []), - ...(stacksError ? [stacksError] : []), - ...(repoError ? [repoError] : []), - ...(appError ? [appError] : []), - ...(faqError ? [faqError] : []), - ], + errors: combineErrors([ + reposError, + stacksError, + repoError, + appError, + faqError, + ]), }) } diff --git a/pages/careers/hire/[job].tsx b/pages/careers/hire/[job].tsx index bac39d05..6e1553be 100644 --- a/pages/careers/hire/[job].tsx +++ b/pages/careers/hire/[job].tsx @@ -16,6 +16,7 @@ import { getJobListing, getJobListingSlugs } from '@src/data/getJobListings' import { type FullJobListingFragment } from '@src/generated/graphqlDirectus' import { ReadMdContent } from '@src/markdoc/mdParser' import { type MarkdocPage } from '@src/markdoc/mdSchema' +import { combineErrors } from '@src/utils/combineErrors' import { propsWithGlobalSettings } from '@src/utils/getGlobalProps' const PAGE_PARAM_NAME = 'job' as const @@ -118,6 +119,6 @@ export const getStaticProps: GetStaticProps = async (context) => { footerVariant: FooterVariant.kitchenSink, job, markdoc, - errors: [...(jobError ? [jobError] : [])], + errors: combineErrors([jobError]), }) } diff --git a/pages/careers/index.tsx b/pages/careers/index.tsx index 7bb36a27..78ab01dd 100644 --- a/pages/careers/index.tsx +++ b/pages/careers/index.tsx @@ -21,6 +21,7 @@ import { ScrollToLink } from '@src/components/ScrollToLink' import { CenteredSectionHead } from '@src/components/SectionHeads' import { getJobListings } from '@src/data/getJobListings' import { type MinJobListingFragment } from '@src/generated/graphqlDirectus' +import { combineErrors } from '@src/utils/combineErrors' import { propsWithGlobalSettings } from '@src/utils/getGlobalProps' import { ValueCard } from '../../src/components/ValueCard' @@ -292,6 +293,6 @@ export const getStaticProps = async () => { 'We are a growing team working on interesting problems in the cloud with Kubernetes, Elixir, Go, and React. We’re always interested in hiring new talent!', footerVariant: FooterVariant.kitchenSink, jobs: jobs || [], - errors: [...(jobsError ? [jobsError.message] : [])], + errors: combineErrors([jobsError]), }) } diff --git a/pages/community.tsx b/pages/community.tsx index 516ce12f..b1fff015 100644 --- a/pages/community.tsx +++ b/pages/community.tsx @@ -28,6 +28,7 @@ import { getContributors } from '@src/data/getGithubData' import { propsWithGlobalSettings } from '@src/utils/getGlobalProps' import { HeaderPad } from '../src/components/layout/HeaderPad' +import { combineErrors } from '../src/utils/combineErrors' export default function Community({ contributors, @@ -174,11 +175,19 @@ export const getStaticProps: GetStaticProps = async ( footerVariant: FooterVariant.kitchenSink, events: events || [], callouts: pageData.callouts, - errors: [ - ...(githubError ? [githubError] : []), - ...(eventsError ? [eventsError] : []), - ...(featuredContributorsError ? [featuredContributorsError] : []), - ...(pageDataError ? [pageDataError] : []), - ], + errors: combineErrors([ + githubError, + eventsError, + featuredContributorsError, + pageDataError, + ]), }) } + +type BaseError = { + name: string + message: string +} +export type FullError = BaseError & { + graphQLErrors?: readonly BaseError[] | undefined +} diff --git a/pages/index.tsx b/pages/index.tsx index 06e2d81f..92ea1e67 100644 --- a/pages/index.tsx +++ b/pages/index.tsx @@ -59,6 +59,7 @@ import { StandardPageWidth, } from '../src/components/layout/LayoutHelpers' import { HomepageFeaturesSection } from '../src/components/page-sections/HomepageFeaturesSection' +import { combineErrors } from '../src/utils/combineErrors' const HeroImagesSC = styled.div(({ theme: _theme }) => { const baseWidth = 1432 @@ -585,10 +586,6 @@ export const getStaticProps = async () => { featuredQuote: page?.featured_quote || null, buildStackTabs, footerVariant: FooterVariant.kitchenSink, - errors: [ - ...(error ? [`${error}`] : []), - ...(stacksError ? [stacksError] : []), - ...(reposError ? [reposError] : []), - ], + errors: combineErrors([error, stacksError, reposError]), }) } diff --git a/pages/legal/[legal].tsx b/pages/legal/[legal].tsx index a0838467..0e38d51e 100644 --- a/pages/legal/[legal].tsx +++ b/pages/legal/[legal].tsx @@ -17,6 +17,7 @@ import { getLegalPageData, getLegalPageSlugs } from '@src/data/getLegalPageData' import { type MarkdownPageFragment } from '@src/generated/graphqlDirectus' import { readMdPage } from '@src/markdoc/mdParser' import { type MarkdocPage } from '@src/markdoc/mdSchema' +import { combineErrors } from '@src/utils/combineErrors' import { propsWithGlobalSettings } from '@src/utils/getGlobalProps' import { HeaderPad } from '../../src/components/layout/HeaderPad' @@ -133,6 +134,6 @@ export const getStaticProps: GetStaticProps = async ( title: page.title, subtitle: page.subtitle, markdoc, - errors: [...(pageDataError ? [pageDataError] : [])], + errors: combineErrors([pageDataError]), }) } diff --git a/pages/marketplace.tsx b/pages/marketplace.tsx index 4590f959..61b794a6 100644 --- a/pages/marketplace.tsx +++ b/pages/marketplace.tsx @@ -55,6 +55,7 @@ import { type FaqListQueryVariables, } from '@src/generated/graphqlDirectus' import { type BasicRepoFragment } from '@src/generated/graphqlPlural' +import { combineErrors } from '@src/utils/combineErrors' import { type GlobalProps, propsWithGlobalSettings, @@ -612,10 +613,6 @@ export const getStaticProps: GetStaticProps = async () => { tags: tags || [], categories: categories || [], faqs: normalizeM2mItems(faqData.collapsible_lists?.[0]) || [], - errors: [ - ...(reposError ? [reposError] : []), - ...(stacksError ? [reposError] : []), - ...(faqError ? [faqError] : []), - ], + errors: combineErrors([reposError, stacksError, faqError]), }) } diff --git a/pages/plural-stacks/[stack].tsx b/pages/plural-stacks/[stack].tsx index 03f0ac4c..e7167145 100644 --- a/pages/plural-stacks/[stack].tsx +++ b/pages/plural-stacks/[stack].tsx @@ -60,6 +60,7 @@ import { type BasicRepoFragment, type StackCollectionFragment, } from '@src/generated/graphqlPlural' +import { combineErrors } from '@src/utils/combineErrors' import { type GlobalProps, propsWithGlobalSettings, @@ -400,12 +401,12 @@ export const getStaticProps: GetStaticProps = async ( (stackExtras.case_study?.stack_apps as string[]) || [] ), footerVariant: FooterVariant.kitchenSink, - errors: [ - ...(reposError ? [reposError] : []), - ...(stacksError ? [stacksError] : []), - ...(stackError ? [stackError] : []), - ...(appError ? [appError] : []), - ...(faqError ? [faqError] : []), - ], + errors: combineErrors([ + reposError, + stacksError, + stackError, + appError, + faqError, + ]), }) } diff --git a/pages/pricing.tsx b/pages/pricing.tsx index e79f9438..fb2e6ebf 100644 --- a/pages/pricing.tsx +++ b/pages/pricing.tsx @@ -24,6 +24,7 @@ import { type FaqListQuery, type FaqListQueryVariables, } from '@src/generated/graphqlDirectus' +import { combineErrors } from '@src/utils/combineErrors' import { propsWithGlobalSettings } from '@src/utils/getGlobalProps' import { normalizeM2mItems } from '@src/utils/normalizeQuotes' @@ -255,9 +256,6 @@ export const getStaticProps: GetStaticProps = async ( ...pricing, faqs: normalizeM2mItems(faqData.collapsible_lists?.[0]) || [], footerVariant: FooterVariant.kitchenSink, - errors: [ - ...(pricingError ? [pricingError] : []), - ...(faqError ? [faqError] : []), - ], + errors: combineErrors([pricingError, faqError]), }) } diff --git a/pages/product.tsx b/pages/product.tsx index 2aa7c52e..8ab367fd 100644 --- a/pages/product.tsx +++ b/pages/product.tsx @@ -25,6 +25,7 @@ import { WhatIsPluralSection } from '@src/components/page-sections/WhatIsPluralS import { CenteredSectionHead } from '@src/components/SectionHeads' import { getProductPageData } from '@src/data/getProductPageData' import { useAnimationPauser } from '@src/hooks/useAnimationPauser' +import { combineErrors } from '@src/utils/combineErrors' import { propsWithGlobalSettings } from '@src/utils/getGlobalProps' import { normalizeM2mItems } from '@src/utils/normalizeQuotes' @@ -254,6 +255,6 @@ export const getStaticProps = async () => { featuredQuote: pageData?.featured_quote, faqs: normalizeM2mItems(pageData?.faq), footerVariant: FooterVariant.kitchenSink, - errors: [...(pageDataError ? [pageDataError] : [])], + errors: combineErrors([pageDataError]), }) } diff --git a/pages/solutions/[solution].tsx b/pages/solutions/[solution].tsx index 33345464..774b3513 100644 --- a/pages/solutions/[solution].tsx +++ b/pages/solutions/[solution].tsx @@ -50,6 +50,7 @@ import { type SolutionsSlugsQuery, type SolutionsSlugsQueryVariables, } from '@src/generated/graphqlDirectus' +import { combineErrors } from '@src/utils/combineErrors' import { type GlobalProps, propsWithGlobalSettings, @@ -248,11 +249,6 @@ export const getStaticProps: GetStaticProps = async (context) => { featuredQuote: solution.featured_quote || null, buildStackTabs, footerVariant: FooterVariant.kitchenSink, - errors: [ - ...(solutionError ? [solutionError] : []), - ...(faqError ? [faqError] : []), - ...(reposError ? [reposError] : []), - ...(stacksError ? [stacksError] : []), - ], + errors: combineErrors([solutionError, faqError, reposError, stacksError]), }) } diff --git a/src/utils/combineErrors.tsx b/src/utils/combineErrors.tsx new file mode 100644 index 00000000..8726c2c4 --- /dev/null +++ b/src/utils/combineErrors.tsx @@ -0,0 +1,29 @@ +import { isNonNullable } from '@src/utils/isNonNullable' + +import { type FullError } from '../../pages/community' + +export function combineErrors( + errors: (FullError | undefined | null)[] | null | undefined +) { + return errors?.filter(isNonNullable).map(serializableError) ?? [] +} + +export function serializableError(err: FullError) { + if (!err) { + return err + } + const { name, message, graphQLErrors } = err + + return { + name, + message, + ...(graphQLErrors + ? { + graphQLErrors: graphQLErrors.map((gqlErr) => ({ + name: gqlErr.name, + message: gqlErr.message, + })), + } + : {}), + } +} diff --git a/src/utils/getGlobalProps.tsx b/src/utils/getGlobalProps.tsx index 91fa56cd..812675c0 100644 --- a/src/utils/getGlobalProps.tsx +++ b/src/utils/getGlobalProps.tsx @@ -10,6 +10,8 @@ import { import { REVALIDATE_TIME } from '@src/consts' import { getSiteSettings } from '@src/data/getSiteSettings' +import { combineErrors } from './combineErrors' + async function getGlobalProps() { const { data: githubData, error: githubError } = await until(() => getGithubDataServer() @@ -28,7 +30,7 @@ async function getGlobalProps() { swrConfig: { fallback: swrFallback, }, - errors: [...(githubError ? [githubError] : [])], + errors: combineErrors([githubError]), } } type AsyncReturnType Promise> = T extends ( diff --git a/src/utils/isNonNullable.ts b/src/utils/isNonNullable.ts new file mode 100644 index 00000000..bcb7e286 --- /dev/null +++ b/src/utils/isNonNullable.ts @@ -0,0 +1,5 @@ +export function isNonNullable( + value: TValue +): value is NonNullable { + return value != null +}