@@ -40,7 +40,7 @@ module App =
41 type ConnState =
41 type ConnState =
43− | Connecting of Identity
43+ | Connecting
44 | Online of Session
44 | Online of Session
46 type PollResultData =
46 type PollResultData =
@@ -178,12 +178,12 @@ module App =
178 | DoConnect ->
178 | DoConnect ->
179 match model.Identity with
179 match model.Identity with
180 | Some id ->
180 | Some id ->
181− { model with Conn = Connecting id }, [ CmdConnect(model.ServerUrl, id) ]
181+ { model with Conn = Connecting }, [ CmdConnect(model.ServerUrl, id) ]
182 | None -> { model with Error = Some "No identity generated" }, []
182 | None -> { model with Error = Some "No identity generated" }, []
184 | AuthOk token ->
184 | AuthOk token ->
185− match model.Conn with
185+ match model.Conn, model.Identity with
186− | Connecting id ->
186+ | Connecting, Some id ->
187 let session = { Url = model.ServerUrl; Token = token; Identity = id }
187 let session = { Url = model.ServerUrl; Token = token; Identity = id }
188 { model with Conn = Online session; Page = Conversations; Error = None },
188 { model with Conn = Online session; Page = Conversations; Error = None },
189 [ CmdPoll(session, model.PollCursor) ]
189 [ CmdPoll(session, model.PollCursor) ]
@@ -252,7 +252,7 @@ module App =
253 | DoSaveContact ->
253 | DoSaveContact ->
254 if model.NewPubkey <> "" && model.NewNickname <> "" then
254 if model.NewPubkey <> "" && model.NewNickname <> "" then
255− let contact =
255+ let contact: Contact =
256 { Pubkey = model.NewPubkey
256 { Pubkey = model.NewPubkey
257 Nickname = model.NewNickname }
257 Nickname = model.NewNickname }
@@ -281,38 +281,36 @@ module App =
282 | DismissError -> { model with Error = None }, []
282 | DismissError -> { model with Error = None }, []
284− | StateLoaded { Identity = identityOpt; Data = dataOpt } ->
284+ | StateLoaded { Identity = None } -> model, []
285− match identityOpt with
287− | Some identity ->
285+ | StateLoaded { Identity = Some identity; Data = dataOpt } ->
288− let model' = { model with Identity = Some identity; Conn = Connecting identity }
286+ let model' = { model with Identity = Some identity; Conn = Connecting }
290− let model' =
288+ let model' =
291− match dataOpt with
289+ match dataOpt with
292− | Some data ->
290+ | Some data ->
293− let messages =
291+ let messages =
294− data.Messages
292+ data.Messages
295− |> Seq.map (fun (KeyValue(pk, dtos)) ->
293+ |> Seq.map (fun (KeyValue(pk, dtos)) ->
298− |> Array.toList
296+ |> Array.toList
299− |> List.map (fun m ->
297+ |> List.map (fun m ->
300− { Id = m.Id
298+ { Id = m.Id
301− Body = m.Body
299+ Body = m.Body
302− Timestamp = DateTimeOffset.FromUnixTimeSeconds m.TimestampUnix
300+ Timestamp = DateTimeOffset.FromUnixTimeSeconds m.TimestampUnix
303− IsOutgoing = m.IsOutgoing }))
301+ IsOutgoing = m.IsOutgoing }))
304− |> Map.ofSeq
302+ |> Map.ofSeq
306− { model' with
304+ { model' with
307− Contacts = data.Contacts |> Array.toList
305+ Contacts = data.Contacts |> Array.toList
308− Messages = messages
306+ Messages = messages
309− ServerUrl = if data.ServerUrl <> "" then data.ServerUrl else model.ServerUrl
307+ ServerUrl = if data.ServerUrl <> "" then data.ServerUrl else model.ServerUrl
310− PollCursor = data.PollCursor
308+ PollCursor = data.PollCursor
311− Page = Conversations }
309+ Page = Conversations }
313− | None -> { model' with Page = Settings }
311+ | None -> { model' with Page = Settings }
315− model', [ CmdConnect(model'.ServerUrl, identity) ]
313+ model', [ CmdConnect(model'.ServerUrl, identity) ]
317 // ── mapCmd ──
315 // ── mapCmd ──
@@ -325,24 +323,19 @@ module App =
326 |> ignore)
324 |> ignore)
328− let private decryptEvent (privKey: byte[]) (payload: JsonElement) =
326+ let private decryptEvent (privKey: byte[]) (payload: ApiClient.EventPayload) =
330− let blobHex = payload.GetProperty("encryptedBlob").GetString()
331− let tsEl = payload.GetProperty("timestamp")
333− if tsEl.ValueKind = JsonValueKind.String then Int64.Parse(tsEl.GetString())
334− else tsEl.GetInt64()
335− let blob = Crypto.fromHex blobHex
328+ let blob = Crypto.fromHex payload.EncryptedBlob
337 match Crypto.decrypt privKey blob with
330 match Crypto.decrypt privKey blob with
338 | Some(plaintext, senderHex) ->
331 | Some(plaintext, senderHex) ->
339− let ptDoc = JsonDocument.Parse(plaintext)
332+ let pt = JsonDocument.Parse(plaintext).RootElement
340− let ptRoot = ptDoc.RootElement
342− if ptRoot.GetProperty("type").GetString() = "text" then
334+ if pt.GetProperty("type").GetString() = "text" then
343− let msgId = ptRoot.GetProperty("id").GetString()
344− let body = ptRoot.GetProperty("body").GetString()
345− Ok { FromPubkey = senderHex; Body = body; Timestamp = ts; MessageId = msgId }
335+ Ok { FromPubkey = senderHex
336+ Body = pt.GetProperty("body").GetString()
337+ Timestamp = payload.Timestamp
338+ MessageId = pt.GetProperty("id").GetString() }
347 Error "unknown type"
340 Error "unknown type"
348 | None -> Error "decrypt failed"
341 | None -> Error "decrypt failed"
@@ -376,7 +369,7 @@ module App =
376 let ts = DateTimeOffset.UtcNow.ToUnixTimeSeconds()
369 let ts = DateTimeOffset.UtcNow.ToUnixTimeSeconds()
378 let payload =
371 let payload =
379− $"""{{ "type": "text", "id": "{messageId}", "timestamp": {ts}, "body": {JsonSerializer.Serialize(text)} }}"""
372+ JsonSerializer.Serialize({| ``type`` = "text"; id = messageId; timestamp = ts; body = text |})
381 let blob = Crypto.encrypt session.Identity.PrivKey recipPub payload
374 let blob = Crypto.encrypt session.Identity.PrivKey recipPub payload
382 let blobHex = Crypto.toHex blob
375 let blobHex = Crypto.toHex blob
@@ -503,7 +496,7 @@ module App =
504 match model.Conn with
497 match model.Conn with
505 | Offline -> Button("Connect", DoConnect)
498 | Offline -> Button("Connect", DoConnect)
506− | Connecting _ -> Label("Connecting...").centerTextHorizontal()
499+ | Connecting -> Label("Connecting...").centerTextHorizontal()
507 | Online _ ->
500 | Online _ ->
508 Button("Disconnect", DoDisconnect)
501 Button("Disconnect", DoDisconnect)
509 Button("Go to Conversations", Nav Conversations)
502 Button("Go to Conversations", Nav Conversations)
@@ -516,7 +509,7 @@ module App =
516 let connStr =
509 let connStr =
517 match model.Conn with
510 match model.Conn with
518 | Offline -> "OFFLINE"
511 | Offline -> "OFFLINE"
519− | Connecting _ -> "CONNECTING"
512+ | Connecting -> "CONNECTING"
520 | Online _ -> "ONLINE"
513 | Online _ -> "ONLINE"
522 let contactNames =
515 let contactNames =