{-# LANGUAGE CPP #-}
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE ExistentialQuantification #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE UndecidableInstances #-}

module Web.Spock.Internal.Types where

#if MIN_VERSION_base(4,8,0)
#else
import Control.Applicative
#endif
import Control.Monad.Base
import Control.Exception (Exception)
import Control.Monad.Reader
import Control.Monad.Trans.Control
import Control.Monad.Trans.Resource
import qualified Data.HashMap.Strict as HM
import qualified Data.ByteString as BS
import qualified Data.Vault.Lazy as V
import Data.Pool
import qualified Data.Text as T
import Data.Time.Clock (NominalDiffTime, UTCTime (..))
import Data.Word
import Network.HTTP.Types.Status
import Network.Wai
import Web.Spock.Core

-- | Inside the SpockAllM monad, you may define routes and middleware.
type SpockAllM conn sess st a = SpockT (WebStateM conn sess st) a

-- | A per-request action with typed context @ctx@, database connection @conn@,
-- session value @sess@, and shared application state @st@. The final type
-- parameter is the action's result. Use @getContext@ for the value supplied by
-- a prehook, 'getState' for shared state, and session actions for this visitor.
--
-- This is 'ActionCtxT' over 'WebStateM'. @lift helper@ enters 'WebStateM';
-- @liftIO operation@ runs IO. Sending a response finishes the action even
-- though response helpers have a polymorphic result type.
type SpockActionCtx ctx conn sess st = ActionCtxT ctx (WebStateM conn sess st)

-- | A per-request 'SpockActionCtx' with context @()@. This is the usual handler
-- type outside a prehook. Its @conn@, @sess@, and @st@ parameters have the same
-- meanings as in the application's route-registration type.
type SpockAction conn sess st = SpockActionCtx () conn sess st

-- | Spock configuration, use 'defaultSpockCfg' and change single values if needed
data SpockCfg conn sess st = SpockCfg
  { -- | initial application global state
    forall conn sess st. SpockCfg conn sess st -> st
spc_initialState :: st,
    -- | See 'PoolOrConn'
    forall conn sess st. SpockCfg conn sess st -> PoolOrConn conn
spc_database :: PoolOrConn conn,
    -- | See 'SessionCfg'
    forall conn sess st.
SpockCfg conn sess st -> SessionCfg conn sess st
spc_sessionCfg :: SessionCfg conn sess st,
    -- | Maximum request size in bytes. 'Nothing' means no limit. Defaults to 5 MB in @defaultSpockCfg@.
    forall conn sess st. SpockCfg conn sess st -> Maybe Word64
spc_maxRequestSize :: Maybe Word64,
    -- | Custom error handlers for implicit errors such as not matching routes or
    -- exceptions during a request handler run.
    forall conn sess st.
SpockCfg conn sess st -> Status -> ActionCtxT () IO ()
spc_errorHandler :: Status -> ActionCtxT () IO (),
    -- | Function that should be called to log errors.
    forall conn sess st. SpockCfg conn sess st -> Text -> IO ()
spc_logError :: T.Text -> IO (),
    -- | Optional request IDs and structured handler/access/error logging.
    forall conn sess st. SpockCfg conn sess st -> Maybe LoggingConfig
spc_logging :: Maybe LoggingConfig,
    -- | Slash matching and optional 308 canonical redirects. Defaults to
    -- 'IgnoreSlashes'; set 'StrictSlashes' to distinguish @/foo@ and @/foo/@.
    forall conn sess st. SpockCfg conn sess st -> SlashPolicy
spc_slashPolicy :: SlashPolicy,
    -- | When set to true, all non GET request will require
    -- either an HTTP-Header 'spc_csrfHeaderName' or a
    -- POST-Parameter 'spc_csrfPostName' to be set to the value aquired by 'getCsrfToken'
    forall conn sess st. SpockCfg conn sess st -> Bool
spc_csrfProtection :: Bool,
    -- | see 'spc_csrfHeaderName'
    forall conn sess st. SpockCfg conn sess st -> Text
spc_csrfHeaderName :: T.Text,
    -- | see 'spc_csrfPostName'
    forall conn sess st. SpockCfg conn sess st -> Text
spc_csrfPostName :: T.Text
  }

-- | If Spock should take care of connection pooling, you need to configure
-- it depending on what you need.
data PoolCfg = PoolCfg
  { PoolCfg -> Int
pc_stripes :: Int,
    PoolCfg -> Int
pc_resPerStripe :: Int,
    PoolCfg -> NominalDiffTime
pc_keepOpenTime :: NominalDiffTime
  }

-- | The ConnBuilder instructs Spock how to create or close a database connection.
data ConnBuilder a = ConnBuilder
  { forall a. ConnBuilder a -> IO a
cb_createConn :: IO a,
    forall a. ConnBuilder a -> a -> IO ()
cb_destroyConn :: a -> IO (),
    forall a. ConnBuilder a -> PoolCfg
cb_poolConfiguration :: PoolCfg
  }

-- | You can feed Spock with either a connection pool, or instructions on how to build
-- a connection pool. See 'ConnBuilder'
data PoolOrConn a where
  PCPool :: Pool a -> PoolOrConn a
  PCConn :: ConnBuilder a -> PoolOrConn a
  PCNoDatabase :: PoolOrConn ()

-- | Configuration for the session manager
data SessionCfg conn a st = SessionCfg
  { -- | When to load or create a session. Defaults to 'SessionsOnDemand'.
    forall conn a st. SessionCfg conn a st -> SessionMode
sc_sessionMode :: SessionMode,
    -- | name of the client side cookie
    forall conn a st. SessionCfg conn a st -> Text
sc_cookieName :: T.Text,
    -- | how long the client side cookie should live
    forall conn a st. SessionCfg conn a st -> CookieSettings
sc_cookieSettings :: CookieSettings,
    -- | how long shoud a client session live
    forall conn a st. SessionCfg conn a st -> NominalDiffTime
sc_sessionTTL :: NominalDiffTime,
    -- | entropy of the session id sent to the client
    forall conn a st. SessionCfg conn a st -> Int
sc_sessionIdEntropy :: Int,
    -- | if this is true, every page reload will renew the session time to live counter
    forall conn a st. SessionCfg conn a st -> Bool
sc_sessionExpandTTL :: Bool,
    -- | initial session for visitors
    forall conn a st. SessionCfg conn a st -> a
sc_emptySession :: a,
    -- | Server storage or an authenticated client-cookie codec. Client sessions
    -- do not have server-wide mapping, deletion, or housekeeping capabilities.
    forall conn a st. SessionCfg conn a st -> SessionBackend conn a st
sc_backend :: SessionBackend conn a st
  }

-- | Select storage separately from the shared lifetime, cookie and mode options.
data SessionBackend conn sess st
  = ServerSessions (ServerSessionCfg conn sess st)
  | ClientSessions (ClientSessionCfg sess)

-- | Store, sweep interval and removal hooks used only by server backends.
-- Customize the value returned by @defaultServerSessionCfg@.
data ServerSessionCfg conn sess st = ServerSessionCfg
  { forall conn sess st.
ServerSessionCfg conn sess st
-> SessionStoreInstance (Session conn sess st)
ssc_store :: SessionStoreInstance (Session conn sess st),
    forall conn sess st.
ServerSessionCfg conn sess st -> NominalDiffTime
ssc_housekeepingInterval :: NominalDiffTime,
    forall conn sess st.
ServerSessionCfg conn sess st -> SessionHooks sess
ssc_hooks :: SessionHooks sess
  }

-- | Trusted codec interface for backend packages. Encode must authenticate and
-- encrypt the complete session, bound to the supplied cookie name. Decode must
-- authenticate before returning data, and return Nothing for untrusted input.
-- The Bool asks the manager to reissue a cookie after key or format rotation.
data ClientSessionCodec sess = ClientSessionCodec
  { forall sess.
ClientSessionCodec sess
-> forall conn st. Text -> Session conn sess st -> IO ByteString
csc_encode :: forall conn st. T.Text -> Session conn sess st -> IO BS.ByteString,
    forall sess.
ClientSessionCodec sess
-> forall conn st.
   Text -> ByteString -> IO (Maybe (Session conn sess st, Bool))
csc_decode :: forall conn st. T.Text -> BS.ByteString -> IO (Maybe (Session conn sess st, Bool))
  }

-- | Cookie backend settings. Use a maintained authenticated codec such as
-- @Spock-session-cookie@; plain JSON or unauthenticated encryption is unsafe.
data ClientSessionCfg sess = ClientSessionCfg
  { forall sess. ClientSessionCfg sess -> ClientSessionCodec sess
csc_codec :: ClientSessionCodec sess,
    -- | Limit for the complete Set-Cookie value, including name and attributes.
    -- Must be between 1 and 4096. Oversized writes fail before changing state.
    forall sess. ClientSessionCfg sess -> Int
csc_maxCookieBytes :: Int,
    -- | Server clock. Defaults to getCurrentTime; replace in deterministic tests.
    forall sess. ClientSessionCfg sess -> IO UTCTime
csc_clock :: IO UTCTime
  }

-- | On-demand sessions are loaded only by session actions (including CSRF
-- checks). Disabled sessions leave database pooling and application state usable.
data SessionMode = SessionsAlways | SessionsOnDemand | SessionsDisabled
  deriving (SessionMode -> SessionMode -> Bool
(SessionMode -> SessionMode -> Bool)
-> (SessionMode -> SessionMode -> Bool) -> Eq SessionMode
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: SessionMode -> SessionMode -> Bool
== :: SessionMode -> SessionMode -> Bool
$c/= :: SessionMode -> SessionMode -> Bool
/= :: SessionMode -> SessionMode -> Bool
Eq, Int -> SessionMode -> ShowS
[SessionMode] -> ShowS
SessionMode -> String
(Int -> SessionMode -> ShowS)
-> (SessionMode -> String)
-> ([SessionMode] -> ShowS)
-> Show SessionMode
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> SessionMode -> ShowS
showsPrec :: Int -> SessionMode -> ShowS
$cshow :: SessionMode -> String
show :: SessionMode -> String
$cshowList :: [SessionMode] -> ShowS
showList :: [SessionMode] -> ShowS
Show)

-- | Invalid session configuration, unavailable capabilities or rejected writes.
data SessionError = SessionUseWhenDisabled | CsrfRequiresSessions
  | ServerSessionsRequired | ClientSessionOutsideRequest
  | ClientSessionCookieTooLarge | InvalidClientSessionConfig
  deriving (SessionError -> SessionError -> Bool
(SessionError -> SessionError -> Bool)
-> (SessionError -> SessionError -> Bool) -> Eq SessionError
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: SessionError -> SessionError -> Bool
== :: SessionError -> SessionError -> Bool
$c/= :: SessionError -> SessionError -> Bool
/= :: SessionError -> SessionError -> Bool
Eq, Int -> SessionError -> ShowS
[SessionError] -> ShowS
SessionError -> String
(Int -> SessionError -> ShowS)
-> (SessionError -> String)
-> ([SessionError] -> ShowS)
-> Show SessionError
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> SessionError -> ShowS
showsPrec :: Int -> SessionError -> ShowS
$cshow :: SessionError -> String
show :: SessionError -> String
$cshowList :: [SessionError] -> ShowS
showList :: [SessionError] -> ShowS
Show)

instance Exception SessionError

-- | Hook into the session manager to trigger custom behavior
data SessionHooks a = SessionHooks
  { forall a. SessionHooks a -> HashMap Text a -> IO ()
sh_removed :: HM.HashMap SessionId a -> IO ()
  }

-- | The application environment: connection pool, session manager,
-- configuration, and shared state. It does not contain a particular request.
data WebState conn sess st = WebState
  { forall conn sess st. WebState conn sess st -> Pool conn
web_dbConn :: Pool conn,
    forall conn sess st.
WebState conn sess st -> SpockSessionManager conn sess st
web_sessionMgr :: SpockSessionManager conn sess st,
    forall conn sess st. WebState conn sess st -> st
web_state :: st,
    forall conn sess st. WebState conn sess st -> SpockCfg conn sess st
web_config :: SpockCfg conn sess st
  }

-- | Access application services in 'WebStateM' and Spock's registration/action
-- layers. Helpers polymorphic in this class can use 'getState' and 'runQuery'
-- without committing to either of those layers.
class HasSpock m where
  type SpockConn m :: *
  type SpockState m :: *
  type SpockSession m :: *

  -- | Give you access to a database connectin from the connection pool. The connection is
  -- released back to the pool once the function terminates.
  runQuery :: (SpockConn m -> IO a) -> m a

  -- | Read the application's state. If you wish to have mutable state, you could
  -- use a 'TVar' from the STM packge.
  getState :: m (SpockState m)

  -- | Get the session manager
  getSessMgr :: m (SpockSessionManager (SpockConn m) (SpockSession m) (SpockState m))

  -- | Get the Spock configuration
  getSpockCfg :: m (SpockCfg (SpockConn m) (SpockSession m) (SpockState m))

-- | Add the application's 'WebState' environment to an underlying monad @m@.
-- @conn@, @sess@, and @st@ select the connection, session value, and shared state
-- types; @a@ is the computation's result. This is a reader of an existing
-- environment, not a mutable state transformer. Put an @IORef@ or @TVar@ in
-- @st@ when shared state needs to change, with suitable synchronization.
--
-- Applications normally use 'WebStateM', the resource-managed IO specialization.
newtype WebStateT conn sess st m a = WebStateT {forall conn sess st (m :: * -> *) a.
WebStateT conn sess st m a -> ReaderT (WebState conn sess st) m a
runWebStateT :: ReaderT (WebState conn sess st) m a}
  deriving
    ( Applicative (WebStateT conn sess st m)
Applicative (WebStateT conn sess st m) =>
(forall a b.
 WebStateT conn sess st m a
 -> (a -> WebStateT conn sess st m b) -> WebStateT conn sess st m b)
-> (forall a b.
    WebStateT conn sess st m a
    -> WebStateT conn sess st m b -> WebStateT conn sess st m b)
-> (forall a. a -> WebStateT conn sess st m a)
-> Monad (WebStateT conn sess st m)
forall a. a -> WebStateT conn sess st m a
forall a b.
WebStateT conn sess st m a
-> WebStateT conn sess st m b -> WebStateT conn sess st m b
forall a b.
WebStateT conn sess st m a
-> (a -> WebStateT conn sess st m b) -> WebStateT conn sess st m b
forall conn sess st (m :: * -> *).
Monad m =>
Applicative (WebStateT conn sess st m)
forall conn sess st (m :: * -> *) a.
Monad m =>
a -> WebStateT conn sess st m a
forall conn sess st (m :: * -> *) a b.
Monad m =>
WebStateT conn sess st m a
-> WebStateT conn sess st m b -> WebStateT conn sess st m b
forall conn sess st (m :: * -> *) a b.
Monad m =>
WebStateT conn sess st m a
-> (a -> WebStateT conn sess st m b) -> WebStateT conn sess st m b
forall (m :: * -> *).
Applicative m =>
(forall a b. m a -> (a -> m b) -> m b)
-> (forall a b. m a -> m b -> m b)
-> (forall a. a -> m a)
-> Monad m
$c>>= :: forall conn sess st (m :: * -> *) a b.
Monad m =>
WebStateT conn sess st m a
-> (a -> WebStateT conn sess st m b) -> WebStateT conn sess st m b
>>= :: forall a b.
WebStateT conn sess st m a
-> (a -> WebStateT conn sess st m b) -> WebStateT conn sess st m b
$c>> :: forall conn sess st (m :: * -> *) a b.
Monad m =>
WebStateT conn sess st m a
-> WebStateT conn sess st m b -> WebStateT conn sess st m b
>> :: forall a b.
WebStateT conn sess st m a
-> WebStateT conn sess st m b -> WebStateT conn sess st m b
$creturn :: forall conn sess st (m :: * -> *) a.
Monad m =>
a -> WebStateT conn sess st m a
return :: forall a. a -> WebStateT conn sess st m a
Monad,
      (forall a b.
 (a -> b)
 -> WebStateT conn sess st m a -> WebStateT conn sess st m b)
-> (forall a b.
    a -> WebStateT conn sess st m b -> WebStateT conn sess st m a)
-> Functor (WebStateT conn sess st m)
forall a b.
a -> WebStateT conn sess st m b -> WebStateT conn sess st m a
forall a b.
(a -> b)
-> WebStateT conn sess st m a -> WebStateT conn sess st m b
forall conn sess st (m :: * -> *) a b.
Functor m =>
a -> WebStateT conn sess st m b -> WebStateT conn sess st m a
forall conn sess st (m :: * -> *) a b.
Functor m =>
(a -> b)
-> WebStateT conn sess st m a -> WebStateT conn sess st m b
forall (f :: * -> *).
(forall a b. (a -> b) -> f a -> f b)
-> (forall a b. a -> f b -> f a) -> Functor f
$cfmap :: forall conn sess st (m :: * -> *) a b.
Functor m =>
(a -> b)
-> WebStateT conn sess st m a -> WebStateT conn sess st m b
fmap :: forall a b.
(a -> b)
-> WebStateT conn sess st m a -> WebStateT conn sess st m b
$c<$ :: forall conn sess st (m :: * -> *) a b.
Functor m =>
a -> WebStateT conn sess st m b -> WebStateT conn sess st m a
<$ :: forall a b.
a -> WebStateT conn sess st m b -> WebStateT conn sess st m a
Functor,
      Functor (WebStateT conn sess st m)
Functor (WebStateT conn sess st m) =>
(forall a. a -> WebStateT conn sess st m a)
-> (forall a b.
    WebStateT conn sess st m (a -> b)
    -> WebStateT conn sess st m a -> WebStateT conn sess st m b)
-> (forall a b c.
    (a -> b -> c)
    -> WebStateT conn sess st m a
    -> WebStateT conn sess st m b
    -> WebStateT conn sess st m c)
-> (forall a b.
    WebStateT conn sess st m a
    -> WebStateT conn sess st m b -> WebStateT conn sess st m b)
-> (forall a b.
    WebStateT conn sess st m a
    -> WebStateT conn sess st m b -> WebStateT conn sess st m a)
-> Applicative (WebStateT conn sess st m)
forall a. a -> WebStateT conn sess st m a
forall a b.
WebStateT conn sess st m a
-> WebStateT conn sess st m b -> WebStateT conn sess st m a
forall a b.
WebStateT conn sess st m a
-> WebStateT conn sess st m b -> WebStateT conn sess st m b
forall a b.
WebStateT conn sess st m (a -> b)
-> WebStateT conn sess st m a -> WebStateT conn sess st m b
forall a b c.
(a -> b -> c)
-> WebStateT conn sess st m a
-> WebStateT conn sess st m b
-> WebStateT conn sess st m c
forall conn sess st (m :: * -> *).
Applicative m =>
Functor (WebStateT conn sess st m)
forall conn sess st (m :: * -> *) a.
Applicative m =>
a -> WebStateT conn sess st m a
forall conn sess st (m :: * -> *) a b.
Applicative m =>
WebStateT conn sess st m a
-> WebStateT conn sess st m b -> WebStateT conn sess st m a
forall conn sess st (m :: * -> *) a b.
Applicative m =>
WebStateT conn sess st m a
-> WebStateT conn sess st m b -> WebStateT conn sess st m b
forall conn sess st (m :: * -> *) a b.
Applicative m =>
WebStateT conn sess st m (a -> b)
-> WebStateT conn sess st m a -> WebStateT conn sess st m b
forall conn sess st (m :: * -> *) a b c.
Applicative m =>
(a -> b -> c)
-> WebStateT conn sess st m a
-> WebStateT conn sess st m b
-> WebStateT conn sess st m c
forall (f :: * -> *).
Functor f =>
(forall a. a -> f a)
-> (forall a b. f (a -> b) -> f a -> f b)
-> (forall a b c. (a -> b -> c) -> f a -> f b -> f c)
-> (forall a b. f a -> f b -> f b)
-> (forall a b. f a -> f b -> f a)
-> Applicative f
$cpure :: forall conn sess st (m :: * -> *) a.
Applicative m =>
a -> WebStateT conn sess st m a
pure :: forall a. a -> WebStateT conn sess st m a
$c<*> :: forall conn sess st (m :: * -> *) a b.
Applicative m =>
WebStateT conn sess st m (a -> b)
-> WebStateT conn sess st m a -> WebStateT conn sess st m b
<*> :: forall a b.
WebStateT conn sess st m (a -> b)
-> WebStateT conn sess st m a -> WebStateT conn sess st m b
$cliftA2 :: forall conn sess st (m :: * -> *) a b c.
Applicative m =>
(a -> b -> c)
-> WebStateT conn sess st m a
-> WebStateT conn sess st m b
-> WebStateT conn sess st m c
liftA2 :: forall a b c.
(a -> b -> c)
-> WebStateT conn sess st m a
-> WebStateT conn sess st m b
-> WebStateT conn sess st m c
$c*> :: forall conn sess st (m :: * -> *) a b.
Applicative m =>
WebStateT conn sess st m a
-> WebStateT conn sess st m b -> WebStateT conn sess st m b
*> :: forall a b.
WebStateT conn sess st m a
-> WebStateT conn sess st m b -> WebStateT conn sess st m b
$c<* :: forall conn sess st (m :: * -> *) a b.
Applicative m =>
WebStateT conn sess st m a
-> WebStateT conn sess st m b -> WebStateT conn sess st m a
<* :: forall a b.
WebStateT conn sess st m a
-> WebStateT conn sess st m b -> WebStateT conn sess st m a
Applicative,
      Monad (WebStateT conn sess st m)
Monad (WebStateT conn sess st m) =>
(forall a. IO a -> WebStateT conn sess st m a)
-> MonadIO (WebStateT conn sess st m)
forall a. IO a -> WebStateT conn sess st m a
forall conn sess st (m :: * -> *).
MonadIO m =>
Monad (WebStateT conn sess st m)
forall conn sess st (m :: * -> *) a.
MonadIO m =>
IO a -> WebStateT conn sess st m a
forall (m :: * -> *).
Monad m =>
(forall a. IO a -> m a) -> MonadIO m
$cliftIO :: forall conn sess st (m :: * -> *) a.
MonadIO m =>
IO a -> WebStateT conn sess st m a
liftIO :: forall a. IO a -> WebStateT conn sess st m a
MonadIO,
      MonadReader (WebState conn sess st),
      (forall (m :: * -> *).
 Monad m =>
 Monad (WebStateT conn sess st m)) =>
(forall (m :: * -> *) a.
 Monad m =>
 m a -> WebStateT conn sess st m a)
-> MonadTrans (WebStateT conn sess st)
forall conn sess st (m :: * -> *).
Monad m =>
Monad (WebStateT conn sess st m)
forall conn sess st (m :: * -> *) a.
Monad m =>
m a -> WebStateT conn sess st m a
forall (m :: * -> *). Monad m => Monad (WebStateT conn sess st m)
forall (m :: * -> *) a.
Monad m =>
m a -> WebStateT conn sess st m a
forall (t :: (* -> *) -> * -> *).
(forall (m :: * -> *). Monad m => Monad (t m)) =>
(forall (m :: * -> *) a. Monad m => m a -> t m a) -> MonadTrans t
$clift :: forall conn sess st (m :: * -> *) a.
Monad m =>
m a -> WebStateT conn sess st m a
lift :: forall (m :: * -> *) a.
Monad m =>
m a -> WebStateT conn sess st m a
MonadTrans
    )

instance MonadBase b m => MonadBase b (WebStateT conn sess st m) where
  liftBase :: forall α. b α -> WebStateT conn sess st m α
liftBase = b α -> WebStateT conn sess st m α
forall (t :: (* -> *) -> * -> *) (b :: * -> *) (m :: * -> *) α.
(MonadTrans t, MonadBase b m) =>
b α -> t m α
liftBaseDefault

instance MonadTransControl (WebStateT conn sess st) where
  type StT (WebStateT conn sess st) a = a
  liftWith :: forall (m :: * -> *) a.
Monad m =>
(Run (WebStateT conn sess st) -> m a) -> WebStateT conn sess st m a
liftWith = (forall b.
 ReaderT (WebState conn sess st) m b -> WebStateT conn sess st m b)
-> (forall (o :: * -> *) b.
    WebStateT conn sess st o b -> ReaderT (WebState conn sess st) o b)
-> (RunDefault
      (WebStateT conn sess st) (ReaderT (WebState conn sess st))
    -> m a)
-> WebStateT conn sess st m a
forall (m :: * -> *) (n :: (* -> *) -> * -> *)
       (t :: (* -> *) -> * -> *) a.
(Monad m, MonadTransControl n) =>
(forall b. n m b -> t m b)
-> (forall (o :: * -> *) b. t o b -> n o b)
-> (RunDefault t n -> m a)
-> t m a
defaultLiftWith ReaderT (WebState conn sess st) m b -> WebStateT conn sess st m b
forall b.
ReaderT (WebState conn sess st) m b -> WebStateT conn sess st m b
forall conn sess st (m :: * -> *) a.
ReaderT (WebState conn sess st) m a -> WebStateT conn sess st m a
WebStateT WebStateT conn sess st o b -> ReaderT (WebState conn sess st) o b
forall conn sess st (m :: * -> *) a.
WebStateT conn sess st m a -> ReaderT (WebState conn sess st) m a
forall (o :: * -> *) b.
WebStateT conn sess st o b -> ReaderT (WebState conn sess st) o b
runWebStateT
  restoreT :: forall (m :: * -> *) a.
Monad m =>
m (StT (WebStateT conn sess st) a) -> WebStateT conn sess st m a
restoreT = (ReaderT (WebState conn sess st) m a -> WebStateT conn sess st m a)
-> m (StT (ReaderT (WebState conn sess st)) a)
-> WebStateT conn sess st m a
forall (m :: * -> *) (n :: (* -> *) -> * -> *) a
       (t :: (* -> *) -> * -> *).
(Monad m, MonadTransControl n) =>
(n m a -> t m a) -> m (StT n a) -> t m a
defaultRestoreT ReaderT (WebState conn sess st) m a -> WebStateT conn sess st m a
forall conn sess st (m :: * -> *) a.
ReaderT (WebState conn sess st) m a -> WebStateT conn sess st m a
WebStateT

instance MonadBaseControl b m => MonadBaseControl b (WebStateT conn sess st m) where
  type StM (WebStateT conn sess st m) a = ComposeSt (WebStateT conn sess st) m a
  restoreM :: forall a.
StM (WebStateT conn sess st m) a -> WebStateT conn sess st m a
restoreM = ComposeSt (WebStateT conn sess st) m a
-> WebStateT conn sess st m a
StM (WebStateT conn sess st m) a -> WebStateT conn sess st m a
forall (t :: (* -> *) -> * -> *) (b :: * -> *) (m :: * -> *) a.
(MonadTransControl t, MonadBaseControl b m) =>
ComposeSt t m a -> t m a
defaultRestoreM
  liftBaseWith :: forall a.
(RunInBase (WebStateT conn sess st m) b -> b a)
-> WebStateT conn sess st m a
liftBaseWith = (RunInBaseDefault (WebStateT conn sess st) m b -> b a)
-> WebStateT conn sess st m a
(RunInBase (WebStateT conn sess st m) b -> b a)
-> WebStateT conn sess st m a
forall (t :: (* -> *) -> * -> *) (b :: * -> *) (m :: * -> *) a.
(MonadTransControl t, MonadBaseControl b m) =>
(RunInBaseDefault t m b -> b a) -> t m a
defaultLiftBaseWith

-- | Shared application services over @ResourceT IO@. This is the base monad
-- underneath both route registration and request actions in full Spock.
-- Helpers here can use 'getState' and 'runQuery', but have no request body,
-- response, hook context, or current visitor's session. Those require the
-- action layer. Lift such a helper into an action or registration block with
-- @lift@; use @runSpockIO@ with an existing environment to run it from IO.
type WebStateM conn sess st = WebStateT conn sess st (ResourceT IO)

type SessionId = T.Text

data Session conn sess st = Session
  { forall conn sess st. Session conn sess st -> Text
sess_id :: !SessionId,
    forall conn sess st. Session conn sess st -> Text
sess_csrfToken :: !T.Text,
    forall conn sess st. Session conn sess st -> UTCTime
sess_validUntil :: !UTCTime,
    forall conn sess st. Session conn sess st -> sess
sess_data :: !sess
  }

data SessionStoreInstance sess where
  SessionStoreInstance :: forall sess tx. (Monad tx, Functor tx, Applicative tx) => SessionStore sess tx -> SessionStoreInstance sess

data SessionStore sess tx = SessionStore
  { -- | Run the entire supplied transaction atomically, isolated from other
    -- transactions. Session lookup, expiration, renewal, and modification rely
    -- on this guarantee to avoid lost updates or restoring deleted sessions.
    forall sess (tx :: * -> *).
SessionStore sess tx -> forall a. tx a -> IO a
ss_runTx :: forall a. tx a -> IO a,
    forall sess (tx :: * -> *).
SessionStore sess tx -> Text -> tx (Maybe sess)
ss_loadSession :: SessionId -> tx (Maybe sess),
    forall sess (tx :: * -> *). SessionStore sess tx -> Text -> tx ()
ss_deleteSession :: SessionId -> tx (),
    forall sess (tx :: * -> *). SessionStore sess tx -> sess -> tx ()
ss_storeSession :: sess -> tx (),
    forall sess (tx :: * -> *). SessionStore sess tx -> tx [sess]
ss_toList :: tx [sess],
    forall sess (tx :: * -> *).
SessionStore sess tx -> (sess -> Bool) -> tx ()
ss_filterSessions :: (sess -> Bool) -> tx (),
    forall sess (tx :: * -> *).
SessionStore sess tx -> (sess -> tx sess) -> tx ()
ss_mapSessions :: (sess -> tx sess) -> tx ()
  }

instance Show (Session conn sess st) where
  show :: Session conn sess st -> String
show = Text -> String
forall a. Show a => a -> String
show (Text -> String)
-> (Session conn sess st -> Text) -> Session conn sess st -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Session conn sess st -> Text
forall conn sess st. Session conn sess st -> Text
sess_id

type SpockSessionManager conn sess st = SessionManager (SpockActionCtx () conn sess st) conn sess st

data SessionIf m = SessionIf
  { forall (m :: * -> *). SessionIf m -> forall a. Key a -> m (Maybe a)
si_queryVault :: forall a. V.Key a -> m (Maybe a),
    forall (m :: * -> *). SessionIf m -> (Vault -> Vault) -> m ()
si_modifyVault :: (V.Vault -> V.Vault) -> m (),
    forall (m :: * -> *).
SessionIf m -> MultiHeader -> ByteString -> m ()
si_setRawMultiHeader :: MultiHeader -> BS.ByteString -> m (),
    forall (m :: * -> *). SessionIf m -> IO (Key Text)
si_vaultKey :: IO (V.Key SessionId)
  }

data SessionManager m conn sess st = SessionManager
  { forall (m :: * -> *) conn sess st.
SessionManager m conn sess st -> m Text
sm_getSessionId :: m SessionId,
    forall (m :: * -> *) conn sess st.
SessionManager m conn sess st -> m Text
sm_getCsrfToken :: m T.Text,
    forall (m :: * -> *) conn sess st.
SessionManager m conn sess st -> m ()
sm_regenerateSessionId :: m (),
    forall (m :: * -> *) conn sess st.
SessionManager m conn sess st -> m ()
sm_destroySession :: m (),
    forall (m :: * -> *) conn sess st.
SessionManager m conn sess st -> m sess
sm_readSession :: m sess,
    forall (m :: * -> *) conn sess st.
SessionManager m conn sess st -> sess -> m ()
sm_writeSession :: sess -> m (),
    forall (m :: * -> *) conn sess st.
SessionManager m conn sess st
-> forall a. (sess -> (sess, a)) -> m a
sm_modifySession :: forall a. (sess -> (sess, a)) -> m a,
    forall (m :: * -> *) conn sess st.
SessionManager m conn sess st
-> Maybe (ServerSessionManager m sess)
sm_serverSessions :: Maybe (ServerSessionManager m sess),
    forall (m :: * -> *) conn sess st.
SessionManager m conn sess st -> Middleware
sm_middleware :: Middleware,
    forall (m :: * -> *) conn sess st.
SessionManager m conn sess st -> IO ()
sm_closeSessionManager :: IO ()
  }

-- | Explicit capability available only for enabled server-backed sessions.
-- Public actions in Web.Spock.SessionActions.Server require this handle.
data ServerSessionManager m sess = ServerSessionManager
  { forall (m :: * -> *) sess.
ServerSessionManager m sess
-> (forall (n :: * -> *). Monad n => sess -> n sess) -> m ()
ssm_mapSessions :: (forall n. Monad n => sess -> n sess) -> m (),
    forall (m :: * -> *) sess. ServerSessionManager m sess -> m ()
ssm_clearAllSessions :: m ()
  }