Compare commits
	
		
			No commits in common. "bec1ae4a3b23ac64849010170e3c94eabf1d9fee" and "487c872d43c5bcebccc383d35ee5ada361e73073" have entirely different histories. 
		
	
	
		
			bec1ae4a3b
			...
			487c872d43
		
	
		
							
								
								
									
										
											BIN
										
									
								
								docs/logo.png
								
								
								
								
							
							
						
						
									
										
											BIN
										
									
								
								docs/logo.png
								
								
								
								
							
										
											Binary file not shown.
										
									
								
							| 
		 Before Width: | Height: | Size: 7.7 KiB  | 
| 
						 | 
				
			
			@ -1,16 +0,0 @@
 | 
			
		|||
<svg version="1.1" viewBox="0 0 27.9 32" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
 | 
			
		||||
 <title>Matrix (protocol) logo</title>
 | 
			
		||||
 <g transform="translate(-.095 .005)" fill="#040404">
 | 
			
		||||
    <path d="m27.1 31.2v-30.5h-2.19v-0.732h3.04v32h-3.04v-0.732z"/>
 | 
			
		||||
    <g transform="translate(13.95 16) scale(0.03,-0.03)">
 | 
			
		||||
        <polygon fill="#F0AD00" points="-280,-90 0,190 280,-90" transform="translate(0 -210)"/>
 | 
			
		||||
        <polygon fill="#7FD13B" points="-280,-90 0,190 280,-90" transform="translate(-210 0) rotate(-90)"/>
 | 
			
		||||
        <polygon fill="#7FD13B" points="-198,-66 0,132 198,-66" transform="translate(207 207) rotate(-45)"/>
 | 
			
		||||
        <polygon fill="#60B5CC" points="-130,0 0,-130 130,0 0,130" transform="translate(150 0)"/>
 | 
			
		||||
        <polygon fill="#5A6378" points="-191,61 69,61 191,-61 -69,-61" transform="translate(-89 239)"/>
 | 
			
		||||
        <polygon fill="#F0AD00" points="-130,-44 0,86 130,-44" transform="translate(0 106) rotate(-180)"/>
 | 
			
		||||
        <polygon fill="#60B5CC" points="-130,-44 0,86 130,-44" transform="translate(256 -150) rotate(-270)"/>
 | 
			
		||||
    </g>
 | 
			
		||||
    <path d="m0.936 0.732v30.5h2.19v0.732h-3.04v-32h3.03v0.732z"/>
 | 
			
		||||
 </g>
 | 
			
		||||
</svg>
 | 
			
		||||
