on master help sign in
Improve type safety and simplify code: named API types, filter events at boundary, record types for Msg cases, eliminate redundant encrypt parameter
ecdd432iko
client/ApiClient.fs+14−10
@@ -8,7 +8,11 @@ open System.Threading.Tasks
8
8
9module ApiClient =
9module ApiClient =
10
10
11− type PollEvent = { Id: string; EventType: string; Payload: JsonElement }
11+ type PollEvent = { Id: string; Payload: JsonElement }
12+
13+ type AuthResult = { Token: string; ExpiresAt: int64 }
14+ type SendResult = { Status: string; MessageId: string }
15+ type PollResponse = { Events: PollEvent list; Cursor: uint64 }
12
16
13 /// Awaits a Task without converting TaskCanceledException to F# async
17 /// Awaits a Task without converting TaskCanceledException to F# async
14 /// cancellation (which bypasses try...with). Re-raises it as a regular exception.
18 /// cancellation (which bypasses try...with). Re-raises it as a regular exception.
@@ -72,9 +76,9 @@ module ApiClient =
72
76
73 let! doc = postJson $"{serverUrl}/auth/verify" body None
77 let! doc = postJson $"{serverUrl}/auth/verify" body None
74 let root = expectObject doc "/auth/verify"
78 let root = expectObject doc "/auth/verify"
79+ return
75− let token = root.GetProperty("token").GetString()
80+ { Token = root.GetProperty("token").GetString()
76− let expiresAt = root.GetProperty("expiresAt").GetInt64()
81+ ExpiresAt = root.GetProperty("expiresAt").GetInt64() }
77− return (token, expiresAt)
78 }
82 }
79
83
80 let sendMessage (serverUrl: string) (token: string) (toHex: string) (blobHex: string) (timestamp: int64) =
84 let sendMessage (serverUrl: string) (token: string) (toHex: string) (blobHex: string) (timestamp: int64) =
@@ -84,9 +88,9 @@ module ApiClient =
84
88
85 let! doc = postJson $"{serverUrl}/messages" body (Some token)
89 let! doc = postJson $"{serverUrl}/messages" body (Some token)
86 let root = expectObject doc "/messages"
90 let root = expectObject doc "/messages"
87− let status = root.GetProperty("status").GetString()
88− let msgId = root.GetProperty("messageId").GetString()
89− return (status, msgId)
91+ return
92+ { Status = root.GetProperty("status").GetString()
93+ MessageId = root.GetProperty("messageId").GetString() }
90 }
94 }
91
95
92 let private pollClient =
96 let private pollClient =
@@ -110,13 +114,13 @@ module ApiClient =
110
114
111 let events =
115 let events =
112 [ for e in events.EnumerateArray() do
116 [ for e in events.EnumerateArray() do
113− if e.ValueKind = JsonValueKind.Object then
117+ if e.ValueKind = JsonValueKind.Object
118+ && e.GetProperty("eventType").GetString() = "message" then
114 yield
119 yield
115 { Id = e.GetProperty("id").GetString()
120 { Id = e.GetProperty("id").GetString()
116− EventType = e.GetProperty("eventType").GetString()
117 Payload = e.GetProperty("payload") } ]
121 Payload = e.GetProperty("payload") } ]
118
122
119− return (events, cursor)
123+ return { Events = events; Cursor = cursor }
120 }
124 }
121
125
122 let ackMessages (serverUrl: string) (token: string) (messageIds: string list) =
126 let ackMessages (serverUrl: string) (token: string) (messageIds: string list) =
client/App.fs+41−41
@@ -43,6 +43,15 @@ module App =
43 | Connecting
43 | Connecting
44 | Online of Session
44 | Online of Session
45
45
46+ type PollResultData =
47+ { Messages: IncomingMessage list
48+ Status: string
49+ Cursor: uint64 }
50+
51+ type LoadedState =
52+ { Identity: Identity option
53+ Data: Store.DataDto option }
54+
46 // ── Model ──
55 // ── Model ──
47
56
48 type Model =
57 type Model =
@@ -78,11 +87,11 @@ module App =
78 | SetNewNickname of string
87 | SetNewNickname of string
79 | DoSaveContact
88 | DoSaveContact
80 | DoDeleteContact of string
89 | DoDeleteContact of string
81− | PollResult of messages: IncomingMessage list * status: string * cursor: uint64
90+ | PollResult of PollResultData
82 | DoPoll
91 | DoPoll
83 | CopyPubKey
92 | CopyPubKey
84 | DismissError
93 | DismissError
85− | StateLoaded of Identity option * Store.DataDto option
94+ | StateLoaded of LoadedState
86
95
87 // ── CmdMsg ──
96 // ── CmdMsg ──
88
97
@@ -110,6 +119,9 @@ module App =
110 let private messagesFor (pk: string) (messages: Map<string, ChatMessage list>) =
119 let private messagesFor (pk: string) (messages: Map<string, ChatMessage list>) =
111 messages |> Map.tryFind pk |> Option.defaultValue []
120 messages |> Map.tryFind pk |> Option.defaultValue []
112
121
122+ let private appendMessage (pk: string) (msg: ChatMessage) (messages: Map<string, ChatMessage list>) =
123+ messages |> Map.add pk (messagesFor pk messages @ [ msg ])
124+
113 let private addContactIfNew (contact: Contact) (contacts: Contact list) =
125 let private addContactIfNew (contact: Contact) (contacts: Contact list) =
114 if contacts |> List.exists (fun c -> c.Pubkey = contact.Pubkey) then contacts
126 if contacts |> List.exists (fun c -> c.Pubkey = contact.Pubkey) then contacts
115 else contacts @ [ contact ]
127 else contacts @ [ contact ]
@@ -194,26 +206,23 @@ module App =
194 Body = text
206 Body = text
195 Timestamp = DateTimeOffset.UtcNow
207 Timestamp = DateTimeOffset.UtcNow
196 IsOutgoing = true }
208 IsOutgoing = true }
197− let msgs = messagesFor pk model.Messages
198
209
199 let model' =
210 let model' =
200 { model with
211 { model with
201 ComposeText = ""
212 ComposeText = ""
202− Messages = model.Messages |> Map.add pk (msgs @ [ outMsg ]) }
213+ Messages = model.Messages |> appendMessage pk outMsg }
203
214
204 model', CmdSend(session, pk, text, id) :: saveCmd model'
215 model', CmdSend(session, pk, text, id) :: saveCmd model'
205 | _ -> model, []
216 | _ -> model, []
206
217
207 | Sent status -> { model with LastSendStatus = status }, []
218 | Sent status -> { model with LastSendStatus = status }, []
208
219
209− | PollResult(incoming, status, newCursor) ->
220+ | PollResult { Messages = incoming; Status = status; Cursor = newCursor } ->
210 let model' =
221 let model' =
211 incoming
222 incoming
212 |> List.fold
223 |> List.fold
213 (fun m msg ->
224 (fun m msg ->
214− let msgs = messagesFor msg.FromPubkey m.Messages
225+ if messagesFor msg.FromPubkey m.Messages |> List.exists (fun x -> x.Id = msg.MessageId) then
215−
216− if msgs |> List.exists (fun x -> x.Id = msg.MessageId) then
217 m
226 m
218 else
227 else
219 let chatMsg =
228 let chatMsg =
@@ -224,7 +233,7 @@ module App =
224
233
225 { m with
234 { m with
226 Contacts = m.Contacts |> addContactIfNew { Pubkey = msg.FromPubkey; Nickname = truncKey msg.FromPubkey }
235 Contacts = m.Contacts |> addContactIfNew { Pubkey = msg.FromPubkey; Nickname = truncKey msg.FromPubkey }
227− Messages = m.Messages |> Map.add msg.FromPubkey (msgs @ [ chatMsg ]) })
236+ Messages = m.Messages |> appendMessage msg.FromPubkey chatMsg })
228 { model with PollStatus = status; PollCursor = newCursor }
237 { model with PollStatus = status; PollCursor = newCursor }
229
238
230 let cmds =
239 let cmds =
@@ -273,10 +282,12 @@ module App =
273
282
274 | DismissError -> { model with Error = None }, []
283 | DismissError -> { model with Error = None }, []
275
284
276− | StateLoaded(identityOpt, dataOpt) ->
285+ | StateLoaded { Identity = identityOpt; Data = dataOpt } ->
277 match identityOpt with
286 match identityOpt with
278 | None -> model, []
287 | None -> model, []
279 | Some identity ->
288 | Some identity ->
289+ let model' = { model with Identity = Some identity; Conn = Connecting }
290+
280 let model' =
291 let model' =
281 match dataOpt with
292 match dataOpt with
282 | Some data ->
293 | Some data ->
@@ -302,22 +313,14 @@ module App =
302 acc |> Map.add pk msgs)
313 acc |> Map.add pk msgs)
303 Map.empty
314 Map.empty
304
315
305− { model with
316+ { model' with
306− Identity = Some identity
307 Contacts = contacts
317 Contacts = contacts
308 Messages = messages
318 Messages = messages
309− ServerUrl =
310− if data.ServerUrl <> "" then data.ServerUrl
319+ ServerUrl = if data.ServerUrl <> "" then data.ServerUrl else model.ServerUrl
311− else model.ServerUrl
312 PollCursor = data.PollCursor
320 PollCursor = data.PollCursor
313− Page = Conversations
321+ Page = Conversations }
314− Conn = Connecting }
315
322
316− | None ->
317− { model with
318− Identity = Some identity
319− Page = Settings
323+ | None -> { model' with Page = Settings }
320− Conn = Connecting }
321
324
322 model', [ CmdConnect(model'.ServerUrl, identity) ]
325 model', [ CmdConnect(model'.ServerUrl, identity) ]
323
326
@@ -366,12 +369,12 @@ module App =
366 try
369 try
367 let! challenge = ApiClient.requestChallenge url identity.PubKeyHex
370 let! challenge = ApiClient.requestChallenge url identity.PubKeyHex
368 let sigHex = Crypto.signChallenge identity.PrivKey challenge
371 let sigHex = Crypto.signChallenge identity.PrivKey challenge
369− let! (token, _) = ApiClient.verify url identity.PubKeyHex challenge sigHex
372+ let! result = ApiClient.verify url identity.PubKeyHex challenge sigHex
370
373
371− if String.IsNullOrEmpty(token) then
374+ if String.IsNullOrEmpty(result.Token) then
372 return AuthErr "Authentication rejected by server"
375 return AuthErr "Authentication rejected by server"
373 else
376 else
374− return AuthOk token
377+ return AuthOk result.Token
375 with ex ->
378 with ex ->
376 return AuthErr ex.Message
379 return AuthErr ex.Message
377 })
380 })
@@ -379,17 +382,16 @@ module App =
379 | CmdSend(session, recipientHex, text, messageId) ->
382 | CmdSend(session, recipientHex, text, messageId) ->
380 asyncCmd (async {
383 asyncCmd (async {
381 try
384 try
382− let pubKey = Crypto.fromHex session.Identity.PubKeyHex
383 let recipPub = Crypto.fromHex recipientHex
385 let recipPub = Crypto.fromHex recipientHex
384 let ts = DateTimeOffset.UtcNow.ToUnixTimeSeconds()
386 let ts = DateTimeOffset.UtcNow.ToUnixTimeSeconds()
385
387
386 let payload =
388 let payload =
387 $"""{{ "type": "text", "id": "{messageId}", "timestamp": {ts}, "body": {JsonSerializer.Serialize(text)} }}"""
389 $"""{{ "type": "text", "id": "{messageId}", "timestamp": {ts}, "body": {JsonSerializer.Serialize(text)} }}"""
388
390
389− let blob = Crypto.encrypt session.Identity.PrivKey pubKey recipPub payload
391+ let blob = Crypto.encrypt session.Identity.PrivKey recipPub payload
390 let blobHex = Crypto.toHex blob
392 let blobHex = Crypto.toHex blob
391− let! (status, msgId) = ApiClient.sendMessage session.Url session.Token recipientHex blobHex ts
393+ let! result = ApiClient.sendMessage session.Url session.Token recipientHex blobHex ts
392− return Sent $"{status}:{msgId}"
394+ return Sent $"{result.Status}:{result.MessageId}"
393 with ex ->
395 with ex ->
394 return DismissError // TODO: show send errors properly
396 return DismissError // TODO: show send errors properly
395 })
397 })
@@ -397,15 +399,13 @@ module App =
397 | CmdPoll(session, cursor) ->
399 | CmdPoll(session, cursor) ->
398 asyncCmd (async {
400 asyncCmd (async {
399 try
401 try
400− let! (events, newCursor) = ApiClient.poll session.Url session.Token cursor
402+ let! response = ApiClient.poll session.Url session.Token cursor
401 let messages, ackIds, errors =
403 let messages, ackIds, errors =
402− events
404+ response.Events
403 |> List.fold (fun (msgs, acks, errs) evt ->
405 |> List.fold (fun (msgs, acks, errs) evt ->
404− if evt.EventType <> "message" then (msgs, acks, errs)
405− else
406− match decryptEvent session.Identity.PrivKey evt.Payload with
406+ match decryptEvent session.Identity.PrivKey evt.Payload with
407− | Ok msg -> (msg :: msgs, evt.Id :: acks, errs)
407+ | Ok msg -> (msg :: msgs, evt.Id :: acks, errs)
408− | Error err -> (msgs, acks, err :: errs))
408+ | Error err -> (msgs, acks, err :: errs))
409 ([], [], [])
409 ([], [], [])
410
410
411 if not ackIds.IsEmpty then
411 if not ackIds.IsEmpty then
@@ -414,17 +414,17 @@ module App =
414 let now = DateTimeOffset.UtcNow.ToString("HH:mm:ss")
414 let now = DateTimeOffset.UtcNow.ToString("HH:mm:ss")
415
415
416 let status =
416 let status =
417− $"[{now}] evts:{events.Length} msgs:{messages.Length} errs:{errors.Length}"
417+ $"[{now}] evts:{response.Events.Length} msgs:{messages.Length} errs:{errors.Length}"
418 + (match errors with err :: _ -> $" [{err}]" | [] -> "")
418 + (match errors with err :: _ -> $" [{err}]" | [] -> "")
419
419
420− return PollResult(List.rev messages, status, newCursor)
420+ return PollResult { Messages = List.rev messages; Status = status; Cursor = response.Cursor }
421 with
421 with
422 | :? TimeoutException ->
422 | :? TimeoutException ->
423− return PollResult([], "polling...", cursor)
423+ return PollResult { Messages = []; Status = "polling..."; Cursor = cursor }
424 | ex ->
424 | ex ->
425 let now = DateTimeOffset.UtcNow.ToString("HH:mm:ss")
425 let now = DateTimeOffset.UtcNow.ToString("HH:mm:ss")
426 do! Async.Sleep 3000
426 do! Async.Sleep 3000
427− return PollResult([], $"[{now}] poll error: {ex.Message}", cursor)
427+ return PollResult { Messages = []; Status = $"[{now}] poll error: {ex.Message}"; Cursor = cursor }
428 })
428 })
429
429
430 | CmdCopyToClipboard text ->
430 | CmdCopyToClipboard text ->
@@ -436,7 +436,7 @@ module App =
436 asyncCmd (async {
436 asyncCmd (async {
437 let! identity = Store.loadIdentity ()
437 let! identity = Store.loadIdentity ()
438 let data = Store.loadData ()
438 let data = Store.loadData ()
439− return StateLoaded(identity, data)
439+ return StateLoaded { Identity = identity; Data = data }
440 })
440 })
441
441
442 | CmdSaveIdentity identity ->
442 | CmdSaveIdentity identity ->
client/Crypto.fs+2−1
@@ -23,7 +23,8 @@ module Crypto =
23 let message = Encoding.UTF8.GetBytes(challenge)
23 let message = Encoding.UTF8.GetBytes(challenge)
24 PublicKeyAuth.SignDetached(message, privKey) |> toHex
24 PublicKeyAuth.SignDetached(message, privKey) |> toHex
25
25
26− let encrypt (senderPrivKey: byte[]) (senderPubKey: byte[]) (recipientEd25519Pub: byte[]) (plaintext: string) : byte[] =
26+ let encrypt (senderPrivKey: byte[]) (recipientEd25519Pub: byte[]) (plaintext: string) : byte[] =
27+ let senderPubKey = senderPrivKey.[32..63]
27 let ephKp = PublicKeyBox.GenerateKeyPair()
28 let ephKp = PublicKeyBox.GenerateKeyPair()
28 let recipientX25519Pub =
29 let recipientX25519Pub =
29 PublicKeyAuth.ConvertEd25519PublicKeyToCurve25519PublicKey(recipientEd25519Pub)
30 PublicKeyAuth.ConvertEd25519PublicKeyToCurve25519PublicKey(recipientEd25519Pub)
client/bin/Debug/net10.0-ios/iossimulator-arm64/Skrepka.app/Skrepka.dll

