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
72 changes: 71 additions & 1 deletion lib/websafe/fetch-easyeda-json.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,60 @@
import type { RawEasyEdaJson } from "../schemas/easy-eda-json-schema"

async function tryJlcpcbFallbackSearch(
jlcpcbPartNumber: string,
searchUrl: string,
searchHeaders: Record<string, string>,
originalSearchData: string,
fetch: typeof globalThis.fetch,
): Promise<{ success: boolean; result: any } | null> {
try {
const jlcpcbResponse = await fetch(
"https://jlcpcb.com/api/overseas-pcb-order/v1/shoppingCart/smtGood/selectSmtComponentList",
{
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
keyword: jlcpcbPartNumber,
currentPage: 1,
pageSize: 10,
}),
},
)
if (!jlcpcbResponse.ok) return null

const jlcpcbData = await jlcpcbResponse.json()
const parts = jlcpcbData?.data?.componentPageInfo?.list
if (!parts?.length) return null

const partName = parts[0].erpComponentName
if (!partName) return null

// Search EasyEDA with the manufacturer part name
const fallbackSearchData = originalSearchData.replace(
`wd=${jlcpcbPartNumber}`,
`wd=${encodeURIComponent(partName)}`,
)
const fallbackResponse = await fetch(searchUrl, {
method: "POST",
headers: searchHeaders,
body: fallbackSearchData,
})
if (!fallbackResponse.ok) return null

const fallbackResult = await fallbackResponse.json()
if (
!fallbackResult.success ||
!fallbackResult.result?.lists?.lcsc?.length
) {
return null
}

return fallbackResult
} catch {
return null
}
}

export async function fetchEasyEDAComponent(
jlcpcbPartNumber: string,
{ fetch = globalThis.fetch }: { fetch?: typeof globalThis.fetch } = {},
Expand Down Expand Up @@ -41,7 +96,22 @@ export async function fetchEasyEDAComponent(

const searchResult = await searchResponse.json()
if (!searchResult.success || !searchResult.result.lists.lcsc.length) {
throw new Error("Component not found")
// Try JLCPCB API to get manufacturer part name and retry search
const jlcpcbResult = await tryJlcpcbFallbackSearch(
jlcpcbPartNumber,
searchUrl,
searchHeaders,
searchData,
fetch,
)
if (jlcpcbResult) {
searchResult.result = jlcpcbResult.result
searchResult.success = jlcpcbResult.success
} else {
throw new Error(
`Component ${jlcpcbPartNumber} not found. This may be a JLCPCB-exclusive part without EasyEDA data.`,
)
}
}

const bestMatchComponent =
Expand Down
11 changes: 11 additions & 0 deletions tests/fetch-tests/c9900037709-jlcpcb-shop-part.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { expect, it } from "bun:test"
import { fetchEasyEDAComponent } from "lib/websafe/fetch-easyeda-json"

it("should fetch JLCPCB shop part C9900037709 via manufacturer name fallback", async () => {
const result = await fetchEasyEDAComponent("C9900037709")

// C9900037709 is a JLCPCB-exclusive TXB0104 part not in EasyEDA/LCSC directly.
// The fallback should find a TXB0104 variant via the manufacturer part name.
expect(result).toBeDefined()
expect(result.dataStr?.head?.c_para?.["Manufacturer Part"]).toMatch(/TXB0104/)
})