| 
		 Before Width: | Height: | Size: 1.2 KiB  | 
							
								
								
									
										2
									
								
								elm.json
								
								
								
								
							
							
						
						
									
										2
									
								
								elm.json
								
								
								
								
							| 
						 | 
				
			
			@ -3,7 +3,7 @@
 | 
			
		|||
    "name": "noordstar/elm-matrix-sdk-beta",
 | 
			
		||||
    "summary": "Matrix SDK for instant communication. Unstable beta version for testing only.",
 | 
			
		||||
    "license": "EUPL-1.1",
 | 
			
		||||
    "version": "3.2.0",
 | 
			
		||||
    "version": "3.1.0",
 | 
			
		||||
    "exposed-modules": [
 | 
			
		||||
        "Matrix",
 | 
			
		||||
        "Matrix.Event",
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,4 +1,4 @@
 | 
			
		|||
module Internal.Api.BaseUrl.Api exposing (baseUrl)
 | 
			
		||||
module Internal.Api.BaseUrl.Api exposing (..)
 | 
			
		||||
 | 
			
		||||
{-|
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -7,30 +7,31 @@ module Internal.Api.BaseUrl.Api exposing (baseUrl)
 | 
			
		|||
 | 
			
		||||
This module looks for the right homeserver address.
 | 
			
		||||
 | 
			
		||||
@docs baseUrl
 | 
			
		||||
 | 
			
		||||
-}
 | 
			
		||||
 | 
			
		||||
import Internal.Api.Chain as C
 | 
			
		||||
import Internal.Api.Request as R
 | 
			
		||||
import Internal.Config.Leaks as L
 | 
			
		||||
import Internal.Config.Log exposing (log)
 | 
			
		||||
import Internal.Config.Text as Text
 | 
			
		||||
import Internal.Tools.Json as Json
 | 
			
		||||
import Internal.Values.Context as Context
 | 
			
		||||
import Internal.Values.Envelope as E
 | 
			
		||||
import Internal.Values.Vault as V
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
{-| Get the homeserver base URL of a given server name.
 | 
			
		||||
-}
 | 
			
		||||
baseUrl : BaseUrlInput -> C.TaskChain R.Error (E.EnvelopeUpdate V.VaultUpdate) ph { ph | baseUrl : () }
 | 
			
		||||
baseUrl data =
 | 
			
		||||
    R.toChain
 | 
			
		||||
        { logHttp =
 | 
			
		||||
            \r ->
 | 
			
		||||
                ( E.HttpRequest r
 | 
			
		||||
                , Text.logs.httpRequest r.method r.url
 | 
			
		||||
                , String.concat
 | 
			
		||||
                    -- TODO: Move this to Internal.Config.Text module
 | 
			
		||||
                    [ "Matrix HTTP: "
 | 
			
		||||
                    , r.method
 | 
			
		||||
                    , " "
 | 
			
		||||
                    , r.url
 | 
			
		||||
                    ]
 | 
			
		||||
                    |> log.info
 | 
			
		||||
                    |> List.singleton
 | 
			
		||||
                )
 | 
			
		||||
| 
						 | 
				
			
			@ -47,7 +48,12 @@ baseUrl data =
 | 
			
		|||
        , toUpdate =
 | 
			
		||||
            \info ->
 | 
			
		||||
                ( E.SetBaseUrl info.homeserver.baseUrl
 | 
			
		||||
                , Text.logs.baseUrlFound data.url info.homeserver.baseUrl
 | 
			
		||||
                , String.concat
 | 
			
		||||
                    [ "Found baseURL of "
 | 
			
		||||
                    , data.url
 | 
			
		||||
                    , " at address "
 | 
			
		||||
                    , info.homeserver.baseUrl
 | 
			
		||||
                    ]
 | 
			
		||||
                    |> log.debug
 | 
			
		||||
                    |> List.singleton
 | 
			
		||||
                )
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,7 +1,7 @@
 | 
			
		|||
module Internal.Api.Chain exposing
 | 
			
		||||
    ( TaskChain, CompleteChain
 | 
			
		||||
    , IdemChain, toTask
 | 
			
		||||
    , fail, succeed, andThen, catchWith, maybe
 | 
			
		||||
    , fail, succeed, andThen, catchWith
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
{-|
 | 
			
		||||
| 
						 | 
				
			
			@ -27,7 +27,7 @@ avoid leaking values passing through the API in unexpected ways.
 | 
			
		|||
 | 
			
		||||
## Operations
 | 
			
		||||
 | 
			
		||||
@docs fail, succeed, andThen, catchWith, maybe
 | 
			
		||||
@docs fail, succeed, andThen, catchWith
 | 
			
		||||
 | 
			
		||||
-}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -15,7 +15,6 @@ retrieve this event e.g. by being a member in the room for this event.
 | 
			
		|||
import Internal.Api.Api as A
 | 
			
		||||
import Internal.Api.Request as R
 | 
			
		||||
import Internal.Config.Log exposing (log)
 | 
			
		||||
import Internal.Config.Text as Text
 | 
			
		||||
import Internal.Tools.Json as Json
 | 
			
		||||
import Internal.Tools.Timestamp as Timestamp
 | 
			
		||||
import Internal.Values.Envelope as E
 | 
			
		||||
| 
						 | 
				
			
			@ -86,7 +85,7 @@ getEventV1 { eventId, roomId } =
 | 
			
		|||
            \event ->
 | 
			
		||||
                ( E.ContentUpdate <| V.MapRoom roomId (Room.AddEvent event)
 | 
			
		||||
                , event.eventId
 | 
			
		||||
                    |> Text.logs.getEventId
 | 
			
		||||
                    |> (++) "Received event id "
 | 
			
		||||
                    |> log.debug
 | 
			
		||||
                    |> List.singleton
 | 
			
		||||
                )
 | 
			
		||||
| 
						 | 
				
			
			@ -110,7 +109,7 @@ getEventV2 { eventId, roomId } =
 | 
			
		|||
            \event ->
 | 
			
		||||
                ( E.ContentUpdate <| V.MapRoom roomId (Room.AddEvent event)
 | 
			
		||||
                , event.eventId
 | 
			
		||||
                    |> Text.logs.getEventId
 | 
			
		||||
                    |> (++) "Received event id "
 | 
			
		||||
                    |> log.debug
 | 
			
		||||
                    |> List.singleton
 | 
			
		||||
                )
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -21,7 +21,6 @@ event to the room.
 | 
			
		|||
import Internal.Api.Api as A
 | 
			
		||||
import Internal.Api.Request as R
 | 
			
		||||
import Internal.Config.Log exposing (log)
 | 
			
		||||
import Internal.Config.Text as Text
 | 
			
		||||
import Internal.Tools.Json as Json
 | 
			
		||||
import Internal.Values.Envelope as E
 | 
			
		||||
import Internal.Values.Room as Room
 | 
			
		||||
| 
						 | 
				
			
			@ -96,7 +95,13 @@ inviteV1 { roomId, user } =
 | 
			
		|||
        , toUpdate =
 | 
			
		||||
            always
 | 
			
		||||
                ( E.ContentUpdate <| V.MapRoom roomId (Room.Invite user)
 | 
			
		||||
                , Text.logs.invitedUser (User.toString user) roomId
 | 
			
		||||
                , String.concat
 | 
			
		||||
                    -- TODO: Move to Internal.Config.Text
 | 
			
		||||
                    [ "Invited user "
 | 
			
		||||
                    , User.toString user
 | 
			
		||||
                    , " to room "
 | 
			
		||||
                    , roomId
 | 
			
		||||
                    ]
 | 
			
		||||
                    |> log.debug
 | 
			
		||||
                    |> List.singleton
 | 
			
		||||
                )
 | 
			
		||||
| 
						 | 
				
			
			@ -120,7 +125,13 @@ inviteV2 { reason, roomId, user } =
 | 
			
		|||
        , toUpdate =
 | 
			
		||||
            always
 | 
			
		||||
                ( E.ContentUpdate <| V.MapRoom roomId (Room.Invite user)
 | 
			
		||||
                , Text.logs.invitedUser (User.toString user) roomId
 | 
			
		||||
                , String.concat
 | 
			
		||||
                    -- TODO: Move to Internal.Config.Text
 | 
			
		||||
                    [ "Invited user "
 | 
			
		||||
                    , User.toString user
 | 
			
		||||
                    , " to room "
 | 
			
		||||
                    , roomId
 | 
			
		||||
                    ]
 | 
			
		||||
                    |> log.debug
 | 
			
		||||
                    |> List.singleton
 | 
			
		||||
                )
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -14,8 +14,6 @@ This module allows the user to log in using a username and password.
 | 
			
		|||
import Internal.Api.Api as A
 | 
			
		||||
import Internal.Api.Request as R
 | 
			
		||||
import Internal.Config.Leaks as L
 | 
			
		||||
import Internal.Config.Log exposing (log)
 | 
			
		||||
import Internal.Config.Text as Text
 | 
			
		||||
import Internal.Tools.Json as Json
 | 
			
		||||
import Internal.Values.Context as Context
 | 
			
		||||
import Internal.Values.Envelope as E
 | 
			
		||||
| 
						 | 
				
			
			@ -24,8 +22,6 @@ import Internal.Values.Vault as V
 | 
			
		|||
import Json.Encode as E
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
{-| Log in using a username and password.
 | 
			
		||||
-}
 | 
			
		||||
loginWithUsernameAndPassword : LoginWithUsernameAndPasswordInput -> A.TaskChain (Phantom a) (Phantom { a | accessToken : () })
 | 
			
		||||
loginWithUsernameAndPassword =
 | 
			
		||||
    A.startWithVersion "r0.0.0" loginWithUsernameAndPasswordV1
 | 
			
		||||
| 
						 | 
				
			
			@ -50,10 +46,8 @@ loginWithUsernameAndPassword =
 | 
			
		|||
        |> A.versionChain
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
{-| Context needed for logging in with a username and password
 | 
			
		||||
-}
 | 
			
		||||
type alias Phantom a =
 | 
			
		||||
    { a | baseUrl : (), now : (), versions : () }
 | 
			
		||||
    { a | baseUrl : (), versions : () }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
type alias LoginWithUsernameAndPasswordInput =
 | 
			
		||||
| 
						 | 
				
			
			@ -165,354 +159,333 @@ type alias PhantomV1 a =
 | 
			
		|||
 | 
			
		||||
 | 
			
		||||
loginWithUsernameAndPasswordV1 : LoginWithUsernameAndPasswordInputV1 i -> A.TaskChain (PhantomV1 a) (PhantomV1 { a | accessToken : () })
 | 
			
		||||
loginWithUsernameAndPasswordV1 { username, password } =
 | 
			
		||||
    \context ->
 | 
			
		||||
        A.request
 | 
			
		||||
            { attributes =
 | 
			
		||||
                [ R.bodyString "password" password
 | 
			
		||||
                , R.bodyString "type" "m.login.password"
 | 
			
		||||
                , R.bodyString "user" username
 | 
			
		||||
                , R.onStatusCode 400 "M_UNKNOWN"
 | 
			
		||||
                , R.onStatusCode 403 "M_FORBIDDEN"
 | 
			
		||||
                ]
 | 
			
		||||
            , coder = coderV1
 | 
			
		||||
            , method = "POST"
 | 
			
		||||
            , path = [ "_matrix", "client", "r0", "login" ]
 | 
			
		||||
            , contextChange =
 | 
			
		||||
                \out -> Context.setAccessToken out.accessToken
 | 
			
		||||
            , toUpdate =
 | 
			
		||||
                \out ->
 | 
			
		||||
                    ( E.More
 | 
			
		||||
                        [ E.SetAccessToken
 | 
			
		||||
                            { created = Context.getNow context
 | 
			
		||||
                            , expiryMs = Nothing
 | 
			
		||||
                            , lastUsed = Context.getNow context
 | 
			
		||||
                            , refresh = out.refreshToken
 | 
			
		||||
                            , value = out.accessToken
 | 
			
		||||
                            }
 | 
			
		||||
                        , out.user
 | 
			
		||||
                            |> Maybe.map (V.SetUser >> E.ContentUpdate)
 | 
			
		||||
                            |> E.Optional
 | 
			
		||||
                        ]
 | 
			
		||||
                    , Text.logs.loggedInAs username
 | 
			
		||||
                        |> log.debug
 | 
			
		||||
                        |> List.singleton
 | 
			
		||||
                    )
 | 
			
		||||
            }
 | 
			
		||||
            context
 | 
			
		||||
loginWithUsernameAndPasswordV1 { username, password } context =
 | 
			
		||||
    A.request
 | 
			
		||||
        { attributes =
 | 
			
		||||
            [ R.bodyString "password" password
 | 
			
		||||
            , R.bodyString "type" "m.login.password"
 | 
			
		||||
            , R.bodyString "user" username
 | 
			
		||||
            , R.onStatusCode 400 "M_UNKNOWN"
 | 
			
		||||
            , R.onStatusCode 403 "M_FORBIDDEN"
 | 
			
		||||
            ]
 | 
			
		||||
        , coder = coderV1
 | 
			
		||||
        , method = "POST"
 | 
			
		||||
        , path = [ "_matrix", "client", "r0", "login" ]
 | 
			
		||||
        , contextChange =
 | 
			
		||||
            \out -> Context.setAccessToken out.accessToken
 | 
			
		||||
        , toUpdate =
 | 
			
		||||
            \out ->
 | 
			
		||||
                ( E.More
 | 
			
		||||
                    [ E.SetAccessToken
 | 
			
		||||
                        { created = Context.getNow context
 | 
			
		||||
                        , expiryMs = Nothing
 | 
			
		||||
                        , lastUsed = Context.getNow context
 | 
			
		||||
                        , refresh = out.refreshToken
 | 
			
		||||
                        , value = out.accessToken
 | 
			
		||||
                        }
 | 
			
		||||
                    , out.user
 | 
			
		||||
                        |> Maybe.map (V.SetUser >> E.ContentUpdate)
 | 
			
		||||
                        |> E.Optional
 | 
			
		||||
                    ]
 | 
			
		||||
                , []
 | 
			
		||||
                )
 | 
			
		||||
        }
 | 
			
		||||
        context
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
loginWithUsernameAndPasswordV2 : LoginWithUsernameAndPasswordInputV2 i -> A.TaskChain (PhantomV1 a) (PhantomV1 { a | accessToken : () })
 | 
			
		||||
loginWithUsernameAndPasswordV2 { deviceId, initialDeviceDisplayName, username, password } =
 | 
			
		||||
    \context ->
 | 
			
		||||
        A.request
 | 
			
		||||
            { attributes =
 | 
			
		||||
                [ R.bodyOpString "device_id" deviceId
 | 
			
		||||
                , R.bodyOpString "initial_device_display_name" initialDeviceDisplayName
 | 
			
		||||
                , R.bodyString "password" password
 | 
			
		||||
                , R.bodyString "type" "m.login.password"
 | 
			
		||||
                , R.bodyString "user" username
 | 
			
		||||
                , R.onStatusCode 400 "M_UNKNOWN"
 | 
			
		||||
                , R.onStatusCode 403 "M_FORBIDDEN"
 | 
			
		||||
                , R.onStatusCode 429 "string" -- Yup. That's what it says.
 | 
			
		||||
                ]
 | 
			
		||||
            , coder = coderV2
 | 
			
		||||
            , method = "POST"
 | 
			
		||||
            , path = [ "_matrix", "client", "r0", "login" ]
 | 
			
		||||
            , contextChange =
 | 
			
		||||
                \out -> Context.setAccessToken out.accessToken
 | 
			
		||||
            , toUpdate =
 | 
			
		||||
                \out ->
 | 
			
		||||
                    ( E.More
 | 
			
		||||
                        [ E.SetAccessToken
 | 
			
		||||
                            { created = Context.getNow context
 | 
			
		||||
                            , expiryMs = Nothing
 | 
			
		||||
                            , lastUsed = Context.getNow context
 | 
			
		||||
                            , refresh = Nothing
 | 
			
		||||
                            , value = out.accessToken
 | 
			
		||||
                            }
 | 
			
		||||
                        , out.user
 | 
			
		||||
                            |> Maybe.map (V.SetUser >> E.ContentUpdate)
 | 
			
		||||
                            |> E.Optional
 | 
			
		||||
                        , out.deviceId
 | 
			
		||||
                            |> Maybe.map E.SetDeviceId
 | 
			
		||||
                            |> E.Optional
 | 
			
		||||
                        ]
 | 
			
		||||
                    , Text.logs.loggedInAs username
 | 
			
		||||
                        |> log.debug
 | 
			
		||||
                        |> List.singleton
 | 
			
		||||
                    )
 | 
			
		||||
            }
 | 
			
		||||
            context
 | 
			
		||||
loginWithUsernameAndPasswordV2 { deviceId, initialDeviceDisplayName, username, password } context =
 | 
			
		||||
    A.request
 | 
			
		||||
        { attributes =
 | 
			
		||||
            [ R.bodyOpString "device_id" deviceId
 | 
			
		||||
            , R.bodyOpString "initial_device_display_name" initialDeviceDisplayName
 | 
			
		||||
            , R.bodyString "password" password
 | 
			
		||||
            , R.bodyString "type" "m.login.password"
 | 
			
		||||
            , R.bodyString "user" username
 | 
			
		||||
            , R.onStatusCode 400 "M_UNKNOWN"
 | 
			
		||||
            , R.onStatusCode 403 "M_FORBIDDEN"
 | 
			
		||||
            , R.onStatusCode 429 "string" -- Yup. That's what it says.
 | 
			
		||||
            ]
 | 
			
		||||
        , coder = coderV2
 | 
			
		||||
        , method = "POST"
 | 
			
		||||
        , path = [ "_matrix", "client", "r0", "login" ]
 | 
			
		||||
        , contextChange =
 | 
			
		||||
            \out -> Context.setAccessToken out.accessToken
 | 
			
		||||
        , toUpdate =
 | 
			
		||||
            \out ->
 | 
			
		||||
                ( E.More
 | 
			
		||||
                    [ E.SetAccessToken
 | 
			
		||||
                        { created = Context.getNow context
 | 
			
		||||
                        , expiryMs = Nothing
 | 
			
		||||
                        , lastUsed = Context.getNow context
 | 
			
		||||
                        , refresh = Nothing
 | 
			
		||||
                        , value = out.accessToken
 | 
			
		||||
                        }
 | 
			
		||||
                    , out.user
 | 
			
		||||
                        |> Maybe.map (V.SetUser >> E.ContentUpdate)
 | 
			
		||||
                        |> E.Optional
 | 
			
		||||
                    , out.deviceId
 | 
			
		||||
                        |> Maybe.map E.SetDeviceId
 | 
			
		||||
                        |> E.Optional
 | 
			
		||||
                    ]
 | 
			
		||||
                , []
 | 
			
		||||
                )
 | 
			
		||||
        }
 | 
			
		||||
        context
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
loginWithUsernameAndPasswordV3 : LoginWithUsernameAndPasswordInputV2 i -> A.TaskChain (PhantomV1 a) (PhantomV1 { a | accessToken : () })
 | 
			
		||||
loginWithUsernameAndPasswordV3 { deviceId, initialDeviceDisplayName, username, password } =
 | 
			
		||||
    \context ->
 | 
			
		||||
        A.request
 | 
			
		||||
            { attributes =
 | 
			
		||||
                [ R.bodyOpString "address" Nothing
 | 
			
		||||
                , R.bodyOpString "device_id" deviceId
 | 
			
		||||
                , R.bodyValue "identifier"
 | 
			
		||||
                    (E.object
 | 
			
		||||
                        [ ( "type", E.string "m.id.user" )
 | 
			
		||||
                        , ( "user", E.string username )
 | 
			
		||||
                        ]
 | 
			
		||||
                    )
 | 
			
		||||
                , R.bodyOpString "initial_device_display_name" initialDeviceDisplayName
 | 
			
		||||
                , R.bodyString "password" password
 | 
			
		||||
                , R.bodyString "type" "m.login.password"
 | 
			
		||||
                , R.bodyString "user" username
 | 
			
		||||
                , R.onStatusCode 400 "M_UNKNOWN"
 | 
			
		||||
                , R.onStatusCode 403 "M_FORBIDDEN"
 | 
			
		||||
                , R.onStatusCode 429 "M_LIMIT_EXCEEDED"
 | 
			
		||||
                ]
 | 
			
		||||
            , coder = coderV3
 | 
			
		||||
            , method = "POST"
 | 
			
		||||
            , path = [ "_matrix", "client", "r0", "login" ]
 | 
			
		||||
            , contextChange =
 | 
			
		||||
                \out -> Context.setAccessToken out.accessToken
 | 
			
		||||
            , toUpdate =
 | 
			
		||||
                \out ->
 | 
			
		||||
                    ( E.More
 | 
			
		||||
                        [ E.SetAccessToken
 | 
			
		||||
                            { created = Context.getNow context
 | 
			
		||||
                            , expiryMs = Nothing
 | 
			
		||||
                            , lastUsed = Context.getNow context
 | 
			
		||||
                            , refresh = Nothing
 | 
			
		||||
                            , value = out.accessToken
 | 
			
		||||
                            }
 | 
			
		||||
                        , out.user
 | 
			
		||||
                            |> Maybe.map (V.SetUser >> E.ContentUpdate)
 | 
			
		||||
                            |> E.Optional
 | 
			
		||||
                        , out.deviceId
 | 
			
		||||
                            |> Maybe.map E.SetDeviceId
 | 
			
		||||
                            |> E.Optional
 | 
			
		||||
                        ]
 | 
			
		||||
                    , Text.logs.loggedInAs username
 | 
			
		||||
                        |> log.debug
 | 
			
		||||
                        |> List.singleton
 | 
			
		||||
                    )
 | 
			
		||||
            }
 | 
			
		||||
            context
 | 
			
		||||
loginWithUsernameAndPasswordV3 { deviceId, initialDeviceDisplayName, username, password } context =
 | 
			
		||||
    A.request
 | 
			
		||||
        { attributes =
 | 
			
		||||
            [ R.bodyOpString "address" Nothing
 | 
			
		||||
            , R.bodyOpString "device_id" deviceId
 | 
			
		||||
            , R.bodyValue "identifier"
 | 
			
		||||
                (E.object
 | 
			
		||||
                    [ ( "type", E.string "m.id.user" )
 | 
			
		||||
                    , ( "user", E.string username )
 | 
			
		||||
                    ]
 | 
			
		||||
                )
 | 
			
		||||
            , R.bodyOpString "initial_device_display_name" initialDeviceDisplayName
 | 
			
		||||
            , R.bodyString "password" password
 | 
			
		||||
            , R.bodyString "type" "m.login.password"
 | 
			
		||||
            , R.bodyString "user" username
 | 
			
		||||
            , R.onStatusCode 400 "M_UNKNOWN"
 | 
			
		||||
            , R.onStatusCode 403 "M_FORBIDDEN"
 | 
			
		||||
            , R.onStatusCode 429 "M_LIMIT_EXCEEDED"
 | 
			
		||||
            ]
 | 
			
		||||
        , coder = coderV3
 | 
			
		||||
        , method = "POST"
 | 
			
		||||
        , path = [ "_matrix", "client", "r0", "login" ]
 | 
			
		||||
        , contextChange =
 | 
			
		||||
            \out -> Context.setAccessToken out.accessToken
 | 
			
		||||
        , toUpdate =
 | 
			
		||||
            \out ->
 | 
			
		||||
                ( E.More
 | 
			
		||||
                    [ E.SetAccessToken
 | 
			
		||||
                        { created = Context.getNow context
 | 
			
		||||
                        , expiryMs = Nothing
 | 
			
		||||
                        , lastUsed = Context.getNow context
 | 
			
		||||
                        , refresh = Nothing
 | 
			
		||||
                        , value = out.accessToken
 | 
			
		||||
                        }
 | 
			
		||||
                    , out.user
 | 
			
		||||
                        |> Maybe.map (V.SetUser >> E.ContentUpdate)
 | 
			
		||||
                        |> E.Optional
 | 
			
		||||
                    , out.deviceId
 | 
			
		||||
                        |> Maybe.map E.SetDeviceId
 | 
			
		||||
                        |> E.Optional
 | 
			
		||||
                    ]
 | 
			
		||||
                , []
 | 
			
		||||
                )
 | 
			
		||||
        }
 | 
			
		||||
        context
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
loginWithUsernameAndPasswordV4 : LoginWithUsernameAndPasswordInputV2 i -> A.TaskChain (PhantomV1 a) (PhantomV1 { a | accessToken : () })
 | 
			
		||||
loginWithUsernameAndPasswordV4 { deviceId, initialDeviceDisplayName, username, password } =
 | 
			
		||||
    \context ->
 | 
			
		||||
        A.request
 | 
			
		||||
            { attributes =
 | 
			
		||||
                [ R.bodyOpString "address" Nothing
 | 
			
		||||
                , R.bodyOpString "device_id" deviceId
 | 
			
		||||
                , R.bodyValue "identifier"
 | 
			
		||||
                    (E.object
 | 
			
		||||
                        [ ( "type", E.string "m.id.user" )
 | 
			
		||||
                        , ( "user", E.string username )
 | 
			
		||||
                        ]
 | 
			
		||||
                    )
 | 
			
		||||
                , R.bodyOpString "initial_device_display_name" initialDeviceDisplayName
 | 
			
		||||
                , R.bodyString "password" password
 | 
			
		||||
                , R.bodyString "type" "m.login.password"
 | 
			
		||||
                , R.bodyString "user" username
 | 
			
		||||
                , R.onStatusCode 400 "M_UNKNOWN"
 | 
			
		||||
                , R.onStatusCode 403 "M_FORBIDDEN"
 | 
			
		||||
                , R.onStatusCode 429 "M_LIMIT_EXCEEDED"
 | 
			
		||||
                ]
 | 
			
		||||
            , coder = coderV4
 | 
			
		||||
            , method = "POST"
 | 
			
		||||
            , path = [ "_matrix", "client", "r0", "login" ]
 | 
			
		||||
            , contextChange =
 | 
			
		||||
                \out -> Context.setAccessToken out.accessToken
 | 
			
		||||
            , toUpdate =
 | 
			
		||||
                \out ->
 | 
			
		||||
                    ( E.More
 | 
			
		||||
                        [ E.SetAccessToken
 | 
			
		||||
                            { created = Context.getNow context
 | 
			
		||||
                            , expiryMs = Nothing
 | 
			
		||||
                            , lastUsed = Context.getNow context
 | 
			
		||||
                            , refresh = Nothing
 | 
			
		||||
                            , value = out.accessToken
 | 
			
		||||
                            }
 | 
			
		||||
                        , out.user
 | 
			
		||||
                            |> Maybe.map (V.SetUser >> E.ContentUpdate)
 | 
			
		||||
                            |> E.Optional
 | 
			
		||||
                        , out.wellKnown
 | 
			
		||||
                            |> Maybe.map (.homeserver >> .baseUrl)
 | 
			
		||||
                            |> Maybe.map E.SetBaseUrl
 | 
			
		||||
                            |> E.Optional
 | 
			
		||||
                        , out.deviceId
 | 
			
		||||
                            |> Maybe.map E.SetDeviceId
 | 
			
		||||
                            |> E.Optional
 | 
			
		||||
                        ]
 | 
			
		||||
                    , Text.logs.loggedInAs username
 | 
			
		||||
                        |> log.debug
 | 
			
		||||
                        |> List.singleton
 | 
			
		||||
                    )
 | 
			
		||||
            }
 | 
			
		||||
            context
 | 
			
		||||
loginWithUsernameAndPasswordV4 { deviceId, initialDeviceDisplayName, username, password } context =
 | 
			
		||||
    A.request
 | 
			
		||||
        { attributes =
 | 
			
		||||
            [ R.bodyOpString "address" Nothing
 | 
			
		||||
            , R.bodyOpString "device_id" deviceId
 | 
			
		||||
            , R.bodyValue "identifier"
 | 
			
		||||
                (E.object
 | 
			
		||||
                    [ ( "type", E.string "m.id.user" )
 | 
			
		||||
                    , ( "user", E.string username )
 | 
			
		||||
                    ]
 | 
			
		||||
                )
 | 
			
		||||
            , R.bodyOpString "initial_device_display_name" initialDeviceDisplayName
 | 
			
		||||
            , R.bodyString "password" password
 | 
			
		||||
            , R.bodyString "type" "m.login.password"
 | 
			
		||||
            , R.bodyString "user" username
 | 
			
		||||
            , R.onStatusCode 400 "M_UNKNOWN"
 | 
			
		||||
            , R.onStatusCode 403 "M_FORBIDDEN"
 | 
			
		||||
            , R.onStatusCode 429 "M_LIMIT_EXCEEDED"
 | 
			
		||||
            ]
 | 
			
		||||
        , coder = coderV4
 | 
			
		||||
        , method = "POST"
 | 
			
		||||
        , path = [ "_matrix", "client", "r0", "login" ]
 | 
			
		||||
        , contextChange =
 | 
			
		||||
            \out -> Context.setAccessToken out.accessToken
 | 
			
		||||
        , toUpdate =
 | 
			
		||||
            \out ->
 | 
			
		||||
                ( E.More
 | 
			
		||||
                    [ E.SetAccessToken
 | 
			
		||||
                        { created = Context.getNow context
 | 
			
		||||
                        , expiryMs = Nothing
 | 
			
		||||
                        , lastUsed = Context.getNow context
 | 
			
		||||
                        , refresh = Nothing
 | 
			
		||||
                        , value = out.accessToken
 | 
			
		||||
                        }
 | 
			
		||||
                    , out.user
 | 
			
		||||
                        |> Maybe.map (V.SetUser >> E.ContentUpdate)
 | 
			
		||||
                        |> E.Optional
 | 
			
		||||
                    , out.wellKnown
 | 
			
		||||
                        |> Maybe.map (.homeserver >> .baseUrl)
 | 
			
		||||
                        |> Maybe.map E.SetBaseUrl
 | 
			
		||||
                        |> E.Optional
 | 
			
		||||
                    , out.deviceId
 | 
			
		||||
                        |> Maybe.map E.SetDeviceId
 | 
			
		||||
                        |> E.Optional
 | 
			
		||||
                    ]
 | 
			
		||||
                , []
 | 
			
		||||
                )
 | 
			
		||||
        }
 | 
			
		||||
        context
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
loginWithUsernameAndPasswordV5 : LoginWithUsernameAndPasswordInputV2 i -> A.TaskChain (PhantomV1 a) (PhantomV1 { a | accessToken : () })
 | 
			
		||||
loginWithUsernameAndPasswordV5 { deviceId, initialDeviceDisplayName, username, password } =
 | 
			
		||||
    \context ->
 | 
			
		||||
        A.request
 | 
			
		||||
            { attributes =
 | 
			
		||||
                [ R.bodyOpString "address" Nothing
 | 
			
		||||
                , R.bodyOpString "device_id" deviceId
 | 
			
		||||
                , R.bodyValue "identifier"
 | 
			
		||||
                    (E.object
 | 
			
		||||
                        [ ( "type", E.string "m.id.user" )
 | 
			
		||||
                        , ( "user", E.string username )
 | 
			
		||||
                        ]
 | 
			
		||||
                    )
 | 
			
		||||
                , R.bodyOpString "initial_device_display_name" initialDeviceDisplayName
 | 
			
		||||
                , R.bodyString "password" password
 | 
			
		||||
                , R.bodyString "type" "m.login.password"
 | 
			
		||||
                , R.bodyString "user" username
 | 
			
		||||
                , R.onStatusCode 400 "M_UNKNOWN"
 | 
			
		||||
                , R.onStatusCode 403 "M_FORBIDDEN"
 | 
			
		||||
                , R.onStatusCode 429 "M_LIMIT_EXCEEDED"
 | 
			
		||||
                ]
 | 
			
		||||
            , coder = coderV4
 | 
			
		||||
            , method = "POST"
 | 
			
		||||
            , path = [ "_matrix", "client", "v3", "login" ]
 | 
			
		||||
            , contextChange =
 | 
			
		||||
                \out -> Context.setAccessToken out.accessToken
 | 
			
		||||
            , toUpdate =
 | 
			
		||||
                \out ->
 | 
			
		||||
                    ( E.More
 | 
			
		||||
                        [ E.SetAccessToken
 | 
			
		||||
                            { created = Context.getNow context
 | 
			
		||||
                            , expiryMs = Nothing
 | 
			
		||||
                            , lastUsed = Context.getNow context
 | 
			
		||||
                            , refresh = Nothing
 | 
			
		||||
                            , value = out.accessToken
 | 
			
		||||
                            }
 | 
			
		||||
                        , out.user
 | 
			
		||||
                            |> Maybe.map (V.SetUser >> E.ContentUpdate)
 | 
			
		||||
                            |> E.Optional
 | 
			
		||||
                        , out.wellKnown
 | 
			
		||||
                            |> Maybe.map (.homeserver >> .baseUrl)
 | 
			
		||||
                            |> Maybe.map E.SetBaseUrl
 | 
			
		||||
                            |> E.Optional
 | 
			
		||||
                        , out.deviceId
 | 
			
		||||
                            |> Maybe.map E.SetDeviceId
 | 
			
		||||
                            |> E.Optional
 | 
			
		||||
                        ]
 | 
			
		||||
                    , Text.logs.loggedInAs username
 | 
			
		||||
                        |> log.debug
 | 
			
		||||
                        |> List.singleton
 | 
			
		||||
                    )
 | 
			
		||||
            }
 | 
			
		||||
            context
 | 
			
		||||
loginWithUsernameAndPasswordV5 { deviceId, initialDeviceDisplayName, username, password } context =
 | 
			
		||||
    A.request
 | 
			
		||||
        { attributes =
 | 
			
		||||
            [ R.bodyOpString "address" Nothing
 | 
			
		||||
            , R.bodyOpString "device_id" deviceId
 | 
			
		||||
            , R.bodyValue "identifier"
 | 
			
		||||
                (E.object
 | 
			
		||||
                    [ ( "type", E.string "m.id.user" )
 | 
			
		||||
                    , ( "user", E.string username )
 | 
			
		||||
                    ]
 | 
			
		||||
                )
 | 
			
		||||
            , R.bodyOpString "initial_device_display_name" initialDeviceDisplayName
 | 
			
		||||
            , R.bodyString "password" password
 | 
			
		||||
            , R.bodyString "type" "m.login.password"
 | 
			
		||||
            , R.bodyString "user" username
 | 
			
		||||
            , R.onStatusCode 400 "M_UNKNOWN"
 | 
			
		||||
            , R.onStatusCode 403 "M_FORBIDDEN"
 | 
			
		||||
            , R.onStatusCode 429 "M_LIMIT_EXCEEDED"
 | 
			
		||||
            ]
 | 
			
		||||
        , coder = coderV4
 | 
			
		||||
        , method = "POST"
 | 
			
		||||
        , path = [ "_matrix", "client", "v3", "login" ]
 | 
			
		||||
        , contextChange =
 | 
			
		||||
            \out -> Context.setAccessToken out.accessToken
 | 
			
		||||
        , toUpdate =
 | 
			
		||||
            \out ->
 | 
			
		||||
                ( E.More
 | 
			
		||||
                    [ E.SetAccessToken
 | 
			
		||||
                        { created = Context.getNow context
 | 
			
		||||
                        , expiryMs = Nothing
 | 
			
		||||
                        , lastUsed = Context.getNow context
 | 
			
		||||
                        , refresh = Nothing
 | 
			
		||||
                        , value = out.accessToken
 | 
			
		||||
                        }
 | 
			
		||||
                    , out.user
 | 
			
		||||
                        |> Maybe.map (V.SetUser >> E.ContentUpdate)
 | 
			
		||||
                        |> E.Optional
 | 
			
		||||
                    , out.wellKnown
 | 
			
		||||
                        |> Maybe.map (.homeserver >> .baseUrl)
 | 
			
		||||
                        |> Maybe.map E.SetBaseUrl
 | 
			
		||||
                        |> E.Optional
 | 
			
		||||
                    , out.deviceId
 | 
			
		||||
                        |> Maybe.map E.SetDeviceId
 | 
			
		||||
                        |> E.Optional
 | 
			
		||||
                    ]
 | 
			
		||||
                , []
 | 
			
		||||
                )
 | 
			
		||||
        }
 | 
			
		||||
        context
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
loginWithUsernameAndPasswordV6 : LoginWithUsernameAndPasswordInputV3 i -> A.TaskChain (PhantomV1 a) (PhantomV1 { a | accessToken : () })
 | 
			
		||||
loginWithUsernameAndPasswordV6 { deviceId, enableRefreshToken, initialDeviceDisplayName, username, password } =
 | 
			
		||||
    \context ->
 | 
			
		||||
        A.request
 | 
			
		||||
            { attributes =
 | 
			
		||||
                [ R.bodyOpString "address" Nothing
 | 
			
		||||
                , R.bodyOpString "device_id" deviceId
 | 
			
		||||
                , R.bodyValue "identifier"
 | 
			
		||||
                    (E.object
 | 
			
		||||
                        [ ( "type", E.string "m.id.user" )
 | 
			
		||||
                        , ( "user", E.string username )
 | 
			
		||||
                        ]
 | 
			
		||||
                    )
 | 
			
		||||
                , R.bodyOpString "initial_device_display_name" initialDeviceDisplayName
 | 
			
		||||
                , R.bodyString "password" password
 | 
			
		||||
                , R.bodyOpBool "refresh_token" enableRefreshToken
 | 
			
		||||
                , R.bodyString "type" "m.login.password"
 | 
			
		||||
                , R.bodyString "user" username
 | 
			
		||||
                , R.onStatusCode 400 "M_UNKNOWN"
 | 
			
		||||
                , R.onStatusCode 403 "M_FORBIDDEN"
 | 
			
		||||
                , R.onStatusCode 429 "M_LIMIT_EXCEEDED"
 | 
			
		||||
                ]
 | 
			
		||||
            , coder = coderV5
 | 
			
		||||
            , method = "POST"
 | 
			
		||||
            , path = [ "_matrix", "client", "v3", "login" ]
 | 
			
		||||
            , contextChange =
 | 
			
		||||
                \out -> Context.setAccessToken out.accessToken
 | 
			
		||||
            , toUpdate =
 | 
			
		||||
                \out ->
 | 
			
		||||
                    ( E.More
 | 
			
		||||
                        [ E.SetAccessToken
 | 
			
		||||
                            { created = Context.getNow context
 | 
			
		||||
                            , expiryMs = out.expiresInMs
 | 
			
		||||
                            , lastUsed = Context.getNow context
 | 
			
		||||
                            , refresh = out.refreshToken
 | 
			
		||||
                            , value = out.accessToken
 | 
			
		||||
                            }
 | 
			
		||||
                        , out.user
 | 
			
		||||
                            |> Maybe.map (V.SetUser >> E.ContentUpdate)
 | 
			
		||||
                            |> E.Optional
 | 
			
		||||
                        , out.wellKnown
 | 
			
		||||
                            |> Maybe.map (.homeserver >> .baseUrl)
 | 
			
		||||
                            |> Maybe.map E.SetBaseUrl
 | 
			
		||||
                            |> E.Optional
 | 
			
		||||
                        , out.deviceId
 | 
			
		||||
                            |> Maybe.map E.SetDeviceId
 | 
			
		||||
                            |> E.Optional
 | 
			
		||||
                        ]
 | 
			
		||||
                    , Text.logs.loggedInAs username
 | 
			
		||||
                        |> log.debug
 | 
			
		||||
                        |> List.singleton
 | 
			
		||||
                    )
 | 
			
		||||
            }
 | 
			
		||||
            context
 | 
			
		||||
loginWithUsernameAndPasswordV6 { deviceId, enableRefreshToken, initialDeviceDisplayName, username, password } context =
 | 
			
		||||
    A.request
 | 
			
		||||
        { attributes =
 | 
			
		||||
            [ R.bodyOpString "address" Nothing
 | 
			
		||||
            , R.bodyOpString "device_id" deviceId
 | 
			
		||||
            , R.bodyValue "identifier"
 | 
			
		||||
                (E.object
 | 
			
		||||
                    [ ( "type", E.string "m.id.user" )
 | 
			
		||||
                    , ( "user", E.string username )
 | 
			
		||||
                    ]
 | 
			
		||||
                )
 | 
			
		||||
            , R.bodyOpString "initial_device_display_name" initialDeviceDisplayName
 | 
			
		||||
            , R.bodyString "password" password
 | 
			
		||||
            , R.bodyOpBool "refresh_token" enableRefreshToken
 | 
			
		||||
            , R.bodyString "type" "m.login.password"
 | 
			
		||||
            , R.bodyString "user" username
 | 
			
		||||
            , R.onStatusCode 400 "M_UNKNOWN"
 | 
			
		||||
            , R.onStatusCode 403 "M_FORBIDDEN"
 | 
			
		||||
            , R.onStatusCode 429 "M_LIMIT_EXCEEDED"
 | 
			
		||||
            ]
 | 
			
		||||
        , coder = coderV5
 | 
			
		||||
        , method = "POST"
 | 
			
		||||
        , path = [ "_matrix", "client", "v3", "login" ]
 | 
			
		||||
        , contextChange =
 | 
			
		||||
            \out -> Context.setAccessToken out.accessToken
 | 
			
		||||
        , toUpdate =
 | 
			
		||||
            \out ->
 | 
			
		||||
                ( E.More
 | 
			
		||||
                    [ E.SetAccessToken
 | 
			
		||||
                        { created = Context.getNow context
 | 
			
		||||
                        , expiryMs = out.expiresInMs
 | 
			
		||||
                        , lastUsed = Context.getNow context
 | 
			
		||||
                        , refresh = out.refreshToken
 | 
			
		||||
                        , value = out.accessToken
 | 
			
		||||
                        }
 | 
			
		||||
                    , out.user
 | 
			
		||||
                        |> Maybe.map (V.SetUser >> E.ContentUpdate)
 | 
			
		||||
                        |> E.Optional
 | 
			
		||||
                    , out.wellKnown
 | 
			
		||||
                        |> Maybe.map (.homeserver >> .baseUrl)
 | 
			
		||||
                        |> Maybe.map E.SetBaseUrl
 | 
			
		||||
                        |> E.Optional
 | 
			
		||||
                    , out.deviceId
 | 
			
		||||
                        |> Maybe.map E.SetDeviceId
 | 
			
		||||
                        |> E.Optional
 | 
			
		||||
                    ]
 | 
			
		||||
                , []
 | 
			
		||||
                )
 | 
			
		||||
        }
 | 
			
		||||
        context
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
loginWithUsernameAndPasswordV7 : LoginWithUsernameAndPasswordInputV3 i -> A.TaskChain (PhantomV1 a) (PhantomV1 { a | accessToken : () })
 | 
			
		||||
loginWithUsernameAndPasswordV7 { deviceId, enableRefreshToken, initialDeviceDisplayName, username, password } =
 | 
			
		||||
    \context ->
 | 
			
		||||
        A.request
 | 
			
		||||
            { attributes =
 | 
			
		||||
                [ R.bodyOpString "address" Nothing
 | 
			
		||||
                , R.bodyOpString "device_id" deviceId
 | 
			
		||||
                , R.bodyValue "identifier"
 | 
			
		||||
                    (E.object
 | 
			
		||||
                        [ ( "type", E.string "m.id.user" )
 | 
			
		||||
                        , ( "user", E.string username )
 | 
			
		||||
                        ]
 | 
			
		||||
                    )
 | 
			
		||||
                , R.bodyOpString "initial_device_display_name" initialDeviceDisplayName
 | 
			
		||||
                , R.bodyString "password" password
 | 
			
		||||
                , R.bodyOpBool "refresh_token" enableRefreshToken
 | 
			
		||||
                , R.bodyString "type" "m.login.password"
 | 
			
		||||
                , R.bodyString "user" username
 | 
			
		||||
                , R.onStatusCode 400 "M_UNKNOWN"
 | 
			
		||||
                , R.onStatusCode 403 "M_FORBIDDEN"
 | 
			
		||||
                , R.onStatusCode 429 "M_LIMIT_EXCEEDED"
 | 
			
		||||
                ]
 | 
			
		||||
            , coder = coderV6
 | 
			
		||||
            , method = "POST"
 | 
			
		||||
            , path = [ "_matrix", "client", "v3", "login" ]
 | 
			
		||||
            , contextChange =
 | 
			
		||||
                \out -> Context.setAccessToken out.accessToken
 | 
			
		||||
            , toUpdate =
 | 
			
		||||
                \out ->
 | 
			
		||||
                    ( E.More
 | 
			
		||||
                        [ E.SetAccessToken
 | 
			
		||||
                            { created = Context.getNow context
 | 
			
		||||
                            , expiryMs = out.expiresInMs
 | 
			
		||||
                            , lastUsed = Context.getNow context
 | 
			
		||||
                            , refresh = out.refreshToken
 | 
			
		||||
                            , value = out.accessToken
 | 
			
		||||
                            }
 | 
			
		||||
                        , E.ContentUpdate (V.SetUser out.user)
 | 
			
		||||
                        , out.wellKnown
 | 
			
		||||
                            |> Maybe.map (.homeserver >> .baseUrl)
 | 
			
		||||
                            |> Maybe.map E.SetBaseUrl
 | 
			
		||||
                            |> E.Optional
 | 
			
		||||
                        , E.SetDeviceId out.deviceId
 | 
			
		||||
                        ]
 | 
			
		||||
                    , Text.logs.loggedInAs username
 | 
			
		||||
                        |> log.debug
 | 
			
		||||
                        |> List.singleton
 | 
			
		||||
                    )
 | 
			
		||||
            }
 | 
			
		||||
            context
 | 
			
		||||
loginWithUsernameAndPasswordV7 { deviceId, enableRefreshToken, initialDeviceDisplayName, username, password } context =
 | 
			
		||||
    A.request
 | 
			
		||||
        { attributes =
 | 
			
		||||
            [ R.bodyOpString "address" Nothing
 | 
			
		||||
            , R.bodyOpString "device_id" deviceId
 | 
			
		||||
            , R.bodyValue "identifier"
 | 
			
		||||
                (E.object
 | 
			
		||||
                    [ ( "type", E.string "m.id.user" )
 | 
			
		||||
                    , ( "user", E.string username )
 | 
			
		||||
                    ]
 | 
			
		||||
                )
 | 
			
		||||
            , R.bodyOpString "initial_device_display_name" initialDeviceDisplayName
 | 
			
		||||
            , R.bodyString "password" password
 | 
			
		||||
            , R.bodyOpBool "refresh_token" enableRefreshToken
 | 
			
		||||
            , R.bodyString "type" "m.login.password"
 | 
			
		||||
            , R.bodyString "user" username
 | 
			
		||||
            , R.onStatusCode 400 "M_UNKNOWN"
 | 
			
		||||
            , R.onStatusCode 403 "M_FORBIDDEN"
 | 
			
		||||
            , R.onStatusCode 429 "M_LIMIT_EXCEEDED"
 | 
			
		||||
            ]
 | 
			
		||||
        , coder = coderV6
 | 
			
		||||
        , method = "POST"
 | 
			
		||||
        , path = [ "_matrix", "client", "v3", "login" ]
 | 
			
		||||
        , contextChange =
 | 
			
		||||
            \out -> Context.setAccessToken out.accessToken
 | 
			
		||||
        , toUpdate =
 | 
			
		||||
            \out ->
 | 
			
		||||
                ( E.More
 | 
			
		||||
                    [ E.SetAccessToken
 | 
			
		||||
                        { created = Context.getNow context
 | 
			
		||||
                        , expiryMs = out.expiresInMs
 | 
			
		||||
                        , lastUsed = Context.getNow context
 | 
			
		||||
                        , refresh = out.refreshToken
 | 
			
		||||
                        , value = out.accessToken
 | 
			
		||||
                        }
 | 
			
		||||
                    , E.ContentUpdate (V.SetUser out.user)
 | 
			
		||||
                    , out.wellKnown
 | 
			
		||||
                        |> Maybe.map (.homeserver >> .baseUrl)
 | 
			
		||||
                        |> Maybe.map E.SetBaseUrl
 | 
			
		||||
                        |> E.Optional
 | 
			
		||||
                    , E.SetDeviceId out.deviceId
 | 
			
		||||
                    ]
 | 
			
		||||
                , []
 | 
			
		||||
                )
 | 
			
		||||
        }
 | 
			
		||||
        context
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
coderV1 : Json.Coder LoginWithUsernameAndPasswordOutputV1
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -28,8 +28,6 @@ import Internal.Values.Context as Context
 | 
			
		|||
import Internal.Values.Envelope as E
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
{-| Update message type that is being returned.
 | 
			
		||||
-}
 | 
			
		||||
type alias Msg =
 | 
			
		||||
    Backpack
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -13,28 +13,25 @@ Get the current time.
 | 
			
		|||
 | 
			
		||||
import Internal.Api.Api as A
 | 
			
		||||
import Internal.Config.Log exposing (log)
 | 
			
		||||
import Internal.Config.Text as Text
 | 
			
		||||
import Internal.Values.Context as Context
 | 
			
		||||
import Internal.Values.Envelope as E
 | 
			
		||||
import Task
 | 
			
		||||
import Time
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
{-| Get the current time and place it in the context.
 | 
			
		||||
-}
 | 
			
		||||
getNow : A.TaskChain a { a | now : () }
 | 
			
		||||
getNow =
 | 
			
		||||
    \_ ->
 | 
			
		||||
        Task.map
 | 
			
		||||
            (\now ->
 | 
			
		||||
                { messages = [ E.SetNow now ]
 | 
			
		||||
                , logs =
 | 
			
		||||
                    now
 | 
			
		||||
                        |> Time.posixToMillis
 | 
			
		||||
                        |> Text.logs.getNow
 | 
			
		||||
                        |> log.debug
 | 
			
		||||
                        |> List.singleton
 | 
			
		||||
                , contextChange = Context.setNow now
 | 
			
		||||
                }
 | 
			
		||||
            )
 | 
			
		||||
            Time.now
 | 
			
		||||
getNow _ =
 | 
			
		||||
    Task.map
 | 
			
		||||
        (\now ->
 | 
			
		||||
            { messages = [ E.SetNow now ]
 | 
			
		||||
            , logs =
 | 
			
		||||
                [ "Identified current time at Unix time "
 | 
			
		||||
                , now |> Time.posixToMillis |> String.fromInt
 | 
			
		||||
                ]
 | 
			
		||||
                    |> String.concat
 | 
			
		||||
                    |> log.debug
 | 
			
		||||
                    |> List.singleton
 | 
			
		||||
            , contextChange = Context.setNow now
 | 
			
		||||
            }
 | 
			
		||||
        )
 | 
			
		||||
        Time.now
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -287,7 +287,7 @@ fullBody value _ =
 | 
			
		|||
    FullBody value
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
getBody : List ContextAttr -> Maybe Json.Value
 | 
			
		||||
getBody : List ContextAttr -> Json.Value
 | 
			
		||||
getBody attributes =
 | 
			
		||||
    attributes
 | 
			
		||||
        |> List.filterMap
 | 
			
		||||
| 
						 | 
				
			
			@ -301,30 +301,19 @@ getBody attributes =
 | 
			
		|||
            )
 | 
			
		||||
        |> List.reverse
 | 
			
		||||
        |> List.head
 | 
			
		||||
        |> (\fb ->
 | 
			
		||||
                case fb of
 | 
			
		||||
                    Just _ ->
 | 
			
		||||
                        fb
 | 
			
		||||
        |> Maybe.withDefault
 | 
			
		||||
            (List.filterMap
 | 
			
		||||
                (\attr ->
 | 
			
		||||
                    case attr of
 | 
			
		||||
                        BodyParam key value ->
 | 
			
		||||
                            Just ( key, value )
 | 
			
		||||
 | 
			
		||||
                    Nothing ->
 | 
			
		||||
                        case
 | 
			
		||||
                            List.filterMap
 | 
			
		||||
                                (\attr ->
 | 
			
		||||
                                    case attr of
 | 
			
		||||
                                        BodyParam key value ->
 | 
			
		||||
                                            Just ( key, value )
 | 
			
		||||
 | 
			
		||||
                                        _ ->
 | 
			
		||||
                                            Nothing
 | 
			
		||||
                                )
 | 
			
		||||
                                attributes
 | 
			
		||||
                        of
 | 
			
		||||
                            [] ->
 | 
			
		||||
                                Nothing
 | 
			
		||||
 | 
			
		||||
                            head :: tail ->
 | 
			
		||||
                                Just <| E.object (head :: tail)
 | 
			
		||||
           )
 | 
			
		||||
                        _ ->
 | 
			
		||||
                            Nothing
 | 
			
		||||
                )
 | 
			
		||||
                attributes
 | 
			
		||||
                |> E.object
 | 
			
		||||
            )
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
getHeaders : List ContextAttr -> List Http.Header
 | 
			
		||||
| 
						 | 
				
			
			@ -490,21 +479,21 @@ rawApiCallResolver decoder statusCodeErrors =
 | 
			
		|||
                    Http.BadUrl s
 | 
			
		||||
                        |> InternetException
 | 
			
		||||
                        |> Tuple.pair
 | 
			
		||||
                        |> (|>) [ log.error ("Encountered bad URL " ++ s) ]
 | 
			
		||||
                        |> (|>) []
 | 
			
		||||
                        |> Err
 | 
			
		||||
 | 
			
		||||
                Http.Timeout_ ->
 | 
			
		||||
                    Http.Timeout
 | 
			
		||||
                        |> InternetException
 | 
			
		||||
                        |> Tuple.pair
 | 
			
		||||
                        |> (|>) [ log.error "Encountered timeout - maybe the server is down?" ]
 | 
			
		||||
                        |> (|>) []
 | 
			
		||||
                        |> Err
 | 
			
		||||
 | 
			
		||||
                Http.NetworkError_ ->
 | 
			
		||||
                    Http.NetworkError
 | 
			
		||||
                        |> InternetException
 | 
			
		||||
                        |> Tuple.pair
 | 
			
		||||
                        |> (|>) [ log.error "Encountered a network error - the user might be offline" ]
 | 
			
		||||
                        |> (|>) []
 | 
			
		||||
                        |> Err
 | 
			
		||||
 | 
			
		||||
                Http.BadStatus_ metadata body ->
 | 
			
		||||
| 
						 | 
				
			
			@ -545,10 +534,7 @@ toChain data apiContext =
 | 
			
		|||
                        { method = call.method
 | 
			
		||||
                        , headers = getHeaders call.attributes
 | 
			
		||||
                        , url = getUrl call
 | 
			
		||||
                        , body =
 | 
			
		||||
                            getBody call.attributes
 | 
			
		||||
                                |> Maybe.map Http.jsonBody
 | 
			
		||||
                                |> Maybe.withDefault Http.emptyBody
 | 
			
		||||
                        , body = Http.jsonBody (getBody call.attributes)
 | 
			
		||||
                        , resolver = rawApiCallResolver (Json.decode data.coder) (getStatusCodes call.attributes)
 | 
			
		||||
                        , timeout = getTimeout call.attributes
 | 
			
		||||
                        }
 | 
			
		||||
| 
						 | 
				
			
			@ -558,10 +544,7 @@ toChain data apiContext =
 | 
			
		|||
                        { method = call.method
 | 
			
		||||
                        , headers = getHeaders call.attributes
 | 
			
		||||
                        , url = getUrl call
 | 
			
		||||
                        , body =
 | 
			
		||||
                            getBody call.attributes
 | 
			
		||||
                                |> Maybe.map Http.jsonBody
 | 
			
		||||
                                |> Maybe.withDefault Http.emptyBody
 | 
			
		||||
                        , body = Http.jsonBody (getBody call.attributes)
 | 
			
		||||
                        , resolver =
 | 
			
		||||
                            rawApiCallResolver
 | 
			
		||||
                                (Json.decode data.coder
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,4 +1,4 @@
 | 
			
		|||
module Internal.Api.SendMessageEvent.Api exposing (Phantom, sendMessageEvent)
 | 
			
		||||
module Internal.Api.SendMessageEvent.Api exposing (..)
 | 
			
		||||
 | 
			
		||||
{-|
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -7,7 +7,7 @@ module Internal.Api.SendMessageEvent.Api exposing (Phantom, sendMessageEvent)
 | 
			
		|||
 | 
			
		||||
This module helps send message events to rooms on the Matrix API.
 | 
			
		||||
 | 
			
		||||
@docs Phantom, sendMessageEvent
 | 
			
		||||
@docs Phantom
 | 
			
		||||
 | 
			
		||||
-}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -15,13 +15,10 @@ import Internal.Api.Api as A
 | 
			
		|||
import Internal.Api.Request as R
 | 
			
		||||
import Internal.Config.Leaks as L
 | 
			
		||||
import Internal.Config.Log exposing (log)
 | 
			
		||||
import Internal.Config.Text as Text
 | 
			
		||||
import Internal.Tools.Json as Json
 | 
			
		||||
import Internal.Values.Envelope as E
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
{-| Send a message event to the Matrix room.
 | 
			
		||||
-}
 | 
			
		||||
sendMessageEvent : SendMessageEventInput -> A.TaskChain (Phantom a) (Phantom a)
 | 
			
		||||
sendMessageEvent =
 | 
			
		||||
    A.startWithVersion "r0.0.0" sendMessageEventV1
 | 
			
		||||
| 
						 | 
				
			
			@ -47,10 +44,8 @@ sendMessageEvent =
 | 
			
		|||
        |> A.versionChain
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
{-| Context needed for sending a message event
 | 
			
		||||
-}
 | 
			
		||||
type alias Phantom a =
 | 
			
		||||
    { a | accessToken : (), baseUrl : (), versions : () }
 | 
			
		||||
    a
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
type alias PhantomV1 a =
 | 
			
		||||
| 
						 | 
				
			
			@ -85,7 +80,7 @@ type alias SendMessageEventOutputV2 =
 | 
			
		|||
sendMessageEventV1 : SendMessageEventInputV1 i -> A.TaskChain (PhantomV1 a) (PhantomV1 a)
 | 
			
		||||
sendMessageEventV1 { content, eventType, roomId, transactionId } =
 | 
			
		||||
    A.request
 | 
			
		||||
        { attributes = [ R.accessToken, R.fullBody content ]
 | 
			
		||||
        { attributes = [ R.fullBody content ]
 | 
			
		||||
        , coder = coderV1
 | 
			
		||||
        , contextChange = always identity
 | 
			
		||||
        , method = "PUT"
 | 
			
		||||
| 
						 | 
				
			
			@ -94,7 +89,9 @@ sendMessageEventV1 { content, eventType, roomId, transactionId } =
 | 
			
		|||
            \out ->
 | 
			
		||||
                ( E.More []
 | 
			
		||||
                , out.eventId
 | 
			
		||||
                    |> Text.logs.sendEvent
 | 
			
		||||
                    |> Maybe.map ((++) ", received event id ")
 | 
			
		||||
                    |> Maybe.withDefault ""
 | 
			
		||||
                    |> (++) "Sent event"
 | 
			
		||||
                    |> log.debug
 | 
			
		||||
                    |> List.singleton
 | 
			
		||||
                )
 | 
			
		||||
| 
						 | 
				
			
			@ -104,7 +101,7 @@ sendMessageEventV1 { content, eventType, roomId, transactionId } =
 | 
			
		|||
sendMessageEventV2 : SendMessageEventInputV1 i -> A.TaskChain (PhantomV1 a) (PhantomV1 a)
 | 
			
		||||
sendMessageEventV2 { content, eventType, roomId, transactionId } =
 | 
			
		||||
    A.request
 | 
			
		||||
        { attributes = [ R.accessToken, R.fullBody content ]
 | 
			
		||||
        { attributes = [ R.fullBody content ]
 | 
			
		||||
        , coder = coderV2
 | 
			
		||||
        , contextChange = always identity
 | 
			
		||||
        , method = "PUT"
 | 
			
		||||
| 
						 | 
				
			
			@ -113,8 +110,7 @@ sendMessageEventV2 { content, eventType, roomId, transactionId } =
 | 
			
		|||
            \out ->
 | 
			
		||||
                ( E.More []
 | 
			
		||||
                , out.eventId
 | 
			
		||||
                    |> Maybe.Just
 | 
			
		||||
                    |> Text.logs.sendEvent
 | 
			
		||||
                    |> (++) "Sent event, received event id "
 | 
			
		||||
                    |> log.debug
 | 
			
		||||
                    |> List.singleton
 | 
			
		||||
                )
 | 
			
		||||
| 
						 | 
				
			
			@ -124,7 +120,7 @@ sendMessageEventV2 { content, eventType, roomId, transactionId } =
 | 
			
		|||
sendMessageEventV3 : SendMessageEventInputV1 i -> A.TaskChain (PhantomV1 a) (PhantomV1 a)
 | 
			
		||||
sendMessageEventV3 { content, eventType, roomId, transactionId } =
 | 
			
		||||
    A.request
 | 
			
		||||
        { attributes = [ R.accessToken, R.fullBody content ]
 | 
			
		||||
        { attributes = [ R.fullBody content ]
 | 
			
		||||
        , coder = coderV2
 | 
			
		||||
        , contextChange = always identity
 | 
			
		||||
        , method = "PUT"
 | 
			
		||||
| 
						 | 
				
			
			@ -133,8 +129,7 @@ sendMessageEventV3 { content, eventType, roomId, transactionId } =
 | 
			
		|||
            \out ->
 | 
			
		||||
                ( E.More []
 | 
			
		||||
                , out.eventId
 | 
			
		||||
                    |> Maybe.Just
 | 
			
		||||
                    |> Text.logs.sendEvent
 | 
			
		||||
                    |> (++) "Sent event, received event id "
 | 
			
		||||
                    |> log.debug
 | 
			
		||||
                    |> List.singleton
 | 
			
		||||
                )
 | 
			
		||||
| 
						 | 
				
			
			@ -166,7 +161,7 @@ coderV1 =
 | 
			
		|||
        (Json.field.optional.value
 | 
			
		||||
            { fieldName = "event_id"
 | 
			
		||||
            , toField = .eventId
 | 
			
		||||
            , description = [ "A unique identifier for the event." ]
 | 
			
		||||
            , description = Debug.todo "Needs docs"
 | 
			
		||||
            , coder = Json.string
 | 
			
		||||
            }
 | 
			
		||||
        )
 | 
			
		||||
| 
						 | 
				
			
			@ -179,7 +174,7 @@ coderV2 =
 | 
			
		|||
        , description =
 | 
			
		||||
            [ "This endpoint is used to send a message event to a room. Message events allow access to historical events and pagination, making them suited for \"once-off\" activity in a room."
 | 
			
		||||
            , "The body of the request should be the content object of the event; the fields in this object will vary depending on the type of event."
 | 
			
		||||
            , "https://spec.matrix.org/legacy/client_server/r0.6.1.html#put-matrix-client-r0-rooms-roomid-send-eventtype-txnid"
 | 
			
		||||
            , "https://spec.matrix.org/legacy/r0.0.0/client_server.html#put-matrix-client-r0-rooms-roomid-send-eventtype-txnid"
 | 
			
		||||
            ]
 | 
			
		||||
        , init = always SendMessageEventOutputV2
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -197,7 +192,7 @@ coderV2 =
 | 
			
		|||
        (Json.field.required
 | 
			
		||||
            { fieldName = "event_id"
 | 
			
		||||
            , toField = .eventId
 | 
			
		||||
            , description = [ "A unique identifier for the event." ]
 | 
			
		||||
            , description = Debug.todo "Needs docs"
 | 
			
		||||
            , coder = Json.string
 | 
			
		||||
            }
 | 
			
		||||
        )
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -65,7 +65,7 @@ type alias UFTask a b =
 | 
			
		|||
 | 
			
		||||
{-| Get an access token to talk to the Matrix API
 | 
			
		||||
-}
 | 
			
		||||
getAccessToken : UFTask { a | baseUrl : (), now : (), versions : () } { a | accessToken : (), baseUrl : (), now : (), versions : () }
 | 
			
		||||
getAccessToken : UFTask { a | now : () } { a | accessToken : (), now : () }
 | 
			
		||||
getAccessToken c =
 | 
			
		||||
    case Context.fromApiFormat c of
 | 
			
		||||
        context ->
 | 
			
		||||
| 
						 | 
				
			
			@ -149,43 +149,11 @@ finishTask uftask =
 | 
			
		|||
                }
 | 
			
		||||
            )
 | 
			
		||||
        |> C.catchWith
 | 
			
		||||
            (\e ->
 | 
			
		||||
                case e of
 | 
			
		||||
                    Request.MissingPassword ->
 | 
			
		||||
                        { messages = []
 | 
			
		||||
                        , logs = [ log.error "Cannot log in - password is missing" ]
 | 
			
		||||
                        , contextChange = Context.reset
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                    Request.MissingUsername ->
 | 
			
		||||
                        { messages = []
 | 
			
		||||
                        , logs = [ log.error "Cannot log in - username is missing" ]
 | 
			
		||||
                        , contextChange = Context.reset
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                    Request.NoSupportedVersion ->
 | 
			
		||||
                        { messages = []
 | 
			
		||||
                        , logs = [ log.error "No supported version is available to complete the API interaction." ]
 | 
			
		||||
                        , contextChange = Context.reset
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                    Request.ServerReturnsBadJSON t ->
 | 
			
		||||
                        { messages = []
 | 
			
		||||
                        , logs = [ log.error ("The server returned invalid JSON: " ++ t) ]
 | 
			
		||||
                        , contextChange = Context.reset
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                    Request.ServerReturnsError name _ ->
 | 
			
		||||
                        { messages = []
 | 
			
		||||
                        , logs = [ log.error ("The server returns an error: " ++ name) ]
 | 
			
		||||
                        , contextChange = Context.reset
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                    _ ->
 | 
			
		||||
                        { messages = [] -- TODO: Maybe categorize errors?
 | 
			
		||||
                        , logs = [ log.warn "Encountered unhandled error" ]
 | 
			
		||||
                        , contextChange = Context.reset
 | 
			
		||||
                        }
 | 
			
		||||
            (\_ ->
 | 
			
		||||
                { messages = [] -- TODO: Maybe categorize errors?
 | 
			
		||||
                , logs = [ log.warn "Encountered unhandled error" ]
 | 
			
		||||
                , contextChange = Context.reset
 | 
			
		||||
                }
 | 
			
		||||
            )
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -23,7 +23,7 @@ will assume until overriden by the user.
 | 
			
		|||
-}
 | 
			
		||||
currentVersion : String
 | 
			
		||||
currentVersion =
 | 
			
		||||
    "beta 3.2.0"
 | 
			
		||||
    "beta 3.1.0"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
{-| The default device name that is being communicated with the Matrix API.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -112,8 +112,7 @@ decodedDictSize from to =
 | 
			
		|||
{-| Documentation used for all functions and data types in JSON coders
 | 
			
		||||
-}
 | 
			
		||||
docs :
 | 
			
		||||
    { accessToken : TypeDocs
 | 
			
		||||
    , context : TypeDocs
 | 
			
		||||
    { context : TypeDocs
 | 
			
		||||
    , envelope : TypeDocs
 | 
			
		||||
    , event : TypeDocs
 | 
			
		||||
    , hashdict : TypeDocs
 | 
			
		||||
| 
						 | 
				
			
			@ -128,16 +127,9 @@ docs :
 | 
			
		|||
    , timelineFilter : TypeDocs
 | 
			
		||||
    , unsigned : TypeDocs
 | 
			
		||||
    , vault : TypeDocs
 | 
			
		||||
    , versions : TypeDocs
 | 
			
		||||
    }
 | 
			
		||||
docs =
 | 
			
		||||
    { accessToken =
 | 
			
		||||
        { name = "Access Token"
 | 
			
		||||
        , description =
 | 
			
		||||
            [ "The Access Token type stores information about an access token - its value, when it expires, and how one may get a new access token when the current value expires."
 | 
			
		||||
            ]
 | 
			
		||||
        }
 | 
			
		||||
    , context =
 | 
			
		||||
    { context =
 | 
			
		||||
        { name = "Context"
 | 
			
		||||
        , description =
 | 
			
		||||
            [ "The Context is the set of variables that the user (mostly) cannot control."
 | 
			
		||||
| 
						 | 
				
			
			@ -231,12 +223,6 @@ docs =
 | 
			
		|||
            [ "Main type storing all relevant information from the Matrix API."
 | 
			
		||||
            ]
 | 
			
		||||
        }
 | 
			
		||||
    , versions =
 | 
			
		||||
        { name = "Versions"
 | 
			
		||||
        , description =
 | 
			
		||||
            [ "Versions type describing the supported spec versions and MSC properties."
 | 
			
		||||
            ]
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -258,24 +244,14 @@ failures =
 | 
			
		|||
what they do and what they are for.
 | 
			
		||||
-}
 | 
			
		||||
fields :
 | 
			
		||||
    { accessToken :
 | 
			
		||||
        { created : Desc
 | 
			
		||||
        , expiryMs : Desc
 | 
			
		||||
        , lastUsed : Desc
 | 
			
		||||
        , refresh : Desc
 | 
			
		||||
        , value : Desc
 | 
			
		||||
        }
 | 
			
		||||
    , context :
 | 
			
		||||
    { context :
 | 
			
		||||
        { accessToken : Desc
 | 
			
		||||
        , baseUrl : Desc
 | 
			
		||||
        , deviceId : Desc
 | 
			
		||||
        , experimental : Desc
 | 
			
		||||
        , now : Desc
 | 
			
		||||
        , password : Desc
 | 
			
		||||
        , refreshToken : Desc
 | 
			
		||||
        , username : Desc
 | 
			
		||||
        , serverName : Desc
 | 
			
		||||
        , suggestedAccessToken : Desc
 | 
			
		||||
        , transaction : Desc
 | 
			
		||||
        , versions : Desc
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -345,51 +321,25 @@ fields :
 | 
			
		|||
    , vault :
 | 
			
		||||
        { accountData : Desc
 | 
			
		||||
        , rooms : Desc
 | 
			
		||||
        , user : Desc
 | 
			
		||||
        }
 | 
			
		||||
    , versions :
 | 
			
		||||
        { unstableFeatures : Desc
 | 
			
		||||
        , versions : Desc
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
fields =
 | 
			
		||||
    { accessToken =
 | 
			
		||||
        { created =
 | 
			
		||||
            [ "Timestamp of when the access token was received." ]
 | 
			
		||||
        , expiryMs =
 | 
			
		||||
            [ "Given time in milliseconds of when the access token might expire." ]
 | 
			
		||||
        , lastUsed =
 | 
			
		||||
            [ "Timestamp of when the access token was last used." ]
 | 
			
		||||
        , refresh =
 | 
			
		||||
            [ "Refresh token used to gain a new access token." ]
 | 
			
		||||
        , value =
 | 
			
		||||
            [ "Secret access token value." ]
 | 
			
		||||
        }
 | 
			
		||||
    , context =
 | 
			
		||||
    { context =
 | 
			
		||||
        { accessToken =
 | 
			
		||||
            [ "The access token used for authentication with the Matrix server."
 | 
			
		||||
            ]
 | 
			
		||||
        , baseUrl =
 | 
			
		||||
            [ "The base URL of the Matrix server."
 | 
			
		||||
            ]
 | 
			
		||||
        , deviceId =
 | 
			
		||||
            [ "The reported device ID according to the API."
 | 
			
		||||
            ]
 | 
			
		||||
        , experimental =
 | 
			
		||||
            [ "Experimental features supported by the homeserver."
 | 
			
		||||
            ]
 | 
			
		||||
        , now =
 | 
			
		||||
            [ "The most recently found timestamp."
 | 
			
		||||
            ]
 | 
			
		||||
        , password =
 | 
			
		||||
            [ "The user's password for authentication purposes."
 | 
			
		||||
            ]
 | 
			
		||||
        , refreshToken =
 | 
			
		||||
            [ "The token used to obtain a new access token upon expiration of the current access token."
 | 
			
		||||
            ]
 | 
			
		||||
        , suggestedAccessToken =
 | 
			
		||||
            [ "An access token provided with no context by the user."
 | 
			
		||||
            ]
 | 
			
		||||
        , username =
 | 
			
		||||
            [ "The username of the Matrix account."
 | 
			
		||||
            ]
 | 
			
		||||
| 
						 | 
				
			
			@ -560,16 +510,6 @@ fields =
 | 
			
		|||
        , rooms =
 | 
			
		||||
            [ "Directory of joined rooms that the user is a member of."
 | 
			
		||||
            ]
 | 
			
		||||
        , user =
 | 
			
		||||
            [ "User that the Vault is logging in as."
 | 
			
		||||
            ]
 | 
			
		||||
        }
 | 
			
		||||
    , versions =
 | 
			
		||||
        { unstableFeatures =
 | 
			
		||||
            [ "Unstable features such as experimental MSCs that are supported by a homeserver."
 | 
			
		||||
            ]
 | 
			
		||||
        , versions =
 | 
			
		||||
            [ "Spec versions supported by a homeserver." ]
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -605,51 +545,18 @@ happened. Most of these unexpected results, are taken account of by the Elm SDK,
 | 
			
		|||
but logged so that the programmer can do something about it.
 | 
			
		||||
-}
 | 
			
		||||
logs :
 | 
			
		||||
    { baseUrlFound : String -> String -> String
 | 
			
		||||
    , getEventId : String -> String
 | 
			
		||||
    , getNow : Int -> String
 | 
			
		||||
    , httpRequest : String -> String -> String
 | 
			
		||||
    , invitedUser : String -> String -> String
 | 
			
		||||
    , keyIsNotAnInt : String -> String
 | 
			
		||||
    , loggedInAs : String -> String
 | 
			
		||||
    , sendEvent : Maybe String -> String
 | 
			
		||||
    { keyIsNotAnInt : String -> String
 | 
			
		||||
    , serverReturnedInvalidJSON : String -> String
 | 
			
		||||
    , serverReturnedUnknownJSON : String -> String
 | 
			
		||||
    }
 | 
			
		||||
logs =
 | 
			
		||||
    { baseUrlFound =
 | 
			
		||||
        \url baseUrl ->
 | 
			
		||||
            String.concat [ "Found baseURL of ", url, " at address ", baseUrl ]
 | 
			
		||||
    , getEventId = (++) "Received event with id = "
 | 
			
		||||
    , getNow =
 | 
			
		||||
        \now ->
 | 
			
		||||
            String.concat
 | 
			
		||||
                [ "Identified current time at Unix time "
 | 
			
		||||
                , String.fromInt now
 | 
			
		||||
                ]
 | 
			
		||||
    , httpRequest =
 | 
			
		||||
        \method url -> String.concat [ "Matrix HTTP: ", method, " ", url ]
 | 
			
		||||
    , invitedUser =
 | 
			
		||||
        \userId roomId ->
 | 
			
		||||
            String.concat [ "Invited user ", userId, " to room ", roomId ]
 | 
			
		||||
    , keyIsNotAnInt =
 | 
			
		||||
    { keyIsNotAnInt =
 | 
			
		||||
        \key ->
 | 
			
		||||
            String.concat
 | 
			
		||||
                [ "Encountered a key `"
 | 
			
		||||
                , key
 | 
			
		||||
                , "` that cannot be converted to an Int"
 | 
			
		||||
                ]
 | 
			
		||||
    , loggedInAs =
 | 
			
		||||
        \username ->
 | 
			
		||||
            String.concat [ "Successfully logged in as user ", username ]
 | 
			
		||||
    , sendEvent =
 | 
			
		||||
        \eventId ->
 | 
			
		||||
            case eventId of
 | 
			
		||||
                Just e ->
 | 
			
		||||
                    "Sent event, received event id " ++ e
 | 
			
		||||
 | 
			
		||||
                Nothing ->
 | 
			
		||||
                    "Sent event, event id not known - make sure to check transaction id"
 | 
			
		||||
    , serverReturnedInvalidJSON = (++) "The server returned invalid JSON: "
 | 
			
		||||
    , serverReturnedUnknownJSON = (++) "The server returned JSON that doesn't seem to live up to spec rules: "
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -50,6 +50,8 @@ for interacting with the Matrix API.
 | 
			
		|||
import Internal.Config.Text as Text
 | 
			
		||||
import Internal.Grammar.UserId as U
 | 
			
		||||
import Internal.Tools.Json as Json
 | 
			
		||||
import Json.Decode as D
 | 
			
		||||
import Json.Encode as E
 | 
			
		||||
import Set exposing (Set)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -174,14 +174,14 @@ coder =
 | 
			
		|||
        (Json.field.optional.value
 | 
			
		||||
            { fieldName = "deviceId"
 | 
			
		||||
            , toField = .deviceId
 | 
			
		||||
            , description = Text.fields.context.deviceId
 | 
			
		||||
            , description = Debug.todo "Needs docs"
 | 
			
		||||
            , coder = Json.string
 | 
			
		||||
            }
 | 
			
		||||
        )
 | 
			
		||||
        (Json.field.optional.value
 | 
			
		||||
            { fieldName = "now"
 | 
			
		||||
            , toField = .now
 | 
			
		||||
            , description = Text.fields.context.now
 | 
			
		||||
            , description = Debug.todo "Needs docs"
 | 
			
		||||
            , coder = Timestamp.coder
 | 
			
		||||
            }
 | 
			
		||||
        )
 | 
			
		||||
| 
						 | 
				
			
			@ -209,7 +209,7 @@ coder =
 | 
			
		|||
        (Json.field.optional.value
 | 
			
		||||
            { fieldName = "suggestedAccessToken"
 | 
			
		||||
            , toField = always Nothing -- Do not save
 | 
			
		||||
            , description = Text.fields.context.suggestedAccessToken
 | 
			
		||||
            , description = Debug.todo "Needs docs"
 | 
			
		||||
            , coder = Json.string
 | 
			
		||||
            }
 | 
			
		||||
        )
 | 
			
		||||
| 
						 | 
				
			
			@ -241,42 +241,42 @@ coder =
 | 
			
		|||
coderAccessToken : Json.Coder AccessToken
 | 
			
		||||
coderAccessToken =
 | 
			
		||||
    Json.object5
 | 
			
		||||
        { name = Text.docs.accessToken.name
 | 
			
		||||
        , description = Text.docs.accessToken.description
 | 
			
		||||
        { name = Debug.todo "Needs docs"
 | 
			
		||||
        , description = Debug.todo "Needs docs"
 | 
			
		||||
        , init = AccessToken
 | 
			
		||||
        }
 | 
			
		||||
        (Json.field.required
 | 
			
		||||
            { fieldName = "created"
 | 
			
		||||
            , toField = .created
 | 
			
		||||
            , description = Text.fields.accessToken.created
 | 
			
		||||
            , description = Debug.todo "Needs docs"
 | 
			
		||||
            , coder = Timestamp.coder
 | 
			
		||||
            }
 | 
			
		||||
        )
 | 
			
		||||
        (Json.field.optional.value
 | 
			
		||||
            { fieldName = "expiryMs"
 | 
			
		||||
            , toField = .expiryMs
 | 
			
		||||
            , description = Text.fields.accessToken.expiryMs
 | 
			
		||||
            , description = Debug.todo "Needs docs"
 | 
			
		||||
            , coder = Json.int
 | 
			
		||||
            }
 | 
			
		||||
        )
 | 
			
		||||
        (Json.field.required
 | 
			
		||||
            { fieldName = "lastUsed"
 | 
			
		||||
            , toField = .lastUsed
 | 
			
		||||
            , description = Text.fields.accessToken.lastUsed
 | 
			
		||||
            , description = Debug.todo "Needs docs"
 | 
			
		||||
            , coder = Timestamp.coder
 | 
			
		||||
            }
 | 
			
		||||
        )
 | 
			
		||||
        (Json.field.optional.value
 | 
			
		||||
            { fieldName = "refresh"
 | 
			
		||||
            , toField = .refresh
 | 
			
		||||
            , description = Text.fields.accessToken.refresh
 | 
			
		||||
            , description = Debug.todo "Needs docs"
 | 
			
		||||
            , coder = Json.string
 | 
			
		||||
            }
 | 
			
		||||
        )
 | 
			
		||||
        (Json.field.required
 | 
			
		||||
            { fieldName = "value"
 | 
			
		||||
            , toField = .value
 | 
			
		||||
            , description = Text.fields.accessToken.value
 | 
			
		||||
            , description = Debug.todo "Needs docs"
 | 
			
		||||
            , coder = Json.string
 | 
			
		||||
            }
 | 
			
		||||
        )
 | 
			
		||||
| 
						 | 
				
			
			@ -318,28 +318,23 @@ init sn =
 | 
			
		|||
-}
 | 
			
		||||
mostPopularToken : Context -> Maybe String
 | 
			
		||||
mostPopularToken c =
 | 
			
		||||
    case c.suggestedAccessToken of
 | 
			
		||||
        Just _ ->
 | 
			
		||||
            c.suggestedAccessToken
 | 
			
		||||
    c.accessTokens
 | 
			
		||||
        |> Hashdict.values
 | 
			
		||||
        |> List.sortBy
 | 
			
		||||
            (\token ->
 | 
			
		||||
                case token.expiryMs of
 | 
			
		||||
                    Nothing ->
 | 
			
		||||
                        ( 0, Timestamp.toMs token.created )
 | 
			
		||||
 | 
			
		||||
        Nothing ->
 | 
			
		||||
            c.accessTokens
 | 
			
		||||
                |> Hashdict.values
 | 
			
		||||
                |> List.sortBy
 | 
			
		||||
                    (\token ->
 | 
			
		||||
                        case token.expiryMs of
 | 
			
		||||
                            Nothing ->
 | 
			
		||||
                                ( 0, Timestamp.toMs token.created )
 | 
			
		||||
 | 
			
		||||
                            Just e ->
 | 
			
		||||
                                ( 1
 | 
			
		||||
                                , token.created
 | 
			
		||||
                                    |> Timestamp.add e
 | 
			
		||||
                                    |> Timestamp.toMs
 | 
			
		||||
                                )
 | 
			
		||||
                    )
 | 
			
		||||
                |> List.head
 | 
			
		||||
                |> Maybe.map .value
 | 
			
		||||
                    Just e ->
 | 
			
		||||
                        ( 1
 | 
			
		||||
                        , token.created
 | 
			
		||||
                            |> Timestamp.add e
 | 
			
		||||
                            |> Timestamp.toMs
 | 
			
		||||
                        )
 | 
			
		||||
            )
 | 
			
		||||
        |> List.head
 | 
			
		||||
        |> Maybe.map .value
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
{-| Reset the phantom type of the Context, effectively forgetting all values.
 | 
			
		||||
| 
						 | 
				
			
			@ -422,21 +417,21 @@ setVersions value (APIContext c) =
 | 
			
		|||
versionsCoder : Json.Coder Versions
 | 
			
		||||
versionsCoder =
 | 
			
		||||
    Json.object2
 | 
			
		||||
        { name = Text.docs.versions.name
 | 
			
		||||
        , description = Text.docs.versions.description
 | 
			
		||||
        { name = Debug.todo "Add name" -- Text.docs.versions.name
 | 
			
		||||
        , description = Debug.todo "Add description" -- Text.docs.versions.description
 | 
			
		||||
        , init = Versions
 | 
			
		||||
        }
 | 
			
		||||
        (Json.field.required
 | 
			
		||||
            { fieldName = "versions"
 | 
			
		||||
            , toField = .versions
 | 
			
		||||
            , description = Text.fields.versions.versions
 | 
			
		||||
            , description = Debug.todo "Add description"
 | 
			
		||||
            , coder = Json.list Json.string
 | 
			
		||||
            }
 | 
			
		||||
        )
 | 
			
		||||
        (Json.field.optional.withDefault
 | 
			
		||||
            { fieldName = "unstableFeatures"
 | 
			
		||||
            , toField = .unstableFeatures
 | 
			
		||||
            , description = Text.fields.versions.unstableFeatures
 | 
			
		||||
            , description = Debug.todo "Add description"
 | 
			
		||||
            , coder = Json.set Json.string
 | 
			
		||||
            , default = ( Set.empty, [] )
 | 
			
		||||
            , defaultToString = Json.encode (Json.set Json.string) >> E.encode 0
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -56,7 +56,7 @@ import Internal.Tools.Json as Json
 | 
			
		|||
import Internal.Values.Event as Event exposing (Event)
 | 
			
		||||
import Internal.Values.StateManager as StateManager exposing (StateManager)
 | 
			
		||||
import Internal.Values.Timeline as Timeline exposing (Timeline)
 | 
			
		||||
import Internal.Values.User exposing (User)
 | 
			
		||||
import Internal.Values.User as User exposing (User)
 | 
			
		||||
import Json.Encode as E
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -255,7 +255,7 @@ update ru room =
 | 
			
		|||
        AddSync batch ->
 | 
			
		||||
            addSync batch room
 | 
			
		||||
 | 
			
		||||
        Invite _ ->
 | 
			
		||||
        Invite user ->
 | 
			
		||||
            -- TODO: Invite user
 | 
			
		||||
            room
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -36,7 +36,7 @@ Since the username is safely parsed, one can get these parts of the username.
 | 
			
		|||
 | 
			
		||||
-}
 | 
			
		||||
 | 
			
		||||
import Internal.Config.Log exposing (log)
 | 
			
		||||
import Internal.Config.Log as Log exposing (log)
 | 
			
		||||
import Internal.Grammar.ServerName as ServerName
 | 
			
		||||
import Internal.Grammar.UserId as UserId
 | 
			
		||||
import Internal.Tools.Json as Json
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -33,6 +33,8 @@ Rooms are environments where people can have a conversation with each other.
 | 
			
		|||
-}
 | 
			
		||||
 | 
			
		||||
import FastDict as Dict exposing (Dict)
 | 
			
		||||
import Internal.Api.Request as Request
 | 
			
		||||
import Internal.Config.Log exposing (Log)
 | 
			
		||||
import Internal.Config.Text as Text
 | 
			
		||||
import Internal.Tools.Hashdict as Hashdict exposing (Hashdict)
 | 
			
		||||
import Internal.Tools.Json as Json
 | 
			
		||||
| 
						 | 
				
			
			@ -84,7 +86,7 @@ coder =
 | 
			
		|||
        (Json.field.required
 | 
			
		||||
            { fieldName = "user"
 | 
			
		||||
            , toField = .user
 | 
			
		||||
            , description = Text.fields.vault.user
 | 
			
		||||
            , description = Debug.todo "Needs description"
 | 
			
		||||
            , coder = User.coder
 | 
			
		||||
            }
 | 
			
		||||
        )
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,7 +1,7 @@
 | 
			
		|||
module Matrix exposing
 | 
			
		||||
    ( Vault, fromUserId
 | 
			
		||||
    ( Vault
 | 
			
		||||
    , VaultUpdate, update
 | 
			
		||||
    , addAccessToken, sendMessageEvent
 | 
			
		||||
    , sendMessageEvent, fromUserId
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
{-|
 | 
			
		||||
| 
						 | 
				
			
			@ -29,16 +29,16 @@ support a monolithic public registry. (:
 | 
			
		|||
 | 
			
		||||
## Debugging
 | 
			
		||||
 | 
			
		||||
@docs addAccessToken, sendMessageEvent
 | 
			
		||||
@docs sendMessageEvent
 | 
			
		||||
 | 
			
		||||
-}
 | 
			
		||||
 | 
			
		||||
import Internal.Api.Main as Api
 | 
			
		||||
import Internal.Values.Envelope as Envelope
 | 
			
		||||
import Internal.Values.User as User
 | 
			
		||||
import Internal.Values.Vault as Internal
 | 
			
		||||
import Json.Encode as E
 | 
			
		||||
import Types exposing (Vault(..), VaultUpdate(..))
 | 
			
		||||
import Internal.Values.User as User
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
{-| The Vault type stores all relevant information about the Matrix API.
 | 
			
		||||
| 
						 | 
				
			
			@ -56,22 +56,18 @@ type alias Vault =
 | 
			
		|||
type alias VaultUpdate =
 | 
			
		||||
    Types.VaultUpdate
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
addAccessToken : String -> Vault -> Vault
 | 
			
		||||
addAccessToken token (Vault vault) =
 | 
			
		||||
    Envelope.mapContext (\c -> { c | suggestedAccessToken = Just token }) vault
 | 
			
		||||
        |> Vault
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
{-| Use a fully-fledged Matrix ID to connect.
 | 
			
		||||
 | 
			
		||||
    case Matrix.fromUserId "@alice:example.org" of
 | 
			
		||||
        Just vault ->
 | 
			
		||||
            "We got a vault!"
 | 
			
		||||
 | 
			
		||||
        
 | 
			
		||||
        Nothing ->
 | 
			
		||||
            "Invalid username"
 | 
			
		||||
 | 
			
		||||
-}
 | 
			
		||||
fromUserId : String -> Maybe Vault
 | 
			
		||||
fromUserId =
 | 
			
		||||
| 
						 | 
				
			
			@ -79,13 +75,12 @@ fromUserId =
 | 
			
		|||
        >> Maybe.map
 | 
			
		||||
            (\u ->
 | 
			
		||||
                Envelope.init
 | 
			
		||||
                    { serverName = "https://" ++ User.domain u
 | 
			
		||||
                    { serverName = User.domain u
 | 
			
		||||
                    , content = Internal.init u
 | 
			
		||||
                    }
 | 
			
		||||
            )
 | 
			
		||||
        >> Maybe.map Vault
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
{-| Send a message event to a room.
 | 
			
		||||
 | 
			
		||||
This function can be used in a scenario where the user does not want to sync
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,13 +3,10 @@ module Test.Values.Context exposing (..)
 | 
			
		|||
import Expect
 | 
			
		||||
import Fuzz exposing (Fuzzer)
 | 
			
		||||
import Internal.Config.Leaks as Leaks
 | 
			
		||||
import Internal.Tools.Hashdict as Hashdict
 | 
			
		||||
import Internal.Values.Context as Context exposing (Context, Versions)
 | 
			
		||||
import Internal.Values.Context as Context exposing (Context)
 | 
			
		||||
import Json.Decode as D
 | 
			
		||||
import Json.Encode as E
 | 
			
		||||
import Set
 | 
			
		||||
import Test exposing (..)
 | 
			
		||||
import Test.Tools.Timestamp as TestTimestamp
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
fuzzer : Fuzzer Context
 | 
			
		||||
| 
						 | 
				
			
			@ -19,31 +16,14 @@ fuzzer =
 | 
			
		|||
        maybeString =
 | 
			
		||||
            Fuzz.maybe Fuzz.string
 | 
			
		||||
    in
 | 
			
		||||
    Fuzz.map8 (\a b c d e ( f, g ) ( h, i ) ( j, k ) -> Context a b c d e f g h i j k)
 | 
			
		||||
        (Fuzz.constant <| Hashdict.empty .value)
 | 
			
		||||
    Fuzz.map7 Context
 | 
			
		||||
        maybeString
 | 
			
		||||
        maybeString
 | 
			
		||||
        (Fuzz.maybe TestTimestamp.fuzzer)
 | 
			
		||||
        maybeString
 | 
			
		||||
        (Fuzz.pair
 | 
			
		||||
            maybeString
 | 
			
		||||
            Fuzz.string
 | 
			
		||||
        )
 | 
			
		||||
        (Fuzz.pair
 | 
			
		||||
            maybeString
 | 
			
		||||
            maybeString
 | 
			
		||||
        )
 | 
			
		||||
        (Fuzz.pair
 | 
			
		||||
            maybeString
 | 
			
		||||
            (Fuzz.maybe <| versionsFuzzer)
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
versionsFuzzer : Fuzzer Versions
 | 
			
		||||
versionsFuzzer =
 | 
			
		||||
    Fuzz.map2 Versions
 | 
			
		||||
        (Fuzz.list Fuzz.string)
 | 
			
		||||
        (Fuzz.map Set.fromList <| Fuzz.list Fuzz.string)
 | 
			
		||||
        maybeString
 | 
			
		||||
        maybeString
 | 
			
		||||
        maybeString
 | 
			
		||||
        (Fuzz.maybe <| Fuzz.list Fuzz.string)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
{-| If a leak is spotted, make sure to change the leaking value and then test
 | 
			
		||||
| 
						 | 
				
			
			@ -84,7 +64,7 @@ leaks =
 | 
			
		|||
                    |> Expect.notEqual Leaks.transaction
 | 
			
		||||
            )
 | 
			
		||||
        , fuzz2 fuzzer
 | 
			
		||||
            versionsFuzzer
 | 
			
		||||
            (Fuzz.list Fuzz.string)
 | 
			
		||||
            "Versions"
 | 
			
		||||
            (\context value ->
 | 
			
		||||
                context
 | 
			
		||||
| 
						 | 
				
			
			@ -130,7 +110,7 @@ apiContext =
 | 
			
		|||
                    |> Expect.equal value
 | 
			
		||||
            )
 | 
			
		||||
        , fuzz2 fuzzer
 | 
			
		||||
            versionsFuzzer
 | 
			
		||||
            (Fuzz.list Fuzz.string)
 | 
			
		||||
            "Versions"
 | 
			
		||||
            (\context value ->
 | 
			
		||||
                context
 | 
			
		||||
| 
						 | 
				
			
			@ -146,7 +126,7 @@ json : Test
 | 
			
		|||
json =
 | 
			
		||||
    describe "JSON encode + JSON decode"
 | 
			
		||||
        [ test "Empty is {}"
 | 
			
		||||
            (Context.init ""
 | 
			
		||||
            (Context.init
 | 
			
		||||
                |> Context.encode
 | 
			
		||||
                |> E.encode 0
 | 
			
		||||
                |> Expect.equal "{}"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -28,7 +28,7 @@ suite =
 | 
			
		|||
                [ fuzz Fuzz.string
 | 
			
		||||
                    "currentVersion"
 | 
			
		||||
                    (\s ->
 | 
			
		||||
                        { content = s, serverName = "" }
 | 
			
		||||
                        s
 | 
			
		||||
                            |> Envelope.init
 | 
			
		||||
                            |> Envelope.extractSettings .currentVersion
 | 
			
		||||
                            |> Expect.equal Default.currentVersion
 | 
			
		||||
| 
						 | 
				
			
			@ -36,7 +36,7 @@ suite =
 | 
			
		|||
                , fuzz Fuzz.string
 | 
			
		||||
                    "deviceName"
 | 
			
		||||
                    (\s ->
 | 
			
		||||
                        { content = s, serverName = "" }
 | 
			
		||||
                        s
 | 
			
		||||
                            |> Envelope.init
 | 
			
		||||
                            |> Envelope.extractSettings .deviceName
 | 
			
		||||
                            |> Expect.equal Default.deviceName
 | 
			
		||||
| 
						 | 
				
			
			@ -44,7 +44,7 @@ suite =
 | 
			
		|||
                , fuzz Fuzz.string
 | 
			
		||||
                    "syncTime"
 | 
			
		||||
                    (\s ->
 | 
			
		||||
                        { content = s, serverName = "" }
 | 
			
		||||
                        s
 | 
			
		||||
                            |> Envelope.init
 | 
			
		||||
                            |> Envelope.extractSettings .syncTime
 | 
			
		||||
                            |> Expect.equal Default.syncTime
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,7 +1,9 @@
 | 
			
		|||
module Test.Values.Room exposing (..)
 | 
			
		||||
 | 
			
		||||
import Expect
 | 
			
		||||
import Fuzz exposing (Fuzzer)
 | 
			
		||||
import Internal.Values.Room as Room exposing (Room)
 | 
			
		||||
import Json.Decode as D
 | 
			
		||||
import Json.Encode as E
 | 
			
		||||
import Test exposing (..)
 | 
			
		||||
import Test.Filter.Timeline as TestFilter
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,7 +2,7 @@ module Test.Values.Timeline exposing (..)
 | 
			
		|||
 | 
			
		||||
import Expect
 | 
			
		||||
import Fuzz exposing (Fuzzer)
 | 
			
		||||
import Internal.Filter.Timeline as Filter
 | 
			
		||||
import Internal.Filter.Timeline as Filter exposing (Filter)
 | 
			
		||||
import Internal.Tools.Json as Json
 | 
			
		||||
import Internal.Values.Timeline as Timeline exposing (Batch, Timeline)
 | 
			
		||||
import Json.Decode as D
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,13 +0,0 @@
 | 
			
		|||
module Test.Values.User exposing (..)
 | 
			
		||||
 | 
			
		||||
import Fuzz exposing (Fuzzer)
 | 
			
		||||
import Internal.Grammar.ServerName as SN
 | 
			
		||||
import Internal.Values.User exposing (User)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
fuzzer : Fuzzer User
 | 
			
		||||
fuzzer =
 | 
			
		||||
    Fuzz.constant
 | 
			
		||||
        { localpart = "temporary"
 | 
			
		||||
        , domain = { host = SN.DNS "matrix.org", port_ = Nothing }
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -1,22 +1,20 @@
 | 
			
		|||
module Test.Values.Vault exposing (..)
 | 
			
		||||
 | 
			
		||||
import FastDict as Dict
 | 
			
		||||
import FastDict as Dict exposing (Dict)
 | 
			
		||||
import Fuzz exposing (Fuzzer)
 | 
			
		||||
import Internal.Tools.Json as Json
 | 
			
		||||
import Internal.Values.Vault exposing (Vault)
 | 
			
		||||
import Test exposing (..)
 | 
			
		||||
import Test.Tools.Hashdict as TestHashdict
 | 
			
		||||
import Test.Values.Room as TestRoom
 | 
			
		||||
import Test.Values.User as TestUser
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
vault : Fuzzer Vault
 | 
			
		||||
vault =
 | 
			
		||||
    Fuzz.map3 Vault
 | 
			
		||||
    Fuzz.map2 Vault
 | 
			
		||||
        (Fuzz.string
 | 
			
		||||
            |> Fuzz.map (\k -> ( k, Json.encode Json.int 0 ))
 | 
			
		||||
            |> Fuzz.list
 | 
			
		||||
            |> Fuzz.map Dict.fromList
 | 
			
		||||
        )
 | 
			
		||||
        (TestHashdict.fuzzer .roomId TestRoom.fuzzer)
 | 
			
		||||
        TestUser.fuzzer
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue