packages feed

hyperbole 0.6.1 → 0.7.0

raw patch · 49 files changed

+1671/−1285 lines, 49 filesdep +directorydep +resourcetdep +wai-extradep −http-api-datadep ~aesondep ~http-client-tlsnew-component:exe:docgenPVP ok

version bump matches the API change (PVP)

Dependencies added: directory, resourcet, wai-extra

Dependencies removed: http-api-data

Dependency ranges changed: aeson, http-client-tls

API changes (from Hackage documentation)

- Web.Hyperbole: ($sel:html:View) :: View c a -> Eff '[Reader (c, ViewState c)] (Html a)
- Web.Hyperbole: [$sel:body:Request] :: Request -> ByteString
- Web.Hyperbole: [$sel:cookies:Request] :: Request -> Cookies
- Web.Hyperbole: [$sel:dataCell:TableColumn] :: TableColumn c dt -> dt -> View c ()
- Web.Hyperbole: [$sel:event:Request] :: Request -> Maybe (Event TargetViewId Encoded Encoded)
- Web.Hyperbole: [$sel:headCell:TableColumn] :: TableColumn c dt -> TableHead c ()
- Web.Hyperbole: [$sel:host:Request] :: Request -> Host
- Web.Hyperbole: [$sel:html:View] :: View c a -> Eff '[Reader (c, ViewState c)] (Html a)
- Web.Hyperbole: [$sel:method:Request] :: Request -> Method
- Web.Hyperbole: [$sel:path:Request] :: Request -> Path
- Web.Hyperbole: [$sel:query:Request] :: Request -> Query
- Web.Hyperbole: [$sel:requestId:Request] :: Request -> RequestId
- Web.Hyperbole: [$sel:value:FieldName] :: FieldName a -> Text
- Web.Hyperbole: class FromParam a
- Web.Hyperbole: class ToParam a
- Web.Hyperbole: decodeFormValue :: FromParam a => Maybe Text -> Either String a
- Web.Hyperbole: parseParam :: (FromParam a, Generic a, GFromJSON Zero (Rep a)) => ParamValue -> Either String a
- Web.Hyperbole: toParam :: (ToParam a, Generic a, GToJSON Zero (Rep a)) => a -> ParamValue
- Web.Hyperbole.Application: [$sel:serverError:ServerOptions] :: ServerOptions -> ResponseError -> ServerError
- Web.Hyperbole.Application: [$sel:toDocument:ServerOptions] :: ServerOptions -> ByteString -> ByteString
- Web.Hyperbole.Data.Cookie: [$sel:key:Cookie] :: Cookie -> Key
- Web.Hyperbole.Data.Cookie: [$sel:path:Cookie] :: Cookie -> Maybe Path
- Web.Hyperbole.Data.Cookie: [$sel:secure:Cookie] :: Cookie -> Bool
- Web.Hyperbole.Data.Cookie: [$sel:value:Cookie] :: Cookie -> Maybe CookieValue
- Web.Hyperbole.Data.Cookie: instance GHC.Base.Monoid Web.Hyperbole.Data.Cookie.Cookies
- Web.Hyperbole.Data.Cookie: instance GHC.Base.Semigroup Web.Hyperbole.Data.Cookie.Cookies
- Web.Hyperbole.Data.Cookie: instance GHC.Show.Show Web.Hyperbole.Data.Cookie.Cookie
- Web.Hyperbole.Data.Cookie: instance GHC.Show.Show Web.Hyperbole.Data.Cookie.CookieValue
- Web.Hyperbole.Data.Cookie: instance GHC.Show.Show Web.Hyperbole.Data.Cookie.Cookies
- Web.Hyperbole.Data.Encoded: [$sel:text:ConName] :: ConName -> Text
- Web.Hyperbole.Data.Encoded: decodeParam :: Text -> ParamValue
- Web.Hyperbole.Data.Encoded: desanitizeParamText :: Text -> Text
- Web.Hyperbole.Data.Encoded: encodeParam :: ParamValue -> Text
- Web.Hyperbole.Data.Encoded: instance Data.String.IsString Web.Hyperbole.Data.Encoded.ConName
- Web.Hyperbole.Data.Encoded: instance GHC.Base.Monoid Web.Hyperbole.Data.Encoded.ConName
- Web.Hyperbole.Data.Encoded: instance GHC.Base.Monoid Web.Hyperbole.Data.Encoded.Encoded
- Web.Hyperbole.Data.Encoded: instance GHC.Base.Semigroup Web.Hyperbole.Data.Encoded.ConName
- Web.Hyperbole.Data.Encoded: instance GHC.Base.Semigroup Web.Hyperbole.Data.Encoded.Encoded
- Web.Hyperbole.Data.Encoded: instance GHC.Show.Show Web.Hyperbole.Data.Encoded.ConName
- Web.Hyperbole.Data.Encoded: instance GHC.Show.Show Web.Hyperbole.Data.Encoded.Encoded
- Web.Hyperbole.Data.Encoded: instance Web.Hyperbole.Data.Encoded.FromEncoded Web.Hyperbole.Data.Param.ParamValue
- Web.Hyperbole.Data.Encoded: instance Web.Hyperbole.Data.Encoded.GFromEncoded GHC.Generics.U1
- Web.Hyperbole.Data.Encoded: instance Web.Hyperbole.Data.Encoded.GToEncoded GHC.Generics.U1
- Web.Hyperbole.Data.Encoded: instance Web.Hyperbole.Data.Encoded.ToEncoded Web.Hyperbole.Data.Param.ParamValue
- Web.Hyperbole.Data.Encoded: instance Web.Hyperbole.Data.Param.FromParam a => Web.Hyperbole.Data.Encoded.GFromEncoded (GHC.Generics.K1 GHC.Generics.R a)
- Web.Hyperbole.Data.Encoded: instance Web.Hyperbole.Data.Param.ToParam a => Web.Hyperbole.Data.Encoded.GToEncoded (GHC.Generics.K1 GHC.Generics.R a)
- Web.Hyperbole.Data.Encoded: instance forall k (c :: GHC.Generics.Meta) (f :: k -> *). (GHC.Generics.Constructor c, Web.Hyperbole.Data.Encoded.GFromEncoded f) => Web.Hyperbole.Data.Encoded.GFromEncoded (GHC.Generics.M1 GHC.Generics.C c f)
- Web.Hyperbole.Data.Encoded: instance forall k (c :: GHC.Generics.Meta) (f :: k -> *). (GHC.Generics.Constructor c, Web.Hyperbole.Data.Encoded.GToEncoded f) => Web.Hyperbole.Data.Encoded.GToEncoded (GHC.Generics.M1 GHC.Generics.C c f)
- Web.Hyperbole.Data.Encoded: instance forall k (f :: k -> *) (d :: GHC.Generics.Meta). Web.Hyperbole.Data.Encoded.GFromEncoded f => Web.Hyperbole.Data.Encoded.GFromEncoded (GHC.Generics.M1 GHC.Generics.D d f)
- Web.Hyperbole.Data.Encoded: instance forall k (f :: k -> *) (d :: GHC.Generics.Meta). Web.Hyperbole.Data.Encoded.GToEncoded f => Web.Hyperbole.Data.Encoded.GToEncoded (GHC.Generics.M1 GHC.Generics.D d f)
- Web.Hyperbole.Data.Encoded: instance forall k (f :: k -> *) (g :: k -> *). (Web.Hyperbole.Data.Encoded.GFromEncoded f, Web.Hyperbole.Data.Encoded.GFromEncoded g) => Web.Hyperbole.Data.Encoded.GFromEncoded (f GHC.Generics.:*: g)
- Web.Hyperbole.Data.Encoded: instance forall k (f :: k -> *) (g :: k -> *). (Web.Hyperbole.Data.Encoded.GFromEncoded f, Web.Hyperbole.Data.Encoded.GFromEncoded g) => Web.Hyperbole.Data.Encoded.GFromEncoded (f GHC.Generics.:+: g)
- Web.Hyperbole.Data.Encoded: instance forall k (f :: k -> *) (g :: k -> *). (Web.Hyperbole.Data.Encoded.GToEncoded f, Web.Hyperbole.Data.Encoded.GToEncoded g) => Web.Hyperbole.Data.Encoded.GToEncoded (f GHC.Generics.:*: g)
- Web.Hyperbole.Data.Encoded: instance forall k (f :: k -> *) (g :: k -> *). (Web.Hyperbole.Data.Encoded.GToEncoded f, Web.Hyperbole.Data.Encoded.GToEncoded g) => Web.Hyperbole.Data.Encoded.GToEncoded (f GHC.Generics.:+: g)
- Web.Hyperbole.Data.Encoded: instance forall k (f :: k -> *) (s :: GHC.Generics.Meta). Web.Hyperbole.Data.Encoded.GFromEncoded f => Web.Hyperbole.Data.Encoded.GFromEncoded (GHC.Generics.M1 GHC.Generics.S s f)
- Web.Hyperbole.Data.Encoded: instance forall k (f :: k -> *) (s :: GHC.Generics.Meta). Web.Hyperbole.Data.Encoded.GToEncoded f => Web.Hyperbole.Data.Encoded.GToEncoded (GHC.Generics.M1 GHC.Generics.S s f)
- Web.Hyperbole.Data.Encoded: paramParser :: Parser ParamValue
- Web.Hyperbole.Data.JSON: JSON :: a -> JSON a
- Web.Hyperbole.Data.JSON: class () => FromJSON a
- Web.Hyperbole.Data.JSON: class () => ToJSON a
- Web.Hyperbole.Data.JSON: instance Data.Aeson.Types.FromJSON.FromJSON a => Web.Hyperbole.Data.Encoded.FromEncoded (Web.Hyperbole.Data.JSON.JSON a)
- Web.Hyperbole.Data.JSON: instance Data.Aeson.Types.ToJSON.ToJSON a => Web.Hyperbole.Data.Encoded.ToEncoded (Web.Hyperbole.Data.JSON.JSON a)
- Web.Hyperbole.Data.JSON: newtype JSON a
- Web.Hyperbole.Data.Param: Param :: Text -> Param
- Web.Hyperbole.Data.Param: ParamValue :: Text -> ParamValue
- Web.Hyperbole.Data.Param: [$sel:text:Param] :: Param -> Text
- Web.Hyperbole.Data.Param: [$sel:value:ParamValue] :: ParamValue -> Text
- Web.Hyperbole.Data.Param: class FromParam a
- Web.Hyperbole.Data.Param: class ToParam a
- Web.Hyperbole.Data.Param: decodeFormValue :: FromParam a => Maybe Text -> Either String a
- Web.Hyperbole.Data.Param: genericParseParam :: (Generic a, GFromJSON Zero (Rep a)) => ParamValue -> Either String a
- Web.Hyperbole.Data.Param: genericToParam :: (Generic a, GToJSON Zero (Rep a)) => a -> ParamValue
- Web.Hyperbole.Data.Param: instance (Web.Hyperbole.Data.Param.FromParam a, Web.Hyperbole.Data.Param.FromParam b) => Web.Hyperbole.Data.Param.FromParam (Data.Either.Either a b)
- Web.Hyperbole.Data.Param: instance (Web.Hyperbole.Data.Param.FromParam a, Web.Hyperbole.Data.Param.FromParam b) => Web.Hyperbole.Data.Param.FromParam (a, b)
- Web.Hyperbole.Data.Param: instance (Web.Hyperbole.Data.Param.ToParam a, Web.Hyperbole.Data.Param.ToParam b) => Web.Hyperbole.Data.Param.ToParam (Data.Either.Either a b)
- Web.Hyperbole.Data.Param: instance (Web.Hyperbole.Data.Param.ToParam a, Web.Hyperbole.Data.Param.ToParam b) => Web.Hyperbole.Data.Param.ToParam (a, b)
- Web.Hyperbole.Data.Param: instance Data.String.IsString Web.Hyperbole.Data.Param.Param
- Web.Hyperbole.Data.Param: instance Data.String.IsString Web.Hyperbole.Data.Param.ParamValue
- Web.Hyperbole.Data.Param: instance GHC.Classes.Eq Web.Hyperbole.Data.Param.Param
- Web.Hyperbole.Data.Param: instance GHC.Classes.Eq Web.Hyperbole.Data.Param.ParamValue
- Web.Hyperbole.Data.Param: instance GHC.Classes.Ord Web.Hyperbole.Data.Param.Param
- Web.Hyperbole.Data.Param: instance GHC.Classes.Ord Web.Hyperbole.Data.Param.ParamValue
- Web.Hyperbole.Data.Param: instance GHC.Generics.Generic Web.Hyperbole.Data.Param.ParamValue
- Web.Hyperbole.Data.Param: instance GHC.Show.Show Web.Hyperbole.Data.Param.Param
- Web.Hyperbole.Data.Param: instance GHC.Show.Show Web.Hyperbole.Data.Param.ParamValue
- Web.Hyperbole.Data.Param: instance Web.Hyperbole.Data.Param.FromParam (GHC.Maybe.Maybe Data.Text.Internal.Text)
- Web.Hyperbole.Data.Param: instance Web.Hyperbole.Data.Param.FromParam Data.Aeson.Types.Internal.Value
- Web.Hyperbole.Data.Param: instance Web.Hyperbole.Data.Param.FromParam Data.Text.Internal.Text
- Web.Hyperbole.Data.Param: instance Web.Hyperbole.Data.Param.FromParam Data.Time.Clock.Internal.UTCTime.UTCTime
- Web.Hyperbole.Data.Param: instance Web.Hyperbole.Data.Param.FromParam GHC.Base.String
- Web.Hyperbole.Data.Param: instance Web.Hyperbole.Data.Param.FromParam GHC.Num.Integer.Integer
- Web.Hyperbole.Data.Param: instance Web.Hyperbole.Data.Param.FromParam GHC.Types.Bool
- Web.Hyperbole.Data.Param: instance Web.Hyperbole.Data.Param.FromParam GHC.Types.Char
- Web.Hyperbole.Data.Param: instance Web.Hyperbole.Data.Param.FromParam GHC.Types.Double
- Web.Hyperbole.Data.Param: instance Web.Hyperbole.Data.Param.FromParam GHC.Types.Float
- Web.Hyperbole.Data.Param: instance Web.Hyperbole.Data.Param.FromParam GHC.Types.Int
- Web.Hyperbole.Data.Param: instance Web.Hyperbole.Data.Param.FromParam GHC.Types.Word
- Web.Hyperbole.Data.Param: instance Web.Hyperbole.Data.Param.FromParam GHC.Word.Word16
- Web.Hyperbole.Data.Param: instance Web.Hyperbole.Data.Param.FromParam GHC.Word.Word32
- Web.Hyperbole.Data.Param: instance Web.Hyperbole.Data.Param.FromParam GHC.Word.Word64
- Web.Hyperbole.Data.Param: instance Web.Hyperbole.Data.Param.FromParam GHC.Word.Word8
- Web.Hyperbole.Data.Param: instance Web.Hyperbole.Data.Param.FromParam Network.URI.URI
- Web.Hyperbole.Data.Param: instance Web.Hyperbole.Data.Param.FromParam Web.Hyperbole.Data.Param.ParamValue
- Web.Hyperbole.Data.Param: instance Web.Hyperbole.Data.Param.FromParam a => Web.Hyperbole.Data.Param.FromParam (GHC.Maybe.Maybe a)
- Web.Hyperbole.Data.Param: instance Web.Hyperbole.Data.Param.FromParam a => Web.Hyperbole.Data.Param.FromParam [a]
- Web.Hyperbole.Data.Param: instance Web.Hyperbole.Data.Param.ToParam Data.Aeson.Types.Internal.Value
- Web.Hyperbole.Data.Param: instance Web.Hyperbole.Data.Param.ToParam Data.Text.Internal.Text
- Web.Hyperbole.Data.Param: instance Web.Hyperbole.Data.Param.ToParam Data.Time.Clock.Internal.UTCTime.UTCTime
- Web.Hyperbole.Data.Param: instance Web.Hyperbole.Data.Param.ToParam GHC.Base.String
- Web.Hyperbole.Data.Param: instance Web.Hyperbole.Data.Param.ToParam GHC.Num.Integer.Integer
- Web.Hyperbole.Data.Param: instance Web.Hyperbole.Data.Param.ToParam GHC.Types.Bool
- Web.Hyperbole.Data.Param: instance Web.Hyperbole.Data.Param.ToParam GHC.Types.Char
- Web.Hyperbole.Data.Param: instance Web.Hyperbole.Data.Param.ToParam GHC.Types.Double
- Web.Hyperbole.Data.Param: instance Web.Hyperbole.Data.Param.ToParam GHC.Types.Float
- Web.Hyperbole.Data.Param: instance Web.Hyperbole.Data.Param.ToParam GHC.Types.Int
- Web.Hyperbole.Data.Param: instance Web.Hyperbole.Data.Param.ToParam GHC.Types.Word
- Web.Hyperbole.Data.Param: instance Web.Hyperbole.Data.Param.ToParam GHC.Word.Word16
- Web.Hyperbole.Data.Param: instance Web.Hyperbole.Data.Param.ToParam GHC.Word.Word32
- Web.Hyperbole.Data.Param: instance Web.Hyperbole.Data.Param.ToParam GHC.Word.Word64
- Web.Hyperbole.Data.Param: instance Web.Hyperbole.Data.Param.ToParam GHC.Word.Word8
- Web.Hyperbole.Data.Param: instance Web.Hyperbole.Data.Param.ToParam Network.URI.URI
- Web.Hyperbole.Data.Param: instance Web.Hyperbole.Data.Param.ToParam Web.Hyperbole.Data.Param.ParamValue
- Web.Hyperbole.Data.Param: instance Web.Hyperbole.Data.Param.ToParam a => Web.Hyperbole.Data.Param.ToParam (GHC.Maybe.Maybe a)
- Web.Hyperbole.Data.Param: instance Web.Hyperbole.Data.Param.ToParam a => Web.Hyperbole.Data.Param.ToParam [a]
- Web.Hyperbole.Data.Param: jsonOptions :: Options
- Web.Hyperbole.Data.Param: jsonParam :: ToJSON a => a -> ParamValue
- Web.Hyperbole.Data.Param: jsonParse :: FromJSON a => ParamValue -> Either String a
- Web.Hyperbole.Data.Param: newtype Param
- Web.Hyperbole.Data.Param: newtype ParamValue
- Web.Hyperbole.Data.Param: parseParam :: (FromParam a, Generic a, GFromJSON Zero (Rep a)) => ParamValue -> Either String a
- Web.Hyperbole.Data.Param: parseQueryParam :: FromHttpApiData a => ParamValue -> Either String a
- Web.Hyperbole.Data.Param: readParam :: Read a => ParamValue -> Either String a
- Web.Hyperbole.Data.Param: showParam :: Show a => a -> ParamValue
- Web.Hyperbole.Data.Param: toParam :: (ToParam a, Generic a, GToJSON Zero (Rep a)) => a -> ParamValue
- Web.Hyperbole.Data.Param: toQueryParam :: ToHttpApiData a => a -> ParamValue
- Web.Hyperbole.Data.QueryData: instance (GHC.Generics.Selector s, Web.Hyperbole.Data.Param.FromParam a, Data.Default.Internal.Default a) => Web.Hyperbole.Data.QueryData.GFromQuery (GHC.Generics.M1 GHC.Generics.S s (GHC.Generics.K1 GHC.Generics.R a))
- Web.Hyperbole.Data.QueryData: instance (GHC.Generics.Selector s, Web.Hyperbole.Data.Param.ToParam a, GHC.Classes.Eq a, Data.Default.Internal.Default a) => Web.Hyperbole.Data.QueryData.GToQuery (GHC.Generics.M1 GHC.Generics.S s (GHC.Generics.K1 GHC.Generics.R a))
- Web.Hyperbole.Data.QueryData: instance GHC.Base.Monoid Web.Hyperbole.Data.QueryData.QueryData
- Web.Hyperbole.Data.QueryData: instance GHC.Base.Semigroup Web.Hyperbole.Data.QueryData.QueryData
- Web.Hyperbole.Data.QueryData: instance GHC.Generics.Selector s => Web.Hyperbole.Data.QueryData.GFromQuery (GHC.Generics.M1 GHC.Generics.S s (GHC.Generics.K1 GHC.Generics.R Data.Text.Internal.Text))
- Web.Hyperbole.Data.QueryData: instance GHC.Generics.Selector s => Web.Hyperbole.Data.QueryData.GToQuery (GHC.Generics.M1 GHC.Generics.S s (GHC.Generics.K1 GHC.Generics.R Data.Text.Internal.Text))
- Web.Hyperbole.Data.QueryData: instance GHC.IsList.IsList Web.Hyperbole.Data.QueryData.QueryData
- Web.Hyperbole.Data.QueryData: instance GHC.Show.Show Web.Hyperbole.Data.QueryData.QueryData
- Web.Hyperbole.Data.QueryData: instance forall k (f :: k -> *) (c :: GHC.Generics.Meta). Web.Hyperbole.Data.QueryData.GFromQuery f => Web.Hyperbole.Data.QueryData.GFromQuery (GHC.Generics.M1 GHC.Generics.C c f)
- Web.Hyperbole.Data.QueryData: instance forall k (f :: k -> *) (d :: GHC.Generics.Meta). Web.Hyperbole.Data.QueryData.GFromQuery f => Web.Hyperbole.Data.QueryData.GFromQuery (GHC.Generics.M1 GHC.Generics.D d f)
- Web.Hyperbole.Data.QueryData: instance forall k (f :: k -> *) (d :: GHC.Generics.Meta). Web.Hyperbole.Data.QueryData.GToQuery f => Web.Hyperbole.Data.QueryData.GToQuery (GHC.Generics.M1 GHC.Generics.C d f)
- Web.Hyperbole.Data.QueryData: instance forall k (f :: k -> *) (d :: GHC.Generics.Meta). Web.Hyperbole.Data.QueryData.GToQuery f => Web.Hyperbole.Data.QueryData.GToQuery (GHC.Generics.M1 GHC.Generics.D d f)
- Web.Hyperbole.Data.QueryData: instance forall k (f :: k -> *) (g :: k -> *). (Web.Hyperbole.Data.QueryData.GFromQuery f, Web.Hyperbole.Data.QueryData.GFromQuery g) => Web.Hyperbole.Data.QueryData.GFromQuery (f GHC.Generics.:*: g)
- Web.Hyperbole.Data.QueryData: instance forall k (f :: k -> *) (g :: k -> *). (Web.Hyperbole.Data.QueryData.GToQuery f, Web.Hyperbole.Data.QueryData.GToQuery g) => Web.Hyperbole.Data.QueryData.GToQuery (f GHC.Generics.:*: g)
- Web.Hyperbole.Data.URI: [$sel:segments:Path] :: Path -> [Segment]
- Web.Hyperbole.Data.URI: [$sel:uri:Endpoint] :: Endpoint a -> URI
- Web.Hyperbole.Data.URI: instance Data.String.IsString Web.Hyperbole.Data.URI.Path
- Web.Hyperbole.Data.URI: instance GHC.IsList.IsList Web.Hyperbole.Data.URI.Path
- Web.Hyperbole.Data.URI: instance GHC.Show.Show Web.Hyperbole.Data.URI.Path
- Web.Hyperbole.Document: instance GHC.Generics.Generic Web.Hyperbole.Document.DocumentHead
- Web.Hyperbole.Effect.GenRandom: [$sel:value:Token] :: Token a -> Text
- Web.Hyperbole.Effect.GenRandom: instance forall k (a :: k). GHC.Read.Read (Web.Hyperbole.Effect.GenRandom.Token a)
- Web.Hyperbole.Effect.GenRandom: instance forall k (a :: k). GHC.Show.Show (Web.Hyperbole.Effect.GenRandom.Token a)
- Web.Hyperbole.Effect.GenRandom: instance forall k (a :: k). Web.Hyperbole.Data.Param.FromParam (Web.Hyperbole.Effect.GenRandom.Token a)
- Web.Hyperbole.Effect.GenRandom: instance forall k (a :: k). Web.Hyperbole.Data.Param.ToParam (Web.Hyperbole.Effect.GenRandom.Token a)
- Web.Hyperbole.Effect.OAuth2: AuthFlow :: URI -> Token State -> AuthFlow
- Web.Hyperbole.Effect.OAuth2: Authenticated :: TokenType -> Maybe Int -> Maybe Scopes -> Token Access -> Maybe (Token Refresh) -> Authenticated
- Web.Hyperbole.Effect.OAuth2: Bearer :: TokenType
- Web.Hyperbole.Effect.OAuth2: Config :: Token ClientId -> Token ClientSecret -> Endpoint Auth -> Endpoint (Token ()) -> Config
- Web.Hyperbole.Effect.OAuth2: OAuth2BadEnv :: String -> String -> OAuth2Error
- Web.Hyperbole.Effect.OAuth2: OAuth2BadResponse :: String -> ByteString -> OAuth2Error
- Web.Hyperbole.Effect.OAuth2: OAuth2TokenRequest :: HttpException -> OAuth2Error
- Web.Hyperbole.Effect.OAuth2: Scopes :: [Text] -> Scopes
- Web.Hyperbole.Effect.OAuth2: Token :: Text -> Token a
- Web.Hyperbole.Effect.OAuth2: [$sel:accessToken:Authenticated] :: Authenticated -> Token Access
- Web.Hyperbole.Effect.OAuth2: [$sel:authorize:Config] :: Config -> Endpoint Auth
- Web.Hyperbole.Effect.OAuth2: [$sel:clientId:Config] :: Config -> Token ClientId
- Web.Hyperbole.Effect.OAuth2: [$sel:clientSecret:Config] :: Config -> Token ClientSecret
- Web.Hyperbole.Effect.OAuth2: [$sel:expiresIn:Authenticated] :: Authenticated -> Maybe Int
- Web.Hyperbole.Effect.OAuth2: [$sel:redirect:AuthFlow] :: AuthFlow -> URI
- Web.Hyperbole.Effect.OAuth2: [$sel:refreshToken:Authenticated] :: Authenticated -> Maybe (Token Refresh)
- Web.Hyperbole.Effect.OAuth2: [$sel:scope:Authenticated] :: Authenticated -> Maybe Scopes
- Web.Hyperbole.Effect.OAuth2: [$sel:state:AuthFlow] :: AuthFlow -> Token State
- Web.Hyperbole.Effect.OAuth2: [$sel:token:Config] :: Config -> Endpoint (Token ())
- Web.Hyperbole.Effect.OAuth2: [$sel:tokenType:Authenticated] :: Authenticated -> TokenType
- Web.Hyperbole.Effect.OAuth2: [$sel:value:Token] :: Token a -> Text
- Web.Hyperbole.Effect.OAuth2: [AuthUrl] :: URI -> Scopes -> OAuth2 m URI
- Web.Hyperbole.Effect.OAuth2: [ExchangeAuth] :: Token Code -> OAuth2 m Authenticated
- Web.Hyperbole.Effect.OAuth2: [ExchangeRefresh] :: Token Refresh -> OAuth2 m Authenticated
- Web.Hyperbole.Effect.OAuth2: [ValidateCode] :: OAuth2 m (Token Code)
- Web.Hyperbole.Effect.OAuth2: authUrl :: OAuth2 :> es => URI -> Scopes -> Eff es URI
- Web.Hyperbole.Effect.OAuth2: data Access
- Web.Hyperbole.Effect.OAuth2: data Auth
- Web.Hyperbole.Effect.OAuth2: data AuthFlow
- Web.Hyperbole.Effect.OAuth2: data Authenticated
- Web.Hyperbole.Effect.OAuth2: data ClientId
- Web.Hyperbole.Effect.OAuth2: data ClientSecret
- Web.Hyperbole.Effect.OAuth2: data Code
- Web.Hyperbole.Effect.OAuth2: data Config
- Web.Hyperbole.Effect.OAuth2: data OAuth2 :: Effect
- Web.Hyperbole.Effect.OAuth2: data OAuth2Error
- Web.Hyperbole.Effect.OAuth2: data Refresh
- Web.Hyperbole.Effect.OAuth2: data State
- Web.Hyperbole.Effect.OAuth2: data TokenType
- Web.Hyperbole.Effect.OAuth2: exchangeAuth :: OAuth2 :> es => Token Code -> Eff es Authenticated
- Web.Hyperbole.Effect.OAuth2: exchangeRefresh :: OAuth2 :> es => Token Refresh -> Eff es Authenticated
- Web.Hyperbole.Effect.OAuth2: getConfigEnv :: Environment :> es => Eff es Config
- Web.Hyperbole.Effect.OAuth2: instance Data.Aeson.Types.FromJSON.FromJSON Web.Hyperbole.Effect.OAuth2.Authenticated
- Web.Hyperbole.Effect.OAuth2: instance Data.Aeson.Types.FromJSON.FromJSON Web.Hyperbole.Effect.OAuth2.Scopes
- Web.Hyperbole.Effect.OAuth2: instance Data.Aeson.Types.FromJSON.FromJSON Web.Hyperbole.Effect.OAuth2.TokenType
- Web.Hyperbole.Effect.OAuth2: instance Data.Aeson.Types.ToJSON.ToJSON Web.Hyperbole.Effect.OAuth2.Authenticated
- Web.Hyperbole.Effect.OAuth2: instance Data.Aeson.Types.ToJSON.ToJSON Web.Hyperbole.Effect.OAuth2.Scopes
- Web.Hyperbole.Effect.OAuth2: instance Data.Aeson.Types.ToJSON.ToJSON Web.Hyperbole.Effect.OAuth2.TokenType
- Web.Hyperbole.Effect.OAuth2: instance Data.Default.Internal.Default Web.Hyperbole.Effect.OAuth2.AuthFlow
- Web.Hyperbole.Effect.OAuth2: instance Data.String.IsString Web.Hyperbole.Effect.OAuth2.Scopes
- Web.Hyperbole.Effect.OAuth2: instance GHC.Exception.Type.Exception Web.Hyperbole.Effect.OAuth2.OAuth2Error
- Web.Hyperbole.Effect.OAuth2: instance GHC.Generics.Generic Web.Hyperbole.Effect.OAuth2.AuthFlow
- Web.Hyperbole.Effect.OAuth2: instance GHC.Generics.Generic Web.Hyperbole.Effect.OAuth2.Authenticated
- Web.Hyperbole.Effect.OAuth2: instance GHC.Generics.Generic Web.Hyperbole.Effect.OAuth2.Scopes
- Web.Hyperbole.Effect.OAuth2: instance GHC.Generics.Generic Web.Hyperbole.Effect.OAuth2.TokenType
- Web.Hyperbole.Effect.OAuth2: instance GHC.Read.Read Web.Hyperbole.Effect.OAuth2.TokenType
- Web.Hyperbole.Effect.OAuth2: instance GHC.Show.Show Web.Hyperbole.Effect.OAuth2.Authenticated
- Web.Hyperbole.Effect.OAuth2: instance GHC.Show.Show Web.Hyperbole.Effect.OAuth2.OAuth2Error
- Web.Hyperbole.Effect.OAuth2: instance GHC.Show.Show Web.Hyperbole.Effect.OAuth2.Scopes
- Web.Hyperbole.Effect.OAuth2: instance GHC.Show.Show Web.Hyperbole.Effect.OAuth2.TokenType
- Web.Hyperbole.Effect.OAuth2: instance Web.Hyperbole.Data.Encoded.FromEncoded Web.Hyperbole.Effect.OAuth2.AuthFlow
- Web.Hyperbole.Effect.OAuth2: instance Web.Hyperbole.Data.Encoded.FromEncoded Web.Hyperbole.Effect.OAuth2.Authenticated
- Web.Hyperbole.Effect.OAuth2: instance Web.Hyperbole.Data.Encoded.ToEncoded Web.Hyperbole.Effect.OAuth2.AuthFlow
- Web.Hyperbole.Effect.OAuth2: instance Web.Hyperbole.Data.Encoded.ToEncoded Web.Hyperbole.Effect.OAuth2.Authenticated
- Web.Hyperbole.Effect.OAuth2: instance Web.Hyperbole.Data.Param.FromParam Web.Hyperbole.Effect.OAuth2.Authenticated
- Web.Hyperbole.Effect.OAuth2: instance Web.Hyperbole.Data.Param.FromParam Web.Hyperbole.Effect.OAuth2.Scopes
- Web.Hyperbole.Effect.OAuth2: instance Web.Hyperbole.Data.Param.FromParam Web.Hyperbole.Effect.OAuth2.TokenType
- Web.Hyperbole.Effect.OAuth2: instance Web.Hyperbole.Data.Param.ToParam Web.Hyperbole.Effect.OAuth2.Authenticated
- Web.Hyperbole.Effect.OAuth2: instance Web.Hyperbole.Data.Param.ToParam Web.Hyperbole.Effect.OAuth2.Scopes
- Web.Hyperbole.Effect.OAuth2: instance Web.Hyperbole.Data.Param.ToParam Web.Hyperbole.Effect.OAuth2.TokenType
- Web.Hyperbole.Effect.OAuth2: instance Web.Hyperbole.Effect.Session.Session Web.Hyperbole.Effect.OAuth2.AuthFlow
- Web.Hyperbole.Effect.OAuth2: instance Web.Hyperbole.Effect.Session.Session Web.Hyperbole.Effect.OAuth2.Authenticated
- Web.Hyperbole.Effect.OAuth2: newtype Scopes
- Web.Hyperbole.Effect.OAuth2: newtype Token a
- Web.Hyperbole.Effect.OAuth2: runOAuth2 :: (GenRandom :> es, IOE :> es, Hyperbole :> es) => Config -> Manager -> Eff (OAuth2 : es) a -> Eff es a
- Web.Hyperbole.Effect.OAuth2: validateCode :: OAuth2 :> es => Eff es (Token Code)
- Web.Hyperbole.Effect.Request: request :: Hyperbole :> es => Eff es Request
- Web.Hyperbole.Effect.Session: instance forall k (d :: GHC.Generics.Meta) (f :: k -> *). GHC.Generics.Datatype d => Web.Hyperbole.Effect.Session.GDatatypeName (GHC.Generics.M1 GHC.Generics.D d f)
- Web.Hyperbole.HyperView.Event: instance GHC.Read.Read Web.Hyperbole.HyperView.Event.Key
- Web.Hyperbole.HyperView.Event: instance GHC.Show.Show Web.Hyperbole.HyperView.Event.Key
- Web.Hyperbole.HyperView.Event: toActionInput :: ViewAction a => (val -> a) -> Encoded
- Web.Hyperbole.HyperView.Forms: Form :: Map Text [Text] -> Form
- Web.Hyperbole.HyperView.Forms: FormOptions :: (String -> String) -> FormOptions
- Web.Hyperbole.HyperView.Forms: [$sel:id:Input] :: Input (id :: Type) (a :: Type) -> id
- Web.Hyperbole.HyperView.Forms: [$sel:inputName:Input] :: Input (id :: Type) (a :: Type) -> FieldName a
- Web.Hyperbole.HyperView.Forms: [$sel:value:FieldName] :: FieldName a -> Text
- Web.Hyperbole.HyperView.Forms: [fieldLabelModifier] :: FormOptions -> String -> String
- Web.Hyperbole.HyperView.Forms: [unForm] :: Form -> Map Text [Text]
- Web.Hyperbole.HyperView.Forms: class () => FromFormKey k
- Web.Hyperbole.HyperView.Forms: data () => FormOptions
- Web.Hyperbole.HyperView.Forms: instance (GHC.Generics.Selector s, Web.Hyperbole.Data.Param.FromParam a) => Web.Hyperbole.HyperView.Forms.GFormParse (GHC.Generics.M1 GHC.Generics.S s (GHC.Generics.K1 GHC.Generics.R a))
- Web.Hyperbole.HyperView.Forms: instance (GHC.Generics.Selector s, Web.Hyperbole.HyperView.Forms.GenField a) => Web.Hyperbole.HyperView.Forms.GFieldsGen (GHC.Generics.M1 GHC.Generics.S s (GHC.Generics.K1 GHC.Generics.R a))
- Web.Hyperbole.HyperView.Forms: instance (Web.Hyperbole.Data.Param.FromParam id, Web.Hyperbole.Data.Param.ToParam id, Web.Hyperbole.Data.Param.FromParam a, Web.Hyperbole.Data.Param.ToParam a, Web.Hyperbole.Data.Param.ToParam opt, Web.Hyperbole.Data.Param.FromParam opt) => Web.Hyperbole.View.ViewId.ViewId (Web.Hyperbole.HyperView.Forms.Radio id a opt)
- Web.Hyperbole.HyperView.Forms: instance (Web.Hyperbole.View.ViewId.ViewId id, Web.Hyperbole.Data.Param.FromParam id, Web.Hyperbole.Data.Param.ToParam id) => Web.Hyperbole.View.ViewId.ViewId (Web.Hyperbole.HyperView.Forms.Input id a)
- Web.Hyperbole.HyperView.Forms: instance GHC.Generics.Generic (Web.Hyperbole.HyperView.Forms.FormFields id)
- Web.Hyperbole.HyperView.Forms: instance GHC.Generics.Generic (Web.Hyperbole.HyperView.Forms.Input id a)
- Web.Hyperbole.HyperView.Forms: instance GHC.Generics.Generic (Web.Hyperbole.HyperView.Forms.Radio id a opt)
- Web.Hyperbole.HyperView.Forms: instance GHC.Show.Show Web.Hyperbole.HyperView.Forms.InputType
- Web.Hyperbole.HyperView.Forms: instance Web.Hyperbole.HyperView.Forms.FromFormF form => Web.Hyperbole.HyperView.Forms.FromForm (form Data.Functor.Identity.Identity)
- Web.Hyperbole.HyperView.Forms: instance Web.Hyperbole.HyperView.Forms.GFieldsGen GHC.Generics.U1
- Web.Hyperbole.HyperView.Forms: instance Web.Hyperbole.HyperView.Forms.GenField (GHC.Maybe.Maybe a)
- Web.Hyperbole.HyperView.Forms: instance forall k (a :: k). Data.String.IsString (Web.Hyperbole.HyperView.Forms.FieldName a)
- Web.Hyperbole.HyperView.Forms: instance forall k (a :: k). GHC.Base.Monoid (Web.Hyperbole.HyperView.Forms.Validated a)
- Web.Hyperbole.HyperView.Forms: instance forall k (a :: k). GHC.Base.Semigroup (Web.Hyperbole.HyperView.Forms.Validated a)
- Web.Hyperbole.HyperView.Forms: instance forall k (a :: k). GHC.Show.Show (Web.Hyperbole.HyperView.Forms.FieldName a)
- Web.Hyperbole.HyperView.Forms: instance forall k (a :: k). GHC.Show.Show (Web.Hyperbole.HyperView.Forms.Validated a)
- Web.Hyperbole.HyperView.Forms: instance forall k (a :: k). Web.Hyperbole.Data.Param.FromParam (Web.Hyperbole.HyperView.Forms.FieldName a)
- Web.Hyperbole.HyperView.Forms: instance forall k (a :: k). Web.Hyperbole.Data.Param.ToParam (Web.Hyperbole.HyperView.Forms.FieldName a)
- Web.Hyperbole.HyperView.Forms: instance forall k (f :: k -> *) (c :: GHC.Generics.Meta). Web.Hyperbole.HyperView.Forms.GFieldsGen f => Web.Hyperbole.HyperView.Forms.GFieldsGen (GHC.Generics.M1 GHC.Generics.C c f)
- Web.Hyperbole.HyperView.Forms: instance forall k (f :: k -> *) (c :: GHC.Generics.Meta). Web.Hyperbole.HyperView.Forms.GFormParse f => Web.Hyperbole.HyperView.Forms.GFormParse (GHC.Generics.M1 GHC.Generics.C c f)
- Web.Hyperbole.HyperView.Forms: instance forall k (f :: k -> *) (d :: GHC.Generics.Meta). Web.Hyperbole.HyperView.Forms.GFieldsGen f => Web.Hyperbole.HyperView.Forms.GFieldsGen (GHC.Generics.M1 GHC.Generics.D d f)
- Web.Hyperbole.HyperView.Forms: instance forall k (f :: k -> *) (d :: GHC.Generics.Meta). Web.Hyperbole.HyperView.Forms.GFormParse f => Web.Hyperbole.HyperView.Forms.GFormParse (GHC.Generics.M1 GHC.Generics.D d f)
- Web.Hyperbole.HyperView.Forms: instance forall k (f :: k -> *) (g :: k -> *). (Web.Hyperbole.HyperView.Forms.GFieldsGen f, Web.Hyperbole.HyperView.Forms.GFieldsGen g) => Web.Hyperbole.HyperView.Forms.GFieldsGen (f GHC.Generics.:*: g)
- Web.Hyperbole.HyperView.Forms: instance forall k (f :: k -> *) (g :: k -> *). (Web.Hyperbole.HyperView.Forms.GFormParse f, Web.Hyperbole.HyperView.Forms.GFormParse g) => Web.Hyperbole.HyperView.Forms.GFormParse (f GHC.Generics.:*: g)
- Web.Hyperbole.HyperView.Forms: newtype () => Form
- Web.Hyperbole.HyperView.Input: [$sel:defaultOption:Option] :: Option id opt -> opt
- Web.Hyperbole.HyperView.Input: [$sel:id:Option] :: Option id opt -> id
- Web.Hyperbole.HyperView.Input: instance (Web.Hyperbole.Data.Param.ToParam id, Web.Hyperbole.Data.Param.ToParam opt, Web.Hyperbole.Data.Param.FromParam id, Web.Hyperbole.Data.Param.FromParam opt) => Web.Hyperbole.View.ViewId.ViewId (Web.Hyperbole.HyperView.Input.Option id opt)
- Web.Hyperbole.HyperView.Input: instance GHC.Generics.Generic (Web.Hyperbole.HyperView.Input.Option id opt)
- Web.Hyperbole.HyperView.Types: instance GHC.Generics.Generic (Web.Hyperbole.HyperView.Types.Action ())
- Web.Hyperbole.HyperView.Types: instance GHC.Generics.Generic (Web.Hyperbole.HyperView.Types.Action (Web.Hyperbole.HyperView.Types.Root views))
- Web.Hyperbole.HyperView.Types: instance GHC.Generics.Generic (Web.Hyperbole.HyperView.Types.Root views)
- Web.Hyperbole.HyperView.Types: instance GHC.Generics.Generic Web.Hyperbole.HyperView.Types.ConcurrencyMode
- Web.Hyperbole.Route: instance Web.Hyperbole.Route.GenRoute GHC.Generics.U1
- Web.Hyperbole.Route: instance Web.Hyperbole.Route.Route GHC.Base.String
- Web.Hyperbole.Route: instance Web.Hyperbole.Route.Route a => Web.Hyperbole.Route.Route (GHC.Maybe.Maybe a)
- Web.Hyperbole.Route: instance Web.Hyperbole.Route.Route sub => Web.Hyperbole.Route.GenRoute (GHC.Generics.K1 GHC.Generics.R sub)
- Web.Hyperbole.Route: instance forall k (a :: k -> *) (b :: k -> *). (Web.Hyperbole.Route.GenRoute a, Web.Hyperbole.Route.GenRoute b) => Web.Hyperbole.Route.GenRoute (a GHC.Generics.:*: b)
- Web.Hyperbole.Route: instance forall k (a :: k -> *) (b :: k -> *). (Web.Hyperbole.Route.GenRoute a, Web.Hyperbole.Route.GenRoute b) => Web.Hyperbole.Route.GenRoute (a GHC.Generics.:+: b)
- Web.Hyperbole.Route: instance forall k (c :: GHC.Generics.Meta) (f :: k -> *). (GHC.Generics.Constructor c, Web.Hyperbole.Route.GenRoute f) => Web.Hyperbole.Route.GenRoute (GHC.Generics.M1 GHC.Generics.C c f)
- Web.Hyperbole.Route: instance forall k (f :: k -> *) (c :: GHC.Generics.Meta). Web.Hyperbole.Route.GenRoute f => Web.Hyperbole.Route.GenRoute (GHC.Generics.M1 GHC.Generics.D c f)
- Web.Hyperbole.Route: instance forall k (f :: k -> *) (c :: GHC.Generics.Meta). Web.Hyperbole.Route.GenRoute f => Web.Hyperbole.Route.GenRoute (GHC.Generics.M1 GHC.Generics.S c f)
- Web.Hyperbole.Server.Handler: instance (Web.Hyperbole.HyperView.Types.HyperView view es, Web.Hyperbole.Data.Encoded.ToEncoded (Web.Hyperbole.View.ViewId.ViewState view), Web.Hyperbole.Data.Encoded.FromEncoded (Web.Hyperbole.View.ViewId.ViewState view), Web.Hyperbole.Server.Handler.RunHandlers views es) => Web.Hyperbole.Server.Handler.RunHandlers (view : views) es
- Web.Hyperbole.Server.Message: [$sel:body:Message] :: Message -> MessageBody
- Web.Hyperbole.Server.Message: [$sel:event:Message] :: Message -> Event TargetViewId Encoded Encoded
- Web.Hyperbole.Server.Message: [$sel:messageType:Message] :: Message -> Text
- Web.Hyperbole.Server.Message: [$sel:metadata:Message] :: Message -> Metadata
- Web.Hyperbole.Server.Message: [$sel:requestId:Message] :: Message -> RequestId
- Web.Hyperbole.Server.Message: [$sel:value:MessageBody] :: MessageBody -> ByteString
- Web.Hyperbole.Server.Message: instance GHC.Base.Monoid Web.Hyperbole.Server.Message.Metadata
- Web.Hyperbole.Server.Message: instance GHC.Base.Semigroup Web.Hyperbole.Server.Message.Metadata
- Web.Hyperbole.Server.Message: instance GHC.Exception.Type.Exception Web.Hyperbole.Server.Message.MessageError
- Web.Hyperbole.Server.Message: instance GHC.Generics.Generic Web.Hyperbole.Server.Message.Metadata
- Web.Hyperbole.Server.Message: instance GHC.Show.Show Web.Hyperbole.Server.Message.Message
- Web.Hyperbole.Server.Message: instance GHC.Show.Show Web.Hyperbole.Server.Message.MessageBody
- Web.Hyperbole.Server.Message: instance GHC.Show.Show Web.Hyperbole.Server.Message.MessageError
- Web.Hyperbole.Server.Message: instance GHC.Show.Show Web.Hyperbole.Server.Message.Metadata
- Web.Hyperbole.Server.Options: [$sel:serverError:ServerOptions] :: ServerOptions -> ResponseError -> ServerError
- Web.Hyperbole.Server.Options: [$sel:toDocument:ServerOptions] :: ServerOptions -> ByteString -> ByteString
- Web.Hyperbole.Server.Socket: [$sel:request:SocketRequest] :: SocketRequest -> Maybe Request
- Web.Hyperbole.Server.Socket: instance Data.String.IsString Web.Hyperbole.Server.Socket.Command
- Web.Hyperbole.Types.Client: [$sel:pageTitle:Client] :: Client -> Maybe Text
- Web.Hyperbole.Types.Client: [$sel:query:Client] :: Client -> Maybe QueryData
- Web.Hyperbole.Types.Client: [$sel:requestId:Client] :: Client -> RequestId
- Web.Hyperbole.Types.Client: [$sel:session:Client] :: Client -> Cookies
- Web.Hyperbole.Types.Event: [$sel:action:Event] :: Event id act st -> act
- Web.Hyperbole.Types.Event: [$sel:encoded:TargetViewId] :: TargetViewId -> Encoded
- Web.Hyperbole.Types.Event: [$sel:state:Event] :: Event id act st -> st
- Web.Hyperbole.Types.Event: [$sel:viewId:Event] :: Event id act st -> id
- Web.Hyperbole.Types.Event: instance (GHC.Show.Show act, GHC.Show.Show id, GHC.Show.Show st) => GHC.Show.Show (Web.Hyperbole.Types.Event.Event id act st)
- Web.Hyperbole.Types.Event: instance GHC.Show.Show Web.Hyperbole.Types.Event.TargetViewId
- Web.Hyperbole.Types.Request: [$sel:body:Request] :: Request -> ByteString
- Web.Hyperbole.Types.Request: [$sel:cookies:Request] :: Request -> Cookies
- Web.Hyperbole.Types.Request: [$sel:event:Request] :: Request -> Maybe (Event TargetViewId Encoded Encoded)
- Web.Hyperbole.Types.Request: [$sel:host:Request] :: Request -> Host
- Web.Hyperbole.Types.Request: [$sel:method:Request] :: Request -> Method
- Web.Hyperbole.Types.Request: [$sel:path:Request] :: Request -> Path
- Web.Hyperbole.Types.Request: [$sel:query:Request] :: Request -> Query
- Web.Hyperbole.Types.Request: [$sel:requestId:Request] :: Request -> RequestId
- Web.Hyperbole.Types.Request: [$sel:text:Host] :: Host -> ByteString
- Web.Hyperbole.Types.Request: instance GHC.Show.Show Web.Hyperbole.Types.Request.Host
- Web.Hyperbole.Types.Request: instance GHC.Show.Show Web.Hyperbole.Types.Request.Request
- Web.Hyperbole.Types.Request: instance GHC.Show.Show Web.Hyperbole.Types.Request.RequestId
- Web.Hyperbole.Types.Response: [$sel:body:ServerError] :: ServerError -> Body
- Web.Hyperbole.Types.Response: [$sel:body:ViewUpdate] :: ViewUpdate -> Body
- Web.Hyperbole.Types.Response: [$sel:message:ServerError] :: ServerError -> Text
- Web.Hyperbole.Types.Response: [$sel:viewId:ViewUpdate] :: ViewUpdate -> TargetViewId
- Web.Hyperbole.Types.Response: instance Data.String.IsString Web.Hyperbole.Types.Response.ResponseError
- Web.Hyperbole.Types.Response: instance GHC.Show.Show Web.Hyperbole.Types.Response.ResponseError
- Web.Hyperbole.View: [$sel:dataCell:TableColumn] :: TableColumn c dt -> dt -> View c ()
- Web.Hyperbole.View: [$sel:headCell:TableColumn] :: TableColumn c dt -> TableHead c ()
- Web.Hyperbole.View.Tag: [$sel:dataCell:TableColumn] :: TableColumn c dt -> dt -> View c ()
- Web.Hyperbole.View.Tag: [$sel:headCell:TableColumn] :: TableColumn c dt -> TableHead c ()
- Web.Hyperbole.View.Tag: instance GHC.Base.Applicative (Web.Hyperbole.View.Tag.ListItem c)
- Web.Hyperbole.View.Tag: instance GHC.Base.Applicative (Web.Hyperbole.View.Tag.Table c)
- Web.Hyperbole.View.Tag: instance GHC.Base.Applicative (Web.Hyperbole.View.Tag.TableColumns c dt)
- Web.Hyperbole.View.Tag: instance GHC.Base.Applicative (Web.Hyperbole.View.Tag.TableHead id)
- Web.Hyperbole.View.Tag: instance GHC.Base.Functor (Web.Hyperbole.View.Tag.ListItem c)
- Web.Hyperbole.View.Tag: instance GHC.Base.Functor (Web.Hyperbole.View.Tag.Table c)
- Web.Hyperbole.View.Tag: instance GHC.Base.Functor (Web.Hyperbole.View.Tag.TableColumns c dt)
- Web.Hyperbole.View.Tag: instance GHC.Base.Functor (Web.Hyperbole.View.Tag.TableHead id)
- Web.Hyperbole.View.Tag: instance GHC.Base.Monad (Web.Hyperbole.View.Tag.ListItem c)
- Web.Hyperbole.View.Tag: instance GHC.Base.Monad (Web.Hyperbole.View.Tag.Table c)
- Web.Hyperbole.View.Tag: instance GHC.Base.Monad (Web.Hyperbole.View.Tag.TableColumns c dt)
- Web.Hyperbole.View.Tag: instance GHC.Base.Monad (Web.Hyperbole.View.Tag.TableHead id)
- Web.Hyperbole.View.Types: [$sel:html:View] :: View c a -> Eff '[Reader (c, ViewState c)] (Html a)
- Web.Hyperbole.View.Types: instance (Web.Hyperbole.View.ViewId.ViewId a, Web.Hyperbole.Data.Param.FromParam a, Web.Hyperbole.Data.Param.ToParam a) => Web.Hyperbole.View.ViewId.ViewId (Web.Hyperbole.View.Types.ChildView a)
- Web.Hyperbole.View.Types: instance Data.String.IsString (Web.Hyperbole.View.Types.View c ())
- Web.Hyperbole.View.Types: instance GHC.Base.Applicative (Web.Hyperbole.View.Types.View ctx)
- Web.Hyperbole.View.Types: instance GHC.Base.Functor (Web.Hyperbole.View.Types.View c)
- Web.Hyperbole.View.Types: instance GHC.Base.Monad (Web.Hyperbole.View.Types.View ctx)
- Web.Hyperbole.View.Types: instance GHC.Generics.Generic (Web.Hyperbole.View.Types.ChildView a)
+ Web.Hyperbole: ($dmbaseRoute) :: (Route a, Generic a, GenRoute (Rep a)) => Maybe a
+ Web.Hyperbole: ($dmcookiePath) :: Session a => Maybe Path
+ Web.Hyperbole: ($dmcookieSecure) :: Session a => Bool
+ Web.Hyperbole: ($dmdef) :: (Default a, Generic a, GDefault (Rep a)) => a
+ Web.Hyperbole: ($dmfromField) :: (FromField a, FromJSON a) => Maybe FormParam -> Either String a
+ Web.Hyperbole: ($dmfromForm) :: (FromForm form, Generic form, GFormParse (Rep form)) => Form -> Either String form
+ Web.Hyperbole: ($dmfromFormF) :: (FromFormF f, Generic (f Identity), GFormParse (Rep (f Identity))) => Form -> Either String (f Identity)
+ Web.Hyperbole: ($dmgenFields) :: (GenFields f form, Generic (form f), GFieldsGen (Rep (form f))) => form f
+ Web.Hyperbole: ($dmmatchRoute) :: (Route a, Generic a, GenRoute (Rep a)) => Path -> Maybe a
+ Web.Hyperbole: ($dmparseAction) :: (ViewAction a, Generic a, GFromEncoded (Rep a)) => Encoded -> Either String a
+ Web.Hyperbole: ($dmparseCookie) :: (Session a, FromJSON a) => CookieValue -> Either String a
+ Web.Hyperbole: ($dmparseInputValue) :: (InputValue a, FromJSON a) => Text -> Either String a
+ Web.Hyperbole: ($dmparseQuery) :: (FromQuery a, Generic a, GFromQuery (Rep a)) => QueryData -> Either String a
+ Web.Hyperbole: ($dmparseViewId) :: (ViewId a, Generic a, GFromEncoded (Rep a)) => Encoded -> Either String a
+ Web.Hyperbole: ($dmroutePath) :: (Route a, Generic a, Eq a, GenRoute (Rep a)) => a -> Path
+ Web.Hyperbole: ($dmsessionKey) :: (Session a, Generic a, GDatatypeName (Rep a)) => Key
+ Web.Hyperbole: ($dmtoAction) :: (ViewAction a, Generic a, GToEncoded (Rep a)) => a -> Encoded
+ Web.Hyperbole: ($dmtoCookie) :: (Session a, ToJSON a) => a -> CookieValue
+ Web.Hyperbole: ($dmtoQuery) :: (ToQuery a, Generic a, GToQuery (Rep a)) => a -> QueryData
+ Web.Hyperbole: ($dmtoViewId) :: (ViewId a, Generic a, GToEncoded (Rep a)) => a -> Encoded
+ Web.Hyperbole: -- setting this to something other than <tt>()</tt>
+ Web.Hyperbole: Form :: [Param] -> [FileParam] -> Form
+ Web.Hyperbole: UploadedFile :: FilePath -> Text -> Text -> UploadedFile
+ Web.Hyperbole: [contentType] :: UploadedFile -> Text
+ Web.Hyperbole: [cookies] :: Request -> Cookies
+ Web.Hyperbole: [dataCell] :: TableColumn c dt -> dt -> View c ()
+ Web.Hyperbole: [event] :: Request -> Maybe (Event TargetViewId Encoded Value)
+ Web.Hyperbole: [fileName] :: UploadedFile -> Text
+ Web.Hyperbole: [filePath] :: UploadedFile -> FilePath
+ Web.Hyperbole: [files] :: Form -> [FileParam]
+ Web.Hyperbole: [form] :: Request -> Form
+ Web.Hyperbole: [headCell] :: TableColumn c dt -> TableHead c ()
+ Web.Hyperbole: [host] :: Request -> Host
+ Web.Hyperbole: [html] :: View c a -> Eff '[Reader (c, ViewState c)] (Html a)
+ Web.Hyperbole: [input] :: Request -> Text
+ Web.Hyperbole: [method] :: Request -> Method
+ Web.Hyperbole: [params] :: Form -> [Param]
+ Web.Hyperbole: [path] :: Request -> Path
+ Web.Hyperbole: [query] :: Request -> Query
+ Web.Hyperbole: [requestId] :: Request -> RequestId
+ Web.Hyperbole: [value] :: FieldName (a :: k) -> Text
+ Web.Hyperbole: class FromField a
+ Web.Hyperbole: class InputValue a
+ Web.Hyperbole: data Form
+ Web.Hyperbole: data UploadedFile
+ Web.Hyperbole: fileInput :: View (Input id a) ()
+ Web.Hyperbole: fromField :: FromField a => Maybe FormParam -> Either String a
+ Web.Hyperbole: html :: View c a -> Eff '[Reader (c, ViewState c)] (Html a)
+ Web.Hyperbole: inputValue :: forall a (es :: [Effect]). (InputValue a, Hyperbole :> es) => Eff es a
+ Web.Hyperbole: lookupField :: ParamKey -> Form -> Maybe FormParam
+ Web.Hyperbole: parseField :: FromField a => ParamKey -> Form -> Either String a
+ Web.Hyperbole: parseInputValue :: InputValue a => Text -> Either String a
+ Web.Hyperbole: type Rep a :: Type -> Type;
+ Web.Hyperbole.Application: [parseRequestBody] :: ServerOptions -> ParseRequestBodyOptions
+ Web.Hyperbole.Application: [serverError] :: ServerOptions -> ResponseError -> ServerError
+ Web.Hyperbole.Application: [toDocument] :: ServerOptions -> ByteString -> ByteString
+ Web.Hyperbole.Application: defaultParseRequestBodyOptions :: ParseRequestBodyOptions
+ Web.Hyperbole.Data.Argument: JSON :: Value -> Argument
+ Web.Hyperbole.Data.Argument: argumentParser :: Parser Argument
+ Web.Hyperbole.Data.Argument: data Argument
+ Web.Hyperbole.Data.Argument: decodeArgument :: FromJSON a => Text -> Either String a
+ Web.Hyperbole.Data.Argument: decodeToArgument :: Text -> Either String Argument
+ Web.Hyperbole.Data.Argument: encodeArgument :: ToJSON a => a -> Text
+ Web.Hyperbole.Data.Argument: encodeFromArgument :: Argument -> Text
+ Web.Hyperbole.Data.Argument: encodeJSON :: Value -> Text
+ Web.Hyperbole.Data.Argument: instance GHC.Classes.Eq Web.Hyperbole.Data.Argument.Argument
+ Web.Hyperbole.Data.Argument: instance GHC.Classes.Ord Web.Hyperbole.Data.Argument.Argument
+ Web.Hyperbole.Data.Argument: instance GHC.Internal.Generics.Generic Web.Hyperbole.Data.Argument.Argument
+ Web.Hyperbole.Data.Argument: instance GHC.Internal.Show.Show Web.Hyperbole.Data.Argument.Argument
+ Web.Hyperbole.Data.Argument: parseArgument :: FromJSON a => Argument -> Either String a
+ Web.Hyperbole.Data.Argument: toArgument :: ToJSON a => a -> Argument
+ Web.Hyperbole.Data.Cookie: [key] :: Cookie -> Key
+ Web.Hyperbole.Data.Cookie: [path] :: Cookie -> Maybe Path
+ Web.Hyperbole.Data.Cookie: [secure] :: Cookie -> Bool
+ Web.Hyperbole.Data.Cookie: [value] :: Cookie -> Maybe CookieValue
+ Web.Hyperbole.Data.Cookie: instance GHC.Internal.Base.Monoid Web.Hyperbole.Data.Cookie.Cookies
+ Web.Hyperbole.Data.Cookie: instance GHC.Internal.Base.Semigroup Web.Hyperbole.Data.Cookie.Cookies
+ Web.Hyperbole.Data.Cookie: instance GHC.Internal.Show.Show Web.Hyperbole.Data.Cookie.Cookie
+ Web.Hyperbole.Data.Cookie: instance GHC.Internal.Show.Show Web.Hyperbole.Data.Cookie.CookieValue
+ Web.Hyperbole.Data.Cookie: instance GHC.Internal.Show.Show Web.Hyperbole.Data.Cookie.Cookies
+ Web.Hyperbole.Data.Encoded: ($dmparseEncoded) :: (FromEncoded a, Generic a, GFromEncoded (Rep a)) => Encoded -> Either String a
+ Web.Hyperbole.Data.Encoded: ($dmtoEncoded) :: (ToEncoded a, Generic a, GToEncoded (Rep a)) => a -> Encoded
+ Web.Hyperbole.Data.Encoded: [text] :: ConName -> Text
+ Web.Hyperbole.Data.Encoded: instance Data.Aeson.Types.FromJSON.FromJSON a => Web.Hyperbole.Data.Encoded.GFromEncoded (GHC.Internal.Generics.K1 GHC.Internal.Generics.R a)
+ Web.Hyperbole.Data.Encoded: instance Data.Aeson.Types.ToJSON.ToJSON a => Web.Hyperbole.Data.Encoded.GToEncoded (GHC.Internal.Generics.K1 GHC.Internal.Generics.R a)
+ Web.Hyperbole.Data.Encoded: instance GHC.Internal.Base.Monoid Web.Hyperbole.Data.Encoded.ConName
+ Web.Hyperbole.Data.Encoded: instance GHC.Internal.Base.Monoid Web.Hyperbole.Data.Encoded.Encoded
+ Web.Hyperbole.Data.Encoded: instance GHC.Internal.Base.Semigroup Web.Hyperbole.Data.Encoded.ConName
+ Web.Hyperbole.Data.Encoded: instance GHC.Internal.Base.Semigroup Web.Hyperbole.Data.Encoded.Encoded
+ Web.Hyperbole.Data.Encoded: instance GHC.Internal.Data.String.IsString Web.Hyperbole.Data.Encoded.ConName
+ Web.Hyperbole.Data.Encoded: instance GHC.Internal.Show.Show Web.Hyperbole.Data.Encoded.ConName
+ Web.Hyperbole.Data.Encoded: instance GHC.Internal.Show.Show Web.Hyperbole.Data.Encoded.Encoded
+ Web.Hyperbole.Data.Encoded: instance Web.Hyperbole.Data.Encoded.FromEncoded Web.Hyperbole.Data.Argument.Argument
+ Web.Hyperbole.Data.Encoded: instance Web.Hyperbole.Data.Encoded.GFromEncoded GHC.Internal.Generics.U1
+ Web.Hyperbole.Data.Encoded: instance Web.Hyperbole.Data.Encoded.GToEncoded GHC.Internal.Generics.U1
+ Web.Hyperbole.Data.Encoded: instance Web.Hyperbole.Data.Encoded.ToEncoded Web.Hyperbole.Data.Argument.Argument
+ Web.Hyperbole.Data.Encoded: instance forall k (c :: GHC.Internal.Generics.Meta) (f :: k -> *). (GHC.Internal.Generics.Constructor c, Web.Hyperbole.Data.Encoded.GFromEncoded f) => Web.Hyperbole.Data.Encoded.GFromEncoded (GHC.Internal.Generics.M1 GHC.Internal.Generics.C c f)
+ Web.Hyperbole.Data.Encoded: instance forall k (c :: GHC.Internal.Generics.Meta) (f :: k -> *). (GHC.Internal.Generics.Constructor c, Web.Hyperbole.Data.Encoded.GToEncoded f) => Web.Hyperbole.Data.Encoded.GToEncoded (GHC.Internal.Generics.M1 GHC.Internal.Generics.C c f)
+ Web.Hyperbole.Data.Encoded: instance forall k (f :: k -> *) (d :: GHC.Internal.Generics.Meta). Web.Hyperbole.Data.Encoded.GFromEncoded f => Web.Hyperbole.Data.Encoded.GFromEncoded (GHC.Internal.Generics.M1 GHC.Internal.Generics.D d f)
+ Web.Hyperbole.Data.Encoded: instance forall k (f :: k -> *) (d :: GHC.Internal.Generics.Meta). Web.Hyperbole.Data.Encoded.GToEncoded f => Web.Hyperbole.Data.Encoded.GToEncoded (GHC.Internal.Generics.M1 GHC.Internal.Generics.D d f)
+ Web.Hyperbole.Data.Encoded: instance forall k (f :: k -> *) (g :: k -> *). (Web.Hyperbole.Data.Encoded.GFromEncoded f, Web.Hyperbole.Data.Encoded.GFromEncoded g) => Web.Hyperbole.Data.Encoded.GFromEncoded (f GHC.Internal.Generics.:*: g)
+ Web.Hyperbole.Data.Encoded: instance forall k (f :: k -> *) (g :: k -> *). (Web.Hyperbole.Data.Encoded.GFromEncoded f, Web.Hyperbole.Data.Encoded.GFromEncoded g) => Web.Hyperbole.Data.Encoded.GFromEncoded (f GHC.Internal.Generics.:+: g)
+ Web.Hyperbole.Data.Encoded: instance forall k (f :: k -> *) (g :: k -> *). (Web.Hyperbole.Data.Encoded.GToEncoded f, Web.Hyperbole.Data.Encoded.GToEncoded g) => Web.Hyperbole.Data.Encoded.GToEncoded (f GHC.Internal.Generics.:*: g)
+ Web.Hyperbole.Data.Encoded: instance forall k (f :: k -> *) (g :: k -> *). (Web.Hyperbole.Data.Encoded.GToEncoded f, Web.Hyperbole.Data.Encoded.GToEncoded g) => Web.Hyperbole.Data.Encoded.GToEncoded (f GHC.Internal.Generics.:+: g)
+ Web.Hyperbole.Data.Encoded: instance forall k (f :: k -> *) (s :: GHC.Internal.Generics.Meta). Web.Hyperbole.Data.Encoded.GFromEncoded f => Web.Hyperbole.Data.Encoded.GFromEncoded (GHC.Internal.Generics.M1 GHC.Internal.Generics.S s f)
+ Web.Hyperbole.Data.Encoded: instance forall k (f :: k -> *) (s :: GHC.Internal.Generics.Meta). Web.Hyperbole.Data.Encoded.GToEncoded f => Web.Hyperbole.Data.Encoded.GToEncoded (GHC.Internal.Generics.M1 GHC.Internal.Generics.S s f)
+ Web.Hyperbole.Data.QueryData: ($dmparseQuery) :: (FromQuery a, Generic a, GFromQuery (Rep a)) => QueryData -> Either String a
+ Web.Hyperbole.Data.QueryData: ($dmtoQuery) :: (ToQuery a, Generic a, GToQuery (Rep a)) => a -> QueryData
+ Web.Hyperbole.Data.QueryData: Param :: Text -> Param
+ Web.Hyperbole.Data.QueryData: [text] :: Param -> Text
+ Web.Hyperbole.Data.QueryData: decodeParam :: FromJSON a => Text -> Either String a
+ Web.Hyperbole.Data.QueryData: encodeParam :: ToJSON a => a -> Text
+ Web.Hyperbole.Data.QueryData: instance (GHC.Internal.Generics.Selector s, Data.Aeson.Types.FromJSON.FromJSON a, Data.Default.Internal.Default a) => Web.Hyperbole.Data.QueryData.GFromQuery (GHC.Internal.Generics.M1 GHC.Internal.Generics.S s (GHC.Internal.Generics.K1 GHC.Internal.Generics.R a))
+ Web.Hyperbole.Data.QueryData: instance (GHC.Internal.Generics.Selector s, Data.Aeson.Types.ToJSON.ToJSON a, GHC.Classes.Eq a, Data.Default.Internal.Default a) => Web.Hyperbole.Data.QueryData.GToQuery (GHC.Internal.Generics.M1 GHC.Internal.Generics.S s (GHC.Internal.Generics.K1 GHC.Internal.Generics.R a))
+ Web.Hyperbole.Data.QueryData: instance GHC.Classes.Eq Web.Hyperbole.Data.QueryData.Param
+ Web.Hyperbole.Data.QueryData: instance GHC.Classes.Ord Web.Hyperbole.Data.QueryData.Param
+ Web.Hyperbole.Data.QueryData: instance GHC.Internal.Base.Monoid Web.Hyperbole.Data.QueryData.QueryData
+ Web.Hyperbole.Data.QueryData: instance GHC.Internal.Base.Semigroup Web.Hyperbole.Data.QueryData.QueryData
+ Web.Hyperbole.Data.QueryData: instance GHC.Internal.Data.String.IsString Web.Hyperbole.Data.QueryData.Param
+ Web.Hyperbole.Data.QueryData: instance GHC.Internal.Generics.Selector s => Web.Hyperbole.Data.QueryData.GFromQuery (GHC.Internal.Generics.M1 GHC.Internal.Generics.S s (GHC.Internal.Generics.K1 GHC.Internal.Generics.R Data.Text.Internal.Text))
+ Web.Hyperbole.Data.QueryData: instance GHC.Internal.Generics.Selector s => Web.Hyperbole.Data.QueryData.GToQuery (GHC.Internal.Generics.M1 GHC.Internal.Generics.S s (GHC.Internal.Generics.K1 GHC.Internal.Generics.R Data.Text.Internal.Text))
+ Web.Hyperbole.Data.QueryData: instance GHC.Internal.IsList.IsList Web.Hyperbole.Data.QueryData.QueryData
+ Web.Hyperbole.Data.QueryData: instance GHC.Internal.Show.Show Web.Hyperbole.Data.QueryData.Param
+ Web.Hyperbole.Data.QueryData: instance GHC.Internal.Show.Show Web.Hyperbole.Data.QueryData.QueryData
+ Web.Hyperbole.Data.QueryData: instance forall k (f :: k -> *) (c :: GHC.Internal.Generics.Meta). Web.Hyperbole.Data.QueryData.GFromQuery f => Web.Hyperbole.Data.QueryData.GFromQuery (GHC.Internal.Generics.M1 GHC.Internal.Generics.C c f)
+ Web.Hyperbole.Data.QueryData: instance forall k (f :: k -> *) (d :: GHC.Internal.Generics.Meta). Web.Hyperbole.Data.QueryData.GFromQuery f => Web.Hyperbole.Data.QueryData.GFromQuery (GHC.Internal.Generics.M1 GHC.Internal.Generics.D d f)
+ Web.Hyperbole.Data.QueryData: instance forall k (f :: k -> *) (d :: GHC.Internal.Generics.Meta). Web.Hyperbole.Data.QueryData.GToQuery f => Web.Hyperbole.Data.QueryData.GToQuery (GHC.Internal.Generics.M1 GHC.Internal.Generics.C d f)
+ Web.Hyperbole.Data.QueryData: instance forall k (f :: k -> *) (d :: GHC.Internal.Generics.Meta). Web.Hyperbole.Data.QueryData.GToQuery f => Web.Hyperbole.Data.QueryData.GToQuery (GHC.Internal.Generics.M1 GHC.Internal.Generics.D d f)
+ Web.Hyperbole.Data.QueryData: instance forall k (f :: k -> *) (g :: k -> *). (Web.Hyperbole.Data.QueryData.GFromQuery f, Web.Hyperbole.Data.QueryData.GFromQuery g) => Web.Hyperbole.Data.QueryData.GFromQuery (f GHC.Internal.Generics.:*: g)
+ Web.Hyperbole.Data.QueryData: instance forall k (f :: k -> *) (g :: k -> *). (Web.Hyperbole.Data.QueryData.GToQuery f, Web.Hyperbole.Data.QueryData.GToQuery g) => Web.Hyperbole.Data.QueryData.GToQuery (f GHC.Internal.Generics.:*: g)
+ Web.Hyperbole.Data.QueryData: newtype Param
+ Web.Hyperbole.Data.QueryData: parseParam :: FromJSON a => Value -> Either String a
+ Web.Hyperbole.Data.URI: [segments] :: Path -> [Segment]
+ Web.Hyperbole.Data.URI: [uri] :: Endpoint (a :: k) -> URI
+ Web.Hyperbole.Data.URI: instance GHC.Internal.Data.String.IsString Web.Hyperbole.Data.URI.Path
+ Web.Hyperbole.Data.URI: instance GHC.Internal.IsList.IsList Web.Hyperbole.Data.URI.Path
+ Web.Hyperbole.Data.URI: instance GHC.Internal.Show.Show Web.Hyperbole.Data.URI.Path
+ Web.Hyperbole.Data.URI: parseURI :: String -> Maybe URI
+ Web.Hyperbole.Document: instance GHC.Internal.Generics.Generic Web.Hyperbole.Document.DocumentHead
+ Web.Hyperbole.Effect.GenRandom: [value] :: Token (a :: k) -> Text
+ Web.Hyperbole.Effect.GenRandom: instance forall k (a :: k). GHC.Internal.Generics.Generic (Web.Hyperbole.Effect.GenRandom.Token a)
+ Web.Hyperbole.Effect.GenRandom: instance forall k (a :: k). GHC.Internal.Read.Read (Web.Hyperbole.Effect.GenRandom.Token a)
+ Web.Hyperbole.Effect.GenRandom: instance forall k (a :: k). GHC.Internal.Show.Show (Web.Hyperbole.Effect.GenRandom.Token a)
+ Web.Hyperbole.Effect.Hyperbole: request :: forall (es :: [Effect]). Hyperbole :> es => Eff es Request
+ Web.Hyperbole.Effect.Request: inputValue :: forall a (es :: [Effect]). (InputValue a, Hyperbole :> es) => Eff es a
+ Web.Hyperbole.Effect.Session: ($dmcookiePath) :: Session a => Maybe Path
+ Web.Hyperbole.Effect.Session: ($dmcookieSecure) :: Session a => Bool
+ Web.Hyperbole.Effect.Session: ($dmparseCookie) :: (Session a, FromJSON a) => CookieValue -> Either String a
+ Web.Hyperbole.Effect.Session: ($dmsessionKey) :: (Session a, Generic a, GDatatypeName (Rep a)) => Key
+ Web.Hyperbole.Effect.Session: ($dmtoCookie) :: (Session a, ToJSON a) => a -> CookieValue
+ Web.Hyperbole.Effect.Session: instance forall k (d :: GHC.Internal.Generics.Meta) (f :: k -> *). GHC.Internal.Generics.Datatype d => Web.Hyperbole.Effect.Session.GDatatypeName (GHC.Internal.Generics.M1 GHC.Internal.Generics.D d f)
+ Web.Hyperbole.HyperView.Event: instance GHC.Internal.Read.Read Web.Hyperbole.HyperView.Event.Key
+ Web.Hyperbole.HyperView.Event: instance GHC.Internal.Show.Show Web.Hyperbole.HyperView.Event.Key
+ Web.Hyperbole.HyperView.Forms: ($dmfromField) :: (FromField a, FromJSON a) => Maybe FormParam -> Either String a
+ Web.Hyperbole.HyperView.Forms: ($dmfromForm) :: (FromForm form, Generic form, GFormParse (Rep form)) => Form -> Either String form
+ Web.Hyperbole.HyperView.Forms: ($dmfromFormF) :: (FromFormF f, Generic (f Identity), GFormParse (Rep (f Identity))) => Form -> Either String (f Identity)
+ Web.Hyperbole.HyperView.Forms: ($dmgenFields) :: (GenFields f form, Generic (form f), GFieldsGen (Rep (form f))) => form f
+ Web.Hyperbole.HyperView.Forms: [id] :: Input id a -> id
+ Web.Hyperbole.HyperView.Forms: [inputName] :: Input id a -> FieldName a
+ Web.Hyperbole.HyperView.Forms: [value] :: FieldName (a :: k) -> Text
+ Web.Hyperbole.HyperView.Forms: class FromField a
+ Web.Hyperbole.HyperView.Forms: fileInput :: View (Input id a) ()
+ Web.Hyperbole.HyperView.Forms: fromField :: FromField a => Maybe FormParam -> Either String a
+ Web.Hyperbole.HyperView.Forms: instance (Data.Aeson.Types.FromJSON.FromJSON id, Data.Aeson.Types.FromJSON.FromJSON opt, Data.Aeson.Types.ToJSON.ToJSON id, Data.Aeson.Types.ToJSON.ToJSON opt) => Web.Hyperbole.View.ViewId.ViewId (Web.Hyperbole.HyperView.Forms.Radio id a opt)
+ Web.Hyperbole.HyperView.Forms: instance (GHC.Internal.Generics.Selector s, Web.Hyperbole.HyperView.Forms.FromField a) => Web.Hyperbole.HyperView.Forms.GFormParse (GHC.Internal.Generics.M1 GHC.Internal.Generics.S s (GHC.Internal.Generics.K1 GHC.Internal.Generics.R a))
+ Web.Hyperbole.HyperView.Forms: instance (GHC.Internal.Generics.Selector s, Web.Hyperbole.HyperView.Forms.GenField a) => Web.Hyperbole.HyperView.Forms.GFieldsGen (GHC.Internal.Generics.M1 GHC.Internal.Generics.S s (GHC.Internal.Generics.K1 GHC.Internal.Generics.R a))
+ Web.Hyperbole.HyperView.Forms: instance (Web.Hyperbole.HyperView.Forms.FromField a, Web.Hyperbole.HyperView.Forms.FromField b) => Web.Hyperbole.HyperView.Forms.FromField (GHC.Internal.Data.Either.Either a b)
+ Web.Hyperbole.HyperView.Forms: instance (Web.Hyperbole.View.ViewId.ViewId id, Data.Aeson.Types.FromJSON.FromJSON id) => Web.Hyperbole.View.ViewId.ViewId (Web.Hyperbole.HyperView.Forms.Input id a)
+ Web.Hyperbole.HyperView.Forms: instance GHC.Internal.Generics.Generic (Web.Hyperbole.HyperView.Forms.FormFields id)
+ Web.Hyperbole.HyperView.Forms: instance GHC.Internal.Generics.Generic (Web.Hyperbole.HyperView.Forms.Input id a)
+ Web.Hyperbole.HyperView.Forms: instance GHC.Internal.Generics.Generic (Web.Hyperbole.HyperView.Forms.Radio id a opt)
+ Web.Hyperbole.HyperView.Forms: instance GHC.Internal.Show.Show Web.Hyperbole.HyperView.Forms.InputType
+ Web.Hyperbole.HyperView.Forms: instance Web.Hyperbole.HyperView.Forms.FromField (GHC.Internal.Maybe.Maybe Data.ByteString.Internal.Type.ByteString)
+ Web.Hyperbole.HyperView.Forms: instance Web.Hyperbole.HyperView.Forms.FromField (GHC.Internal.Maybe.Maybe Data.Text.Internal.Text)
+ Web.Hyperbole.HyperView.Forms: instance Web.Hyperbole.HyperView.Forms.FromField (GHC.Internal.Maybe.Maybe GHC.Internal.Base.String)
+ Web.Hyperbole.HyperView.Forms: instance Web.Hyperbole.HyperView.Forms.FromField (GHC.Internal.Maybe.Maybe Web.Hyperbole.Types.Request.UploadedFile)
+ Web.Hyperbole.HyperView.Forms: instance Web.Hyperbole.HyperView.Forms.FromField Data.ByteString.Internal.Type.ByteString
+ Web.Hyperbole.HyperView.Forms: instance Web.Hyperbole.HyperView.Forms.FromField Data.Text.Internal.Text
+ Web.Hyperbole.HyperView.Forms: instance Web.Hyperbole.HyperView.Forms.FromField Data.Time.Clock.Internal.UTCTime.UTCTime
+ Web.Hyperbole.HyperView.Forms: instance Web.Hyperbole.HyperView.Forms.FromField GHC.Internal.Base.String
+ Web.Hyperbole.HyperView.Forms: instance Web.Hyperbole.HyperView.Forms.FromField GHC.Num.Integer.Integer
+ Web.Hyperbole.HyperView.Forms: instance Web.Hyperbole.HyperView.Forms.FromField GHC.Types.Bool
+ Web.Hyperbole.HyperView.Forms: instance Web.Hyperbole.HyperView.Forms.FromField GHC.Types.Char
+ Web.Hyperbole.HyperView.Forms: instance Web.Hyperbole.HyperView.Forms.FromField GHC.Types.Double
+ Web.Hyperbole.HyperView.Forms: instance Web.Hyperbole.HyperView.Forms.FromField GHC.Types.Float
+ Web.Hyperbole.HyperView.Forms: instance Web.Hyperbole.HyperView.Forms.FromField GHC.Types.Int
+ Web.Hyperbole.HyperView.Forms: instance Web.Hyperbole.HyperView.Forms.FromField Network.URI.URI
+ Web.Hyperbole.HyperView.Forms: instance Web.Hyperbole.HyperView.Forms.FromField Web.Hyperbole.Types.Request.UploadedFile
+ Web.Hyperbole.HyperView.Forms: instance Web.Hyperbole.HyperView.Forms.FromField a => Web.Hyperbole.HyperView.Forms.FromField (GHC.Internal.Maybe.Maybe a)
+ Web.Hyperbole.HyperView.Forms: instance Web.Hyperbole.HyperView.Forms.FromFormF form => Web.Hyperbole.HyperView.Forms.FromForm (form GHC.Internal.Data.Functor.Identity.Identity)
+ Web.Hyperbole.HyperView.Forms: instance Web.Hyperbole.HyperView.Forms.GFieldsGen GHC.Internal.Generics.U1
+ Web.Hyperbole.HyperView.Forms: instance Web.Hyperbole.HyperView.Forms.GenField (GHC.Internal.Maybe.Maybe a)
+ Web.Hyperbole.HyperView.Forms: instance forall k (a :: k). Data.Aeson.Types.FromJSON.FromJSON (Web.Hyperbole.HyperView.Forms.FieldName a)
+ Web.Hyperbole.HyperView.Forms: instance forall k (a :: k). Data.Aeson.Types.ToJSON.ToJSON (Web.Hyperbole.HyperView.Forms.FieldName a)
+ Web.Hyperbole.HyperView.Forms: instance forall k (a :: k). GHC.Internal.Base.Monoid (Web.Hyperbole.HyperView.Forms.Validated a)
+ Web.Hyperbole.HyperView.Forms: instance forall k (a :: k). GHC.Internal.Base.Semigroup (Web.Hyperbole.HyperView.Forms.Validated a)
+ Web.Hyperbole.HyperView.Forms: instance forall k (a :: k). GHC.Internal.Data.String.IsString (Web.Hyperbole.HyperView.Forms.FieldName a)
+ Web.Hyperbole.HyperView.Forms: instance forall k (a :: k). GHC.Internal.Show.Show (Web.Hyperbole.HyperView.Forms.FieldName a)
+ Web.Hyperbole.HyperView.Forms: instance forall k (a :: k). GHC.Internal.Show.Show (Web.Hyperbole.HyperView.Forms.Validated a)
+ Web.Hyperbole.HyperView.Forms: instance forall k (f :: k -> *) (c :: GHC.Internal.Generics.Meta). Web.Hyperbole.HyperView.Forms.GFieldsGen f => Web.Hyperbole.HyperView.Forms.GFieldsGen (GHC.Internal.Generics.M1 GHC.Internal.Generics.C c f)
+ Web.Hyperbole.HyperView.Forms: instance forall k (f :: k -> *) (c :: GHC.Internal.Generics.Meta). Web.Hyperbole.HyperView.Forms.GFormParse f => Web.Hyperbole.HyperView.Forms.GFormParse (GHC.Internal.Generics.M1 GHC.Internal.Generics.C c f)
+ Web.Hyperbole.HyperView.Forms: instance forall k (f :: k -> *) (d :: GHC.Internal.Generics.Meta). Web.Hyperbole.HyperView.Forms.GFieldsGen f => Web.Hyperbole.HyperView.Forms.GFieldsGen (GHC.Internal.Generics.M1 GHC.Internal.Generics.D d f)
+ Web.Hyperbole.HyperView.Forms: instance forall k (f :: k -> *) (d :: GHC.Internal.Generics.Meta). Web.Hyperbole.HyperView.Forms.GFormParse f => Web.Hyperbole.HyperView.Forms.GFormParse (GHC.Internal.Generics.M1 GHC.Internal.Generics.D d f)
+ Web.Hyperbole.HyperView.Forms: instance forall k (f :: k -> *) (g :: k -> *). (Web.Hyperbole.HyperView.Forms.GFieldsGen f, Web.Hyperbole.HyperView.Forms.GFieldsGen g) => Web.Hyperbole.HyperView.Forms.GFieldsGen (f GHC.Internal.Generics.:*: g)
+ Web.Hyperbole.HyperView.Forms: instance forall k (f :: k -> *) (g :: k -> *). (Web.Hyperbole.HyperView.Forms.GFormParse f, Web.Hyperbole.HyperView.Forms.GFormParse g) => Web.Hyperbole.HyperView.Forms.GFormParse (f GHC.Internal.Generics.:*: g)
+ Web.Hyperbole.HyperView.Forms: lookupField :: ParamKey -> Form -> Maybe FormParam
+ Web.Hyperbole.HyperView.Forms: parseField :: FromField a => ParamKey -> Form -> Either String a
+ Web.Hyperbole.HyperView.Input: ($dmparseInputValue) :: (InputValue a, FromJSON a) => Text -> Either String a
+ Web.Hyperbole.HyperView.Input: [defaultOption] :: Option id opt -> opt
+ Web.Hyperbole.HyperView.Input: [id] :: Option id opt -> id
+ Web.Hyperbole.HyperView.Input: class InputValue a
+ Web.Hyperbole.HyperView.Input: encodeOption :: ToJSON opt => opt -> Text
+ Web.Hyperbole.HyperView.Input: instance (Data.Aeson.Types.ToJSON.ToJSON id, Data.Aeson.Types.ToJSON.ToJSON opt, Data.Aeson.Types.FromJSON.FromJSON id, Data.Aeson.Types.FromJSON.FromJSON opt) => Web.Hyperbole.View.ViewId.ViewId (Web.Hyperbole.HyperView.Input.Option id opt)
+ Web.Hyperbole.HyperView.Input: instance GHC.Internal.Generics.Generic (Web.Hyperbole.HyperView.Input.Option id opt)
+ Web.Hyperbole.HyperView.Input: instance Web.Hyperbole.HyperView.Input.InputValue (GHC.Internal.Maybe.Maybe Data.Text.Internal.Text)
+ Web.Hyperbole.HyperView.Input: instance Web.Hyperbole.HyperView.Input.InputValue (GHC.Internal.Maybe.Maybe GHC.Internal.Base.String)
+ Web.Hyperbole.HyperView.Input: instance Web.Hyperbole.HyperView.Input.InputValue Data.Text.Internal.Text
+ Web.Hyperbole.HyperView.Input: instance Web.Hyperbole.HyperView.Input.InputValue GHC.Num.Integer.Integer
+ Web.Hyperbole.HyperView.Input: instance Web.Hyperbole.HyperView.Input.InputValue GHC.Types.Double
+ Web.Hyperbole.HyperView.Input: instance Web.Hyperbole.HyperView.Input.InputValue GHC.Types.Float
+ Web.Hyperbole.HyperView.Input: instance Web.Hyperbole.HyperView.Input.InputValue GHC.Types.Int
+ Web.Hyperbole.HyperView.Input: instance Web.Hyperbole.HyperView.Input.InputValue a => Web.Hyperbole.HyperView.Input.InputValue (GHC.Internal.Maybe.Maybe a)
+ Web.Hyperbole.HyperView.Input: parseInputValue :: InputValue a => Text -> Either String a
+ Web.Hyperbole.HyperView.Types: instance GHC.Internal.Generics.Generic (Web.Hyperbole.HyperView.Types.Action ())
+ Web.Hyperbole.HyperView.Types: instance GHC.Internal.Generics.Generic (Web.Hyperbole.HyperView.Types.Action (Web.Hyperbole.HyperView.Types.Root views))
+ Web.Hyperbole.HyperView.Types: instance GHC.Internal.Generics.Generic (Web.Hyperbole.HyperView.Types.Root views)
+ Web.Hyperbole.HyperView.Types: instance GHC.Internal.Generics.Generic Web.Hyperbole.HyperView.Types.ConcurrencyMode
+ Web.Hyperbole.Route: ($dmbaseRoute) :: (Route a, Generic a, GenRoute (Rep a)) => Maybe a
+ Web.Hyperbole.Route: ($dmmatchRoute) :: (Route a, Generic a, GenRoute (Rep a)) => Path -> Maybe a
+ Web.Hyperbole.Route: ($dmroutePath) :: (Route a, Generic a, Eq a, GenRoute (Rep a)) => a -> Path
+ Web.Hyperbole.Route: instance Web.Hyperbole.Route.GenRoute GHC.Internal.Generics.U1
+ Web.Hyperbole.Route: instance Web.Hyperbole.Route.Route GHC.Internal.Base.String
+ Web.Hyperbole.Route: instance Web.Hyperbole.Route.Route a => Web.Hyperbole.Route.Route (GHC.Internal.Maybe.Maybe a)
+ Web.Hyperbole.Route: instance Web.Hyperbole.Route.Route sub => Web.Hyperbole.Route.GenRoute (GHC.Internal.Generics.K1 GHC.Internal.Generics.R sub)
+ Web.Hyperbole.Route: instance forall k (a :: k -> *) (b :: k -> *). (Web.Hyperbole.Route.GenRoute a, Web.Hyperbole.Route.GenRoute b) => Web.Hyperbole.Route.GenRoute (a GHC.Internal.Generics.:*: b)
+ Web.Hyperbole.Route: instance forall k (a :: k -> *) (b :: k -> *). (Web.Hyperbole.Route.GenRoute a, Web.Hyperbole.Route.GenRoute b) => Web.Hyperbole.Route.GenRoute (a GHC.Internal.Generics.:+: b)
+ Web.Hyperbole.Route: instance forall k (c :: GHC.Internal.Generics.Meta) (f :: k -> *). (GHC.Internal.Generics.Constructor c, Web.Hyperbole.Route.GenRoute f) => Web.Hyperbole.Route.GenRoute (GHC.Internal.Generics.M1 GHC.Internal.Generics.C c f)
+ Web.Hyperbole.Route: instance forall k (f :: k -> *) (c :: GHC.Internal.Generics.Meta). Web.Hyperbole.Route.GenRoute f => Web.Hyperbole.Route.GenRoute (GHC.Internal.Generics.M1 GHC.Internal.Generics.D c f)
+ Web.Hyperbole.Route: instance forall k (f :: k -> *) (c :: GHC.Internal.Generics.Meta). Web.Hyperbole.Route.GenRoute f => Web.Hyperbole.Route.GenRoute (GHC.Internal.Generics.M1 GHC.Internal.Generics.S c f)
+ Web.Hyperbole.Server.Handler: instance (Web.Hyperbole.HyperView.Types.HyperView view es, Data.Aeson.Types.ToJSON.ToJSON (Web.Hyperbole.View.ViewId.ViewState view), Data.Aeson.Types.FromJSON.FromJSON (Web.Hyperbole.View.ViewId.ViewState view), Web.Hyperbole.Server.Handler.RunHandlers views es) => Web.Hyperbole.Server.Handler.RunHandlers (view : views) es
+ Web.Hyperbole.Server.Handler: parseState :: FromJSON a => Value -> Either String a
+ Web.Hyperbole.Server.Message: [body] :: Message -> MessageBody
+ Web.Hyperbole.Server.Message: [event] :: Message -> Event TargetViewId Encoded Value
+ Web.Hyperbole.Server.Message: [messageType] :: Message -> Text
+ Web.Hyperbole.Server.Message: [metadata] :: Message -> Metadata
+ Web.Hyperbole.Server.Message: [requestId] :: Message -> RequestId
+ Web.Hyperbole.Server.Message: [value] :: MessageBody -> ByteString
+ Web.Hyperbole.Server.Message: instance GHC.Internal.Base.Monoid Web.Hyperbole.Server.Message.Metadata
+ Web.Hyperbole.Server.Message: instance GHC.Internal.Base.Semigroup Web.Hyperbole.Server.Message.Metadata
+ Web.Hyperbole.Server.Message: instance GHC.Internal.Exception.Type.Exception Web.Hyperbole.Server.Message.MessageError
+ Web.Hyperbole.Server.Message: instance GHC.Internal.Generics.Generic Web.Hyperbole.Server.Message.Metadata
+ Web.Hyperbole.Server.Message: instance GHC.Internal.Show.Show Web.Hyperbole.Server.Message.Message
+ Web.Hyperbole.Server.Message: instance GHC.Internal.Show.Show Web.Hyperbole.Server.Message.MessageBody
+ Web.Hyperbole.Server.Message: instance GHC.Internal.Show.Show Web.Hyperbole.Server.Message.MessageError
+ Web.Hyperbole.Server.Message: instance GHC.Internal.Show.Show Web.Hyperbole.Server.Message.Metadata
+ Web.Hyperbole.Server.Options: [parseRequestBody] :: ServerOptions -> ParseRequestBodyOptions
+ Web.Hyperbole.Server.Options: [serverError] :: ServerOptions -> ResponseError -> ServerError
+ Web.Hyperbole.Server.Options: [toDocument] :: ServerOptions -> ByteString -> ByteString
+ Web.Hyperbole.Server.Options: defaultParseRequestBodyOptions :: ParseRequestBodyOptions
+ Web.Hyperbole.Server.Socket: [request] :: SocketRequest -> Maybe Request
+ Web.Hyperbole.Server.Socket: instance GHC.Internal.Data.String.IsString Web.Hyperbole.Server.Socket.Command
+ Web.Hyperbole.Server.Uploads: withPostBody :: forall (es :: [Effect]) a. IOE :> es => ParseRequestBodyOptions -> Request -> ([Param] -> [FileParam] -> Eff es a) -> Eff es a
+ Web.Hyperbole.Types.Client: [pageTitle] :: Client -> Maybe Text
+ Web.Hyperbole.Types.Client: [query] :: Client -> Maybe QueryData
+ Web.Hyperbole.Types.Client: [requestId] :: Client -> RequestId
+ Web.Hyperbole.Types.Client: [session] :: Client -> Cookies
+ Web.Hyperbole.Types.Event: [action] :: Event id act st -> act
+ Web.Hyperbole.Types.Event: [encoded] :: TargetViewId -> Encoded
+ Web.Hyperbole.Types.Event: [state] :: Event id act st -> st
+ Web.Hyperbole.Types.Event: [viewId] :: Event id act st -> id
+ Web.Hyperbole.Types.Event: instance (GHC.Internal.Show.Show act, GHC.Internal.Show.Show id, GHC.Internal.Show.Show st) => GHC.Internal.Show.Show (Web.Hyperbole.Types.Event.Event id act st)
+ Web.Hyperbole.Types.Event: instance GHC.Internal.Show.Show Web.Hyperbole.Types.Event.TargetViewId
+ Web.Hyperbole.Types.Request: FileParam :: UploadedFile -> FormParam
+ Web.Hyperbole.Types.Request: Form :: [Param] -> [FileParam] -> Form
+ Web.Hyperbole.Types.Request: FormParam :: Text -> FormParam
+ Web.Hyperbole.Types.Request: UploadedFile :: FilePath -> Text -> Text -> UploadedFile
+ Web.Hyperbole.Types.Request: [contentType] :: UploadedFile -> Text
+ Web.Hyperbole.Types.Request: [cookies] :: Request -> Cookies
+ Web.Hyperbole.Types.Request: [event] :: Request -> Maybe (Event TargetViewId Encoded Value)
+ Web.Hyperbole.Types.Request: [fileName] :: UploadedFile -> Text
+ Web.Hyperbole.Types.Request: [filePath] :: UploadedFile -> FilePath
+ Web.Hyperbole.Types.Request: [files] :: Form -> [FileParam]
+ Web.Hyperbole.Types.Request: [form] :: Request -> Form
+ Web.Hyperbole.Types.Request: [host] :: Request -> Host
+ Web.Hyperbole.Types.Request: [input] :: Request -> Text
+ Web.Hyperbole.Types.Request: [method] :: Request -> Method
+ Web.Hyperbole.Types.Request: [params] :: Form -> [Param]
+ Web.Hyperbole.Types.Request: [path] :: Request -> Path
+ Web.Hyperbole.Types.Request: [query] :: Request -> Query
+ Web.Hyperbole.Types.Request: [requestId] :: Request -> RequestId
+ Web.Hyperbole.Types.Request: [text] :: Host -> ByteString
+ Web.Hyperbole.Types.Request: data Form
+ Web.Hyperbole.Types.Request: data FormParam
+ Web.Hyperbole.Types.Request: data UploadedFile
+ Web.Hyperbole.Types.Request: instance GHC.Classes.Eq Web.Hyperbole.Types.Request.FormParam
+ Web.Hyperbole.Types.Request: instance GHC.Classes.Eq Web.Hyperbole.Types.Request.RequestId
+ Web.Hyperbole.Types.Request: instance GHC.Classes.Eq Web.Hyperbole.Types.Request.UploadedFile
+ Web.Hyperbole.Types.Request: instance GHC.Internal.Data.String.IsString Web.Hyperbole.Types.Request.FormParam
+ Web.Hyperbole.Types.Request: instance GHC.Internal.Show.Show Web.Hyperbole.Types.Request.Form
+ Web.Hyperbole.Types.Request: instance GHC.Internal.Show.Show Web.Hyperbole.Types.Request.FormParam
+ Web.Hyperbole.Types.Request: instance GHC.Internal.Show.Show Web.Hyperbole.Types.Request.Host
+ Web.Hyperbole.Types.Request: instance GHC.Internal.Show.Show Web.Hyperbole.Types.Request.Request
+ Web.Hyperbole.Types.Request: instance GHC.Internal.Show.Show Web.Hyperbole.Types.Request.RequestId
+ Web.Hyperbole.Types.Request: instance GHC.Internal.Show.Show Web.Hyperbole.Types.Request.UploadedFile
+ Web.Hyperbole.Types.Request: type File y = (ByteString, FileInfo y)
+ Web.Hyperbole.Types.Request: type FileParam = (ByteString, UploadedFile)
+ Web.Hyperbole.Types.Request: type Param = (ByteString, ByteString)
+ Web.Hyperbole.Types.Response: [body] :: ServerError -> Body
+ Web.Hyperbole.Types.Response: [message] :: ServerError -> Text
+ Web.Hyperbole.Types.Response: [viewId] :: ViewUpdate -> TargetViewId
+ Web.Hyperbole.Types.Response: instance GHC.Internal.Data.String.IsString Web.Hyperbole.Types.Response.ResponseError
+ Web.Hyperbole.Types.Response: instance GHC.Internal.Show.Show Web.Hyperbole.Types.Response.ResponseError
+ Web.Hyperbole.View: [dataCell] :: TableColumn c dt -> dt -> View c ()
+ Web.Hyperbole.View: [headCell] :: TableColumn c dt -> TableHead c ()
+ Web.Hyperbole.View.Tag: [dataCell] :: TableColumn c dt -> dt -> View c ()
+ Web.Hyperbole.View.Tag: [headCell] :: TableColumn c dt -> TableHead c ()
+ Web.Hyperbole.View.Tag: instance GHC.Internal.Base.Applicative (Web.Hyperbole.View.Tag.ListItem c)
+ Web.Hyperbole.View.Tag: instance GHC.Internal.Base.Applicative (Web.Hyperbole.View.Tag.Table c)
+ Web.Hyperbole.View.Tag: instance GHC.Internal.Base.Applicative (Web.Hyperbole.View.Tag.TableColumns c dt)
+ Web.Hyperbole.View.Tag: instance GHC.Internal.Base.Applicative (Web.Hyperbole.View.Tag.TableHead id)
+ Web.Hyperbole.View.Tag: instance GHC.Internal.Base.Functor (Web.Hyperbole.View.Tag.ListItem c)
+ Web.Hyperbole.View.Tag: instance GHC.Internal.Base.Functor (Web.Hyperbole.View.Tag.Table c)
+ Web.Hyperbole.View.Tag: instance GHC.Internal.Base.Functor (Web.Hyperbole.View.Tag.TableColumns c dt)
+ Web.Hyperbole.View.Tag: instance GHC.Internal.Base.Functor (Web.Hyperbole.View.Tag.TableHead id)
+ Web.Hyperbole.View.Tag: instance GHC.Internal.Base.Monad (Web.Hyperbole.View.Tag.ListItem c)
+ Web.Hyperbole.View.Tag: instance GHC.Internal.Base.Monad (Web.Hyperbole.View.Tag.Table c)
+ Web.Hyperbole.View.Tag: instance GHC.Internal.Base.Monad (Web.Hyperbole.View.Tag.TableColumns c dt)
+ Web.Hyperbole.View.Tag: instance GHC.Internal.Base.Monad (Web.Hyperbole.View.Tag.TableHead id)
+ Web.Hyperbole.View.Types: [html] :: View c a -> Eff '[Reader (c, ViewState c)] (Html a)
+ Web.Hyperbole.View.Types: instance (Web.Hyperbole.View.ViewId.ViewId a, Data.Aeson.Types.ToJSON.ToJSON a, Data.Aeson.Types.FromJSON.FromJSON a) => Web.Hyperbole.View.ViewId.ViewId (Web.Hyperbole.View.Types.ChildView a)
+ Web.Hyperbole.View.Types: instance GHC.Internal.Base.Applicative (Web.Hyperbole.View.Types.View ctx)
+ Web.Hyperbole.View.Types: instance GHC.Internal.Base.Functor (Web.Hyperbole.View.Types.View c)
+ Web.Hyperbole.View.Types: instance GHC.Internal.Base.Monad (Web.Hyperbole.View.Types.View ctx)
+ Web.Hyperbole.View.Types: instance GHC.Internal.Data.String.IsString (Web.Hyperbole.View.Types.View c ())
+ Web.Hyperbole.View.Types: instance GHC.Internal.Generics.Generic (Web.Hyperbole.View.Types.ChildView a)
+ Web.Hyperbole.View.ViewAction: ($dmparseAction) :: (ViewAction a, Generic a, GFromEncoded (Rep a)) => Encoded -> Either String a
+ Web.Hyperbole.View.ViewAction: ($dmtoAction) :: (ViewAction a, Generic a, GToEncoded (Rep a)) => a -> Encoded
+ Web.Hyperbole.View.ViewId: ($dmparseViewId) :: (ViewId a, Generic a, GFromEncoded (Rep a)) => Encoded -> Either String a
+ Web.Hyperbole.View.ViewId: ($dmtoViewId) :: (ViewId a, Generic a, GToEncoded (Rep a)) => a -> Encoded
+ Web.Hyperbole.View.ViewId: -- setting this to something other than <tt>()</tt>
+ Web.Hyperbole.View.ViewId: -- | Most hyperviews are stateless, but you can track internal state by
- Web.Hyperbole: FieldName :: Text -> FieldName a
+ Web.Hyperbole: FieldName :: Text -> FieldName (a :: k)
- Web.Hyperbole: Invalid :: Text -> Validated a
+ Web.Hyperbole: Invalid :: Text -> Validated (a :: k)
- Web.Hyperbole: NotInvalid :: Validated a
+ Web.Hyperbole: NotInvalid :: Validated (a :: k)
- Web.Hyperbole: Request :: Host -> Path -> Query -> ByteString -> Method -> Cookies -> Maybe (Event TargetViewId Encoded Encoded) -> RequestId -> Request
+ Web.Hyperbole: Request :: Host -> Path -> Query -> Method -> Cookies -> Maybe (Event TargetViewId Encoded Value) -> RequestId -> Form -> Text -> Request
- Web.Hyperbole: Valid :: Validated a
+ Web.Hyperbole: Valid :: Validated (a :: k)
- Web.Hyperbole: baseRoute :: (Route a, Generic a, GenRoute (Rep a)) => Maybe a
+ Web.Hyperbole: baseRoute :: Route a => Maybe a
- Web.Hyperbole: checkbox :: forall id a. Bool -> View (Input id a) ()
+ Web.Hyperbole: checkbox :: Bool -> View (Input id a) ()
- Web.Hyperbole: class () => (e :: Effect) :> (es :: [Effect])
+ Web.Hyperbole: class (e :: Effect) :> (es :: [Effect])
- Web.Hyperbole: class () => Default a
+ Web.Hyperbole: class Default a
- Web.Hyperbole: class FromForm (form :: Type)
+ Web.Hyperbole: class FromForm form
- Web.Hyperbole: class FromFormF (f :: (Type -> Type) -> Type)
+ Web.Hyperbole: class FromFormF (f :: Type -> Type -> Type)
- Web.Hyperbole: class () => FromJSON a
+ Web.Hyperbole: class FromJSON a
- Web.Hyperbole: class GenFields f (form :: (Type -> Type) -> Type)
+ Web.Hyperbole: class GenFields (f :: Type -> Type) (form :: Type -> Type -> Type)
- Web.Hyperbole: class () => Generic a where {
+ Web.Hyperbole: class Generic a where {
- Web.Hyperbole: class HasViewId m view
+ Web.Hyperbole: class HasViewId (m :: k -> Type) (view :: k)
- Web.Hyperbole: class (ViewId id, ViewAction (Action id), ConcurrencyValue (Concurrency id)) => HyperView id es where {
+ Web.Hyperbole: class (ViewId id, ViewAction Action id, ConcurrencyValue Concurrency id) => HyperView id (es :: [Effect]) where {
- Web.Hyperbole: class () => ToJSON a
+ Web.Hyperbole: class ToJSON a
- Web.Hyperbole: clearQuery :: Hyperbole :> es => Eff es ()
+ Web.Hyperbole: clearQuery :: forall (es :: [Effect]). Hyperbole :> es => Eff es ()
- Web.Hyperbole: context :: forall c. View c (c, ViewState c)
+ Web.Hyperbole: context :: View c (c, ViewState c)
- Web.Hyperbole: data () => Eff (es :: [Effect]) a
+ Web.Hyperbole: data Eff (es :: [Effect]) a
- Web.Hyperbole: data Hyperbole :: Effect
+ Web.Hyperbole: data Hyperbole (a :: Type -> Type) b
- Web.Hyperbole: data () => Identity a
+ Web.Hyperbole: data Identity a
- Web.Hyperbole: data () => URI
+ Web.Hyperbole: data URI
- Web.Hyperbole: data Validated a
+ Web.Hyperbole: data Validated (a :: k)
- Web.Hyperbole: deleteParam :: Hyperbole :> es => Param -> Eff es ()
+ Web.Hyperbole: deleteParam :: forall (es :: [Effect]). Hyperbole :> es => Param -> Eff es ()
- Web.Hyperbole: deleteSession :: forall a es. (Session a, Hyperbole :> es) => Eff es ()
+ Web.Hyperbole: deleteSession :: forall a (es :: [Effect]). (Session a, Hyperbole :> es) => Eff es ()
- Web.Hyperbole: dropdown :: forall opt id. ViewAction (Action id) => (opt -> Action id) -> opt -> View (Option id opt) () -> View id ()
+ Web.Hyperbole: dropdown :: forall opt id. (ViewAction (Action id), FromJSON opt) => Action id -> opt -> View (Option id opt) () -> View id ()
- Web.Hyperbole: execView :: forall c a. c -> ViewState c -> View c a -> Html a
+ Web.Hyperbole: execView :: c -> ViewState c -> View c a -> Html a
- Web.Hyperbole: field :: forall (id :: Type) (a :: Type). FieldName a -> View (Input id a) () -> View (FormFields id) ()
+ Web.Hyperbole: field :: forall id a. FieldName a -> View (Input id a) () -> View (FormFields id) ()
- Web.Hyperbole: fieldNames :: forall form. GenFields FieldName form => form FieldName
+ Web.Hyperbole: fieldNames :: GenFields (FieldName :: Type -> Type) form => form (FieldName :: Type -> Type)
- Web.Hyperbole: formData :: forall form es. (FromForm form, Hyperbole :> es) => Eff es form
+ Web.Hyperbole: formData :: forall form (es :: [Effect]). (FromForm form, Hyperbole :> es) => Eff es form
- Web.Hyperbole: fromForm :: (FromForm form, Generic form, GFormParse (Rep form)) => Form -> Either String form
+ Web.Hyperbole: fromForm :: FromForm form => Form -> Either String form
- Web.Hyperbole: fromFormF :: (FromFormF f, Generic (f Identity), GFormParse (Rep (f Identity))) => Form -> Either String (f Identity)
+ Web.Hyperbole: fromFormF :: FromFormF f => Form -> Either String (f Identity)
- Web.Hyperbole: genFields :: (GenFields f form, Generic (form f), GFieldsGen (Rep (form f))) => form f
+ Web.Hyperbole: genFields :: GenFields f form => form f
- Web.Hyperbole: hyper :: forall id ctx. (HyperViewHandled id ctx, ViewId id, ViewState id ~ (), ConcurrencyValue (Concurrency id)) => id -> View id () -> View ctx ()
+ Web.Hyperbole: hyper :: (HyperViewHandled id ctx, ViewId id, ViewState id ~ (), ConcurrencyValue (Concurrency id)) => id -> View id () -> View ctx ()
- Web.Hyperbole: hyperState :: forall id ctx. (HyperViewHandled id ctx, ViewId id, ToEncoded (ViewState id), ConcurrencyValue (Concurrency id)) => id -> ViewState id -> View id () -> View ctx ()
+ Web.Hyperbole: hyperState :: (HyperViewHandled id ctx, ViewId id, ToJSON (ViewState id), ConcurrencyValue (Concurrency id)) => id -> ViewState id -> View id () -> View ctx ()
- Web.Hyperbole: input :: forall id a. InputType -> View (Input id a) ()
+ Web.Hyperbole: input :: InputType -> View (Input id a) ()
- Web.Hyperbole: invalidText :: forall a id. Validated a -> View (Input id a) ()
+ Web.Hyperbole: invalidText :: Validated a -> View (Input id a) ()
- Web.Hyperbole: isInvalid :: Validated a -> Bool
+ Web.Hyperbole: isInvalid :: forall {k} (a :: k). Validated a -> Bool
- Web.Hyperbole: lookupParam :: (FromParam a, Hyperbole :> es) => Param -> Eff es (Maybe a)
+ Web.Hyperbole: lookupParam :: forall a (es :: [Effect]). (FromJSON a, Hyperbole :> es) => Param -> Eff es (Maybe a)
- Web.Hyperbole: lookupSession :: forall a es. (Session a, Hyperbole :> es) => Eff es (Maybe a)
+ Web.Hyperbole: lookupSession :: forall a (es :: [Effect]). (Session a, Hyperbole :> es) => Eff es (Maybe a)
- Web.Hyperbole: matchRoute :: (Route a, Generic a, GenRoute (Rep a)) => Path -> Maybe a
+ Web.Hyperbole: matchRoute :: Route a => Path -> Maybe a
- Web.Hyperbole: modifyQuery :: (ToQuery a, FromQuery a, Default a, Hyperbole :> es) => (a -> a) -> Eff es a
+ Web.Hyperbole: modifyQuery :: forall a (es :: [Effect]). (ToQuery a, FromQuery a, Default a, Hyperbole :> es) => (a -> a) -> Eff es a
- Web.Hyperbole: modifySession :: (Session a, Default a, Hyperbole :> es) => (a -> a) -> Eff es a
+ Web.Hyperbole: modifySession :: forall a (es :: [Effect]). (Session a, Default a, Hyperbole :> es) => (a -> a) -> Eff es a
- Web.Hyperbole: modifySession_ :: (Session a, Default a, Hyperbole :> es) => (a -> a) -> Eff es ()
+ Web.Hyperbole: modifySession_ :: forall a (es :: [Effect]). (Session a, Default a, Hyperbole :> es) => (a -> a) -> Eff es ()
- Web.Hyperbole: newtype FieldName a
+ Web.Hyperbole: newtype FieldName (a :: k)
- Web.Hyperbole: notFound :: Hyperbole :> es => Eff es a
+ Web.Hyperbole: notFound :: forall (es :: [Effect]) a. Hyperbole :> es => Eff es a
- Web.Hyperbole: onInput :: (ViewAction (Action id), Attributable a) => (Text -> Action id) -> DelayMs -> Attributes a -> Attributes a
+ Web.Hyperbole: onInput :: (ViewAction (Action id), Attributable a) => Action id -> DelayMs -> Attributes a -> Attributes a
- Web.Hyperbole: option :: forall opt id. (ViewAction (Action id), Eq opt, ToParam opt) => opt -> Text -> View (Option id opt) ()
+ Web.Hyperbole: option :: forall opt id. (ViewAction (Action id), Eq opt, ToJSON opt) => opt -> Text -> View (Option id opt) ()
- Web.Hyperbole: pageTitle :: Hyperbole :> es => Text -> Eff es ()
+ Web.Hyperbole: pageTitle :: forall (es :: [Effect]). Hyperbole :> es => Text -> Eff es ()
- Web.Hyperbole: param :: (FromParam a, Hyperbole :> es) => Param -> Eff es a
+ Web.Hyperbole: param :: forall a (es :: [Effect]). (FromJSON a, Hyperbole :> es) => Param -> Eff es a
- Web.Hyperbole: parseAction :: (ViewAction a, Generic a, GFromEncoded (Rep a)) => Encoded -> Either String a
+ Web.Hyperbole: parseAction :: ViewAction a => Encoded -> Either String a
- Web.Hyperbole: parseCookie :: (Session a, FromEncoded a) => CookieValue -> Either String a
+ Web.Hyperbole: parseCookie :: Session a => CookieValue -> Either String a
- Web.Hyperbole: parseQuery :: (FromQuery a, Generic a, GFromQuery (Rep a)) => QueryData -> Either String a
+ Web.Hyperbole: parseQuery :: FromQuery a => QueryData -> Either String a
- Web.Hyperbole: parseViewId :: (ViewId a, Generic a, GFromEncoded (Rep a)) => Encoded -> Either String a
+ Web.Hyperbole: parseViewId :: ViewId a => Encoded -> Either String a
- Web.Hyperbole: pushEvent :: (ToJSON a, Hyperbole :> es) => Text -> a -> Eff es ()
+ Web.Hyperbole: pushEvent :: forall a (es :: [Effect]). (ToJSON a, Hyperbole :> es) => Text -> a -> Eff es ()
- Web.Hyperbole: pushUpdate :: (Hyperbole :> es, ViewId id, ToEncoded (ViewState id), ConcurrencyValue (Concurrency id)) => View id () -> Eff (Reader id : (State (ViewState id) : es)) ()
+ Web.Hyperbole: pushUpdate :: forall (es :: [Effect]) id. (Hyperbole :> es, ViewId id, ToJSON (ViewState id), ConcurrencyValue (Concurrency id)) => View id () -> Eff (Reader id ': (State (ViewState id) ': es)) ()
- Web.Hyperbole: query :: (FromQuery a, Hyperbole :> es) => Eff es a
+ Web.Hyperbole: query :: forall a (es :: [Effect]). (FromQuery a, Hyperbole :> es) => Eff es a
- Web.Hyperbole: queryParams :: Hyperbole :> es => Eff es QueryData
+ Web.Hyperbole: queryParams :: forall (es :: [Effect]). Hyperbole :> es => Eff es QueryData
- Web.Hyperbole: radio :: forall id a opt. (Eq opt, ToParam opt) => opt -> View (Radio id a opt) ()
+ Web.Hyperbole: radio :: forall id a opt. (Eq opt, ToJSON opt) => opt -> View (Radio id a opt) ()
- Web.Hyperbole: redirect :: Hyperbole :> es => URI -> Eff es a
+ Web.Hyperbole: redirect :: forall (es :: [Effect]) a. Hyperbole :> es => URI -> Eff es a
- Web.Hyperbole: request :: Hyperbole :> es => Eff es Request
+ Web.Hyperbole: request :: forall (es :: [Effect]). Hyperbole :> es => Eff es Request
- Web.Hyperbole: respondError :: Hyperbole :> es => ResponseError -> Eff es a
+ Web.Hyperbole: respondError :: forall (es :: [Effect]) a. Hyperbole :> es => ResponseError -> Eff es a
- Web.Hyperbole: respondErrorView :: Hyperbole :> es => Text -> View () () -> Eff es a
+ Web.Hyperbole: respondErrorView :: forall (es :: [Effect]) a. Hyperbole :> es => Text -> View () () -> Eff es a
- Web.Hyperbole: routePath :: (Route a, Generic a, Eq a, GenRoute (Rep a)) => a -> Path
+ Web.Hyperbole: routePath :: Route a => a -> Path
- Web.Hyperbole: routeRequest :: (Hyperbole :> es, Route route) => (route -> Eff es Response) -> Eff es Response
+ Web.Hyperbole: routeRequest :: forall (es :: [Effect]) route. (Hyperbole :> es, Route route) => (route -> Eff es Response) -> Eff es Response
- Web.Hyperbole: runPage :: (Hyperbole :> es, RunHandlers views es) => Page es views -> Eff es Response
+ Web.Hyperbole: runPage :: forall (es :: [Effect]) (views :: [Type]). (Hyperbole :> es, RunHandlers views es) => Page es views -> Eff es Response
- Web.Hyperbole: saveSession :: forall a es. (Session a, Hyperbole :> es) => a -> Eff es ()
+ Web.Hyperbole: saveSession :: forall a (es :: [Effect]). (Session a, Hyperbole :> es) => a -> Eff es ()
- Web.Hyperbole: search :: ViewAction (Action id) => (Text -> Action id) -> DelayMs -> View id ()
+ Web.Hyperbole: search :: ViewAction (Action id) => Action id -> DelayMs -> View id ()
- Web.Hyperbole: select :: forall opt id a. Eq opt => opt -> View (Option id opt) () -> View (Input id a) ()
+ Web.Hyperbole: select :: Eq opt => opt -> View (Option id opt) () -> View (Input id a) ()
- Web.Hyperbole: session :: (Session a, Default a, Hyperbole :> es) => Eff es a
+ Web.Hyperbole: session :: forall a (es :: [Effect]). (Session a, Default a, Hyperbole :> es) => Eff es a
- Web.Hyperbole: sessionKey :: (Session a, Generic a, GDatatypeName (Rep a)) => Key
+ Web.Hyperbole: sessionKey :: Session a => Key
- Web.Hyperbole: setParam :: (ToParam a, Hyperbole :> es) => Param -> a -> Eff es ()
+ Web.Hyperbole: setParam :: forall a (es :: [Effect]). (ToJSON a, Hyperbole :> es) => Param -> a -> Eff es ()
- Web.Hyperbole: setQuery :: (ToQuery a, Hyperbole :> es) => a -> Eff es ()
+ Web.Hyperbole: setQuery :: forall a (es :: [Effect]). (ToQuery a, Hyperbole :> es) => a -> Eff es ()
- Web.Hyperbole: target :: forall id ctx. (HyperViewHandled id ctx, ViewId id) => id -> ViewState id -> View id () -> View ctx ()
+ Web.Hyperbole: target :: (HyperViewHandled id ctx, ViewId id) => id -> ViewState id -> View id () -> View ctx ()
- Web.Hyperbole: textarea :: forall id a. Maybe Text -> View (Input id a) ()
+ Web.Hyperbole: textarea :: Maybe Text -> View (Input id a) ()
- Web.Hyperbole: toAction :: (ViewAction a, Generic a, GToEncoded (Rep a)) => a -> Encoded
+ Web.Hyperbole: toAction :: ViewAction a => a -> Encoded
- Web.Hyperbole: toCookie :: (Session a, ToEncoded a) => a -> CookieValue
+ Web.Hyperbole: toCookie :: Session a => a -> CookieValue
- Web.Hyperbole: toQuery :: (ToQuery a, Generic a, GToQuery (Rep a)) => a -> QueryData
+ Web.Hyperbole: toQuery :: ToQuery a => a -> QueryData
- Web.Hyperbole: toViewId :: (ViewId a, Generic a, GToEncoded (Rep a)) => a -> Encoded
+ Web.Hyperbole: toViewId :: ViewId a => a -> Encoded
- Web.Hyperbole: trigger :: (HyperView id es, HyperViewHandled id view, Hyperbole :> es) => id -> Action id -> Eff (Reader view : es) ()
+ Web.Hyperbole: trigger :: forall id (es :: [Effect]) view. (HyperView id es, HyperViewHandled id view, Hyperbole :> es) => id -> Action id -> Eff (Reader view ': es) ()
- Web.Hyperbole: type Concurrency id = Drop;
+ Web.Hyperbole: type Concurrency id = 'Drop;
- Web.Hyperbole: type Page es (views :: [Type]) = Eff (Reader (Root views) : es) (View (Root views) ())
+ Web.Hyperbole: type Page (es :: [Type -> Type -> Type -> Type]) (views :: [Type]) = Eff Reader Root views ': es View Root views ()
- Web.Hyperbole: type Require id = '[];
+ Web.Hyperbole: type Require id = '[] :: [Type];
- Web.Hyperbole: update :: (HyperView id es, Hyperbole :> es) => Action id -> Eff (Reader id : (State (ViewState id) : es)) (View id ())
+ Web.Hyperbole: update :: HyperView id es => Action id -> Eff (Reader id ': (State (ViewState id) ': es)) (View id ())
- Web.Hyperbole: validate :: Bool -> Text -> Validated a
+ Web.Hyperbole: validate :: forall {k} (a :: k). Bool -> Text -> Validated a
- Web.Hyperbole.Application: ServerOptions :: (ByteString -> ByteString) -> (ResponseError -> ServerError) -> ServerOptions
+ Web.Hyperbole.Application: ServerOptions :: (ByteString -> ByteString) -> (ResponseError -> ServerError) -> ParseRequestBodyOptions -> ServerOptions
- Web.Hyperbole.Application: routeRequest :: (Hyperbole :> es, Route route) => (route -> Eff es Response) -> Eff es Response
+ Web.Hyperbole.Application: routeRequest :: forall (es :: [Effect]) route. (Hyperbole :> es, Route route) => (route -> Eff es Response) -> Eff es Response
- Web.Hyperbole.Data.Encoded: Encoded :: ConName -> [ParamValue] -> Encoded
+ Web.Hyperbole.Data.Encoded: Encoded :: ConName -> [Argument] -> Encoded
- Web.Hyperbole.Data.Encoded: class GFromEncoded f
+ Web.Hyperbole.Data.Encoded: class GFromEncoded (f :: k -> Type)
- Web.Hyperbole.Data.Encoded: class GToEncoded f
+ Web.Hyperbole.Data.Encoded: class GToEncoded (f :: k -> Type)
- Web.Hyperbole.Data.Encoded: gParseEncoded :: GFromEncoded f => Encoded -> Either String (f p, [ParamValue])
+ Web.Hyperbole.Data.Encoded: gParseEncoded :: forall (p :: k). GFromEncoded f => Encoded -> Either String (f p, [Argument])
- Web.Hyperbole.Data.Encoded: gToEncoded :: GToEncoded f => f p -> Encoded
+ Web.Hyperbole.Data.Encoded: gToEncoded :: forall (p :: k). GToEncoded f => f p -> Encoded
- Web.Hyperbole.Data.Encoded: parseEncoded :: (FromEncoded a, Generic a, GFromEncoded (Rep a)) => Encoded -> Either String a
+ Web.Hyperbole.Data.Encoded: parseEncoded :: FromEncoded a => Encoded -> Either String a
- Web.Hyperbole.Data.Encoded: toEncoded :: (ToEncoded a, Generic a, GToEncoded (Rep a)) => a -> Encoded
+ Web.Hyperbole.Data.Encoded: toEncoded :: ToEncoded a => a -> Encoded
- Web.Hyperbole.Data.QueryData: QueryData :: Map Param ParamValue -> QueryData
+ Web.Hyperbole.Data.QueryData: QueryData :: Map Param Text -> QueryData
- Web.Hyperbole.Data.QueryData: class GFromQuery f
+ Web.Hyperbole.Data.QueryData: class GFromQuery (f :: k -> Type)
- Web.Hyperbole.Data.QueryData: class GToQuery f
+ Web.Hyperbole.Data.QueryData: class GToQuery (f :: k -> Type)
- Web.Hyperbole.Data.QueryData: elems :: QueryData -> [ParamValue]
+ Web.Hyperbole.Data.QueryData: elems :: QueryData -> [Text]
- Web.Hyperbole.Data.QueryData: gParseQuery :: GFromQuery f => QueryData -> Either String (f p)
+ Web.Hyperbole.Data.QueryData: gParseQuery :: forall (p :: k). GFromQuery f => QueryData -> Either String (f p)
- Web.Hyperbole.Data.QueryData: gToQuery :: GToQuery f => f p -> QueryData
+ Web.Hyperbole.Data.QueryData: gToQuery :: forall (p :: k). GToQuery f => f p -> QueryData
- Web.Hyperbole.Data.QueryData: insert :: ToParam a => Param -> a -> QueryData -> QueryData
+ Web.Hyperbole.Data.QueryData: insert :: ToJSON a => Param -> a -> QueryData -> QueryData
- Web.Hyperbole.Data.QueryData: lookup :: FromParam a => Param -> QueryData -> Maybe a
+ Web.Hyperbole.Data.QueryData: lookup :: FromJSON a => Param -> QueryData -> Maybe a
- Web.Hyperbole.Data.QueryData: parse :: ByteString -> QueryData
+ Web.Hyperbole.Data.QueryData: parse :: Text -> QueryData
- Web.Hyperbole.Data.QueryData: parseQuery :: (FromQuery a, Generic a, GFromQuery (Rep a)) => QueryData -> Either String a
+ Web.Hyperbole.Data.QueryData: parseQuery :: FromQuery a => QueryData -> Either String a
- Web.Hyperbole.Data.QueryData: render :: QueryData -> ByteString
+ Web.Hyperbole.Data.QueryData: render :: QueryData -> Text
- Web.Hyperbole.Data.QueryData: require :: FromParam a => Param -> QueryData -> Either String a
+ Web.Hyperbole.Data.QueryData: require :: FromJSON a => Param -> QueryData -> Either String a
- Web.Hyperbole.Data.QueryData: singleton :: ToParam a => Param -> a -> QueryData
+ Web.Hyperbole.Data.QueryData: singleton :: ToJSON a => Param -> a -> QueryData
- Web.Hyperbole.Data.QueryData: toQuery :: (ToQuery a, Generic a, GToQuery (Rep a)) => a -> QueryData
+ Web.Hyperbole.Data.QueryData: toQuery :: ToQuery a => a -> QueryData
- Web.Hyperbole.Data.URI: Endpoint :: URI -> Endpoint a
+ Web.Hyperbole.Data.URI: Endpoint :: URI -> Endpoint (a :: k)
- Web.Hyperbole.Data.URI: data () => URI
+ Web.Hyperbole.Data.URI: data URI
- Web.Hyperbole.Data.URI: data () => URIAuth
+ Web.Hyperbole.Data.URI: data URIAuth
- Web.Hyperbole.Data.URI: newtype Endpoint a
+ Web.Hyperbole.Data.URI: newtype Endpoint (a :: k)
- Web.Hyperbole.Effect.Client: pageTitle :: Hyperbole :> es => Text -> Eff es ()
+ Web.Hyperbole.Effect.Client: pageTitle :: forall (es :: [Effect]). Hyperbole :> es => Text -> Eff es ()
- Web.Hyperbole.Effect.Client: pushEvent :: (ToJSON a, Hyperbole :> es) => Text -> a -> Eff es ()
+ Web.Hyperbole.Effect.Client: pushEvent :: forall a (es :: [Effect]). (ToJSON a, Hyperbole :> es) => Text -> a -> Eff es ()
- Web.Hyperbole.Effect.Client: trigger :: (HyperView id es, HyperViewHandled id view, Hyperbole :> es) => id -> Action id -> Eff (Reader view : es) ()
+ Web.Hyperbole.Effect.Client: trigger :: forall id (es :: [Effect]) view. (HyperView id es, HyperViewHandled id view, Hyperbole :> es) => id -> Action id -> Eff (Reader view ': es) ()
- Web.Hyperbole.Effect.GenRandom: Token :: Text -> Token a
+ Web.Hyperbole.Effect.GenRandom: Token :: Text -> Token (a :: k)
- Web.Hyperbole.Effect.GenRandom: [GenRandomList] :: Random a => [a] -> GenRandom m a
+ Web.Hyperbole.Effect.GenRandom: [GenRandomList] :: forall b (a :: Type -> Type). Random b => [b] -> GenRandom a b
- Web.Hyperbole.Effect.GenRandom: [GenRandomToken] :: Int -> GenRandom m (Token a)
+ Web.Hyperbole.Effect.GenRandom: [GenRandomToken] :: forall {k} (a :: Type -> Type) (a1 :: k). Int -> GenRandom a (Token a1)
- Web.Hyperbole.Effect.GenRandom: [GenRandom] :: Random a => (a, a) -> GenRandom m a
+ Web.Hyperbole.Effect.GenRandom: [GenRandom] :: forall b (a :: Type -> Type). Random b => (b, b) -> GenRandom a b
- Web.Hyperbole.Effect.GenRandom: data GenRandom :: Effect
+ Web.Hyperbole.Effect.GenRandom: data GenRandom (a :: Type -> Type) b
- Web.Hyperbole.Effect.GenRandom: genRandom :: (Random a, GenRandom :> es) => (a, a) -> Eff es a
+ Web.Hyperbole.Effect.GenRandom: genRandom :: forall a (es :: [Effect]). (Random a, GenRandom :> es) => (a, a) -> Eff es a
- Web.Hyperbole.Effect.GenRandom: genRandomList :: (Random a, GenRandom :> es) => [a] -> Eff es a
+ Web.Hyperbole.Effect.GenRandom: genRandomList :: forall a (es :: [Effect]). (Random a, GenRandom :> es) => [a] -> Eff es a
- Web.Hyperbole.Effect.GenRandom: genRandomToken :: GenRandom :> es => Int -> Eff es (Token a)
+ Web.Hyperbole.Effect.GenRandom: genRandomToken :: forall {k} (es :: [Effect]) (a :: k). GenRandom :> es => Int -> Eff es (Token a)
- Web.Hyperbole.Effect.GenRandom: newtype Token a
+ Web.Hyperbole.Effect.GenRandom: newtype Token (a :: k)
- Web.Hyperbole.Effect.GenRandom: runRandom :: IOE :> es => Eff (GenRandom : es) a -> Eff es a
+ Web.Hyperbole.Effect.GenRandom: runRandom :: forall (es :: [Effect]) a. IOE :> es => Eff (GenRandom ': es) a -> Eff es a
- Web.Hyperbole.Effect.Hyperbole: [GetClient] :: Hyperbole m Client
+ Web.Hyperbole.Effect.Hyperbole: [GetClient] :: forall (a :: Type -> Type). Hyperbole a Client
- Web.Hyperbole.Effect.Hyperbole: [GetRequest] :: Hyperbole m Request
+ Web.Hyperbole.Effect.Hyperbole: [GetRequest] :: forall (a :: Type -> Type). Hyperbole a Request
- Web.Hyperbole.Effect.Hyperbole: [ModClient] :: (Client -> Client) -> Hyperbole m ()
+ Web.Hyperbole.Effect.Hyperbole: [ModClient] :: forall (a :: Type -> Type). (Client -> Client) -> Hyperbole a ()
- Web.Hyperbole.Effect.Hyperbole: [PushEvent] :: Text -> Value -> Hyperbole m ()
+ Web.Hyperbole.Effect.Hyperbole: [PushEvent] :: forall (a :: Type -> Type). Text -> Value -> Hyperbole a ()
- Web.Hyperbole.Effect.Hyperbole: [PushTrigger] :: TargetViewId -> Encoded -> Hyperbole m ()
+ Web.Hyperbole.Effect.Hyperbole: [PushTrigger] :: forall (a :: Type -> Type). TargetViewId -> Encoded -> Hyperbole a ()
- Web.Hyperbole.Effect.Hyperbole: [PushUpdate] :: ViewUpdate -> Hyperbole m ()
+ Web.Hyperbole.Effect.Hyperbole: [PushUpdate] :: forall (a :: Type -> Type). ViewUpdate -> Hyperbole a ()
- Web.Hyperbole.Effect.Hyperbole: [RespondNow] :: Response -> Hyperbole m a
+ Web.Hyperbole.Effect.Hyperbole: [RespondNow] :: forall (a :: Type -> Type) b. Response -> Hyperbole a b
- Web.Hyperbole.Effect.Hyperbole: data Hyperbole :: Effect
+ Web.Hyperbole.Effect.Hyperbole: data Hyperbole (a :: Type -> Type) b
- Web.Hyperbole.Effect.Hyperbole: runHyperboleLocal :: Request -> Eff (Error Response : (State Client : (Writer [Remote] : es))) Response -> Eff es (Response, Client, [Remote])
+ Web.Hyperbole.Effect.Hyperbole: runHyperboleLocal :: forall (es :: [(Type -> Type) -> Type -> Type]). Request -> Eff (Error Response ': (State Client ': (Writer [Remote] ': es))) Response -> Eff es (Response, Client, [Remote])
- Web.Hyperbole.Effect.Query: clearQuery :: Hyperbole :> es => Eff es ()
+ Web.Hyperbole.Effect.Query: clearQuery :: forall (es :: [Effect]). Hyperbole :> es => Eff es ()
- Web.Hyperbole.Effect.Query: deleteParam :: Hyperbole :> es => Param -> Eff es ()
+ Web.Hyperbole.Effect.Query: deleteParam :: forall (es :: [Effect]). Hyperbole :> es => Param -> Eff es ()
- Web.Hyperbole.Effect.Query: lookupParam :: (FromParam a, Hyperbole :> es) => Param -> Eff es (Maybe a)
+ Web.Hyperbole.Effect.Query: lookupParam :: forall a (es :: [Effect]). (FromJSON a, Hyperbole :> es) => Param -> Eff es (Maybe a)
- Web.Hyperbole.Effect.Query: modifyQuery :: (ToQuery a, FromQuery a, Default a, Hyperbole :> es) => (a -> a) -> Eff es a
+ Web.Hyperbole.Effect.Query: modifyQuery :: forall a (es :: [Effect]). (ToQuery a, FromQuery a, Default a, Hyperbole :> es) => (a -> a) -> Eff es a
- Web.Hyperbole.Effect.Query: modifyQueryData :: Hyperbole :> es => (QueryData -> QueryData) -> Eff es ()
+ Web.Hyperbole.Effect.Query: modifyQueryData :: forall (es :: [Effect]). Hyperbole :> es => (QueryData -> QueryData) -> Eff es ()
- Web.Hyperbole.Effect.Query: param :: (FromParam a, Hyperbole :> es) => Param -> Eff es a
+ Web.Hyperbole.Effect.Query: param :: forall a (es :: [Effect]). (FromJSON a, Hyperbole :> es) => Param -> Eff es a
- Web.Hyperbole.Effect.Query: query :: (FromQuery a, Hyperbole :> es) => Eff es a
+ Web.Hyperbole.Effect.Query: query :: forall a (es :: [Effect]). (FromQuery a, Hyperbole :> es) => Eff es a
- Web.Hyperbole.Effect.Query: queryParams :: Hyperbole :> es => Eff es QueryData
+ Web.Hyperbole.Effect.Query: queryParams :: forall (es :: [Effect]). Hyperbole :> es => Eff es QueryData
- Web.Hyperbole.Effect.Query: setParam :: (ToParam a, Hyperbole :> es) => Param -> a -> Eff es ()
+ Web.Hyperbole.Effect.Query: setParam :: forall a (es :: [Effect]). (ToJSON a, Hyperbole :> es) => Param -> a -> Eff es ()
- Web.Hyperbole.Effect.Query: setQuery :: (ToQuery a, Hyperbole :> es) => a -> Eff es ()
+ Web.Hyperbole.Effect.Query: setQuery :: forall a (es :: [Effect]). (ToQuery a, Hyperbole :> es) => a -> Eff es ()
- Web.Hyperbole.Effect.Request: formBody :: Hyperbole :> es => Eff es Form
+ Web.Hyperbole.Effect.Request: formBody :: forall (es :: [Effect]). Hyperbole :> es => Eff es Form
- Web.Hyperbole.Effect.Request: reqPath :: Hyperbole :> es => Eff es Path
+ Web.Hyperbole.Effect.Request: reqPath :: forall (es :: [Effect]). Hyperbole :> es => Eff es Path
- Web.Hyperbole.Effect.Response: hyperView :: (HyperView id es, ToEncoded (ViewState id)) => id -> ViewState id -> View id () -> Eff es Response
+ Web.Hyperbole.Effect.Response: hyperView :: forall id (es :: [Effect]). (HyperView id es, ToJSON (ViewState id)) => id -> ViewState id -> View id () -> Eff es Response
- Web.Hyperbole.Effect.Response: notFound :: Hyperbole :> es => Eff es a
+ Web.Hyperbole.Effect.Response: notFound :: forall (es :: [Effect]) a. Hyperbole :> es => Eff es a
- Web.Hyperbole.Effect.Response: parseError :: Hyperbole :> es => String -> Eff es a
+ Web.Hyperbole.Effect.Response: parseError :: forall (es :: [Effect]) a. Hyperbole :> es => String -> Eff es a
- Web.Hyperbole.Effect.Response: pushUpdate :: (Hyperbole :> es, ViewId id, ToEncoded (ViewState id), ConcurrencyValue (Concurrency id)) => View id () -> Eff (Reader id : (State (ViewState id) : es)) ()
+ Web.Hyperbole.Effect.Response: pushUpdate :: forall (es :: [Effect]) id. (Hyperbole :> es, ViewId id, ToJSON (ViewState id), ConcurrencyValue (Concurrency id)) => View id () -> Eff (Reader id ': (State (ViewState id) ': es)) ()
- Web.Hyperbole.Effect.Response: pushUpdateTo :: (Hyperbole :> es, ViewId id, ToEncoded (ViewState id), ConcurrencyValue (Concurrency id)) => id -> ViewState id -> View id () -> Eff es ()
+ Web.Hyperbole.Effect.Response: pushUpdateTo :: forall (es :: [Effect]) id. (Hyperbole :> es, ViewId id, ToJSON (ViewState id), ConcurrencyValue (Concurrency id)) => id -> ViewState id -> View id () -> Eff es ()
- Web.Hyperbole.Effect.Response: redirect :: Hyperbole :> es => URI -> Eff es a
+ Web.Hyperbole.Effect.Response: redirect :: forall (es :: [Effect]) a. Hyperbole :> es => URI -> Eff es a
- Web.Hyperbole.Effect.Response: respondError :: Hyperbole :> es => ResponseError -> Eff es a
+ Web.Hyperbole.Effect.Response: respondError :: forall (es :: [Effect]) a. Hyperbole :> es => ResponseError -> Eff es a
- Web.Hyperbole.Effect.Response: respondErrorView :: Hyperbole :> es => Text -> View () () -> Eff es a
+ Web.Hyperbole.Effect.Response: respondErrorView :: forall (es :: [Effect]) a. Hyperbole :> es => Text -> View () () -> Eff es a
- Web.Hyperbole.Effect.Session: class GDatatypeName f
+ Web.Hyperbole.Effect.Session: class GDatatypeName (f :: k -> Type)
- Web.Hyperbole.Effect.Session: clientSessionCookies :: Hyperbole :> es => Eff es Cookies
+ Web.Hyperbole.Effect.Session: clientSessionCookies :: forall (es :: [Effect]). Hyperbole :> es => Eff es Cookies
- Web.Hyperbole.Effect.Session: deleteSession :: forall a es. (Session a, Hyperbole :> es) => Eff es ()
+ Web.Hyperbole.Effect.Session: deleteSession :: forall a (es :: [Effect]). (Session a, Hyperbole :> es) => Eff es ()
- Web.Hyperbole.Effect.Session: gDatatypeName :: GDatatypeName f => f p -> Text
+ Web.Hyperbole.Effect.Session: gDatatypeName :: forall (p :: k). GDatatypeName f => f p -> Text
- Web.Hyperbole.Effect.Session: genericTypeName :: forall a. (Generic a, GDatatypeName (Rep a)) => Text
+ Web.Hyperbole.Effect.Session: genericTypeName :: (Generic a, GDatatypeName (Rep a)) => Text
- Web.Hyperbole.Effect.Session: lookupSession :: forall a es. (Session a, Hyperbole :> es) => Eff es (Maybe a)
+ Web.Hyperbole.Effect.Session: lookupSession :: forall a (es :: [Effect]). (Session a, Hyperbole :> es) => Eff es (Maybe a)
- Web.Hyperbole.Effect.Session: modifyCookies :: Hyperbole :> es => (Cookies -> Cookies) -> Eff es ()
+ Web.Hyperbole.Effect.Session: modifyCookies :: forall (es :: [Effect]). Hyperbole :> es => (Cookies -> Cookies) -> Eff es ()
- Web.Hyperbole.Effect.Session: modifySession :: (Session a, Default a, Hyperbole :> es) => (a -> a) -> Eff es a
+ Web.Hyperbole.Effect.Session: modifySession :: forall a (es :: [Effect]). (Session a, Default a, Hyperbole :> es) => (a -> a) -> Eff es a
- Web.Hyperbole.Effect.Session: modifySession_ :: (Session a, Default a, Hyperbole :> es) => (a -> a) -> Eff es ()
+ Web.Hyperbole.Effect.Session: modifySession_ :: forall a (es :: [Effect]). (Session a, Default a, Hyperbole :> es) => (a -> a) -> Eff es ()
- Web.Hyperbole.Effect.Session: parseCookie :: (Session a, FromEncoded a) => CookieValue -> Either String a
+ Web.Hyperbole.Effect.Session: parseCookie :: Session a => CookieValue -> Either String a
- Web.Hyperbole.Effect.Session: parseSession :: (Session a, Hyperbole :> es) => Key -> CookieValue -> Eff es a
+ Web.Hyperbole.Effect.Session: parseSession :: forall a (es :: [Effect]). (Session a, Hyperbole :> es) => Key -> CookieValue -> Eff es a
- Web.Hyperbole.Effect.Session: requestSessionCookies :: Hyperbole :> es => Eff es Cookies
+ Web.Hyperbole.Effect.Session: requestSessionCookies :: forall (es :: [Effect]). Hyperbole :> es => Eff es Cookies
- Web.Hyperbole.Effect.Session: saveSession :: forall a es. (Session a, Hyperbole :> es) => a -> Eff es ()
+ Web.Hyperbole.Effect.Session: saveSession :: forall a (es :: [Effect]). (Session a, Hyperbole :> es) => a -> Eff es ()
- Web.Hyperbole.Effect.Session: session :: (Session a, Default a, Hyperbole :> es) => Eff es a
+ Web.Hyperbole.Effect.Session: session :: forall a (es :: [Effect]). (Session a, Default a, Hyperbole :> es) => Eff es a
- Web.Hyperbole.Effect.Session: sessionCookie :: forall a. Session a => a -> Cookie
+ Web.Hyperbole.Effect.Session: sessionCookie :: Session a => a -> Cookie
- Web.Hyperbole.Effect.Session: sessionCookies :: Hyperbole :> es => Eff es Cookies
+ Web.Hyperbole.Effect.Session: sessionCookies :: forall (es :: [Effect]). Hyperbole :> es => Eff es Cookies
- Web.Hyperbole.Effect.Session: sessionKey :: (Session a, Generic a, GDatatypeName (Rep a)) => Key
+ Web.Hyperbole.Effect.Session: sessionKey :: Session a => Key
- Web.Hyperbole.Effect.Session: setCookie :: (ToParam a, Hyperbole :> es) => Cookie -> Eff es ()
+ Web.Hyperbole.Effect.Session: setCookie :: forall a (es :: [Effect]). (ToJSON a, Hyperbole :> es) => Cookie -> Eff es ()
- Web.Hyperbole.Effect.Session: toCookie :: (Session a, ToEncoded a) => a -> CookieValue
+ Web.Hyperbole.Effect.Session: toCookie :: Session a => a -> CookieValue
- Web.Hyperbole.HyperView: data () => State s (a :: Type -> Type) b
+ Web.Hyperbole.HyperView: data State s (a :: Type -> Type) b
- Web.Hyperbole.HyperView.Event: onChange :: (ViewAction (Action id), Attributable a) => (value -> Action id) -> Attributes a -> Attributes a
+ Web.Hyperbole.HyperView.Event: onChange :: (ViewAction (Action id), Attributable a) => Action id -> Attributes a -> Attributes a
- Web.Hyperbole.HyperView.Event: onInput :: (ViewAction (Action id), Attributable a) => (Text -> Action id) -> DelayMs -> Attributes a -> Attributes a
+ Web.Hyperbole.HyperView.Event: onInput :: (ViewAction (Action id), Attributable a) => Action id -> DelayMs -> Attributes a -> Attributes a
- Web.Hyperbole.HyperView.Event: target :: forall id ctx. (HyperViewHandled id ctx, ViewId id) => id -> ViewState id -> View id () -> View ctx ()
+ Web.Hyperbole.HyperView.Event: target :: (HyperViewHandled id ctx, ViewId id) => id -> ViewState id -> View id () -> View ctx ()
- Web.Hyperbole.HyperView.Forms: FieldName :: Text -> FieldName a
+ Web.Hyperbole.HyperView.Forms: FieldName :: Text -> FieldName (a :: k)
- Web.Hyperbole.HyperView.Forms: Input :: id -> FieldName a -> Input (id :: Type) (a :: Type)
+ Web.Hyperbole.HyperView.Forms: Input :: id -> FieldName a -> Input id a
- Web.Hyperbole.HyperView.Forms: Invalid :: Text -> Validated a
+ Web.Hyperbole.HyperView.Forms: Invalid :: Text -> Validated (a :: k)
- Web.Hyperbole.HyperView.Forms: NotInvalid :: Validated a
+ Web.Hyperbole.HyperView.Forms: NotInvalid :: Validated (a :: k)
- Web.Hyperbole.HyperView.Forms: Valid :: Validated a
+ Web.Hyperbole.HyperView.Forms: Valid :: Validated (a :: k)
- Web.Hyperbole.HyperView.Forms: checkbox :: forall id a. Bool -> View (Input id a) ()
+ Web.Hyperbole.HyperView.Forms: checkbox :: Bool -> View (Input id a) ()
- Web.Hyperbole.HyperView.Forms: class FromForm (form :: Type)
+ Web.Hyperbole.HyperView.Forms: class FromForm form
- Web.Hyperbole.HyperView.Forms: class FromFormF (f :: (Type -> Type) -> Type)
+ Web.Hyperbole.HyperView.Forms: class FromFormF (f :: Type -> Type -> Type)
- Web.Hyperbole.HyperView.Forms: class GFieldsGen f
+ Web.Hyperbole.HyperView.Forms: class GFieldsGen (f :: k -> Type)
- Web.Hyperbole.HyperView.Forms: class GenFields f (form :: (Type -> Type) -> Type)
+ Web.Hyperbole.HyperView.Forms: class GenFields (f :: Type -> Type) (form :: Type -> Type -> Type)
- Web.Hyperbole.HyperView.Forms: class () => Generic a
+ Web.Hyperbole.HyperView.Forms: class Generic a
- Web.Hyperbole.HyperView.Forms: data () => Identity a
+ Web.Hyperbole.HyperView.Forms: data Identity a
- Web.Hyperbole.HyperView.Forms: data Input (id :: Type) (a :: Type)
+ Web.Hyperbole.HyperView.Forms: data Input id a
- Web.Hyperbole.HyperView.Forms: data Validated a
+ Web.Hyperbole.HyperView.Forms: data Validated (a :: k)
- Web.Hyperbole.HyperView.Forms: field :: forall (id :: Type) (a :: Type). FieldName a -> View (Input id a) () -> View (FormFields id) ()
+ Web.Hyperbole.HyperView.Forms: field :: forall id a. FieldName a -> View (Input id a) () -> View (FormFields id) ()
- Web.Hyperbole.HyperView.Forms: fieldNames :: forall form. GenFields FieldName form => form FieldName
+ Web.Hyperbole.HyperView.Forms: fieldNames :: GenFields (FieldName :: Type -> Type) form => form (FieldName :: Type -> Type)
- Web.Hyperbole.HyperView.Forms: formData :: forall form es. (FromForm form, Hyperbole :> es) => Eff es form
+ Web.Hyperbole.HyperView.Forms: formData :: forall form (es :: [Effect]). (FromForm form, Hyperbole :> es) => Eff es form
- Web.Hyperbole.HyperView.Forms: fromForm :: (FromForm form, Generic form, GFormParse (Rep form)) => Form -> Either String form
+ Web.Hyperbole.HyperView.Forms: fromForm :: FromForm form => Form -> Either String form
- Web.Hyperbole.HyperView.Forms: fromFormF :: (FromFormF f, Generic (f Identity), GFormParse (Rep (f Identity))) => Form -> Either String (f Identity)
+ Web.Hyperbole.HyperView.Forms: fromFormF :: FromFormF f => Form -> Either String (f Identity)
- Web.Hyperbole.HyperView.Forms: gFieldsGen :: GFieldsGen f => f p
+ Web.Hyperbole.HyperView.Forms: gFieldsGen :: forall (p :: k). GFieldsGen f => f p
- Web.Hyperbole.HyperView.Forms: genFields :: (GenFields f form, Generic (form f), GFieldsGen (Rep (form f))) => form f
+ Web.Hyperbole.HyperView.Forms: genFields :: GenFields f form => form f
- Web.Hyperbole.HyperView.Forms: input :: forall id a. InputType -> View (Input id a) ()
+ Web.Hyperbole.HyperView.Forms: input :: InputType -> View (Input id a) ()
- Web.Hyperbole.HyperView.Forms: invalidText :: forall a id. Validated a -> View (Input id a) ()
+ Web.Hyperbole.HyperView.Forms: invalidText :: Validated a -> View (Input id a) ()
- Web.Hyperbole.HyperView.Forms: isInvalid :: Validated a -> Bool
+ Web.Hyperbole.HyperView.Forms: isInvalid :: forall {k} (a :: k). Validated a -> Bool
- Web.Hyperbole.HyperView.Forms: newtype FieldName a
+ Web.Hyperbole.HyperView.Forms: newtype FieldName (a :: k)
- Web.Hyperbole.HyperView.Forms: radio :: forall id a opt. (Eq opt, ToParam opt) => opt -> View (Radio id a opt) ()
+ Web.Hyperbole.HyperView.Forms: radio :: forall id a opt. (Eq opt, ToJSON opt) => opt -> View (Radio id a opt) ()
- Web.Hyperbole.HyperView.Forms: select :: forall opt id a. Eq opt => opt -> View (Option id opt) () -> View (Input id a) ()
+ Web.Hyperbole.HyperView.Forms: select :: Eq opt => opt -> View (Option id opt) () -> View (Input id a) ()
- Web.Hyperbole.HyperView.Forms: textarea :: forall id a. Maybe Text -> View (Input id a) ()
+ Web.Hyperbole.HyperView.Forms: textarea :: Maybe Text -> View (Input id a) ()
- Web.Hyperbole.HyperView.Forms: validate :: Bool -> Text -> Validated a
+ Web.Hyperbole.HyperView.Forms: validate :: forall {k} (a :: k). Bool -> Text -> Validated a
- Web.Hyperbole.HyperView.Handled: type NotDesc id ctx x cs = TypeError ('Text "" :<>: 'ShowType x :<>: 'Text ", a child of HyperView " :<>: 'ShowType id :<>: 'Text ", not handled by context " :<>: 'ShowType ctx :$$: ('Text " Require = " ':<>: 'ShowType cs))
+ Web.Hyperbole.HyperView.Handled: type NotDesc (id :: t) (ctx :: t1) (x :: t2) (cs :: t3) = TypeError 'Text "" ':<>: 'ShowType x ':<>: 'Text ", a child of HyperView " ':<>: 'ShowType id ':<>: 'Text ", not handled by context " ':<>: 'ShowType ctx ':$$: 'Text " Require = " ':<>: 'ShowType cs :: k
- Web.Hyperbole.HyperView.Handled: type NotHandled id ctx (views :: [Type]) = TypeError ('Text "HyperView " :<>: 'ShowType id :<>: 'Text " not found in (Require " :<>: 'ShowType ctx :<>: 'Text ")" :$$: 'Text " " :<>: 'ShowType views :$$: 'Text "Try adding it to the HyperView instance:" :$$: 'Text " instance HyperView " :<>: 'ShowType ctx :<>: 'Text " where" :$$: 'Text " type Action " :<>: 'ShowType ctx :<>: 'Text " = " :<>: ShowType (Action id) :<>: 'Text "" :$$: 'Text " type Require " :<>: 'ShowType ctx :<>: 'Text " = [" :<>: ShowType id :<>: 'Text ", ...]")
+ Web.Hyperbole.HyperView.Handled: type NotHandled id (ctx :: t) (views :: [Type]) = TypeError 'Text "HyperView " ':<>: 'ShowType id ':<>: 'Text " not found in (Require " ':<>: 'ShowType ctx ':<>: 'Text ")" ':$$: 'Text " " ':<>: 'ShowType views ':$$: 'Text "Try adding it to the HyperView instance:" ':$$: 'Text " instance HyperView " ':<>: 'ShowType ctx ':<>: 'Text " where" ':$$: 'Text " type Action " ':<>: 'ShowType ctx ':<>: 'Text " = " ':<>: 'ShowType Action id ':<>: 'Text "" ':$$: 'Text " type Require " ':<>: 'ShowType ctx ':<>: 'Text " = [" ':<>: 'ShowType id ':<>: 'Text ", ...]" :: k
- Web.Hyperbole.HyperView.Handled: type NotInPage x total = TypeError ('Text "" :<>: 'ShowType x :<>: 'Text " not included in: " :$$: 'Text " Page es " :<>: ShowType total :$$: 'Text "try expanding the page views to:" :$$: 'Text " Page es " :<>: ShowType (x : total))
+ Web.Hyperbole.HyperView.Handled: type NotInPage (x :: a) (total :: [a]) = TypeError 'Text "" ':<>: 'ShowType x ':<>: 'Text " not included in: " ':$$: 'Text " Page es " ':<>: 'ShowType total ':$$: 'Text "try expanding the page views to:" ':$$: 'Text " Page es " ':<>: 'ShowType x ': total :: k
- Web.Hyperbole.HyperView.Handled: type family AllInPage ids total :: Constraint
+ Web.Hyperbole.HyperView.Handled: type family AllInPage (ids :: [a]) (total :: [a])
- Web.Hyperbole.HyperView.Hyper: hyper :: forall id ctx. (HyperViewHandled id ctx, ViewId id, ViewState id ~ (), ConcurrencyValue (Concurrency id)) => id -> View id () -> View ctx ()
+ Web.Hyperbole.HyperView.Hyper: hyper :: (HyperViewHandled id ctx, ViewId id, ViewState id ~ (), ConcurrencyValue (Concurrency id)) => id -> View id () -> View ctx ()
- Web.Hyperbole.HyperView.Hyper: hyperState :: forall id ctx. (HyperViewHandled id ctx, ViewId id, ToEncoded (ViewState id), ConcurrencyValue (Concurrency id)) => id -> ViewState id -> View id () -> View ctx ()
+ Web.Hyperbole.HyperView.Hyper: hyperState :: (HyperViewHandled id ctx, ViewId id, ToJSON (ViewState id), ConcurrencyValue (Concurrency id)) => id -> ViewState id -> View id () -> View ctx ()
- Web.Hyperbole.HyperView.Hyper: hyperUnsafe :: forall id ctx. (ViewId id, ViewState id ~ ViewState id, ToEncoded (ViewState id), ConcurrencyValue (Concurrency id)) => id -> ViewState id -> View id () -> View ctx ()
+ Web.Hyperbole.HyperView.Hyper: hyperUnsafe :: (ViewId id, ViewState id ~ ViewState id, ToJSON (ViewState id), ConcurrencyValue (Concurrency id)) => id -> ViewState id -> View id () -> View ctx ()
- Web.Hyperbole.HyperView.Input: dropdown :: forall opt id. ViewAction (Action id) => (opt -> Action id) -> opt -> View (Option id opt) () -> View id ()
+ Web.Hyperbole.HyperView.Input: dropdown :: forall opt id. (ViewAction (Action id), FromJSON opt) => Action id -> opt -> View (Option id opt) () -> View id ()
- Web.Hyperbole.HyperView.Input: option :: forall opt id. (ViewAction (Action id), Eq opt, ToParam opt) => opt -> Text -> View (Option id opt) ()
+ Web.Hyperbole.HyperView.Input: option :: forall opt id. (ViewAction (Action id), Eq opt, ToJSON opt) => opt -> Text -> View (Option id opt) ()
- Web.Hyperbole.HyperView.Input: search :: ViewAction (Action id) => (Text -> Action id) -> DelayMs -> View id ()
+ Web.Hyperbole.HyperView.Input: search :: ViewAction (Action id) => Action id -> DelayMs -> View id ()
- Web.Hyperbole.HyperView.Types: class ConcurrencyValue a
+ Web.Hyperbole.HyperView.Types: class ConcurrencyValue (a :: k)
- Web.Hyperbole.HyperView.Types: class (ViewId id, ViewAction (Action id), ConcurrencyValue (Concurrency id)) => HyperView id es where {
+ Web.Hyperbole.HyperView.Types: class (ViewId id, ViewAction Action id, ConcurrencyValue Concurrency id) => HyperView id (es :: [Effect]) where {
- Web.Hyperbole.HyperView.Types: type Concurrency id = Drop;
+ Web.Hyperbole.HyperView.Types: type Concurrency id = 'Drop;
- Web.Hyperbole.HyperView.Types: type Require id = '[];
+ Web.Hyperbole.HyperView.Types: type Require id = '[] :: [Type];
- Web.Hyperbole.HyperView.Types: update :: (HyperView id es, Hyperbole :> es) => Action id -> Eff (Reader id : (State (ViewState id) : es)) (View id ())
+ Web.Hyperbole.HyperView.Types: update :: HyperView id es => Action id -> Eff (Reader id ': (State (ViewState id) ': es)) (View id ())
- Web.Hyperbole.Page: runPage :: (Hyperbole :> es, RunHandlers views es) => Page es views -> Eff es Response
+ Web.Hyperbole.Page: runPage :: forall (es :: [Effect]) (views :: [Type]). (Hyperbole :> es, RunHandlers views es) => Page es views -> Eff es Response
- Web.Hyperbole.Page: subPage :: Hyperbole :> es => Eff (Reader (Root inner) : es) a -> Eff es a
+ Web.Hyperbole.Page: subPage :: forall (es :: [Effect]) (inner :: [Type]) a. Hyperbole :> es => Eff (Reader (Root inner) ': es) a -> Eff es a
- Web.Hyperbole.Page: type Page es (views :: [Type]) = Eff (Reader (Root views) : es) (View (Root views) ())
+ Web.Hyperbole.Page: type Page (es :: [Type -> Type -> Type -> Type]) (views :: [Type]) = Eff Reader Root views ': es View Root views ()
- Web.Hyperbole.Route: baseRoute :: (Route a, Generic a, GenRoute (Rep a)) => Maybe a
+ Web.Hyperbole.Route: baseRoute :: Route a => Maybe a
- Web.Hyperbole.Route: class GenRoute f
+ Web.Hyperbole.Route: class GenRoute (f :: k -> Type)
- Web.Hyperbole.Route: genPaths :: GenRoute f => f p -> [Text]
+ Web.Hyperbole.Route: genPaths :: forall (p :: k). GenRoute f => f p -> [Text]
- Web.Hyperbole.Route: genRoute :: GenRoute f => [Text] -> Maybe (f p)
+ Web.Hyperbole.Route: genRoute :: forall (p :: k). GenRoute f => [Text] -> Maybe (f p)
- Web.Hyperbole.Route: genRouteRead :: Read x => [Text] -> Maybe (K1 R x a)
+ Web.Hyperbole.Route: genRouteRead :: forall {k} x (a :: k). Read x => [Text] -> Maybe (K1 R x a)
- Web.Hyperbole.Route: matchRoute :: (Route a, Generic a, GenRoute (Rep a)) => Path -> Maybe a
+ Web.Hyperbole.Route: matchRoute :: Route a => Path -> Maybe a
- Web.Hyperbole.Route: routePath :: (Route a, Generic a, Eq a, GenRoute (Rep a)) => a -> Path
+ Web.Hyperbole.Route: routePath :: Route a => a -> Path
- Web.Hyperbole.Server.Handler: class RunHandlers (views :: [Type]) es
+ Web.Hyperbole.Server.Handler: class RunHandlers (views :: [Type]) (es :: [Effect])
- Web.Hyperbole.Server.Handler: decodeEvent :: forall id es. (HyperView id es, FromEncoded (ViewState id)) => Event TargetViewId Encoded Encoded -> Eff es (Maybe (Event id (Action id) (ViewState id)))
+ Web.Hyperbole.Server.Handler: decodeEvent :: forall id (es :: [Effect]). (HyperView id es, FromJSON (ViewState id), Hyperbole :> es) => Event TargetViewId Encoded Value -> Eff es (Maybe (Event id (Action id) (ViewState id)))
- Web.Hyperbole.Server.Handler: loadPageResponse :: Eff es (View (Root total) ()) -> Eff es Response
+ Web.Hyperbole.Server.Handler: loadPageResponse :: forall (es :: [Effect]) (total :: [Type]). Eff es (View (Root total) ()) -> Eff es Response
- Web.Hyperbole.Server.Handler: runHandler :: forall id es. (HyperView id es, ToEncoded (ViewState id), FromEncoded (ViewState id), Hyperbole :> es) => Event TargetViewId Encoded Encoded -> (Action id -> Eff (Reader id : (State (ViewState id) : es)) (View id ())) -> Eff es (Maybe Response)
+ Web.Hyperbole.Server.Handler: runHandler :: forall id (es :: [Effect]). (HyperView id es, ToJSON (ViewState id), FromJSON (ViewState id), Hyperbole :> es) => Event TargetViewId Encoded Value -> (Action id -> Eff (Reader id ': (State (ViewState id) ': es)) (View id ())) -> Eff es (Maybe Response)
- Web.Hyperbole.Server.Handler: runHandlers :: (RunHandlers views es, Hyperbole :> es) => Event TargetViewId Encoded Encoded -> Eff es (Maybe Response)
+ Web.Hyperbole.Server.Handler: runHandlers :: RunHandlers views es => Event TargetViewId Encoded Value -> Eff es (Maybe Response)
- Web.Hyperbole.Server.Handler: runLoad :: forall views es. (Hyperbole :> es, RunHandlers views es) => Eff es (View (Root views) ()) -> Eff es Response
+ Web.Hyperbole.Server.Handler: runLoad :: forall (views :: [Type]) (es :: [Effect]). (Hyperbole :> es, RunHandlers views es) => Eff es (View (Root views) ()) -> Eff es Response
- Web.Hyperbole.Server.Message: Message :: Text -> Event TargetViewId Encoded Encoded -> RequestId -> Metadata -> MessageBody -> Message
+ Web.Hyperbole.Server.Message: Message :: Text -> Event TargetViewId Encoded Value -> RequestId -> Metadata -> MessageBody -> Message
- Web.Hyperbole.Server.Message: parseActionMessage :: Text -> Either String Message
+ Web.Hyperbole.Server.Message: parseActionMessage :: ByteString -> Either String Message
- Web.Hyperbole.Server.Options: ServerOptions :: (ByteString -> ByteString) -> (ResponseError -> ServerError) -> ServerOptions
+ Web.Hyperbole.Server.Options: ServerOptions :: (ByteString -> ByteString) -> (ResponseError -> ServerError) -> ParseRequestBodyOptions -> ServerOptions
- Web.Hyperbole.Server.Socket: handleRequestSocket :: (IOE :> es, Concurrent :> es) => ServerOptions -> TVar RunningActions -> Request -> Connection -> Eff (Hyperbole : es) Response -> Eff es ()
+ Web.Hyperbole.Server.Socket: handleRequestSocket :: forall (es :: [Effect]). (IOE :> es, Concurrent :> es) => ServerOptions -> TVar RunningActions -> Request -> Connection -> Eff (Hyperbole ': es) Response -> Eff es ()
- Web.Hyperbole.Server.Socket: runHyperboleSocket :: IOE :> es => ServerOptions -> Connection -> Request -> Eff (Hyperbole : es) Response -> Eff es (Response, Client, [Remote])
+ Web.Hyperbole.Server.Socket: runHyperboleSocket :: forall (es :: [Effect]). IOE :> es => ServerOptions -> Connection -> Request -> Eff (Hyperbole ': es) Response -> Eff es (Response, Client, [Remote])
- Web.Hyperbole.Server.Socket: sendError :: IOE :> es => Connection -> Metadata -> ServerError -> Eff es ()
+ Web.Hyperbole.Server.Socket: sendError :: forall (es :: [Effect]). IOE :> es => Connection -> Metadata -> ServerError -> Eff es ()
- Web.Hyperbole.Server.Socket: sendEvent :: IOE :> es => Connection -> Request -> Text -> Value -> Eff es ()
+ Web.Hyperbole.Server.Socket: sendEvent :: forall (es :: [Effect]). IOE :> es => Connection -> Request -> Text -> Value -> Eff es ()
- Web.Hyperbole.Server.Socket: sendRedirect :: IOE :> es => Connection -> Metadata -> URI -> Eff es ()
+ Web.Hyperbole.Server.Socket: sendRedirect :: forall (es :: [Effect]). IOE :> es => Connection -> Metadata -> URI -> Eff es ()
- Web.Hyperbole.Server.Socket: sendRemote :: IOE :> es => Command -> Connection -> Request -> Remote -> Eff es ()
+ Web.Hyperbole.Server.Socket: sendRemote :: forall (es :: [Effect]). IOE :> es => Command -> Connection -> Request -> Remote -> Eff es ()
- Web.Hyperbole.Server.Socket: sendResponse :: IOE :> es => Connection -> Metadata -> Body -> Eff es ()
+ Web.Hyperbole.Server.Socket: sendResponse :: forall (es :: [Effect]). IOE :> es => Connection -> Metadata -> Body -> Eff es ()
- Web.Hyperbole.Server.Socket: sendTrigger :: IOE :> es => Connection -> Request -> TargetViewId -> Encoded -> Eff es ()
+ Web.Hyperbole.Server.Socket: sendTrigger :: forall (es :: [Effect]). IOE :> es => Connection -> Request -> TargetViewId -> Encoded -> Eff es ()
- Web.Hyperbole.Server.Socket: sendUpdate :: IOE :> es => Connection -> Request -> TargetViewId -> Body -> Eff es ()
+ Web.Hyperbole.Server.Socket: sendUpdate :: forall (es :: [Effect]). IOE :> es => Connection -> Request -> TargetViewId -> Body -> Eff es ()
- Web.Hyperbole.Server.Socket: type RunningActions = Map TargetViewId (Encoded, Async ())
+ Web.Hyperbole.Server.Socket: type RunningActions = Map TargetViewId (Encoded, RequestId, Async ())
- Web.Hyperbole.Server.Wai: fromWaiRequest :: Request -> ByteString -> Either MessageError Request
+ Web.Hyperbole.Server.Wai: fromWaiRequest :: Request -> Form -> Either MessageError Request
- Web.Hyperbole.Server.Wai: handleRequestWai :: IOE :> es => ServerOptions -> Request -> (Response -> IO ResponseReceived) -> Eff (Hyperbole : es) Response -> Eff es ResponseReceived
+ Web.Hyperbole.Server.Wai: handleRequestWai :: forall (es :: [Effect]). IOE :> es => ServerOptions -> Request -> (Response -> IO ResponseReceived) -> Eff (Hyperbole ': es) Response -> Eff es ResponseReceived
- Web.Hyperbole.Server.Wai: runHyperboleWai :: Request -> Eff (Hyperbole : es) Response -> Eff es (Response, Client, [Remote])
+ Web.Hyperbole.Server.Wai: runHyperboleWai :: forall (es :: [Effect]). IOE :> es => Request -> Eff (Hyperbole ': es) Response -> Eff es (Response, Client, [Remote])
- Web.Hyperbole.TypeList: type Elem e es = ElemOr e es (NotElem e es)
+ Web.Hyperbole.TypeList: type Elem e (es :: [Type]) = ElemOr e es NotElem e es :: Constraint
- Web.Hyperbole.TypeList: type NotElem x (orig :: [Type]) = TypeError ('ShowType x ':<>: 'Text " not found in " ':<>: 'ShowType orig)
+ Web.Hyperbole.TypeList: type NotElem (x :: t) (orig :: [Type]) = TypeError 'ShowType x ':<>: 'Text " not found in " ':<>: 'ShowType orig :: k
- Web.Hyperbole.TypeList: type family TupleList a
+ Web.Hyperbole.TypeList: type family TupleList a :: [Type]
- Web.Hyperbole.Types.Request: Request :: Host -> Path -> Query -> ByteString -> Method -> Cookies -> Maybe (Event TargetViewId Encoded Encoded) -> RequestId -> Request
+ Web.Hyperbole.Types.Request: Request :: Host -> Path -> Query -> Method -> Cookies -> Maybe (Event TargetViewId Encoded Value) -> RequestId -> Form -> Text -> Request
- Web.Hyperbole.Types.Response: ErrNotHandled :: Event TargetViewId Encoded Encoded -> ResponseError
+ Web.Hyperbole.Types.Response: ErrNotHandled :: Event TargetViewId Encoded Value -> ResponseError
- Web.Hyperbole.View.Types: class HasViewId m view
+ Web.Hyperbole.View.Types: class HasViewId (m :: k -> Type) (view :: k)
- Web.Hyperbole.View.Types: context :: forall c. View c (c, ViewState c)
+ Web.Hyperbole.View.Types: context :: View c (c, ViewState c)
- Web.Hyperbole.View.Types: execView :: forall c a. c -> ViewState c -> View c a -> Html a
+ Web.Hyperbole.View.Types: execView :: c -> ViewState c -> View c a -> Html a
- Web.Hyperbole.View.ViewAction: parseAction :: (ViewAction a, Generic a, GFromEncoded (Rep a)) => Encoded -> Either String a
+ Web.Hyperbole.View.ViewAction: parseAction :: ViewAction a => Encoded -> Either String a
- Web.Hyperbole.View.ViewAction: toAction :: (ViewAction a, Generic a, GToEncoded (Rep a)) => a -> Encoded
+ Web.Hyperbole.View.ViewAction: toAction :: ViewAction a => a -> Encoded
- Web.Hyperbole.View.ViewId: parseViewId :: (ViewId a, Generic a, GFromEncoded (Rep a)) => Encoded -> Either String a
+ Web.Hyperbole.View.ViewId: parseViewId :: ViewId a => Encoded -> Either String a
- Web.Hyperbole.View.ViewId: toViewId :: (ViewId a, Generic a, GToEncoded (Rep a)) => a -> Encoded
+ Web.Hyperbole.View.ViewId: toViewId :: ViewId a => a -> Encoded

Files

CHANGELOG.md view
@@ -1,5 +1,29 @@ # Revision history for hyperbole ++## 0.7.0 -- TODO++Features:+* Accept multipart form file uploads with good default security settings++Improvements:+* `trigger` and `pushEvent` now send to the client immediately instead of waiting for the action to finish+* Added `cookieSecure` option to Session class+* Deprecated `toActionInput` in favor of `inputValue` - Instead of partially applying a constructor, inputs are read with a function similar to forms+* `Web.Hyperbole.Data.Param` was unnecessary and removed. Everything uses ToJSON and FromJSON as an intermediate encoding+* moved OAuth2 to sub-package to allow for dependencies on cryptography libraries++Breaking Changes:+* Actions with input like `search`, `onInput` and `dropdown` should now use an action with no arguments. Get the value using `inputValue` instead+* `ToParam` and `FromParam` are no longer used. Use the generic implementation of `ToJSON` and `FromJSON` instead++Maintenance:+* NIX support is fully up to date+* Strict Typescript+* [Many issues resolved](https://github.com/seanhess/hyperbole/issues?q=is%3Aissue%20state%3Aclosed)+++ ## 0.6.0 -- 2026-01-15  Improvements:
README.md view
@@ -15,7 +15,7 @@ module Main where  import Data.Text (Text)-import Web.Atomic.CSS+import Web.Atomic.CSS (border, (~)) import Web.Hyperbole  main :: IO ()@@ -78,6 +78,7 @@     build-depends:         base       , hyperbole+      , atomic-css       , text      default-language: GHC2021@@ -97,8 +98,8 @@ <!--     <img src="https://github.com/seanhess/hyperbole/raw/main/docs/hackage.svg"> --> <!-- </a> --> -* [Local Development](./docs/dev.md) * [Comparison with Similar Frameworks](./docs/comparison.md)+* [Local Development](./docs/dev.md) * [Using NIX](./docs/nix.md)  In the Wild@@ -108,7 +109,7 @@   <img alt="National Solar Observatory" src="https://nso1.b-cdn.net/wp-content/uploads/2020/03/NSO-logo-orange-text.png" width="400"/> </a> -The NSO uses Hyperbole to manage Level 2 Data pipelines for the [DKIST telescope](https://nso.edu/telescopes/dki-solar-telescope/). It uses complex user interfaces, workers, databases, and more. [The entire codebase is open source](https://github.com/DKISTDC/level2/). +The NSO uses Hyperbole to manage Level 2 Data pipelines for the [DKIST telescope](https://nso.edu/telescopes/dki-solar-telescope/)   @@ -125,3 +126,7 @@ * [Tushar Adhatrao](https://github.com/tusharad) * [Benjamin Thomas](https://github.com/benjamin-thomas) * [Adithya Obilisetty](https://github.com/adithyaov)+* [Jens Krause](https://github.com/sectore)+* [He Zhenxing](https://github.com/hezhenxing)+* [fanshi1028](https://github.com/fanshi1028)+* [jkasalt](https://github.com/jkasalt)
client/dist/hyperbole.js view
@@ -1,21 +1,15 @@-"use strict";(()=>{var Ce="data-key",A=function(e,n){return Object.prototype.hasOwnProperty.call(e,n)},Re=function(e,n){return n?A(e,n)?(console.warn("[OmDomDom]: Children with duplicate keys detected. Children with duplicate keys will be skipped, resulting in dropped node references. Keys must be unique and non-indexed."),!1):!0:!1},y=function(e,n){var r=e.length,i=-1;if(r)for(;++i<r&&n(e[i],i)!==!1;);},Ve=function(e){var n={};y(e,function(i){var o=i.attributes[Ce];Re(n,o)&&(n[o]=i)});for(var r in n)return n},$=function(e,n,r){return e.node.insertBefore(n.node,r)},He=function(e,n){for(var r in e)n[r]=e[r]},ke=function(e){var n=e.trim().replace(/\s+</g,"<").replace(/>\s+/g,">"),r=new DOMParser,i=r.parseFromString(n,"text/html");return i.body};function Se(t,e){var n=t==null?null:typeof Symbol<"u"&&t[Symbol.iterator]||t["@@iterator"];if(n!=null){var r,i,o,s,c=[],a=!0,l=!1;try{if(o=(n=n.call(t)).next,e===0){if(Object(n)!==n)return;a=!1}else for(;!(a=(r=o.call(n)).done)&&(c.push(r.value),c.length!==e);a=!0);}catch(d){l=!0,i=d}finally{try{if(!a&&n.return!=null&&(s=n.return(),Object(s)!==s))return}finally{if(l)throw i}}return c}}function Y(t,e){return qe(t)||Se(t,e)||De(t,e)||Oe()}function qe(t){if(Array.isArray(t))return t}function De(t,e){if(t){if(typeof t=="string")return _(t,e);var n=Object.prototype.toString.call(t).slice(8,-1);if(n==="Object"&&t.constructor&&(n=t.constructor.name),n==="Map"||n==="Set")return Array.from(t);if(n==="Arguments"||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))return _(t,e)}}function _(t,e){(e==null||e>t.length)&&(e=t.length);for(var n=0,r=new Array(e);n<e;n++)r[n]=t[n];return r}function Oe(){throw new TypeError(`Invalid attempt to destructure non-iterable instance.-In order to be iterable, non-array objects must have a [Symbol.iterator]() method.`)}var m={STRING:"string",INT:"number",BOOL:"boolean"},g={},S=function(e,n,r){return{attrName:e,propName:n,type:r}},Pe=[["style","cssText"],["class","className"]];y(Pe,function(t){var e=Y(t,2),n=e[0],r=e[1];g[n]=S(n,r||n,m.STRING)});var Ue=["autofocus","draggable","hidden","checked","multiple","muted","selected"];y(Ue,function(t){g[t]=S(t,t,m.BOOL)});var Be=[["tabindex","tabIndex"]];y(Be,function(t){var e=Y(t,2),n=e[0],r=e[1];g[n]=S(n,r,m.INT)});var I={xlink:{prefix:"xlink:",resource:"http://www.w3.org/1999/xlink"},xml:{prefix:"xml:",resource:"http://www.w3.org/XML/1998/namespace"}},x=function(e,n,r,i){switch(n){case m.STRING:{r===g.style.propName?i===null?e.style[r]="":e.style[r]=i:i===null?e[r]="":e[r]=i;break}case m.INT:{if(i===null){var o=r.toLowerCase();e.removeAttribute(o)}else if(i==="0")e[r]=0;else if(i==="-1")e[r]=-1;else{var s=parseInt(i,10);isNaN(s)||(e[r]=s)}break}case m.BOOL:{["","true"].indexOf(i)<0?e[r]=!1:e[r]=!0;break}}},Ke=function(e,n){y(n,function(r){if(A(g,r)){var i=g[r];x(e.node,i.type,i.propName,null)}else r in e.node&&x(e.node,m.STRING,r,null),e.node.removeAttribute(r);delete e.attributes[r]})},je=function(e,n){for(var r in n){var i=n[r];if(e.attributes[r]=i,A(g,r)){var o=g[r];x(e.node,o.type,o.propName,i);continue}if(r.startsWith(I.xlink.prefix)){e.node.setAttributeNS(I.xlink.resource,r,i);continue}if(r.startsWith(I.xml.prefix)){e.node.setAttributeNS(I.xml.resource,r,i);continue}r in e.node&&x(e.node,m.STRING,r,i),e.node.setAttribute(r,i||"")}},Fe=function(e,n){for(var r in g){var i=g[r],o=i.propName,s=e.getAttribute(r);r===g.style.attrName?n[r]=e.style[o]:typeof s=="string"&&(n[r]=s)}},We=function(e){return Array.prototype.reduce.call(e.attributes,function(n,r){return A(g,r.name)||(n[r.name]=r.value),n},{})},Ge=function(e){var n=We(e);return Fe(e,n),n},Qe=function(e,n){var r=[],i={};for(var o in n.attributes){var s=n.attributes[o],c=e.attributes[o];s!==c&&typeof c>"u"&&r.push(o)}for(var a in e.attributes){var l=n.attributes[a],d=e.attributes[a];l!==d&&typeof d<"u"&&(i[a]=d)}Ke(n,r),je(n,i)},Je="data-key";function $e(t,e,n){var r=t.children.length,i=e.children.length;if(!(!r&&!i)){var o=Ve(e.children),s=Array(r);o!==void 0?y(t.children,function(l,d){var f=e.node.childNodes,u=l.attributes[Je];if(Object.prototype.hasOwnProperty.call(o,u)){var p=o[u];Array.prototype.indexOf.call(f,p.node)!==d&&$(e,p,f[d]),s[d]=p,delete o[u],n(l,s[d])}else $(e,l,f[d]),s[d]=l}):y(t.children,function(l,d){var f=e.children[d];typeof f<"u"?(n(l,f),s[d]=f):(e.node.appendChild(l.node),s[d]=l)}),e.children=s;var c=e.node.childNodes.length,a=c-r;if(a>0)for(;a>0;)e.node.removeChild(e.node.childNodes[c-1]),c--,a--}}var z=function t(e,n,r){if(!(!e||!n)){r=r||n.node.parentNode;var i=e.content&&e.content!==n.content;if(e.type!==n.type||i)return r.replaceChild(e.node,n.node),He(e,n);Qe(e,n),$e(e,n,t)}};var q=function t(e){var n=arguments.length>1&&arguments[1]!==void 0?arguments[1]:!1;typeof e=="string"&&(e=ke(e));var r=e.tagName==="BODY",i=e.childNodes,o=i?i.length:0;if(r){if(o>1)throw new Error("[OmDomDom]: Your element should not have more than one root node.");if(o===0)throw new Error("[OmDomDom]: Your element should have at least one root node.");return t(i[0])}var s=e.nodeType===3?"text":e.nodeType===8?"comment":e.tagName.toLowerCase(),c=n||s==="svg",a=e.nodeType===1?Ge(e):{},l=o>0?null:e.textContent,d=Array(o);return y(i,function(f,u){d[u]=t(f,c)}),{type:s,attributes:a,children:d,content:l,node:e,isSVGContext:c}};function D(t,e){var n=[];for(var r of e){let i=t(r);if(i)n.push(i);else break}return n}function X(t,e){let n=0;for(;n<e.length&&t(e[n]);)n++;return e.slice(n)}function N(t){return t.map(e=>e.key+": "+e.value).join(`-`)}function L(t){return{cookies:t.filter(e=>e.key=="Cookie").map(e=>e.value),error:E("Error",t),query:E("Query",t),pageTitle:E("PageTitle",t),events:Z("Event",t).map(P),actions:Z("Trigger",t).map(U)}}function O(t){let e=D(te,t.trim().split(`-`));return L(e)}function E(t,e){return e.find(n=>n.key==t)?.value}function Z(t,e){return e.filter(n=>n.key==t).map(n=>n.value)}function ee(t){let e=t.split(`-`),n=e[0],r=D(te,e.slice(1)),i=X(o=>o=="",e.slice(r.length+1));return{command:n,metas:r,rest:i}}function te(t){let e=t.match(/^(\w+)\: (.*)$/);if(e)return{key:e[1],value:e[2]}}function P(t){let[e,n]=ne(t);return{name:e,detail:JSON.parse(n)}}function U(t){let[e,n]=ne(t);return[e,n]}function ne(t){let e=t.indexOf("|");if(e===-1){let n=new Error("Bad Encoding, Expected Segment");throw n.message=t,n}return[t.slice(0,e),t.slice(e+1)]}function ie(t,e,n,r,i){let o=[{key:"Cookie",value:decodeURI(document.cookie)},{key:"Query",value:window.location.search}];return{viewId:t,action:e,state:n,requestId:r,meta:o,form:_e(i)}}function _e(t){if(!t)return;let e=new URLSearchParams;return t.forEach((n,r)=>{e.append(r,n)}),e}function oe(t){let e=["|ACTION|","ViewId: "+t.viewId,"Action: "+t.action];return t.state&&e.push("State: "+t.state),e.push("RequestId: "+t.requestId),[e.join(`-`),N(t.meta)].join(`-`)+Ye(t.form)}function Ye(t){return t?`--`+t:""}var ze=0;function se(){return{requestId:++ze,isCancelled:!1}}function B(t,e){return t+" "+Xe(e)}function Xe(t){return t==""?"|":t.replace(/_/g,"\\_").replace(/\s+/g,"_")}var Ze=window.location.protocol==="https:"?"wss:":"ws:",ae=`${Ze}//${window.location.host}${window.location.pathname}`,C=class{constructor(e=ae){this.hasEverConnected=!1;this.isConnected=!1;this.reconnectDelay=0;this.queue=[];this.events=new EventTarget;let n=new WebSocket(e);this.socket=n}connect(e=ae,n=!1){let r=n?new WebSocket(e):this.socket;this.socket=r;function i(s){console.error("Connect Error",s)}function o(s){console.error("Socket Error",s)}r.addEventListener("error",i),r.addEventListener("open",s=>{console.log("Websocket Connected"),this.hasEverConnected&&document.dispatchEvent(new Event("hyp-socket-reconnect")),this.isConnected=!0,this.hasEverConnected=!0,this.reconnectDelay=1e3,r.removeEventListener("error",i),r.addEventListener("error",o),document.dispatchEvent(new Event("hyp-socket-connect")),this.runQueue()}),r.addEventListener("close",s=>{console.log("CLOSE SOCKET"),this.isConnected&&document.dispatchEvent(new Event("hyp-socket-disconnect")),this.isConnected=!1,r.removeEventListener("error",o),this.hasEverConnected&&(console.log("Reconnecting in "+this.reconnectDelay/1e3+"s"),setTimeout(()=>this.connect(e,!0),this.reconnectDelay)),r.removeEventListener("error",o)}),r.addEventListener("message",s=>this.onMessage(s))}async sendAction(e){if(this.isConnected){let n=oe(e);this.socket.send(n)}else this.queue.push(e)}runQueue(){let e=this.queue.pop();e&&(console.log("runQueue: ",e),this.sendAction(e),this.runQueue())}onMessage(e){let{command:n,metas:r,rest:i}=ee(e.data),o=parseInt(s("RequestId"),0);function s(u){let p=E(u,r);if(!p)throw new R("Missing Required Metadata: "+u,e.data);return p}function c(u){let p=s("ViewId"),M=s("Action");return{requestId:o,targetViewId:void 0,viewId:p,action:M,meta:L(r),body:u.join(`-`)}}function a(u){let p=c(u);return p.targetViewId=E("TargetViewId",r),p}function l(u){let p=u[0];return{requestId:o,meta:L(r),url:p}}function d(u){let{requestId:p,meta:M,viewId:V,action:H}=c(u),[k,Le]=U(s("Trigger"));return{requestId:p,meta:M,viewId:V,action:H,targetViewId:k,targetAction:Le}}function f(u){let{requestId:p,meta:M,viewId:V,action:H}=c(u),k=P(s("Event"));return{requestId:p,meta:M,viewId:V,action:H,event:k}}switch(n){case"|UPDATE|":return this.dispatchEvent(new CustomEvent("update",{detail:a(i)}));case"|RESPONSE|":return this.dispatchEvent(new CustomEvent("response",{detail:c(i)}));case"|REDIRECT|":return this.dispatchEvent(new CustomEvent("redirect",{detail:l(i)}));case"|TRIGGER|":return this.dispatchEvent(new CustomEvent("trigger",{detail:d(i)}));case"|EVENT|":return this.dispatchEvent(new CustomEvent("event",{detail:f(i)}));default:throw new R("Unknown Server Command: "+n,e.data)}}addEventListener(e,n){this.events.addEventListener(e,n)}dispatchEvent(e){this.events.dispatchEvent(e)}disconnect(){this.isConnected=!1,this.hasEverConnected=!1,this.socket.close()}},R=class extends Error{constructor(e,n){super(e+`-`+n),this.name="ProtocolError"}};function K(t,e=100,n={}){if(typeof t!="function")throw new TypeError(`Expected the first parameter to be a function, got \`${typeof t}\`.`);if(e<0)throw new RangeError("`wait` must not be negative.");if(typeof n=="boolean")throw new TypeError("The `options` parameter must be an object, not a boolean. Use `{immediate: true}` instead.");let{immediate:r}=n,i,o,s,c,a;function l(){let u=i,p=o;return i=void 0,o=void 0,a=t.apply(u,p),a}function d(){let u=Date.now()-c;u<e&&u>=0?s=setTimeout(d,e-u):(s=void 0,r||(a=l()))}let f=function(...u){if(i&&this!==i&&Object.getPrototypeOf(this)===Object.getPrototypeOf(i))throw new Error("Debounced method called with different contexts of the same prototype.");i=this,o=u,c=Date.now();let p=r&&!s;if(s||(s=setTimeout(d,e)),p)return a=l(),a};return Object.defineProperty(f,"isPending",{get(){return s!==void 0}}),f.clear=()=>{s&&(clearTimeout(s),s=void 0,i=void 0,o=void 0)},f.flush=()=>{s&&f.trigger()},f.trigger=()=>{a=l(),f.clear()},f}var T=t=>t?.runAction!==void 0;function j(t){let e=new Event("hyp-content",{bubbles:!0});t.dispatchEvent(e)}function F(t,e){t.querySelectorAll("[id]").forEach(n=>{n.runAction=function(r){return e(n,r)},n.concurrency=n.dataset.concurrency||"Drop",n.cancelActiveRequest=function(){n.activeRequest&&!n.activeRequest?.isCancelled&&(n.activeRequest.isCancelled=!0)},j(t)})}function ce(t){de("keydown",t)}function ue(t){de("keyup",t)}function de(t,e){document.addEventListener(t,function(n){if(!(n.target instanceof HTMLElement)){console.warn("listenKeyEvent received event with non HTMLElment as EventTarget: %o",n);return}let r=n.target,i="on"+t+n.key,o=r.dataset[i];if(!o)return;n.preventDefault();let s=w(r);if(!s){console.error("Missing target: ",r);return}e(s,o)})}function le(t,e){document.addEventListener(t,function(n){if(!(n.target instanceof HTMLElement)){console.warn("listenBubblingEvent received an event with non HTMLElment as EventTarget: %o",n);return}let i=n.target.closest("[data-on"+t+"]");if(!i)return;n.preventDefault();let o=w(i);if(!o){console.error("Missing target: ",i);return}let s=i.dataset["on"+t];if(s===void 0){console.error("Missing action: ",i,t);return}e(o,s)})}function pe(t){le("click",t)}function fe(t){le("dblclick",t)}function ge(t){document.addEventListener("hyp-load",function(e){let n=e.detail.onLoad,r=e.detail.target;t(r,n)}),document.addEventListener("hyp-mouseenter",function(e){let n=e.detail.onMouseEnter,r=e.detail.target;t(r,n)}),document.addEventListener("hyp-mouseleave",function(e){let n=e.detail.onMouseLeave,r=e.detail.target;t(r,n)})}function W(t){t.querySelectorAll("[data-onload]").forEach(e=>{let n=parseInt(e.dataset.delay||"")||0,r=e.dataset.onload;setTimeout(()=>{let i=w(e);if(e.dataset.onload!=r)return;let o=new CustomEvent("hyp-load",{bubbles:!0,detail:{target:i,onLoad:r}});e.dispatchEvent(o)},n)})}function G(t){t.querySelectorAll("[data-onmouseenter]").forEach(e=>{let n=e.dataset.onmouseenter,r=J(e);e.onmouseenter=()=>{let i=new CustomEvent("hyp-mouseenter",{bubbles:!0,detail:{target:r,onMouseEnter:n}});e.dispatchEvent(i)}})}function Q(t){t.querySelectorAll("[data-onmouseleave]").forEach(e=>{let n=e.dataset.onmouseleave,r=J(e);e.onmouseleave=()=>{let i=new CustomEvent("hyp-mouseleave",{bubbles:!0,detail:{target:r,onMouseLeave:n}});e.dispatchEvent(i)}})}function ve(t){document.addEventListener("change",function(e){if(!(e.target instanceof HTMLElement)){console.warn("listenChange received an event with non HTMLElment as EventTarget: %o",e);return}let r=e.target.closest("[data-onchange]");if(!r)return;if(e.preventDefault(),r.value===null){console.error("Missing input value:",r);return}let i=w(r);if(!i){console.error("Missing target: listenChange");return}if(!r.dataset.onchange){console.error("Missing onchange: ",r);return}let o=B(r.dataset.onchange,r.value);t(i,o)})}function me(t,e){document.addEventListener("input",function(n){if(!(n.target instanceof HTMLElement)){console.warn("listenInput received an event with non HTMLElment as EventTarget: %o",n);return}let i=n.target.closest("[data-oninput]");if(!i)return;let o=parseInt(i.dataset.delay||"")||250;o<250&&console.warn("Input delay < 250 can result in poor performance."),n.preventDefault();let s=w(i);if(!s){console.error("Missing target: ",i);return}t(s),i.debouncedCallback||(i.debouncedCallback=K(()=>{if(!i.dataset.oninput){console.error("Missing onInput: ",i);return}let c=B(i.dataset.oninput,i.value);e(s,c)},o)),i.debouncedCallback()})}function ye(t){document.addEventListener("submit",function(e){if(!(e.target instanceof HTMLFormElement)){console.warn("listenFormSubmit received an event with non HTMLElment as EventTarget: %o",e);return}let n=e.target;if(!n.dataset.onsubmit){console.error("Missing onSubmit: ",n);return}e.preventDefault();let r=w(n),i=new FormData(n);if(!r){console.error("Missing target: ",n);return}t(r,n.dataset.onsubmit,i)})}function Ne(t){return t.closest("[data-target]")?.dataset.target||t.closest("[id]")?.id}function w(t){let e=J(t);if(!T(e)){console.error("Non HyperView target: ",e);return}return e}function J(t){let e=Ne(t),n=e&&document.getElementById(e);if(!n){console.error("Cannot find target: ",e,t);return}return n}function he(t){if(t!=et()){t!=""&&(t="?"+t);let e=location.pathname+t;window.history.replaceState({},"",e)}}function et(){let t=window.location.search;return t.startsWith("?")?t.substring(1):t}function Ee(t){let n=new DOMParser().parseFromString(t,"text/html"),r=n.querySelector("style");return{content:n.querySelector("div"),css:r}}var we={name:"web-ui",version:"0.6.0",description:"Development -----------",main:"index.js",directories:{client:"client"},scripts:{build:"esbuild src/index.ts --bundle --minify --sourcemap --outfile=dist/hyperbole.js",dev:"esbuild src/index.ts --bundle --minify --sourcemap --watch=forever --outfile=dist/hyperbole.js",check:"tsc --noEmit --preserveWatchOutput --watch"},author:"",license:"ISC",devDependencies:{esbuild:"^0.28.0",typescript:"^6.0.3"},dependencies:{omdomdom:"^0.3.2",debounce:"^3.0.0"}};console.log("Hyperbole "+we.version+"b");var b,be=new Set;async function v(t,e,n){if(t.activeRequest&&!t.activeRequest?.isCancelled&&t.concurrency=="Drop"){console.warn("Drop action overlapping with active request ("+t.activeRequest+")",e);return}t._timeout=window.setTimeout(()=>{t.classList.add("hyp-loading")},100);let r=t.dataset.state,i=se(),o=ie(t.id,e,r,i.requestId,n);t.activeRequest=i,h.sendAction(o)}function nt(t){Ae(t.targetViewId,t.targetAction)}function rt(t){let e=document.getElementById(t.viewId);xe(t.event,e)}function it(t){console.log("REDIRECT",t),Te(t.meta.cookies??[]),window.location.href=t.url}function ot(t){let e=Me(t);e&&(delete e.activeRequest,clearTimeout(e._timeout),e.classList.remove("hyp-loading"))}function Me(t){let e=t.targetViewId||t.viewId,n=document.getElementById(e);if(!T(n)){console.error("Missing Update HyperView Target: ",e,t);return}if(n.activeRequest?.requestId&&t.requestId<n.activeRequest.requestId)return console.warn("Ignore Stale Action ("+t.requestId+") vs ("+n.activeRequest.requestId+"): "+t.action),n;if(n.activeRequest?.isCancelled)return console.warn("Cancelled request",n.activeRequest?.requestId),delete n.activeRequest,n;let r=Ee(t.body);if(!r.content)return console.error("Empty Response!",t.body),n;at(r.css);let i=q(n),o=q(r.content),s=o.attributes;if(!t.meta.error&&s.id!=n.id){console.error("Mismatched ViewId in update - ",s.id," target:",n.id);return}let c=s["data-state"];o.attributes=i.attributes,z(o,i);let a=document.getElementById(n.id);return a?(j(a),c===void 0||c=="()"?delete a.dataset.state:a.dataset.state=c,Ie(t.meta,a),Te(t.meta.cookies??[]),W(a),G(a),Q(a),st(a),F(a,v),n):(console.warn("Target Missing: ",n.id),n)}function Te(t){t.forEach(e=>{console.log("SetCookie: ",e),document.cookie=e})}function Ie(t,e){t.query!=null&&he(t.query),t.pageTitle!=null&&(document.title=t.pageTitle),t.events?.forEach(n=>{xe(n,e)}),t.actions?.forEach(([n,r])=>{Ae(n,r)})}function xe(t,e){setTimeout(()=>{let n=new CustomEvent(t.name,{bubbles:!0,detail:t.detail});(e||document).dispatchEvent(n)},10)}function Ae(t,e){setTimeout(()=>{let n=window.Hyperbole?.hyperView(t);n&&v(n,e)},10)}function st(t){let e=t.querySelector("[autofocus]");e?.focus&&e.focus(),t.querySelectorAll("input[value]").forEach(n=>{let r=n.getAttribute("value");r!==null&&(n.value=r)}),t.querySelectorAll("input[type=checkbox]").forEach(n=>{let r=n.dataset.checked=="True";n.checked=r})}function at(t){if(!t)return;let e=t.sheet?.cssRules;if(e)for(let n=0;n<e.length;n++){let r=e.item(n);r&&be.has(r.cssText)==!1&&b.sheet&&(b.sheet.insertRule(r.cssText),be.add(r.cssText))}}function ct(){let t=O(document.getElementById("hyp.metadata")?.innerText??"");Ie(t,null);let e=document.body.querySelector("style");e!==null?b=e:(console.warn("rootStyles missing from page, creating..."),b=document.createElement("style"),b.type="text/css",document.body.appendChild(b)),ge(async function(r,i){v(r,i)}),W(document.body),G(document.body),Q(document.body),F(document.body,v),pe(async function(r,i){v(r,i)}),fe(async function(r,i){v(r,i)}),ce(async function(r,i){v(r,i)}),ue(async function(r,i){v(r,i)}),ye(async function(r,i,o){v(r,i,o)}),ve(async function(r,i){v(r,i)});function n(r){r.concurrency=="Replace"&&r.cancelActiveRequest()}me(n,async function(r,i){v(r,i)})}document.addEventListener("DOMContentLoaded",ct);var h=new C;h.connect();h.addEventListener("update",t=>{Me(t.detail)});h.addEventListener("response",t=>ot(t.detail));h.addEventListener("redirect",t=>it(t.detail));h.addEventListener("trigger",t=>nt(t.detail));h.addEventListener("event",t=>rt(t.detail));window.Hyperbole={runAction:v,parseMetadata:O,action:function(t,...e){return e.reduce((n,r)=>n+" "+JSON.stringify(r),t)},hyperView:function(t){let e=document.getElementById(t);if(!T(e)){console.error("Element id="+t+" was not a HyperView");return}return e},socket:h};})();-/*! Bundled license information:+(function(){var e=`data-key`,t=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n=function(e,n){return n?t(e,n)?(console.warn(`[OmDomDom]: Children with duplicate keys detected. Children with duplicate keys will be skipped, resulting in dropped node references. Keys must be unique and non-indexed.`),!1):!0:!1},r=function(e,t){var n=e.length,r=-1;if(n)for(;++r<n&&t(e[r],r)!==!1;);},i=function(t){var i={};for(var a in r(t,function(t){var r=t.attributes[e];n(i,r)&&(i[r]=t)}),i)return i},a=function(e,t,n){return e.node.insertBefore(t.node,n)},o=function(e,t){for(var n in e)t[n]=e[n]},s=function(e){var t=e.trim().replace(/\s+</g,`<`).replace(/>\s+/g,`>`);return new DOMParser().parseFromString(t,`text/html`).body};function c(e,t){var n=e==null?null:typeof Symbol<`u`&&e[Symbol.iterator]||e[`@@iterator`];if(n!=null){var r,i,a,o,s=[],c=!0,l=!1;try{if(a=(n=n.call(e)).next,t===0){if(Object(n)!==n)return;c=!1}else for(;!(c=(r=a.call(n)).done)&&(s.push(r.value),s.length!==t);c=!0);}catch(e){l=!0,i=e}finally{try{if(!c&&n.return!=null&&(o=n.return(),Object(o)!==o))return}finally{if(l)throw i}}return s}}function l(e,t){return u(e)||c(e,t)||d(e,t)||ee()}function u(e){if(Array.isArray(e))return e}function d(e,t){if(e){if(typeof e==`string`)return f(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);if(n===`Object`&&e.constructor&&(n=e.constructor.name),n===`Map`||n===`Set`)return Array.from(e);if(n===`Arguments`||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))return f(e,t)}}function f(e,t){(t==null||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n<t;n++)r[n]=e[n];return r}function ee(){throw TypeError(`Invalid attempt to destructure non-iterable instance.+In order to be iterable, non-array objects must have a [Symbol.iterator]() method.`)}var p={STRING:`string`,INT:`number`,BOOL:`boolean`},m={},h=function(e,t,n){return{attrName:e,propName:t,type:n}};r([[`style`,`cssText`],[`class`,`className`]],function(e){var t=l(e,2),n=t[0],r=t[1];m[n]=h(n,r||n,p.STRING)}),r([`autofocus`,`draggable`,`hidden`,`checked`,`multiple`,`muted`,`selected`],function(e){m[e]=h(e,e,p.BOOL)}),r([[`tabindex`,`tabIndex`]],function(e){var t=l(e,2),n=t[0],r=t[1];m[n]=h(n,r,p.INT)});var g={xlink:{prefix:`xlink:`,resource:`http://www.w3.org/1999/xlink`},xml:{prefix:`xml:`,resource:`http://www.w3.org/XML/1998/namespace`}},_=function(e,t,n,r){switch(t){case p.STRING:n===m.style.propName?r===null?e.style[n]=``:e.style[n]=r:r===null?e[n]=``:e[n]=r;break;case p.INT:if(r===null){var i=n.toLowerCase();e.removeAttribute(i)}else if(r===`0`)e[n]=0;else if(r===`-1`)e[n]=-1;else{var a=parseInt(r,10);isNaN(a)||(e[n]=a)}break;case p.BOOL:[``,`true`].indexOf(r)<0?e[n]=!1:e[n]=!0;break}},te=function(e,n){r(n,function(n){if(t(m,n)){var r=m[n];_(e.node,r.type,r.propName,null)}else n in e.node&&_(e.node,p.STRING,n,null),e.node.removeAttribute(n);delete e.attributes[n]})},ne=function(e,n){for(var r in n){var i=n[r];if(e.attributes[r]=i,t(m,r)){var a=m[r];_(e.node,a.type,a.propName,i);continue}if(r.startsWith(g.xlink.prefix)){e.node.setAttributeNS(g.xlink.resource,r,i);continue}if(r.startsWith(g.xml.prefix)){e.node.setAttributeNS(g.xml.resource,r,i);continue}r in e.node&&_(e.node,p.STRING,r,i),e.node.setAttribute(r,i||``)}},re=function(e,t){for(var n in m){var r=m[n].propName,i=e.getAttribute(n);n===m.style.attrName?t[n]=e.style[r]:typeof i==`string`&&(t[n]=i)}},ie=function(e){return Array.prototype.reduce.call(e.attributes,function(e,n){return t(m,n.name)||(e[n.name]=n.value),e},{})},ae=function(e){var t=ie(e);return re(e,t),t},oe=function(e,t){var n=[],r={};for(var i in t.attributes){var a=t.attributes[i],o=e.attributes[i];a!==o&&o===void 0&&n.push(i)}for(var s in e.attributes){var c=t.attributes[s],l=e.attributes[s];c!==l&&l!==void 0&&(r[s]=l)}te(t,n),ne(t,r)},se=`data-key`;function ce(e,t,n){var o=e.children.length,s=t.children.length;if(!(!o&&!s)){var c=i(t.children),l=Array(o);c===void 0?r(e.children,function(e,r){var i=t.children[r];i===void 0?(t.node.appendChild(e.node),l[r]=e):(n(e,i),l[r]=i)}):r(e.children,function(e,r){var i=t.node.childNodes,o=e.attributes[se];if(Object.prototype.hasOwnProperty.call(c,o)){var s=c[o];Array.prototype.indexOf.call(i,s.node)!==r&&a(t,s,i[r]),l[r]=s,delete c[o],n(e,l[r])}else a(t,e,i[r]),l[r]=e}),t.children=l;var u=t.node.childNodes.length,d=u-o;if(d>0)for(;d>0;)t.node.removeChild(t.node.childNodes[u-1]),u--,d--}}var le=function e(t,n,r){if(!(!t||!n)){r||=n.node.parentNode;var i=t.content&&t.content!==n.content;if(t.type!==n.type||i)return r.replaceChild(t.node,n.node),o(t,n);oe(t,n),ce(t,n,e)}},v=function e(t){var n=arguments.length>1&&arguments[1]!==void 0?arguments[1]:!1;typeof t==`string`&&(t=s(t));var i=t.tagName===`BODY`,a=t.childNodes,o=a?a.length:0;if(i){if(o>1)throw Error(`[OmDomDom]: Your element should not have more than one root node.`);if(o===0)throw Error(`[OmDomDom]: Your element should have at least one root node.`);return e(a[0])}var c=t.nodeType===3?`text`:t.nodeType===8?`comment`:t.tagName.toLowerCase(),l=n||c===`svg`,u=t.nodeType===1?ae(t):{},d=o>0?null:t.textContent,f=Array(o);return r(a,function(t,n){f[n]=e(t,l)}),{type:c,attributes:u,children:f,content:d,node:t,isSVGContext:l}};function ue(e,t){var n=[];for(var r of t){let t=e(r);if(t)n.push(t);else break}return n}function de(e,t){let n=0;for(;n<t.length&&e(t[n]);)n++;return t.slice(n)}function fe(e){return e.map(e=>e.key+`: `+e.value).join(`+`)}function y(e){return{cookies:e.filter(e=>e.key==`Cookie`).map(e=>e.value),error:x(`Error`,e),query:x(`Query`,e),pageTitle:x(`PageTitle`,e),events:S(`Event`,e).map(w),actions:S(`Trigger`,e).map(T)}}function b(e){return y(C(e.trim().split(`+`)))}function x(e,t){return t.find(t=>t.key==e)?.value}function S(e,t){return t.filter(t=>t.key==e).map(e=>e.value)}function C(e){return ue(pe,e)}function pe(e){let t=e.match(/^(\w+): (.*)$/);if(t)return{key:t[1],value:t[2]}}function w(e){let[t,n]=E(e);return{name:t,detail:JSON.parse(n)}}function T(e){let[t,n]=E(e);return[t,n]}function E(e){let t=e.indexOf(`|`);if(t===-1){let t=Error(`Bad Encoding, Expected Segment`);throw t.message=e,t}return[e.slice(0,t),e.slice(t+1)]}function me(e,t,n,r,i){let a=[{key:`Cookie`,value:decodeURI(document.cookie)},{key:`Query`,value:window.location.search}],o,s;return i instanceof FormData?o=i:i&&(s=i),{viewId:e,action:t,state:n,requestId:r,meta:a,form:o,value:s}}function he(e){let t=[`|ACTION|`,`ViewId: `+e.viewId,`Action: `+e.action];return e.state&&t.push(`State: `+e.state),t.push(`RequestId: `+e.requestId),[t.join(`+`),fe(e.meta)].join(`+`)+ge(e.value)}function ge(e){return e?` -omdomdom/lib/omdomdom.es.js:-  (*!-    * @license MIT (https://github.com/geotrev/omdomdom/blob/master/LICENSE)-    * Omdomdom v0.3.2 (https://github.com/geotrev/omdomdom)-    * Copyright 2023 George Treviranus <geowtrev@gmail.com>-    *)-*/+`+e:``}var _e=0;function ve(){return{requestId:++_e,isCancelled:!1}}function ye(e){return new DOMParser().parseFromString(e,`text/html`)}function be(e){let t=e.querySelector(`style`);return{content:e.querySelector(`div`),css:t}}function xe(e,t){let n=D(t,e,`ViewId`),r=D(t,e,`Action`);return{kind:`response`,requestId:parseInt(D(t,e,`RequestId`),0),targetViewId:void 0,viewId:n,action:r,meta:y(e),body:t.join(`+`)}}function D(e,t,n){let r=x(n,t);if(!r)throw new O(`Missing Required Metadata: `+n,e.join(`+`));return r}var O=class extends Error{constructor(e,t){super(e+`+`+t),this.name=`ProtocolError`}},k=`${window.location.protocol===`https:`?`wss:`:`ws:`}//${window.location.host}${window.location.pathname}`,A=class{socket;hasEverConnected=!1;isConnected=!1;reconnectDelay=0;queue=[];events;constructor(e=k){this.events=new EventTarget;let t=new WebSocket(e);this.socket=t}connect(e=k,t=!1){let n=t?new WebSocket(e):this.socket;this.socket=n;function r(e){console.error(`Connect Error`,e)}function i(e){console.error(`Socket Error`,e)}n.addEventListener(`error`,r),n.addEventListener(`open`,e=>{console.log(`Websocket Connected`),this.hasEverConnected&&document.dispatchEvent(new Event(`hyp-socket-reconnect`)),this.isConnected=!0,this.hasEverConnected=!0,this.reconnectDelay=1e3,n.removeEventListener(`error`,r),n.addEventListener(`error`,i),document.dispatchEvent(new Event(`hyp-socket-connect`)),this.runQueue()}),n.addEventListener(`close`,t=>{console.log(`CLOSE SOCKET`),this.isConnected&&document.dispatchEvent(new Event(`hyp-socket-disconnect`)),this.isConnected=!1,n.removeEventListener(`error`,i),this.hasEverConnected&&(console.log(`Reconnecting in `+this.reconnectDelay/1e3+`s`),setTimeout(()=>this.connect(e,!0),this.reconnectDelay)),n.removeEventListener(`error`,i)}),n.addEventListener(`message`,e=>this.onMessage(e))}async sendAction(e){if(this.isConnected){let t=he(e);this.socket.send(t)}else this.queue.push(e)}runQueue(){let e=this.queue.pop();e&&(console.log(`runQueue: `,e),this.sendAction(e),this.runQueue())}onMessage(e){let{command:t,metas:n,rest:r}=j(e.data),i=parseInt(a(`RequestId`),0);function a(t){let r=x(t,n);if(!r)throw new O(`Missing Required Metadata: `+t,e.data);return r}function o(e){return{requestId:i,targetViewId:void 0,viewId:a(`ViewId`),action:a(`Action`),meta:y(n),body:e.join(`+`)}}function s(e){let t=o(e);return t.targetViewId=x(`TargetViewId`,n),t}function c(e){let t=e[0];return{requestId:i,meta:y(n),url:t}}function l(e){let{requestId:t,meta:n,viewId:r,action:i}=o(e),[s,c]=T(a(`Trigger`));return{requestId:t,meta:n,viewId:r,action:i,targetViewId:s,targetAction:c}}function u(e){let{requestId:t,meta:n,viewId:r,action:i}=o(e);return{requestId:t,meta:n,viewId:r,action:i,event:w(a(`Event`))}}switch(t){case`|UPDATE|`:this.dispatchEvent(new CustomEvent(`update`,{detail:s(r)}));return;case`|RESPONSE|`:this.dispatchEvent(new CustomEvent(`response`,{detail:o(r)}));return;case`|REDIRECT|`:return this.dispatchEvent(new CustomEvent(`redirect`,{detail:c(r)}));case`|TRIGGER|`:return this.dispatchEvent(new CustomEvent(`trigger`,{detail:l(r)}));case`|EVENT|`:return this.dispatchEvent(new CustomEvent(`event`,{detail:u(r)}));default:throw new O(`Unknown Server Command: `+t,e.data)}}addEventListener(e,t){this.events.addEventListener(e,t)}dispatchEvent(e){this.events.dispatchEvent(e)}disconnect(){this.isConnected=!1,this.hasEverConnected=!1,this.socket.close()}};function j(e){let t=e.split(`+`),n=t[0],r=C(t.slice(1));return{command:n,metas:r,rest:de(e=>e==``,t.slice(r.length+1))}}function M(e,t=100,n={}){if(typeof e!=`function`)throw TypeError(`Expected the first parameter to be a function, got \`${typeof e}\`.`);if(t<0)throw RangeError("`wait` must not be negative.");if(typeof n==`boolean`)throw TypeError("The `options` parameter must be an object, not a boolean. Use `{immediate: true}` instead.");let{immediate:r}=n,i,a,o,s,c;function l(){let t=i,n=a;return i=void 0,a=void 0,c=e.apply(t,n),c}function u(){let e=Date.now()-s;e<t&&e>=0?o=setTimeout(u,t-e):(o=void 0,r||(c=l()))}let d=function(...e){if(i&&this!==i&&Object.getPrototypeOf(this)===Object.getPrototypeOf(i))throw Error(`Debounced method called with different contexts of the same prototype.`);i=this,a=e,s=Date.now();let n=r&&!o;if(o||=setTimeout(u,t),n)return c=l(),c};return Object.defineProperty(d,`isPending`,{get(){return o!==void 0}}),d.clear=()=>{o&&(clearTimeout(o),o=void 0,i=void 0,a=void 0)},d.flush=()=>{o&&d.trigger()},d.trigger=()=>{c=l(),d.clear()},d}var N=e=>e?.runAction!==void 0;function P(e){let t=new Event(`hyp-content`,{bubbles:!0});e.dispatchEvent(t)}function F(e,t){e.querySelectorAll(`[id]`).forEach(n=>{n.runAction=function(e,r){return t(n,e,r)},n.concurrency=n.dataset.concurrency||`Drop`,n.cancelActiveRequest=function(){n.activeRequest&&!n.activeRequest?.isCancelled&&(n.activeRequest.isCancelled=!0)},P(e)})}function Se(e){I(`keydown`,e)}function Ce(e){I(`keyup`,e)}function I(e,t){document.addEventListener(e,function(n){if(!(n.target instanceof HTMLElement)){console.warn(`listenKeyEvent received event with non HTMLElment as EventTarget: %o`,n);return}let r=n.target,i=`on`+e+n.key,a=r.dataset[i];if(!a)return;n.preventDefault();let o=V(r);if(!o){console.error(`Missing target: `,r);return}t(o,a)})}function L(e,t){document.addEventListener(e,function(n){if(!(n.target instanceof Element)){console.warn(`listenBubblingEvent received an event with non Elment as EventTarget: %o`,n);return}let r=n.target.closest(`[data-on`+e+`]`);if(!r)return;n.preventDefault();let i=V(r);if(!i){console.error(`Missing target: `,r);return}let a=r.dataset[`on`+e];if(a===void 0){console.error(`Missing action: `,r,e);return}t(i,a)})}function we(e){L(`click`,e)}function Te(e){L(`dblclick`,e)}function Ee(e){document.addEventListener(`hyp-load`,function(t){let n=t.detail.onLoad,r=t.detail.target;e(r,n)}),document.addEventListener(`hyp-mouseenter`,function(t){let n=t.detail.onMouseEnter,r=t.detail.target;e(r,n)}),document.addEventListener(`hyp-mouseleave`,function(t){let n=t.detail.onMouseLeave,r=t.detail.target;e(r,n)})}function R(e){e.querySelectorAll(`[data-onload]`).forEach(e=>{let t=parseInt(e.dataset.delay||``)||0,n=e.dataset.onload;setTimeout(()=>{let t=V(e);if(e.dataset.onload!=n)return;let r=new CustomEvent(`hyp-load`,{bubbles:!0,detail:{target:t,onLoad:n}});e.dispatchEvent(r)},t)})}function z(e){e.querySelectorAll(`[data-onmouseenter]`).forEach(e=>{let t=e.dataset.onmouseenter,n=H(e);e.onmouseenter=()=>{let r=new CustomEvent(`hyp-mouseenter`,{bubbles:!0,detail:{target:n,onMouseEnter:t}});e.dispatchEvent(r)}})}function B(e){e.querySelectorAll(`[data-onmouseleave]`).forEach(e=>{let t=e.dataset.onmouseleave,n=H(e);e.onmouseleave=()=>{let r=new CustomEvent(`hyp-mouseleave`,{bubbles:!0,detail:{target:n,onMouseLeave:t}});e.dispatchEvent(r)}})}function De(e){document.addEventListener(`change`,function(t){if(!(t.target instanceof HTMLElement)){console.warn(`listenChange received an event with non HTMLElment as EventTarget: %o`,t);return}let n=t.target.closest(`[data-onchange]`);if(!n)return;if(t.preventDefault(),n.value===null){console.error(`Missing input value:`,n);return}let r=V(n);if(!r){console.error(`Missing target: listenChange`);return}if(!n.dataset.onchange){console.error(`Missing onchange: `,n);return}e(r,n.dataset.onchange,n.value)})}function Oe(e,t){document.addEventListener(`input`,function(n){if(!(n.target instanceof HTMLElement)){console.warn(`listenInput received an event with non HTMLElment as EventTarget: %o`,n);return}let r=n.target.closest(`[data-oninput]`);if(!r)return;let i=parseInt(r.dataset.delay||``)||250;i<250&&console.warn(`Input delay < 250 can result in poor performance.`),n.preventDefault();let a=V(r);if(!a){console.error(`Missing target: `,r);return}e(a),r.debouncedCallback||=M(()=>{if(!r.dataset.oninput){console.error(`Missing onInput: `,r);return}t(a,r.dataset.oninput,r.value)},i),r.debouncedCallback()})}function ke(e){document.addEventListener(`submit`,function(t){if(!(t.target instanceof HTMLFormElement)){console.warn(`listenFormSubmit received an event with non HTMLElment as EventTarget: %o`,t);return}let n=t.target;if(!n.dataset.onsubmit){console.error(`Missing onSubmit: `,n);return}t.preventDefault();let r=V(n),i=new FormData(n);if(!r){console.error(`Missing target: `,r);return}e(r,n.dataset.onsubmit,i)})}function Ae(e){return e.closest(`[data-target]`)?.dataset.target||e.closest(`[id]`)?.id}function V(e){let t=H(e);if(!N(t)){console.error(`Non HyperView target: `,t);return}return t}function H(e){let t=Ae(e),n=t&&document.getElementById(t);if(!n){console.error(`Cannot find target: `,t,e);return}return n}function je(e){if(e!=Me()){e!=``&&(e=`?`+e);let t=location.pathname+e;window.history.replaceState({},``,t)}}function Me(){let e=window.location.search;return e.startsWith(`?`)?e.substring(1):e}async function Ne(e){let t=window.location.href,n={Accept:`text/html`,"Hyp-ViewId":e.viewId,"Hyp-RequestId":e.requestId,"Hyp-Action":e.action,"Hyp-State":e.state||`()`};console.log(`sendActionHttp`,e.form);let{metas:r,rest:i}=Pe(await(await fetch(t,{method:`POST`,headers:n,body:e.form,redirect:`manual`})).text());return xe(r,i)}function Pe(e){let t=e.split(`+`);return{metas:C(t.slice(1)),rest:t.slice(2)}}console.log(`Hyperbole 0.7.0b`);var U,W=new Set;async function G(e,t,n){if(e.activeRequest&&!e.activeRequest?.isCancelled&&e.concurrency==`Drop`){console.warn(`Drop action overlapping with active request`,e.activeRequest,t);return}e._timeout=window.setTimeout(()=>{e.classList.add(`hyp-loading`)},100);let r=e.dataset.state,i=ve(),a=me(e.id,t,r,i.requestId,n);if(e.activeRequest=i,!a.form)$.sendAction(a);else{let e=await Ne(a);switch(console.log(`RESPONSE`,e),e.kind){case`redirect`:console.log(`TODO HANDLE REDIRECT`);break;case`response`:q(e);break}}}function K(e){Q(e.targetViewId,e.targetAction)}function Fe(e){let t=document.getElementById(e.viewId);Z(e.event,t)}function Ie(e){console.log(`REDIRECT`,e),Y(e.meta.cookies??[]),window.location.href=e.url}function q(e){let t=J(e.viewId,e);t&&(delete t.activeRequest,clearTimeout(t._timeout),t.classList.remove(`hyp-loading`))}function Le(e){e.meta.error?J(e.viewId,e):e.targetViewId?J(e.targetViewId,e):console.error(`Missing Update targetViewId`,e)}function J(e,t){let n=document.getElementById(e);if(!N(n)){console.error(`Missing Update HyperView Target: `,e,t);return}if(n.activeRequest?.requestId&&t.requestId<n.activeRequest.requestId)return console.warn(`Ignore Stale Action (`+t.requestId+`) vs (`+n.activeRequest.requestId+`): `+t.action),n;if(n.activeRequest?.isCancelled)return console.warn(`Cancelled request`,n.activeRequest?.requestId),delete n.activeRequest,n;let r=be(ye(t.body));if(!r.content)return console.error(`Empty Response!`,t.body),n;ze(r.css);let i=v(n),a=v(r.content),o=a.attributes;if(!t.meta.error&&o.id!=n.id){console.error(`Mismatched ViewId in update - `,o.id,` target:`,n.id);return}let s=o[`data-state`];a.attributes=i.attributes,le(a,i);let c=document.getElementById(n.id);return c?(P(c),s===void 0||s==`()`?delete c.dataset.state:c.dataset.state=s,X(t.meta,c),Y(t.meta.cookies??[]),R(c),z(c),B(c),Re(c),F(c,G),n):(console.warn(`Target Missing: `,n.id),n)}function Y(e){e.forEach(e=>{console.log(`SetCookie: `,e),document.cookie=e})}function X(e,t){e.query!=null&&je(e.query),e.pageTitle!=null&&(document.title=e.pageTitle),e.events?.forEach(e=>{Z(e,t)}),e.actions?.forEach(([e,t])=>{Q(e,t)})}function Z(e,t){setTimeout(()=>{let n=new CustomEvent(e.name,{bubbles:!0,detail:e.detail});(t||document).dispatchEvent(n)},10)}function Q(e,t){setTimeout(()=>{let n=window.Hyperbole?.hyperView(e);n&&G(n,t,void 0)},10)}function Re(e){let t=e.querySelector(`[autofocus]`);t?.focus&&t.focus(),e.querySelectorAll(`input[value]`).forEach(e=>{let t=e.getAttribute(`value`);t!==null&&(e.value=t)}),e.querySelectorAll(`input[type=checkbox]`).forEach(e=>{e.checked=e.dataset.checked==`True`})}function ze(e){if(!e)return;let t=e.sheet?.cssRules;if(t)for(let e=0;e<t.length;e++){let n=t.item(e);n&&W.has(n.cssText)==0&&U.sheet&&(U.sheet.insertRule(n.cssText),W.add(n.cssText))}}function Be(){X(b(document.getElementById(`hyp.metadata`)?.innerText??``),null);let e=document.body.querySelector(`style`);e===null?(console.warn(`rootStyles missing from page, creating...`),U=document.createElement(`style`),U.type=`text/css`,document.body.appendChild(U)):U=e,Ee(async function(e,t){G(e,t,void 0)}),R(document.body),z(document.body),B(document.body),F(document.body,G),we(async function(e,t){G(e,t,void 0)}),Te(async function(e,t){G(e,t,void 0)}),Se(async function(e,t){G(e,t,void 0)}),Ce(async function(e,t){G(e,t)}),ke(async function(e,t,n){G(e,t,n)}),De(async function(e,t,n){G(e,t,n)});function t(e){e.concurrency==`Replace`&&e.cancelActiveRequest()}Oe(t,async function(e,t,n){G(e,t,n)})}document.addEventListener(`DOMContentLoaded`,Be);var $=new A;$.connect(),$.addEventListener(`update`,e=>Le(e.detail)),$.addEventListener(`response`,e=>q(e.detail)),$.addEventListener(`redirect`,e=>Ie(e.detail)),$.addEventListener(`trigger`,e=>K(e.detail)),$.addEventListener(`event`,e=>Fe(e.detail)),window.Hyperbole={runAction:G,parseMetadata:b,action:function(e,...t){return t.reduce((e,t)=>e+` `+JSON.stringify(t),e)},hyperView:function(e){let t=document.getElementById(e);if(!N(t)){console.error(`Element id=`+e+` was not a HyperView`);return}return t},socket:$}})(); //# sourceMappingURL=hyperbole.js.map
client/dist/hyperbole.js.map view
@@ -1,7 +1,1 @@-{-  "version": 3,-  "sources": ["../node_modules/omdomdom/src/utilities/index.js", "../node_modules/omdomdom/src/parsers/index.js", "../node_modules/omdomdom/src/attributes/records.js", "../node_modules/omdomdom/src/attributes/set-property.js", "../node_modules/omdomdom/src/attributes/index.js", "../node_modules/omdomdom/src/children/index.js", "../node_modules/omdomdom/src/omdomdom.js", "../src/lib.ts", "../src/message.ts", "../src/action.ts", "../src/sockets.ts", "../node_modules/debounce/index.js", "../src/hyperview.ts", "../src/events.ts", "../src/browser.ts", "../src/response.ts", "../package.json", "../src/index.ts"],-  "sourcesContent": ["const DATA_KEY_ATTRIBUTE = \"data-key\"\n\n/**\n * Checks if the object property exists.\n * @param {Object.<string, any>} obj\n * @param {string} prop\n * @returns {boolean}\n */\nexport const hasProperty = (obj, prop) =>\n  Object.prototype.hasOwnProperty.call(obj, prop)\n\n/**\n * Checks if a property in a keyMap is unique. if not, it's skipped.\n * @param {Object.<string, VirtualNode>} map\n * @param {string} key\n * @returns {boolean}\n */\nconst keyIsValid = (map, key) => {\n  if (!key) return false\n\n  if (hasProperty(map, key)) {\n    // eslint-disable-next-line no-console\n    console.warn(\n      \"[OmDomDom]: Children with duplicate keys detected. Children with duplicate keys will be skipped, resulting in dropped node references. Keys must be unique and non-indexed.\"\n    )\n    return false\n  }\n\n  return true\n}\n\n/**\n * lodash forEach, basically.\n * If `false` is explicitly returned, break the loop.\n * @param {[]} items\n * @param fn\n */\nexport const forEach = (items, fn) => {\n  const length = items.length\n  let idx = -1\n\n  if (!length) return\n\n  while (++idx < length) {\n    if (fn(items[idx], idx) === false) break\n  }\n}\n\n/**\n * Generates a <key: vNode> map of a virtual node list.\n * @param {VirtualNode[]} children\n * @returns {Object.<string, VirtualNode>|undefined}\n */\nexport const createKeyMap = (children) => {\n  const map = {}\n\n  forEach(children, (child) => {\n    const key = child.attributes[DATA_KEY_ATTRIBUTE]\n    if (keyIsValid(map, key)) {\n      map[key] = child\n    }\n  })\n\n  // Cheap way to check if the map contains keys,\n  // and if so, returns the map on the first iteration.\n  for (const _ in map) {\n    return map\n  }\n}\n\nexport const insertBefore = (parent, child, refNode) => {\n  return parent.node.insertBefore(child.node, refNode)\n}\n\n/**\n * Transfers properties from one virtual node to another.\n * @param {VirtualNode} template\n * @param {VirtualNode} vNode\n */\nexport const assignVNode = (template, vNode) => {\n  for (let property in template) {\n    vNode[property] = template[property]\n  }\n}\n", "/**\n * Convert stringified HTML into valid HTML, stripping all extra spaces.\n * @param {string} htmlString\n */\nexport const toHTML = (htmlString) => {\n  /**\n   * Remove all extraneous whitespace:\n   * - From the beginning + end of the document fragment\n   * - If there's more than one space before a left tag bracket, replace them with one\n   * - If there's more than one space before a right tag bracket, replace them with one\n   */\n  const processedDOMString = htmlString\n    .trim()\n    .replace(/\\s+</g, \"<\")\n    .replace(/>\\s+/g, \">\")\n\n  const parser = new DOMParser()\n  const context = parser.parseFromString(processedDOMString, \"text/html\")\n\n  return context.body\n}\n", "import { forEach } from \"../utilities\"\n\nconst Types = { STRING: \"string\", INT: \"number\", BOOL: \"boolean\" }\nconst DomProperties = {}\n\n/**\n * Creates a new record for DomProperties\n * @param {string} attrName\n * @param {string} propName\n * @param {string} type\n */\nconst createRecord = (attrName, propName, type) => ({\n  attrName,\n  propName,\n  type,\n})\n\n// Set string records\nconst stringProps = [\n  // Style is a special snowflake, and needs an extra property to set its text\n  // value. This is less confusing and achieves the same result with one reflow,\n  // compared to a new reflow for each Element.style[styleProperty] setter.\n  [\"style\", \"cssText\"],\n  [\"class\", \"className\"],\n]\nforEach(stringProps, ([attr, property]) => {\n  DomProperties[attr] = createRecord(attr, property || attr, Types.STRING)\n})\n\n// Set boolean records\nconst booleanProps = [\n  \"autofocus\",\n  \"draggable\",\n  \"hidden\",\n  \"checked\",\n  \"multiple\",\n  \"muted\",\n  \"selected\",\n]\nforEach(booleanProps, (attr) => {\n  DomProperties[attr] = createRecord(attr, attr, Types.BOOL)\n})\n\n// Set Integer records\nconst integerProps = [[\"tabindex\", \"tabIndex\"]]\nforEach(integerProps, ([attr, property]) => {\n  DomProperties[attr] = createRecord(attr, property, Types.INT)\n})\n\n/**\n * Attributes with these namespaces require `setAttributeNS`\n * @type {Object.<string, string>}\n */\nconst Namespace = {\n  xlink: {\n    prefix: \"xlink:\",\n    resource: \"http://www.w3.org/1999/xlink\",\n  },\n  xml: {\n    prefix: \"xml:\",\n    resource: \"http://www.w3.org/XML/1998/namespace\",\n  },\n}\n\nexport { Types, Namespace, DomProperties }\n", "import { Types, DomProperties } from \"./records\"\n\n/**\n * Set a given attribute as a property, if it has a property equivalent\n * @param {HTMLElement} node\n * @param {string|number|boolean} type\n * @param {string} prop\n * @param {*} value\n */\nexport const setProperty = (element, type, prop, value) => {\n  switch (type) {\n    case Types.STRING: {\n      if (prop === DomProperties.style.propName) {\n        if (value === null) {\n          element.style[prop] = \"\"\n        } else {\n          element.style[prop] = value\n        }\n      } else if (value === null) {\n        element[prop] = \"\"\n      } else {\n        element[prop] = value\n      }\n      break\n    }\n\n    case Types.INT: {\n      if (value === null) {\n        const attr = prop.toLowerCase()\n        // The attribute needs to be removed to reset the property,\n        // otherwise the value coerced + reflected onto the attribute.\n        element.removeAttribute(attr)\n      } else if (value === \"0\") {\n        element[prop] = 0\n      } else if (value === \"-1\") {\n        element[prop] = -1\n      } else {\n        const parsed = parseInt(value, 10)\n        if (!isNaN(parsed)) {\n          element[prop] = parsed\n        }\n      }\n      break\n    }\n\n    case Types.BOOL: {\n      if ([\"\", \"true\"].indexOf(value) < 0) {\n        element[prop] = false\n      } else {\n        element[prop] = true\n      }\n      break\n    }\n\n    default:\n      break\n  }\n}\n", "import { hasProperty, forEach } from \"../utilities\"\nimport { Namespace, DomProperties, Types } from \"./records\"\nimport { setProperty } from \"./set-property\"\n\n/**\n * Removes stale attributes from the element.\n * @param {HTMLElement} vNode\n * @param {string[]} attributes\n */\nconst removeAttributes = (vNode, attributes) => {\n  forEach(attributes, (attrName) => {\n    if (hasProperty(DomProperties, attrName)) {\n      const propertyRecord = DomProperties[attrName]\n      setProperty(\n        vNode.node,\n        propertyRecord.type,\n        propertyRecord.propName,\n        null\n      )\n    } else {\n      if (attrName in vNode.node) {\n        setProperty(vNode.node, Types.STRING, attrName, null)\n      }\n      vNode.node.removeAttribute(attrName)\n    }\n\n    delete vNode.attributes[attrName]\n  })\n}\n\n/**\n * Adds attributes to the element.\n * @param {VirtualNode} vNode\n * @param {Object.<string, string>} attributes\n */\nconst setAttributes = (vNode, attributes) => {\n  for (let attrName in attributes) {\n    const value = attributes[attrName]\n    vNode.attributes[attrName] = value\n\n    if (hasProperty(DomProperties, attrName)) {\n      const propertyRecord = DomProperties[attrName]\n      setProperty(\n        vNode.node,\n        propertyRecord.type,\n        propertyRecord.propName,\n        value\n      )\n      continue\n    }\n\n    // Set namespaced properties using setAttributeNS\n    if (attrName.startsWith(Namespace.xlink.prefix)) {\n      vNode.node.setAttributeNS(Namespace.xlink.resource, attrName, value)\n      continue\n    }\n\n    if (attrName.startsWith(Namespace.xml.prefix)) {\n      vNode.node.setAttributeNS(Namespace.xml.resource, attrName, value)\n      continue\n    }\n\n    if (attrName in vNode.node) {\n      setProperty(vNode.node, Types.STRING, attrName, value)\n    }\n    vNode.node.setAttribute(attrName, value || \"\")\n  }\n}\n\n/**\n * Checks property-based attributes. If the attribute exists,\n * then we should set its property value.\n * @param {HTMLElement} element\n * @param {Object.<string, string>} attributes\n */\nconst getPropertyValues = (element, attributes) => {\n  for (let attrName in DomProperties) {\n    const propertyRecord = DomProperties[attrName]\n    const propName = propertyRecord.propName\n    const attrValue = element.getAttribute(attrName)\n\n    if (attrName === DomProperties.style.attrName) {\n      attributes[attrName] = element.style[propName]\n    } else if (typeof attrValue === \"string\") {\n      attributes[attrName] = attrValue\n    }\n  }\n}\n\n/**\n * Gets non-property attributes.\n * @param {HTMLElement} element\n * @returns {Object.<string, string>}\n */\nconst getBaseAttributes = (element) => {\n  return Array.prototype.reduce.call(\n    element.attributes,\n    (attributes, attrName) => {\n      if (!hasProperty(DomProperties, attrName.name)) {\n        attributes[attrName.name] = attrName.value\n      }\n      return attributes\n    },\n    {}\n  )\n}\n\n/**\n * Gets all attributes.\n * @param {HTMLElement} element\n * @returns {Object.<string, string>}\n */\nexport const getAttributes = (element) => {\n  const attributes = getBaseAttributes(element)\n  getPropertyValues(element, attributes)\n\n  return attributes\n}\n\n/**\n * Reconcile attributes from vNode to template\n * @param {VirtualNode} template\n * @param {VirtualNode} vNode\n */\nexport const updateAttributes = (template, vNode) => {\n  let removedAttributes = []\n  let changedAttributes = {}\n\n  // Get stale attributes\n  for (let attrName in vNode.attributes) {\n    const oldValue = vNode.attributes[attrName]\n    const nextValue = template.attributes[attrName]\n    if (oldValue === nextValue) continue\n\n    if (typeof nextValue === \"undefined\") {\n      removedAttributes.push(attrName)\n    }\n  }\n\n  // Get changed or new attributes\n  for (let attrName in template.attributes) {\n    const oldValue = vNode.attributes[attrName]\n    const nextValue = template.attributes[attrName]\n    if (oldValue === nextValue) continue\n\n    if (typeof nextValue !== \"undefined\") {\n      changedAttributes[attrName] = nextValue\n    }\n  }\n\n  // Add and remove attributes\n  removeAttributes(vNode, removedAttributes)\n  setAttributes(vNode, changedAttributes)\n}\n", "import { forEach, createKeyMap, insertBefore } from \"../utilities\"\n\nconst DATA_KEY_ATTRIBUTE = \"data-key\"\n\n/**\n * Both template and vNode have arrays of virtual nodes. Diff them.\n * @param {VirtualNode} template - new virtual node tree.\n * @param {VirtualNode} vNode - existing virtual node tree.\n */\nexport function patchChildren(template, vNode, patch) {\n  const templateChildrenLength = template.children.length\n  const vNodeChildrenLength = vNode.children.length\n\n  if (!templateChildrenLength && !vNodeChildrenLength) return\n\n  const vNodeKeyMap = createKeyMap(vNode.children)\n  let nextChildren = Array(templateChildrenLength)\n\n  if (vNodeKeyMap !== undefined) {\n    forEach(template.children, (templateChild, idx) => {\n      const childNodes = vNode.node.childNodes\n      const key = templateChild.attributes[DATA_KEY_ATTRIBUTE]\n\n      if (Object.prototype.hasOwnProperty.call(vNodeKeyMap, key)) {\n        const keyedChild = vNodeKeyMap[key]\n\n        if (Array.prototype.indexOf.call(childNodes, keyedChild.node) !== idx) {\n          insertBefore(vNode, keyedChild, childNodes[idx])\n        }\n\n        nextChildren[idx] = keyedChild\n\n        // Remove entry to prevent dupes\n        delete vNodeKeyMap[key]\n        patch(templateChild, nextChildren[idx])\n      } else {\n        insertBefore(vNode, templateChild, childNodes[idx])\n        nextChildren[idx] = templateChild\n      }\n    })\n  } else {\n    forEach(template.children, (templateChild, idx) => {\n      const vNodeChild = vNode.children[idx]\n\n      if (typeof vNodeChild !== \"undefined\") {\n        patch(templateChild, vNodeChild)\n        nextChildren[idx] = vNodeChild\n      } else {\n        vNode.node.appendChild(templateChild.node)\n        nextChildren[idx] = templateChild\n      }\n    })\n  }\n\n  vNode.children = nextChildren\n\n  // Remove any real nodes that are left over from the diff\n  let childNodesLength = vNode.node.childNodes.length\n  let delta = childNodesLength - templateChildrenLength\n\n  if (delta > 0) {\n    while (delta > 0) {\n      vNode.node.removeChild(vNode.node.childNodes[childNodesLength - 1])\n      childNodesLength--\n      delta--\n    }\n  }\n}\n", "import { forEach, assignVNode } from \"./utilities\"\nimport { toHTML } from \"./parsers\"\nimport { updateAttributes, getAttributes } from \"./attributes\"\nimport { patchChildren } from \"./children\"\n\n/**\n * Object representation of a DOM element.\n * @typedef VirtualNode\n * @type {Object}\n * @property {string} type - The type of node. E.g., tag name, \"comment\", or \"text\".\n * @property {Object.<string, string>} attributes - List of attributes, if any.\n * @property {TextNode|CommentNode} content - Text or comment content, if any.\n * @property {VirtualNode[]} children - Child virtual nodes, if any.\n * @property {HTMLElement} node - The corresponding DOM element.\n * @property {boolean} isSVGContext\n */\n\n/**\n * Reconcile differences between two virtual DOM trees.\n * @param {VirtualNode} template - new virtual node tree.\n * @param {VirtualNode} vNode - existing virtual node tree.\n * @param {Node} rootNode - the HTML element containing the current node context\n */\nexport const patch = (template, vNode, rootNode) => {\n  // This came happen if a null result is given for either\n  // template or vNode. Impossible to compare - return.\n  if (!template || !vNode) return\n\n  rootNode = rootNode || vNode.node.parentNode\n  const contentChanged = template.content && template.content !== vNode.content\n\n  // If the type or content changed, replace the node completely\n  if (template.type !== vNode.type || contentChanged) {\n    rootNode.replaceChild(template.node, vNode.node)\n    return assignVNode(template, vNode)\n  }\n\n  // Update attributes, if any\n  updateAttributes(template, vNode)\n\n  // Diff child nodes recursively\n  patchChildren(template, vNode, patch)\n}\n\n/**\n * Renders a node into the given root context. This happens one time,\n * when a component is first rendered.\n * All subsequent renders are the result of reconciliation.\n * @param {VirtualNode} vDOM\n * @param {ShadowRoot|HTMLElement} root\n */\nexport const render = (vNode, root) => {\n  root.appendChild(vNode.node)\n}\n\n/**\n * Creates a new virtual DOM from a root node.\n * @param {HTMLElement|ShadowRoot|HTMLBodyElement} node\n * @param {boolean} isSVGContext\n * @returns {VirtualNode}\n */\nexport const create = (node, isSVGContext = false) => {\n  if (typeof node === \"string\") {\n    node = toHTML(node)\n  }\n\n  const isRoot = node.tagName === \"BODY\"\n  const childNodes = node.childNodes\n  const numChildNodes = childNodes ? childNodes.length : 0\n\n  // toHTML returns a `body` tag as its root node, but we want the first child only\n  if (isRoot) {\n    if (numChildNodes > 1) {\n      throw new Error(\n        \"[OmDomDom]: Your element should not have more than one root node.\"\n      )\n    } else if (numChildNodes === 0) {\n      throw new Error(\n        \"[OmDomDom]: Your element should have at least one root node.\"\n      )\n    } else {\n      return create(childNodes[0])\n    }\n  }\n\n  const type =\n    node.nodeType === 3\n      ? \"text\"\n      : node.nodeType === 8\n      ? \"comment\"\n      : node.tagName.toLowerCase()\n  const isSVG = isSVGContext || type === \"svg\"\n  const attributes = node.nodeType === 1 ? getAttributes(node) : {}\n  const content = numChildNodes > 0 ? null : node.textContent\n\n  // Recursively build children\n  const children = Array(numChildNodes)\n  forEach(childNodes, (child, idx) => {\n    children[idx] = create(child, isSVG)\n  })\n\n  return { type, attributes, children, content, node, isSVGContext: isSVG }\n}\n", "\n\nexport function takeWhileMap<T, A>(pred: (val: T) => A | undefined, lines: T[]): A[] {\n  var output = []\n  for (var line of lines) {\n    let a = pred(line)\n    if (a)\n      output.push(a)\n    else\n      break;\n  }\n\n  return output\n}\n\nexport function dropWhile<T, A>(pred: (val: T) => A | undefined, lines: T[]): T[] {\n  let index = 0;\n  while (index < lines.length && pred(lines[index])) {\n    index++;\n  }\n  return lines.slice(index);\n}\n\n", "\nimport { takeWhileMap, dropWhile } from \"./lib\"\n\n\n\nexport type Meta = { key: string, value: string }\nexport type ViewId = string\nexport type RequestId = number\nexport type EncodedAction = string\nexport type ViewState = string\n\nexport type RemoteEvent = { name: string, detail: unknown }\n\n\nexport function renderMetas(meta: Meta[]): string {\n  return meta.map(m => m.key + \": \" + m.value).join('\\n')\n}\n\nexport type Metadata = {\n  cookies?: string[]\n  // redirect?: string\n  error?: string\n  query?: string\n  events?: RemoteEvent[]\n  actions?: [ViewId, EncodedAction][],\n  pageTitle?: string\n}\n\n\nexport function toMetadata(meta: Meta[]): Metadata {\n\n  return {\n    cookies: meta.filter(m => m.key == \"Cookie\").map(m => m.value),\n    // redirect: metaValue(\"Redirect\", meta),\n    error: metaValue(\"Error\", meta),\n    query: metaValue(\"Query\", meta),\n    pageTitle: metaValue(\"PageTitle\", meta),\n    events: metaValuesAll(\"Event\", meta).map(parseRemoteEvent),\n    actions: metaValuesAll(\"Trigger\", meta).map(parseAction),\n  }\n}\n\n// viewId: meta.find(m => m.key == \"VIEW-ID\")?.value,\n\nexport function parseMetadata(input: string): Metadata {\n  let metas = takeWhileMap(parseMeta, input.trim().split(\"\\n\"))\n  return toMetadata(metas)\n}\n\n\nexport function metaValue(key: string, metas: Meta[]): string | undefined {\n  return metas.find(m => m.key == key)?.value\n}\n\nexport function metaValuesAll(key: string, metas: Meta[]): string[] {\n  return metas.filter(m => m.key == key).map(m => m.value)\n}\n\nexport type SplitMessage = {\n  command: string,\n  metas: Meta[],\n  rest: string[]\n}\n\n\nexport function splitMessage(message: string): SplitMessage {\n  let lines = message.split(\"\\n\")\n  let command: string = lines[0]\n  let metas: Meta[] = takeWhileMap(parseMeta, lines.slice(1))\n  // console.log(\"Split Metadata\", lines.length)\n  // console.log(\" [0]\", lines[0])\n  // console.log(\" [1]\", lines[1])\n  let rest = dropWhile(l => l == \"\", lines.slice(metas.length + 1))\n\n  return { command, metas, rest }\n}\n\nexport function parseMeta(line: string): Meta | undefined {\n  let match = line.match(/^(\\w+)\\: (.*)$/)\n  if (match) {\n    return {\n      key: match[1],\n      value: match[2]\n    }\n  }\n}\n\n\nexport function parseRemoteEvent(input: string): RemoteEvent {\n  let [name, data] = breakNextSegment(input)\n  return {\n    name,\n    detail: JSON.parse(data)\n  }\n}\n\nexport function parseAction(input: string): [ViewId, string] {\n  let [viewId, action] = breakNextSegment(input)\n  return [viewId, action]\n}\n\nfunction breakNextSegment(input: string): [string, string] {\n  let ix = input.indexOf('|')\n  if (ix === -1) {\n    let err = new Error(\"Bad Encoding, Expected Segment\")\n    err.message = input\n    throw err\n  }\n  return [input.slice(0, ix), input.slice(ix + 1)]\n}\n\n", "\nimport { Meta, ViewId, RequestId, EncodedAction, ViewState } from \"./message\"\nimport * as message from \"./message\"\n\n\n\nexport type ActionMessage = {\n  viewId: ViewId\n  action: EncodedAction\n  requestId: RequestId\n  state?: ViewState\n  meta: Meta[]\n  form: URLSearchParams | undefined\n}\n\n\n\n\nexport function actionMessage(id: ViewId, action: EncodedAction, state: ViewState | undefined, reqId: RequestId, form?: FormData): ActionMessage {\n  let meta: Meta[] = [\n    { key: \"Cookie\", value: decodeURI(document.cookie) },\n    { key: \"Query\", value: window.location.search }\n  ]\n\n  return { viewId: id, action, state, requestId: reqId, meta, form: toSearch(form) }\n}\n\nexport function toSearch(form?: FormData): URLSearchParams | undefined {\n  if (!form) return undefined\n\n  const params = new URLSearchParams()\n\n  form.forEach((value, key) => {\n    params.append(key, value as string)\n  })\n\n  return params\n}\n\nexport function renderActionMessage(msg: ActionMessage): string {\n  let header = [\n    \"|ACTION|\",\n    \"ViewId: \" + msg.viewId,\n    \"Action: \" + msg.action,\n  ]\n\n\n  if (msg.state) {\n    header.push(\"State: \" + msg.state)\n  }\n\n  header.push(\"RequestId: \" + msg.requestId)\n\n  return [\n    header.join('\\n'),\n    message.renderMetas(msg.meta),\n  ].join('\\n') + renderForm(msg.form)\n}\n\n\nexport function renderForm(form: URLSearchParams | undefined): string {\n  if (!form) return \"\"\n  return \"\\n\\n\" + form\n}\n\nlet globalRequestId: RequestId = 0\n\nexport type Request = {\n  requestId: RequestId\n  isCancelled: boolean\n}\n\nexport function newRequest(): Request {\n  let requestId = ++globalRequestId\n  return { requestId, isCancelled: false }\n}\n\n\n\n// Sanitized Encoding ------------------------------------\n\nexport function encodedParam(action: string, param: string): string {\n  return action + ' ' + sanitizeParam(param)\n}\n\nfunction sanitizeParam(param: string): string {\n  if (param == \"\") {\n    return \"|\"\n  }\n\n  return param.replace(/_/g, \"\\\\_\").replace(/\\s+/g, \"_\")\n}\n", "import { ActionMessage, renderActionMessage } from './action'\nimport { ResponseBody } from \"./response\"\nimport * as message from \"./message\"\nimport { ViewId, RequestId, EncodedAction, metaValue, Metadata, RemoteEvent } from \"./message\"\n\nconst protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';\nconst defaultAddress = `${protocol}//${window.location.host}${window.location.pathname}`\n\ninterface SocketConnectionEventMap {\n  \"update\": CustomEvent<Update>;\n  \"response\": CustomEvent<Update>;\n  \"redirect\": CustomEvent<Redirect>;\n  \"trigger\": CustomEvent<Trigger>;\n  \"event\": CustomEvent<JSEvent>;\n}\n\nexport class SocketConnection {\n  socket: WebSocket\n\n  hasEverConnected: boolean = false\n  isConnected: boolean = false\n  reconnectDelay: number = 0\n  queue: ActionMessage[] = []\n  events: EventTarget\n\n  constructor(addr = defaultAddress) {\n    this.events = new EventTarget()\n    const sock = new WebSocket(addr)\n    this.socket = sock\n  }\n\n  connect(addr = defaultAddress, createSocket = false) {\n    const sock = createSocket ? new WebSocket(addr) : this.socket\n    this.socket = sock\n\n    function onConnectError(ev: Event) {\n      console.error(\"Connect Error\", ev)\n    }\n\n    function onSocketError(ev: Event) {\n      console.error(\"Socket Error\", ev)\n    }\n\n\n    // initial connection errors\n    sock.addEventListener('error', onConnectError)\n\n    sock.addEventListener('open', (_event) => {\n      console.log(\"Websocket Connected\")\n\n      if (this.hasEverConnected) {\n        document.dispatchEvent(new Event(\"hyp-socket-reconnect\"))\n      }\n\n      this.isConnected = true\n      this.hasEverConnected = true\n      this.reconnectDelay = 1000\n      sock.removeEventListener('error', onConnectError)\n      sock.addEventListener('error', onSocketError)\n\n      document.dispatchEvent(new Event(\"hyp-socket-connect\"))\n\n      this.runQueue()\n    })\n\n    sock.addEventListener('close', _ => {\n      console.log(\"CLOSE SOCKET\")\n      if (this.isConnected) {\n        document.dispatchEvent(new Event(\"hyp-socket-disconnect\"))\n      }\n\n      this.isConnected = false\n      sock.removeEventListener('error', onSocketError)\n\n      // attempt to reconnect in 1s\n      if (this.hasEverConnected) {\n        console.log(\"Reconnecting in \" + (this.reconnectDelay / 1000) + \"s\")\n        setTimeout(() => this.connect(addr, true), this.reconnectDelay)\n      }\n\n      sock.removeEventListener('error', onSocketError)\n    })\n\n    sock.addEventListener('message', ev => this.onMessage(ev))\n  }\n\n  async sendAction(action: ActionMessage) {\n    if (this.isConnected) {\n      let msg = renderActionMessage(action)\n      this.socket.send(msg)\n    }\n    else {\n      this.queue.push(action)\n    }\n  }\n\n  private runQueue() {\n    // send all messages queued while disconnected \n    let next: ActionMessage | undefined = this.queue.pop()\n    if (next) {\n      console.log(\"runQueue: \", next)\n      this.sendAction(next)\n      this.runQueue()\n    }\n  }\n\n\n  // full responses will never be sent over!\n  private onMessage(event: MessageEvent) {\n    let { command, metas, rest } = message.splitMessage(event.data)\n    // console.log(\"MESSAGE\", command, metas, rest)\n\n    let requestId = parseInt(requireMeta(\"RequestId\"), 0)\n\n    function requireMeta(key: string): string {\n      let val = metaValue(key, metas)\n      if (!val) throw new ProtocolError(\"Missing Required Metadata: \" + key, event.data)\n      return val\n    }\n\n    function parseResponse(rest: string[]): Update {\n      let viewId = requireMeta(\"ViewId\")\n      let action = requireMeta(\"Action\")\n      return {\n        requestId,\n        targetViewId: undefined,\n        viewId,\n        action,\n        meta: message.toMetadata(metas),\n        body: rest.join(\"\\n\"),\n      }\n    }\n\n    function parseUpdate(rest: string[]): Update {\n      let up = parseResponse(rest)\n      // add the TargetViewId\n      up.targetViewId = metaValue(\"TargetViewId\", metas)\n      return up\n    }\n\n    function parseRedirect(rest: string[]): Redirect {\n      let url = rest[0]\n      return {\n        requestId,\n        meta: message.toMetadata(metas),\n        url\n      }\n    }\n\n    function parseTrigger(rest: string[]): Trigger {\n      let { requestId, meta, viewId, action } = parseResponse(rest)\n      let [targetViewId, targetAction] = message.parseAction(requireMeta(\"Trigger\"))\n      return { requestId, meta, viewId, action, targetViewId, targetAction }\n    }\n\n    function parseEvent(rest: string[]): JSEvent {\n      let { requestId, meta, viewId, action } = parseResponse(rest)\n      let event = message.parseRemoteEvent(requireMeta(\"Event\"))\n      return { requestId, meta, viewId, action, event }\n    }\n\n\n    switch (command) {\n\n      case \"|UPDATE|\":\n        return this.dispatchEvent(new CustomEvent(\"update\", { detail: parseUpdate(rest) }))\n\n      case \"|RESPONSE|\":\n        return this.dispatchEvent(new CustomEvent(\"response\", { detail: parseResponse(rest) }))\n\n      case \"|REDIRECT|\":\n        return this.dispatchEvent(new CustomEvent(\"redirect\", { detail: parseRedirect(rest) }))\n\n      case \"|TRIGGER|\":\n        return this.dispatchEvent(new CustomEvent(\"trigger\", { detail: parseTrigger(rest) }))\n\n      case \"|EVENT|\":\n        return this.dispatchEvent(new CustomEvent(\"event\", { detail: parseEvent(rest) }))\n\n      default:\n        throw new ProtocolError(\"Unknown Server Command: \" + command, event.data)\n    }\n  }\n\n\n  // so what if they send remote events in the page? trigger, redirect, page title, etc...\n  // we aren't connected yet on a page thing\n\n  // private async waitMessage(reqId: RequestId, id: ViewId): Promise<ParsedResponse> {\n  //   return new Promise((resolve, reject) => {\n  //     const onMessage = (event: MessageEvent) => {\n  //       let data: string = event.data\n  //       let lines = data.split(\"\\n\").slice(1)  // drop the command line\n  //\n  //       let parsed = splitMetadata(lines)\n  //       let metadata: Metadata = parsed.metadata\n  //\n  //       if (!metadata.requestId) {\n  //         console.error(\"Missing RequestId!\", metadata, event.data)\n  //         return\n  //       }\n  //\n  //       if (metadata.requestId != reqId) {\n  //         // skip, it's not us!\n  //         return\n  //       }\n  //\n  //\n  //       // We have found our message. Remove the listener\n  //       this.socket.removeEventListener('message', onMessage)\n  //\n  //       // set the cookies. These happen automatically in http\n  //       metadata.cookies.forEach((cookie: string) => {\n  //         document.cookie = cookie\n  //       })\n  //\n  //       if (metadata.error) {\n  //         reject(new FetchError(id, metadata.error, parsed.rest.join('\\n')))\n  //         return\n  //       }\n  //\n  //       resolve(parsed)\n  //     }\n  //\n  //     this.socket.addEventListener('message', onMessage)\n  //     this.socket.addEventListener('error', reject)\n  //   })\n  // }\n\n  addEventListener<K extends keyof SocketConnectionEventMap>(e: K, cb: (ev: SocketConnectionEventMap[K]) => void) {\n    this.events.addEventListener(e,\n      // @ts-ignore: HACK\n      cb\n    )\n  }\n\n  dispatchEvent<K extends keyof SocketConnectionEventMap>(e: SocketConnectionEventMap[K]) {\n    this.events.dispatchEvent(e)\n  }\n\n  disconnect() {\n    this.isConnected = false\n    this.hasEverConnected = false\n    this.socket.close()\n  }\n}\n\n\nexport type Update = {\n  requestId: RequestId\n  meta: Metadata\n  viewId: ViewId\n  targetViewId?: ViewId\n  action: EncodedAction\n  body: ResponseBody\n}\n\nexport type Redirect = {\n  requestId: RequestId\n  meta: Metadata\n  url: string\n}\n\nexport type Trigger = {\n  requestId: RequestId\n  meta: Metadata\n  viewId: ViewId\n  action: EncodedAction\n  targetViewId: ViewId\n  targetAction: string\n}\n\nexport type JSEvent = {\n  requestId: RequestId\n  meta: Metadata\n  viewId: ViewId\n  action: EncodedAction\n  event: RemoteEvent\n}\n\nexport type MessageType = string\n\n\n// PARSING MESSAGE  ---------------------------------------\n\nexport class ProtocolError extends Error {\n  constructor(description: string, body: string) {\n    super(description + \"\\n\" + body)\n    this.name = \"ProtocolError\"\n  }\n}\n", "export default function debounce(function_, wait = 100, options = {}) {\n\tif (typeof function_ !== 'function') {\n\t\tthrow new TypeError(`Expected the first parameter to be a function, got \\`${typeof function_}\\`.`);\n\t}\n\n\tif (wait < 0) {\n\t\tthrow new RangeError('`wait` must not be negative.');\n\t}\n\n\tif (typeof options === 'boolean') {\n\t\tthrow new TypeError('The `options` parameter must be an object, not a boolean. Use `{immediate: true}` instead.');\n\t}\n\n\tconst {immediate} = options;\n\n\tlet storedContext;\n\tlet storedArguments;\n\tlet timeoutId;\n\tlet timestamp;\n\tlet result;\n\n\tfunction run() {\n\t\tconst callContext = storedContext;\n\t\tconst callArguments = storedArguments;\n\t\tstoredContext = undefined;\n\t\tstoredArguments = undefined;\n\t\tresult = function_.apply(callContext, callArguments);\n\t\treturn result;\n\t}\n\n\tfunction later() {\n\t\tconst last = Date.now() - timestamp;\n\n\t\tif (last < wait && last >= 0) {\n\t\t\ttimeoutId = setTimeout(later, wait - last);\n\t\t} else {\n\t\t\ttimeoutId = undefined;\n\n\t\t\tif (!immediate) {\n\t\t\t\tresult = run();\n\t\t\t}\n\t\t}\n\t}\n\n\tconst debounced = function (...arguments_) {\n\t\tif (\n\t\t\tstoredContext\n\t\t\t&& this !== storedContext\n\t\t\t&& Object.getPrototypeOf(this) === Object.getPrototypeOf(storedContext)\n\t\t) {\n\t\t\tthrow new Error('Debounced method called with different contexts of the same prototype.');\n\t\t}\n\n\t\tstoredContext = this; // eslint-disable-line unicorn/no-this-assignment\n\t\tstoredArguments = arguments_;\n\t\ttimestamp = Date.now();\n\n\t\tconst callNow = immediate && !timeoutId;\n\n\t\tif (!timeoutId) {\n\t\t\ttimeoutId = setTimeout(later, wait);\n\t\t}\n\n\t\tif (callNow) {\n\t\t\tresult = run();\n\t\t\treturn result;\n\t\t}\n\n\t\treturn undefined;\n\t};\n\n\tObject.defineProperty(debounced, 'isPending', {\n\t\tget() {\n\t\t\treturn timeoutId !== undefined;\n\t\t},\n\t});\n\n\tdebounced.clear = () => {\n\t\tif (!timeoutId) {\n\t\t\treturn;\n\t\t}\n\n\t\tclearTimeout(timeoutId);\n\t\ttimeoutId = undefined;\n\t\tstoredContext = undefined;\n\t\tstoredArguments = undefined;\n\t};\n\n\tdebounced.flush = () => {\n\t\tif (!timeoutId) {\n\t\t\treturn;\n\t\t}\n\n\t\tdebounced.trigger();\n\t};\n\n\tdebounced.trigger = () => {\n\t\tresult = run();\n\n\t\tdebounced.clear();\n\t};\n\n\treturn debounced;\n}\n", "import { type Request } from \"./action\";\n\nexport interface HyperView extends HTMLElement {\n  runAction(action: string): Promise<void>;\n  activeRequest?: Request;\n  cancelActiveRequest(): void;\n  concurrency: ConcurrencyMode;\n  _timeout?: number;\n}\n\nexport const isHyperView = (ele: any): ele is HyperView => {\n  return ele?.runAction !== undefined;\n};\n\nexport type ConcurrencyMode = string;\n\nexport function dispatchContent(node: HTMLElement): void {\n  let event = new Event(\"hyp-content\", { bubbles: true })\n  node.dispatchEvent(event)\n}\n\nexport function enrichHyperViews(node: HTMLElement, runAction: (target: HyperView, action: string, form?: FormData) => Promise<void>): void {\n  // enrich all the hyperviews\n  node.querySelectorAll<HyperView>(\"[id]\").forEach((element) => {\n    element.runAction = function(action: string) {\n      return runAction(element, action)\n    }\n\n    element.concurrency = element.dataset.concurrency || \"Drop\"\n\n    element.cancelActiveRequest = function() {\n      if (element.activeRequest && !element.activeRequest?.isCancelled) {\n        element.activeRequest.isCancelled = true\n      }\n    }\n\n    dispatchContent(node)\n  })\n}\n", "\nimport debounce from 'debounce'\nimport { encodedParam } from './action'\nimport { HyperView, isHyperView } from './hyperview'\n\nexport type UrlFragment = string\n\nexport function listenKeydown(cb: (target: HyperView, action: string) => void): void {\n  listenKeyEvent(\"keydown\", cb)\n}\n\nexport function listenKeyup(cb: (target: HyperView, action: string) => void): void {\n  listenKeyEvent(\"keyup\", cb)\n}\n\nexport function listenKeyEvent(event: \"keyup\" | \"keydown\", cb: (target: HyperView, action: string) => void): void {\n\n  document.addEventListener(event, function(e: KeyboardEvent) {\n    if (!(e.target instanceof HTMLElement)) {\n      console.warn(\"listenKeyEvent received event with non HTMLElment as EventTarget: %o\", e)\n      return\n    }\n    let source = e.target\n\n    let datasetKey = \"on\" + event + e.key\n    let action = source.dataset[datasetKey]\n    if (!action) return\n\n    e.preventDefault()\n    const target =  nearestHyperViewTarget(source)\n    if (!target) {\n      console.error(\"Missing target: \", source)\n      return\n    }\n    cb(target, action)\n  })\n}\n\nexport function listenBubblingEvent(event: string, cb: (_target: HyperView, action: string) => void): void {\n  document.addEventListener(event, function(e) {\n    if (!(e.target instanceof HTMLElement)) {\n      console.warn(\"listenBubblingEvent received an event with non HTMLElment as EventTarget: %o\", e)\n      return\n    }\n    let el = e.target\n\n    // clicks can fire on internal elements. Find the parent with a click handler\n    let source = el.closest<HTMLElement>(\"[data-on\" + event + \"]\")\n    if (!source) return\n\n    e.preventDefault()\n    let target = nearestHyperViewTarget(source)\n    if (!target) {\n      console.error(\"Missing target: \", source)\n      return\n    }\n    const action = source.dataset[\"on\" + event]\n    if (action === undefined) {\n      console.error(\"Missing action: \", source, event)\n      return\n    }\n    cb(target, action)\n  })\n}\n\nexport function listenClick(cb: (target: HyperView, action: string) => void): void {\n  listenBubblingEvent(\"click\", cb)\n}\n\nexport function listenDblClick(cb: (target: HyperView, action: string) => void): void {\n  listenBubblingEvent(\"dblclick\", cb)\n}\n\n\nexport function listenTopLevel(cb: (target: HyperView, action: string) => void): void {\n  document.addEventListener(\"hyp-load\", function(e: CustomEvent) {\n    let action = e.detail.onLoad\n    let target = e.detail.target\n    cb(target, action)\n  })\n\n  document.addEventListener(\"hyp-mouseenter\", function(e: CustomEvent) {\n    let action = e.detail.onMouseEnter\n    let target = e.detail.target\n    cb(target, action)\n  })\n\n  document.addEventListener(\"hyp-mouseleave\", function(e: CustomEvent) {\n    let action = e.detail.onMouseLeave\n    let target = e.detail.target\n    cb(target, action)\n  })\n}\n\n\nexport function listenLoad(node: HTMLElement): void {\n\n  // it doesn't really matter WHO runs this except that it should have target\n  node.querySelectorAll<HTMLElement>(\"[data-onload]\").forEach((load) => {\n    let delay = parseInt(load.dataset.delay || \"\") || 0\n    let onLoad = load.dataset.onload\n    // console.log(\"load start\", load.dataset.onLoad)\n\n    // load no longer exists!\n    // we should clear the timeout or back out if the dom is replaced in the interem\n    setTimeout(() => {\n      let target = nearestHyperViewTarget(load)\n      // console.log(\"load go\", load.dataset.onLoad)\n\n      if (load.dataset.onload != onLoad) {\n        // the onLoad no longer exists\n        return\n      }\n\n      const event = new CustomEvent(\"hyp-load\", { bubbles: true, detail: { target, onLoad } })\n      load.dispatchEvent(event)\n    }, delay)\n  })\n}\n\nexport function listenMouseEnter(node: HTMLElement): void {\n  node.querySelectorAll<HTMLElement>(\"[data-onmouseenter]\").forEach((node) => {\n    let onMouseEnter = node.dataset.onmouseenter\n\n    let target = nearestAnyTarget(node)\n\n    node.onmouseenter = () => {\n      const event = new CustomEvent(\"hyp-mouseenter\", { bubbles: true, detail: { target, onMouseEnter } })\n      node.dispatchEvent(event)\n    }\n  })\n}\n\nexport function listenMouseLeave(node: HTMLElement): void {\n  node.querySelectorAll<HTMLElement>(\"[data-onmouseleave]\").forEach((node) => {\n    let onMouseLeave = node.dataset.onmouseleave\n\n    let target = nearestAnyTarget(node)\n\n    node.onmouseleave = () => {\n      const event = new CustomEvent(\"hyp-mouseleave\", { bubbles: true, detail: { target, onMouseLeave } })\n      node.dispatchEvent(event)\n    }\n  })\n}\n\n\nexport function listenChange(cb: (target: HyperView, action: string) => void): void {\n  document.addEventListener(\"change\", function(e) {\n    if (!(e.target instanceof HTMLElement)) {\n      console.warn(\"listenChange received an event with non HTMLElment as EventTarget: %o\", e)\n      return\n    }\n    let el = e.target\n\n    let source = el.closest<HTMLInputElement>(\"[data-onchange]\")\n\n    if (!source) return\n    e.preventDefault()\n\n    if (source.value === null) {\n      console.error(\"Missing input value:\", source)\n      return\n    }\n\n    let target = nearestHyperViewTarget(source)\n    if (!target) {\n      console.error(\"Missing target: listenChange\")\n      return\n    }\n    if (!source.dataset.onchange) {\n      console.error(\"Missing onchange: \", source)\n      return\n    }\n    let action = encodedParam(source.dataset.onchange, source.value)\n    cb(target, action)\n  })\n}\n\ninterface LiveInputElement extends HTMLInputElement {\n  debouncedCallback?: Function;\n}\n\nexport function listenInput(startedTyping: (target: HyperView) => void, cb: (target: HyperView, action: string) => void): void {\n  document.addEventListener(\"input\", function(e) {\n    if (!(e.target instanceof HTMLElement)) {\n      console.warn(\"listenInput received an event with non HTMLElment as EventTarget: %o\", e)\n      return\n    }\n    let el = e.target\n    const source = el.closest<LiveInputElement>(\"[data-oninput]\")\n\n    if (!source) return\n\n    let delay = parseInt(source.dataset.delay || \"\") || 250\n    if (delay < 250) {\n      console.warn(\"Input delay < 250 can result in poor performance.\")\n    }\n\n    e.preventDefault()\n\n    const target = nearestHyperViewTarget(source)\n    if (!target) {\n      console.error(\"Missing target: \", source)\n      return\n    }\n\n    // I want to CANCEL the active request as soon as we start typing\n    startedTyping(target)\n\n    if (!source.debouncedCallback) {\n      source.debouncedCallback = debounce(() => {\n        if (!source.dataset.oninput) {\n          console.error(\"Missing onInput: \", source)\n          return\n        }\n        const action = encodedParam(source.dataset.oninput, source.value)\n        cb(target, action)\n      }, delay)\n    }\n\n    source.debouncedCallback()\n  })\n}\n\n\n\nexport function listenFormSubmit(cb: (target: HyperView, action: string, form: FormData) => void): void {\n  document.addEventListener(\"submit\", function(e) {\n    if (!(e.target instanceof HTMLFormElement)) {\n      console.warn(\"listenFormSubmit received an event with non HTMLElment as EventTarget: %o\", e)\n      return\n    }\n    let form = e.target\n\n\n    if (!form.dataset.onsubmit) {\n      console.error(\"Missing onSubmit: \", form)\n      return\n    }\n\n    e.preventDefault()\n\n    let target = nearestHyperViewTarget(form)\n    const formData = new FormData(form)\n    if (!target) {\n      console.error(\"Missing target: \", form)\n      return\n    }\n    cb(target, form.dataset.onsubmit, formData)\n  })\n}\n\nfunction nearestTargetId(node: HTMLElement): string | undefined {\n  let targetData = node.closest<HTMLElement>(\"[data-target]\")\n  return targetData?.dataset.target || node.closest(\"[id]\")?.id\n}\n\nfunction nearestHyperViewTarget(node: HTMLElement): HyperView | undefined {\n  const target = nearestAnyTarget(node)\n\n  if (!isHyperView(target)) {\n    console.error(\"Non HyperView target: \", target)\n    return\n  }\n\n  return target\n}\n\nfunction nearestAnyTarget(node: HTMLElement): HTMLElement | undefined {\n  let targetId = nearestTargetId(node)\n  let target = targetId && document.getElementById(targetId)\n\n  if (!target) {\n    console.error(\"Cannot find target: \", targetId, node)\n    return\n  }\n\n  return target\n}\n", "\nexport function setQuery(query: string) {\n  if (query != currentQuery()) {\n    if (query != \"\") query = \"?\" + query\n    let url = location.pathname + query\n    // console.log(\"history.replaceState(\", url, \")\")\n    window.history.replaceState({}, \"\", url)\n  }\n}\n\nfunction currentQuery(): string {\n  const query = window.location.search;\n  return query.startsWith('?') ? query.substring(1) : query;\n}\n", "\nimport { ViewId, Metadata } from './message'\n\n\n\nexport type Response = {\n  meta: Metadata\n  body: ResponseBody\n}\n\nexport type ResponseBody = string\n\nexport function parseResponse(res: ResponseBody): LiveUpdate {\n  const parser = new DOMParser()\n  const doc = parser.parseFromString(res, 'text/html')\n  const css = doc.querySelector<HTMLStyleElement>(\"style\")\n  const content = doc.querySelector<HTMLElement>(\"div\")\n\n  return {\n    content: content,\n    css: css\n  }\n}\n\nexport type LiveUpdate = {\n  content: HTMLElement | null\n  css: HTMLStyleElement | null\n}\n\n\nexport class FetchError extends Error {\n  viewId: ViewId\n  body: string\n  constructor(viewId: ViewId, msg: string, body: string) {\n    super(msg)\n    this.viewId = viewId\n    this.name = \"Fetch Error\"\n    this.body = body\n  }\n}\n", "{\n  \"name\": \"web-ui\",\n  \"version\": \"0.6.0\",\n  \"description\": \"Development -----------\",\n  \"main\": \"index.js\",\n  \"directories\": {\n    \"client\": \"client\"\n  },\n  \"scripts\": {\n    \"build\": \"esbuild src/index.ts --bundle --minify --sourcemap --outfile=dist/hyperbole.js\",\n    \"dev\": \"esbuild src/index.ts --bundle --minify --sourcemap --watch=forever --outfile=dist/hyperbole.js\",\n    \"check\": \"tsc --noEmit --preserveWatchOutput --watch\"\n  },\n  \"author\": \"\",\n  \"license\": \"ISC\",\n  \"devDependencies\": {\n    \"esbuild\": \"^0.28.0\",\n    \"typescript\": \"^6.0.3\"\n  },\n  \"dependencies\": {\n    \"omdomdom\": \"^0.3.2\",\n    \"debounce\": \"^3.0.0\"\n  }\n}\n", "import { patch, create } from \"omdomdom/lib/omdomdom.es.js\"\nimport { SocketConnection, Update, Redirect, Trigger, JSEvent } from './sockets'\nimport { listenChange, listenClick, listenDblClick, listenFormSubmit, listenLoad, listenTopLevel, listenInput, listenKeydown, listenKeyup, listenMouseEnter, listenMouseLeave } from './events'\nimport { actionMessage, newRequest } from './action'\nimport { ViewId, Metadata, parseMetadata, RemoteEvent, EncodedAction } from './message'\nimport { setQuery } from \"./browser\"\nimport { parseResponse, LiveUpdate } from './response'\nimport { dispatchContent, enrichHyperViews, HyperView, isHyperView } from \"./hyperview\"\n\nimport PACKAGE from '../package.json';\n\n\n// console.log(\"VERSION 2\", INIT_PAGE, INIT_STATE)\nconsole.log(\"Hyperbole \" + PACKAGE.version + \"b\")\n\n\nlet rootStyles: HTMLStyleElement;\nlet addedRulesIndex = new Set();\n\n\n\n\n\n// Run an action in a given HyperView\nasync function runAction(target: HyperView, action: string, form?: FormData) {\n\n  if (target.activeRequest && !target.activeRequest?.isCancelled) {\n    // Active Request!\n    if (target.concurrency == \"Drop\") {\n      console.warn(\"Drop action overlapping with active request (\" + target.activeRequest + \")\", action)\n      return\n    }\n  }\n\n  target._timeout = window.setTimeout(() => {\n    // add loading after 100ms, not right away\n    // if it runs shorter than that we probably don't want to show the user any loading feedback\n    target.classList.add(\"hyp-loading\")\n  }, 100)\n\n  let state = target.dataset.state\n\n  let req = newRequest()\n  let msg = actionMessage(target.id, action, state, req.requestId, form)\n\n  // Set the requestId\n  target.activeRequest = req\n\n  sock.sendAction(msg)\n}\n\nfunction handleTrigger(trigger: Trigger) {\n  runTrigger(trigger.targetViewId, trigger.targetAction)\n}\n\nfunction handleEvent(ev: JSEvent) {\n  let target = document.getElementById(ev.viewId)\n  runRemoteEvent(ev.event, target)\n}\n\n// TODO: redirect concurrency\nfunction handleRedirect(red: Redirect) {\n  console.log(\"REDIRECT\", red)\n\n  // the other metdata doesn't apply, they are all specific to the page\n  applyCookies(red.meta.cookies ?? [])\n\n  window.location.href = red.url\n}\n\n// in-process update\nfunction handleResponse(res: Update) {\n  // console.log(\"Handle Response\", res)\n  let target = handleUpdate(res)\n  if (!target) return\n\n  // clean up the request\n  delete target.activeRequest\n  clearTimeout(target._timeout)\n  target.classList.remove(\"hyp-loading\")\n}\n\nfunction handleUpdate(res: Update): HyperView | undefined {\n  // console.log(\"|UPDATE|\", res)\n\n  let targetViewId = res.targetViewId || res.viewId\n  let target = document.getElementById(targetViewId)\n\n  if (!isHyperView(target)) {\n    console.error(\"Missing Update HyperView Target: \", targetViewId, res)\n    return\n  }\n\n  if (target.activeRequest?.requestId && res.requestId < target.activeRequest.requestId) {\n    // this should only happen on Replace, since other requests should be dropped\n    // but it's safe to assume we never want to apply an old requestId\n    console.warn(\"Ignore Stale Action (\" + res.requestId + \") vs (\" + target.activeRequest.requestId + \"): \" + res.action)\n    return target\n  }\n  else if (target.activeRequest?.isCancelled) {\n    console.warn(\"Cancelled request\", target.activeRequest?.requestId)\n    delete target.activeRequest\n    return target\n  }\n\n  let update: LiveUpdate = parseResponse(res.body)\n\n  if (!update.content) {\n    console.error(\"Empty Response!\", res.body)\n    return target\n  }\n\n  // First, update the stylesheet\n  addCSS(update.css)\n\n\n  // Patch the node\n  const old: VNode = create(target)\n  let next: VNode = create(update.content)\n  let atts = next.attributes\n\n  if (!res.meta.error && atts[\"id\"] != target.id) {\n    console.error(\"Mismatched ViewId in update - \", atts[\"id\"], \" target:\", target.id)\n    return\n  }\n\n  let state = atts[\"data-state\"]\n  next.attributes = old.attributes\n\n\n  patch(next, old)\n\n\n  // Emit relevant events\n  let newTarget = document.getElementById(target.id)\n\n  if (!newTarget) {\n    console.warn(\"Target Missing: \", target.id)\n    return target\n  }\n\n  dispatchContent(newTarget)\n\n  // re-add state attribute \n  if (state === undefined || state == \"()\")\n    delete newTarget.dataset.state\n  else\n    newTarget.dataset.state = state\n\n  // execute the metadata, anything that doesn't interrupt the dom update\n  runMetadata(res.meta, newTarget)\n  applyCookies(res.meta.cookies ?? [])\n\n  // now way for these to bubble)\n  listenLoad(newTarget)\n  listenMouseEnter(newTarget)\n  listenMouseLeave(newTarget)\n  fixInputs(newTarget)\n  enrichHyperViews(newTarget, runAction)\n\n  return target\n}\n// catch (err) {\n//   console.error(\"Caught Error in HyperView (\" + target.id + \"):\\n\", err)\n//\n//   // Hyperbole catches handler errors, and the server controls what to display to the user on an error\n//   //  but if you manage to crash your parent server process somehow, the response may be empty\n//   target.innerHTML = err.body || \"<div style='background:red;color:white;padding:10px'>Hyperbole Internal Error</div>\"\n// }\n\nfunction applyCookies(cookies: string[]) {\n  cookies.forEach((cookie: string) => {\n    console.log(\"SetCookie: \", cookie)\n    document.cookie = cookie\n  })\n}\n\nfunction runMetadata(meta: Metadata, target: HTMLElement | null) {\n  if (meta.query != null) {\n    setQuery(meta.query)\n  }\n\n  if (meta.pageTitle != null) {\n    document.title = meta.pageTitle\n  }\n\n  meta.events?.forEach((remoteEvent) => {\n    runRemoteEvent(remoteEvent, target)\n  })\n\n  meta.actions?.forEach(([viewId, action]) => {\n    runTrigger(viewId, action)\n  })\n}\n\nfunction runRemoteEvent(remoteEvent: RemoteEvent, target: HTMLElement | null) {\n  setTimeout(() => {\n    let event = new CustomEvent(remoteEvent.name, { bubbles: true, detail: remoteEvent.detail })\n    let eventTarget = target || document\n    eventTarget.dispatchEvent(event)\n  }, 10)\n}\n\nfunction runTrigger(viewId: ViewId, action: EncodedAction) {\n  setTimeout(() => {\n    let view = window.Hyperbole?.hyperView(viewId)\n    if (view) {\n      runAction(view, action)\n    }\n  }, 10)\n}\n\n\nfunction fixInputs(target: HTMLElement) {\n  let focused = target.querySelector<HTMLInputElement>(\"[autofocus]\")\n  if (focused?.focus) {\n    focused.focus()\n  }\n\n  target.querySelectorAll<HTMLInputElement>(\"input[value]\").forEach((input) => {\n    let val = input.getAttribute(\"value\")\n    if (val !== null) {\n      input.value = val\n    }\n  })\n\n  target.querySelectorAll<HTMLInputElement>(\"input[type=checkbox]\").forEach((checkbox) => {\n    let checked = checkbox.dataset.checked == \"True\"\n    checkbox.checked = checked\n  })\n}\n\nfunction addCSS(src: HTMLStyleElement | null) {\n  if (!src) return;\n  const rules = src.sheet?.cssRules\n  if (!rules) return;\n  for (let i = 0; i < rules.length; i++) {\n    const rule = rules.item(i)\n    if (rule && addedRulesIndex.has(rule.cssText) == false && rootStyles.sheet) {\n      rootStyles.sheet.insertRule(rule.cssText);\n      addedRulesIndex.add(rule.cssText);\n    }\n  }\n}\n\n\n\n\nfunction init() {\n  // metadata attached to initial page loads need to be executed\n  let meta = parseMetadata(document.getElementById(\"hyp.metadata\")?.innerText ?? \"\")\n  // runMetadataImmediate(meta)\n  runMetadata(meta, null)\n\n  const style = document.body.querySelector('style')\n\n  if (style !== null) {\n    rootStyles = style\n  } else {\n    console.warn(\"rootStyles missing from page, creating...\")\n    rootStyles = document.createElement(\"style\")\n    rootStyles.type = \"text/css\"\n    document.body.appendChild(rootStyles)\n  }\n\n  listenTopLevel(async function(target: HyperView, action: string) {\n    runAction(target, action)\n  })\n\n  listenLoad(document.body)\n  listenMouseEnter(document.body)\n  listenMouseLeave(document.body)\n  enrichHyperViews(document.body, runAction)\n\n\n  listenClick(async function(target: HyperView, action: string) {\n    // console.log(\"CLICK\", target.id, action)\n    runAction(target, action)\n  })\n\n  listenDblClick(async function(target: HyperView, action: string) {\n    // console.log(\"DBLCLICK\", target.id, action)\n    runAction(target, action)\n  })\n\n  listenKeydown(async function(target: HyperView, action: string) {\n    // console.log(\"KEYDOWN\", target.id, action)\n    runAction(target, action)\n  })\n\n  listenKeyup(async function(target: HyperView, action: string) {\n    // console.log(\"KEYUP\", target.id, action)\n    runAction(target, action)\n  })\n\n  listenFormSubmit(async function(target: HyperView, action: string, form: FormData) {\n    // console.log(\"FORM\", target.id, action, form)\n    runAction(target, action, form)\n  })\n\n  listenChange(async function(target: HyperView, action: string) {\n    runAction(target, action)\n  })\n\n  function onStartedTyping(target: HyperView) {\n    if (target.concurrency == \"Replace\") {\n      target.cancelActiveRequest()\n    }\n  }\n\n  listenInput(onStartedTyping, async function(target: HyperView, action: string) {\n    runAction(target, action)\n  })\n}\n\n\n\n\n\n\ndocument.addEventListener(\"DOMContentLoaded\", init)\n\n\n\n\nconst sock = new SocketConnection()\n// Should we connect to the socket or not?\nsock.connect()\nsock.addEventListener(\"update\", (ev: CustomEvent<Update>) => { handleUpdate(ev.detail) })\nsock.addEventListener(\"response\", (ev: CustomEvent<Update>) => handleResponse(ev.detail))\nsock.addEventListener(\"redirect\", (ev: CustomEvent<Redirect>) => handleRedirect(ev.detail))\nsock.addEventListener(\"trigger\", (ev: CustomEvent<Trigger>) => handleTrigger(ev.detail))\nsock.addEventListener(\"event\", (ev: CustomEvent<JSEvent>) => handleEvent(ev.detail))\n\n\n\n\n\ntype VNode = {\n  // One of three value types are used:\n  // - The tag name of the element\n  // - \"text\" if text node\n  // - \"comment\" if comment node\n  type: string\n\n  // An object whose key/value pairs are the attribute\n  // name and value, respectively\n  attributes: { [key: string]: string | undefined }\n\n  // Is set to `true` if a node is an `svg`, which tells\n  // Omdomdom to treat it, and its children, as such\n  isSVGContext: boolean\n\n  // The content of a \"text\" or \"comment\" node\n  content: string\n\n  // An array of virtual node children\n  children: Array<VNode>\n\n  // The real DOM node\n  node: Node\n}\n\n\n\n\n\ndeclare global {\n  interface Window {\n    Hyperbole?: HyperboleAPI;\n  }\n  interface DocumentEventMap {\n    \"hyp-load\": CustomEvent;\n    \"hyp-mouseenter\": CustomEvent;\n    \"hyp-mouseleave\": CustomEvent;\n  }\n}\n\nexport interface HyperboleAPI {\n  runAction(target: HTMLElement, action: string, form?: FormData): Promise<void>\n  action(con: string, ...params: any[]): string\n  hyperView(viewId: ViewId): HyperView | undefined\n  parseMetadata(input: string): Metadata\n  socket: SocketConnection\n}\n\nwindow.Hyperbole =\n{\n  runAction: runAction,\n  parseMetadata: parseMetadata,\n  action: function(con, ...params: any[]) {\n    return params.reduce((str, param) => str + \" \" + JSON.stringify(param), con);\n  },\n  hyperView: function(viewId) {\n    let element = document.getElementById(viewId)\n    if (!isHyperView(element)) {\n      console.error(\"Element id=\" + viewId + \" was not a HyperView\")\n      return\n    }\n    return element\n  },\n  socket: sock\n}\n"],-  "mappings": "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",-  "names": ["DATA_KEY_ATTRIBUTE", "hasProperty", "obj", "prop", "Object", "prototype", "hasOwnProperty", "call", "keyIsValid", "map", "key", "console", "warn", "forEach", "items", "fn", "length", "idx", "createKeyMap", "children", "child", "attributes", "_", "insertBefore", "parent", "refNode", "node", "assignVNode", "template", "vNode", "property", "toHTML", "htmlString", "processedDOMString", "trim", "replace", "parser", "DOMParser", "context", "parseFromString", "body", "Types", "STRING", "INT", "BOOL", "DomProperties", "createRecord", "attrName", "propName", "type", "stringProps", "_ref", "_ref2", "_slicedToArray", "attr", "booleanProps", "integerProps", "_ref3", "_ref4", "Namespace", "xlink", "prefix", "resource", "xml", "setProperty", "element", "value", "style", "toLowerCase", "removeAttribute", "parsed", "parseInt", "isNaN", "indexOf", "removeAttributes", "propertyRecord", "setAttributes", "startsWith", "setAttributeNS", "setAttribute", "getPropertyValues", "attrValue", "getAttribute", "getBaseAttributes", "Array", "reduce", "name", "getAttributes", "updateAttributes", "removedAttributes", "changedAttributes", "oldValue", "nextValue", "push", "patchChildren", "patch", "templateChildrenLength", "vNodeChildrenLength", "vNodeKeyMap", "nextChildren", "undefined", "templateChild", "childNodes", "keyedChild", "vNodeChild", "appendChild", "childNodesLength", "delta", "removeChild", "rootNode", "parentNode", "contentChanged", "content", "replaceChild", "create", "node", "isSVGContext", "arguments", "length", "undefined", "toHTML", "isRoot", "tagName", "childNodes", "numChildNodes", "Error", "type", "nodeType", "toLowerCase", "isSVG", "attributes", "getAttributes", "content", "textContent", "children", "Array", "forEach", "child", "idx", "takeWhileMap", "pred", "lines", "output", "line", "a", "dropWhile", "index", "renderMetas", "meta", "m", "toMetadata", "metaValue", "metaValuesAll", "parseRemoteEvent", "parseAction", "parseMetadata", "input", "metas", "takeWhileMap", "parseMeta", "key", "splitMessage", "message", "lines", "command", "rest", "dropWhile", "l", "line", "match", "name", "data", "breakNextSegment", "viewId", "action", "ix", "err", "actionMessage", "id", "action", "state", "reqId", "form", "meta", "toSearch", "params", "value", "key", "renderActionMessage", "msg", "header", "renderMetas", "renderForm", "globalRequestId", "newRequest", "encodedParam", "param", "sanitizeParam", "protocol", "defaultAddress", "SocketConnection", "addr", "sock", "createSocket", "onConnectError", "ev", "onSocketError", "_event", "_", "action", "msg", "renderActionMessage", "next", "event", "command", "metas", "rest", "splitMessage", "requestId", "requireMeta", "key", "val", "metaValue", "ProtocolError", "parseResponse", "viewId", "toMetadata", "parseUpdate", "up", "parseRedirect", "url", "parseTrigger", "meta", "targetViewId", "targetAction", "parseAction", "parseEvent", "parseRemoteEvent", "cb", "description", "body", "debounce", "function_", "wait", "options", "immediate", "storedContext", "storedArguments", "timeoutId", "timestamp", "result", "run", "callContext", "callArguments", "later", "last", "debounced", "arguments_", "callNow", "isHyperView", "ele", "dispatchContent", "node", "event", "enrichHyperViews", "runAction", "element", "action", "listenKeydown", "cb", "listenKeyEvent", "listenKeyup", "event", "e", "source", "datasetKey", "action", "target", "nearestHyperViewTarget", "listenBubblingEvent", "listenClick", "listenDblClick", "listenTopLevel", "listenLoad", "node", "load", "delay", "onLoad", "listenMouseEnter", "onMouseEnter", "nearestAnyTarget", "listenMouseLeave", "onMouseLeave", "listenChange", "encodedParam", "listenInput", "startedTyping", "debounce", "listenFormSubmit", "form", "formData", "nearestTargetId", "isHyperView", "targetId", "setQuery", "query", "currentQuery", "url", "parseResponse", "res", "doc", "css", "package_default", "package_default", "rootStyles", "addedRulesIndex", "runAction", "target", "action", "form", "state", "req", "newRequest", "msg", "actionMessage", "sock", "handleTrigger", "trigger", "runTrigger", "handleEvent", "ev", "runRemoteEvent", "handleRedirect", "red", "applyCookies", "handleResponse", "res", "handleUpdate", "targetViewId", "isHyperView", "update", "parseResponse", "addCSS", "old", "create", "next", "atts", "patch", "newTarget", "dispatchContent", "runMetadata", "listenLoad", "listenMouseEnter", "listenMouseLeave", "fixInputs", "enrichHyperViews", "cookies", "cookie", "meta", "setQuery", "remoteEvent", "viewId", "event", "view", "focused", "input", "val", "checkbox", "checked", "src", "rules", "i", "rule", "init", "parseMetadata", "style", "listenTopLevel", "listenClick", "listenDblClick", "listenKeydown", "listenKeyup", "listenFormSubmit", "listenChange", "onStartedTyping", "listenInput", "SocketConnection", "con", "params", "str", "param", "element"]-}+{"version":3,"file":"hyperbole.js","names":[],"sources":["../node_modules/omdomdom/lib/omdomdom.es.js","../src/lib.ts","../src/message.ts","../src/action.ts","../src/response.ts","../src/sockets.ts","../node_modules/debounce/index.js","../src/hyperview.ts","../src/events.ts","../src/browser.ts","../src/http.ts","../src/index.ts"],"sourcesContent":["/*!\n  * @license MIT (https://github.com/geotrev/omdomdom/blob/master/LICENSE)\n  * Omdomdom v0.3.2 (https://github.com/geotrev/omdomdom)\n  * Copyright 2023 George Treviranus <geowtrev@gmail.com>\n  */\nvar DATA_KEY_ATTRIBUTE$1 = \"data-key\";\nvar hasProperty = function hasProperty(obj, prop) {\n  return Object.prototype.hasOwnProperty.call(obj, prop);\n};\nvar keyIsValid = function keyIsValid(map, key) {\n  if (!key) return false;\n  if (hasProperty(map, key)) {\n    console.warn(\"[OmDomDom]: Children with duplicate keys detected. Children with duplicate keys will be skipped, resulting in dropped node references. Keys must be unique and non-indexed.\");\n    return false;\n  }\n  return true;\n};\nvar forEach = function forEach(items, fn) {\n  var length = items.length;\n  var idx = -1;\n  if (!length) return;\n  while (++idx < length) {\n    if (fn(items[idx], idx) === false) break;\n  }\n};\nvar createKeyMap = function createKeyMap(children) {\n  var map = {};\n  forEach(children, function (child) {\n    var key = child.attributes[DATA_KEY_ATTRIBUTE$1];\n    if (keyIsValid(map, key)) {\n      map[key] = child;\n    }\n  });\n  for (var _ in map) {\n    return map;\n  }\n};\nvar insertBefore = function insertBefore(parent, child, refNode) {\n  return parent.node.insertBefore(child.node, refNode);\n};\nvar assignVNode = function assignVNode(template, vNode) {\n  for (var property in template) {\n    vNode[property] = template[property];\n  }\n};\n\nvar toHTML = function toHTML(htmlString) {\n  var processedDOMString = htmlString.trim().replace(/\\s+</g, \"<\").replace(/>\\s+/g, \">\");\n  var parser = new DOMParser();\n  var context = parser.parseFromString(processedDOMString, \"text/html\");\n  return context.body;\n};\n\nfunction _iterableToArrayLimit(arr, i) {\n  var _i = null == arr ? null : \"undefined\" != typeof Symbol && arr[Symbol.iterator] || arr[\"@@iterator\"];\n  if (null != _i) {\n    var _s,\n      _e,\n      _x,\n      _r,\n      _arr = [],\n      _n = !0,\n      _d = !1;\n    try {\n      if (_x = (_i = _i.call(arr)).next, 0 === i) {\n        if (Object(_i) !== _i) return;\n        _n = !1;\n      } else for (; !(_n = (_s = _x.call(_i)).done) && (_arr.push(_s.value), _arr.length !== i); _n = !0);\n    } catch (err) {\n      _d = !0, _e = err;\n    } finally {\n      try {\n        if (!_n && null != _i.return && (_r = _i.return(), Object(_r) !== _r)) return;\n      } finally {\n        if (_d) throw _e;\n      }\n    }\n    return _arr;\n  }\n}\nfunction _slicedToArray(arr, i) {\n  return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest();\n}\nfunction _arrayWithHoles(arr) {\n  if (Array.isArray(arr)) return arr;\n}\nfunction _unsupportedIterableToArray(o, minLen) {\n  if (!o) return;\n  if (typeof o === \"string\") return _arrayLikeToArray(o, minLen);\n  var n = Object.prototype.toString.call(o).slice(8, -1);\n  if (n === \"Object\" && o.constructor) n = o.constructor.name;\n  if (n === \"Map\" || n === \"Set\") return Array.from(o);\n  if (n === \"Arguments\" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen);\n}\nfunction _arrayLikeToArray(arr, len) {\n  if (len == null || len > arr.length) len = arr.length;\n  for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i];\n  return arr2;\n}\nfunction _nonIterableRest() {\n  throw new TypeError(\"Invalid attempt to destructure non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.\");\n}\n\nvar Types = {\n  STRING: \"string\",\n  INT: \"number\",\n  BOOL: \"boolean\"\n};\nvar DomProperties = {};\nvar createRecord = function createRecord(attrName, propName, type) {\n  return {\n    attrName: attrName,\n    propName: propName,\n    type: type\n  };\n};\nvar stringProps = [[\"style\", \"cssText\"], [\"class\", \"className\"]];\nforEach(stringProps, function (_ref) {\n  var _ref2 = _slicedToArray(_ref, 2),\n    attr = _ref2[0],\n    property = _ref2[1];\n  DomProperties[attr] = createRecord(attr, property || attr, Types.STRING);\n});\nvar booleanProps = [\"autofocus\", \"draggable\", \"hidden\", \"checked\", \"multiple\", \"muted\", \"selected\"];\nforEach(booleanProps, function (attr) {\n  DomProperties[attr] = createRecord(attr, attr, Types.BOOL);\n});\nvar integerProps = [[\"tabindex\", \"tabIndex\"]];\nforEach(integerProps, function (_ref3) {\n  var _ref4 = _slicedToArray(_ref3, 2),\n    attr = _ref4[0],\n    property = _ref4[1];\n  DomProperties[attr] = createRecord(attr, property, Types.INT);\n});\nvar Namespace = {\n  xlink: {\n    prefix: \"xlink:\",\n    resource: \"http://www.w3.org/1999/xlink\"\n  },\n  xml: {\n    prefix: \"xml:\",\n    resource: \"http://www.w3.org/XML/1998/namespace\"\n  }\n};\n\nvar setProperty = function setProperty(element, type, prop, value) {\n  switch (type) {\n    case Types.STRING:\n      {\n        if (prop === DomProperties.style.propName) {\n          if (value === null) {\n            element.style[prop] = \"\";\n          } else {\n            element.style[prop] = value;\n          }\n        } else if (value === null) {\n          element[prop] = \"\";\n        } else {\n          element[prop] = value;\n        }\n        break;\n      }\n    case Types.INT:\n      {\n        if (value === null) {\n          var attr = prop.toLowerCase();\n          element.removeAttribute(attr);\n        } else if (value === \"0\") {\n          element[prop] = 0;\n        } else if (value === \"-1\") {\n          element[prop] = -1;\n        } else {\n          var parsed = parseInt(value, 10);\n          if (!isNaN(parsed)) {\n            element[prop] = parsed;\n          }\n        }\n        break;\n      }\n    case Types.BOOL:\n      {\n        if ([\"\", \"true\"].indexOf(value) < 0) {\n          element[prop] = false;\n        } else {\n          element[prop] = true;\n        }\n        break;\n      }\n  }\n};\n\nvar removeAttributes = function removeAttributes(vNode, attributes) {\n  forEach(attributes, function (attrName) {\n    if (hasProperty(DomProperties, attrName)) {\n      var propertyRecord = DomProperties[attrName];\n      setProperty(vNode.node, propertyRecord.type, propertyRecord.propName, null);\n    } else {\n      if (attrName in vNode.node) {\n        setProperty(vNode.node, Types.STRING, attrName, null);\n      }\n      vNode.node.removeAttribute(attrName);\n    }\n    delete vNode.attributes[attrName];\n  });\n};\nvar setAttributes = function setAttributes(vNode, attributes) {\n  for (var attrName in attributes) {\n    var value = attributes[attrName];\n    vNode.attributes[attrName] = value;\n    if (hasProperty(DomProperties, attrName)) {\n      var propertyRecord = DomProperties[attrName];\n      setProperty(vNode.node, propertyRecord.type, propertyRecord.propName, value);\n      continue;\n    }\n    if (attrName.startsWith(Namespace.xlink.prefix)) {\n      vNode.node.setAttributeNS(Namespace.xlink.resource, attrName, value);\n      continue;\n    }\n    if (attrName.startsWith(Namespace.xml.prefix)) {\n      vNode.node.setAttributeNS(Namespace.xml.resource, attrName, value);\n      continue;\n    }\n    if (attrName in vNode.node) {\n      setProperty(vNode.node, Types.STRING, attrName, value);\n    }\n    vNode.node.setAttribute(attrName, value || \"\");\n  }\n};\nvar getPropertyValues = function getPropertyValues(element, attributes) {\n  for (var attrName in DomProperties) {\n    var propertyRecord = DomProperties[attrName];\n    var propName = propertyRecord.propName;\n    var attrValue = element.getAttribute(attrName);\n    if (attrName === DomProperties.style.attrName) {\n      attributes[attrName] = element.style[propName];\n    } else if (typeof attrValue === \"string\") {\n      attributes[attrName] = attrValue;\n    }\n  }\n};\nvar getBaseAttributes = function getBaseAttributes(element) {\n  return Array.prototype.reduce.call(element.attributes, function (attributes, attrName) {\n    if (!hasProperty(DomProperties, attrName.name)) {\n      attributes[attrName.name] = attrName.value;\n    }\n    return attributes;\n  }, {});\n};\nvar getAttributes = function getAttributes(element) {\n  var attributes = getBaseAttributes(element);\n  getPropertyValues(element, attributes);\n  return attributes;\n};\nvar updateAttributes = function updateAttributes(template, vNode) {\n  var removedAttributes = [];\n  var changedAttributes = {};\n  for (var attrName in vNode.attributes) {\n    var oldValue = vNode.attributes[attrName];\n    var nextValue = template.attributes[attrName];\n    if (oldValue === nextValue) continue;\n    if (typeof nextValue === \"undefined\") {\n      removedAttributes.push(attrName);\n    }\n  }\n  for (var _attrName in template.attributes) {\n    var _oldValue = vNode.attributes[_attrName];\n    var _nextValue = template.attributes[_attrName];\n    if (_oldValue === _nextValue) continue;\n    if (typeof _nextValue !== \"undefined\") {\n      changedAttributes[_attrName] = _nextValue;\n    }\n  }\n  removeAttributes(vNode, removedAttributes);\n  setAttributes(vNode, changedAttributes);\n};\n\nvar DATA_KEY_ATTRIBUTE = \"data-key\";\nfunction patchChildren(template, vNode, patch) {\n  var templateChildrenLength = template.children.length;\n  var vNodeChildrenLength = vNode.children.length;\n  if (!templateChildrenLength && !vNodeChildrenLength) return;\n  var vNodeKeyMap = createKeyMap(vNode.children);\n  var nextChildren = Array(templateChildrenLength);\n  if (vNodeKeyMap !== undefined) {\n    forEach(template.children, function (templateChild, idx) {\n      var childNodes = vNode.node.childNodes;\n      var key = templateChild.attributes[DATA_KEY_ATTRIBUTE];\n      if (Object.prototype.hasOwnProperty.call(vNodeKeyMap, key)) {\n        var keyedChild = vNodeKeyMap[key];\n        if (Array.prototype.indexOf.call(childNodes, keyedChild.node) !== idx) {\n          insertBefore(vNode, keyedChild, childNodes[idx]);\n        }\n        nextChildren[idx] = keyedChild;\n        delete vNodeKeyMap[key];\n        patch(templateChild, nextChildren[idx]);\n      } else {\n        insertBefore(vNode, templateChild, childNodes[idx]);\n        nextChildren[idx] = templateChild;\n      }\n    });\n  } else {\n    forEach(template.children, function (templateChild, idx) {\n      var vNodeChild = vNode.children[idx];\n      if (typeof vNodeChild !== \"undefined\") {\n        patch(templateChild, vNodeChild);\n        nextChildren[idx] = vNodeChild;\n      } else {\n        vNode.node.appendChild(templateChild.node);\n        nextChildren[idx] = templateChild;\n      }\n    });\n  }\n  vNode.children = nextChildren;\n  var childNodesLength = vNode.node.childNodes.length;\n  var delta = childNodesLength - templateChildrenLength;\n  if (delta > 0) {\n    while (delta > 0) {\n      vNode.node.removeChild(vNode.node.childNodes[childNodesLength - 1]);\n      childNodesLength--;\n      delta--;\n    }\n  }\n}\n\nvar patch = function patch(template, vNode, rootNode) {\n  if (!template || !vNode) return;\n  rootNode = rootNode || vNode.node.parentNode;\n  var contentChanged = template.content && template.content !== vNode.content;\n  if (template.type !== vNode.type || contentChanged) {\n    rootNode.replaceChild(template.node, vNode.node);\n    return assignVNode(template, vNode);\n  }\n  updateAttributes(template, vNode);\n  patchChildren(template, vNode, patch);\n};\nvar render = function render(vNode, root) {\n  root.appendChild(vNode.node);\n};\nvar create = function create(node) {\n  var isSVGContext = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;\n  if (typeof node === \"string\") {\n    node = toHTML(node);\n  }\n  var isRoot = node.tagName === \"BODY\";\n  var childNodes = node.childNodes;\n  var numChildNodes = childNodes ? childNodes.length : 0;\n  if (isRoot) {\n    if (numChildNodes > 1) {\n      throw new Error(\"[OmDomDom]: Your element should not have more than one root node.\");\n    } else if (numChildNodes === 0) {\n      throw new Error(\"[OmDomDom]: Your element should have at least one root node.\");\n    } else {\n      return create(childNodes[0]);\n    }\n  }\n  var type = node.nodeType === 3 ? \"text\" : node.nodeType === 8 ? \"comment\" : node.tagName.toLowerCase();\n  var isSVG = isSVGContext || type === \"svg\";\n  var attributes = node.nodeType === 1 ? getAttributes(node) : {};\n  var content = numChildNodes > 0 ? null : node.textContent;\n  var children = Array(numChildNodes);\n  forEach(childNodes, function (child, idx) {\n    children[idx] = create(child, isSVG);\n  });\n  return {\n    type: type,\n    attributes: attributes,\n    children: children,\n    content: content,\n    node: node,\n    isSVGContext: isSVG\n  };\n};\n\nexport { create, patch, render };\n//# sourceMappingURL=omdomdom.es.js.map\n","export function takeWhileMap<T, A>(pred: (val: T) => A | undefined, lines: T[]): A[] {\n  var output = []\n  for (var line of lines) {\n    let a = pred(line)\n    if (a) output.push(a)\n    else break\n  }\n\n  return output\n}\n\nexport function dropWhile<T, A>(pred: (val: T) => A | undefined, lines: T[]): T[] {\n  let index = 0\n  while (index < lines.length && pred(lines[index])) {\n    index++\n  }\n  return lines.slice(index)\n}\n","import { takeWhileMap, dropWhile } from \"./lib\"\n\nexport type Meta = { key: string; value: string }\nexport type ViewId = string\nexport type RequestId = number\nexport type EncodedAction = string\nexport type ViewState = string\n\nexport type RemoteEvent = { name: string; detail: unknown }\n\nexport function renderMetas(meta: Meta[]): string {\n  return meta.map((m) => m.key + \": \" + m.value).join(\"\\n\")\n}\n\nexport type Metadata = {\n  cookies?: string[]\n  // redirect?: string\n  error?: string\n  query?: string\n  events?: RemoteEvent[]\n  actions?: [ViewId, EncodedAction][]\n  pageTitle?: string\n}\n\nexport function toMetadata(meta: Meta[]): Metadata {\n  return {\n    cookies: meta.filter((m) => m.key == \"Cookie\").map((m) => m.value),\n    // redirect: metaValue(\"Redirect\", meta),\n    error: metaValue(\"Error\", meta),\n    query: metaValue(\"Query\", meta),\n    pageTitle: metaValue(\"PageTitle\", meta),\n    events: metaValuesAll(\"Event\", meta).map(parseRemoteEvent),\n    actions: metaValuesAll(\"Trigger\", meta).map(parseAction),\n  }\n}\n\n// viewId: meta.find(m => m.key == \"VIEW-ID\")?.value,\n\nexport function parseMetadata(input: string): Metadata {\n  let metas = parseMetas(input.trim().split(\"\\n\"))\n  return toMetadata(metas)\n}\n\nexport function metaValue(key: string, metas: Meta[]): string | undefined {\n  return metas.find((m) => m.key == key)?.value\n}\n\nexport function metaValuesAll(key: string, metas: Meta[]): string[] {\n  return metas.filter((m) => m.key == key).map((m) => m.value)\n}\n\nexport type SplitMessage = {\n  command: string\n  metas: Meta[]\n  rest: string[]\n}\n\nexport function splitMessage(message: string): SplitMessage {\n  let lines = message.split(\"\\n\")\n  let command: string = lines[0]\n  let metas: Meta[] = takeWhileMap(parseMeta, lines.slice(1))\n  // console.log(\"Split Metadata\", lines.length)\n  // console.log(\" [0]\", lines[0])\n  // console.log(\" [1]\", lines[1])\n  let rest = dropWhile((l) => l == \"\", lines.slice(metas.length + 1))\n\n  return { command, metas, rest }\n}\n\nexport function parseMetas(lines: string[]): Meta[] {\n  return takeWhileMap(parseMeta, lines)\n}\n\nexport function parseMeta(line: string): Meta | undefined {\n  let match = line.match(/^(\\w+): (.*)$/)\n  if (match) {\n    return {\n      key: match[1],\n      value: match[2],\n    }\n  }\n}\n\nexport function parseRemoteEvent(input: string): RemoteEvent {\n  let [name, data] = breakNextSegment(input)\n  return {\n    name,\n    detail: JSON.parse(data),\n  }\n}\n\nexport function parseAction(input: string): [ViewId, string] {\n  let [viewId, action] = breakNextSegment(input)\n  return [viewId, action]\n}\n\nfunction breakNextSegment(input: string): [string, string] {\n  let ix = input.indexOf(\"|\")\n  if (ix === -1) {\n    let err = new Error(\"Bad Encoding, Expected Segment\")\n    err.message = input\n    throw err\n  }\n  return [input.slice(0, ix), input.slice(ix + 1)]\n}\n","import {\n  type Meta,\n  type ViewId,\n  type RequestId,\n  type ViewState,\n  type EncodedAction,\n} from \"./message\"\nimport * as message from \"./message\"\n\nexport type ActionMessage = {\n  viewId: ViewId\n  action: EncodedAction\n  requestId: RequestId\n  state?: ViewState\n  meta: Meta[]\n  form?: FormData\n  value?: InputValue\n}\n\nexport type InputValue = string\n\nexport type ActionBody = FormData | InputValue\n\nexport function actionMessage(\n  id: ViewId,\n  action: EncodedAction,\n  state: ViewState | undefined,\n  reqId: RequestId,\n  body?: ActionBody,\n): ActionMessage {\n  let meta: Meta[] = [\n    { key: \"Cookie\", value: decodeURI(document.cookie) },\n    { key: \"Query\", value: window.location.search },\n  ]\n\n  let form = undefined\n  let value = undefined\n  if (body instanceof FormData) {\n    form = body\n  } else if (body) {\n    value = body as string\n  }\n\n  return { viewId: id, action, state, requestId: reqId, meta, form, value }\n}\n\nexport function renderActionMessage(msg: ActionMessage): string {\n  let header = [\"|ACTION|\", \"ViewId: \" + msg.viewId, \"Action: \" + msg.action]\n\n  if (msg.state) {\n    header.push(\"State: \" + msg.state)\n  }\n\n  header.push(\"RequestId: \" + msg.requestId)\n\n  return [header.join(\"\\n\"), message.renderMetas(msg.meta)].join(\"\\n\") + renderInput(msg.value)\n  // Forms are submitted via fetch() + renderForm(msg.form)\n}\n\nexport function renderInput(value?: InputValue): string {\n  if (!value) return \"\"\n  return \"\\n\\n\" + value\n}\n\nlet globalRequestId: RequestId = 0\n\nexport type Request = {\n  requestId: RequestId\n  isCancelled: boolean\n}\n\nexport function newRequest(): Request {\n  let requestId = ++globalRequestId\n  return { requestId, isCancelled: false }\n}\n","import {\n  type ViewId,\n  type Metadata,\n  type Meta,\n  metaValue,\n  toMetadata,\n  type RequestId,\n  type EncodedAction,\n} from \"./message\"\n\nexport type ResponseBody = string\n\nexport function parseResponseDocument(res: ResponseBody): Document {\n  const parser = new DOMParser()\n  return parser.parseFromString(res, \"text/html\")\n}\n\nexport function documentUpdate(doc: Document): LiveUpdate {\n  const css = doc.querySelector<HTMLStyleElement>(\"style\")\n  const content = doc.querySelector<HTMLElement>(\"div\")\n\n  return {\n    content: content,\n    css: css,\n  }\n}\n\nexport type BaseResponse = {\n  requestId: RequestId\n  meta: Metadata\n  viewId: ViewId\n  targetViewId?: ViewId\n  action: EncodedAction\n  body: ResponseBody\n}\n\nexport type Response = BaseResponse & {\n  kind: \"response\"\n}\n\nexport type Update = BaseResponse & {\n  kind: \"update\"\n  targetViewId: ViewId\n}\n\nexport type Redirect = {\n  kind: \"redirect\"\n  requestId: RequestId\n  meta: Metadata\n  url: string\n}\n\nexport function parseUpdate(metas: Meta[], rest: string[]): Update {\n  let { requestId, viewId, action, meta, body } = parseResponse(metas, rest)\n\n  return {\n    kind: \"update\",\n    targetViewId: metaValue(\"TargetViewId\", metas) || viewId,\n    requestId,\n    viewId,\n    action,\n    meta,\n    body,\n  }\n}\n\nexport function parseResponse(metas: Meta[], rest: string[]): Response {\n  let viewId = requireMeta(rest, metas, \"ViewId\")\n  let action = requireMeta(rest, metas, \"Action\")\n  let requestId = parseInt(requireMeta(rest, metas, \"RequestId\"), 0)\n  return {\n    kind: \"response\",\n    requestId,\n    targetViewId: undefined, // only set on push update\n    viewId,\n    action,\n    meta: toMetadata(metas),\n    body: rest.join(\"\\n\"),\n  }\n}\n\nexport function parseRedirect(metas: Meta[], rest: string[]): Redirect {\n  let url = rest[0]\n  let requestId = parseInt(requireMeta(rest, metas, \"RequestId\"), 0)\n  return {\n    kind: \"redirect\",\n    requestId,\n    meta: toMetadata(metas),\n    url,\n  }\n}\n\nexport function requireMeta(lines: string[], metas: Meta[], key: string): string {\n  let val = metaValue(key, metas)\n  if (!val) throw new ProtocolError(\"Missing Required Metadata: \" + key, lines.join(\"\\n\"))\n  return val\n}\n\nexport type LiveUpdate = {\n  content: HTMLElement | null\n  css: HTMLStyleElement | null\n}\n\nexport class FetchError extends Error {\n  viewId: ViewId\n  body: string\n  constructor(viewId: ViewId, msg: string, body: string) {\n    super(msg)\n    this.viewId = viewId\n    this.name = \"Fetch Error\"\n    this.body = body\n  }\n}\n\nexport class ProtocolError extends Error {\n  constructor(description: string, body: string) {\n    super(description + \"\\n\" + body)\n    this.name = \"ProtocolError\"\n  }\n}\n","import { type ActionMessage, renderActionMessage } from \"./action\"\nimport { type ResponseBody, ProtocolError, type Response } from \"./response\"\nimport { dropWhile } from \"./lib\"\nimport * as message from \"./message\"\nimport {\n  type ViewId,\n  type RequestId,\n  type EncodedAction,\n  metaValue,\n  type Metadata,\n  type RemoteEvent,\n  type Meta,\n} from \"./message\"\n\nconst protocol = window.location.protocol === \"https:\" ? \"wss:\" : \"ws:\"\nconst defaultAddress = `${protocol}//${window.location.host}${window.location.pathname}`\n\ninterface SocketConnectionEventMap {\n  update: CustomEvent<Update>\n  response: CustomEvent<Response>\n  redirect: CustomEvent<Redirect>\n  trigger: CustomEvent<Trigger>\n  event: CustomEvent<JSEvent>\n}\n\nexport class SocketConnection {\n  socket: WebSocket\n\n  hasEverConnected: boolean = false\n  isConnected: boolean = false\n  reconnectDelay: number = 0\n  queue: ActionMessage[] = []\n  events: EventTarget\n\n  constructor(addr = defaultAddress) {\n    this.events = new EventTarget()\n    const sock = new WebSocket(addr)\n    this.socket = sock\n  }\n\n  connect(addr = defaultAddress, createSocket = false) {\n    const sock = createSocket ? new WebSocket(addr) : this.socket\n    this.socket = sock\n\n    function onConnectError(ev: Event) {\n      console.error(\"Connect Error\", ev)\n    }\n\n    function onSocketError(ev: Event) {\n      console.error(\"Socket Error\", ev)\n    }\n\n    // initial connection errors\n    sock.addEventListener(\"error\", onConnectError)\n\n    sock.addEventListener(\"open\", (_event) => {\n      console.log(\"Websocket Connected\")\n\n      if (this.hasEverConnected) {\n        document.dispatchEvent(new Event(\"hyp-socket-reconnect\"))\n      }\n\n      this.isConnected = true\n      this.hasEverConnected = true\n      this.reconnectDelay = 1000\n      sock.removeEventListener(\"error\", onConnectError)\n      sock.addEventListener(\"error\", onSocketError)\n\n      document.dispatchEvent(new Event(\"hyp-socket-connect\"))\n\n      this.runQueue()\n    })\n\n    sock.addEventListener(\"close\", (_) => {\n      console.log(\"CLOSE SOCKET\")\n      if (this.isConnected) {\n        document.dispatchEvent(new Event(\"hyp-socket-disconnect\"))\n      }\n\n      this.isConnected = false\n      sock.removeEventListener(\"error\", onSocketError)\n\n      // attempt to reconnect in 1s\n      if (this.hasEverConnected) {\n        console.log(\"Reconnecting in \" + this.reconnectDelay / 1000 + \"s\")\n        setTimeout(() => this.connect(addr, true), this.reconnectDelay)\n      }\n\n      sock.removeEventListener(\"error\", onSocketError)\n    })\n\n    sock.addEventListener(\"message\", (ev) => this.onMessage(ev))\n  }\n\n  async sendAction(action: ActionMessage) {\n    if (this.isConnected) {\n      let msg = renderActionMessage(action)\n      this.socket.send(msg)\n    } else {\n      this.queue.push(action)\n    }\n  }\n\n  private runQueue() {\n    // send all messages queued while disconnected\n    let next: ActionMessage | undefined = this.queue.pop()\n    if (next) {\n      console.log(\"runQueue: \", next)\n      void this.sendAction(next)\n      this.runQueue()\n    }\n  }\n\n  // full responses will never be sent over!\n  private onMessage(event: MessageEvent) {\n    let { command, metas, rest } = splitMessage(event.data)\n    // console.log(\"MESSAGE\", command, metas, rest)\n\n    let requestId = parseInt(requireMeta(\"RequestId\"), 0)\n\n    function requireMeta(key: string): string {\n      let val = metaValue(key, metas)\n      if (!val) throw new ProtocolError(\"Missing Required Metadata: \" + key, event.data)\n      return val\n    }\n\n    function parseResponse(rest: string[]): Update {\n      let viewId = requireMeta(\"ViewId\")\n      let action = requireMeta(\"Action\")\n      return {\n        requestId,\n        targetViewId: undefined,\n        viewId,\n        action,\n        meta: message.toMetadata(metas),\n        body: rest.join(\"\\n\"),\n      }\n    }\n\n    function parseUpdate(rest: string[]): Update {\n      let up = parseResponse(rest)\n      // add the TargetViewId\n      up.targetViewId = metaValue(\"TargetViewId\", metas)\n      return up\n    }\n\n    function parseRedirect(rest: string[]): Redirect {\n      let url = rest[0]\n      return {\n        requestId,\n        meta: message.toMetadata(metas),\n        url,\n      }\n    }\n\n    function parseTrigger(rest: string[]): Trigger {\n      let { requestId, meta, viewId, action } = parseResponse(rest)\n      let [targetViewId, targetAction] = message.parseAction(requireMeta(\"Trigger\"))\n      return { requestId, meta, viewId, action, targetViewId, targetAction }\n    }\n\n    function parseEvent(rest: string[]): JSEvent {\n      let { requestId, meta, viewId, action } = parseResponse(rest)\n      let event = message.parseRemoteEvent(requireMeta(\"Event\"))\n      return { requestId, meta, viewId, action, event }\n    }\n\n    switch (command) {\n      case \"|UPDATE|\":\n        this.dispatchEvent(new CustomEvent<Update>(\"update\", { detail: parseUpdate(rest) }))\n        return\n\n      case \"|RESPONSE|\":\n        this.dispatchEvent(new CustomEvent<Update>(\"response\", { detail: parseResponse(rest) }))\n        return\n\n      case \"|REDIRECT|\":\n        return this.dispatchEvent(new CustomEvent(\"redirect\", { detail: parseRedirect(rest) }))\n\n      case \"|TRIGGER|\":\n        return this.dispatchEvent(new CustomEvent(\"trigger\", { detail: parseTrigger(rest) }))\n\n      case \"|EVENT|\":\n        return this.dispatchEvent(new CustomEvent(\"event\", { detail: parseEvent(rest) }))\n\n      default:\n        throw new ProtocolError(\"Unknown Server Command: \" + command, event.data)\n    }\n  }\n\n  // so what if they send remote events in the page? trigger, redirect, page title, etc...\n  // we aren't connected yet on a page thing\n\n  // private async waitMessage(reqId: RequestId, id: ViewId): Promise<ParsedResponse> {\n  //   return new Promise((resolve, reject) => {\n  //     const onMessage = (event: MessageEvent) => {\n  //       let data: string = event.data\n  //       let lines = data.split(\"\\n\").slice(1)  // drop the command line\n  //\n  //       let parsed = splitMetadata(lines)\n  //       let metadata: Metadata = parsed.metadata\n  //\n  //       if (!metadata.requestId) {\n  //         console.error(\"Missing RequestId!\", metadata, event.data)\n  //         return\n  //       }\n  //\n  //       if (metadata.requestId != reqId) {\n  //         // skip, it's not us!\n  //         return\n  //       }\n  //\n  //\n  //       // We have found our message. Remove the listener\n  //       this.socket.removeEventListener('message', onMessage)\n  //\n  //       // set the cookies. These happen automatically in http\n  //       metadata.cookies.forEach((cookie: string) => {\n  //         document.cookie = cookie\n  //       })\n  //\n  //       if (metadata.error) {\n  //         reject(new FetchError(id, metadata.error, parsed.rest.join('\\n')))\n  //         return\n  //       }\n  //\n  //       resolve(parsed)\n  //     }\n  //\n  //     this.socket.addEventListener('message', onMessage)\n  //     this.socket.addEventListener('error', reject)\n  //   })\n  // }\n\n  addEventListener<K extends keyof SocketConnectionEventMap>(\n    e: K,\n    cb: (ev: SocketConnectionEventMap[K]) => void,\n  ) {\n    this.events.addEventListener(\n      e,\n      // @ts-ignore: HACK\n      cb,\n    )\n  }\n\n  dispatchEvent<K extends keyof SocketConnectionEventMap>(e: SocketConnectionEventMap[K]) {\n    this.events.dispatchEvent(e)\n  }\n\n  disconnect() {\n    this.isConnected = false\n    this.hasEverConnected = false\n    this.socket.close()\n  }\n}\n\nexport type Update = {\n  requestId: RequestId\n  meta: Metadata\n  viewId: ViewId\n  targetViewId?: ViewId\n  action: EncodedAction\n  body: ResponseBody\n}\n\nexport type Redirect = {\n  requestId: RequestId\n  meta: Metadata\n  url: string\n}\n\nexport type Trigger = {\n  requestId: RequestId\n  meta: Metadata\n  viewId: ViewId\n  action: EncodedAction\n  targetViewId: ViewId\n  targetAction: string\n}\n\nexport type JSEvent = {\n  requestId: RequestId\n  meta: Metadata\n  viewId: ViewId\n  action: EncodedAction\n  event: RemoteEvent\n}\n\nexport type MessageType = string\n\nexport type SplitMessage = {\n  command: string\n  metas: Meta[]\n  rest: string[]\n}\n\nexport function splitMessage(msg: string): SplitMessage {\n  let lines = msg.split(\"\\n\")\n  let command: string = lines[0]\n  let metas: Meta[] = message.parseMetas(lines.slice(1))\n  // console.log(\"Split Metadata\", lines.length)\n  // console.log(\" [0]\", lines[0])\n  // console.log(\" [1]\", lines[1])\n  let rest = dropWhile((l) => l == \"\", lines.slice(metas.length + 1))\n\n  return { command, metas, rest }\n}\n","export default function debounce(function_, wait = 100, options = {}) {\n\tif (typeof function_ !== 'function') {\n\t\tthrow new TypeError(`Expected the first parameter to be a function, got \\`${typeof function_}\\`.`);\n\t}\n\n\tif (wait < 0) {\n\t\tthrow new RangeError('`wait` must not be negative.');\n\t}\n\n\tif (typeof options === 'boolean') {\n\t\tthrow new TypeError('The `options` parameter must be an object, not a boolean. Use `{immediate: true}` instead.');\n\t}\n\n\tconst {immediate} = options;\n\n\tlet storedContext;\n\tlet storedArguments;\n\tlet timeoutId;\n\tlet timestamp;\n\tlet result;\n\n\tfunction run() {\n\t\tconst callContext = storedContext;\n\t\tconst callArguments = storedArguments;\n\t\tstoredContext = undefined;\n\t\tstoredArguments = undefined;\n\t\tresult = function_.apply(callContext, callArguments);\n\t\treturn result;\n\t}\n\n\tfunction later() {\n\t\tconst last = Date.now() - timestamp;\n\n\t\tif (last < wait && last >= 0) {\n\t\t\ttimeoutId = setTimeout(later, wait - last);\n\t\t} else {\n\t\t\ttimeoutId = undefined;\n\n\t\t\tif (!immediate) {\n\t\t\t\tresult = run();\n\t\t\t}\n\t\t}\n\t}\n\n\tconst debounced = function (...arguments_) {\n\t\tif (\n\t\t\tstoredContext\n\t\t\t&& this !== storedContext\n\t\t\t&& Object.getPrototypeOf(this) === Object.getPrototypeOf(storedContext)\n\t\t) {\n\t\t\tthrow new Error('Debounced method called with different contexts of the same prototype.');\n\t\t}\n\n\t\tstoredContext = this; // eslint-disable-line unicorn/no-this-assignment\n\t\tstoredArguments = arguments_;\n\t\ttimestamp = Date.now();\n\n\t\tconst callNow = immediate && !timeoutId;\n\n\t\tif (!timeoutId) {\n\t\t\ttimeoutId = setTimeout(later, wait);\n\t\t}\n\n\t\tif (callNow) {\n\t\t\tresult = run();\n\t\t\treturn result;\n\t\t}\n\n\t\treturn undefined;\n\t};\n\n\tObject.defineProperty(debounced, 'isPending', {\n\t\tget() {\n\t\t\treturn timeoutId !== undefined;\n\t\t},\n\t});\n\n\tdebounced.clear = () => {\n\t\tif (!timeoutId) {\n\t\t\treturn;\n\t\t}\n\n\t\tclearTimeout(timeoutId);\n\t\ttimeoutId = undefined;\n\t\tstoredContext = undefined;\n\t\tstoredArguments = undefined;\n\t};\n\n\tdebounced.flush = () => {\n\t\tif (!timeoutId) {\n\t\t\treturn;\n\t\t}\n\n\t\tdebounced.trigger();\n\t};\n\n\tdebounced.trigger = () => {\n\t\tresult = run();\n\n\t\tdebounced.clear();\n\t};\n\n\treturn debounced;\n}\n","import { type Request, type ActionBody } from \"./action\"\n\nexport interface HyperView extends HTMLElement {\n  runAction(action: string, body?: ActionBody): Promise<void>\n  activeRequest?: Request\n  cancelActiveRequest(): void\n  concurrency: ConcurrencyMode\n  _timeout?: number\n}\n\nexport const isHyperView = (ele: any): ele is HyperView => {\n  return ele?.runAction !== undefined\n}\n\nexport type ConcurrencyMode = string\n\nexport function dispatchContent(node: HTMLElement): void {\n  let event = new Event(\"hyp-content\", { bubbles: true })\n  node.dispatchEvent(event)\n}\n\nexport function enrichHyperViews(\n  node: HTMLElement,\n  runAction: (target: HyperView, action: string, body: ActionBody) => Promise<void>,\n): void {\n  // enrich all the hyperviews\n  node.querySelectorAll<HyperView>(\"[id]\").forEach((element) => {\n    element.runAction = function (action: string, body: ActionBody) {\n      return runAction(element, action, body)\n    }\n\n    element.concurrency = element.dataset.concurrency || \"Drop\"\n\n    element.cancelActiveRequest = function () {\n      if (element.activeRequest && !element.activeRequest?.isCancelled) {\n        element.activeRequest.isCancelled = true\n      }\n    }\n\n    dispatchContent(node)\n  })\n}\n","import debounce from \"debounce\"\nimport { type InputValue } from \"./action\"\nimport { isHyperView, type HyperView } from \"./hyperview\"\n\nexport type UrlFragment = string\n\nexport function listenKeydown(cb: (target: HyperView, action: string) => void): void {\n  listenKeyEvent(\"keydown\", cb)\n}\n\nexport function listenKeyup(cb: (target: HyperView, action: string) => void): void {\n  listenKeyEvent(\"keyup\", cb)\n}\n\nexport function listenKeyEvent(\n  event: \"keyup\" | \"keydown\",\n  cb: (target: HyperView, action: string) => void,\n): void {\n  document.addEventListener(event, function (e: KeyboardEvent) {\n    if (!(e.target instanceof HTMLElement)) {\n      console.warn(\"listenKeyEvent received event with non HTMLElment as EventTarget: %o\", e)\n      return\n    }\n    let source = e.target\n\n    let datasetKey = \"on\" + event + e.key\n    let action = source.dataset[datasetKey]\n    if (!action) return\n\n    e.preventDefault()\n    const target = nearestHyperViewTarget(source)\n    if (!target) {\n      console.error(\"Missing target: \", source)\n      return\n    }\n    cb(target, action)\n  })\n}\n\nexport function listenBubblingEvent(\n  event: string,\n  cb: (_target: HyperView, action: string) => void,\n): void {\n  document.addEventListener(event, function (e) {\n    if (!(e.target instanceof Element)) {\n      console.warn(\"listenBubblingEvent received an event with non Elment as EventTarget: %o\", e)\n      return\n    }\n    let el = e.target\n\n    // clicks can fire on internal elements. Find the parent with a click handler\n    let source = el.closest<HTMLElement>(\"[data-on\" + event + \"]\")\n    if (!source) return\n\n    e.preventDefault()\n    let target = nearestHyperViewTarget(source)\n    if (!target) {\n      console.error(\"Missing target: \", source)\n      return\n    }\n    const action = source.dataset[\"on\" + event]\n    if (action === undefined) {\n      console.error(\"Missing action: \", source, event)\n      return\n    }\n    cb(target, action)\n  })\n}\n\nexport function listenClick(cb: (target: HyperView, action: string) => void): void {\n  listenBubblingEvent(\"click\", cb)\n}\n\nexport function listenDblClick(cb: (target: HyperView, action: string) => void): void {\n  listenBubblingEvent(\"dblclick\", cb)\n}\n\nexport function listenTopLevel(cb: (target: HyperView, action: string) => void): void {\n  document.addEventListener(\"hyp-load\", function (e: CustomEvent) {\n    let action = e.detail.onLoad\n    let target = e.detail.target\n    cb(target, action)\n  })\n\n  document.addEventListener(\"hyp-mouseenter\", function (e: CustomEvent) {\n    let action = e.detail.onMouseEnter\n    let target = e.detail.target\n    cb(target, action)\n  })\n\n  document.addEventListener(\"hyp-mouseleave\", function (e: CustomEvent) {\n    let action = e.detail.onMouseLeave\n    let target = e.detail.target\n    cb(target, action)\n  })\n}\n\nexport function listenLoad(node: HTMLElement): void {\n  // it doesn't really matter WHO runs this except that it should have target\n  node.querySelectorAll<HTMLElement>(\"[data-onload]\").forEach((load) => {\n    let delay = parseInt(load.dataset.delay || \"\") || 0\n    let onLoad = load.dataset.onload\n    // console.log(\"load start\", load.dataset.onLoad)\n\n    // load no longer exists!\n    // we should clear the timeout or back out if the dom is replaced in the interem\n    setTimeout(() => {\n      let target = nearestHyperViewTarget(load)\n      // console.log(\"load go\", load.dataset.onLoad)\n\n      if (load.dataset.onload != onLoad) {\n        // the onLoad no longer exists\n        return\n      }\n\n      const event = new CustomEvent(\"hyp-load\", { bubbles: true, detail: { target, onLoad } })\n      load.dispatchEvent(event)\n    }, delay)\n  })\n}\n\nexport function listenMouseEnter(node: HTMLElement): void {\n  node.querySelectorAll<HTMLElement>(\"[data-onmouseenter]\").forEach((node) => {\n    let onMouseEnter = node.dataset.onmouseenter\n\n    let target = nearestAnyTarget(node)\n\n    node.onmouseenter = () => {\n      const event = new CustomEvent(\"hyp-mouseenter\", {\n        bubbles: true,\n        detail: { target, onMouseEnter },\n      })\n      node.dispatchEvent(event)\n    }\n  })\n}\n\nexport function listenMouseLeave(node: HTMLElement): void {\n  node.querySelectorAll<HTMLElement>(\"[data-onmouseleave]\").forEach((node) => {\n    let onMouseLeave = node.dataset.onmouseleave\n\n    let target = nearestAnyTarget(node)\n\n    node.onmouseleave = () => {\n      const event = new CustomEvent(\"hyp-mouseleave\", {\n        bubbles: true,\n        detail: { target, onMouseLeave },\n      })\n      node.dispatchEvent(event)\n    }\n  })\n}\n\nexport function listenChange(cb: (target: HyperView, action: string, value: string) => void): void {\n  document.addEventListener(\"change\", function (e) {\n    if (!(e.target instanceof HTMLElement)) {\n      console.warn(\"listenChange received an event with non HTMLElment as EventTarget: %o\", e)\n      return\n    }\n    let el = e.target\n\n    let source = el.closest<HTMLInputElement>(\"[data-onchange]\")\n\n    if (!source) return\n    e.preventDefault()\n\n    if (source.value === null) {\n      console.error(\"Missing input value:\", source)\n      return\n    }\n\n    let target = nearestHyperViewTarget(source)\n    if (!target) {\n      console.error(\"Missing target: listenChange\")\n      return\n    }\n\n    if (!source.dataset.onchange) {\n      console.error(\"Missing onchange: \", source)\n      return\n    }\n\n    cb(target, source.dataset.onchange, source.value)\n  })\n}\n\ninterface LiveInputElement extends HTMLInputElement {\n  debouncedCallback?: Function\n}\n\nexport function listenInput(\n  startedTyping: (target: HyperView) => void,\n  cb: (target: HyperView, action: string, value: InputValue) => void,\n): void {\n  document.addEventListener(\"input\", function (e) {\n    if (!(e.target instanceof HTMLElement)) {\n      console.warn(\"listenInput received an event with non HTMLElment as EventTarget: %o\", e)\n      return\n    }\n    let el = e.target\n    const source = el.closest<LiveInputElement>(\"[data-oninput]\")\n\n    if (!source) return\n\n    let delay = parseInt(source.dataset.delay || \"\") || 250\n    if (delay < 250) {\n      console.warn(\"Input delay < 250 can result in poor performance.\")\n    }\n\n    e.preventDefault()\n\n    const target = nearestHyperViewTarget(source)\n    if (!target) {\n      console.error(\"Missing target: \", source)\n      return\n    }\n\n    // I want to CANCEL the active request as soon as we start typing\n    startedTyping(target)\n\n    if (!source.debouncedCallback) {\n      source.debouncedCallback = debounce(() => {\n        if (!source.dataset.oninput) {\n          console.error(\"Missing onInput: \", source)\n          return\n        }\n\n        cb(target, source.dataset.oninput, source.value)\n      }, delay)\n    }\n\n    source.debouncedCallback()\n  })\n}\n\nexport function listenFormSubmit(\n  cb: (target: HyperView, action: string, form: FormData) => void,\n): void {\n  document.addEventListener(\"submit\", function (e) {\n    if (!(e.target instanceof HTMLFormElement)) {\n      console.warn(\"listenFormSubmit received an event with non HTMLElment as EventTarget: %o\", e)\n      return\n    }\n    let form = e.target\n\n    if (!form.dataset.onsubmit) {\n      console.error(\"Missing onSubmit: \", form)\n      return\n    }\n\n    e.preventDefault()\n\n    let target = nearestHyperViewTarget(form)\n    const formData = new FormData(form)\n    if (!target) {\n      console.error(\"Missing target: \", target)\n      return\n    }\n    cb(target, form.dataset.onsubmit, formData)\n  })\n}\n\nfunction nearestTargetId(node: HTMLElement): string | undefined {\n  let targetData = node.closest<HTMLElement>(\"[data-target]\")\n  return targetData?.dataset.target || node.closest(\"[id]\")?.id\n}\n\nfunction nearestHyperViewTarget(node: HTMLElement): HyperView | undefined {\n  const target = nearestAnyTarget(node)\n\n  if (!isHyperView(target)) {\n    console.error(\"Non HyperView target: \", target)\n    return\n  }\n\n  return target\n}\n\nfunction nearestAnyTarget(node: HTMLElement): HTMLElement | undefined {\n  let targetId = nearestTargetId(node)\n  let target = targetId && document.getElementById(targetId)\n\n  if (!target) {\n    console.error(\"Cannot find target: \", targetId, node)\n    return\n  }\n\n  return target\n}\n","export function setQuery(query: string) {\n  if (query != currentQuery()) {\n    if (query != \"\") query = \"?\" + query\n    let url = location.pathname + query\n    // console.log(\"history.replaceState(\", url, \")\")\n    window.history.replaceState({}, \"\", url)\n  }\n}\n\nfunction currentQuery(): string {\n  const query = window.location.search\n  return query.startsWith(\"?\") ? query.substring(1) : query\n}\n","import { type ActionMessage } from \"./action\"\nimport { type Response, type Redirect, parseResponse } from \"./response\"\nimport { type Meta, parseMetas } from \"./message\"\n\n// Could be a redirect or response\nexport async function sendActionHttp(msg: ActionMessage): Promise<Response | Redirect> {\n  // console.log(\"HTTP sendAction\", msg.url.toString())\n  let url = window.location.href\n\n  let headers: any = {\n    Accept: \"text/html\",\n    \"Hyp-ViewId\": msg.viewId,\n    \"Hyp-RequestId\": msg.requestId,\n    \"Hyp-Action\": msg.action,\n    \"Hyp-State\": msg.state || \"()\",\n  }\n\n  console.log(\"sendActionHttp\", msg.form)\n\n  let res = await fetch(url, {\n    method: \"POST\",\n    headers: headers,\n    body: msg.form,\n    // we never want this to be redirected\n    redirect: \"manual\",\n  })\n\n  let body = await res.text()\n\n  // TODO: handle redirects. Check status code and do it\n  // if (!res.ok) {\n  //   throw new FetchError(msg.viewId, \"Invalid Status:\" + res.status, body)\n  // }\n\n  const { metas, rest } = splitResponse(body)\n  const response = parseResponse(metas, rest)\n  return response\n}\n\nexport function splitResponse(body: string): SplitResponse {\n  let lines = body.split(\"\\n\")\n  // drop the <script> start line\n  let metas = parseMetas(lines.slice(1))\n  let rest = lines.slice(2)\n  // drop the </script> end line and 2x whitespace\n  return { metas, rest }\n}\n\nexport type SplitResponse = {\n  metas: Meta[]\n  rest: string[]\n}\n\n// export function documentScriptMeta(doc: Document): Metadata {\n//   const meta = doc.querySelector<HTMLScriptElement>(\"script#hyp.metadata\")\n//   return parseMetadata(meta?.textContent || \"\")\n// }\n","import { patch, create } from \"omdomdom/lib/omdomdom.es.js\"\nimport { SocketConnection, type Update, type Redirect, type Trigger, type JSEvent } from \"./sockets\"\nimport {\n  listenChange,\n  listenClick,\n  listenDblClick,\n  listenFormSubmit,\n  listenLoad,\n  listenTopLevel,\n  listenInput,\n  listenKeydown,\n  listenKeyup,\n  listenMouseEnter,\n  listenMouseLeave,\n} from \"./events\"\nimport { actionMessage, newRequest, type ActionBody, type InputValue } from \"./action\"\nimport {\n  type ViewId,\n  type Metadata,\n  parseMetadata,\n  type RemoteEvent,\n  type EncodedAction,\n} from \"./message\"\nimport { setQuery } from \"./browser\"\nimport {\n  parseResponseDocument,\n  type LiveUpdate,\n  type Response,\n  type BaseResponse,\n  documentUpdate,\n} from \"./response\"\nimport { dispatchContent, enrichHyperViews, type HyperView, isHyperView } from \"./hyperview\"\nimport { sendActionHttp } from \"./http\"\n\ndeclare const __VERSION__: string\n\n// console.log(\"VERSION 2\", INIT_PAGE, INIT_STATE)\nconsole.log(\"Hyperbole \" + __VERSION__ + \"b\")\n\nlet rootStyles: HTMLStyleElement\nlet addedRulesIndex = new Set()\n\n// Run an action in a given HyperView\nasync function runAction(target: HyperView, action: string, body?: ActionBody) {\n  if (target.activeRequest && !target.activeRequest?.isCancelled) {\n    // Active Request!\n    if (target.concurrency == \"Drop\") {\n      console.warn(\"Drop action overlapping with active request\", target.activeRequest, action)\n      return\n    }\n  }\n\n  target._timeout = window.setTimeout(() => {\n    // add loading after 100ms, not right away\n    // if it runs shorter than that we probably don't want to show the user any loading feedback\n    target.classList.add(\"hyp-loading\")\n  }, 100)\n\n  let state = target.dataset.state\n\n  let req = newRequest()\n  let msg = actionMessage(target.id, action, state, req.requestId, body)\n\n  // Set the requestId\n  target.activeRequest = req\n\n  if (!msg.form) {\n    // If we have a form, send via HTTP instead of socket\n    // NOTE: this disables push update!\n    void sock.sendAction(msg)\n  } else {\n    let res = await sendActionHttp(msg)\n    console.log(\"RESPONSE\", res)\n\n    // TODO: redirect on http\n    // TODO: forward errors to view. Right now they throw!\n    switch (res.kind) {\n      case \"redirect\":\n        console.log(\"TODO HANDLE REDIRECT\")\n        break\n      case \"response\":\n        handleResponse(res)\n        break\n    }\n  }\n}\n\nfunction handleTrigger(trigger: Trigger) {\n  runTrigger(trigger.targetViewId, trigger.targetAction)\n}\n\nfunction handleEvent(ev: JSEvent) {\n  let target = document.getElementById(ev.viewId)\n  runRemoteEvent(ev.event, target)\n}\n\n// TODO: redirect concurrency\nfunction handleRedirect(red: Redirect) {\n  console.log(\"REDIRECT\", red)\n\n  // the other metdata doesn't apply, they are all specific to the page\n  applyCookies(red.meta.cookies ?? [])\n\n  window.location.href = red.url\n}\n\n// in-process update\nfunction handleResponse(res: Response) {\n  // console.log(\"Handle Response\", res)\n  let target = runUpdate(res.viewId, res)\n  if (!target) return\n\n  // clean up the request\n  delete target.activeRequest\n  clearTimeout(target._timeout)\n  target.classList.remove(\"hyp-loading\")\n}\n\nfunction handleUpdate(up: Update) {\n  if (up.meta.error) {\n    runUpdate(up.viewId, up)\n  } else if (!up.targetViewId) {\n    console.error(\"Missing Update targetViewId\", up)\n  } else {\n    runUpdate(up.targetViewId, up)\n  }\n}\n\nfunction runUpdate(targetViewId: ViewId, res: BaseResponse): HyperView | undefined {\n  // console.log(\"|UPDATE|\", res)\n\n  // let targetViewId = res.targetViewId || res.viewId\n  let target = document.getElementById(targetViewId)\n\n  if (!isHyperView(target)) {\n    console.error(\"Missing Update HyperView Target: \", targetViewId, res)\n    return\n  }\n\n  if (target.activeRequest?.requestId && res.requestId < target.activeRequest.requestId) {\n    // this should only happen on Replace, since other requests should be dropped\n    // but it's safe to assume we never want to apply an old requestId\n    console.warn(\n      \"Ignore Stale Action (\" +\n        res.requestId +\n        \") vs (\" +\n        target.activeRequest.requestId +\n        \"): \" +\n        res.action,\n    )\n    return target\n  } else if (target.activeRequest?.isCancelled) {\n    console.warn(\"Cancelled request\", target.activeRequest?.requestId)\n    delete target.activeRequest\n    return target\n  }\n\n  let update: LiveUpdate = documentUpdate(parseResponseDocument(res.body))\n\n  if (!update.content) {\n    console.error(\"Empty Response!\", res.body)\n    return target\n  }\n\n  // First, update the stylesheet\n  addCSS(update.css)\n\n  // Patch the node\n  const old: VNode = create(target)\n  let next: VNode = create(update.content)\n  let atts = next.attributes\n\n  if (!res.meta.error && atts[\"id\"] != target.id) {\n    console.error(\"Mismatched ViewId in update - \", atts[\"id\"], \" target:\", target.id)\n    return\n  }\n\n  let state = atts[\"data-state\"]\n  next.attributes = old.attributes\n\n  patch(next, old)\n\n  // Emit relevant events\n  let newTarget = document.getElementById(target.id)\n\n  if (!newTarget) {\n    console.warn(\"Target Missing: \", target.id)\n    return target\n  }\n\n  dispatchContent(newTarget)\n\n  // re-add state attribute\n  if (state === undefined || state == \"()\") delete newTarget.dataset.state\n  else newTarget.dataset.state = state\n\n  // execute the metadata, anything that doesn't interrupt the dom update\n  runMetadata(res.meta, newTarget)\n  applyCookies(res.meta.cookies ?? [])\n\n  // now way for these to bubble)\n  listenLoad(newTarget)\n  listenMouseEnter(newTarget)\n  listenMouseLeave(newTarget)\n  fixInputs(newTarget)\n  enrichHyperViews(newTarget, runAction)\n\n  return target\n}\n// catch (err) {\n//   console.error(\"Caught Error in HyperView (\" + target.id + \"):\\n\", err)\n//\n//   // Hyperbole catches handler errors, and the server controls what to display to the user on an error\n//   //  but if you manage to crash your parent server process somehow, the response may be empty\n//   target.innerHTML = err.body || \"<div style='background:red;color:white;padding:10px'>Hyperbole Internal Error</div>\"\n// }\n\nfunction applyCookies(cookies: string[]) {\n  cookies.forEach((cookie: string) => {\n    console.log(\"SetCookie: \", cookie)\n    document.cookie = cookie\n  })\n}\n\nfunction runMetadata(meta: Metadata, target: HTMLElement | null) {\n  if (meta.query != null) {\n    setQuery(meta.query)\n  }\n\n  if (meta.pageTitle != null) {\n    document.title = meta.pageTitle\n  }\n\n  meta.events?.forEach((remoteEvent) => {\n    runRemoteEvent(remoteEvent, target)\n  })\n\n  meta.actions?.forEach(([viewId, action]) => {\n    runTrigger(viewId, action)\n  })\n}\n\nfunction runRemoteEvent(remoteEvent: RemoteEvent, target: HTMLElement | null) {\n  setTimeout(() => {\n    let event = new CustomEvent(remoteEvent.name, { bubbles: true, detail: remoteEvent.detail })\n    let eventTarget = target || document\n    eventTarget.dispatchEvent(event)\n  }, 10)\n}\n\nfunction runTrigger(viewId: ViewId, action: EncodedAction) {\n  setTimeout(() => {\n    let view = window.Hyperbole?.hyperView(viewId)\n    if (view) {\n      void runAction(view, action, undefined)\n    }\n  }, 10)\n}\n\nfunction fixInputs(target: HTMLElement) {\n  let focused = target.querySelector<HTMLInputElement>(\"[autofocus]\")\n  if (focused?.focus) {\n    focused.focus()\n  }\n\n  target.querySelectorAll<HTMLInputElement>(\"input[value]\").forEach((input) => {\n    let val = input.getAttribute(\"value\")\n    if (val !== null) {\n      input.value = val\n    }\n  })\n\n  target.querySelectorAll<HTMLInputElement>(\"input[type=checkbox]\").forEach((checkbox) => {\n    let checked = checkbox.dataset.checked == \"True\"\n    checkbox.checked = checked\n  })\n}\n\nfunction addCSS(src: HTMLStyleElement | null) {\n  if (!src) return\n  const rules = src.sheet?.cssRules\n  if (!rules) return\n  for (let i = 0; i < rules.length; i++) {\n    const rule = rules.item(i)\n    if (rule && addedRulesIndex.has(rule.cssText) == false && rootStyles.sheet) {\n      rootStyles.sheet.insertRule(rule.cssText)\n      addedRulesIndex.add(rule.cssText)\n    }\n  }\n}\n\nfunction init() {\n  // metadata attached to initial page loads need to be executed\n  let meta = parseMetadata(document.getElementById(\"hyp.metadata\")?.innerText ?? \"\")\n  // runMetadataImmediate(meta)\n  runMetadata(meta, null)\n\n  const style = document.body.querySelector(\"style\")\n\n  if (style !== null) {\n    rootStyles = style\n  } else {\n    console.warn(\"rootStyles missing from page, creating...\")\n    rootStyles = document.createElement(\"style\")\n    rootStyles.type = \"text/css\"\n    document.body.appendChild(rootStyles)\n  }\n\n  listenTopLevel(async function (target: HyperView, action: string) {\n    void runAction(target, action, undefined)\n  })\n\n  listenLoad(document.body)\n  listenMouseEnter(document.body)\n  listenMouseLeave(document.body)\n  enrichHyperViews(document.body, runAction)\n\n  listenClick(async function (target: HyperView, action: string) {\n    // console.log(\"CLICK\", target.id, action)\n    void runAction(target, action, undefined)\n  })\n\n  listenDblClick(async function (target: HyperView, action: string) {\n    // console.log(\"DBLCLICK\", target.id, action)\n    void runAction(target, action, undefined)\n  })\n\n  listenKeydown(async function (target: HyperView, action: string) {\n    // console.log(\"KEYDOWN\", target.id, action)\n    void runAction(target, action, undefined)\n  })\n\n  listenKeyup(async function (target: HyperView, action: string) {\n    // console.log(\"KEYUP\", target.id, action)\n    void runAction(target, action)\n  })\n\n  listenFormSubmit(async function (target: HyperView, action: string, form: FormData) {\n    // console.log(\"FORM\", target.id, action, form)\n    void runAction(target, action, form)\n  })\n\n  listenChange(async function (target: HyperView, action: string, value: string) {\n    void runAction(target, action, value)\n  })\n\n  function onStartedTyping(target: HyperView) {\n    if (target.concurrency == \"Replace\") {\n      target.cancelActiveRequest()\n    }\n  }\n\n  listenInput(\n    onStartedTyping,\n    async function (target: HyperView, action: string, value: InputValue) {\n      void runAction(target, action, value)\n    },\n  )\n}\n\ndocument.addEventListener(\"DOMContentLoaded\", init)\n\nconst sock = new SocketConnection()\n// Should we connect to the socket or not?\nsock.connect()\nsock.addEventListener(\"update\", (ev: CustomEvent<Update>) => handleUpdate(ev.detail))\nsock.addEventListener(\"response\", (ev: CustomEvent<Response>) => handleResponse(ev.detail))\nsock.addEventListener(\"redirect\", (ev: CustomEvent<Redirect>) => handleRedirect(ev.detail))\nsock.addEventListener(\"trigger\", (ev: CustomEvent<Trigger>) => handleTrigger(ev.detail))\nsock.addEventListener(\"event\", (ev: CustomEvent<JSEvent>) => handleEvent(ev.detail))\n\ntype VNode = {\n  // One of three value types are used:\n  // - The tag name of the element\n  // - \"text\" if text node\n  // - \"comment\" if comment node\n  type: string\n\n  // An object whose key/value pairs are the attribute\n  // name and value, respectively\n  attributes: { [key: string]: string | undefined }\n\n  // Is set to `true` if a node is an `svg`, which tells\n  // Omdomdom to treat it, and its children, as such\n  isSVGContext: boolean\n\n  // The content of a \"text\" or \"comment\" node\n  content: string\n\n  // An array of virtual node children\n  children: Array<VNode>\n\n  // The real DOM node\n  node: Node\n}\n\ndeclare global {\n  interface Window {\n    Hyperbole?: HyperboleAPI\n  }\n  interface DocumentEventMap {\n    \"hyp-load\": CustomEvent\n    \"hyp-mouseenter\": CustomEvent\n    \"hyp-mouseleave\": CustomEvent\n  }\n}\n\nexport interface HyperboleAPI {\n  runAction(target: HTMLElement, action: string, body?: ActionBody): Promise<void>\n  action(con: string, ...params: any[]): string\n  hyperView(viewId: ViewId): HyperView | undefined\n  parseMetadata(input: string): Metadata\n  socket: SocketConnection\n}\n\nwindow.Hyperbole = {\n  runAction: runAction,\n  parseMetadata: parseMetadata,\n  action: function (con, ...params: any[]) {\n    return params.reduce((str, param) => str + \" \" + JSON.stringify(param), con)\n  },\n  hyperView: function (viewId) {\n    let element = document.getElementById(viewId)\n    if (!isHyperView(element)) {\n      console.error(\"Element id=\" + viewId + \" was not a HyperView\")\n      return\n    }\n    return element\n  },\n  socket: sock,\n}\n"],"x_google_ignoreList":[0,6],"mappings":"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"}
client/util/live-reload.js view
@@ -1,4 +1,4 @@-// This isn't magic. If you want custom behavior, copy and modify this however you like. +// This isn't magic. If you want custom behavior, copy and modify this however you like. // // As with any custom js, add to a single page via the `script` combinator //  page = do@@ -12,14 +12,14 @@ console.log("Live Reload enabled")  function showNotification(message) {-  const notification = document.createElement('div');+  const notification = document.createElement("div")   notification.classList.add("live-reload")-  notification.innerHTML = message;+  notification.innerHTML = message   jackIn(notification.style)-  notification.addEventListener('click', function() {+  notification.addEventListener("click", function () {     notification.remove()   })-  document.body.appendChild(notification);+  document.body.appendChild(notification) }  document.addEventListener("hyp-socket-disconnect", () => {@@ -32,17 +32,16 @@   }, 0) }) - // duplicate cyber style stuff here so the default live reload is fun function jackIn(style) {-  style.position = 'fixed';-  style.bottom = '15px';-  style.left = '15px';-  style.right = '15px';-  style.backgroundColor = 'rgba(160, 63, 56, 1.0)';-  style.color = '#fff';-  style.borderTop = 'solid #EC6458 4px';-  style.padding = '15px';-  style.zIndex = '1000';-  style.clipPath = 'polygon(0 0, 100% 0, 100% calc(100% - 16px), calc(100% - 16px) 100%, 0 100%)';+  style.position = "fixed"+  style.bottom = "15px"+  style.left = "15px"+  style.right = "15px"+  style.backgroundColor = "rgba(160, 63, 56, 1.0)"+  style.color = "#fff"+  style.borderTop = "solid #EC6458 4px"+  style.padding = "15px"+  style.zIndex = "1000"+  style.clipPath = "polygon(0 0, 100% 0, 100% calc(100% - 16px), calc(100% - 16px) 100%, 0 100%)" }
+ docs/Docgen.hs view
@@ -0,0 +1,278 @@+module Main where++import Data.Char (isAlpha, isSpace)+import Data.String.Conversions (cs)+import Data.Text (Text)+import Data.Text qualified as T+import Data.Text.IO qualified as T+import System.Directory+import System.Environment (getArgs)+import System.FilePath+++main :: IO ()+main = do+  args <- getArgs+  case args of+    [original, input, output] -> do+      src <- readSource input+      expanded <- expandFile src+      let linePragma = T.pack $ "{-# LINE 1 \"" ++ original ++ "\" #-}"+      let final = SourceCode [linePragma] <> expanded+      T.writeFile output $ T.unlines final.lines+    _ -> error "Usage (Hyperbole Internal Only): docgen src/MyModule.hs /tmp/input/MyModule.hs /build/output/Original.hs"+++-- test :: IO ()+-- test = do+--   src <- readSource "./src/Web/Hyperbole.hs"+--   SourceCode lns <- expandFile src+--   mapM_ print lns++-- expandSourcesTo :: FilePath -> IO ()+-- expandSourcesTo tmpDir = do+--   allFiles <- relativeSourceFiles "./src"+--   -- mapM_ (putStrLn . ("SOURCE " <>)) allFiles+--   mapM_ (expandAndCopyFileTo tmpDir) allFiles++-- copyExtraFilesTo :: FilePath -> IO ()+-- copyExtraFilesTo tmpDir = do+--   createDirectoryIfMissing True tmpDir+--   copyFile "./cabal.project" (tmpDir </> "cabal.project")+--   copyFile "./hyperbole.cabal" (tmpDir </> "hyperbole.cabal")+--   copyFile "./README.md" (tmpDir </> "README.md")+--   copyFile "./CHANGELOG.md" (tmpDir </> "CHANGELOG.md")+--   copyFile "./LICENSE" (tmpDir </> "LICENSE")+--   createDirectoryIfMissing True (tmpDir </> "client/dist")+--   copyFile "./client/dist/hyperbole.js" (tmpDir </> "client/dist/hyperbole.js")+--   copyFile "./client/dist/hyperbole.js.map" (tmpDir </> "client/dist/hyperbole.js.map")+--   createDirectoryIfMissing True (tmpDir </> "client/util")+--   copyFile "./client/util/live-reload.js" (tmpDir </> "client/util/live-reload.js")++-- expandAndCopyFileTo :: FilePath -> FilePath -> IO ()+-- expandAndCopyFileTo tmpDir pth = do+--   putStrLn $ "EXPANDING " <> pth+--   src <- readSource pth+--   expanded <- expandFile src+--   writeSource tmpDir pth expanded++readSource :: FilePath -> IO SourceCode+readSource pth = do+  inp <- T.readFile pth+  pure $ SourceCode $ T.lines inp+++writeSource :: FilePath -> FilePath -> SourceCode -> IO ()+writeSource tmpDir relPath src = do+  let pth = tmpDir </> cleanRelativeDir relPath+  -- putStrLn $ "WRITE " <> pth <> " " <> show (length src.lines)+  createDirectoryIfMissing True $ takeDirectory pth+  T.writeFile pth $ T.unlines src.lines+ where+  cleanRelativeDir =+    dropWhile (== '/') . dropWhile (== '.')+++-- relativeSourceFiles :: FilePath -> IO [FilePath]+-- relativeSourceFiles dir = do+--   contents <- tryDirectory dir+--   let folders = filter isFolder contents+--   let files = filter isSourceFile contents+--+--   files' <- mapM (relativeSourceFiles . addDir) folders+--+--   pure $ fmap addDir files <> mconcat files'+--  where+--   isSourceFile pth = takeExtension pth == ".hs"+--   isFolder pth = takeExtension pth == ""+--   addDir = (dir </>)+--   tryDirectory pth = do+--     res <- try $ listDirectory pth+--     case res of+--       Left (_ :: SomeException) -> do+--         putStrLn $ "SKIPPED" <> pth+--         pure []+--       Right files -> pure files++data Macro+  = Embed+  { moduleName :: ModuleName+  , definition :: TopLevelDefinition+  }+  deriving (Eq)+newtype SourceCode = SourceCode {lines :: [Text]}+  deriving newtype (Monoid, Semigroup)+instance Show Macro where+  -- show (Example p) = "Example " <> show p+  show (Embed mn def) = "Embed " <> show mn <> " " <> show def+++newtype ModuleName = ModuleName Text+  deriving newtype (Eq, Show)+++newtype TopLevelDefinition = TopLevelDefinition Text+  deriving newtype (Show, Eq)+++expandFile :: SourceCode -> IO SourceCode+expandFile (SourceCode lns) =+  SourceCode . mconcat <$> mapM expandLine lns+++-- > EMBED Example/Docs/BasicPage.hs page+expandLine :: Text -> IO [Text]+expandLine line = do+  case parseMacro line of+    Nothing -> do+      pure [line]+    Just (pre, Embed src def) -> do+      expandEmbed src pre def+ where+  -- Just (pre, Example src) -> do+  --   expandExample src pre++  parseMacro :: Text -> Maybe (Text, Macro)+  parseMacro inp = do+    parseEmbed inp -- <|> parseExample inp++  -- parseExample l = do+  --   case T.splitOn "#EXAMPLE " l of+  --     [prefix, src] -> do+  --       pure (prefix, Example $ path src)+  --     _ -> Nothing++  parseEmbed l = do+    case T.splitOn "#EMBED " l of+      [prefix, info] -> do+        (mn, definition) <- splitSrcDef $ T.dropWhile (== ' ') info+        pure (prefix, Embed mn definition)+      _ -> Nothing++  splitSrcDef inp =+    let (mn, def) = T.breakOn " " inp+     in pure (ModuleName mn, TopLevelDefinition $ T.drop 1 def)+++-- look it up as a URI...++-- * #EXAMPLE /simple+++-- expandExample :: Path -> Text -> IO [Text]+-- expandExample p prefix = do+--   let pre = if T.null prefix then "▶️ " else prefix+--   r <- appRoute+--   pure [pre <> "[" <> routeTitle r <> "](" <> uriToText (exampleBaseURI ./. p) <> ")"]+--  where+--   appRoute :: IO AppRoute+--   appRoute = do+--     case matchRoute @AppRoute p of+--       Nothing -> fail $ "Could not find example: " <> cs (pathToText False p)+--       Just r -> pure r++-- exampleBaseURI :: URI+-- exampleBaseURI = [uri|https://hyperbole.live|]++modulePath :: ModuleName -> FilePath+modulePath (ModuleName mn) = cs $ T.replace "." "/" mn <> ".hs"+++expandEmbed :: ModuleName -> Text -> TopLevelDefinition -> IO [Text]+expandEmbed mn pfx def = do+  let src = modulePath mn+  -- putStrLn $ "  embed: " <> src+  source <- T.readFile $ "./demo/" <> src+  expanded <- requireTopLevel def (SourceCode $ T.lines source)+  pure $ fmap markupLine expanded+ where+  requireTopLevel :: TopLevelDefinition -> SourceCode -> IO [Text]+  requireTopLevel tld sc =+    case findTopLevel tld sc of+      [] -> fail $ "Could not find: " <> show (Embed mn def) <> " " <> show def+      lns -> pure lns++  -- addPrefix line = embed.prefix <> line+  markupLine :: Text -> Text+  markupLine line =+    case pfx of+      "" -> markupLineAt line+      _ -> markupLinePrefix line+  markupLineAt =+    T.replace "\"" "\\\"" . highlightTermsLine+  markupLinePrefix line =+    pfx <> line+++highlightTermsLine :: Text -> Text+highlightTermsLine ln = mconcat $ fmap highlightWord $ T.groupBy isSameTerm ln+ where+  isSameTerm :: Char -> Char -> Bool+  isSameTerm c1 c2 =+    (isAlpha c1 && isAlpha c2)+      || (isSpace c1 && isSpace c2)++  highlightWord :: Text -> Text+  highlightWord w =+    if w `elem` terms+      then "'" <> w <> "'"+      else w++  terms :: [Text]+  terms =+    [ "HyperView"+    , "View"+    , "Action"+    , "update"+    , "hyper"+    , "Page"+    , "liveApp"+    , "quickStartDocument"+    , "runPage"+    , "run"+    , "ViewId"+    , "viewId"+    , "ViewAction"+    , "Eff"+    , "button"+    , "el"+    , "el_"+    , "Hyperbole"+    , "Route"+    , "routeRequest"+    , "route"+    , "layout"+    , "Response"+    , "ToParam"+    , "FromParam"+    , "Session"+    , "FromQuery"+    , "ToQuery"+    , "lookupParam"+    , "setParam"+    , "DefaultParam"+    , "Client"+    ]+++-- returns lines of a top-level definition+findTopLevel :: TopLevelDefinition -> SourceCode -> [Text]+findTopLevel (TopLevelDefinition definition) source =+  let rest = dropWhile (not . isTopLevel) source.lines+   in dropWhileEnd isEmpty $ takeWhile isCurrentDefinition rest+ where+  isTopLevel = T.isPrefixOf definition+  isEmpty = T.null+  -- isBlankLine line = T.null $ T.strip line+  isCurrentDefinition line =+    isTopLevel line || not (isFullyOutdented line)+  dropWhileEnd p as =+    reverse $ dropWhile p $ reverse as+++isFullyOutdented :: Text -> Bool+isFullyOutdented line =+  case cs (T.take 1 line) of+    "" -> False+    [c] -> not $ isSpace c+    _ -> False
hyperbole.cabal view
@@ -1,11 +1,11 @@ cabal-version: 2.2 --- This file has been generated from package.yaml by hpack version 0.37.0.+-- This file has been generated from package.yaml by hpack version 0.39.5. -- -- see: https://github.com/sol/hpack  name:           hyperbole-version:        0.6.1+version:        0.7.0 synopsis:       Interactive HTML apps using type-safe serverside Haskell description:    Interactive HTML applications with type-safe serverside Haskell. Inspired by HTMX, Elm, and Phoenix LiveView. category:       Web, Network@@ -17,8 +17,10 @@ license-file:   LICENSE build-type:     Simple tested-with:-    GHC == 9.8.2-  , GHC == 9.6.6+    GHC == 9.12.4+  , GHC == 9.10.3+  , GHC == 9.8.4+  , GHC == 9.6.7 extra-source-files:     client/dist/hyperbole.js     client/dist/hyperbole.js.map@@ -35,17 +37,15 @@   exposed-modules:       Web.Hyperbole       Web.Hyperbole.Application+      Web.Hyperbole.Data.Argument       Web.Hyperbole.Data.Cookie       Web.Hyperbole.Data.Encoded-      Web.Hyperbole.Data.JSON-      Web.Hyperbole.Data.Param       Web.Hyperbole.Data.QueryData       Web.Hyperbole.Data.URI       Web.Hyperbole.Document       Web.Hyperbole.Effect.Client       Web.Hyperbole.Effect.GenRandom       Web.Hyperbole.Effect.Hyperbole-      Web.Hyperbole.Effect.OAuth2       Web.Hyperbole.Effect.Query       Web.Hyperbole.Effect.Request       Web.Hyperbole.Effect.Response@@ -63,6 +63,7 @@       Web.Hyperbole.Server.Message       Web.Hyperbole.Server.Options       Web.Hyperbole.Server.Socket+      Web.Hyperbole.Server.Uploads       Web.Hyperbole.Server.Wai       Web.Hyperbole.TypeList       Web.Hyperbole.Types.Client@@ -92,9 +93,61 @@       DataKinds       DerivingStrategies       DeriveAnyClass+  ghc-options: -Wall -fdefer-typed-holes -F -pgmF=docgen+  build-tool-depends:+      hyperbole:docgen+  build-depends:+      aeson >=2.1.2.1 && <2.4+    , atomic-css ==0.2.*+    , attoparsec ==0.14.*+    , attoparsec-aeson >=2.1 && <2.3+    , base >=4.16 && <5+    , bytestring >=0.11 && <0.13+    , casing >=0.1.2 && <0.2+    , containers >=0.6 && <1+    , cookie >=0.4 && <0.6+    , data-default ==0.8.*+    , effectful >=2.4 && <3+    , file-embed >=0.0.10 && <0.1+    , filepath >=1.4 && <2+    , http-client ==0.7.*+    , http-client-tls >=0.3 && <0.5+    , http-types ==0.12.*+    , network >=3.1 && <4+    , network-uri >=2.6.4.1 && <2.7+    , random >=1.2 && <2+    , resourcet >=1.2 && <2+    , string-conversions ==0.4.*+    , string-interpolate ==0.3.*+    , text >=1.2 && <3+    , time >=1.12 && <2+    , wai >=3.2 && <4+    , wai-extra >=3.1.10 && <3.2+    , wai-websockets >=3.0 && <4+    , warp >=3.3 && <4+    , websockets >=0.12 && <0.14+  default-language: GHC2021++executable docgen+  main-is: Docgen.hs+  other-modules:+      Paths_hyperbole+  autogen-modules:+      Paths_hyperbole+  hs-source-dirs:+      docs+  default-extensions:+      OverloadedStrings+      OverloadedRecordDot+      DuplicateRecordFields+      NoFieldSelectors+      TypeFamilies+      DataKinds+      DerivingStrategies+      DeriveAnyClass   ghc-options: -Wall -fdefer-typed-holes   build-depends:-      aeson >=2.1.2.1 && <2.3+      aeson >=2.1.2.1 && <2.4     , atomic-css ==0.2.*     , attoparsec ==0.14.*     , attoparsec-aeson >=2.1 && <2.3@@ -104,21 +157,23 @@     , containers >=0.6 && <1     , cookie >=0.4 && <0.6     , data-default ==0.8.*+    , directory >=1.2 && <1.4     , effectful >=2.4 && <3     , file-embed >=0.0.10 && <0.1     , filepath >=1.4 && <2-    , http-api-data >=0.6 && <0.8     , http-client ==0.7.*-    , http-client-tls ==0.3.*+    , http-client-tls >=0.3 && <0.5     , http-types ==0.12.*     , network >=3.1 && <4     , network-uri >=2.6.4.1 && <2.7     , random >=1.2 && <2+    , resourcet >=1.2 && <2     , string-conversions ==0.4.*     , string-interpolate ==0.3.*     , text >=1.2 && <3     , time >=1.12 && <2     , wai >=3.2 && <4+    , wai-extra >=3.1.10 && <3.2     , wai-websockets >=3.0 && <4     , warp >=3.3 && <4     , websockets >=0.12 && <0.14@@ -128,9 +183,9 @@   type: exitcode-stdio-1.0   main-is: Spec.hs   other-modules:+      Test.ArgumentSpec       Test.EncodedSpec       Test.FormSpec-      Test.ParamSpec       Test.QuerySpec       Test.RouteSpec       Test.SessionSpec@@ -156,7 +211,7 @@   build-tool-depends:       skeletest:skeletest-preprocessor   build-depends:-      aeson >=2.1.2.1 && <2.3+      aeson >=2.1.2.1 && <2.4     , atomic-css ==0.2.*     , attoparsec ==0.14.*     , attoparsec-aeson >=2.1 && <2.3@@ -169,20 +224,21 @@     , effectful >=2.4 && <3     , file-embed >=0.0.10 && <0.1     , filepath >=1.4 && <2-    , http-api-data >=0.6 && <0.8     , http-client ==0.7.*-    , http-client-tls ==0.3.*+    , http-client-tls >=0.3 && <0.5     , http-types ==0.12.*     , hyperbole     , network >=3.1 && <4     , network-uri >=2.6.4.1 && <2.7     , random >=1.2 && <2+    , resourcet >=1.2 && <2     , skeletest     , string-conversions ==0.4.*     , string-interpolate ==0.3.*     , text >=1.2 && <3     , time >=1.12 && <2     , wai >=3.2 && <4+    , wai-extra >=3.1.10 && <3.2     , wai-websockets >=3.0 && <4     , warp >=3.3 && <4     , websockets >=0.12 && <0.14
src/Web/Hyperbole.hs view
@@ -39,6 +39,8 @@     -- ** Request #request#   , request   , Request (..)+  , Form (..)+  , UploadedFile (..)      -- ** Response #response#   , respondError@@ -90,6 +92,7 @@   , Option      -- * Events+  , inputValue   , onClick   , onDblClick   , onMouseEnter@@ -100,11 +103,15 @@   , onKeyDown   , onKeyUp   , Key (..)+  , InputValue (..)      -- * Type-Safe Forms #forms#     -- $forms   , FromForm (..)   , FromFormF (..)+  , lookupField+  , parseField+  , FromField (..)   , formData   , GenFields (..)   , fieldNames@@ -125,6 +132,7 @@   , select   , checked   , textarea+  , fileInput   , submit   , View.placeholder   , InputType (..)@@ -137,8 +145,6 @@      -- * Query Param Encoding #query-param#   , QueryData-  , ToParam (..)-  , FromParam (..)   , ToEncoded   , FromEncoded @@ -183,13 +189,12 @@ import Web.Atomic.Types () import Web.Hyperbole.Application import Web.Hyperbole.Data.Encoded (FromEncoded, ToEncoded)-import Web.Hyperbole.Data.Param import Web.Hyperbole.Data.QueryData import Web.Hyperbole.Document import Web.Hyperbole.Effect.Client import Web.Hyperbole.Effect.Hyperbole import Web.Hyperbole.Effect.Query-import Web.Hyperbole.Effect.Request+import Web.Hyperbole.Effect.Request (inputValue) import Web.Hyperbole.Effect.Response import Web.Hyperbole.Effect.Session import Web.Hyperbole.HyperView@@ -207,5 +212,3 @@  Please visit https://hyperbole.live for documentation and examples -}---- TODO: NSO link
src/Web/Hyperbole/Application.hs view
@@ -6,6 +6,7 @@   , liveAppWith   , ServerOptions (..)   , defaultErrorMessage+  , defaultParseRequestBodyOptions   , defaultError   , socketApp   , quickStartDocument@@ -25,12 +26,12 @@ import Network.WebSockets qualified as WS import Web.Hyperbole.Document import Web.Hyperbole.Effect.Hyperbole-import Web.Hyperbole.Effect.Request (reqPath) import Web.Hyperbole.Effect.Response (notFound) import Web.Hyperbole.Route import Web.Hyperbole.Server.Options import Web.Hyperbole.Server.Socket (RunningActions, handleRequestSocket) import Web.Hyperbole.Server.Wai (handleRequestWai)+import Web.Hyperbole.Types.Request import Web.Hyperbole.Types.Response  @@ -44,6 +45,7 @@     ServerOptions       { toDocument = doc       , serverError = defaultError+      , parseRequestBody = defaultParseRequestBodyOptions       }  @@ -103,5 +105,5 @@ -} routeRequest :: (Hyperbole :> es, Route route) => (route -> Eff es Response) -> Eff es Response routeRequest actions = do-  pth <- reqPath-  maybe notFound actions $ matchRoute pth+  r <- request+  maybe notFound actions $ matchRoute r.path
+ src/Web/Hyperbole/Data/Argument.hs view
@@ -0,0 +1,129 @@+{-# LANGUAGE BlockArguments #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE OverloadedLists #-}++module Web.Hyperbole.Data.Argument where++import Control.Applicative ((<|>))+import Data.Aeson (FromJSON (..), ToJSON (..), Value (..))+import Data.Aeson qualified as A+import Data.Aeson.KeyMap (KeyMap, (!?))+import Data.Aeson.Parser (json)+import Data.Attoparsec.ByteString qualified as AB+import Data.Attoparsec.ByteString qualified as Atto+import Data.Attoparsec.ByteString.Char8 (sepBy)+import Data.Attoparsec.ByteString.Char8 qualified as AC+import Data.Bifunctor (first)+import Data.Char (isAlphaNum, isUpper)+import Data.Maybe (fromMaybe)+import Data.String.Conversions (cs)+import Data.Text (Text)+import Data.Text qualified as T+import GHC.Exts (IsList (..))+import GHC.Generics+++data Argument+  = JSON Value+  deriving (Show, Eq, Ord, Generic)+++-------------------------------------------------------------------------------+-- ARGUMENT ENCODING+-------------------------------------------------------------------------------++toArgument :: (ToJSON a) => a -> Argument+toArgument = JSON . toJSON+++parseArgument :: forall a. (FromJSON a) => Argument -> Either String a+parseArgument (JSON v) = do+  case A.fromJSON v of+    A.Success a -> pure a+    A.Error e -> Left e+++-- | Parses both json and our custom constructor format+argumentParser :: Atto.Parser Argument+argumentParser =+  JSON <$> (json <|> constructor <|> innerProduct)+ where+  innerProduct = do+    _ <- AC.char '('+    tag <- AC.takeWhile1 isAlphaNum+    contents :: KeyMap Value <- innerContents <|> pure []+    _ <- AC.char ')'+    pure $ Object $ [("tag", String $ cs tag)] <> contents++  innerContents = do+    _ <- AC.char ' '+    args <- json `sepBy` AC.space+    pure $ case args of+      [] -> []+      [a] -> [("contents", a)]+      as -> [("contents", Array $ fromList as)]++  constructor = do+    s <- AC.takeWhile1 isAlphaNum+    pure $ String (cs s)+++-- decode a single argument+decodeToArgument :: Text -> Either String Argument+decodeToArgument inp =+  first (\e -> "decodeArgument: " <> cs inp <> " failed with error: " <> e) $ AB.parseOnly argumentParser (cs inp)+++decodeArgument :: (FromJSON a) => Text -> Either String a+decodeArgument inp = do+  decodeToArgument inp >>= parseArgument+++encodeArgument :: (ToJSON a) => a -> Text+encodeArgument a = encodeFromArgument $ toArgument a+++-- | JSON Encode argument, but alter it slightly to use raw strings for constructors without parameters, and switch to two-element sum encoding+encodeFromArgument :: Argument -> Text+encodeFromArgument (JSON v) = encodeJSON v+++-- | Encodes as JSON for simple values, but forces constructors into our custom show-like format+encodeJSON :: Value -> Text+encodeJSON = \case+  (String s) ->+    if isConstructorName s+      then s+      else encodeValue $ String s+  (Object km) ->+    simplifySumEncoding $ Object km+  v -> encodeValue v+ where+  encodeValue :: Value -> Text+  encodeValue = cs . A.encode++  isConstructorName :: Text -> Bool+  isConstructorName "" = False+  isConstructorName t =+    isUpper (T.head t) && T.all isAlphaNum t++  simplifySumEncoding :: Value -> Text+  simplifySumEncoding (Object o) = fromMaybe (encodeValue $ Object o) $ do+    innerProduct o <|> simpleTag o+  simplifySumEncoding v = encodeValue v++  innerProduct :: KeyMap Value -> Maybe Text+  innerProduct o = do+    String t <- o !? "tag"+    c <- o !? "contents"+    let contents = case c of+          Array a -> T.intercalate " " $ toList $ fmap encodeValue a+          other -> encodeValue other+    pure $ "(" <> t <> " " <> contents <> ")"++  simpleTag :: KeyMap Value -> Maybe Text+  simpleTag o = do+    t <- o !? "tag"+    case t of+      String s -> pure $ "(" <> s <> ")"+      v -> pure $ encodeValue v
src/Web/Hyperbole/Data/Cookie.hs view
@@ -78,4 +78,4 @@ parseValue :: ByteString -> ByteString -> Either String Cookie parseValue k val = do   let cval = CookieValue $ cs $ urlDecode True val-  pure $ Cookie (cs k) Nothing (Just $ cval) True+  pure $ Cookie (cs k) Nothing (Just cval) True
src/Web/Hyperbole/Data/Encoded.hs view
@@ -1,14 +1,14 @@+{-# LANGUAGE BlockArguments #-} {-# LANGUAGE DefaultSignatures #-}-{-# LANGUAGE LambdaCase #-} {-# LANGUAGE OverloadedLists #-}+{-# LANGUAGE UndecidableInstances #-}  module Web.Hyperbole.Data.Encoded where  import Data.Aeson (FromJSON (..), ToJSON (..), Value (..)) import Data.Aeson qualified as A import Data.Attoparsec.ByteString qualified as AB-import Data.Attoparsec.ByteString qualified as Atto-import Data.Attoparsec.ByteString.Char8 (isSpace, sepBy, takeWhile1)+import Data.Attoparsec.ByteString.Char8 (sepBy) import Data.Attoparsec.ByteString.Char8 qualified as AC import Data.Bifunctor (first) import Data.String (IsString)@@ -16,7 +16,7 @@ import Data.Text (Text) import Data.Text qualified as T import GHC.Generics-import Web.Hyperbole.Data.Param+import Web.Hyperbole.Data.Argument   newtype ConName = ConName {text :: Text}@@ -28,12 +28,13 @@   mempty = ConName ""  -{- | Pretty Human Readable top-levelencoding for ViewAction and ViewId+{- | Human Readable top-level encoding for ViewAction and ViewId For simple Sum and Product types it is equivalent to the Show/Read instance  MyConstructor 1 2 3+OtherConstructor "hello" 2 -}-data Encoded = Encoded ConName [ParamValue]+data Encoded = Encoded ConName [Argument]   deriving (Show, Eq, Ord)  @@ -69,7 +70,7 @@ -- | Basic Encoding encodedToText :: Encoded -> Text encodedToText (Encoded con values) =-  T.intercalate " " (con.text : fmap encodeParam values)+  T.intercalate " " (con.text : fmap encodeFromArgument values)   encodedParseText :: Text -> Either String Encoded@@ -80,7 +81,7 @@   encodedParser = do     con <- AC.takeTill AC.isSpace     AC.skipSpace-    ps <- paramParser `sepBy` AC.char ' '+    ps <- argumentParser `sepBy` AC.char ' '     pure $ Encoded (ConName (cs con)) ps  @@ -111,12 +112,12 @@   toEncoded = id instance ToEncoded () where   toEncoded _ = mempty-instance ToEncoded ParamValue where-  toEncoded p = Encoded mempty [toParam p]+instance ToEncoded Argument where+  toEncoded a = Encoded mempty [a] instance ToEncoded Int where-  toEncoded = toEncoded . toParam+  toEncoded n = toEncoded $ JSON (Number $ fromIntegral n) instance ToEncoded Text where-  toEncoded = toEncoded . toParam+  toEncoded t = toEncoded $ JSON (String t)   -- | Custom Encoding for embedding into web documents. Noteably used for 'ViewId' and 'ViewAction'@@ -130,15 +131,23 @@   parseEncoded = pure instance FromEncoded () where   parseEncoded _ = pure ()-instance FromEncoded ParamValue where-  parseEncoded (Encoded _ ps) = do-    case ps of-      [p] -> parseParam p-      _ -> Left $ "Expected single param value [param] but got: " <> show ps+instance FromEncoded Argument where+  parseEncoded (Encoded _ as) = do+    case as of+      [a] -> pure a+      _ -> Left $ "Expected single argument value [arg] but got: " <> show as instance FromEncoded Int where-  parseEncoded enc = parseEncoded enc >>= parseParam+  parseEncoded enc = do+    arg <- parseEncoded @Argument enc+    case arg of+      JSON (Number a) -> pure $ round a+      other -> Left $ "Expected Int but got " <> show other instance FromEncoded Text where-  parseEncoded enc = parseEncoded enc >>= parseParam+  parseEncoded enc = do+    arg <- parseEncoded @Argument enc+    case arg of+      JSON (String t) -> pure t+      other -> Left $ "Expected Text but got " <> show other   fromResult :: A.Result a -> Either String a@@ -147,91 +156,6 @@   ---------------------------------------------------------------------------------- PARAM ENCODING----------------------------------------------------------------------------------- Params need to be sanitized and escaped, because we want to use spaces to separate our params--- Data.Param by default does not sanitize spaces--paramParser :: Atto.Parser ParamValue-paramParser = do-  t <- takeWhile1 (not . isSpace)-  pure $ decodeParam $ cs t---decodeParam :: Text -> ParamValue-decodeParam = \case-  "|" -> ParamValue ""-  t -> ParamValue $ desanitizeParamText t----- Param encoding scheme:---   Wire format must not contain bare spaces (field separator) or real newlines.---   We use backslash as the escape character:---     '\'  → "\\"    (escape backslash itself, so it cannot be confused with an escape prefix)---     '\n' → "\n"    (literal backslash + 'n', for real newline characters)---     '_'  → "\_"    (escape underscore, since bare underscore encodes space)---     ' '  → "_"     (encode space as underscore)---   Decoding is the single-pass reverse of the above.------ The critical invariant: backslash is escaped FIRST on encode and unescaped--- LAST on decode.  This ensures that JSON escape sequences (e.g. the two chars--- '\' 'n' inside "[\"\n\"]") are treated as an escaped backslash followed by--- a plain 'n', not as the param newline escape.--- See: https://github.com/seanhess/hyperbole/issues/187--desanitizeParamText :: Text -> Text-desanitizeParamText = go- where-  go t = case T.uncons t of-    Nothing -> ""-    Just ('\\', rest) -> case T.uncons rest of-      Just ('\\', rest') -> T.cons '\\' (go rest')   -- \\ → \-      Just ('n', rest')  -> T.cons '\n' (go rest')   -- \n → newline-      Just ('_', rest')  -> T.cons '_' (go rest')    -- \_ → _-      _                  -> T.cons '\\' (go rest)    -- bare backslash (shouldn't occur)-    Just ('_', rest) -> T.cons ' ' (go rest)         -- _ → space-    Just (c, rest)   -> T.cons c (go rest)            -- other chars verbatim-----   | T.isSuffixOf "\\" seg = T.dropEnd 1 seg <> "_" <> txt---   | otherwise = seg <> " " <> txt---- foldr join "" $--- where------ join "" "" = " "--- join "" " " = " "--- join seg "" = seg--- join seg txt---   | T.isSuffixOf "\\" seg = T.dropEnd 1 seg <> "_" <> txt---   | otherwise = seg <> " " <> txt--encodeParam :: ParamValue -> Text-encodeParam (ParamValue t) =-  case t of-    "" -> "|"-    _ -> sanitizeParamText t- where-  -- Encode a param value for the wire format.-  -- Backslash MUST be escaped first (before newline), otherwise a literal-  -- backslash followed by 'n' in the input (e.g. from JSON encoding) would-  -- be indistinguishable from the newline escape on the wire.-  -- See: https://github.com/seanhess/hyperbole/issues/187-  sanitizeParamText :: Text -> Text-  sanitizeParamText =-    T.replace " " "_" . T.replace "_" "\\_" . T.replace "\n" "\\n" . T.replace "\\" "\\\\"----- decodeParamValue :: (FromParam a) => Text -> Either String a--- decodeParamValue = parseParam . decodeParam---- decodeParam :: Text -> ParamValue--- decodeParam inp = do---   case A.eitherDecode (cs inp) of---     Left _ -> paramFromText inp---     Right v -> ParamValue inp v--------------------------------------------------------------------------------- -- GENERICS ------------------------------------------------------------------------------- @@ -252,7 +176,6 @@   instance GToEncoded U1 where-  -- WARNING: not sure if this will work   gToEncoded U1 = mempty  @@ -270,14 +193,16 @@   gToEncoded (M1 f) = gToEncoded f  -instance (ToParam a) => GToEncoded (K1 R a) where-  gToEncoded (K1 a) = Encoded mempty [toParam a]+instance (ToJSON a) => GToEncoded (K1 R a) where+  gToEncoded (K1 a) = do+    let JSON val = toArgument a+    Encoded mempty [JSON val]   -- GFromEncoded: Generic ViewAction Decoding  class GFromEncoded f where-  gParseEncoded :: Encoded -> Either String (f p, [ParamValue])+  gParseEncoded :: Encoded -> Either String (f p, [Argument])   instance (GFromEncoded f, GFromEncoded g) => GFromEncoded (f :+: g) where@@ -287,7 +212,7 @@     case (el, er) of       (Right (l, lvals), _) -> pure (L1 l, lvals)       (_, Right (r, rvals)) -> pure (R1 r, rvals)-      (Left _, Left _) ->+      (Left _e1, Left _e2) ->         Left $ "No matching sum constructor: " <> cs con.text <> " " <> cs (show vals)  @@ -322,11 +247,16 @@     pure (M1 a, rest)  -instance (FromParam a) => GFromEncoded (K1 R a) where+-- how can we *sometimes* parse it as user input?+-- we can branch here based on something the client sends?+-- wrap it in user input instead?+-- newtype Input a = Input a+-- then I can overload it here.+instance (FromJSON a) => GFromEncoded (K1 R a) where   gParseEncoded (Encoded con vals) = do     case vals of       (param : rest) -> do-        case parseParam param of+        case parseArgument param of           -- consume one param           Right a -> pure (K1 a, rest)           Left e -> Left (cs e)
− src/Web/Hyperbole/Data/JSON.hs
@@ -1,21 +0,0 @@-module Web.Hyperbole.Data.JSON (JSON (..), ToJSON, FromJSON) where--import Data.Aeson as A-import Data.String.Conversions (cs)-import Web.Hyperbole.Data.Encoded-import Web.Hyperbole.Data.Param----- JSON Encoded Data ---------------------------------------- | This type always encodes data via JSON-newtype JSON a = JSON a---instance (ToJSON a) => ToEncoded (JSON a) where-  toEncoded (JSON a) = Encoded "" [jsonParam a]-instance (FromJSON a) => FromEncoded (JSON a) where-  parseEncoded (Encoded _ [ParamValue t]) = do-    JSON <$> A.eitherDecode (cs t)-  parseEncoded (Encoded _ prms) = do-    Left $ "Could not parse JSON Encoded, expected one param: " <> show prms
− src/Web/Hyperbole/Data/Param.hs
@@ -1,287 +0,0 @@-{-# LANGUAGE DefaultSignatures #-}--module Web.Hyperbole.Data.Param where--import Data.Aeson (FromJSON, GFromJSON, GToJSON, Options (..), SumEncoding (..), ToJSON, Value (..), Zero, defaultOptions, genericParseJSON, genericToJSON)-import Data.Aeson qualified as A-import Data.Aeson.Types qualified as A-import Data.Bifunctor (first)-import Data.String (IsString (..))-import Data.String.Conversions (cs)-import Data.Text (Text)-import Data.Time.Clock (UTCTime)-import Data.Word-import GHC.Exts (IsList (..))-import GHC.Generics-import Text.Read (readMaybe)-import Web.HttpApiData (FromHttpApiData, ToHttpApiData)-import Web.HttpApiData qualified as HttpApiData-import Web.Hyperbole.Data.URI (URI (..), parseURIReference, uriToText)---newtype Param = Param {text :: Text}-  deriving newtype (Show, Eq, Ord, IsString)----- | Encode arbitrarily complex data into url form encoded data-newtype ParamValue = ParamValue {value :: Text}-  deriving newtype (Ord, Eq)-  deriving (Show, Generic)---instance IsString ParamValue where-  fromString s = ParamValue (cs s)---{- | 'session's, 'form's, and 'query's all encode data as query strings. ToParam and FromParam control how a datatype is encoded to a parameter.- --This is equivalent to Web.HttpApiData, which is missing some instances and has some strange defaults--@-#EMBED Example.Docs.Sessions data AppColor-@--}-class ToParam a where-  toParam :: a -> ParamValue-  default toParam :: (Generic a, GToJSON Zero (Rep a)) => a -> ParamValue-  toParam = genericToParam---instance ToParam ParamValue where-  toParam = id-instance ToParam Int where-  toParam = jsonParam-instance ToParam Integer where-  toParam = jsonParam-instance ToParam Text where-  toParam = toQueryParam-instance {-# OVERLAPS #-} ToParam String where-  toParam = toQueryParam-instance ToParam Float where-  toParam = jsonParam-instance ToParam Double where-  toParam = jsonParam-instance ToParam Word where-  toParam = jsonParam-instance ToParam Word8 where-  toParam = jsonParam-instance ToParam Word16 where-  toParam = jsonParam-instance ToParam Word32 where-  toParam = jsonParam-instance ToParam Word64 where-  toParam = jsonParam-instance ToParam Bool where-  toParam = jsonParam-instance ToParam Char where-  toParam = toQueryParam-instance ToParam UTCTime where-  toParam = toQueryParam-instance ToParam URI where-  toParam = toParam . uriToText-instance ToParam Value where-  toParam = jsonParam-instance (ToParam a, ToParam b) => ToParam (a, b) where-  toParam (a, b) = toParam [toParam a, toParam b]---{- | Decode data from a 'query', 'session', or 'form' parameter value--@-#EMBED Example.Docs.Sessions data AppColor-@--}-class FromParam a where-  parseParam :: ParamValue -> Either String a-  default parseParam :: (Generic a, GFromJSON Zero (Rep a)) => ParamValue -> Either String a-  parseParam = genericParseParam---  decodeFormValue :: Maybe Text -> Either String a-  decodeFormValue mval = do-    case mval of-      Nothing -> Left "missing form field value"-      Just t -> do-        parseParam $ ParamValue t----- decodeParamValue :: Text -> Either String a--- decodeParamValue = parseParam . decodeParam---- Permissive instances. Some of these come directly from forms!-instance FromParam ParamValue where-  parseParam = pure-instance FromParam Int where-  parseParam "" = pure 0-  parseParam p = jsonParse p-instance FromParam Integer where-  parseParam "" = pure 0-  parseParam p = jsonParse p-instance FromParam Float where-  parseParam "" = pure 0-  parseParam p = jsonParse p-instance FromParam Double where-  parseParam "" = pure 0-  parseParam p = jsonParse p-instance FromParam Text where-  parseParam = parseQueryParam-instance (FromParam a, FromParam b) => FromParam (a, b) where-  parseParam p = do-    ps <- parseParam @[ParamValue] p-    case ps of-      [pa, pb] -> (,) <$> parseParam pa <*> parseParam pb-      _ -> Left $ "Expected [a,b] but got: " <> cs p.value----- -- we don't need to desanitize the text--- parseFormField [inp] = do---   parseParam $ ParamValue inp (String inp)--instance {-# OVERLAPS #-} FromParam String where-  parseParam p = cs <$> parseQueryParam @Text p----- parseFormField sel f = do---   inp :: Text <- first cs $ FE.parseUnique @Text (cs sel) f---   parseParam $ ParamValue inp (String inp)-instance FromParam Word where-  parseParam = jsonParse-instance FromParam Word8 where-  parseParam = jsonParse-instance FromParam Word16 where-  parseParam = jsonParse-instance FromParam Word32 where-  parseParam = jsonParse-instance FromParam Word64 where-  parseParam = jsonParse-instance FromParam Bool where-  parseParam (ParamValue t) =-    case t of-      "on" -> pure True-      "off" -> pure False-      "" -> pure False-      "false" -> pure False-      "true" -> pure True-      other -> Left $ "Could not parse bool param: " <> cs other---  decodeFormValue Nothing = pure False-  decodeFormValue (Just t) =-    parseParam $ ParamValue t---instance FromParam Char where-  parseParam = parseQueryParam-instance FromParam UTCTime where-  parseParam = parseQueryParam-instance FromParam Value where-  parseParam = jsonParse---instance FromParam URI where-  parseParam (ParamValue t) = do-    case parseURIReference (cs t) of-      Nothing -> Left $ "Invalid URI: " <> cs t-      Just u -> pure u---instance {-# OVERLAPPABLE #-} (ToParam a) => ToParam [a] where-  toParam as =-    -- JSON encode the individual params-    let ps :: [ParamValue] = fmap toParam as-     in toParam $ Array $ fromList $ fmap (String . (.value)) ps-instance {-# OVERLAPPABLE #-} (FromParam a) => FromParam [a] where-  parseParam p = do-    ts <- jsonParse @[Text] p-    mapM (parseParam . ParamValue) ts---instance (ToParam a) => ToParam (Maybe a) where-  toParam Nothing = ParamValue "~"-  toParam (Just a) = toParam a-instance {-# OVERLAPPABLE #-} (FromParam a) => FromParam (Maybe a) where-  parseParam (ParamValue "") = pure Nothing-  parseParam (ParamValue "~") = pure Nothing-  parseParam t = Just <$> parseParam @a t---  decodeFormValue Nothing = pure Nothing-  decodeFormValue (Just t) = do-    parseParam @(Maybe a) (ParamValue t)---instance {-# OVERLAPS #-} FromParam (Maybe Text) where-  parseParam (ParamValue "~") = pure Nothing-  -- keep empty strings, the default instance discards them-  parseParam (ParamValue "") = pure (Just "")-  parseParam t = Just <$> parseParam @Text t---  decodeFormValue Nothing = pure Nothing-  decodeFormValue (Just t) = do-    parseParam @(Maybe Text) (ParamValue t)---instance (ToParam a, ToParam b) => ToParam (Either a b) where-  toParam (Left a) = toParam a-  toParam (Right b) = toParam b-instance (FromParam a, FromParam b) => FromParam (Either a b) where-  parseParam val =-    case parseParam @a val of-      Right a -> pure $ Left a-      Left _ -> do-        case parseParam @b val of-          Left _ -> Left $ "Could not parse Either param: " <> show val-          Right b -> pure $ Right b---parseQueryParam :: (FromHttpApiData a) => ParamValue -> Either String a-parseQueryParam (ParamValue t) =-  first cs $ HttpApiData.parseQueryParam t---toQueryParam :: (ToHttpApiData a) => a -> ParamValue-toQueryParam a =-  ParamValue $ HttpApiData.toQueryParam a----- | Encode a Show as a query param-showParam :: (Show a) => a -> ParamValue-showParam a = toQueryParam $ show a----- | Decode a Read as a query param-readParam :: (Read a) => ParamValue -> Either String a-readParam p = do-  str <- parseQueryParam p-  case readMaybe str of-    Nothing -> Left $ cs $ "Could not read query param: " <> str-    Just a -> pure a---genericToParam :: (Generic a, GToJSON Zero (Rep a)) => a -> ParamValue-genericToParam a =-  case genericToJSON jsonOptions a of-    String t -> ParamValue t-    other -> jsonParam other---genericParseParam :: (Generic a, GFromJSON Zero (Rep a)) => ParamValue -> Either String a-genericParseParam (ParamValue t) = do-  val <- maybe (pure $ String t) pure $ A.decode (cs t)-  A.parseEither (genericParseJSON jsonOptions) val----- Encoding --------------------------------------------------------------jsonOptions :: A.Options-jsonOptions = defaultOptions{sumEncoding = TwoElemArray}---jsonParam :: (ToJSON a) => a -> ParamValue-jsonParam a = ParamValue (cs $ A.encode a)---jsonParse :: (FromJSON a) => ParamValue -> Either String a-jsonParse (ParamValue t) = do-  A.eitherDecode (cs t)
src/Web/Hyperbole/Data/QueryData.hs view
@@ -3,42 +3,69 @@  module Web.Hyperbole.Data.QueryData where -import Data.Aeson (Value (Null))+import Control.Applicative ((<|>))+import Data.Aeson (FromJSON (..), Result (..), ToJSON (..), Value (..), fromJSON)+import Data.Aeson qualified as A import Data.ByteString (ByteString) import Data.Default (Default (..)) import Data.Map.Strict (Map) import Data.Map.Strict qualified as M import Data.Maybe (fromMaybe)+import Data.String (IsString) import Data.String.Conversions (cs) import Data.Text (Text, pack)+import Data.Text qualified as T import GHC.Exts (IsList (..)) import GHC.Generics import Network.HTTP.Types (Query, QueryItem, renderQuery) import Network.HTTP.Types qualified as HTTP-import Web.Hyperbole.Data.Encoded (decodeParam, encodeParam)-import Web.Hyperbole.Data.Param import Prelude hiding (lookup)  +newtype Param = Param {text :: Text}+  deriving newtype (Show, Eq, Ord, IsString)++ -- | Key-value store for query params and sessions-newtype QueryData = QueryData (Map Param ParamValue)+newtype QueryData = QueryData (Map Param Text)   deriving (Show)   deriving newtype (Monoid, Semigroup)   instance IsList QueryData where-  type Item QueryData = (Param, ParamValue)+  type Item QueryData = (Param, Text)   fromList = QueryData . fromList   toList (QueryData m) = toList m  -singleton :: (ToParam a) => Param -> a -> QueryData-singleton key a = QueryData $ M.singleton key (toParam a)+parseParam :: (FromJSON a) => Value -> Either String a+parseParam v =+  case fromJSON v of+    Success a -> pure a+    Error e -> Left e  -insert :: (ToParam a) => Param -> a -> QueryData -> QueryData+-- the "default" encoding uses unquoted strings+encodeParam :: (ToJSON a) => a -> Text+encodeParam a = do+  case A.toJSON a of+    String s -> cs s+    val -> cs $ A.encode val+++-- | Decode a parameter from JSON. Uses unquoted strings when possible+decodeParam :: (FromJSON a) => Text -> Either String a+decodeParam inp = maybe (Left $ "Could not decode Query Param: " <> cs inp) pure $ do+  A.decode (cs inp) <|> A.decode (cs $ "\"" <> inp <> "\"")+++singleton :: (ToJSON a) => Param -> a -> QueryData+singleton key a = QueryData $ M.singleton key (encodeParam a)+++insert :: (ToJSON a) => Param -> a -> QueryData -> QueryData insert p a (QueryData m) =-  QueryData $ M.insert p (toParam a) m+  QueryData $ M.insert p (encodeParam a) m   insertAll :: (ToQuery a) => a -> QueryData -> QueryData@@ -52,17 +79,17 @@   QueryData $ M.delete p m  -lookup :: (FromParam a) => Param -> QueryData -> Maybe a+lookup :: (FromJSON a) => Param -> QueryData -> Maybe a lookup k (QueryData m) = do-  t <- M.lookup k m-  either (const Nothing) pure $ parseParam t+  t :: Text <- M.lookup k m+  either (const Nothing) pure $ decodeParam t  -require :: (FromParam a) => Param -> QueryData -> Either String a+require :: (FromJSON a) => Param -> QueryData -> Either String a require p (QueryData m) = do   case M.lookup p m of     Nothing -> Left $ "Missing Key: " <> cs p.text-    Just val -> parseParam val+    Just val -> decodeParam val   filterKey :: (Param -> Bool) -> QueryData -> QueryData@@ -74,44 +101,48 @@ member k (QueryData qd) = M.member k qd  -elems :: QueryData -> [ParamValue]+elems :: QueryData -> [Text] elems (QueryData m) = M.elems m  -render :: QueryData -> ByteString+render :: QueryData -> Text render qd =-  renderQuery False (HTTP.toQuery $ fromQueryData qd)+  T.replace "%20" "+" $ cs $ renderQuery False (HTTP.toQuery $ fromQueryData qd)  -parse :: ByteString -> QueryData+parse :: Text -> QueryData parse =-  -- urlDecode True-  queryData . HTTP.parseQuery+  -- it already knows how to handle + signs on parse+  queryData . HTTP.parseQuery . cs   queryData :: Query -> QueryData queryData q =   fromList $ fmap fromQueryItem q  where-  fromQueryItem :: QueryItem -> (Param, ParamValue)-  fromQueryItem (key, mval) =+  fromQueryItem :: QueryItem -> (Param, Text)+  fromQueryItem (key, mval) = do     (Param (cs key), fromParam mval) -  fromParam :: Maybe ByteString -> ParamValue-  fromParam Nothing = jsonParam Null-  fromParam (Just t) = decodeParam (cs t)+  -- do we include fields that don't have a value? Sure+  fromParam :: Maybe ByteString -> Text+  fromParam Nothing = ""+  fromParam (Just t) = cs t  +-- Now we have our own thing!+-- 1. ALWAYS encode strings without quotes+-- 2. How do you distinguish between numbers and strings then?++-- problem: strings are always quoted+-- if we unquote them, they might be a string like "30" fromQueryData :: QueryData -> Query fromQueryData q =   fmap toQueryItem $ toList q  where-  toQueryItem :: (Param, ParamValue) -> QueryItem+  toQueryItem :: (Param, Text) -> QueryItem   toQueryItem (Param prm, pval) =-    (cs prm, Just $ toQueryValue pval)--  toQueryValue :: ParamValue -> ByteString-  toQueryValue = cs . encodeParam+    (cs prm, Just $ cs pval)   {- | Decode a type from a 'QueryData'. Missing fields are set to 'Data.Default.def'@@ -187,7 +218,7 @@   gParseQuery q = M1 <$> gParseQuery q  -instance {-# OVERLAPPABLE #-} (Selector s, FromParam a, Default a) => GFromQuery (M1 S s (K1 R a)) where+instance {-# OVERLAPPABLE #-} (Selector s, FromJSON a, Default a) => GFromQuery (M1 S s (K1 R a)) where   gParseQuery q = do     let s = selName (undefined :: M1 S s (K1 R (f a)) p)     let mval = lookup (Param $ pack s) q@@ -219,7 +250,7 @@   gToQuery (M1 f) = gToQuery f  -instance {-# OVERLAPPABLE #-} (Selector s, ToParam a, Eq a, Default a) => GToQuery (M1 S s (K1 R a)) where+instance {-# OVERLAPPABLE #-} (Selector s, ToJSON a, Eq a, Default a) => GToQuery (M1 S s (K1 R a)) where   gToQuery (M1 (K1 a))     | a == def = mempty     | otherwise =@@ -235,7 +266,7 @@         let sel = Param $ pack $ selName (undefined :: M1 S s (K1 R (f a)) p)          in singleton sel a --- instance {-# OVERLAPS #-} (Selector s, ToParam a, Eq a) => GToQuery (M1 S s (K1 R [a])) where+-- instance {-# OVERLAPS #-} (Selector s, ToJSON a, Eq a) => GToQuery (M1 S s (K1 R [a])) where --   gToQuery (M1 (K1 a)) --     | a == [] = mempty --     | otherwise =
src/Web/Hyperbole/Data/URI.hs view
@@ -9,6 +9,7 @@   , Segment   , path   , parseURIReference+  , parseURI   , pathUri   , uriToText   , pathToText@@ -34,7 +35,7 @@ import Data.Text qualified as T import GHC.Exts (IsList (..)) import Network.HTTP.Types (Query, QueryItem, parseQuery, renderQuery)-import Network.URI (URI (..), URIAuth (..), parseURIReference, uriToString)+import Network.URI (URI (..), URIAuth (..), parseURI, parseURIReference, uriToString) import Network.URI qualified as Network import Network.URI.Static (uri) import System.FilePath (normalise, (</>))
src/Web/Hyperbole/Document.hs view
@@ -48,7 +48,7 @@ @ -} quickStartDocument :: BL.ByteString -> BL.ByteString-quickStartDocument = document (mobileFriendly >> quickStart)+quickStartDocument = document quickStart   -- | A simple mobile-friendly header with all required embeds and live reload
src/Web/Hyperbole/Effect/GenRandom.hs view
@@ -8,8 +8,8 @@ import Data.Text (Text) import Effectful import Effectful.Dispatch.Dynamic+import GHC.Generics (Generic) import System.Random (Random, randomRIO)-import Web.Hyperbole.Data.Param (FromParam, ToParam)   data GenRandom :: Effect where@@ -53,4 +53,5 @@   newtype Token a = Token {value :: Text}-  deriving newtype (FromJSON, ToJSON, FromParam, ToParam, Eq, Show, Read, Ord)+  deriving newtype (FromJSON, ToJSON, Eq, Show, Read, Ord)+  deriving (Generic)
src/Web/Hyperbole/Effect/Hyperbole.hs view
@@ -5,6 +5,7 @@ import Data.Aeson (Value) import Data.Text (Text) import Effectful+import Effectful.Dispatch.Dynamic import Effectful.Error.Static import Effectful.State.Static.Local import Effectful.Writer.Static.Local@@ -47,3 +48,8 @@       , query = mempty       , pageTitle = Nothing       }+++-- | Return all information about the 'Request'+request :: (Hyperbole :> es) => Eff es Request+request = send GetRequest
− src/Web/Hyperbole/Effect/OAuth2.hs
@@ -1,284 +0,0 @@-{-# LANGUAGE CPP #-}-{-# LANGUAGE DerivingVia #-}-{-# LANGUAGE LambdaCase #-}--module Web.Hyperbole.Effect.OAuth2-  ( OAuth2 (..)-  , authUrl-  , validateCode-  , exchangeAuth-  , exchangeRefresh-  , runOAuth2-  , getConfigEnv-  , Scopes (..)-  , AuthFlow (..)-  , Config (..)-  , TokenType (..)-  , Authenticated (..)-  , Token (..)-  , ClientId-  , ClientSecret-  , Code-  , Access-  , Refresh-  , State-  , Auth-  , OAuth2Error (..)-  ) where--import Control.Monad (unless, when)-import Data.Aeson (FromJSON (..), Options (..), ToJSON (..), Value (..), defaultOptions, eitherDecode, genericParseJSON, genericToJSON)-import Data.ByteString.Lazy qualified as BL-import Data.Default-import Data.Maybe (isJust)-import Data.String (IsString (..))-import Data.String.Conversions (cs)-import Data.Text (Text)-import Data.Text qualified as T-import Effectful-import Effectful.Dispatch.Dynamic-import Effectful.Environment-import Effectful.Exception-import GHC.Generics (Generic)-import Network.HTTP.Client (HttpException, Request (..), RequestBody (..))-import Network.HTTP.Client qualified as HTTP-import Network.HTTP.Types (hAccept, hContentType)-import Network.URI (parseURI)-import Text.Casing (quietSnake)-import Web.Hyperbole.Data.Encoded-import Web.Hyperbole.Data.Param-import Web.Hyperbole.Data.URI-import Web.Hyperbole.Effect.GenRandom-import Web.Hyperbole.Effect.Hyperbole-import Web.Hyperbole.Effect.Query-import Web.Hyperbole.Effect.Response (respondError)-import Web.Hyperbole.Effect.Session (Session (..), deleteSession, saveSession, session)-import Web.Hyperbole.Types.Response---authUrl :: (OAuth2 :> es) => URI -> Scopes -> Eff es URI-authUrl redirectUrl scopes = send $ AuthUrl redirectUrl scopes---validateCode :: (OAuth2 :> es) => Eff es (Token Code)-validateCode = send ValidateCode---exchangeAuth :: (OAuth2 :> es) => Token Code -> Eff es Authenticated-exchangeAuth authCode = send $ ExchangeAuth authCode---exchangeRefresh :: (OAuth2 :> es) => Token Refresh -> Eff es Authenticated-exchangeRefresh refToken = send $ ExchangeRefresh refToken---data OAuth2 :: Effect where-  AuthUrl :: URI -> Scopes -> OAuth2 m URI-  ValidateCode :: OAuth2 m (Token Code)-  ExchangeAuth :: Token Code -> OAuth2 m Authenticated-  ExchangeRefresh :: Token Refresh -> OAuth2 m Authenticated---type instance DispatchOf OAuth2 = 'Dynamic---runOAuth2-  :: (GenRandom :> es, IOE :> es, Hyperbole :> es)-  => Config-  -> HTTP.Manager-  -> Eff (OAuth2 : es) a-  -> Eff es a-runOAuth2 cfg mgr = interpret $ \_ -> \case-  AuthUrl red scopes -> do-    state <- genRandomToken 6-    let url = authorizationUrl cfg.authorize cfg.clientId red scopes state-    saveSession $ AuthFlow red state-    pure url-  ValidateCode -> do-    flow <- session @AuthFlow-    validateRedirectParams flow-  ExchangeAuth authCode -> do-    flow <- session @AuthFlow-    let params = tokenParams cfg.clientId cfg.clientSecret flow.redirect authCode-    auth <- sendTokenRequest cfg mgr params-    deleteSession @AuthFlow-    pure auth-  ExchangeRefresh refToken -> do-    let params = refreshParams cfg.clientId cfg.clientSecret refToken-    sendTokenRequest cfg mgr params---{- | read oauth config from env. This is not required, you can obtain these secrets another way-and configure the app however you please. Just pass the results into runOAuth2 in your app--}-getConfigEnv :: (Environment :> es) => Eff es Config-getConfigEnv = do-  clientId <- Token . cs <$> getEnv "OAUTH2_CLIENT_ID"-  clientSecret <- Token . cs <$> getEnv "OAUTH2_CLIENT_SECRET"-  authorize <- Endpoint <$> getEnvURI "OAUTH2_AUTHORIZE_ENDPOINT"-  token <- Endpoint <$> getEnvURI "OAUTH2_TOKEN_ENDPOINT"-  pure $ Config{clientId, clientSecret, authorize, token}- where-  getEnvURI n = do-    str <- getEnv n-    case parseURI str of-      Nothing -> throwIO $ OAuth2BadEnv n str-      Just u -> pure u----- Types ---------------------------------------------------newtype Scopes = Scopes [Text]-  deriving (Show, Generic)-  deriving anyclass (FromParam, ToParam)-instance ToJSON Scopes where-  toJSON (Scopes ss) = String $ T.unwords ss-instance FromJSON Scopes where-  parseJSON v = do-    t <- parseJSON @String v-    pure $ fromString t-instance IsString Scopes where-  fromString s = Scopes $ T.words $ cs s---data ClientId-data ClientSecret-data Code-data Refresh-data Access-data State-data Auth--#if (!MIN_VERSION_aeson(2,2,0))-instance FromJSON URI-instance ToJSON URI-instance FromJSON URIAuth-instance ToJSON URIAuth-#endif---data AuthFlow = AuthFlow-  { redirect :: URI-  , state :: Token State-  }-  deriving (Generic, FromEncoded, ToEncoded)-instance Session AuthFlow where-  sessionKey = "OAuth2AuthFlow"-  cookiePath = Just "/"-instance Default AuthFlow where-  def = AuthFlow (pathUri "/") (Token mempty)---data Config = Config-  { clientId :: Token ClientId-  , clientSecret :: Token ClientSecret-  , authorize :: Endpoint Auth-  , token :: Endpoint (Token ())-  }---data TokenType-  = Bearer-  deriving (Show, Read, Generic, ToParam, FromParam)-instance ToJSON TokenType where-  toJSON s = toJSON $ show s-instance FromJSON TokenType where-  parseJSON (String ttyp) | T.toLower ttyp == "bearer" = pure Bearer-  parseJSON val = fail $ "expected TokenType but got " <> show val---data Authenticated = Authenticated-  { tokenType :: TokenType-  , expiresIn :: Maybe Int-  , scope :: Maybe Scopes-  , accessToken :: Token Access-  , refreshToken :: Maybe (Token Refresh)-  }-  deriving (Generic, Show, ToParam, FromParam, ToEncoded, FromEncoded)-instance FromJSON Authenticated where-  parseJSON = genericParseJSON defaultOptions{fieldLabelModifier = quietSnake}-instance ToJSON Authenticated where-  toJSON = genericToJSON defaultOptions{fieldLabelModifier = quietSnake}-instance Session Authenticated where-  sessionKey = "OAuth2Authenticated"-  cookiePath = Just "/"---data OAuth2Error-  = OAuth2BadResponse String BL.ByteString-  | OAuth2TokenRequest HttpException-  | OAuth2BadEnv String String-  deriving (Show, Exception)----- Lower level ----------------------------------------------------authorizationUrl :: Endpoint Auth -> Token ClientId -> URI -> Scopes -> Token State -> URI-authorizationUrl (Endpoint auth) (Token cid) redUrl (Scopes scopes) (Token state) =-  auth{uriQuery = cs $ renderQuery True authParams}- where-  authParams =-    [ ("response_type", Just "code")-    , ("client_id", Just $ cs cid)-    , ("redirect_uri", Just $ cs $ uriToText redUrl)-    , ("scope", Just $ cs $ T.intercalate " " scopes)-    , ("state", Just $ cs state)-    ]---tokenParams :: Token ClientId -> Token ClientSecret -> URI -> Token Code -> Query-tokenParams (Token cid) (Token sec) redUrl (Token ac) =-  [ ("grant_type", Just "authorization_code")-  , ("client_id", Just $ cs cid)-  , ("client_secret", Just $ cs sec)-  , ("redirect_uri", Just $ cs $ uriToText redUrl)-  , ("code", Just $ cs ac)-  ]---refreshParams :: Token ClientId -> Token ClientSecret -> Token Refresh -> Query-refreshParams (Token cid) (Token sec) (Token ref) =-  [ ("grant_type", Just "refresh_token")-  , ("client_id", Just $ cs cid)-  , ("client_secret", Just $ cs sec)-  , ("refresh_token", Just $ cs ref)-  ]---validateRedirectParams :: (Hyperbole :> es) => AuthFlow -> Eff es (Token Code)-validateRedirectParams flow = do-  err <- lookupParam @Text "error"--  when (isJust err) $ do-    desc <- param "error_description"-    respondError $ ErrAuth desc--  authState <- param @(Token State) "state"-  authCode <- param @(Token Code) "code"--  unless (flow.state == authState) $ do-    respondError $ ErrAuth "Oauth2 State mismatch"--  pure authCode---sendTokenRequest :: (IOE :> es) => Config -> HTTP.Manager -> Query -> Eff es Authenticated-sendTokenRequest cfg mgr params = do-  baseReq <- HTTP.requestFromURI cfg.token.uri--  let req =-        baseReq-          { method = "POST"-          , requestBody = RequestBodyBS $ renderQuery False params-          , requestHeaders =-              [ (hContentType, "application/x-www-form-urlencoded")-              , (hAccept, "application/json")-              ]-          }--  res <- liftIO (HTTP.httpLbs req mgr) `catch` (throwIO . OAuth2TokenRequest)--  let body = HTTP.responseBody res-  case eitherDecode @Authenticated body of-    Left e -> throwIO $ OAuth2BadResponse e body-    Right tr -> pure tr
src/Web/Hyperbole/Effect/Query.hs view
@@ -1,18 +1,17 @@ module Web.Hyperbole.Effect.Query where +import Data.Aeson (FromJSON, ToJSON) import Data.ByteString qualified as BS import Data.Default (Default (..)) import Data.Maybe (fromMaybe) import Data.String.Conversions (cs) import Effectful import Effectful.Dispatch.Dynamic (send)-import Web.Hyperbole.Data.Param (FromParam (..), Param, ToParam (..))-import Web.Hyperbole.Data.QueryData (FromQuery (..), QueryData (..), ToQuery (..), queryData)+import Web.Hyperbole.Data.QueryData (FromQuery (..), Param (..), QueryData (..), ToQuery (..), queryData) import Web.Hyperbole.Data.QueryData qualified as QueryData-import Web.Hyperbole.Effect.Hyperbole (Hyperbole (..))-import Web.Hyperbole.Effect.Request (request)+import Web.Hyperbole.Effect.Hyperbole (Hyperbole (..), request) import Web.Hyperbole.Types.Client (Client (..), clientSetQuery)-import Web.Hyperbole.Types.Request+import Web.Hyperbole.Types.Request hiding (Param) import Web.Hyperbole.Types.Response import Prelude @@ -57,13 +56,13 @@   setQuery (mempty :: QueryData)  -{- | Parse a single query parameter. Return a 400 status if missing or if parsing fails. See 'FromParam'+{- | Parse a single query parameter. Return a 400 status if missing or if parsing fails. See 'decodeParam'  @ #EMBED Example.Docs.Params page' @ -}-param :: (FromParam a, Hyperbole :> es) => Param -> Eff es a+param :: (FromJSON a, Hyperbole :> es) => Param -> Eff es a param p = do   q <- queryParams   case QueryData.require p q of@@ -78,18 +77,18 @@ #EMBED Example.Docs.SideEffects page @ -}-lookupParam :: (FromParam a, Hyperbole :> es) => Param -> Eff es (Maybe a)+lookupParam :: (FromJSON a, Hyperbole :> es) => Param -> Eff es (Maybe a) lookupParam p = do   QueryData.lookup p <$> queryParams  -{- | Modify the client's querystring to set a single parameter. See 'ToParam'+{- | Modify the client's querystring to set a single parameter. See 'encodeParam'  @ #EMBED Example.Docs.Params instance HyperView Message @ -}-setParam :: (ToParam a, Hyperbole :> es) => Param -> a -> Eff es ()+setParam :: (ToJSON a, Hyperbole :> es) => Param -> a -> Eff es () setParam key a = do   modifyQueryData (QueryData.insert key a) 
src/Web/Hyperbole/Effect/Request.hs view
@@ -1,20 +1,13 @@ module Web.Hyperbole.Effect.Request where -import Data.String.Conversions (cs) import Effectful-import Effectful.Dispatch.Dynamic-import Web.FormUrlEncoded (Form, urlDecodeForm) import Web.Hyperbole.Data.URI (Path (..)) import Web.Hyperbole.Effect.Hyperbole+import Web.Hyperbole.Effect.Response (parseError)+import Web.Hyperbole.HyperView.Input (InputValue (..)) import Web.Hyperbole.Types.Request-import Web.Hyperbole.Types.Response  --- | Return all information about the 'Request'-request :: (Hyperbole :> es) => Eff es Request-request = send GetRequest-- {- | Return the request path  >>> reqPath@@ -24,12 +17,18 @@ reqPath = (.path) <$> request  -{- | Return the request body as a Web.FormUrlEncoded.Form+{- | Return the request body as a 'Form'  Prefer using Type-Safe 'Form's when possible -} formBody :: (Hyperbole :> es) => Eff es Form formBody = do-  b <- (.body) <$> request-  let ef = urlDecodeForm b-  either (send . RespondNow . Err . ErrParse . cs) pure ef+  (.form) <$> request+++inputValue :: (InputValue a, Hyperbole :> es) => Eff es a+inputValue = do+  t <- (.input) <$> request+  case parseInputValue t of+    Left err -> parseError $ "Input: " <> err+    Right a -> pure a
src/Web/Hyperbole/Effect/Response.hs view
@@ -1,11 +1,11 @@ module Web.Hyperbole.Effect.Response where +import Data.Aeson (ToJSON) import Data.Text (Text) import Effectful import Effectful.Dispatch.Dynamic import Effectful.Reader.Dynamic import Effectful.State.Dynamic-import Web.Hyperbole.Data.Encoded import Web.Hyperbole.Data.URI import Web.Hyperbole.Effect.Hyperbole (Hyperbole (..)) import Web.Hyperbole.HyperView (ConcurrencyValue (..), HyperView (..), hyperUnsafe)@@ -15,20 +15,20 @@   -- | Respond with the given hyperview-hyperView :: (HyperView id es, ToEncoded (ViewState id)) => id -> ViewState id -> View id () -> Eff es Response+hyperView :: (HyperView id es, ToJSON (ViewState id)) => id -> ViewState id -> View id () -> Eff es Response hyperView i st vw = do   let vid = TargetViewId (toViewId i)   pure $ Response $ ViewUpdate vid $ renderBody $ hyperUnsafe i st vw  -pushUpdate :: (Hyperbole :> es, ViewId id, ToEncoded (ViewState id), ConcurrencyValue (Concurrency id)) => View id () -> Eff (Reader id : State (ViewState id) : es) ()+pushUpdate :: (Hyperbole :> es, ViewId id, ToJSON (ViewState id), ConcurrencyValue (Concurrency id)) => View id () -> Eff (Reader id : State (ViewState id) : es) () pushUpdate vw = do   i <- viewId   st <- get   pushUpdateTo i st vw  -pushUpdateTo :: (Hyperbole :> es, ViewId id, ToEncoded (ViewState id), ConcurrencyValue (Concurrency id)) => id -> ViewState id -> View id () -> Eff es ()+pushUpdateTo :: (Hyperbole :> es, ViewId id, ToJSON (ViewState id), ConcurrencyValue (Concurrency id)) => id -> ViewState id -> View id () -> Eff es () pushUpdateTo i st vw = do   send $ PushUpdate $ ViewUpdate (TargetViewId $ toViewId i) $ renderBody $ hyperUnsafe i st vw 
src/Web/Hyperbole/Effect/Session.hs view
@@ -3,6 +3,8 @@  module Web.Hyperbole.Effect.Session where +import Data.Aeson (FromJSON, ToJSON)+import Data.Aeson qualified as A import Data.Default (Default (..)) import Data.Maybe (fromMaybe) import Data.String.Conversions (cs)@@ -11,11 +13,8 @@ import Effectful.Dispatch.Dynamic import GHC.Generics import Web.Hyperbole.Data.Cookie as Cookie-import Web.Hyperbole.Data.Encoded as Encoded-import Web.Hyperbole.Data.Param import Web.Hyperbole.Data.URI (Path)-import Web.Hyperbole.Effect.Hyperbole (Hyperbole (..))-import Web.Hyperbole.Effect.Request (request)+import Web.Hyperbole.Effect.Hyperbole (Hyperbole (..), request) import Web.Hyperbole.Types.Client (Client (..), clientModCookies) import Web.Hyperbole.Types.Request import Web.Hyperbole.Types.Response@@ -50,15 +49,15 @@    -- | Encode type to a a cookie value   toCookie :: a -> CookieValue-  default toCookie :: (ToEncoded a) => a -> CookieValue-  toCookie = CookieValue . cs . Encoded.encode+  default toCookie :: (ToJSON a) => a -> CookieValue+  toCookie = CookieValue . cs . A.encode     -- | Decode from a cookie value. Defaults to FromJSON   parseCookie :: CookieValue -> Either String a-  default parseCookie :: (FromEncoded a) => CookieValue -> Either String a+  default parseCookie :: (FromJSON a) => CookieValue -> Either String a   parseCookie (CookieValue bs) = do-    Encoded.decodeEither (cs bs)+    A.eitherDecode (cs bs)   {- | Load data from a browser cookie. If it doesn't exist, the 'Default' instance is used@@ -84,7 +83,10 @@   mck <- Cookie.lookup key <$> sessionCookies   case mck of     Nothing -> pure Nothing-    Just val -> Just <$> parseSession key val+    Just cook ->+      case parseCookie cook of+        Left _ -> pure Nothing+        Right a -> pure $ Just a   {- | Persist datatypes in browser cookies@@ -131,7 +133,7 @@   -- | save a single datatype to a specific key in the session-setCookie :: (ToParam a, Hyperbole :> es) => Cookie -> Eff es ()+setCookie :: (ToJSON a, Hyperbole :> es) => Cookie -> Eff es () setCookie ck = do   modifyCookies (Cookie.insert ck) 
src/Web/Hyperbole/HyperView/Event.hs view
@@ -54,17 +54,14 @@  > input (onInput OnSearch) 250 id -}-onInput :: (ViewAction (Action id), Attributable a) => (Text -> Action id) -> DelayMs -> Attributes a -> Attributes a+onInput :: (ViewAction (Action id), Attributable a) => Action id -> DelayMs -> Attributes a -> Attributes a onInput a delay = do-  att (eventName "input") (encodedToText $ toActionInput a) . att "data-delay" (cs $ show delay)+  att (eventName "input") (encodedToText $ toAction a) . att "data-delay" (cs $ show delay)  --- WARNING: no way to do this generically right now, because toActionInput is specialized to Text---   the change event DOES assume that the target has a string value---   but, that doesn't let us implement dropdown-onChange :: (ViewAction (Action id), Attributable a) => (value -> Action id) -> Attributes a -> Attributes a+onChange :: (ViewAction (Action id), Attributable a) => Action id -> Attributes a -> Attributes a onChange a = do-  att (eventName "change") (encodedToText $ toActionInput a)+  att (eventName "change") (encodedToText $ toAction a)   onSubmit :: (ViewAction (Action id), Attributable a) => Action id -> Attributes a -> Attributes a@@ -105,17 +102,6 @@   | Shift   | OtherKey Text   deriving (Show, Read)----- | Serialize a constructor that expects a single input, like `data MyAction = GoSearch Text`-toActionInput :: (ViewAction a) => (val -> a) -> Encoded-toActionInput act =-  -- laziness should let us drop the last item?-  -- maybe... I bet it evaluates it strictly-  let Encoded con vals = toAction (act undefined)-   in if null vals-        then Encoded con vals-        else Encoded con (init vals)   -- | Internal
src/Web/Hyperbole/HyperView/Forms.hs view
@@ -1,10 +1,14 @@ {-# LANGUAGE AllowAmbiguousTypes #-} {-# LANGUAGE DefaultSignatures #-}+{-# LANGUAGE LambdaCase #-} {-# LANGUAGE UndecidableInstances #-}  module Web.Hyperbole.HyperView.Forms   ( FromForm (..)   , FromFormF (..)+  , lookupField+  , parseField+  , FromField (..)   , GenFields (..)   , fieldNames   , FieldName (..)@@ -15,6 +19,7 @@   , field   , label   , input+  , fileInput   , checkbox   , radioGroup   , radio@@ -23,7 +28,6 @@   , textarea   , submit   , formData-  , FormOptions (..)   , Validated (..)   , isInvalid   , invalidText@@ -31,34 +35,37 @@   , Identity      -- * Re-exports-  , FE.FromFormKey   , Generic   , GFieldsGen (..)   , GenField (..)-  , Form (..)   ) where -import Data.Bifunctor (first)+import Control.Applicative ((<|>))+import Data.Aeson (FromJSON, ToJSON)+import Data.Bifunctor (first, second)+import Data.ByteString qualified as BS import Data.Functor.Identity (Identity (..)) import Data.Kind (Type) import Data.Maybe (fromMaybe) import Data.String (IsString (..)) import Data.String.Conversions (cs) import Data.Text (Text, pack)+import Data.Time.Clock (UTCTime) import Effectful import GHC.Generics+import Network.URI import Text.Casing (kebab)+import Text.Read (readMaybe) import Web.Atomic.Types hiding (Selector)-import Web.FormUrlEncoded (Form (..), FormOptions (..))-import Web.FormUrlEncoded qualified as FE-import Web.Hyperbole.Data.Param+import Web.Hyperbole.Data.Argument import Web.Hyperbole.Effect.Hyperbole-import Web.Hyperbole.Effect.Request+import Web.Hyperbole.Effect.Request (formBody) import Web.Hyperbole.Effect.Response (parseError) import Web.Hyperbole.HyperView.Event (onSubmit) import Web.Hyperbole.HyperView.Input (Option (..), checked) import Web.Hyperbole.HyperView.Types+import Web.Hyperbole.Types.Request import Web.Hyperbole.View  @@ -66,6 +73,9 @@ -- FORM PARSING ------------------------------------------------------------------------------ +type ParamKey = BS.ByteString++ {- | Simple types that be decoded from form data  @@@ -73,20 +83,20 @@ @ -} class FromForm (form :: Type) where-  fromForm :: FE.Form -> Either String form-  default fromForm :: (Generic form, GFormParse (Rep form)) => FE.Form -> Either String form+  fromForm :: Form -> Either String form+  default fromForm :: (Generic form, GFormParse (Rep form)) => Form -> Either String form   fromForm f = to <$> gFormParse f  -{- | A Higher-Kinded type that can be parsed from a 'Web.FormUrlEncoded.Form'+{- | A Higher-Kinded type that can be parsed from a 'Form'  @ #EMBED Example.FormValidation data UserForm @ -} class FromFormF (f :: (Type -> Type) -> Type) where-  fromFormF :: FE.Form -> Either String (f Identity)-  default fromFormF :: (Generic (f Identity), GFormParse (Rep (f Identity))) => FE.Form -> Either String (f Identity)+  fromFormF :: Form -> Either String (f Identity)+  default fromFormF :: (Generic (f Identity), GFormParse (Rep (f Identity))) => Form -> Either String (f Identity)   fromFormF f = to <$> gFormParse f  @@ -104,6 +114,21 @@   either parseError pure ef  +lookupField :: ParamKey -> Form -> Maybe FormParam+lookupField key f = FormParam . cs <$> lookup key f.params <|> FileParam <$> lookup key f.files+++parseField :: forall a. (FromField a) => ParamKey -> Form -> Either String a+parseField key f = do+  let mt :: Maybe FormParam = lookupField key f+  a <- first (\err -> cs key <> ": " <> err) $ fromField @a mt+  pure a+++-- where+--  -- lookupFile = FileField <$> lookup key req.files+--  lookupParam = ParamField . ParamValue . cs <$>+ ------------------------------------------------------------------------------ -- GEN FIELDS: Generate a type from selector names ------------------------------------------------------------------------------@@ -180,7 +205,7 @@  -- | Form FieldName. This is embeded as the name attribute, and refers to the key need to parse the form when submitted. See 'fieldNames' newtype FieldName a = FieldName {value :: Text}-  deriving newtype (Show, IsString, FromParam, ToParam)+  deriving newtype (Show, IsString, FromJSON, ToJSON)   -- | Display a 'FormField'. See 'form' and 'Form'@@ -218,8 +243,9 @@   , inputName :: FieldName a   }   deriving (Generic)-instance (ViewId id, FromParam id, ToParam id) => ViewId (Input id a) where+instance (ViewId id, FromJSON id) => ViewId (Input id a) where   type ViewState (Input id a) = ViewState id+  toViewId inp = toViewId inp.id   {- | label for a 'field'@@ -229,6 +255,12 @@ label = tag "label"  +fileInput :: forall id a. View (Input id a) ()+fileInput = do+  inp :: Input id a <- viewId+  tag "input" @ att "type" "file" . name inp.inputName.value $ none++ -- | input for a 'field' input :: forall id a. InputType -> View (Input id a) () input ft = do@@ -263,7 +295,7 @@   , defaultOption :: opt   }   deriving (Generic)-instance (FromParam id, ToParam id, FromParam a, ToParam a, ToParam opt, FromParam opt) => ViewId (Radio id a opt) where+instance (FromJSON id, FromJSON opt, ToJSON id, ToJSON opt) => ViewId (Radio id a opt) where   type ViewState (Radio id a opt) = ViewState id  @@ -271,13 +303,13 @@ radioGroup defOpt = runChildView (\(inp :: Input id a) -> Radio inp.id inp.inputName defOpt)  -radio :: forall id a opt. (Eq opt, ToParam opt) => opt -> View (Radio id a opt) ()+radio :: forall id a opt. (Eq opt, ToJSON opt) => opt -> View (Radio id a opt) () radio val = do   rd :: Radio id a opt <- viewId   tag "input"     @ att "type" "radio"     . name rd.inputName.value-    . value (toParam val).value+    . value (encodeArgument val)     . checked (rd.defaultOption == val)     $ none @@ -391,11 +423,150 @@   ------------------------------------------------------------------------------+-- FormField+------------------------------------------------------------------------------++class FromField a where+  fromField :: Maybe FormParam -> Either String a+  default fromField :: (FromJSON a) => Maybe FormParam -> Either String a+  fromField = argumentField+++argumentField :: (FromJSON a) => Maybe FormParam -> Either String a+argumentField = \case+  Nothing -> Left "Missing form field value"+  Just (FormParam t) -> decodeArgument t+  Just (FileParam _) ->+    Left "Cannot parse uploaded file as param"+++readField :: (Read a) => Maybe FormParam -> Either String a+readField = \case+  Nothing -> Left "Missing form field value"+  Just (FormParam p) -> do+    case readMaybe (cs p) of+      Nothing -> Left "Could not read form field"+      Just a -> pure a+  Just (FileParam _) ->+    Left "Cannot read uploaded file as param"+++instance FromField Int where+  fromField Nothing = pure 0+  fromField (Just "") = pure 0+  fromField (Just t) = readField (Just t)+instance FromField Integer where+  fromField Nothing = pure 0+  fromField (Just "") = pure 0+  fromField (Just t) = readField (Just t)+instance FromField Float where+  fromField Nothing = pure 0+  fromField (Just "") = pure 0+  fromField (Just t) = readField (Just t)+instance FromField Double where+  fromField Nothing = pure 0+  fromField (Just "") = pure 0+  fromField (Just t) = readField (Just t)+++instance FromField Bool where+  fromField Nothing = pure False+  fromField (Just (FileParam _)) = Left "Cannot parse file param as bool"+  fromField (Just (FormParam p)) =+    case p of+      "on" -> pure True+      "off" -> pure False+      "" -> pure False+      "false" -> pure False+      "true" -> pure True+      other -> Left $ "Could not parse bool form param: " <> cs other+instance FromField Char where+  fromField Nothing = Left "Missing form field value"+  fromField (Just (FileParam _)) = Left "Cannot parse file param as Char"+  fromField (Just (FormParam t)) =+    case cs t of+      (c : _) -> pure c+      _ -> Left "Could not parse empty form field as char"+instance FromField UTCTime where+  fromField = readField+instance FromField URI where+  fromField = \case+    Nothing -> Left "Missing form field value"+    Just (FileParam _) -> Left "Cannot parse file param as Char"+    Just (FormParam t) ->+      case parseURIReference (cs t) of+        Nothing -> Left "Invalid URI"+        Just a -> pure a+instance FromField String where+  fromField t = second cs $ fromField @Text t+instance FromField BS.ByteString where+  fromField t = second cs $ fromField @Text t+instance FromField Text where+  fromField = \case+    Nothing -> pure ""+    Just (FormParam t) -> pure t+    Just (FileParam _) -> Left "Cannot parse FileParam as Text"+++instance {-# OVERLAPPABLE #-} (FromField a) => FromField (Maybe a) where+  fromField Nothing = pure Nothing+  fromField (Just "") = pure Nothing+  fromField (Just a) = Just <$> fromField @a (Just a)+instance {-# OVERLAPS #-} FromField (Maybe BS.ByteString) where+  fromField Nothing = pure Nothing+  fromField (Just "") = pure $ Just ""+  fromField (Just a) = Just <$> fromField @BS.ByteString (Just a)+instance {-# OVERLAPS #-} FromField (Maybe Text) where+  fromField Nothing = pure Nothing+  fromField (Just "") = pure $ Just ""+  fromField (Just a) = Just <$> fromField @Text (Just a)+instance {-# OVERLAPS #-} FromField (Maybe String) where+  fromField Nothing = pure Nothing+  fromField (Just "") = pure $ Just ""+  fromField (Just a) = Just <$> fromField @String (Just a)+instance {-# OVERLAPPABLE #-} (FromField a, FromField b) => FromField (Either a b) where+  fromField = \case+    Nothing -> Left "Missing form field value"+    Just p ->+      case fromField @a (Just p) of+        Right a -> pure $ Left a+        Left _ -> pure <$> fromField @b (Just p)+instance FromField UploadedFile where+  fromField = \case+    Nothing -> Left "Missing file upload"+    Just (FormParam "") -> Left "Missing file upload"+    Just (FormParam t) -> Left $ "Cannot parse FormParam as UploadedFile: " <> cs t+    Just (FileParam f) ->+      if f.fileName == mempty+        then Left "Empty file uploaded"+        else pure f+instance {-# OVERLAPS #-} FromField (Maybe UploadedFile) where+  fromField = \case+    Nothing -> pure Nothing+    Just (FileParam f) -> do+      if f.fileName == mempty+        then pure Nothing+        else pure $ Just f+    other -> fromField other+++-- these instances don't make a lot of sense+-- instance (FromField a, FromField b) => FromField (a, b)+-- instance (FromField a, FromField b, FromField c) => FromField (a, b, c)+-- instance {-# OVERLAPPABLE #-} (FromParam a) => FromField [a]+-- instance FromField Value+-- instance FromField Word+-- instance FromField Word8+-- instance FromField Word16+-- instance FromField Word32+-- instance FromField Word64++------------------------------------------------------------------------------ -- GENERIC FORM PARSE ------------------------------------------------------------------------------  class GFormParse f where-  gFormParse :: FE.Form -> Either String (f p)+  gFormParse :: Form -> Either String (f p)   instance (GFormParse f, GFormParse g) => GFormParse (f :*: g) where@@ -413,23 +584,90 @@   gFormParse f = M1 <$> gFormParse f  --- TODO: need a bool instance?--- TODO: need a Maybe a instance?-instance (Selector s, FromParam a) => GFormParse (M1 S s (K1 R a)) where-  -- these CANNOT be json encoded, they are encoded by the browser+instance (Selector s, FromField a) => GFormParse (M1 S s (K1 R a)) where   gFormParse f = do     let sel = selName (undefined :: M1 S s (K1 R (f a)) p)-    mt :: Maybe Text <- first cs $ FE.lookupMaybe (cs sel) f-    a <- first (\err -> sel <> ": " <> err) $ decodeFormValue mt-    pure $ M1 . K1 $ a+    a <- parseField (cs sel) f+    pure $ M1 $ K1 a  --- instance {-# OVERLAPPING #-} (Selector s, FromParam a) => GFormParse (M1 S s (K1 R (Maybe a))) where---   gFormParse f = do---     let sel = selName (undefined :: M1 S s (K1 R (f a)) p)---     mt :: Maybe Text <- first cs $ FE.lookupMaybe (cs sel) f---     ma :: Maybe a <- maybe (pure Nothing) (parseParam . decodeParam) mt---     pure $ M1 . K1 $ ma+-- class GFieldParse f where+--   gFieldParse :: String -> Maybe ParamValue -> Either String (f p)+--+--+-- instance {-# OVERLAPPABLE #-} (FromJSON a) => GFieldParse (K1 R a) where+--   gFieldParse sel Nothing = Left $ "Missing form field: " <> sel+--   gFieldParse _ (Just (ParamText t)) = K1 <$> decodeArgument t+--   gFieldParse sel (Just _) = Left $ "Unexpected file param: " <> sel+--+--+-- instance {-# OVERLAPS #-} (GFieldParse (K1 R a)) => GFieldParse (K1 R (Maybe a)) where+--   gFieldParse _ Nothing = pure $ K1 Nothing+--   gFieldParse _ (Just (ParamText "")) = pure $ K1 Nothing -- an empty string should be Nothing unless overriden+--   gFieldParse sel (Just p) = do+--     K1 a <- gFieldParse @(K1 R a) sel (Just p)+--     pure $ K1 $ Just a+--+--+-- instance {-# OVERLAPS #-} GFieldParse (K1 R Bool) where+--   gFieldParse _ Nothing = pure $ K1 False+--   gFieldParse sel (Just t) = do+--     K1 <$> case t of+--       "on" -> pure True+--       "off" -> pure False+--       "" -> pure False+--       "false" -> pure False+--       "true" -> pure True+--       ParamText other -> Left $ "Could not parse bool field: " <> sel <> " = " <> cs other+--       ParamFile _ -> Left $ "Unexpected file param: " <> sel+--+--+-- instance {-# OVERLAPS #-} GFieldParse (K1 R (Maybe Text)) where+--   gFieldParse _ Nothing = pure $ K1 Nothing+--   gFieldParse sel inp = do+--     K1 t <- gFieldParse @(K1 R Text) sel inp+--     pure $ K1 $ Just t+--+--+-- instance {-# OVERLAPS #-} GFieldParse (K1 R Text) where+--   gFieldParse _ Nothing = pure $ K1 ""+--   gFieldParse _ (Just "") = pure $ K1 ""+--   gFieldParse _ (Just (ParamText t)) = K1 <$> decodeArgument ("\"" <> t <> "\"")+--   gFieldParse sel (Just _) = Left $ "Unexpected file param: " <> sel+--+--+-- instance {-# OVERLAPS #-} GFieldParse (K1 R Int) where+--   gFieldParse _ Nothing = pure $ K1 0+--   gFieldParse _ (Just "") = pure $ K1 0+--   gFieldParse _ (Just (ParamText t)) = K1 <$> decodeArgument t+--   gFieldParse sel (Just _) = Left $ "Unexpected file param: " <> sel+--+--+-- instance {-# OVERLAPS #-} GFieldParse (K1 R Integer) where+--   gFieldParse _ Nothing = pure $ K1 0+--   gFieldParse _ (Just "") = pure $ K1 0+--   gFieldParse _ (Just (ParamText t)) = K1 <$> decodeArgument t+--   gFieldParse sel (Just _) = Left $ "Unexpected file param: " <> sel+--+--+-- instance {-# OVERLAPS #-} GFieldParse (K1 R Float) where+--   gFieldParse _ Nothing = pure $ K1 0+--   gFieldParse _ (Just "") = pure $ K1 0+--   gFieldParse _ (Just (ParamText t)) = K1 <$> decodeArgument t+--   gFieldParse sel (Just _) = Left $ "Unexpected file param: " <> sel+--+--+-- instance {-# OVERLAPS #-} GFieldParse (K1 R Double) where+--   gFieldParse _ Nothing = pure $ K1 0+--   gFieldParse _ (Just "") = pure $ K1 0+--   gFieldParse _ (Just (ParamText t)) = K1 <$> decodeArgument t+--   gFieldParse sel (Just _) = Left $ "Unexpected file param: " <> sel+--+--+-- instance {-# OVERLAPS #-} GFieldParse (K1 R UploadedFile) where+--   gFieldParse sel Nothing = Left $ "Missing form field: " <> sel+--   gFieldParse _ (Just (ParamFile f)) = Right $ K1 f+--   gFieldParse sel (Just (ParamText _)) = Left $ "Unexpected text param: " <> sel  ------------------------------------------------------------------------------ -- GENERIC GENERATE FIELDS
src/Web/Hyperbole/HyperView/Handled.hs view
@@ -91,8 +91,7 @@ -- TODO: Report which view requires the missing one type family CheckDescendents id ctx :: Constraint where   CheckDescendents id (Root total) =-    ( AllInPage (ValidDescendents id) total-    )+    (AllInPage (ValidDescendents id) total)   CheckDescendents id ctx = ()  
src/Web/Hyperbole/HyperView/Hyper.hs view
@@ -2,6 +2,9 @@  module Web.Hyperbole.HyperView.Hyper where +import Data.Aeson (ToJSON)+import Data.Aeson qualified as A+import Data.String.Conversions (cs) import Web.Atomic.Types import Web.Hyperbole.Data.Encoded as Encoded import Web.Hyperbole.HyperView.Handled (HyperViewHandled)@@ -25,9 +28,15 @@ hyper vid = hyperState vid ()  +{- | Embed a 'HyperView' into a page or another 'View' with a starting 'ViewState'++@+#EMBED Example.State.ViewState page+@+-} hyperState   :: forall id ctx-   . (HyperViewHandled id ctx, ViewId id, ToEncoded (ViewState id), ConcurrencyValue (Concurrency id))+   . (HyperViewHandled id ctx, ViewId id, ToJSON (ViewState id), ConcurrencyValue (Concurrency id))   => id   -> ViewState id   -> View id ()@@ -35,7 +44,7 @@ hyperState = hyperUnsafe  -hyperUnsafe :: forall id ctx. (ViewId id, ViewState id ~ ViewState id, ToEncoded (ViewState id), ConcurrencyValue (Concurrency id)) => id -> ViewState id -> View id () -> View ctx ()+hyperUnsafe :: forall id ctx. (ViewId id, ViewState id ~ ViewState id, ToJSON (ViewState id), ConcurrencyValue (Concurrency id)) => id -> ViewState id -> View id () -> View ctx () hyperUnsafe vid st vw = do   tag "div" @ att "id" (encodedToText $ toViewId vid) . state . concurrency $     runViewContext vid st vw@@ -46,6 +55,7 @@       Replace -> att "data-concurrency" (encode Replace)    state =-    if encode st == mempty-      then id-      else att "data-state" (encode st)+    let enc = A.encode st+     in if enc == mempty+          then id+          else att "data-state" (cs enc)
src/Web/Hyperbole/HyperView/Input.hs view
@@ -1,10 +1,14 @@+{-# LANGUAGE DefaultSignatures #-}+{-# LANGUAGE UndecidableInstances #-}+ module Web.Hyperbole.HyperView.Input where +import Data.Aeson (FromJSON, ToJSON) import Data.String.Conversions (cs) import Data.Text (Text) import GHC.Generics (Generic) import Web.Atomic.Types-import Web.Hyperbole.Data.Param (FromParam, ParamValue (..), ToParam (..))+import Web.Hyperbole.Data.Argument (decodeArgument, encodeArgument) import Web.Hyperbole.HyperView.Event (DelayMs, onChange, onClick, onInput) import Web.Hyperbole.HyperView.Types (HyperView (..)) import Web.Hyperbole.Route (Route (..), routeUri)@@ -30,8 +34,8 @@ -} dropdown   :: forall opt id-   . (ViewAction (Action id))-  => (opt -> Action id)+   . (ViewAction (Action id), FromJSON opt)+  => Action id   -> opt -- default option   -> View (Option id opt) ()   -> View id ()@@ -45,15 +49,23 @@ -- | An option for a 'dropdown' or 'select' option   :: forall opt id-   . (ViewAction (Action id), Eq opt, ToParam opt)+   . (ViewAction (Action id), Eq opt, ToJSON opt)   => opt   -> Text   -> View (Option id opt) () option opt cnt = do   os :: Option id opt <- viewId-  tag "option" @ att "value" (toParam opt).value @ selected (os.defaultOption == opt) $ text cnt+  tag "option" @ att "value" (encodeOption opt) @ selected (os.defaultOption == opt) $ text cnt  +encodeOption :: (ToJSON opt) => opt -> Text+encodeOption opt =+  case encodeArgument opt of+    -- For options, an empty string makes much more sense than null for empty values+    "null" -> ""+    other -> other++ -- | sets selected = true if the 'dropdown' predicate returns True selected :: (Attributable h) => Bool -> Attributes h -> Attributes h selected b = if b then att "selected" "true" else id@@ -67,7 +79,7 @@   deriving (Generic)  -instance (ToParam id, ToParam opt, FromParam id, FromParam opt) => ViewId (Option id opt) where+instance (ToJSON id, ToJSON opt, FromJSON id, FromJSON opt) => ViewId (Option id opt) where   type ViewState (Option id opt) = ViewState id  @@ -77,7 +89,7 @@ #EMBED Example.Errors viewSearchUsers @ -}-search :: (ViewAction (Action id)) => (Text -> Action id) -> DelayMs -> View id ()+search :: (ViewAction (Action id)) => Action id -> DelayMs -> View id () search go delay = do   tag "input" none @ onInput go delay @@ -96,3 +108,47 @@ -} route :: (Route a) => a -> View c () -> View c () route r = link (routeUri r)+++-- instance {-# OVERLAPPABLE #-} (FromJSON a) => UserInput (Maybe a) where+--   parseInput "" = pure Nothing+--   parseInput t = pure $ A.decode (cs t)+--+--+-- instance {-# OVERLAPS #-} UserInput (Maybe Text) where+--   parseInput = pure . Just++class InputValue a where+  parseInputValue :: Text -> Either String a+  default parseInputValue :: (FromJSON a) => Text -> Either String a+  parseInputValue = decodeArgument+++instance InputValue Text where+  parseInputValue = pure+instance InputValue Int where+  parseInputValue "" = Right 0+  parseInputValue t = decodeArgument t+instance InputValue Float where+  parseInputValue "" = Right 0+  parseInputValue t = decodeArgument t+instance InputValue Double where+  parseInputValue "" = Right 0+  parseInputValue t = decodeArgument t+instance InputValue Integer where+  parseInputValue "" = Right 0+  parseInputValue t = decodeArgument t+++instance {-# OVERLAPPABLE #-} (InputValue a) => InputValue (Maybe a) where+  parseInputValue "null" = pure Nothing+  parseInputValue "" = pure Nothing+  parseInputValue t = Just <$> parseInputValue t+++instance {-# OVERLAPS #-} InputValue (Maybe Text) where+  parseInputValue t = pure $ Just t+++instance {-# OVERLAPS #-} InputValue (Maybe String) where+  parseInputValue t = pure $ Just (cs t)
src/Web/Hyperbole/HyperView/Types.hs view
@@ -27,16 +27,18 @@ @ -} class (ViewId id, ViewAction (Action id), ConcurrencyValue (Concurrency id)) => HyperView id es where-  -- | Outline all actions that are permitted in this HyperView-  ---  -- > data Action Message = SetMessage Text | ClearMessage-  -- >   deriving (Generic, ViewAction)+  {- | Outline all actions that are permitted in this HyperView++  > data Action Message = SetMessage Text | ClearMessage+  >   deriving (Generic, ViewAction)+  -}   data Action id  -  -- | Include any child hyperviews here. The compiler will make sure that the page knows how to handle them-  ---  -- > type Require Messages = '[ChildView]+  {- | Include any child hyperviews here. The compiler will make sure that the page knows how to handle them++  > type Require Messages = '[ChildView]+  -}   type Require id :: [Type]  @@ -46,19 +48,21 @@   -- type ViewState id :: Type   -- type ViewState id = () -  -- | Control how overlapping actions are handled. 'Drop' by default-  ---  -- > type Concurrency Autocomplete = Replace+  {- | Control how overlapping actions are handled. 'Drop' by default++  > type Concurrency Autocomplete = Replace+  -}   type Concurrency id :: ConcurrencyMode     type Concurrency id = Drop  -  -- | Specify how the view should be updated for each Action-  ---  -- > update (SetMessage msg) = pure $ messageView msg-  -- > update ClearMessage = pure $ messageView ""+  {- | Specify how the view should be updated for each Action++  > update (SetMessage msg) = pure $ messageView msg+  > update ClearMessage = pure $ messageView ""+  -}   update :: (Hyperbole :> es) => Action id -> Eff (Reader id : State (ViewState id) : es) (View id ())  
src/Web/Hyperbole/Server/Handler.hs view
@@ -3,6 +3,8 @@  module Web.Hyperbole.Server.Handler where +import Data.Aeson (FromJSON, ToJSON, Value)+import Data.Aeson qualified as A import Data.Kind (Type) import Effectful import Effectful.Dispatch.Dynamic@@ -10,7 +12,7 @@ import Effectful.State.Dynamic import Web.Hyperbole.Data.Encoded import Web.Hyperbole.Effect.Hyperbole-import Web.Hyperbole.Effect.Response (hyperView, respondError)+import Web.Hyperbole.Effect.Response (hyperView, parseError, respondError) import Web.Hyperbole.HyperView import Web.Hyperbole.Types.Event import Web.Hyperbole.Types.Request@@ -19,14 +21,14 @@   class RunHandlers (views :: [Type]) es where-  runHandlers :: (Hyperbole :> es) => Event TargetViewId Encoded Encoded -> Eff es (Maybe Response)+  runHandlers :: (Hyperbole :> es) => Event TargetViewId Encoded Value -> Eff es (Maybe Response)   instance RunHandlers '[] es where   runHandlers _ = pure Nothing  -instance (HyperView view es, ToEncoded (ViewState view), FromEncoded (ViewState view), RunHandlers views es) => RunHandlers (view : views) es where+instance (HyperView view es, ToJSON (ViewState view), FromJSON (ViewState view), RunHandlers views es) => RunHandlers (view : views) es where   runHandlers rawEvent = do     mr <- runHandler @view rawEvent (update @view)     case mr of@@ -36,8 +38,8 @@  runHandler   :: forall id es-   . (HyperView id es, ToEncoded (ViewState id), FromEncoded (ViewState id), Hyperbole :> es)-  => Event TargetViewId Encoded Encoded+   . (HyperView id es, ToJSON (ViewState id), FromJSON (ViewState id), Hyperbole :> es)+  => Event TargetViewId Encoded Value   -> (Action id -> Eff (Reader id : State (ViewState id) : es) (View id ()))   -> Eff es (Maybe Response) runHandler rawEvent run = do@@ -79,10 +81,21 @@   -- despite not needing any effects, this must be in Eff es to get `es` on the RHS-decodeEvent :: forall id es. (HyperView id es, FromEncoded (ViewState id)) => Event TargetViewId Encoded Encoded -> Eff es (Maybe (Event id (Action id) (ViewState id)))+decodeEvent :: forall id es. (HyperView id es, FromJSON (ViewState id), Hyperbole :> es) => Event TargetViewId Encoded Value -> Eff es (Maybe (Event id (Action id) (ViewState id))) decodeEvent (Event (TargetViewId ti) eact est) =-  pure $ either (const Nothing) Just $ do-    vid <- parseViewId ti-    act <- parseAction eact-    st <- parseEncoded est-    pure $ Event vid act st+  -- First, parse the view id. These should be unique on each page+  case parseViewId ti of+    Left _ -> pure Nothing+    Right vid -> do+      -- Then if parsing the state or action fails, throw an erro+      either parseError (pure . Just) $ do+        act <- parseAction eact+        st <- parseState est+        pure $ Event vid act st+++parseState :: (FromJSON a) => Value -> Either String a+parseState v =+  case A.fromJSON v of+    A.Success a -> pure a+    A.Error e -> Left e
src/Web/Hyperbole/Server/Message.hs view
@@ -4,8 +4,11 @@  import Control.Applicative ((<|>)) import Control.Exception (Exception)+import Data.Aeson (Value (Null)) import Data.Aeson qualified as Aeson-import Data.Attoparsec.Text (Parser, char, endOfLine, isEndOfLine, parseOnly, sepBy, string, takeText, takeTill, takeWhile1)+import Data.Aeson.Parser (json)+import Data.Attoparsec.ByteString.Char8 (Parser, char, endOfLine, isEndOfLine, parseOnly, sepBy, string, takeLazyByteString, takeWhile1)+import Data.Attoparsec.ByteString.Lazy (takeTill) import Data.ByteString qualified as BS import Data.ByteString.Lazy qualified as BL import Data.List qualified as L@@ -39,7 +42,7 @@  data Message = Message   { messageType :: Text-  , event :: Event TargetViewId Encoded Encoded+  , event :: Event TargetViewId Encoded Value   , requestId :: RequestId   , metadata :: Metadata   , body :: MessageBody@@ -64,7 +67,7 @@ mimeType = "application/hyperbole.message"  -parseActionMessage :: Text -> Either String Message+parseActionMessage :: BS.ByteString -> Either String Message parseActionMessage = parseOnly parser  where   parser :: Parser Message@@ -82,17 +85,17 @@     t <- takeWhile1 (/= '|')     _ <- char '|'     endOfLine-    pure t+    pure $ cs t    body :: Parser MessageBody   body = do-    MessageBody . cs . T.strip <$> takeText+    MessageBody . cs . T.strip . cs <$> takeLazyByteString -  event :: Parser (Event TargetViewId Encoded Encoded)+  event :: Parser (Event TargetViewId Encoded Value)   event = do     vid <- targetViewId     act <- encodedAction-    st <- encodedState <|> pure mempty+    st <- encodedState <|> pure Null     pure $ Event vid act st    where     targetViewId :: Parser TargetViewId@@ -115,13 +118,10 @@       endOfLine       pure v -    encodedState :: Parser Encoded+    encodedState :: Parser Value     encodedState = do       _ <- string "State: "-      inp <- takeLine-      v <- case encodedParseText inp of-        Left e -> fail $ "Parse Encoded ViewState failed: " <> cs e <> " from " <> cs inp-        Right a -> pure a+      v <- json       endOfLine       pure v @@ -142,11 +142,11 @@   metaKey = do     key <- takeWhile1 (/= ':')     _ <- string ": "-    pure key+    pure $ cs key    takeLine :: Parser Text   takeLine = do-    takeTill isEndOfLine+    cs <$> takeTill isEndOfLine   -- Render ---------------------------------------------@@ -192,7 +192,7 @@   metaRequestId (RequestId reqId) =     metadata "RequestId" (cs reqId) -  eventMetadata :: Event TargetViewId Encoded Encoded -> Metadata+  eventMetadata :: Event TargetViewId Encoded state -> Metadata   eventMetadata event =     Metadata       [ ("ViewId", encodedToText event.viewId.encoded)
src/Web/Hyperbole/Server/Options.hs view
@@ -1,11 +1,19 @@ {-# LANGUAGE LambdaCase #-} -module Web.Hyperbole.Server.Options where+module Web.Hyperbole.Server.Options+  ( ServerOptions (..)+  , defaultErrorMessage+  , defaultErrorBody+  , defaultError+  , defaultParseRequestBodyOptions+  ) where +import Data.Aeson (Value) import Data.ByteString.Lazy qualified as BL import Data.String.Conversions (cs) import Data.Text (Text) import Data.Text qualified as T+import Network.Wai.Parse as Wai (ParseRequestBodyOptions, defaultParseRequestBodyOptions) import Web.Atomic.CSS import Web.Hyperbole.Data.Encoded (Encoded, encodedToText) import Web.Hyperbole.Types.Event@@ -16,6 +24,7 @@ data ServerOptions = ServerOptions   { toDocument :: BL.ByteString -> BL.ByteString   , serverError :: ResponseError -> ServerError+  , parseRequestBody :: ParseRequestBodyOptions   }  @@ -44,7 +53,7 @@     let msg = defaultErrorMessage err      in ServerError msg (defaultErrorBody msg)  where-  errNotHandled :: Event TargetViewId Encoded Encoded -> ServerError+  errNotHandled :: Event TargetViewId Encoded Value -> ServerError   errNotHandled ev =     ServerError "Action Not Handled" $ Body $ renderLazyByteString $ do       el $ do
src/Web/Hyperbole/Server/Socket.hs view
@@ -2,7 +2,7 @@  module Web.Hyperbole.Server.Socket where -import Control.Monad (void)+import Control.Monad (void, when) import Data.Aeson (Value) import Data.Bifunctor (first) import Data.List qualified as L@@ -14,7 +14,7 @@ import Data.Text (Text) import Effectful import Effectful.Concurrent.Async-import Effectful.Concurrent.STM (TVar, atomically, modifyTVar, readTVar, writeTVar)+import Effectful.Concurrent.STM (STM, TVar, atomically, modifyTVar, readTVar, writeTVar) import Effectful.Dispatch.Dynamic import Effectful.Error.Static (throwError_) import Effectful.Exception@@ -41,7 +41,7 @@   }  -type RunningActions = Map TargetViewId (Encoded, Async ())+type RunningActions = Map TargetViewId (Encoded, RequestId, Async ())   runHyperboleSocket@@ -82,12 +82,11 @@     req <- parseMessageRequest msg      a <- async $ do-      -- is one already running?       res <- trySync $ runHyperboleSocket opts conn req eff       case res of         -- TODO: catch socket errors separately from SomeException?         Left (ex :: SomeException) -> do-          -- It's not safe to send any exception over the wire+          -- It's not safe to send SomeException over the wire           -- log it to the console and send the error to the client           liftIO $ print ex           res2 <- trySync $ sendError conn (requestMetadata req) (opts.serverError ErrInternal)@@ -108,28 +107,45 @@       _ <- waitCatch a       clearRunningAction req.requestId req.event  where-  addRunningAction :: (IOE :> es, Concurrent :> es) => Async () -> RequestId -> Maybe (Event TargetViewId Encoded Encoded) -> Eff es ()-  addRunningAction a (RequestId reqId) = \case+  addRunningAction :: (IOE :> es, Concurrent :> es) => Async () -> RequestId -> Maybe (Event TargetViewId Encoded Value) -> Eff es ()+  addRunningAction a reqId = \case     Nothing -> pure ()     Just (Event vid act _) -> do       -- liftIO $ putStrLn $ " [add] (" <> cs reqId <> ") " <> cs clientId.value <> "|" <> show vid       maold <- atomically $ do+        -- NOTE: actions is unique per-client, which is why it doesn't require a client id         m <- readTVar @RunningActions actions-        writeTVar actions $ M.insert vid (act, a) m+        writeTVar actions $ M.insert vid (act, reqId, a) m         pure $ M.lookup vid m       case maold of-        Nothing -> pure ()-        Just (actold, aold) -> do-          liftIO $ putStrLn $ "CANCEL (" <> cs reqId <> ") " <> cs (encodedToText vid.encoded) <> ": " <> cs (encodedToText actold)+        Nothing -> do+          -- liftIO $ putStrLn $ "nocancel " <> show vid+          pure ()+        Just (actold, RequestId rold, aold) -> do+          liftIO $ putStrLn $ "CANCEL (" <> cs rold <> ") " <> cs (encodedToText vid.encoded) <> ": " <> cs (encodedToText actold)           cancel aold -  clearRunningAction :: (IOE :> es, Concurrent :> es) => RequestId -> Maybe (Event TargetViewId Encoded Encoded) -> Eff es ()-  clearRunningAction (RequestId _) = \case+  clearRunningAction :: (IOE :> es, Concurrent :> es) => RequestId -> Maybe (Event TargetViewId Encoded Value) -> Eff es ()+  clearRunningAction reqId = \case     Nothing -> pure ()-    Just (Event vid _ _) -> do-      _ <- atomically $ modifyTVar actions $ M.delete vid-      pure ()+    Just (Event vid _ _) -> atomically $ do+      active <- isActiveRequestId vid reqId+      when active $ do+        _ <- modifyTVar actions $ M.delete vid+        pure () +  activeRequestId :: TargetViewId -> STM (Maybe RequestId)+  activeRequestId vid = do+    m <- readTVar actions+    pure $ do+      (_, r, _) <- M.lookup vid m+      pure r++  isActiveRequestId :: TargetViewId -> RequestId -> STM Bool+  isActiveRequestId vid reqId = do+    r <- activeRequestId vid+    pure $ r == Just reqId+   onMessageError :: (IOE :> es) => MessageError -> Eff es a   onMessageError e = do     liftIO $ do@@ -139,7 +155,7 @@   receiveMessage :: (IOE :> es) => Eff es Message   receiveMessage = do     t <- receiveText conn-    case parseActionMessage t of+    case parseActionMessage (cs t) of       Left e -> throwIO $ InvalidMessage e t       Right msg -> pure msg @@ -161,7 +177,8 @@         headers = Wai.requestHeaders wreq         method = "POST" -        body = msg.body.value+    -- Parse params as url encoded, ignore files+    let body = cs msg.body.value      query <- HTTP.parseQuery . cs <$> requireMeta "Query" msg.metadata     cookie <- cs <$> requireMeta "Cookie" msg.metadata@@ -174,7 +191,8 @@         , event = Just msg.event         , host         , query-        , body+        , form = Form mempty mempty+        , input = body         , method         , cookies         , requestId = msg.requestId
+ src/Web/Hyperbole/Server/Uploads.hs view
@@ -0,0 +1,34 @@+module Web.Hyperbole.Server.Uploads where++import Control.Monad.Trans.Resource (InternalState, closeInternalState, createInternalState)+import Data.String.Conversions (cs)+import Effectful+import Effectful.Exception (bracket)+import Network.Wai qualified as Wai+import Network.Wai.Parse (File, FileInfo (..), ParseRequestBodyOptions)+import Network.Wai.Parse qualified as Wai+import Web.Hyperbole.Types.Request (FileParam, Param, UploadedFile (..))+++withPostBody :: (IOE :> es) => ParseRequestBodyOptions -> Wai.Request -> ([Param] -> [FileParam] -> Eff es a) -> Eff es a+withPostBody options req action = withUploadState $ \state -> do+  (params, files) <- acceptFileUploads state+  action params $ fmap fileParam files+ where+  withUploadState :: (IOE :> es) => (InternalState -> Eff es a) -> Eff es a+  withUploadState = bracket createInternalState closeInternalState++  acceptFileUploads :: (IOE :> es) => InternalState -> Eff es ([Param], [File FilePath])+  acceptFileUploads state = do+    liftIO $ Wai.parseRequestBodyEx options (Wai.tempFileBackEnd state) req++  fileParam :: Wai.File FilePath -> FileParam+  fileParam (key, f) = (key, fileInfo f)++  fileInfo :: Wai.FileInfo FilePath -> UploadedFile+  fileInfo FileInfo{fileName, fileContentType, fileContent} =+    UploadedFile+      { filePath = fileContent+      , fileName = cs fileName+      , contentType = cs fileContentType+      }
src/Web/Hyperbole/Server/Wai.hs view
@@ -3,6 +3,8 @@  module Web.Hyperbole.Server.Wai where +import Data.Aeson (Value)+import Data.Aeson qualified as A import Data.Bifunctor (first) import Data.ByteString qualified as BS import Data.ByteString.Lazy qualified as BL@@ -28,6 +30,7 @@ import Web.Hyperbole.Effect.Hyperbole import Web.Hyperbole.Server.Message import Web.Hyperbole.Server.Options+import Web.Hyperbole.Server.Uploads (withPostBody) import Web.Hyperbole.Types.Client import Web.Hyperbole.Types.Event (Event (..), TargetViewId (..)) import Web.Hyperbole.Types.Request@@ -43,17 +46,19 @@   -> Eff (Hyperbole : es) Response   -> Eff es Wai.ResponseReceived handleRequestWai options req respond actions = do-  -- NOTE: Remember, this is called for both updates AND for page loads-  body <- liftIO $ Wai.consumeRequestBodyLazy req-  rq <- either throwIO pure $ do-    fromWaiRequest req body-  (res, client, rmts) <- runHyperboleWai rq actions-  liftIO $ sendResponse options rq client res rmts respond+  -- NOTE: Remember, this is called for both updates AND for page loads. We don't have to worry about anything the socket connection is doing+  -- in particular, the socket connection sends a plain text body for input.value, but we don't care here+  withPostBody options.parseRequestBody req $ \params files -> do+    rq <- either throwIO pure $ do+      fromWaiRequest req (Form params files)+    (res, client, rmts) <- runHyperboleWai rq actions+    liftIO $ sendResponse options rq client res rmts respond   -- | Run the 'Hyperbole' effect to get a response runHyperboleWai-  :: Request+  :: (IOE :> es)+  => Request   -> Eff (Hyperbole : es) Response   -> Eff es (Response, Client, [Remote]) runHyperboleWai req = reinterpret (runHyperboleLocal req) $ \_ -> \case@@ -85,7 +90,8 @@   response :: Metadata -> Response -> Wai.Response   response metas = \case     (Err err) ->-      respondError (errStatus err) [] $ options.serverError err+      -- don't send headers+      respondError (errStatus err) [] metas $ options.serverError err     (Response (ViewUpdate _ vw)) -> do       respondHtml status200 (clientHeaders client) $ renderViewResponse metas vw     (Redirect u) -> do@@ -114,7 +120,7 @@   renderViewResponse metas (Body body) =     addDocument $ renderLazyByteString (runViewContext metas () $ scriptMeta metas) <> "\n\n" <> body -  respondError s hs serr = respondHtml s hs $ renderViewResponse (metaError serr.message) serr.body+  respondError s hs metas serr = respondHtml s hs $ renderViewResponse (metaError serr.message <> metas) serr.body   respondHtml s hs = Wai.responseLBS s (contentType ContentHtml : hs)   -- respondText s hs = Wai.responseLBS s (contentType ContentText : hs) @@ -142,8 +148,8 @@   first (\e -> InvalidMessage e (cs inp)) $ parseActionMessage (cs inp)  -fromWaiRequest :: Wai.Request -> BL.ByteString -> Either MessageError Request-fromWaiRequest wr body = do+fromWaiRequest :: Wai.Request -> Form -> Either MessageError Request+fromWaiRequest wr form = do   let pth = path $ cs $ Wai.rawPathInfo wr       query = Wai.queryString wr       headers = Wai.requestHeaders wr@@ -156,24 +162,25 @@    pure $     Request-      { body = body-      , path = pth+      { path = pth       , event       , query       , method       , cookies       , host+      , form+      , input = ""       , requestId       }  where-  lookupEvent :: [Header] -> Maybe (Event TargetViewId Encoded Encoded)+  lookupEvent :: [Header] -> Maybe (Event TargetViewId Encoded Value)   lookupEvent headers = do     viewIdText <- cs <$> L.lookup "Hyp-ViewId" headers     actText <- cs <$> L.lookup "Hyp-Action" headers     stText <- cs <$> L.lookup "Hyp-State" headers     act <- decode actText     viewId <- TargetViewId <$> decode viewIdText-    st <- decode stText+    st <- A.decode stText     pure $ Event viewId act st  
src/Web/Hyperbole/Types/Request.hs view
@@ -1,9 +1,22 @@-module Web.Hyperbole.Types.Request where+module Web.Hyperbole.Types.Request+  ( Request (..)+  , Host (..)+  , Form (..)+  , FormParam (..)+  , Param+  , FileParam+  , File+  , RequestId (..)+  , UploadedFile (..)+  ) where +import Data.Aeson (Value) import Data.ByteString qualified as BS-import Data.ByteString.Lazy qualified as BL+import Data.String (IsString (..))+import Data.String.Conversions (cs) import Data.Text (Text) import Network.HTTP.Types (Method)+import Network.Wai.Parse (File, Param) import Web.Hyperbole.Data.Cookie (Cookies) import Web.Hyperbole.Data.Encoded import Web.Hyperbole.Data.URI (Path, Query)@@ -14,18 +27,46 @@   deriving (Show)  +data UploadedFile = UploadedFile+  { filePath :: FilePath+  , fileName :: Text -- the original file name+  , contentType :: Text -- the mime type+  }+  deriving (Show, Eq)+++type FileParam = (BS.ByteString, UploadedFile)++ data Request = Request   { host :: Host   , path :: Path   , query :: Query-  , body :: BL.ByteString   , method :: Method   , cookies :: Cookies-  , event :: Maybe (Event TargetViewId Encoded Encoded)+  , event :: Maybe (Event TargetViewId Encoded Value)   , requestId :: RequestId+  , form :: Form+  , input :: Text   }   deriving (Show)  -newtype RequestId = RequestId Text+data Form = Form+  { params :: [Param]+  , files :: [FileParam]+  }   deriving (Show)+++data FormParam+  = FormParam Text+  | FileParam UploadedFile+  deriving (Show, Eq)+instance IsString FormParam where+  fromString s = FormParam (cs s)+++newtype RequestId = RequestId Text+  deriving (Show, Eq)+
src/Web/Hyperbole/Types/Response.hs view
@@ -2,6 +2,7 @@  module Web.Hyperbole.Types.Response where +import Data.Aeson (Value) import Data.ByteString.Lazy qualified as BL import Data.String (IsString (..)) import Data.String.Conversions (cs)@@ -32,7 +33,7 @@   | ErrServer Text   | ErrCustom ServerError   | ErrInternal-  | ErrNotHandled (Event TargetViewId Encoded Encoded)+  | ErrNotHandled (Event TargetViewId Encoded Value)   | ErrAuth Text instance Show ResponseError where   show = \case
src/Web/Hyperbole/View/Types.hs view
@@ -1,7 +1,9 @@ {-# LANGUAGE AllowAmbiguousTypes #-}+{-# LANGUAGE UndecidableInstances #-}  module Web.Hyperbole.View.Types where +import Data.Aeson (FromJSON, ToJSON) import Data.String (IsString (..)) import Data.Text (Text, pack) import Effectful@@ -11,8 +13,7 @@ import Web.Atomic.Html (Html (..)) import Web.Atomic.Html qualified as Atomic import Web.Atomic.Types-import Web.Hyperbole.Data.Encoded (decodeEither, encodedToText)-import Web.Hyperbole.Data.Param (FromParam, ToParam (..))+import Web.Hyperbole.Data.Encoded import Web.Hyperbole.View.ViewId  @@ -69,7 +70,7 @@  newtype ChildView a = ChildView a   deriving (Generic)-instance (ViewId a, FromParam a, ToParam a) => ViewId (ChildView a) where+instance (ViewId a, ToJSON a, FromJSON a) => ViewId (ChildView a) where   type ViewState (ChildView a) = ViewState a  
src/Web/Hyperbole/View/ViewId.hs view
@@ -14,7 +14,10 @@ @ -} class ViewId a where+  -- | Most hyperviews are stateless, but you can track internal state by setting this to something other than `()`   type ViewState a :: Type++   type ViewState a = ()  
+ test/Test/ArgumentSpec.hs view
@@ -0,0 +1,121 @@+module Test.ArgumentSpec where++import Data.Aeson as A+import Data.String.Conversions (cs)+import Data.Text (Text)+import GHC.Generics+import Skeletest+import Web.Hyperbole.Data.Argument+import Web.Hyperbole.HyperView.Input+++spec :: Spec+spec = do+  argumentSpec+  inputSpec+++data Tag = A | B+  deriving (Generic, ToJSON, FromJSON, Eq, Show)+++data Tag2 = T2 | Tag Text+  deriving (Generic, ToJSON, FromJSON, Eq, Show)+++data Record = Record+  { age :: Int+  , msg :: Text+  }+  deriving (Generic, ToJSON, FromJSON, Eq)+++argumentSpec :: Spec+argumentSpec = do+  describe "ToArgument" $ do+    it "encodes basics as JSON" $ do+      encodeArgument @Text "hello" `shouldBe` "\"hello\""+      encodeArgument @Int 23 `shouldBe` "23"++    it "encodes simple constructors raw" $ do+      encodeArgument A `shouldBe` "A"+      encodeArgument B `shouldBe` "B"++    it "encodes Maybe as JSON" $ do+      encodeArgument @(Maybe Int) Nothing `shouldBe` "null"+      encodeArgument @(Maybe Int) (Just 23) `shouldBe` "23"+      encodeArgument @(Maybe Tag) (Just A) `shouldBe` "A"+      encodeArgument @(Maybe Tag) Nothing `shouldBe` "null"++    it "encodes complex constructors as products" $ do+      encodeArgument T2 `shouldBe` "(T2)"+      encodeArgument (Tag "hello world") `shouldBe` "(Tag \"hello world\")"++    -- it "should encode lists with spaces = plusses" $ do+    --   encodeArgument @[Int] [1, 2, 3] `shouldBe` ParamValue ("1+2+3")+    --   encodeArgument @[Text] ["one", "two"] `shouldBe` ParamValue ("one+two")+    --   encodeArgument @[Text] ["hello world", "friend"] `shouldBe` ParamValue ("hello%20world+friend")++    it "should not escape text" $ do+      encodeArgument @Text "hello world" `shouldBe` "\"hello world\""+      encodeArgument @Text "hello_world" `shouldBe` "\"hello_world\""+      encodeArgument @Text "hello+world" `shouldBe` "\"hello+world\""++    it "encodes json" $ do+      let r = Record 10 "hello world"+      encodeArgument r `shouldBe` cs (A.encode r)++      let r2 = Record 10 "hello_world"+      encodeArgument r2 `shouldBe` cs (A.encode r2)+      encodeArgument r2 `shouldBe` cs (A.encode r2)++  describe "FromArgument" $ do+    it "parses basics" $ do+      decodeArgument @Text "hello" `shouldBe` Right "hello"+      decodeArgument @Int "3" `shouldBe` Right 3++    it "decodes json" $ do+      let r2 = Record 10 "hello_world"+      decodeArgument (cs $ A.encode r2) `shouldBe` Right r2++    it "can decode numbers as text" $ do+      decodeArgument @Text "\"30\"" `shouldBe` Right "30"++    it "should not escape text" $ do+      decodeArgument @Text "\"hello world\"" `shouldBe` Right "hello world"+      decodeArgument @Text "\"hello_world\"" `shouldBe` Right "hello_world"+      decodeArgument @Text "\"hello+world\"" `shouldBe` Right "hello+world"++  describe "RoundTrip" $ do+    it "round trips constructors" $ do+      decodeArgument (encodeArgument A) `shouldBe` Right A+      decodeArgument (encodeArgument B) `shouldBe` Right B+      decodeArgument (encodeArgument T2) `shouldBe` Right T2+      let t = Tag "woo hoo"+      decodeArgument (encodeArgument t) `shouldBe` Right t++    it "round trips Maybe" $ do+      decodeArgument @(Maybe Int) (encodeArgument @(Maybe Int) Nothing) `shouldBe` Right Nothing+      decodeArgument @(Maybe Int) (encodeArgument @(Maybe Int) (Just 23)) `shouldBe` Right (Just 23)++    it "round trips Maybe Product" $ do+      decodeArgument @(Maybe Tag) (encodeArgument @(Maybe Tag) Nothing) `shouldBe` Right Nothing+      decodeArgument @(Maybe Tag) (encodeArgument @(Maybe Tag) (Just A)) `shouldBe` Right (Just A)+++data LanguageFamily+  = Functional+  | ObjectOriented+  deriving (Eq, Show, ToJSON, FromJSON, Ord, Generic, InputValue)+++inputSpec :: Spec+inputSpec = do+  describe "InputValue" $ do+    it "encodes Maybe option" $ do+      encodeArgument (Just ObjectOriented) `shouldBe` "ObjectOriented"++    it "round trips Maybe option" $ do+      let enc = encodeArgument @(Maybe LanguageFamily) Nothing+      parseInputValue "ObjectOriented" `shouldBe` Right (Just ObjectOriented)+      parseInputValue @(Maybe LanguageFamily) enc `shouldBe` Right Nothing
test/Test/EncodedSpec.hs view
@@ -6,8 +6,8 @@ import Data.Text (Text) import GHC.Generics (Generic) import Skeletest+import Web.Hyperbole.Data.Argument import Web.Hyperbole.Data.Encoded-import Web.Hyperbole.Data.Param   -- TEST: QueryData underscores vs spaces@@ -15,25 +15,24 @@ data One = One   -- toJSON automatically delegates to the child's ToJSON instance   -- when it ought to be enought to delegate to the Generic instance!-  deriving (Generic, Eq, ToEncoded, FromEncoded, ToParam, FromParam)+  deriving (Generic, Eq, ToEncoded, FromEncoded, ToJSON, FromJSON)   data Tag = A | B | C | D-  deriving (Generic, Eq, ToEncoded, ToParam, FromParam)+  deriving (Generic, Eq, ToEncoded, ToJSON, FromJSON)   data Two = Two | Two2 Int   deriving (Generic, Eq, ToJSON, FromJSON, ToEncoded, FromEncoded)  --- Custom Param Encoding-instance ToParam Two where-  toParam Two = "Two"-  toParam other = genericToParam other-instance FromParam Two where-  parseParam "Two" = pure Two-  parseParam other = genericParseParam other-+-- -- Custom Param Encoding+-- instance ToParam Two where+--   toParam Two = "Two"+--   toParam other = genericToParam other+-- instance FromParam Two where+--   parseParam "Two" = pure Two+--   parseParam other = genericParseParam other  data Sum   = Sumthing@@ -48,11 +47,19 @@ data Nested   = Gogo One   | RecordN Record+  | RecordM RecordMaybe   | RecordEx Record Int   | Tag Tag+  | NProd SubProduct   deriving (Generic, ToEncoded, FromEncoded, Eq)  +data SubProduct+  = MoreThanOne Int+  | AnotherOne Text Int+  deriving (Generic, Eq, ToJSON, FromJSON)++ data Product   = Product Text Int Bool   deriving (Generic, Eq, ToEncoded, FromEncoded)@@ -62,9 +69,16 @@   { one :: Int   , two :: Text   }-  deriving (Generic, Show, ToJSON, FromJSON, Eq, ToEncoded, FromEncoded, ToParam, FromParam)+  deriving (Generic, Show, ToJSON, FromJSON, Eq, ToEncoded, FromEncoded)  +data RecordMaybe = RecordMaybe+  { one :: Int+  , two :: Maybe Text+  }+  deriving (Generic, Show, ToJSON, FromJSON, Eq, ToEncoded, FromEncoded)++ data Product4 = Product4 Text Text Text Text deriving (Generic, Show, Eq, Read, FromEncoded, ToEncoded)  @@ -76,38 +90,37 @@      it "should encode multi tags" $ do       genericToEncoded Two `shouldBe` Encoded "Two" []-      genericToEncoded (Two2 3) `shouldBe` Encoded "Two2" [jsonParam $ Number 3]-      genericToEncoded (Gogo One) `shouldBe` Encoded "Gogo" [toParam One]+      genericToEncoded (Two2 3) `shouldBe` Encoded "Two2" [JSON $ Number 3]+      genericToEncoded (Gogo One) `shouldBe` Encoded "Gogo" [toArgument One]      it "should encode sum tags" $ do-      genericToEncoded (CTwo Two) `shouldBe` Encoded "CTwo" [toParam Two]+      genericToEncoded (CTwo Two) `shouldBe` Encoded "CTwo" [toArgument Two]      it "basic" $ do-      genericToEncoded (Gogo One) `shouldBe` Encoded "Gogo" [toParam One]+      genericToEncoded (Gogo One) `shouldBe` Encoded "Gogo" [toArgument One]      it "product" $ do-      genericToEncoded (Product "one" 2 True) `shouldBe` Encoded "Product" [toParam @Text "one", toParam @Int 2, toParam True]+      genericToEncoded (Product "one" 2 True) `shouldBe` Encoded "Product" [toArgument @Text "one", toArgument @Int 2, toArgument True]      it "product4" $ do       let prod = Product4 "one" "two" "three" "four"-      genericToEncoded prod `shouldBe` Encoded "Product4" (fmap toParam ["one" :: Text, "two", "three", "four"])+      genericToEncoded prod `shouldBe` Encoded "Product4" (fmap toArgument ["one" :: Text, "two", "three", "four"])    describe "genericParseEncoded" $ do     it "product4" $ do-      genericParseEncoded (Encoded "Product4" (fmap toParam ["one" :: Text, "two", "three", "four"])) `shouldBe` Right (Product4 "one" "two" "three" "four")+      genericParseEncoded (Encoded "Product4" (fmap toArgument ["one" :: Text, "two", "three", "four"])) `shouldBe` Right (Product4 "one" "two" "three" "four")      it "sum" $ do       genericParseEncoded @Sum (Encoded "Sumthing" []) `shouldBe` Right Sumthing-      genericParseEncoded @Sum (Encoded "Num" [toParam @Int 2]) `shouldBe` Right (Num 2)-      genericParseEncoded @Sum (Encoded "Str" [toParam @Text "OK"]) `shouldBe` Right (Str "OK")+      genericParseEncoded @Sum (Encoded "Num" [toArgument @Int 2]) `shouldBe` Right (Num 2)+      genericParseEncoded @Sum (Encoded "Str" [toArgument @Text "OK"]) `shouldBe` Right (Str "OK") -      genericParseEncoded @Sum (Encoded "COne" [toParam One]) `shouldBe` Right (COne One)-      genericParseEncoded @Sum (Encoded "CTwo" [toParam Two]) `shouldBe` Right (CTwo Two)+      genericParseEncoded @Sum (Encoded "COne" [toArgument One]) `shouldBe` Right (COne One)+      genericParseEncoded @Sum (Encoded "CTwo" [toArgument Two]) `shouldBe` Right (CTwo Two)    describe "toEncoded" $ do     it "encodes numbers as text" $ do-      -- no, this is right, but when we go to decode, we pick up the json instance...-      toEncoded (Num 1) `shouldBe` Encoded "Num" [jsonParam $ Number 1]+      toEncoded (Num 1) `shouldBe` Encoded "Num" [toArgument @Int 1]    describe "toText" $ do     it "should encode single tags" $ do@@ -118,29 +131,28 @@       encodedParseText "One" `shouldBe` Right (Encoded "One" [])      it "parses numbers" $ do-      encodedParseText "Num 1" `shouldBe` Right (Encoded "Num" [jsonParam $ Number 1])+      encodedParseText "Num 1" `shouldBe` Right (Encoded "Num" [JSON $ Number 1])    describe "encode" $ do     it "should encode single tags" $ do       encode One `shouldBe` "One" -    it "encodes strings" $ do-      encode (Str "hello world") `shouldBe` "Str hello_world"-      -- but then how is it going to know the difference between the two?-      encode (Str " ") `shouldBe` "Str _"-      encode (Str "") `shouldBe` "Str |"-      encode (Str "_") `shouldBe` "Str \\_"-      encode (Str "\n") `shouldBe` "Str \\n"-      encode (Str "hello_world") `shouldBe` "Str hello\\_world"-      encode (Str "hello+world") `shouldBe` "Str hello+world"-      encode (Str "hello\nworld") `shouldBe` "Str hello\\nworld"+    it "encodes strings as JSON" $ do+      encode (Str "hello world") `shouldBe` "Str \"hello world\""+      encode (Str " ") `shouldBe` "Str \" \""+      encode (Str "") `shouldBe` "Str \"\""+      encode (Str "_") `shouldBe` "Str \"_\""+      encode (Str "\n") `shouldBe` "Str \"\\n\""+      encode (Str "hello_world") `shouldBe` "Str \"hello_world\""+      encode (Str "hello+world") `shouldBe` "Str \"hello+world\""+      encode (Str "hello\nworld") `shouldBe` "Str \"hello\\nworld\""      it "should encode records`" $ do       -- no field names for ourselves-      encode (Record 1 "two") `shouldBe` "Record 1 two"+      encode (Record 1 "two") `shouldBe` "Record 1 \"two\""       -- but if it is nested it uses the JSON instance, obviously       let r2 = Record 1 "two"-      encode (RecordN r2) `shouldBe` "RecordN " <> encodeParam (jsonParam r2)+      encode (RecordN r2) `shouldBe` "RecordN " <> encodeFromArgument (JSON $ toJSON r2)      it "no special case for nested constructors`" $ do       encode A `shouldBe` "A"@@ -148,106 +160,122 @@      it "should encode sum" $ do       encode (Num 1) `shouldBe` "Num 1"-      encode (Str "hello world") `shouldBe` "Str hello_world"+      encode (Str "hello world") `shouldBe` "Str \"hello world\"" -    it "should encode prodcuts" $ do-      encode (Product "hello world" 2 True) `shouldBe` "Product hello_world 2 true"+    it "should encode products" $ do+      encode (Product "hello world" 2 True) `shouldBe` "Product \"hello world\" 2 true"      it "encodes more constructors" $ do-      encode (CTwo (Two2 3)) `shouldBe` "CTwo [\"Two2\",3]"-      encode (CTwo Two) `shouldBe` "CTwo Two" -- uses the custom toparam instance+      encode (CTwo (Two2 3)) `shouldBe` "CTwo (Two2 3)" -- uses custom tuple constructor+      encode (CTwo Two) `shouldBe` "CTwo (Two)" -- uses the custom simpleTag       encode (COne One) `shouldBe` "COne []" +    it "encodes nested products" $ do+      encode (NProd (AnotherOne "hi" 3)) `shouldBe` "NProd (AnotherOne \"hi\" 3)"++    it "encodes nested records" $ do+      encode (RecordN (Record 3 "hello")) `shouldBe` "RecordN {\"one\":3,\"two\":\"hello\"}"++    it "encodes nested records with nothing as null" $ do+      encode (RecordM (RecordMaybe 3 Nothing)) `shouldBe` "RecordM {\"one\":3,\"two\":null}"+   describe "decode" $ do     it "should encode single tags" $ do       decode "One" `shouldBe` Just One      it "should decode nested sum" $ do       decodeEither "Num 1" `shouldBe` Right (Num 1)-      decodeEither "Str str" `shouldBe` Right (Str "str")-      decodeEither "Str hello_world" `shouldBe` Right (Str "hello world")+      decodeEither "Str \"str\"" `shouldBe` Right (Str "str")+      decodeEither "Str \"hello world\"" `shouldBe` Right (Str "hello world")      it "no special case for nested constructors`" $ do-      decode "Tag A" `shouldBe` Just (Tag A)+      decodeEither "Tag A" `shouldBe` Right (Tag A)      it "decodes strings" $ do-      decode "Str |" `shouldBe` pure (Str "")+      decode "Str \"\"" `shouldBe` pure (Str "")    describe "params" $ do-    it "sanitizeText" $ do-      encodeParam "hello world" `shouldBe` "hello_world"-      encodeParam "hello_world" `shouldBe` "hello\\_world"-      encodeParam "hello\nworld" `shouldBe` "hello\\nworld"--    it "desanitizeText" $ do-      decodeParam "hello_world" `shouldBe` "hello world"-      decodeParam "hello\\_world" `shouldBe` "hello_world"-      decodeParam "hello\\nworld" `shouldBe` "hello\nworld"+    -- it "sanitizeText" $ do+    --   encodeParam "hello world" `shouldBe` "hello_world"+    --   encodeParam "hello_world" `shouldBe` "hello\\_world"+    --   encodeParam "hello\nworld" `shouldBe` "hello\\nworld"+    --+    -- it "desanitizeText" $ do+    --   decodeParam "hello_world" `shouldBe` "hello world"+    --   decodeParam "hello\\_world" `shouldBe` "hello_world"+    --   decodeParam "hello\\nworld" `shouldBe` "hello\nworld"      -- TODO: Add more edge cases to check if "\n" is escaped properly.-    it "edge cases" $ do-      encodeParam "" `shouldBe` "|"-      encodeParam " " `shouldBe` "_"-      encodeParam "  " `shouldBe` "__"+    -- it "edge cases" $ do+    --   encodeParam "" `shouldBe` "\"\""+    --   encodeParam " " `shouldBe` "\"_\""+    --   encodeParam "  " `shouldBe` "\"__\""+    --+    --   encodeParam "_" `shouldBe` "\"\\_\""+    --   encodeParam "__" `shouldBe` "\"\\_\\_\""+    --+    --   decodeParam "|" `shouldBe` ParamValue "|"+    --   decodeParam "_" `shouldBe` ParamValue "_"+    --   decodeParam "\\_" `shouldBe` "_"+    --   decodeParam "\\_\\_" `shouldBe` "__" -      encodeParam "_" `shouldBe` "\\_"-      encodeParam "__" `shouldBe` "\\_\\_"+    describe "round trip" $ do+      it "records" $ do+        let enc = genericToEncoded (Record 1 "two")+        genericParseEncoded enc `shouldBe` Right (Record 1 "two") -      decodeParam "|" `shouldBe` ""-      decodeParam "_" `shouldBe` " "-      decodeParam "\\_" `shouldBe` "_"-      decodeParam "\\_\\_" `shouldBe` "__"+      it "product" $ do+        decode (encode (Product "hello world" 2 False)) `shouldBe` Just (Product "hello world" 2 False)+        decode (encode (Product "bob" (-2) True)) `shouldBe` Just (Product "bob" (-2) True) -  describe "round trip" $ do-    it "records" $ do-      let enc = genericToEncoded (Record 1 "two")-      genericParseEncoded enc `shouldBe` Right (Record 1 "two")+      it "nested product with records" $ do+        let r = RecordEx (Record 2 "three") 33+        let t = encode r+        decode t `shouldBe` Just r -    it "product" $ do-      decode (encode (Product "hello world" 2 False)) `shouldBe` Just (Product "hello world" 2 False)-      decode (encode (Product "bob" (-2) True)) `shouldBe` Just (Product "bob" (-2) True)+      it "special case constructors" $ do+        decodeEither (encode (CTwo Two)) `shouldBe` Right (CTwo Two)+        decode (encode (Tag B)) `shouldBe` Just (Tag B) -    it "nested product with records" $ do-      let r = RecordEx (Record 2 "three") 33-      let t = encode r-      decode t `shouldBe` Just r+      it "special case products" $ do+        decodeEither (encode (CTwo (Two2 3))) `shouldBe` Right (CTwo (Two2 3))+        decodeEither (encode (NProd (AnotherOne "HI" 3))) `shouldBe` Right (NProd (AnotherOne "HI" 3)) -    it "special case constructors" $ do-      decode (encode (CTwo Two)) `shouldBe` Just (CTwo Two)-      decode (encode (Tag B)) `shouldBe` Just (Tag B)+      it "big product" $ do+        let p = Product4 "hello world" "two_times" "three" "four"+        decode (encode p) `shouldBe` Just p -    it "big product" $ do-      let p = Product4 "hello world" "two_times" "three" "four"-      decode (encode p) `shouldBe` Just p+      it "empty strings" $ do+        decode (encode $ Str "") `shouldBe` Just (Str "") -    it "empty strings" $ do-      decode (encode $ Str "") `shouldBe` Just (Str "")+      it "special characters" $ do+        let str = "hello+world \"bob_lives\""+        decode (encode $ Str str) `shouldBe` Just (Str str) -    it "special characters" $ do-      let str = "hello+world \"bob_lives\""-      decode (encode $ Str str) `shouldBe` Just (Str str)+      it "encodes lists`" $ do+        let l = List ["hello, world", "", "+,|<[]"]+        decode @Sum (encode l) `shouldBe` Just l -    it "encodes lists`" $ do-      let l = List ["hello, world", "", "+,|<[]"]-      print $ encode l-      decode @Sum (encode l) `shouldBe` Just l+      it "encodes newlines in strings" $ do+        let s = Str "hello\nworld"+        decode @Sum (encode s) `shouldBe` Just s -    -- Regression tests for https://github.com/seanhess/hyperbole/issues/187-    -- A ViewId (or state) containing a list with newline characters must-    -- encode/decode correctly.  Previously, desanitizeParamText blindly-    -- replaced the JSON escape sequence "\\n" with a real newline, corrupting-    -- the JSON and causing "No Handler for Event viewId".-    it "list with newline character round-trips correctly (issue #187)" $ do-      decode @Sum (encode (List ["\n"])) `shouldBe` Just (List ["\n"])+      -- Regression tests for https://github.com/seanhess/hyperbole/issues/187+      -- A ViewId (or state) containing a list with newline characters must+      -- encode/decode correctly.  Previously, desanitizeParamText blindly+      -- replaced the JSON escape sequence "\\n" with a real newline, corrupting+      -- the JSON and causing "No Handler for Event viewId".+      it "list with newline character round-trips correctly (issue #187)" $ do+        decode @Sum (encode (List ["\n"])) `shouldBe` Just (List ["\n"]) -    it "list with newline in multiple elements" $ do-      decode @Sum (encode (List ["\n", "hello\nworld", "plain"])) `shouldBe` Just (List ["\n", "hello\nworld", "plain"])+      it "list with newline in multiple elements" $ do+        decode @Sum (encode (List ["\n", "hello\nworld", "plain"])) `shouldBe` Just (List ["\n", "hello\nworld", "plain"]) -    it "strings" $ do-      decode @Sum (encode (Str "")) `shouldBe` pure (Str "")-      decode @Sum (encode (Str " ")) `shouldBe` pure (Str " ")-      decode @Sum (encode (Str "_")) `shouldBe` pure (Str "_")-      decode @Sum (encode (Str "~")) `shouldBe` pure (Str "~")-      decode @Sum (encode (Str "+")) `shouldBe` pure (Str "+")-      decode @Sum (encode (Str "hello world")) `shouldBe` pure (Str "hello world")-      decode @Sum (encode (Str "hello_world")) `shouldBe` pure (Str "hello_world")+      it "strings" $ do+        decode @Sum (encode (Str "")) `shouldBe` pure (Str "")+        decode @Sum (encode (Str " ")) `shouldBe` pure (Str " ")+        decode @Sum (encode (Str "_")) `shouldBe` pure (Str "_")+        decode @Sum (encode (Str "~")) `shouldBe` pure (Str "~")+        decode @Sum (encode (Str "+")) `shouldBe` pure (Str "+")+        decode @Sum (encode (Str "hello world")) `shouldBe` pure (Str "hello world")+        decode @Sum (encode (Str "hello_world")) `shouldBe` pure (Str "hello_world")
test/Test/FormSpec.hs view
@@ -1,11 +1,16 @@ {-# LANGUAGE DerivingVia #-} {-# LANGUAGE OverloadedLists #-}+{-# OPTIONS_GHC -Wno-orphans #-}  module Test.FormSpec where +import Data.Aeson (FromJSON, ToJSON) import Data.Text (Text)+import GHC.Exts (IsList (..)) import Skeletest import Web.Hyperbole.HyperView.Forms+import Web.Hyperbole.HyperView.Input (InputValue (..), encodeOption)+import Web.Hyperbole.Types.Request   data Example f = Example@@ -33,17 +38,36 @@   deriving (Generic, FromForm, Show, Eq)  +instance IsList Form where+  type Item Form = Param+  fromList ps = Form ps mempty+  toList (Form ps _) = ps++ spec :: Spec-spec = withMarkers ["param"] $ do+spec = do   describe "forms" $ do-    it "should parse a form" $ do-      case fromForm @(Example Identity) [("message", "hello"), ("age", "23"), ("whatever", "")] of+    it "parses a record" $ do+      case fromForm @(Example Identity) [("message", "hello"), ("age", "23"), ("whatever", "10.4"), ("maybeMessage", "hello world")] of         Left e -> fail $ show e         Right a -> do           a.message `shouldBe` "hello"           a.age `shouldBe` 23-          a.whatever `shouldBe` Nothing+          a.whatever `shouldBe` Just 10.4+          a.maybeMessage `shouldBe` Just "hello world" +    it "parses empty values" $ do+      let e = fromForm @(Example Identity) [("age", ""), ("whatever", "")]+      fmap (.age) e `shouldBe` Right 0+      fmap (.whatever) e `shouldBe` Right Nothing+      fmap (.maybeMessage) e `shouldBe` Right Nothing++    it "parses missing values" $ do+      let e = fromForm @(Example Identity) []+      fmap (.age) e `shouldBe` Right 0+      fmap (.whatever) e `shouldBe` Right Nothing+      fmap (.maybeMessage) e `shouldBe` Right Nothing+     it "should parse a form with a number for the text" $ do       let res = fromForm @(Example Identity) [("message", "30"), ("age", "0"), ("whatever", "2"), ("maybeMessage", "hello")]       res `shouldBe` Right (Example "30" 0 (Just 2) (Just "hello"))@@ -56,7 +80,7 @@       let res = fromForm @(Example Identity) [("message", "30"), ("age", "0"), ("maybeMessage", "")]       res `shouldBe` Right (Example "30" 0 Nothing (Just "")) -    it "parses weird" $ do+    it "parses bools" $ do       fromForm @Flags [("a", "true"), ("b", "off")] `shouldBe` Right (Flags True False)       fromForm @Flags [("a", "on"), ("b", "false")] `shouldBe` Right (Flags True False)       fromForm @Flags [("a", "on")] `shouldBe` Right (Flags True False)@@ -64,8 +88,32 @@     it "parses missing bools as false" $ do       fromForm @Flags [("a", "true")] `shouldBe` Right (Flags True False) -    it "parses underscores" $ do+    it "parses special characters" $ do       fromForm @Todo [("msg", "test")] `shouldBe` Right (Todo "test")       fromForm @Todo [("msg", "hello world")] `shouldBe` Right (Todo "hello world")       fromForm @Todo [("msg", "hello+world")] `shouldBe` Right (Todo "hello+world")       fromForm @Todo [("msg", "hello_world")] `shouldBe` Right (Todo "hello_world")++  describe "options" $ do+    it "decodes option as input" $ do+      let enc = encodeOption (Twonit "Hello world" 33)+      parseInputValue enc `shouldBe` Right (Twonit "Hello world" 33)++    it "decodes option as field" $ do+      let enc = encodeOption (Twonit "Hello world" 33)+      fromField (Just (FormParam enc)) `shouldBe` Right (Twonit "Hello world" 33)++    it "round trips options: Just" $ do+      let enc1 = encodeOption (Just $ Onit "Hello world")+      fromField (Just (FormParam enc1)) `shouldBe` Right (Onit "Hello world")++    it "round trips options: Nothing" $ do+      let enc2 = encodeOption @(Maybe FancySum) Nothing+      fromField @(Maybe FancySum) (Just (FormParam enc2)) `shouldBe` Right Nothing+++data FancySum+  = Unit+  | Onit Text+  | Twonit Text Int+  deriving (Generic, Eq, FromJSON, ToJSON, InputValue, FromField)
− test/Test/ParamSpec.hs
@@ -1,96 +0,0 @@-{-# LANGUAGE OverloadedLists #-}--module Test.ParamSpec where--import Data.Aeson-import Data.String.Conversions (cs)-import Data.Text (Text)-import GHC.Generics-import Skeletest-import Web.Hyperbole.Data.Param---spec :: Spec-spec = withMarkers ["param"] $ do-  describe "param" paramSpec---data Record = Record-  { age :: Int-  , msg :: Text-  }-  deriving (Generic, ToJSON, FromJSON, ToParam, FromParam, Eq)---data Tag = A | B-  deriving (Generic, ToParam, FromParam, Eq, Show)---data Tag2 = C | Tag Text-  deriving (Generic, ToParam, FromParam, Eq, Show)-instance ToJSON Tag2 where-  toJSON = genericToJSON jsonOptions---paramSpec :: Spec-paramSpec = do-  describe "ToParam" $ do-    it "should encode basics" $ do-      toParam @Text "hello" `shouldBe` "hello"-      toParam @Int 23 `shouldBe` ParamValue "23"--    it "should encode Maybe" $ do-      toParam @(Maybe Int) Nothing `shouldBe` ParamValue "~"-      toParam @(Maybe Int) (Just 23) `shouldBe` ParamValue "23"--    it "encodes simple constructors" $ do-      toParam A `shouldBe` ParamValue "A"-      toParam B `shouldBe` ParamValue "B"--    it "encodes complex constructors as json" $ do-      toParam C `shouldBe` jsonParam C-      toParam (Tag "hello world") `shouldBe` jsonParam (Tag "hello world")--    -- it "should encode lists with spaces = plusses" $ do-    --   toParam @[Int] [1, 2, 3] `shouldBe` ParamValue ("1+2+3")-    --   toParam @[Text] ["one", "two"] `shouldBe` ParamValue ("one+two")-    --   toParam @[Text] ["hello world", "friend"] `shouldBe` ParamValue ("hello%20world+friend")--    it "should not escape text" $ do-      toParam @Text "hello world" `shouldBe` ParamValue "hello world"-      toParam @Text "hello_world" `shouldBe` ParamValue "hello_world"-      toParam @Text "hello+world" `shouldBe` ParamValue "hello+world"--    it "encodes json" $ do-      let r = Record 10 "hello world"-      toParam r `shouldBe` jsonParam (toJSON r)--      let r2 = Record 10 "hello_world"-      toParam r2 `shouldBe` jsonParam (toJSON r2)-      toParam r2 `shouldBe` ParamValue (cs (encode r2))--  describe "FromParam" $ do-    it "should parse basics" $ do-      parseParam @Text "hello" `shouldBe` Right "hello"-      parseParam @Int "3" `shouldBe` Right 3--    it "decodes json" $ do-      let r2 = Record 10 "hello_world"-      parseParam (jsonParam r2) `shouldBe` Right r2-      parseParam (ParamValue $ cs $ encode r2) `shouldBe` Right r2--    it "can decode numbers as text" $ do-      parseParam @Text "3" `shouldBe` Right "3"--    it "should not escape text" $ do-      parseParam @Text "hello world" `shouldBe` Right "hello world"-      parseParam @Text "hello_world" `shouldBe` Right "hello_world"-      parseParam @Text "hello+world" `shouldBe` Right "hello+world"--  describe "RoundTrip" $ do-    it "round trips constructors" $ do-      parseParam (toParam A) `shouldBe` Right A-      parseParam (toParam B) `shouldBe` Right B-      parseParam (toParam C) `shouldBe` Right C-      let t = Tag "woo hoo"-      parseParam (toParam t) `shouldBe` Right t
test/Test/QuerySpec.hs view
@@ -27,7 +27,9 @@   { age :: Int   , msg :: Text   }-  deriving (Generic, ToJSON, FromJSON, ToParam, FromParam, Eq, FromQuery, ToQuery)+  deriving (Generic, ToJSON, FromJSON, Eq, FromQuery, ToQuery)+instance Default Record where+  def = Record 0 ""   classSpec :: Spec@@ -43,12 +45,12 @@    describe "ToQuery" $ do     it "encodes record" $ do-      let r = Record 20 "hello world"-      QueryData.render (toQuery r) `shouldBe` "age=20&msg=hello_world"+      let r = Record 20 "hello world_go+big"+      QueryData.render (toQuery r) `shouldBe` "age=20&msg=hello+world_go%2Bbig"    describe "roundtrip" $ do     it "round trips" $ do-      let r = Record 20 "hello world"+      let r = Record 20 "hello world_go+big"       parseQuery (toQuery r) `shouldBe` Right r  @@ -70,9 +72,12 @@     let q = mempty & QueryData.insert @Text "msg" "bob&henry=fast"     QueryData.render q `shouldBe` "msg=bob%26henry%3Dfast" -  -- it "handles underscores" $ do-  --   QueryData.render [(Param "msg", ParamValue "hello_world" $ String "hello_world")] `shouldBe` "msg=hello%5C_world"-  --   QueryData.render [(Param "msg", ParamValue "hello world" $ String "hello world")] `shouldBe` "msg=hello_world"+  it "should roundtrip spaces" $ do+    let msg = "hello world"+    let q = mempty & QueryData.insert @Text "msg" msg+    let out = QueryData.render q+    let q' = QueryData.parse out+    QueryData.lookup "msg" q' `shouldBe` Just msg    it "should roundtrip special characters" $ do     let msg = "bob&henry=fast"@@ -82,17 +87,12 @@     QueryData.lookup "msg" q' `shouldBe` Just msg  --- it "should preserve plusses" $ do---   let QueryData q = QueryData $ M.fromList [("items", "one+two")]---   print $ HTTP.toQuery $ M.toList q---   QueryData.render (QueryData q) `shouldBe` "items=one+two"- data Filters = Filters   { term :: Text   , isActive :: Bool   , another :: Maybe Text   }-  deriving (Eq, Show)+  deriving (Generic, Eq, Show)   instance ToQuery Filters where@@ -111,41 +111,34 @@     pure Filters{..}  -data Filters' = Filters'-  { term :: Text-  , isActive :: Bool-  }-  deriving (Generic, Eq, ToJSON, FromJSON, FromParam, ToParam)-instance Default Filters' where-  def = Filters' "" False-- data Nested = Nested-  { filters :: Filters'+  { record :: Record+  , awesome :: Bool   }-  deriving (Generic, ToQuery, FromQuery)+  deriving (Generic, ToQuery, FromQuery, Eq)  --- instance ToQuery Nested where---   toQuery n =---     mempty & QueryData.insert "filters" (JSON n.filters)--------- instance FromQuery Nested where---   parseQuery q =---     mempty & QueryData.insert "filters" (JSON n.filters)- multiSpec :: Spec multiSpec = do   describe "Roundtrip" $ do     it "should parse from querydata" $ do       let f = Filters "hello world" False Nothing-      let out = QueryData.render (toQuery f)-      let q = QueryData.parse out-      parseQuery q `shouldBe` Right f+      roundTrip f      it "should work with Just" $ do       let f = Filters "hello_world" False (Just "hello")-      let out = QueryData.render (toQuery f)-      let q = QueryData.parse out-      parseQuery q `shouldBe` Right f+      roundTrip f++    it "integers, special characters, spaces" $ do+      let r = Record 30 "hello world_this+is"+      roundTrip r++    it "nested JSON records" $ do+      let r = Record 30 "hello world_this+is"+      let n = Nested r True+      roundTrip n+ where+  roundTrip val = do+    let out = QueryData.render (toQuery val)+    let q = QueryData.parse out+    parseQuery q `shouldBe` Right val
test/Test/SessionSpec.hs view
@@ -2,13 +2,13 @@  module Test.SessionSpec where +import Data.Aeson qualified as A import Data.String.Conversions (cs) import Data.Text (Text) import Network.HTTP.Types (urlEncode) import Skeletest import Web.Hyperbole import Web.Hyperbole.Data.Cookie as Cookie-import Web.Hyperbole.Data.Encoded qualified as Encoded import Web.Hyperbole.Data.URI import Web.Hyperbole.Effect.Session (sessionCookie) @@ -16,13 +16,13 @@ -- import Skeletest.Predicate qualified as P  data Woot = Woot Text-  deriving (Generic, Show, ToEncoded, FromEncoded)+  deriving (Generic, Show, ToJSON, FromJSON) instance Session Woot where   cookiePath = Just $ Path ["somepage"]   data InsecureSession = InsecureSession Text-  deriving (Generic, Show, ToEncoded, FromEncoded)+  deriving (Generic, Show, ToJSON, FromJSON) instance Session InsecureSession where   cookieSecure = False @@ -32,7 +32,7 @@   describe "Session" $ do     it "should encode cookie" $ do       let woot = Woot "hello"-      toCookie woot `shouldBe` CookieValue (cs $ Encoded.encode woot)+      toCookie woot `shouldBe` CookieValue (cs $ A.encode woot)    describe "sessionCookie" $ do     it "should create cookie" $ do@@ -54,13 +54,13 @@     it "should render complex cookie with included path" $ do       let woot = Woot "hello world"       let cookie = sessionCookie woot-      Cookie.render [] cookie `shouldBe` "Woot=" <> urlEncode True (cs $ Encoded.encode woot) <> "; SameSite=None; secure; path=/somepage"+      Cookie.render [] cookie `shouldBe` "Woot=" <> urlEncode True (cs $ A.encode woot) <> "; SameSite=None; secure; path=/somepage"    describe "Session class" $ do     it "should encode class" $ do       let prefs = Preferences "hello" Warning       let cooks = Cookie.insert (sessionCookie prefs) mempty-      Cookie.lookup (sessionKey @Preferences) cooks `shouldBe` Just (CookieValue $ cs $ Encoded.encode prefs)+      Cookie.lookup (sessionKey @Preferences) cooks `shouldBe` Just (CookieValue $ cs $ A.encode prefs)      it "should decode class" $ do       let prefs = Preferences "hello" Warning@@ -78,7 +78,7 @@   { message :: Text   , color :: AppColor   }-  deriving (Generic, Eq, Show, ToEncoded, FromEncoded, Session)+  deriving (Generic, Eq, Show, ToJSON, FromJSON, Session) instance Default Preferences where   def = Preferences "_" White @@ -97,4 +97,4 @@   | PrimaryLight   | Secondary   | SecondaryLight-  deriving (Show, Eq, Generic, ToParam, FromParam)+  deriving (Show, Eq, Generic, ToJSON, FromJSON)
test/Test/ViewActionSpec.hs view
@@ -1,36 +1,52 @@+{-# LANGUAGE BlockArguments #-}+ module Test.ViewActionSpec where +import Data.Aeson (Value (..)) import Data.Text (Text) import GHC.Generics import Skeletest import Skeletest.Predicate qualified as P import Web.Hyperbole (FromJSON, ToJSON)+import Web.Hyperbole.Data.Argument import Web.Hyperbole.Data.Encoded-import Web.Hyperbole.Data.Param import Web.Hyperbole.View-import Web.Hyperbole.HyperView.Event (toActionInput)   data Simple = Simple-  deriving (Generic, Eq, Show, Read, ViewAction, ToJSON, FromJSON, ToParam, FromParam)+  deriving (Generic, Eq, Show, ViewAction)   data Product = Product String Int-  deriving (Generic, Show, Eq, ViewAction, Read, ToJSON, FromJSON, ToEncoded, FromEncoded, ToParam, FromParam)+  deriving (Generic, Show, Eq, ViewAction, Read, ToJSON, FromJSON, ToEncoded, FromEncoded)   data Product' = Product' HasText Int   deriving (Generic, Show, Eq, ViewAction, Read, ToJSON, FromJSON, ToEncoded, FromEncoded)  +data Something = Something+  deriving (Generic, Show, ToJSON, FromJSON, Eq)+++-- If you want another type as an input, you must implement UserInput. We don't automatically parse integers from search fields+newtype NumInput = NumInput Int+  deriving (Generic, Show, Eq)+  deriving anyclass (FromJSON, ToJSON)++ data Sum   = SumA   | SumB Int   | SubC Text   | SubD (Maybe Text)   | SubE Term-  | SubF Simple-  deriving (Generic, Show, Read, Eq, ViewAction)+  | SubF Something+  | SubG Int Something+  | SubH NumInput Int+  | SubI Something Int+  | SubJ Text NumInput+  deriving (Generic, Show, Eq, ViewAction)   data Compound = Compound Product@@ -38,46 +54,41 @@   data HasText = HasText Text-  deriving (Generic, Show, Eq, Read, ViewAction, ToJSON, FromJSON, FromEncoded, ToEncoded, ToParam, FromParam)+  deriving (Generic, Show, Eq, Read, ViewAction, ToJSON, FromJSON, FromEncoded, ToEncoded)   newtype Term = Term Text-  deriving newtype (Eq, Show, ToJSON, FromJSON, Read, ToParam, FromParam)+  deriving newtype (Eq, Show, ToJSON, FromJSON, Read)  +data NumberPair = NumberPair {a :: Int, b :: NumInput}+  deriving (Show, Generic, ToJSON, FromJSON)+++data Nested = Nested NumberPair+  deriving (Generic, ViewAction)++ spec :: Spec spec = withMarkers ["encoded"] $ do   describe "ViewAction" $ do     describe "toAction" $ do       it "simple" $ toAction Simple `shouldBe` Encoded "Simple" []-      it "has text" $ toAction (HasText "hello world") `shouldBe` Encoded "HasText" ["hello world"]-      it "product" $ toAction (Product "hello world" 123) `shouldBe` Encoded "Product" ["hello world", toParam @Int 123]-      it "sum" $ toAction (SumB 123) `shouldBe` Encoded "SumB" [toParam @Int 123]+      it "has text" $ toAction (HasText "hello world") `shouldBe` Encoded "HasText" [JSON $ String "hello world"]+      it "product" $ toAction (Product "hello world" 123) `shouldBe` Encoded "Product" [JSON $ String "hello world", toArgument @Int 123]+      it "sum" $ toAction (SumB 123) `shouldBe` Encoded "SumB" [toArgument @Int 123]       it "compound" $ do         let p = Product "hello world" 123-        toAction (Compound p) `shouldBe` Encoded "Compound" [toParam p]--    describe "toActionInput" $ do-      it "Constructor Text" $ do-        toActionInput SubC `shouldBe` Encoded "SubC" []--      it "Constructor (Maybe Text)" $ do-        toActionInput (SubD . Just) `shouldBe` Encoded "SubD" []--      it "Constructor newtype Term" $ do-        toActionInput (SubE . Term) `shouldBe` Encoded "SubE" []--      it "renders data constructors" $ do-        toActionInput SubF `shouldBe` Encoded "SubF" []+        toAction (Compound p) `shouldBe` Encoded "Compound" [toArgument p]      describe "parseAction" $ do       it "simple" $ parseAction (Encoded "Simple" []) `shouldBe` pure Simple        it "parse product" $ do-        parseAction @Product (Encoded "Product" ["woot", toParam @Int 1234]) `shouldSatisfy` P.right P.anything+        parseAction @Product (Encoded "Product" [JSON $ String "woot", toArgument @Int 1234]) `shouldSatisfy` P.right P.anything        it "parse product with spaces" $ do-        parseAction @Product (Encoded "Product" ["hello world", toParam @Int 1234]) `shouldSatisfy` P.right P.anything+        parseAction @Product (Encoded "Product" [JSON $ String "hello world", toArgument @Int 1234]) `shouldSatisfy` P.right P.anything      describe "roundTrip" $ do       it "simple" $ do
test/Test/ViewIdSpec.hs view
@@ -11,7 +11,7 @@   data Thing = Thing-  deriving (Generic, Show, Eq, ToJSON, FromJSON, ToEncoded, FromEncoded, ViewId, ToParam, FromParam)+  deriving (Generic, Show, Eq, ToJSON, FromJSON, ToEncoded, FromEncoded, ViewId)   data Custom = Custom@@ -27,7 +27,7 @@   | Two Thing   | WithId (Id Thing)   | Compound Text Compound-  deriving (Generic, Show, Eq, ToJSON, FromJSON, ToEncoded, FromEncoded, ViewId, ToParam, FromParam)+  deriving (Generic, Show, Eq, ToJSON, FromJSON, ToEncoded, FromEncoded, ViewId)   data Product4 = Product4 Text Text Text Text@@ -40,7 +40,7 @@   newtype Id a = Id {fromId :: Text}-  deriving newtype (Eq, ToJSON, FromJSON, Ord, Show, ToParam, FromParam)+  deriving newtype (Eq, ToJSON, FromJSON, Ord, Show)   deriving (Generic)  @@ -65,7 +65,7 @@      describe "has-string" $ do       it "should not contain single quotes" $ do-        encodeViewId (HasString "woot") `shouldBe` "HasString woot"+        encodeViewId (HasString "woot") `shouldBe` "HasString \"woot\""         containsSingleQuotes (encodeViewId (HasString "woot")) `shouldBe` False        it "should roundtrip" $ do
test/Test/ViewSpec.hs view
@@ -19,5 +19,5 @@         renderText v `shouldBe` "<div>one</div>\n<div>two</div>"        it "renders all nodes with >>=" $ do-        let v = el "one" >>= \_ -> el "two"+        let v = el "one" >> el "two"         renderText v `shouldBe` "<div>one</div>\n<div>two</div>"