1+ import { readdir } from "node:fs/promises" ;
12import path from "node:path" ;
23import type { BunRequest , RouterTypes , Server } from "bun" ;
34import { WaveKitResponse } from "./response" ;
@@ -8,6 +9,8 @@ const defaultRoutesDir = isDev
89 ? path . join ( process . cwd ( ) , "app" )
910 : path . join ( process . cwd ( ) , "build" , "app" ) ;
1011
12+ const defaultPublicDir = path . join ( process . cwd ( ) , "public" ) ;
13+
1114const defaultOutDir = path . join ( process . cwd ( ) , "build" ) ;
1215
1316export type WaveKitContext = {
@@ -36,15 +39,38 @@ export type WaveKitHooks = {
3639 afterHandler ?: ( response : WaveKitResponse ) => Promise < WaveKitResponse > ;
3740} ;
3841
42+ async function createAssetsHandlers ( {
43+ assetsDir,
44+ } : { assetsDir : string } ) : Promise <
45+ Record < string , RouterTypes . RouteHandlerObject < string > >
46+ > {
47+ const files = await readdir ( assetsDir , { recursive : true } ) ;
48+ const iterableHandlers = files . map ( ( filePath ) => {
49+ const file = Bun . file ( path . join ( assetsDir , filePath ) ) ;
50+ const fileName = `/${ path . basename ( filePath ) } ` ;
51+ const handler = {
52+ async GET ( ) {
53+ return new WaveKitResponse ( file . stream ( ) , {
54+ headers : { "Content-Type" : file . type } ,
55+ } ) ;
56+ } ,
57+ } ;
58+ return [ fileName , handler ] ;
59+ } ) ;
60+ return Object . fromEntries ( iterableHandlers ) ;
61+ }
62+
3963export type CreateWaveKitProps = {
4064 base ?: string | undefined ;
4165 routesDir ?: string | undefined ;
66+ publicDir ?: string | undefined ;
4267 hooks ?: WaveKitHooks ;
4368} ;
4469
4570export async function createWaveKit ( {
4671 base,
4772 routesDir,
73+ publicDir,
4874 hooks,
4975} : CreateWaveKitProps = { } ) : Promise < WaveKit > {
5076 const safeBase = ( base ?? "/" ) === "/" ? "" : ( base ?? "" ) ;
@@ -100,14 +126,20 @@ export async function createWaveKit({
100126 }
101127 return [ safeBase + path , contextHandler ] ;
102128 } ) ;
129+ const assetsHandlers = await createAssetsHandlers ( {
130+ assetsDir : publicDir ?? defaultPublicDir ,
131+ } ) ;
103132 const filteredRoutes = Object . fromEntries (
104133 ( await Promise . all ( routesWithHandlers ) ) . filter ( Boolean ) as [
105134 string ,
106135 RouterTypes . RouteHandlerObject < string > ,
107136 ] [ ] ,
108137 ) ;
109138 return {
110- routes : filteredRoutes ,
139+ routes : {
140+ ...filteredRoutes ,
141+ ...assetsHandlers ,
142+ } ,
111143 store : contextStore ,
112144 } ;
113145}
@@ -120,12 +152,14 @@ function sanitizeRoutePath(routePath: string) {
120152export type SsgRenderProps = {
121153 base ?: string | undefined ;
122154 routesDir ?: string | undefined ;
155+ publicDir ?: string | undefined ;
123156 outDir ?: string | undefined ;
124157} ;
125158
126159export async function ssgRender ( {
127160 base,
128161 routesDir,
162+ publicDir,
129163 outDir,
130164} : SsgRenderProps = { } ) {
131165 const { routes } = await createWaveKit ( { base, routesDir } ) ;
@@ -148,6 +182,16 @@ export async function ssgRender({
148182 }
149183 } ) ,
150184 ) ;
185+ // Copy assets from public directory to build folder
186+ const publicFiles = await readdir ( publicDir ?? defaultPublicDir , {
187+ recursive : true ,
188+ } ) ;
189+ for ( const file of publicFiles ) {
190+ const sourcePath = path . join ( publicDir ?? defaultPublicDir , file ) ;
191+ const destPath = path . join ( outDir ?? defaultOutDir , base ?? "" , file ) ;
192+ await Bun . write ( destPath , Bun . file ( sourcePath ) ) ;
193+ }
194+
151195 await server . stop ( ) ;
152196 console . log (
153197 `Rendered ${ renderedRoutes } route(s) to ${ outDir ?? defaultOutDir } ` ,
0 commit comments