Binary file not shown.

client/bin/Debug/net10.0-ios/iossimulator-arm64/Skrepka.app/Skrepka.pdb

Binary file not shown.

client/bin/Debug/net10.0-ios/iossimulator-arm64/Skrepka.app/_CodeSignature/CodeResources+4−4
@@ -162,11 +162,11 @@
162 </data>
162 </data>
163 <key>Skrepka.dll</key>
163 <key>Skrepka.dll</key>
164 <data>
164 <data>
165− OYwezEvMh2kSn1TCF4gpKXKXgYw=
165+ YuvKkwqaKzWQzRQXpENlDG0Qj74=
166 </data>
166 </data>
167 <key>Skrepka.pdb</key>
167 <key>Skrepka.pdb</key>
168 <data>
168 <data>
169− 6T2QPZw7EFCnFUY/89Ch+oEzRXg=
169+ uWv9Q0kXJ3vU7v5u8O43aOdycdk=
170 </data>
170 </data>
171 <key>Sodium.Core.dll</key>
171 <key>Sodium.Core.dll</key>
172 <data>
172 <data>
@@ -1382,14 +1382,14 @@
1382 <dict>
1382 <dict>
1383 <key>hash2</key>
1383 <key>hash2</key>
1384 <data>
1384 <data>
1385− PMoIkhU1O9+V8P8AeaDyQljOgjR+z5qeuTBn7D/FSGw=
1385+ Z58lx+z8OWKQABghiCVt0azHU+vbKzyMKcw6PrDtiNg=
1386 </data>
1386 </data>
1387 </dict>
1387 </dict>
1388 <key>Skrepka.pdb</key>
1388 <key>Skrepka.pdb</key>
1389 <dict>
1389 <dict>
1390 <key>hash2</key>
1390 <key>hash2</key>
1391 <data>
1391 <data>
1392− YgnXPdc3zZf1mp7BgJZWvrcJtCSxwIhEufHWuJjK14o=
1392+ Z6xpYAcLJvuMODZXHsZdQO2dSNygZZZgeSiq725F/6s=
1393 </data>
1393 </data>
1394 </dict>
1394 </dict>
1395 <key>Sodium.Core.dll</key>
1395 <key>Sodium.Core.dll</key>
client/bin/Debug/net10.0-ios/iossimulator-arm64/Skrepka.dll

