@@ -0,0 +1,81 @@
1+module Yoga.Bun.HTTP where
2+
3+import Prelude
4+
5+import Effect (Effect)
6+import Effect.Aff (Aff)
7+import Effect.Uncurried (EffectFn1, EffectFn2, mkEffectFn1, runEffectFn1, runEffectFn2)
8+import Foreign (Foreign)
9+import Foreign.Object (Object)
10+import Prim.Row (class Union)
11+import Promise (Promise)
12+import Promise.Aff (toAffE, fromAff) as Promise
13+import Web.Fetch.Request (Request)
14+import Web.Fetch.Response (Response)
15+
16+type BunServerImpl = { stop :: EffectFn1 Boolean (Promise Unit) }
17+
18+data CloseActiveConnections = WaitForOpenConnections | ForceTerminateAllOpenConnections
19+
20+type BunServer = { stop :: CloseActiveConnections -> Aff Unit }
21+
22+foreign import serveImpl :: forall options. EffectFn1 options BunServerImpl
23+
24+type BunServeOptionsImpl = (fetch :: EffectFn1 Request (Promise Response), port :: Int, host :: String)
25+
26+serve :: forall opts opts_. Union opts opts_ BunServeOptionsImpl => { fetch :: EffectFn1 Request (Promise Response) | opts } -> Effect BunServer
27+serve opts = do
28+ serverImpl <- runEffectFn1 serveImpl opts
29+ pure
30+ { stop: \closeActiveConnections -> case closeActiveConnections of
31+ WaitForOpenConnections -> runEffectFn1 serverImpl.stop true # Promise.toAffE
32+ ForceTerminateAllOpenConnections -> runEffectFn1 serverImpl.stop false # Promise.toAffE
33+ }
34+
35+mkFetch :: (Request -> Aff Response) -> EffectFn1 Request (Promise Response)
36+mkFetch fetchAff = mkEffectFn1 (fetchAff >>> Promise.fromAff)
37+
38+-- Response Options Type
39+type ResponseOptions = (status :: Int, headers :: Object String, statusText :: String)
40+
41+-- String/text Response
42+foreign import stringResponseImpl :: forall opts. EffectFn2 String { | opts } Response
43+
44+stringResponse :: forall opts opts_. Union opts opts_ ResponseOptions => String -> { | opts } -> Effect Response
45+stringResponse body opts = runEffectFn2 stringResponseImpl body opts
46+
47+-- JSON Response
48+foreign import jsonResponseImpl :: forall opts. EffectFn2 Foreign { | opts } Response
49+
50+jsonResponse :: forall opts opts_. Union opts opts_ ResponseOptions => Foreign -> { | opts } -> Effect Response
51+jsonResponse json opts = runEffectFn2 jsonResponseImpl json opts
52+
53+-- Empty Response (useful for 204 No Content)
54+foreign import emptyResponseImpl :: forall opts. EffectFn1 { | opts } Response
55+
56+emptyResponse :: forall opts opts_. Union opts opts_ ResponseOptions => { | opts } -> Effect Response
57+emptyResponse opts = runEffectFn1 emptyResponseImpl opts
58+
59+-- Response with ArrayBuffer
60+foreign import arrayBufferResponseImpl :: forall opts. EffectFn2 Foreign { | opts } Response
61+
62+arrayBufferResponse :: forall opts opts_. Union opts opts_ ResponseOptions => Foreign -> { | opts } -> Effect Response
63+arrayBufferResponse buffer opts = runEffectFn2 arrayBufferResponseImpl buffer opts
64+
65+-- Response.redirect() - creates a redirect response
66+foreign import responseRedirectImpl :: EffectFn2 String Int Response
67+
68+responseRedirect :: String -> Int -> Effect Response
69+responseRedirect url status = runEffectFn2 responseRedirectImpl url status
70+
71+-- Response.error() - creates a network error response
72+foreign import responseErrorImpl :: Effect Response
73+
74+responseError :: Effect Response
75+responseError = responseErrorImpl
76+
77+-- Clone a Response
78+foreign import cloneResponseImpl :: Response -> Effect Response
79+
80+cloneResponse :: Response -> Effect Response
81+cloneResponse = cloneResponseImpl