11import { plans } from "@/lib/types" ;
22import { WorkspaceRole } from "@dub/prisma/client" ;
3- import { GOOGLE_FAVICON_URL , R2_URL } from "@dub/utils" ;
4- import { fileTypeFromBuffer } from "file-type" ;
53import * as z from "zod/v4" ;
64
75export const RECURRING_MAX_DURATIONS = [ 0 , 1 , 3 , 6 , 12 , 18 , 24 , 36 , 48 ] ;
@@ -12,14 +10,6 @@ export const roleSchema = z
1210 . enum ( WorkspaceRole )
1311 . describe ( "The role of the authenticated user in the workspace." ) ;
1412
15- const allowedImageTypes = [
16- "image/png" ,
17- "image/jpeg" ,
18- "image/jpg" ,
19- "image/gif" ,
20- "image/webp" ,
21- ] ;
22-
2313export const booleanQuerySchema = z
2414 . stringbool ( {
2515 truthy : [ "true" ] ,
@@ -96,93 +86,3 @@ export const maxDurationSchema = z.coerce
9686 message : `Max duration must be ${ RECURRING_MAX_DURATIONS . join ( ", " ) } ` ,
9787 } )
9888 . nullish ( ) ;
99-
100- // Base64 encoded image
101- export const base64ImageSchema = z
102- . string ( )
103- . trim ( )
104- . regex ( / ^ d a t a : i m a g e \/ ( p n g | j p e g | j p g | g i f | w e b p ) ; b a s e 6 4 , / , {
105- message : "Invalid image format, supports only png, jpeg, jpg, gif, webp." ,
106- } )
107- . refine (
108- async ( str ) => {
109- const base64Data = str . split ( "," ) [ 1 ] ;
110-
111- if ( ! base64Data ) {
112- return false ;
113- }
114-
115- try {
116- const buffer = new Uint8Array ( Buffer . from ( base64Data , "base64" ) ) ;
117- const fileType = await fileTypeFromBuffer ( buffer ) ;
118-
119- return fileType && allowedImageTypes . includes ( fileType . mime ) ;
120- } catch ( e ) {
121- return false ;
122- }
123- } ,
124- {
125- message : "Invalid image format, supports only png, jpeg, jpg, gif, webp." ,
126- } ,
127- )
128- . transform ( ( v ) => v || null ) ;
129-
130- // Base64 encoded raster image or SVG
131- export const base64ImageAllowSVGSchema = z
132- . string ( )
133- . trim ( )
134- . regex ( / ^ d a t a : i m a g e \/ ( p n g | j p e g | j p g | g i f | w e b p | s v g \+ x m l ) ; b a s e 6 4 , / , {
135- message :
136- "Invalid image format, supports only png, jpeg, jpg, gif, webp, svg." ,
137- } )
138- . transform ( ( v ) => v || null ) ;
139-
140- export const storedR2ImageUrlSchema = z
141- . url ( )
142- . trim ( )
143- . refine ( ( url ) => url . startsWith ( R2_URL ) , {
144- message : `URL must start with ${ R2_URL } ` ,
145- } ) ;
146-
147- // Google user content URL schema - supports URLs like https://lh3.googleusercontent.com/...
148- // This is needed when users sign up via Google OAuth and want to use their Google profile image
149- // as their workspace logo or avatar
150- export const googleUserContentUrlSchema = z
151- . url ( )
152- . trim ( )
153- . refine ( ( url ) => url . startsWith ( "https://lh3.googleusercontent.com/" ) , {
154- message : "Image URL must be a valid Google user content URL" ,
155- } ) ;
156-
157- // Google favicon URL schema - supports URLs starting with GOOGLE_FAVICON_URL
158- export const googleFaviconUrlSchema = z
159- . url ( )
160- . trim ( )
161- . refine ( ( url ) => url . startsWith ( GOOGLE_FAVICON_URL ) , {
162- message : `Image URL must start with ${ GOOGLE_FAVICON_URL } ` ,
163- } ) ;
164-
165- // Uploaded image could be any of the following:
166- // - Base64 encoded image
167- // - R2_URL
168- // - Special case for GOOGLE_FAVICON_URL
169- // - Google user content URLs (e.g., https://lh3.googleusercontent.com/...)
170- // This schema contains an async refinement check for base64 image validation,
171- // which requires using parseAsync() instead of parse() when validating
172- export const uploadedImageSchema = z
173- . union ( [ base64ImageSchema , storedR2ImageUrlSchema , googleFaviconUrlSchema ] )
174- . transform ( ( v ) => v || null ) ;
175-
176- // Base64 encoded image/SVG or R2_URL
177- // This schema contains an async refinement check for base64 image validation,
178- // which requires using parseAsync() instead of parse() when validating
179- export const uploadedImageAllowSVGSchema = z
180- . union ( [ base64ImageAllowSVGSchema , storedR2ImageUrlSchema ] )
181- . transform ( ( v ) => v || null ) ;
182-
183- export const publicHostedImageSchema = z
184- . url ( )
185- . trim ( )
186- . refine ( ( url ) => url . startsWith ( "http://" ) || url . startsWith ( "https://" ) , {
187- message : "Image URL must start with http:// or https://" ,
188- } ) ;
0 commit comments