Binary file not shown.

client/bin/Debug/net10.0-ios/iossimulator-arm64/Skrepka.pdb

Binary file not shown.

client/bin/Debug/net10.0-maccatalyst/maccatalyst-arm64/Skrepka.app/Contents/MonoBundle/Skrepka.dll

Binary file not shown.

client/bin/Debug/net10.0-maccatalyst/maccatalyst-arm64/Skrepka.app/Contents/MonoBundle/Skrepka.pdb

Binary file not shown.

client/bin/Debug/net10.0-maccatalyst/maccatalyst-arm64/Skrepka.app/Contents/_CodeSignature/CodeResources+2−2
@@ -240,14 +240,14 @@
240 <dict>
240 <dict>
241 <key>hash2</key>
241 <key>hash2</key>
242 <data>
242 <data>
243− sen9DAcM5m8/Ohc6ElADTlEOrvFEm1sSA7fRowfDgrc=
243+ 91zpkFT4/RM8YRa7FJkiFdDR7Pto7K+XY9imNTAYHjo=
244 </data>
244 </data>
245 </dict>
245 </dict>
246 <key>MonoBundle/Skrepka.pdb</key>
246 <key>MonoBundle/Skrepka.pdb</key>
247 <dict>
247 <dict>
248 <key>hash2</key>
248 <key>hash2</key>
249 <data>
249 <data>
250− Ef11Yo4fM1PomVMJpvG73Vxp5MIfM56316luhoVVjyk=
250+ PBlWefCE9ZRLSbMgbnh+/sPWyukURBAZvneq4SzNCRA=
251 </data>
251 </data>
252 </dict>
252 </dict>
253 <key>MonoBundle/Sodium.Core.dll</key>
253 <key>MonoBundle/Sodium.Core.dll</key>
client/bin/Debug/net10.0-maccatalyst/maccatalyst-arm64/Skrepka.dll

