From f67787077e22d0a4608c4795d31cb3e15e0d6ac8 Mon Sep 17 00:00:00 2001 From: Anton Date: Sun, 19 Jul 2026 08:41:54 -0700 Subject: [PATCH] fix(core): guard material-ref parsers against non-string values (Sentry MONOREPO-EDITOR-EM) (#486) * fix(core): guard material-ref parsers against non-string values (Sentry MONOREPO-EDITOR-EM) getLibraryMaterialIdFromRef and getSceneMaterialIdFromRef only guarded against null/undefined, then called .startsWith(). When a non-string material ref reaches them (legacy/malformed wall material slot ref), .startsWith is undefined -> TypeError: e.startsWith is not a function. Narrow with typeof !== 'string' -> return null, so a bad ref degrades to 'no library/scene material' instead of throwing during wall material resolution (packages/viewer wall-materials.ts -> parseMaterialRef). * test(core): cover malformed material refs --------- Co-authored-by: Aymeric Rabot --- packages/core/src/material-library.test.ts | 13 +++++++++++++ packages/core/src/material-library.ts | 5 +++-- 2 files changed, 16 insertions(+), 2 deletions(-) create mode 100644 packages/core/src/material-library.test.ts diff --git a/packages/core/src/material-library.test.ts b/packages/core/src/material-library.test.ts new file mode 100644 index 00000000..344cbbb1 --- /dev/null +++ b/packages/core/src/material-library.test.ts @@ -0,0 +1,13 @@ +import { describe, expect, test } from 'bun:test' +import { getLibraryMaterialIdFromRef, getSceneMaterialIdFromRef } from './material-library' + +describe('material references', () => { + test('rejects malformed runtime values instead of calling string methods', () => { + const malformedRefs: unknown[] = [42, true, {}, []] + + for (const ref of malformedRefs) { + expect(getLibraryMaterialIdFromRef(ref as string)).toBeNull() + expect(getSceneMaterialIdFromRef(ref as string)).toBeNull() + } + }) +}) diff --git a/packages/core/src/material-library.ts b/packages/core/src/material-library.ts index f887d36b..e45a4887 100644 --- a/packages/core/src/material-library.ts +++ b/packages/core/src/material-library.ts @@ -4170,13 +4170,14 @@ export function toSceneMaterialRef(id: string) { } export function getLibraryMaterialIdFromRef(materialRef?: string | null) { - if (!materialRef) return null + if (typeof materialRef !== 'string') return null if (!materialRef.startsWith(LIBRARY_MATERIAL_REF_PREFIX)) return null return materialRef.slice(LIBRARY_MATERIAL_REF_PREFIX.length) } export function getSceneMaterialIdFromRef(materialRef?: string | null): string | null { - if (!materialRef?.startsWith(SCENE_MATERIAL_REF_PREFIX)) return null + if (typeof materialRef !== 'string') return null + if (!materialRef.startsWith(SCENE_MATERIAL_REF_PREFIX)) return null return materialRef.slice(SCENE_MATERIAL_REF_PREFIX.length) }