-----------------------------------------------------------------------------
{-# LANGUAGE OverloadedStrings   #-}
{-# LANGUAGE RecordWildCards     #-}
-----------------------------------------------------------------------------
-- |
-- Module      :  Miso.Cookie
-- Copyright   :  (C) 2016-2026 David M. Johnson
-- License     :  BSD3-style (see the file LICENSE)
-- Maintainer  :  David M. Johnson <code@dmj.io>
-- Stability   :  experimental
-- Portability :  non-portable
--
-- = Overview
--
-- "Miso.Cookie" wraps the browser's
-- <https://developer.mozilla.org/en-US/docs/Web/API/CookieStore CookieStore API>
-- as 'Miso.Effect.Effect' combinators that integrate directly into the
-- Model-View-Update loop.
--
-- = Quick start
--
-- @
-- import "Miso"
-- import "Miso.Cookie"
--
-- data Action
--   = LoadSession
--   | GotSession (Maybe 'Cookie')
--   | SessionError 'Miso.String.MisoString'
--   | SaveTheme
--   | ThemeSaved
--
-- update :: Action -> 'Miso.Effect.Effect' p props Model Action
-- update LoadSession =
--   'cookieGet' \"session\" GotSession SessionError
-- update SaveTheme =
--   'cookieSet' \"theme\" \"dark\" ThemeSaved SessionError
-- update _ = pure ()
-- @
--
-- = Types
--
-- * 'Cookie' — a single cookie with all standard fields
-- * 'CookieChangeEvent' — payload for 'Miso.Subscription.Cookie.cookieChangeSub'
--
-- = API groups
--
-- * __Read__: 'cookieGet', 'cookieGetAll'
-- * __Write__: 'cookieSet'
-- * __Delete__: 'cookieDelete'
--
-- = Availability
--
-- The CookieStore API requires a
-- <https://developer.mozilla.org/en-US/docs/Web/Security/Secure_Contexts secure context>
-- (HTTPS or @localhost@) and is not yet universally supported. Operations
-- silently call the error callback when the API is unavailable.
--
-- = See also
--
-- * "Miso.Subscription.Cookie" — 'Miso.Subscription.Cookie.cookieChangeSub'
--   for subscribing to cookie change events
-- * "Miso.FFI" — raw FFI primitives ('Miso.FFI.cookieGet' etc.) for
--   advanced use-cases
-----------------------------------------------------------------------------
module Miso.Cookie
  ( -- ** Types
    Cookie (..)
  , CookieChangeEvent (..)
    -- ** Read
  , cookieGet
  , cookieGetAll
    -- ** Write
  , cookieSet
    -- ** Delete
  , cookieDelete
  , cookieDeleteWith
    -- ** Construction
  , defaultCookie
    -- ** Synchronous API variants
  , cookieSet_
  , cookieGet_
  , cookieDelete_
  , cookieDeleteWith_
  , cookieGetAll_
  ) where
-----------------------------------------------------------------------------
import           Control.Concurrent (MVar, newEmptyMVar, putMVar, takeMVar)
import           Control.Monad ((<=<), forM_, join)
import           Prelude hiding ((!!))
-----------------------------------------------------------------------------
import           Miso.DSL
import           Miso.Effect
import           Miso.String (MisoString)
import qualified Miso.FFI.Internal as FFI
-----------------------------------------------------------------------------
-- | A cookie from the
-- <https://developer.mozilla.org/en-US/docs/Web/API/CookieStore CookieStore API>.
--
-- Fields map directly to the browser's
-- <https://developer.mozilla.org/en-US/docs/Web/API/CookieStore/get#return_value CookieListItem>.
data Cookie = Cookie
  { Cookie -> MisoString
cookieName        :: MisoString
  -- ^ Cookie name (empty string for nameless cookies)
  , Cookie -> Maybe MisoString
cookieValue       :: Maybe MisoString
  -- ^ Cookie value
  , Cookie -> Maybe MisoString
cookieDomain      :: Maybe MisoString
  -- ^ Cookie domain (@Nothing@ when unset — host-only cookie)
  , Cookie -> MisoString
cookiePath        :: MisoString
  -- ^ Cookie path
  , Cookie -> Maybe Double
cookieExpires     :: Maybe Double
  -- ^ Expiry as Unix milliseconds (@Nothing@ for session cookies)
  , Cookie -> Bool
cookieSecure      :: Bool
  -- ^ @Secure@ flag
  , Cookie -> MisoString
cookieSameSite    :: MisoString
  -- ^ @SameSite@ value: @\"strict\"@, @\"lax\"@, or @\"none\"@
  , Cookie -> Bool
cookiePartitioned :: Bool
  -- ^ @Partitioned@ flag (CHIPS — Cookies Having Independent Partitioned State)
  } deriving (Int -> Cookie -> ShowS
[Cookie] -> ShowS
Cookie -> String
(Int -> Cookie -> ShowS)
-> (Cookie -> String) -> ([Cookie] -> ShowS) -> Show Cookie
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> Cookie -> ShowS
showsPrec :: Int -> Cookie -> ShowS
$cshow :: Cookie -> String
show :: Cookie -> String
$cshowList :: [Cookie] -> ShowS
showList :: [Cookie] -> ShowS
Show, Cookie -> Cookie -> Bool
(Cookie -> Cookie -> Bool)
-> (Cookie -> Cookie -> Bool) -> Eq Cookie
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: Cookie -> Cookie -> Bool
== :: Cookie -> Cookie -> Bool
$c/= :: Cookie -> Cookie -> Bool
/= :: Cookie -> Cookie -> Bool
Eq)
-----------------------------------------------------------------------------
instance ToJSVal Cookie where
  toJSVal :: Cookie -> IO JSVal
toJSVal Cookie {Bool
Maybe Double
Maybe MisoString
MisoString
cookieName :: Cookie -> MisoString
cookieValue :: Cookie -> Maybe MisoString
cookieDomain :: Cookie -> Maybe MisoString
cookiePath :: Cookie -> MisoString
cookieExpires :: Cookie -> Maybe Double
cookieSecure :: Cookie -> Bool
cookieSameSite :: Cookie -> MisoString
cookiePartitioned :: Cookie -> Bool
cookieName :: MisoString
cookieValue :: Maybe MisoString
cookieDomain :: Maybe MisoString
cookiePath :: MisoString
cookieExpires :: Maybe Double
cookieSecure :: Bool
cookieSameSite :: MisoString
cookiePartitioned :: Bool
..} = do
    o <- IO Object
create
    FFI.set "name"        cookieName        o
    FFI.set "value"       cookieValue       o
    FFI.set "path"        cookiePath        o
    FFI.set "secure"      cookieSecure      o
    FFI.set "sameSite"    cookieSameSite    o
    FFI.set "partitioned" cookiePartitioned o
    forM_ cookieDomain  $ \MisoString
d -> MisoString -> MisoString -> Object -> IO ()
forall v. ToJSVal v => MisoString -> v -> Object -> IO ()
FFI.set MisoString
"domain"  MisoString
d Object
o
    forM_ cookieExpires $ \Double
e -> MisoString -> Double -> Object -> IO ()
forall v. ToJSVal v => MisoString -> v -> Object -> IO ()
FFI.set MisoString
"expires" Double
e Object
o
    toJSVal o
  {-# INLINE toJSVal #-}
-----------------------------------------------------------------------------
instance FromJSVal Cookie where
  fromJSVal :: JSVal -> IO (Maybe Cookie)
fromJSVal JSVal
v = do
    name_        <- JSVal -> IO (Maybe MisoString)
forall a. FromJSVal a => JSVal -> IO (Maybe a)
fromJSVal (JSVal -> IO (Maybe MisoString))
-> IO JSVal -> IO (Maybe MisoString)
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< JSVal
v JSVal -> MisoString -> IO JSVal
forall o. ToObject o => o -> MisoString -> IO JSVal
! MisoString
"name"
    value_       <- fromJSVal =<< v ! "value"
    domain_      <- fromJSVal =<< v ! "domain"
    path_        <- fromJSVal =<< v ! "path"
    expires_     <- fromJSVal =<< v ! "expires"
    secure_      <- fromJSVal =<< v ! "secure"
    sameSite_    <- fromJSVal =<< v ! "sameSite"
    partitioned_ <- fromJSVal =<< v ! "partitioned"
    pure $ do
      n   <- name_
      vl  <- value_
      p   <- path_
      sec <- secure_
      ss  <- sameSite_
      par <- partitioned_
      pure Cookie
        { cookieName        = n
        , cookieValue       = vl
        , cookieDomain      = join domain_
        , cookiePath        = p
        , cookieExpires     = join expires_
        , cookieSecure      = sec
        , cookieSameSite    = ss
        , cookiePartitioned = par
        }
  {-# INLINE fromJSVal #-}
-----------------------------------------------------------------------------
-- | The event payload delivered to
-- <https://developer.mozilla.org/en-US/docs/Web/API/CookieStore/change_event cookieStore change>
-- listeners. Consumed by 'Miso.Subscription.Cookie.cookieChangeSub'.
data CookieChangeEvent = CookieChangeEvent
  { CookieChangeEvent -> [Cookie]
cookiesChanged :: [Cookie]
  -- ^ Cookies that were added or updated
  , CookieChangeEvent -> [Cookie]
cookiesDeleted :: [Cookie]
  -- ^ Cookies that were deleted
  } deriving (Int -> CookieChangeEvent -> ShowS
[CookieChangeEvent] -> ShowS
CookieChangeEvent -> String
(Int -> CookieChangeEvent -> ShowS)
-> (CookieChangeEvent -> String)
-> ([CookieChangeEvent] -> ShowS)
-> Show CookieChangeEvent
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> CookieChangeEvent -> ShowS
showsPrec :: Int -> CookieChangeEvent -> ShowS
$cshow :: CookieChangeEvent -> String
show :: CookieChangeEvent -> String
$cshowList :: [CookieChangeEvent] -> ShowS
showList :: [CookieChangeEvent] -> ShowS
Show, CookieChangeEvent -> CookieChangeEvent -> Bool
(CookieChangeEvent -> CookieChangeEvent -> Bool)
-> (CookieChangeEvent -> CookieChangeEvent -> Bool)
-> Eq CookieChangeEvent
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: CookieChangeEvent -> CookieChangeEvent -> Bool
== :: CookieChangeEvent -> CookieChangeEvent -> Bool
$c/= :: CookieChangeEvent -> CookieChangeEvent -> Bool
/= :: CookieChangeEvent -> CookieChangeEvent -> Bool
Eq)
-----------------------------------------------------------------------------
instance FromJSVal CookieChangeEvent where
  fromJSVal :: JSVal -> IO (Maybe CookieChangeEvent)
fromJSVal JSVal
ev = do
    changed_ <- JSVal -> IO (Maybe [Cookie])
forall a. FromJSVal a => JSVal -> IO a
fromJSValUnchecked (JSVal -> IO (Maybe [Cookie])) -> IO JSVal -> IO (Maybe [Cookie])
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< JSVal
ev JSVal -> MisoString -> IO JSVal
forall o. ToObject o => o -> MisoString -> IO JSVal
! MisoString
"changed"
    deleted_ <- fromJSValUnchecked =<< ev ! "deleted"
    pure (CookieChangeEvent <$> changed_ <*> deleted_)
  {-# INLINE fromJSVal #-}
-----------------------------------------------------------------------------
instance ToJSVal CookieChangeEvent where
  toJSVal :: CookieChangeEvent -> IO JSVal
toJSVal CookieChangeEvent {[Cookie]
cookiesChanged :: CookieChangeEvent -> [Cookie]
cookiesDeleted :: CookieChangeEvent -> [Cookie]
cookiesChanged :: [Cookie]
cookiesDeleted :: [Cookie]
..} = do
    o <- IO Object
create
    FFI.set "changed" cookiesChanged o
    FFI.set "deleted" cookiesDeleted o
    toJSVal o
  {-# INLINE toJSVal #-}
-----------------------------------------------------------------------------
instance ToArgs CookieChangeEvent where
  toArgs :: CookieChangeEvent -> IO [JSVal]
toArgs CookieChangeEvent
ev = (JSVal -> [JSVal] -> [JSVal]
forall a. a -> [a] -> [a]
:[]) (JSVal -> [JSVal]) -> IO JSVal -> IO [JSVal]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> CookieChangeEvent -> IO JSVal
forall a. ToJSVal a => a -> IO JSVal
toJSVal CookieChangeEvent
ev
  {-# INLINE toArgs #-}
-----------------------------------------------------------------------------
-- | Retrieve a cookie value by name.
--
-- Calls @successful@ with @'Just' value@ when found, @'Nothing'@ when
-- absent, or @errorful@ with the error message if the operation fails.
--
-- <https://developer.mozilla.org/en-US/docs/Web/API/CookieStore/get>
cookieGet
  :: MisoString
  -- ^ Cookie name
  -> (Maybe MisoString -> action)
  -- ^ Successful callback (@Nothing@ when the cookie is absent)
  -> (MisoString -> action)
  -- ^ Errorful callback
  -> Effect parent props model action
cookieGet :: forall action parent props model.
MisoString
-> (Maybe MisoString -> action)
-> (MisoString -> action)
-> Effect parent props model action
cookieGet MisoString
name Maybe MisoString -> action
successful MisoString -> action
errorful = (Sink action -> IO ()) -> Effect parent props model action
forall action parent props model.
(Sink action -> IO ()) -> Effect parent props model action
withSink ((Sink action -> IO ()) -> Effect parent props model action)
-> (Sink action -> IO ()) -> Effect parent props model action
forall a b. (a -> b) -> a -> b
$ \Sink action
sink ->
  MisoString -> (JSVal -> IO ()) -> (MisoString -> IO ()) -> IO ()
FFI.cookieGet MisoString
name
    (Sink action
sink Sink action
-> (Maybe MisoString -> action) -> Maybe MisoString -> IO ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Maybe MisoString -> action
successful (Maybe MisoString -> IO ())
-> (JSVal -> IO (Maybe MisoString)) -> JSVal -> IO ()
forall (m :: * -> *) b c a.
Monad m =>
(b -> m c) -> (a -> m b) -> a -> m c
<=< JSVal -> IO (Maybe MisoString)
forall a. FromJSVal a => JSVal -> IO (Maybe a)
fromJSVal)
    (Sink action
sink Sink action -> (MisoString -> action) -> MisoString -> IO ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. MisoString -> action
errorful)
-----------------------------------------------------------------------------
-- | Retrieve all cookies visible to the current document.
--
-- <https://developer.mozilla.org/en-US/docs/Web/API/CookieStore/getAll>
cookieGetAll
  :: ([Cookie] -> action)
  -- ^ Successful callback
  -> (MisoString -> action)
  -- ^ Errorful callback
  -> Effect parent props model action
cookieGetAll :: forall action parent props model.
([Cookie] -> action)
-> (MisoString -> action) -> Effect parent props model action
cookieGetAll [Cookie] -> action
successful MisoString -> action
errorful = (Sink action -> IO ()) -> Effect parent props model action
forall action parent props model.
(Sink action -> IO ()) -> Effect parent props model action
withSink ((Sink action -> IO ()) -> Effect parent props model action)
-> (Sink action -> IO ()) -> Effect parent props model action
forall a b. (a -> b) -> a -> b
$ \Sink action
sink -> do
  (JSVal -> IO ()) -> (MisoString -> IO ()) -> IO ()
FFI.cookieGetAll
    (Sink action
sink Sink action -> ([Cookie] -> action) -> [Cookie] -> IO ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Cookie] -> action
successful ([Cookie] -> IO ()) -> (JSVal -> IO [Cookie]) -> JSVal -> IO ()
forall (m :: * -> *) b c a.
Monad m =>
(b -> m c) -> (a -> m b) -> a -> m c
<=< JSVal -> IO [Cookie]
forall a. FromJSVal a => JSVal -> IO a
fromJSValUnchecked)
    (Sink action
sink Sink action -> (MisoString -> action) -> MisoString -> IO ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. MisoString -> action
errorful)
-----------------------------------------------------------------------------
-- | A 'Cookie' with sensible defaults: @path = "/"@, session expiry,
-- @SameSite = "lax"@, not secure, not partitioned, no domain restriction.
defaultCookie :: MisoString -> MisoString -> Cookie
defaultCookie :: MisoString -> MisoString -> Cookie
defaultCookie MisoString
name MisoString
value = Cookie
  { cookieName :: MisoString
cookieName        = MisoString
name
  , cookieValue :: Maybe MisoString
cookieValue       = MisoString -> Maybe MisoString
forall a. a -> Maybe a
Just MisoString
value
  , cookieDomain :: Maybe MisoString
cookieDomain      = Maybe MisoString
forall a. Maybe a
Nothing
  , cookiePath :: MisoString
cookiePath        = MisoString
"/"
  , cookieExpires :: Maybe Double
cookieExpires     = Maybe Double
forall a. Maybe a
Nothing
  , cookieSecure :: Bool
cookieSecure      = Bool
False
  , cookieSameSite :: MisoString
cookieSameSite    = MisoString
"lax"
  , cookiePartitioned :: Bool
cookiePartitioned = Bool
False
  }
-----------------------------------------------------------------------------
-- | Set a cookie via the
-- <https://developer.mozilla.org/en-US/docs/Web/API/CookieStore CookieStore API>.
--
-- Use 'defaultCookie' to construct a 'Cookie' with sensible defaults, or
-- supply a fully specified 'Cookie' record for custom path, domain, expiry etc.
--
-- __Important:__ You cannot use both @expires@ and @maxAge@ in the same call.
-- If you do, the @set()@ method will fail with a @TypeError@.
--
-- <https://developer.mozilla.org/en-US/docs/Web/API/CookieStore/set>
cookieSet
  :: Cookie
  -- ^ Cookie to set (use 'defaultCookie' for the common case)
  -> action
  -- ^ Successful callback
  -> (MisoString -> action)
  -- ^ Errorful callback
  -> Effect parent props model action
cookieSet :: forall action parent props model.
Cookie
-> action
-> (MisoString -> action)
-> Effect parent props model action
cookieSet Cookie
cookie action
successful MisoString -> action
errorful = (Sink action -> IO ()) -> Effect parent props model action
forall action parent props model.
(Sink action -> IO ()) -> Effect parent props model action
withSink ((Sink action -> IO ()) -> Effect parent props model action)
-> (Sink action -> IO ()) -> Effect parent props model action
forall a b. (a -> b) -> a -> b
$ \Sink action
sink -> do
  c_ <- Cookie -> IO JSVal
forall a. ToJSVal a => a -> IO JSVal
toJSVal Cookie
cookie
  FFI.cookieSet c_ (sink successful) (sink . errorful)
-----------------------------------------------------------------------------
-- | Delete a cookie by name.
--
-- <https://developer.mozilla.org/en-US/docs/Web/API/CookieStore/delete>
cookieDelete
  :: MisoString
  -- ^ Cookie name
  -> action
  -- ^ Successful callback
  -> (MisoString -> action)
  -- ^ Errorful callback
  -> Effect parent props model action
cookieDelete :: forall action parent props model.
MisoString
-> action
-> (MisoString -> action)
-> Effect parent props model action
cookieDelete MisoString
name action
successful MisoString -> action
errorful = (Sink action -> IO ()) -> Effect parent props model action
forall action parent props model.
(Sink action -> IO ()) -> Effect parent props model action
withSink ((Sink action -> IO ()) -> Effect parent props model action)
-> (Sink action -> IO ()) -> Effect parent props model action
forall a b. (a -> b) -> a -> b
$ \Sink action
sink ->
  MisoString -> IO () -> (MisoString -> IO ()) -> IO ()
FFI.cookieDelete MisoString
name (Sink action
sink action
successful) (Sink action
sink Sink action -> (MisoString -> action) -> MisoString -> IO ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. MisoString -> action
errorful)
-----------------------------------------------------------------------------
-- | Delete a cookie by matching on name, path, domain, and\/or partitioned
-- flag — useful when multiple cookies share the same name across different
-- paths or domains.
--
-- Use 'defaultCookie' to build the argument and override only the fields
-- you need:
--
-- @
-- 'cookieDeleteWith' ('defaultCookie' \"session\" \"\") { 'cookiePath' = \"\/admin\" }
--   Deleted
--   SessionError
-- @
--
-- <https://developer.mozilla.org/en-US/docs/Web/API/CookieStore/delete>
cookieDeleteWith
  :: Cookie
  -- ^ Cookie whose name, path, domain and partitioned fields are used for matching
  -> action
  -- ^ Successful callback
  -> (MisoString -> action)
  -- ^ Errorful callback
  -> Effect parent props model action
cookieDeleteWith :: forall action parent props model.
Cookie
-> action
-> (MisoString -> action)
-> Effect parent props model action
cookieDeleteWith Cookie
cookie action
successful MisoString -> action
errorful = (Sink action -> IO ()) -> Effect parent props model action
forall action parent props model.
(Sink action -> IO ()) -> Effect parent props model action
withSink ((Sink action -> IO ()) -> Effect parent props model action)
-> (Sink action -> IO ()) -> Effect parent props model action
forall a b. (a -> b) -> a -> b
$ \Sink action
sink -> do
  c_ <- Cookie -> IO JSVal
forall a. ToJSVal a => a -> IO JSVal
toJSVal Cookie
cookie
  FFI.cookieDeleteWith c_ (sink successful) (sink . errorful)
-----------------------------------------------------------------------------
-- | Synchronous API variant of 'cookieSet'.
--
-- Blocks the calling thread until the browser resolves the promise, returning
-- @'Right' ()@ on success or @'Left' err@ on failure.
--
-- __Note:__ best used with 'Miso.Effect.io' or 'Miso.Effect.io_', to avoid blocking the scheduler thread.
cookieSet_ :: Cookie -> IO (Either MisoString ())
cookieSet_ :: Cookie -> IO (Either MisoString ())
cookieSet_ Cookie
cookie = do
  mvar <- IO (MVar (Either MisoString ()))
forall a. IO (MVar a)
newEmptyMVar :: IO (MVar (Either MisoString ()))
  c_ <- toJSVal cookie
  FFI.cookieSet c_
    (putMVar mvar (Right ()))
    (\MisoString
e -> MVar (Either MisoString ()) -> Either MisoString () -> IO ()
forall a. MVar a -> a -> IO ()
putMVar MVar (Either MisoString ())
mvar (MisoString -> Either MisoString ()
forall a b. a -> Either a b
Left MisoString
e))
  takeMVar mvar
{-# INLINE cookieSet_ #-}
-----------------------------------------------------------------------------
-- | Synchronous API variant of 'cookieGet'.
--
-- Blocks the calling thread until the browser resolves the promise, returning
-- @'Right' ('Just' value)@ when the cookie exists, @'Right' 'Nothing'@
-- when absent, or @'Left' err@ on failure.
--
-- __Note:__ best used with 'Miso.Effect.io' or 'Miso.Effect.io_', to avoid blocking the scheduler thread.
cookieGet_ :: MisoString -> IO (Either MisoString (Maybe MisoString))
cookieGet_ :: MisoString -> IO (Either MisoString (Maybe MisoString))
cookieGet_ MisoString
name = do
  mvar <- IO (MVar (Either MisoString (Maybe MisoString)))
forall a. IO (MVar a)
newEmptyMVar :: IO (MVar (Either MisoString (Maybe MisoString)))
  FFI.cookieGet name
    (\JSVal
v -> JSVal -> IO (Maybe MisoString)
forall a. FromJSVal a => JSVal -> IO a
fromJSValUnchecked JSVal
v IO (Maybe MisoString) -> (Maybe MisoString -> IO ()) -> IO ()
forall a b. IO a -> (a -> IO b) -> IO b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= MVar (Either MisoString (Maybe MisoString))
-> Either MisoString (Maybe MisoString) -> IO ()
forall a. MVar a -> a -> IO ()
putMVar MVar (Either MisoString (Maybe MisoString))
mvar (Either MisoString (Maybe MisoString) -> IO ())
-> (Maybe MisoString -> Either MisoString (Maybe MisoString))
-> Maybe MisoString
-> IO ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Maybe MisoString -> Either MisoString (Maybe MisoString)
forall a b. b -> Either a b
Right)
    (\MisoString
e -> MVar (Either MisoString (Maybe MisoString))
-> Either MisoString (Maybe MisoString) -> IO ()
forall a. MVar a -> a -> IO ()
putMVar MVar (Either MisoString (Maybe MisoString))
mvar (MisoString -> Either MisoString (Maybe MisoString)
forall a b. a -> Either a b
Left MisoString
e))
  takeMVar mvar
{-# INLINE cookieGet_ #-}
-----------------------------------------------------------------------------
-- | Synchronous API variant of 'cookieDelete'.
--
-- Blocks the calling thread until the browser resolves the promise, returning
-- @'Right' ()@ on success or @'Left' err@ on failure.
--
-- __Note:__ best used with 'Miso.Effect.io' or 'Miso.Effect.io_', to avoid blocking the scheduler thread.
cookieDelete_ :: MisoString -> IO (Either MisoString ())
cookieDelete_ :: MisoString -> IO (Either MisoString ())
cookieDelete_ MisoString
name = do
  mvar <- IO (MVar (Either MisoString ()))
forall a. IO (MVar a)
newEmptyMVar :: IO (MVar (Either MisoString ()))
  FFI.cookieDelete name
    (putMVar mvar (Right ()))
    (\MisoString
e -> MVar (Either MisoString ()) -> Either MisoString () -> IO ()
forall a. MVar a -> a -> IO ()
putMVar MVar (Either MisoString ())
mvar (MisoString -> Either MisoString ()
forall a b. a -> Either a b
Left MisoString
e))
  takeMVar mvar
{-# INLINE cookieDelete_ #-}
-----------------------------------------------------------------------------
-- | Synchronous API variant of 'cookieDeleteWith'.
--
-- Blocks the calling thread until the browser resolves the promise, returning
-- @'Right' ()@ on success or @'Left' err@ on failure.
--
-- __Note:__ best used with 'Miso.Effect.io' or 'Miso.Effect.io_', to avoid blocking the scheduler thread.
cookieDeleteWith_ :: Cookie -> IO (Either MisoString ())
cookieDeleteWith_ :: Cookie -> IO (Either MisoString ())
cookieDeleteWith_ Cookie
cookie = do
  mvar <- IO (MVar (Either MisoString ()))
forall a. IO (MVar a)
newEmptyMVar :: IO (MVar (Either MisoString ()))
  c_ <- toJSVal cookie
  FFI.cookieDeleteWith c_
    (putMVar mvar (Right ()))
    (\MisoString
e -> MVar (Either MisoString ()) -> Either MisoString () -> IO ()
forall a. MVar a -> a -> IO ()
putMVar MVar (Either MisoString ())
mvar (MisoString -> Either MisoString ()
forall a b. a -> Either a b
Left MisoString
e))
  takeMVar mvar
{-# INLINE cookieDeleteWith_ #-}
-----------------------------------------------------------------------------
-- | Synchronous API variant of 'cookieGetAll'.
--
-- Blocks the calling thread until the browser resolves the promise, returning
-- @'Right' cookies@ on success or @'Left' err@ on failure.
--
-- __Note:__ best used with 'Miso.Effect.io' or 'Miso.Effect.io_', to avoid blocking the scheduler thread.
cookieGetAll_ :: IO (Either MisoString [Cookie])
cookieGetAll_ :: IO (Either MisoString [Cookie])
cookieGetAll_ = do
  mvar <- IO (MVar (Either MisoString [Cookie]))
forall a. IO (MVar a)
newEmptyMVar :: IO (MVar (Either MisoString [Cookie]))
  FFI.cookieGetAll
    (\JSVal
v -> JSVal -> IO [Cookie]
forall a. FromJSVal a => JSVal -> IO a
fromJSValUnchecked JSVal
v IO [Cookie] -> ([Cookie] -> IO ()) -> IO ()
forall a b. IO a -> (a -> IO b) -> IO b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= MVar (Either MisoString [Cookie])
-> Either MisoString [Cookie] -> IO ()
forall a. MVar a -> a -> IO ()
putMVar MVar (Either MisoString [Cookie])
mvar (Either MisoString [Cookie] -> IO ())
-> ([Cookie] -> Either MisoString [Cookie]) -> [Cookie] -> IO ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Cookie] -> Either MisoString [Cookie]
forall a b. b -> Either a b
Right)
    (\MisoString
e -> MVar (Either MisoString [Cookie])
-> Either MisoString [Cookie] -> IO ()
forall a. MVar a -> a -> IO ()
putMVar MVar (Either MisoString [Cookie])
mvar (MisoString -> Either MisoString [Cookie]
forall a b. a -> Either a b
Left MisoString
e))
  takeMVar mvar
{-# INLINE cookieGetAll_ #-}
-----------------------------------------------------------------------------