import { z } from "zod" import { createLogger } from "@scandic-hotels/common/logger/createLogger" import { env } from "@/env/server" const logger = createLogger("contentstack-references") /** * Schema for validating Contentstack Management API references response */ const entryReferenceSchema = z.object({ uid: z.string().optional(), entry_uid: z.string(), content_type_uid: z.string(), locale: z.string(), title: z.string(), _version: z.number().optional(), content_type_title: z.string().optional(), }) const referencesResponseSchema = z.object({ references: z.array(entryReferenceSchema).optional().default([]), }) export type EntryReference = z.infer /** * Fetches all entries that reference the given entry from Contentstack Management API. * * This is used during cache invalidation to find parent pages that embed/reference * the changed entry, so we can invalidate their caches as well. * * @see https://www.contentstack.com/docs/developers/apis/content-management-api#entry-references */ export async function fetchEntryReferences( contentTypeUid: string, entryUid: string ): Promise { const managementToken = env.CMS_MANAGEMENT_TOKEN if (!managementToken) { throw new Error("CMS_MANAGEMENT_TOKEN not configured") } // Contentstack EU region base URL const baseUrl = "https://eu-api.contentstack.com" const url = `${baseUrl}/v3/content_types/${contentTypeUid}/entries/${entryUid}/references` const response = await fetch(url, { method: "GET", headers: { api_key: env.CMS_API_KEY, authorization: managementToken, branch: env.CMS_BRANCH, "Content-Type": "application/json", }, // Don't cache this request - we need fresh data cache: "no-store", }) if (!response.ok) { const errorText = await response.text() throw new Error( `Failed to fetch entry references: ${response.status} ${errorText}`, { cause: response, } ) } const data = await response.json() const parsed = referencesResponseSchema.safeParse(data) if (!parsed.success) { throw new Error("Invalid response from Contentstack references API", { cause: parsed.error, }) } logger.debug( `Found ${parsed.data.references.length} references for ${contentTypeUid}/${entryUid}` ) return parsed.data.references }