fix(v4): serve registries from directory (#10781)

* fix(v4): serve registries from directory

* fix(v4): statically cache registries route

* fix
This commit is contained in:
shadcn
2026-05-27 09:16:59 +04:00
committed by GitHub
parent 3751fdfa4c
commit c873713992
6 changed files with 42 additions and 1321 deletions

View File

@@ -0,0 +1,16 @@
import { NextResponse } from "next/server"
import directory from "@/registry/directory.json"
export const dynamic = "force-static"
export async function GET() {
const registries = directory.map(({ name, homepage, url, description }) => ({
name,
homepage,
url,
description,
}))
return NextResponse.json(registries)
}

View File

@@ -12,7 +12,7 @@ You can see the full list at [https://ui.shadcn.com/r/registries.json](https://u
## Adding a Registry
1. Add your registry to [`apps/v4/registry/directory.json`](https://github.com/shadcn-ui/ui/blob/main/apps/v4/registry/directory.json)
2. Run `pnpm registry:build` to update `registries.json` file.
2. Run `pnpm validate:registries` to validate the registry directory.
3. Create a pull request to https://github.com/shadcn-ui/ui
Once you have submitted your request, it will be validated and reviewed by the team.

File diff suppressed because it is too large Load Diff

View File

@@ -465,9 +465,6 @@ try {
console.log("\n📦 Building public/r/index.json...")
await buildIndex()
console.log("\n📋 Building public/r/registries.json...")
await buildRegistriesJson()
console.log("\n🎨 Building public/r/colors...")
await buildColors()
@@ -1176,32 +1173,6 @@ async function buildIndex() {
await writeIfChanged(outputPath, await formatGeneratedJson(index, outputPath))
}
async function buildRegistriesJson() {
const directoryPath = path.join(process.cwd(), "registry/directory.json")
const directoryContent = await fs.readFile(directoryPath, "utf8")
const directory = JSON.parse(directoryContent) as Array<{
name: string
homepage?: string
url: string
description?: string
featured?: boolean
logo?: string
}>
const registries = directory.map((entry) => ({
name: entry.name,
homepage: entry.homepage,
url: entry.url,
description: entry.description,
}))
const outputPath = path.join(process.cwd(), "public/r/registries.json")
await writeIfChanged(
outputPath,
await formatGeneratedJson(registries, outputPath)
)
}
async function readDirectoryEntries(dirPath: string) {
try {
return await fs.readdir(dirPath, { withFileTypes: true })

View File

@@ -19,24 +19,19 @@ const directoryEntrySchema = registryEntrySchema.extend({
const directorySchema = z.array(directoryEntrySchema)
function getRegistries(directory: z.infer<typeof directorySchema>) {
return directory.map(({ name, homepage, url, description }) => ({
name,
homepage,
url,
description,
}))
}
async function main() {
let hasErrors = false
// 1. Validate registries.json.
const registriesFile = path.join(process.cwd(), "public/r/registries.json")
const registriesContent = await fs.readFile(registriesFile, "utf-8")
const registriesData = JSON.parse(registriesContent)
const registriesResult = registriesSchema.safeParse(registriesData)
if (!registriesResult.success) {
console.error("❌ registries.json validation failed:")
console.error(registriesResult.error.format())
hasErrors = true
} else {
console.log("✅ registries.json is valid")
}
// 2. Validate directory.json.
// 1. Validate directory.json.
const directoryFile = path.join(process.cwd(), "registry/directory.json")
const directoryContent = await fs.readFile(directoryFile, "utf-8")
const directoryData = JSON.parse(directoryContent)
@@ -50,27 +45,19 @@ async function main() {
console.log("✅ directory.json is valid")
}
// 3. Check that all directory.json entries are in registries.json.
if (registriesResult.success && directoryResult.success) {
const registryNames = new Set(
registriesResult.data.map((entry) => entry.name)
)
const directoryNames = new Set(
directoryResult.data.map((entry) => entry.name)
// 2. Validate the public registries payload served by /r/registries.json.
if (directoryResult.success) {
const registriesResult = registriesSchema.safeParse(
getRegistries(directoryResult.data)
)
const missingInRegistries = Array.from(directoryNames).filter(
(name) => !registryNames.has(name)
)
if (missingInRegistries.length > 0) {
console.error(
"\n❌ The following registries are in directory.json but missing from registries.json:"
)
missingInRegistries.forEach((name) => console.error(` ${name}`))
if (!registriesResult.success) {
console.error("❌ /r/registries.json validation failed:")
console.error(registriesResult.error.format())
hasErrors = true
} else {
console.log("✅ All directory entries are present in registries.json")
console.log("✅ /r/registries.json payload is valid")
console.log("✅ /r/registries.json includes all directory entries")
}
}