cljs / src / ird / ipfs.cljs
1,000 words
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
(ns ird.ipfs
  "IPFS pinning, direct uploads, IPNS names and customer gateway domains
  (which can serve your pins directly at /ipfs/<cid>).
  Prepaid hourly billing per pinned MiB plus gateway egress; deletes are
  always free. The standard IPFS Pinning Service API lives in ird.pins.

  For uploading local content use `add-file`, which drives the whole
  grant→upload→pin flow. Every function returns a channel (see ird.async)."
  (:require [ird.async :refer [go-try <?]]
            [ird.errors :as err]
            [ird.gate :as gate]
            [ird.node :as node]
            [ird.transport :as transport]))

(defn list-pins
  "GET /ipfs/pins — List your pins.
  Optional QUERY keys include :status, :q, :limit, :offset."
  ([client] (list-pins client nil))
  ([client query]
   (transport/request client :get "/ipfs/pins" {:query query})))

(defn list-all-pins
  "GET /ipfs/pins — Every pin, following offset pagination.
  Optional QUERY keys include :status, :q and a page :limit (default 100).
  Delivers a vector of pin maps."
  ([client] (list-all-pins client nil))
  ([client query]
   (transport/paginate-offset client :get "/ipfs/pins" :pins query)))

(defn pin
  "POST /ipfs/pins — Pin by CID (202; billing starts once pinned).
  BODY keys include :cid, :name, :origins, :meta."
  [client body]
  (transport/request client :post "/ipfs/pins" {:body body}))

(defn get-pin
  "GET /ipfs/pins/{id} — Pin detail."
  [client id]
  (transport/request client :get ["ipfs" "pins" id]))

(defn unpin
  "DELETE /ipfs/pins/{id} — Unpin (202; free)."
  [client id]
  (transport/request client :delete ["ipfs" "pins" id]))

