Merged in feat/rework-contentstack (pull request #3493)

Feat(SW-3708): refactor contentstack fetching (removing all refs) and cache invalidation

* Remove all REFS

* Revalidate correct language

* PR fixes

* PR fixes

* Throw when errors from contentstack api


Approved-by: Joakim Jäderberg
This commit is contained in:
Linus Flood
2026-01-27 12:38:36 +00:00
parent a5e214f783
commit 5fc93472f4
193 changed files with 489 additions and 9018 deletions

View File

@@ -3,26 +3,11 @@ import { z } from "zod"
import { transformedImageVaultAssetSchema } from "@scandic-hotels/common/utils/imageVault"
import { discriminatedUnionArray } from "../../../utils/discriminatedUnion"
import {
cardGridRefsSchema,
cardsGridSchema,
} from "../schemas/blocks/cardsGrid"
import {
carouselCardsRefsSchema,
carouselCardsSchema,
} from "../schemas/blocks/carouselCards"
import {
fullWidthCampaignBlockRefsSchema,
fullWidthCampaignBlockSchema,
} from "../schemas/blocks/fullWidthCampaign"
import {
joinScandicFriendsBlockRefsSchema,
joinScandicFriendsBlockSchema,
} from "../schemas/blocks/joinScandicFriends"
import {
videoCardRefsSchema,
videoCardSchema,
} from "../schemas/blocks/videoCard"
import { cardsGridSchema } from "../schemas/blocks/cardsGrid"
import { carouselCardsSchema } from "../schemas/blocks/carouselCards"
import { fullWidthCampaignBlockSchema } from "../schemas/blocks/fullWidthCampaign"
import { joinScandicFriendsBlockSchema } from "../schemas/blocks/joinScandicFriends"
import { videoCardSchema } from "../schemas/blocks/videoCard"
import { systemSchema } from "../schemas/system"
import { StartPageEnum } from "./utils"
@@ -85,49 +70,3 @@ export const startPageSchema = z.object({
url: z.string(),
}),
})
/** REFS */
const startPageCardsRefs = z
.object({
__typename: z.literal(StartPageEnum.ContentStack.blocks.CardsGrid),
})
.merge(cardGridRefsSchema)
const startPageFullWidthCampaignRef = z
.object({
__typename: z.literal(StartPageEnum.ContentStack.blocks.FullWidthCampaign),
})
.merge(fullWidthCampaignBlockRefsSchema)
const startPageCarouselCardsRef = z
.object({
__typename: z.literal(StartPageEnum.ContentStack.blocks.CarouselCards),
})
.merge(carouselCardsRefsSchema)
const startPageJoinScandicFriendsRef = z
.object({
__typename: z.literal(StartPageEnum.ContentStack.blocks.JoinScandicFriends),
})
.merge(joinScandicFriendsBlockRefsSchema)
const startPageVideoCardRef = z
.object({
__typename: z.literal(StartPageEnum.ContentStack.blocks.VideoCard),
})
.merge(videoCardRefsSchema)
const startPageBlockRefsItem = z.discriminatedUnion("__typename", [
startPageCardsRefs,
startPageFullWidthCampaignRef,
startPageCarouselCardsRef,
startPageJoinScandicFriendsRef,
startPageVideoCardRef,
])
export const startPageRefsSchema = z.object({
start_page: z.object({
blocks: discriminatedUnionArray(startPageBlockRefsItem.options).nullable(),
system: systemSchema,
}),
})

View File

