1+ import { z } from 'zod'
12import { loadRemoteAddOn } from './custom-add-ons/add-on.js'
23import { loadStarter } from './custom-add-ons/starter.js'
34
4- import type { AddOn , Mode , Starter } from './types'
5+ import type { AddOn , Starter } from './types'
56
6- export type Registry = {
7- starters : Array < {
8- name : string
9- description : string
10- url : string
11- banner ?: string
12- mode : Mode
13- framework : string
14- } >
15- 'add-ons' : Array < {
16- name : string
17- description : string
18- url : string
19- modes : Array < Mode >
20- framework : string
21- } >
22- }
7+ const registrySchema = z . object ( {
8+ starters : z
9+ . array (
10+ z . object ( {
11+ name : z . string ( ) ,
12+ description : z . string ( ) ,
13+ url : z . string ( ) ,
14+ banner : z . string ( ) . optional ( ) ,
15+ mode : z . enum ( [ 'code-router' , 'file-router' ] ) ,
16+ framework : z . string ( ) ,
17+ } ) ,
18+ )
19+ . optional ( ) ,
20+ 'add-ons' : z
21+ . array (
22+ z . object ( {
23+ name : z . string ( ) ,
24+ description : z . string ( ) ,
25+ url : z . string ( ) ,
26+ modes : z . array ( z . enum ( [ 'code-router' , 'file-router' ] ) ) ,
27+ framework : z . string ( ) ,
28+ } ) ,
29+ )
30+ . optional ( ) ,
31+ } )
32+
33+ export type Registry = z . infer < typeof registrySchema >
2334
2435function absolutizeUrl ( originalUrl : string , relativeUrl : string ) {
2536 if ( relativeUrl . startsWith ( 'http' ) || relativeUrl . startsWith ( 'https' ) ) {
@@ -35,22 +46,23 @@ export async function getRawRegistry(
3546 const regUrl = registryUrl || process . env . CTA_REGISTRY
3647 if ( regUrl ) {
3748 const registry = ( await fetch ( regUrl ) . then ( ( res ) => res . json ( ) ) ) as Registry
38- for ( const addOn of registry [ 'add-ons' ] ) {
49+ const parsedRegistry = registrySchema . parse ( registry )
50+ for ( const addOn of parsedRegistry [ 'add-ons' ] || [ ] ) {
3951 addOn . url = absolutizeUrl ( regUrl , addOn . url )
4052 }
41- for ( const starter of registry . starters ) {
53+ for ( const starter of parsedRegistry . starters || [ ] ) {
4254 starter . url = absolutizeUrl ( regUrl , starter . url )
4355 if ( starter . banner ) {
4456 starter . banner = absolutizeUrl ( regUrl , starter . banner )
4557 }
4658 }
47- return registry
59+ return parsedRegistry
4860 }
4961}
5062
5163async function getAddOns ( registry : Registry ) : Promise < Array < AddOn > > {
5264 const addOns : Array < AddOn > = [ ]
53- for ( const addOnInfo of registry [ 'add-ons' ] ) {
65+ for ( const addOnInfo of registry [ 'add-ons' ] || [ ] ) {
5466 const addOn = await loadRemoteAddOn ( addOnInfo . url )
5567 addOns . push ( addOn )
5668 }
@@ -66,7 +78,7 @@ export async function getRegistryAddOns(
6678
6779async function getStarters ( registry : Registry ) : Promise < Array < Starter > > {
6880 const starters : Array < Starter > = [ ]
69- for ( const starterInfo of registry . starters ) {
81+ for ( const starterInfo of registry . starters || [ ] ) {
7082 const starter = await loadStarter ( starterInfo . url )
7183 starters . push ( starter )
7284 }
0 commit comments