1
+ import { z } from 'zod'
1
2
import { loadRemoteAddOn } from './custom-add-ons/add-on.js'
2
3
import { loadStarter } from './custom-add-ons/starter.js'
3
4
4
- import type { AddOn , Mode , Starter } from './types'
5
+ import type { AddOn , Starter } from './types'
5
6
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 >
23
34
24
35
function absolutizeUrl ( originalUrl : string , relativeUrl : string ) {
25
36
if ( relativeUrl . startsWith ( 'http' ) || relativeUrl . startsWith ( 'https' ) ) {
@@ -35,22 +46,23 @@ export async function getRawRegistry(
35
46
const regUrl = registryUrl || process . env . CTA_REGISTRY
36
47
if ( regUrl ) {
37
48
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' ] || [ ] ) {
39
51
addOn . url = absolutizeUrl ( regUrl , addOn . url )
40
52
}
41
- for ( const starter of registry . starters ) {
53
+ for ( const starter of parsedRegistry . starters || [ ] ) {
42
54
starter . url = absolutizeUrl ( regUrl , starter . url )
43
55
if ( starter . banner ) {
44
56
starter . banner = absolutizeUrl ( regUrl , starter . banner )
45
57
}
46
58
}
47
- return registry
59
+ return parsedRegistry
48
60
}
49
61
}
50
62
51
63
async function getAddOns ( registry : Registry ) : Promise < Array < AddOn > > {
52
64
const addOns : Array < AddOn > = [ ]
53
- for ( const addOnInfo of registry [ 'add-ons' ] ) {
65
+ for ( const addOnInfo of registry [ 'add-ons' ] || [ ] ) {
54
66
const addOn = await loadRemoteAddOn ( addOnInfo . url )
55
67
addOns . push ( addOn )
56
68
}
@@ -66,7 +78,7 @@ export async function getRegistryAddOns(
66
78
67
79
async function getStarters ( registry : Registry ) : Promise < Array < Starter > > {
68
80
const starters : Array < Starter > = [ ]
69
- for ( const starterInfo of registry . starters ) {
81
+ for ( const starterInfo of registry . starters || [ ] ) {
70
82
const starter = await loadStarter ( starterInfo . url )
71
83
starters . push ( starter )
72
84
}
0 commit comments