@@ -2,20 +2,11 @@ import { createCounter } from "@scandic-hotels/common/telemetry"
import { router } from "../../.."
import { notFoundError } from "../../../errors"
import {
GetStartPage,
GetStartPageRefs,
} from "../../../graphql/Query/StartPage/StartPage.graphql"
import { GetStartPage } from "../../../graphql/Query/StartPage/StartPage.graphql"
import { request } from "../../../graphql/request"
import { contentstackExtendedProcedureUID } from "../../../procedures"
import {
generateRefsResponseTag,
generateTag,
generateTagsFromAssetSystem,
generateTagsFromSystem,
} from "../../../utils/generateTag"
import { startPageRefsSchema, startPageSchema } from "./output"
import { getConnections } from "./utils"
import { generateTag } from "../../../utils/generateTag"
import { startPageSchema } from "./output"
import type { z } from "zod"
@@ -25,66 +16,19 @@ import type { blocksSchema } from "./output"
export interface GetStartPageData extends z.input<typeof startPageSchema> {}
export interface StartPage extends z.output<typeof startPageSchema> {}
export interface GetStartPageRefsSchema extends z.input<
typeof startPageRefsSchema
> {}
export type Block = z.output<typeof blocksSchema>
export const startPageQueryRouter = router({
get: contentstackExtendedProcedureUID.query(async ({ ctx }) => {
const { lang, uid } = ctx
const getStartPageRefsCounter = createCounter(
"trpc.contentstack.startPage.get.refs"
)
const metricsGetStartPageRefs = getStartPageRefsCounter.init({ lang, uid })
metricsGetStartPageRefs.start()
const refsResponse = await request<GetStartPageRefsSchema>(
GetStartPageRefs,
{
locale: lang,
uid,
},
{
key: generateRefsResponseTag(lang, uid),
ttl: "max",
}
)
if (!refsResponse.data) {
metricsGetStartPageRefs.noDataError()
throw notFoundError({
message: "StartPage refs returned no data",
errorDetails: { lang, uid },
})
}
const validatedRefsData = startPageRefsSchema.safeParse(refsResponse.data)
if (!validatedRefsData.success) {
metricsGetStartPageRefs.validationError(validatedRefsData.error)
return null
}
metricsGetStartPageRefs.success()
const cacheKey = generateTag(lang, uid)
const getStartPageCounter = createCounter("trpc.contentstack.startPage.get")
const metricsGetStartPage = getStartPageCounter.init({ lang, uid })
metricsGetStartPage.start()
const { connections, assetConnections } = getConnections(
validatedRefsData.data
)
const tags = [
generateTagsFromSystem(lang, connections),
generateTagsFromAssetSystem(assetConnections),
generateTag(lang, validatedRefsData.data.start_page.system.uid),
].flat()
const response = await request<GetStartPageData>(
GetStartPage,
{
@@ -92,7 +36,7 @@ export const startPageQueryRouter = router({
uid,
},
{
key: tags,
key: `${cacheKey}`,
ttl: "max",
}
)

View File

@@ -1,8 +1,3 @@
import type { z } from "zod"
import type { AssetSystem, System } from "../schemas/system"
import type { startPageRefsSchema } from "./output"
export namespace StartPageEnum {
export namespace ContentStack {
export const enum blocks {
@@ -14,60 +9,3 @@ export namespace StartPageEnum {
}
}
}
export interface StartPageRefs extends z.output<typeof startPageRefsSchema> {}
export function getConnections({ start_page }: StartPageRefs) {
const connections: System["system"][] = [start_page.system]
const assetConnections: AssetSystem[] = []
if (start_page.blocks) {
start_page.blocks.forEach((block) => {
const typeName = block.__typename
switch (typeName) {
case StartPageEnum.ContentStack.blocks.FullWidthCampaign:
block.full_width_campaign.full_width_campaignConnection.edges.forEach(
({ node }) => {
if (node.system) {
connections.push(node.system)
}
}
)
break
case StartPageEnum.ContentStack.blocks.CardsGrid:
block.cards_grid.forEach((card) => {
connections.push(card)
})
break
case StartPageEnum.ContentStack.blocks.CarouselCards:
block.carousel_cards.card_groups.forEach((group) => {
group.cardConnection.edges.forEach((node) => {
connections.push(node.node.system)
})
})
break
case StartPageEnum.ContentStack.blocks.JoinScandicFriends:
if (block.join_scandic_friends.primary_button) {
connections.push(block.join_scandic_friends.primary_button)
}
break
case StartPageEnum.ContentStack.blocks.VideoCard: {
if (block.video_card?.system) {
connections.push(block.video_card.system)
}
if (block.video_card?.video.sourceConnection.edges[0]) {
assetConnections.push(
block.video_card.video.sourceConnection.edges[0].node
)
}
break
}
default:
const _exhaustiveCheck: never = typeName
break
}
})
}
return { connections, assetConnections }
}