11namespace ARCP.Client.Internal
22
33open System
4+ open System.Text .Json
45open ARCP.Core
56
67/// Map a wire ` job.error ` / ` session.error ` code string back to an
7- /// ` ARCPError ` DU. The reverse direction is ` ARCPError.code ` . Out
8- /// of scope: details payloads beyond ` message ` .
8+ /// ` ARCPError ` DU, parsing structured fields out of the ` details `
9+ /// payload where the DU carries them. The reverse direction is
10+ /// ` ARCPError.code ` .
911[<RequireQualifiedAccess>]
1012module internal JobErrorMapper =
13+ let private prop ( details : JsonElement option ) ( name : string ) : JsonElement option =
14+ match details with
15+ | Some d when d.ValueKind = JsonValueKind.Object ->
16+ match d.TryGetProperty name with
17+ | true , v when v.ValueKind <> JsonValueKind.Null -> Some v
18+ | _ -> None
19+ | _ -> None
20+
21+ let private strField details name fallback =
22+ prop details name |> Option.map ( fun v -> v.GetString()) |> Option.defaultValue fallback
23+
24+ let private intField details name fallback =
25+ prop details name
26+ |> Option.bind ( fun v ->
27+ match v.TryGetInt32() with
28+ | true , n -> Some n
29+ | _ -> None)
30+ |> Option.defaultValue fallback
31+
32+ let private int64Field details name fallback =
33+ prop details name
34+ |> Option.bind ( fun v ->
35+ match v.TryGetInt64() with
36+ | true , n -> Some n
37+ | _ -> None)
38+ |> Option.defaultValue fallback
39+
40+ let private dateField details name fallback =
41+ prop details name
42+ |> Option.bind ( fun v ->
43+ match v.TryGetDateTimeOffset() with
44+ | true , d -> Some d
45+ | _ -> None)
46+ |> Option.defaultValue fallback
47+
1148 let ofWire
1249 ( code : string )
1350 ( message : string )
@@ -20,13 +57,14 @@ module internal JobErrorMapper =
2057 | " JOB_NOT_FOUND" -> ARCPError.JobNotFound jobId
2158 | " DUPLICATE_KEY" -> ARCPError.DuplicateKey message
2259 | " AGENT_NOT_AVAILABLE" -> ARCPError.AgentNotAvailable message
23- | " AGENT_VERSION_NOT_AVAILABLE" -> ARCPError.AgentVersionNotAvailable( message, " " )
60+ | " AGENT_VERSION_NOT_AVAILABLE" -> ARCPError.AgentVersionNotAvailable( message, strField details " version " " " )
2461 | " CANCELLED" -> ARCPError.Cancelled( Some message)
25- | " TIMEOUT" -> ARCPError.Timeout 0
62+ | " TIMEOUT" -> ARCPError.Timeout( intField details " timeout_sec " 0 )
2663 | " HEARTBEAT_LOST" -> ARCPError.HeartbeatLost
27- | " LEASE_EXPIRED" -> ARCPError.LeaseExpired DateTimeOffset.MinValue
28- | " BUDGET_EXHAUSTED" -> ARCPError.BudgetExhausted " USD"
64+ | " LEASE_EXPIRED" -> ARCPError.LeaseExpired( dateField details " expires_at " DateTimeOffset.MinValue)
65+ | " BUDGET_EXHAUSTED" -> ARCPError.BudgetExhausted( strField details " currency " " USD" )
2966 | " INVALID_REQUEST" -> ARCPError.InvalidRequest( message, details)
3067 | " UNAUTHENTICATED" -> ARCPError.Unauthenticated message
31- | " RESUME_WINDOW_EXPIRED" -> ARCPError.ResumeWindowExpired( 0 L, 0 )
68+ | " RESUME_WINDOW_EXPIRED" ->
69+ ARCPError.ResumeWindowExpired( int64Field details " from_seq" 0 L, intField details " window_sec" 0 )
3270 | _ -> ARCPError.InternalError message
0 commit comments