(defn start-upload
  "POST /ipfs/uploads — Start a direct upload. Issues a short-lived
  single-use grant {:upload {:url :token ...}}; POST the raw bytes to that
  URL (see ird.transport/upload-bytes) then poll `get-upload`.
  Optional BODY keys include :name, :format (\"file\" or \"car\"), :meta."
  ([client] (start-upload client nil))
  ([client body]
   (transport/request client :post "/ipfs/uploads" (when body {:body body}))))

(defn get-upload
  "GET /ipfs/uploads/{id} — Upload status (issued/completed/failed/expired)."
  [client id]
  (transport/request client :get ["ipfs" "uploads" id]))

(defn list-names
  "GET /ipfs/names — List your IPNS names."
  [client]
  (transport/request client :get "/ipfs/names"))

(defn create-name
  "POST /ipfs/names — Create an IPNS name.
  Optional BODY keys include :label, :serve."
  ([client] (create-name client nil))
  ([client body]
   (transport/request client :post "/ipfs/names" (when body {:body body}))))

(defn get-name
  "GET /ipfs/names/{id} — IPNS name detail."
  [client id]
  (transport/request client :get ["ipfs" "names" id]))

(defn delete-name
  "DELETE /ipfs/names/{id} — Delete an IPNS name (202)."
  [client id]
  (transport/request client :delete ["ipfs" "names" id]))

(defn publish-target
  "PUT /ipfs/names/{id}/target — Publish a new target for an IPNS name.
  BODY is a plain map with :cid."
  [client id body]
  (transport/request client :put ["ipfs" "names" id "target"] {:body body}))

(defn list-domains
  "GET /ipfs/domains — List your gateway domains."
  [client]
  (transport/request client :get "/ipfs/domains"))

(defn attach-domain
  "POST /ipfs/domains — Attach your own domain as an IPFS gateway.
  BODY keys include :domain and optional :ipns_name_id (link the domain to
  one of your IPNS names) and :pin_ids (pins to serve at /ipfs/<cid> right
  away — manage them later with `update-domain-pins`). Subject to the
  client's domain gate on :domain. The response's :dns_target is the gateway
  IPv4 the domain's A record must point at on manually mapped rows."
  [client body]
  (gate/request client "POST /ipfs/domains" {:domain (:domain body)}
                :post "/ipfs/domains" {:body body}))

(defn get-domain
  "GET /ipfs/domains/{id} — Gateway domain detail."
  [client id]
  (transport/request client :get ["ipfs" "domains" id]))

(defn list-domain-pins
  "GET /ipfs/domains/{id}/pins — The pins a gateway domain serves at
  /ipfs/<cid>, oldest attachment first.
  Optional QUERY keys are :limit (1–100, default 100) and :offset.
  Delivers {:pins :total :limit :offset}."
  ([client id] (list-domain-pins client id nil))
  ([client id query]
   (transport/request client :get ["ipfs" "domains" id "pins"] {:query query})))

(defn list-all-domain-pins
  "GET /ipfs/domains/{id}/pins — Every pin a gateway domain serves,
  following offset pagination (attachments are unbounded). Delivers a vector
  of pin maps."
  ([client id] (list-all-domain-pins client id nil))
  ([client id query]
   (transport/paginate-offset client :get ["ipfs" "domains" id "pins"] :pins query)))

(defn- domain-target
  "Gate target for a gateway domain: its name via `get-domain`. Called only
  when the client has a gate."
  [client id]
  (go-try {:domain (get-in (<? (get-domain client id)) [:domain :domain])}))

(defn update-domain-pins
  "POST /ipfs/domains/{id}/pins — Attach or detach the pins a gateway domain
  serves. BODY keys are :add and :remove, both vectors of pin ids; the delta
  is idempotent, so re-adding an attached pin or removing an absent one is a
  no-op. Subject to the client's domain gate on the gateway's domain
  (resolved via `get-domain` when a gate is set). Delivers the domain's new
  :pin_count."
  [client id body]
  (gate/request client "POST /ipfs/domains/{id}/pins" #(domain-target client id)
                :post ["ipfs" "domains" id "pins"] {:body body}))

(defn detach-domain
  "DELETE /ipfs/domains/{id} — Detach a gateway domain (202). Subject to
  the client's domain gate on the gateway's domain (resolved via
  `get-domain` when a gate is set)."
  [client id]
  (gate/request client "DELETE /ipfs/domains/{id}" #(domain-target client id)
                :delete ["ipfs" "domains" id]))

(defn usage
  "GET /ipfs/usage — Storage usage and cost."
  [client]
  (transport/request client :get "/ipfs/usage"))

(def upload-terminal-status #{"completed" "failed" "expired"})

(defn add-file
  "Convenience: upload local content to IPFS end to end — start an upload
  grant, POST the bytes to the grant URL, then poll the upload until it
  completes and deliver the final upload map (with :cid and :pin_id).

  SOURCE is a file path (string, read with node:fs), or bytes: a Uint8Array
  (a Buffer is one), ArrayBuffer, Blob or ReadableStream.

  OPTS:
    :name        display name for the pin
    :format      \"file\" (default) or \"car\" for a client-packed CAR
                 archive
    :meta        string→string metadata map
    :interval-ms initial poll interval (default 1000, backing off to an 8s
                 cap — see ird.transport/poll-until)
    :timeout-ms  overall deadline (default 300000)

  Delivers an :ird/upload-failed error when the upload fails or expires, or
  :ird/timeout when the deadline passes first."
  ([client source] (add-file client source nil))
  ([client source {:keys [name format meta interval-ms timeout-ms]}]
   (go-try
     (let [bytes (if (string? source) (<? (node/read-file source)) source)
           start-body (cond-> {}
                        name (assoc :name name)
                        format (assoc :format format)
                        meta (assoc :meta meta))
           {:keys [upload]} (<? (start-upload client (not-empty start-body)))
           _ (<? (transport/upload-bytes (:url upload) (:token upload) bytes
                                         {:format (when (= "car" format) "car")
                                          :http-fn (:http-fn client)
                                          :timeout-ms (:timeout-ms client)}))
           final (:upload (<? (transport/poll-until
                               #(get-upload client (:id upload))
                               (fn [resp]
                                 (contains? upload-terminal-status
                                            (get-in resp [:upload :status])))
                               {:interval-ms interval-ms
                                :timeout-ms (or timeout-ms 300000)
                                :message (str "Timed out waiting for IPFS upload " (:id upload))
                                :sleep-fn (:sleep-fn client)})))]
       (if (= "completed" (:status final))
         final
         (throw (err/upload-failed (str "IPFS upload " (:id final) " " (:status final)) final)))))))

static mirror of HEAD · about · clone: git clone https://ird.cod-sursa.ro/cljs.git