From d199c37ac04e4a387f55e1ff1fa8d3d1e3a4e62b Mon Sep 17 00:00:00 2001 From: Saket Reddy <144753536+SaketR3@users.noreply.github.com> Date: Thu, 26 Feb 2026 14:35:56 -0600 Subject: [PATCH 01/12] Protect against unpublished content --- src/lib/utils/api.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/lib/utils/api.ts b/src/lib/utils/api.ts index d2e2d7e2..3112a823 100644 --- a/src/lib/utils/api.ts +++ b/src/lib/utils/api.ts @@ -74,6 +74,11 @@ export class ContentWrapper { res[id] = documentToHtmlString(res[id], { renderNode: { [BLOCKS.EMBEDDED_ASSET]: (node) => { + // Add this safety check: If the asset was deleted/unpublished, skip it. + if (!node.data?.target?.fields) { + return ""; + } + const { file, title, description } = node.data.target.fields; return ` From a9832011bcfc947ee06c1dfe26eed4d57b8ebe92 Mon Sep 17 00:00:00 2001 From: Saket Reddy <144753536+SaketR3@users.noreply.github.com> Date: Thu, 26 Feb 2026 14:54:24 -0600 Subject: [PATCH 02/12] Add safety checks at the top of transformLink() so it gracefully skips missing data --- src/lib/utils/api.ts | 29 ++++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/src/lib/utils/api.ts b/src/lib/utils/api.ts index 3112a823..b29ab454 100644 --- a/src/lib/utils/api.ts +++ b/src/lib/utils/api.ts @@ -124,13 +124,20 @@ export class ContentWrapper { } async transformLink(link: any, type: string | undefined): Promise { + // 1. SAFETY CHECK: Ignore completely empty links + if (!link || !link.sys) return undefined; + switch (type) { case "Asset": - return link.src !== undefined // why do I need to do this? - ? link - : { src: `https:${link.fields.file.url}`, alt: link.fields.title }; + if (link.src !== undefined) return link; + // Safety check for deleted/unpublished assets + if (!link.fields || !link.fields.file) return undefined; + return { src: `https:${link.fields.file.url}`, alt: link.fields.title }; case "Entry": + // 2. SAFETY CHECK: If the entry is unpublished/unresolved, skip it + if (!link.sys.contentType) return undefined; + return await this.serialize( link, await this.client.getContentType(link.sys.contentType.sys.id) @@ -139,5 +146,21 @@ export class ContentWrapper { case undefined: return link; } + + // switch (type) { + // case "Asset": + // return link.src !== undefined // why do I need to do this? + // ? link + // : { src: `https:${link.fields.file.url}`, alt: link.fields.title }; + + // case "Entry": + // return await this.serialize( + // link, + // await this.client.getContentType(link.sys.contentType.sys.id) + // ); + + // case undefined: + // return link; + // } } } From 11a62468d49cb9879a23ee67f9a83879f136fa8e Mon Sep 17 00:00:00 2001 From: Saket Reddy <144753536+SaketR3@users.noreply.github.com> Date: Thu, 26 Feb 2026 14:55:47 -0600 Subject: [PATCH 03/12] Add case array to transformLink --- src/lib/utils/api.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/lib/utils/api.ts b/src/lib/utils/api.ts index b29ab454..c4afffb5 100644 --- a/src/lib/utils/api.ts +++ b/src/lib/utils/api.ts @@ -143,6 +143,16 @@ export class ContentWrapper { await this.client.getContentType(link.sys.contentType.sys.id) ); + case "Array": + const transformedArray = await Promise.all( + res[id].map((link: any) => + this.transformLink(link, field.items!.linkType) + ) + ); + // Filter out any undefined items that were unpublished + res[id] = transformedArray.filter((item) => item !== undefined); + break; + case undefined: return link; } From f22c15ee154f4c90dd0acaeeb6b6575fd418d231 Mon Sep 17 00:00:00 2001 From: Saket Reddy <144753536+SaketR3@users.noreply.github.com> Date: Thu, 26 Feb 2026 15:04:28 -0600 Subject: [PATCH 04/12] Update api.ts --- src/lib/utils/api.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/utils/api.ts b/src/lib/utils/api.ts index c4afffb5..346d2592 100644 --- a/src/lib/utils/api.ts +++ b/src/lib/utils/api.ts @@ -10,7 +10,7 @@ type ContentWrapperGetOptions = { allowPreview: boolean; }; -export class ContentWrapper { +export class ContentWrapper { client: ContentfulClientApi; previewClient: ContentfulClientApi | undefined; From 1df4e4aa621dca699dd2e2f7f527b1e916b50710 Mon Sep 17 00:00:00 2001 From: Saket Reddy <144753536+SaketR3@users.noreply.github.com> Date: Thu, 26 Feb 2026 15:07:52 -0600 Subject: [PATCH 05/12] Protect against invalid semesters --- src/routes/+layout.server.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/routes/+layout.server.ts b/src/routes/+layout.server.ts index 31d49a06..de8846b0 100644 --- a/src/routes/+layout.server.ts +++ b/src/routes/+layout.server.ts @@ -22,7 +22,10 @@ async function getSemesters(contentWrapper: ContentWrapper) { select: "fields.semester", }); - const { semesters } = generateProjectsInfo(projects); + // SAFETY CHECK: Ignore any projects that don't have a semester defined + const validProjects = projects.filter((project) => project && project.semester); + + const { semesters } = generateProjectsInfo(validProjects); return semesters; } From 2d08b89f0344bfab8457d3e00d6ee23bd4638d20 Mon Sep 17 00:00:00 2001 From: Saket Reddy <144753536+SaketR3@users.noreply.github.com> Date: Fri, 27 Feb 2026 14:26:01 -0600 Subject: [PATCH 06/12] Protect against undefined semesters --- src/lib/utils/projects.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/lib/utils/projects.ts b/src/lib/utils/projects.ts index b913fdfa..f70a61e9 100644 --- a/src/lib/utils/projects.ts +++ b/src/lib/utils/projects.ts @@ -34,6 +34,8 @@ export function generateProjectsInfo(projects: Project[]): ProjectsInfo { projects.forEach((project) => project.semester.forEach((semester) => { + if (!semester) return; // skip empty/undefined semesters + if (projectArrayMap[semester] !== undefined) { projectArrayMap[semester].push(project); } else { From 422abf1332f98a4442e65d45605db79406e2f052 Mon Sep 17 00:00:00 2001 From: Saket Reddy <144753536+SaketR3@users.noreply.github.com> Date: Fri, 27 Feb 2026 14:27:11 -0600 Subject: [PATCH 07/12] Protect against undefined semesters --- src/lib/utils/schema.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/lib/utils/schema.ts b/src/lib/utils/schema.ts index da5610c0..e29f6ecb 100644 --- a/src/lib/utils/schema.ts +++ b/src/lib/utils/schema.ts @@ -155,6 +155,8 @@ export function setImageHeight(src: string, height: number): string { } export function parseSemester(semester: string): Semester { + if (!semester) return { season: "", year: 0 }; // protect againt undefined semester + const [season, yearString] = semester.split(" "); const year = parseInt(yearString); @@ -163,6 +165,7 @@ export function parseSemester(semester: string): Semester { } export function semesterToId(semester: string): string { + if (!semester) return ""; // protect againt undefined semester return semester.split(" ").join("-").toLowerCase(); } From 93ee8915bea20726b4b99d3b0a3ff441e3ce932c Mon Sep 17 00:00:00 2001 From: Saket Reddy <144753536+SaketR3@users.noreply.github.com> Date: Fri, 27 Feb 2026 14:37:21 -0600 Subject: [PATCH 08/12] Fix bugs in transformlink --- src/lib/utils/api.ts | 56 ++++++++++++++++++++++++++++++++++---------- 1 file changed, 43 insertions(+), 13 deletions(-) diff --git a/src/lib/utils/api.ts b/src/lib/utils/api.ts index 346d2592..75e8514d 100644 --- a/src/lib/utils/api.ts +++ b/src/lib/utils/api.ts @@ -124,7 +124,12 @@ export class ContentWrapper { } async transformLink(link: any, type: string | undefined): Promise { - // 1. SAFETY CHECK: Ignore completely empty links + // Undefined type --> this is a primitive value + // Just return the string directly! + if (!type) return link; + + // Now we know it's supposed to be a Link (Asset or Entry). + // Ignore completely empty/broken links. if (!link || !link.sys) return undefined; switch (type) { @@ -135,28 +140,53 @@ export class ContentWrapper { return { src: `https:${link.fields.file.url}`, alt: link.fields.title }; case "Entry": - // 2. SAFETY CHECK: If the entry is unpublished/unresolved, skip it + // SAFETY CHECK: If the entry is unpublished/unresolved, skip it if (!link.sys.contentType) return undefined; return await this.serialize( link, await this.client.getContentType(link.sys.contentType.sys.id) ); - - case "Array": - const transformedArray = await Promise.all( - res[id].map((link: any) => - this.transformLink(link, field.items!.linkType) - ) - ); - // Filter out any undefined items that were unpublished - res[id] = transformedArray.filter((item) => item !== undefined); - break; - case undefined: + default: return link; } + // WEBSITE FIX ATTEMPT 1 + // Ignore completely empty links + // if (!link || !link.sys) return undefined; + + // switch (type) { + // case "Asset": + // if (link.src !== undefined) return link; + // // Safety check for deleted/unpublished assets + // if (!link.fields || !link.fields.file) return undefined; + // return { src: `https:${link.fields.file.url}`, alt: link.fields.title }; + + // case "Entry": + // // 2. SAFETY CHECK: If the entry is unpublished/unresolved, skip it + // if (!link.sys.contentType) return undefined; + + // return await this.serialize( + // link, + // await this.client.getContentType(link.sys.contentType.sys.id) + // ); + + // case "Array": + // const transformedArray = await Promise.all( + // res[id].map((link: any) => + // this.transformLink(link, field.items!.linkType) + // ) + // ); + // // Filter out any undefined items that were unpublished + // res[id] = transformedArray.filter((item) => item !== undefined); + // break; + + // case undefined: + // return link; + // } + + // ORIGINAL // switch (type) { // case "Asset": // return link.src !== undefined // why do I need to do this? From 05560bf61668f1a12c9e32dc48acf1acaec3f575 Mon Sep 17 00:00:00 2001 From: Saket Reddy <144753536+SaketR3@users.noreply.github.com> Date: Fri, 27 Feb 2026 15:26:03 -0600 Subject: [PATCH 09/12] Also select slug --- src/routes/+layout.server.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/routes/+layout.server.ts b/src/routes/+layout.server.ts index de8846b0..b7a8638c 100644 --- a/src/routes/+layout.server.ts +++ b/src/routes/+layout.server.ts @@ -19,7 +19,7 @@ async function getSemesters(contentWrapper: ContentWrapper) { // OPTIMIZATION: Only fetch the 'semester' field // We use 'select' to filter out images, descriptions, and other heavy data const projects: Project[] = await contentWrapper.get("project", { - select: "fields.semester", + select: "fields.semester,fields.slug", }); // SAFETY CHECK: Ignore any projects that don't have a semester defined From 875dac9468b1e8ffda2cca8c3cfaa5f8fa65f182 Mon Sep 17 00:00:00 2001 From: Saket Reddy <144753536+SaketR3@users.noreply.github.com> Date: Fri, 27 Feb 2026 15:28:28 -0600 Subject: [PATCH 10/12] Remove fields.slug --- src/routes/+layout.server.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/routes/+layout.server.ts b/src/routes/+layout.server.ts index b7a8638c..de8846b0 100644 --- a/src/routes/+layout.server.ts +++ b/src/routes/+layout.server.ts @@ -19,7 +19,7 @@ async function getSemesters(contentWrapper: ContentWrapper) { // OPTIMIZATION: Only fetch the 'semester' field // We use 'select' to filter out images, descriptions, and other heavy data const projects: Project[] = await contentWrapper.get("project", { - select: "fields.semester,fields.slug", + select: "fields.semester", }); // SAFETY CHECK: Ignore any projects that don't have a semester defined From 4d1dcc57eb3c9b4aac3926f4a3d1e521a42e3ded Mon Sep 17 00:00:00 2001 From: Saket Reddy <144753536+SaketR3@users.noreply.github.com> Date: Fri, 27 Feb 2026 15:42:02 -0600 Subject: [PATCH 11/12] Update api.ts --- src/lib/utils/api.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/utils/api.ts b/src/lib/utils/api.ts index 75e8514d..7d411191 100644 --- a/src/lib/utils/api.ts +++ b/src/lib/utils/api.ts @@ -2,7 +2,7 @@ import { documentToHtmlString } from "@contentful/rich-text-html-renderer"; import { BLOCKS, INLINES } from "@contentful/rich-text-types"; import type { ContentfulClientApi, ContentType, Entry } from "contentful"; import contentful from "contentful"; - + type ContentWrapperGetOptions = { /** * Use draft data from the Contentful preview API if the ContentWrapper is authorized to do so. From ec04f7e949d94d5c241abdc785ae59b549753331 Mon Sep 17 00:00:00 2001 From: Saket Reddy <144753536+SaketR3@users.noreply.github.com> Date: Fri, 27 Feb 2026 16:14:43 -0600 Subject: [PATCH 12/12] Update api.ts --- src/lib/utils/api.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/utils/api.ts b/src/lib/utils/api.ts index 7d411191..95791885 100644 --- a/src/lib/utils/api.ts +++ b/src/lib/utils/api.ts @@ -25,7 +25,7 @@ export class ContentWrapper { }); } } - + async get( entity: string, contentfulOptions: any = {},