Binary file not shown.

client/bin/Debug/net10.0-maccatalyst/maccatalyst-arm64/Skrepka.pdb

Binary file not shown.

client/obj/Debug/net10.0-ios/iossimulator-arm64/Skrepka.AssemblyInfo.fs+1−1
@@ -10,7 +10,7 @@ open System.Reflection
10[<assembly: System.Reflection.AssemblyCompanyAttribute("Skrepka")>]
10[<assembly: System.Reflection.AssemblyCompanyAttribute("Skrepka")>]
11[<assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")>]
11[<assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")>]
12[<assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")>]
12[<assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")>]
13−[<assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0+06f6fccd5eca861f9f6aea926abad74a25306378")>]
13+[<assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0+53111fd5732cdcd3f192c7b234c1e758166a5b4e")>]
14[<assembly: System.Reflection.AssemblyProductAttribute("Skrepka")>]
14[<assembly: System.Reflection.AssemblyProductAttribute("Skrepka")>]
15[<assembly: System.Reflection.AssemblyTitleAttribute("Skrepka")>]
15[<assembly: System.Reflection.AssemblyTitleAttribute("Skrepka")>]
16[<assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")>]
16[<assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")>]
client/obj/Debug/net10.0-ios/iossimulator-arm64/Skrepka.AssemblyInfoInputs.cache+1−1
@@ -1 +1 @@
1−eedd99803c3b27d5759de189487d1f622004d1f2067c5139ac9be1722d4be89f
1+0ef83a245978e87cd24a7f73f252d902b7105a6b078059a69fddd28d07e76f29
client/obj/Debug/net10.0-ios/iossimulator-arm64/Skrepka.dll

Binary file not shown.

client/obj/Debug/net10.0-ios/iossimulator-arm64/Skrepka.fsproj.FileListAbsolute.txt+22
@@ -333,3 +333,25 @@
333/Users/iko/Developer/skrepka/client/obj/Debug/net10.0-ios/iossimulator-arm64/Skrepka.pdb
333/Users/iko/Developer/skrepka/client/obj/Debug/net10.0-ios/iossimulator-arm64/Skrepka.pdb
334/Users/iko/Developer/skrepka/client/obj/Debug/net10.0-ios/iossimulator-arm64/Skrepka.genruntimeconfig.cache
334/Users/iko/Developer/skrepka/client/obj/Debug/net10.0-ios/iossimulator-arm64/Skrepka.genruntimeconfig.cache
335/Users/iko/Developer/skrepka/client/obj/Debug/net10.0-ios/iossimulator-arm64/ref/Skrepka.dll
335/Users/iko/Developer/skrepka/client/obj/Debug/net10.0-ios/iossimulator-arm64/ref/Skrepka.dll
336+/Users/iko/Developer/skrepka/client/obj/Debug/net10.0-ios/iossimulator-arm64/resourcestamps/Fabulous.stamp
337+/Users/iko/Developer/skrepka/client/obj/Debug/net10.0-ios/iossimulator-arm64/resourcestamps/Fabulous.MauiControls.stamp
338+/Users/iko/Developer/skrepka/client/obj/Debug/net10.0-ios/iossimulator-arm64/resourcestamps/FSharp.Core.stamp
339+/Users/iko/Developer/skrepka/client/obj/Debug/net10.0-ios/iossimulator-arm64/resourcestamps/Microsoft.Extensions.Configuration.Abstractions.stamp
340+/Users/iko/Developer/skrepka/client/obj/Debug/net10.0-ios/iossimulator-arm64/resourcestamps/Microsoft.Extensions.Configuration.stamp
341+/Users/iko/Developer/skrepka/client/obj/Debug/net10.0-ios/iossimulator-arm64/resourcestamps/Microsoft.Extensions.DependencyInjection.Abstractions.stamp
342+/Users/iko/Developer/skrepka/client/obj/Debug/net10.0-ios/iossimulator-arm64/resourcestamps/Microsoft.Extensions.DependencyInjection.stamp
343+/Users/iko/Developer/skrepka/client/obj/Debug/net10.0-ios/iossimulator-arm64/resourcestamps/Microsoft.Extensions.Diagnostics.Abstractions.stamp
344+/Users/iko/Developer/skrepka/client/obj/Debug/net10.0-ios/iossimulator-arm64/resourcestamps/Microsoft.Extensions.FileProviders.Abstractions.stamp
345+/Users/iko/Developer/skrepka/client/obj/Debug/net10.0-ios/iossimulator-arm64/resourcestamps/Microsoft.Extensions.Hosting.Abstractions.stamp
346+/Users/iko/Developer/skrepka/client/obj/Debug/net10.0-ios/iossimulator-arm64/resourcestamps/Microsoft.Extensions.Logging.Abstractions.stamp
347+/Users/iko/Developer/skrepka/client/obj/Debug/net10.0-ios/iossimulator-arm64/resourcestamps/Microsoft.Extensions.Logging.stamp
348+/Users/iko/Developer/skrepka/client/obj/Debug/net10.0-ios/iossimulator-arm64/resourcestamps/Microsoft.Extensions.Options.stamp
349+/Users/iko/Developer/skrepka/client/obj/Debug/net10.0-ios/iossimulator-arm64/resourcestamps/Microsoft.Extensions.Primitives.stamp
350+/Users/iko/Developer/skrepka/client/obj/Debug/net10.0-ios/iossimulator-arm64/resourcestamps/Microsoft.Maui.Controls.Compatibility.stamp
351+/Users/iko/Developer/skrepka/client/obj/Debug/net10.0-ios/iossimulator-arm64/resourcestamps/Microsoft.Maui.Controls.stamp
352+/Users/iko/Developer/skrepka/client/obj/Debug/net10.0-ios/iossimulator-arm64/resourcestamps/Microsoft.Maui.Controls.Xaml.stamp
353+/Users/iko/Developer/skrepka/client/obj/Debug/net10.0-ios/iossimulator-arm64/resourcestamps/Microsoft.Maui.stamp
354+/Users/iko/Developer/skrepka/client/obj/Debug/net10.0-ios/iossimulator-arm64/resourcestamps/Microsoft.Maui.Essentials.stamp
355+/Users/iko/Developer/skrepka/client/obj/Debug/net10.0-ios/iossimulator-arm64/resourcestamps/Microsoft.Maui.Graphics.stamp
356+/Users/iko/Developer/skrepka/client/obj/Debug/net10.0-ios/iossimulator-arm64/resourcestamps/Sodium.Core.stamp
357+/Users/iko/Developer/skrepka/client/obj/Debug/net10.0-ios/iossimulator-arm64/unpack/Microsoft.Maui.Essentials/BundleResource/xml/microsoft_maui_essentials_fileprovider_file_paths.xml
client/obj/Debug/net10.0-ios/iossimulator-arm64/Skrepka.pdb

Binary file not shown.

client/obj/Debug/net10.0-ios/iossimulator-arm64/Skrepka.sourcelink.json+1−1
@@ -1 +1 @@
1−{"documents":{"/Users/iko/Developer/skrepka/*":"https://raw.githubusercontent.com/ilyakooo0/skrepka/06f6fccd5eca861f9f6aea926abad74a25306378/*"}}
1+{"documents":{"/Users/iko/Developer/skrepka/*":"https://raw.githubusercontent.com/ilyakooo0/skrepka/53111fd5732cdcd3f192c7b234c1e758166a5b4e/*"}}
client/obj/Debug/net10.0-ios/iossimulator-arm64/ref/Skrepka.dll

Binary file not shown.

client/obj/Debug/net10.0-ios/iossimulator-arm64/refint/Skrepka.dll

Binary file not shown.

client/obj/Debug/net10.0-maccatalyst/maccatalyst-arm64/Skrepka.AssemblyInfo.fs+1−1
@@ -10,7 +10,7 @@ open System.Reflection
10[<assembly: System.Reflection.AssemblyCompanyAttribute("Skrepka")>]
10[<assembly: System.Reflection.AssemblyCompanyAttribute("Skrepka")>]
11[<assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")>]
11[<assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")>]
12[<assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")>]
12[<assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")>]
13−[<assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0+06f6fccd5eca861f9f6aea926abad74a25306378")>]
13+[<assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0+53111fd5732cdcd3f192c7b234c1e758166a5b4e")>]
14[<assembly: System.Reflection.AssemblyProductAttribute("Skrepka")>]
14[<assembly: System.Reflection.AssemblyProductAttribute("Skrepka")>]
15[<assembly: System.Reflection.AssemblyTitleAttribute("Skrepka")>]
15[<assembly: System.Reflection.AssemblyTitleAttribute("Skrepka")>]
16[<assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")>]
16[<assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")>]
client/obj/Debug/net10.0-maccatalyst/maccatalyst-arm64/Skrepka.AssemblyInfoInputs.cache+1−1
@@ -1 +1 @@
1−b108f228be3a948e3c34a84a66948ebb1deac8d4a1b601338c34457cdb6bbecd
1+258df1087fc418adab33f09b6403611ecf00ae4643e2b1d8257eaca6be4c82ac
client/obj/Debug/net10.0-maccatalyst/maccatalyst-arm64/Skrepka.dll

Binary file not shown.

client/obj/Debug/net10.0-maccatalyst/maccatalyst-arm64/Skrepka.pdb

Binary file not shown.

client/obj/Debug/net10.0-maccatalyst/maccatalyst-arm64/Skrepka.sourcelink.json+1−1
@@ -1 +1 @@
1−{"documents":{"/Users/iko/Developer/skrepka/*":"https://raw.githubusercontent.com/ilyakooo0/skrepka/06f6fccd5eca861f9f6aea926abad74a25306378/*"}}
1+{"documents":{"/Users/iko/Developer/skrepka/*":"https://raw.githubusercontent.com/ilyakooo0/skrepka/53111fd5732cdcd3f192c7b234c1e758166a5b4e/*"}}
client/obj/Debug/net10.0-maccatalyst/maccatalyst-arm64/ref/Skrepka.dll

Binary file not shown.

client/obj/Debug/net10.0-maccatalyst/maccatalyst-arm64/refint/Skrepka.dll

Binary file not shown.