Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 30 additions & 1 deletion src/hooks/use-global-obj-loader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export function useGlobalObjLoader(
useEffect(() => {
if (!url) return

const cleanUrl = url.replace(/&cachebust_origin=$/, "")
const cleanUrl = normalizeObjLoaderCacheUrl(url)

const cache = window.TSCIRCUIT_OBJ_LOADER_CACHE
let hasUrlChanged = false
Expand Down Expand Up @@ -120,3 +120,32 @@ export function useGlobalObjLoader(

return obj
}

export function normalizeObjLoaderCacheUrl(url: string): string {
try {
const hasProtocol = /^[a-zA-Z][a-zA-Z\d+\-.]*:/.test(url)
const parsedUrl = new URL(
url,
globalThis.location?.href ?? "https://tscircuit.local",
)
parsedUrl.searchParams.delete("cachebust_origin")

const sortedParams = new URLSearchParams(
Array.from(parsedUrl.searchParams.entries()).sort(([a], [b]) =>
a.localeCompare(b),
),
)
parsedUrl.search = sortedParams.toString()

if (!hasProtocol) {
return `${parsedUrl.pathname}${parsedUrl.search}${parsedUrl.hash}`
}

return parsedUrl.toString()
} catch {
return url
.replace(/([?&])cachebust_origin=[^&]*/g, "$1")
.replace(/[?&]$/, "")
.replace("?&", "?")
}
}
28 changes: 28 additions & 0 deletions tests/normalize-obj-loader-cache-url.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { expect, test } from "bun:test"
import { normalizeObjLoaderCacheUrl } from "../src/hooks/use-global-obj-loader"

test("removes cachebust_origin from remote EasyEDA model URLs", () => {
const url =
"https://modelcdn.tscircuit.com/easyeda_models/download?uuid=c886ec2b42464573a88fc1f647577a49&pn=C5184526&cachebust_origin=https%3A%2F%2Ftscircuit.com"

expect(normalizeObjLoaderCacheUrl(url)).toBe(
"https://modelcdn.tscircuit.com/easyeda_models/download?pn=C5184526&uuid=c886ec2b42464573a88fc1f647577a49",
)
})

test("normalizes cache-equivalent model URLs to the same key", () => {
const first =
"https://modelcdn.tscircuit.com/easyeda_models/download?uuid=abc&pn=C1&cachebust_origin=https%3A%2F%2Ftscircuit.com"
const second =
"https://modelcdn.tscircuit.com/easyeda_models/download?cachebust_origin=http%3A%2F%2Flocalhost%3A3020&pn=C1&uuid=abc"

expect(normalizeObjLoaderCacheUrl(first)).toBe(
normalizeObjLoaderCacheUrl(second),
)
})

test("preserves relative model URLs without cachebust params", () => {
expect(normalizeObjLoaderCacheUrl("/easyeda-models/part.obj")).toBe(
"/easyeda-models/part.obj",
)
})
Loading