(ns ird.errors
"Error values delivered on ird channels. All are ex-info with a :type key:
:ird/api-error non-2xx response (:code :status :response)
:ird/transport-error connection/parse failure (:detail)
:ird/config-error bad client configuration / arguments (:detail)
:ird/domain-denied client-side domain gate refusal (:domain :matched-pattern :op)
:ird/timeout a polling helper hit its deadline (:last)
:ird/job-failed ird.jobs/run: the job ended in failure (:job)
:ird/upload-failed ird.ipfs/add-file: the upload failed/expired (:upload)"
(:require [ird.async :as a]))
(defn api-error
"Error returned by the ird API (non-2xx HTTP status). CODE is the
machine-readable error code, STATUS the HTTP status, RESPONSE the parsed
error body (nil when it was not JSON)."
[message code status response]
(ex-info message {:type :ird/api-error :code code :status status :response response}))
(defn transport-error
"Low-level failure talking to the API (connection failure, timeout,
non-JSON body, unsupported body source)."
[message detail]
(ex-info message {:type :ird/transport-error :detail detail}))
(defn config-error
"Invalid client configuration or arguments."
[message detail]
(ex-info message {:type :ird/config-error :detail detail}))
(defn domain-denied
"Client-side domain gate refusal: the operation targets a domain that the
client's :denied-domains/:allowed-domains configuration forbids. Produced
before any request reaches the API."
[domain matched-pattern op]
(ex-info (str "Domain gate: " (or domain "(unknown domain)") " may not be touched by " op)
{:type :ird/domain-denied :domain domain :matched-pattern matched-pattern :op op}))
(defn timeout
"A polling helper passed its deadline; LAST is the last result seen."
[message last]
(ex-info message {:type :ird/timeout :last last}))
(defn job-failed
"ird.jobs/run: the job reached the failed status. JOB is the job map."
[message job]
(ex-info message {:type :ird/job-failed :job job}))
(defn upload-failed
"ird.ipfs/add-file: the upload failed or expired. UPLOAD is the upload map."
[message upload]
(ex-info message {:type :ird/upload-failed :upload upload}))
(def types
"Every :type an ird error can carry."
#{:ird/api-error :ird/transport-error :ird/config-error :ird/domain-denied
:ird/timeout :ird/job-failed :ird/upload-failed})
(def error?
"True for any error value (js/Error, including ExceptionInfo). Same as
ird.async/error?, re-exported for convenience."
a/error?)
(defn ird-error?
"True when E is an ex-info produced by this library."
[e]
(contains? types (:type (ex-data e))))
(defn api-error? [e] (= :ird/api-error (:type (ex-data e))))
(defn transport-error? [e] (= :ird/transport-error (:type (ex-data e))))
(defn config-error? [e] (= :ird/config-error (:type (ex-data e))))
(defn domain-denied? [e] (= :ird/domain-denied (:type (ex-data e))))
(defn timeout? [e] (= :ird/timeout (:type (ex-data e))))
(defn job-failed? [e] (= :ird/job-failed (:type (ex-data e))))
(defn upload-failed? [e] (= :ird/upload-failed (:type (ex-data e))))