From c87b67af10af4afdf06e4a56d5f4aa9fff7671b3 Mon Sep 17 00:00:00 2001 From: Mikko Koski Date: Thu, 15 Jan 2026 13:46:42 +0200 Subject: [PATCH 1/2] Replace form-data with navite FormData Since Node v18, FormData is natively supported, no need for library. --- package.json | 1 - src/sharetribe/flex_cli/commands/assets.cljs | 5 ++--- src/sharetribe/flex_cli/process_util.cljs | 3 +-- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index ad97910..de75102 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,6 @@ }, "dependencies": { "chalk": "^2.4.2", - "form-data": "^2.5.1", "inquirer": "^6.2.2", "mkdirp": "^0.5.1", "open": "6.4.0", diff --git a/src/sharetribe/flex_cli/commands/assets.cljs b/src/sharetribe/flex_cli/commands/assets.cljs index 8d80432..083dfe4 100644 --- a/src/sharetribe/flex_cli/commands/assets.cljs +++ b/src/sharetribe/flex_cli/commands/assets.cljs @@ -4,7 +4,6 @@ [clojure.set :as set] [clojure.string :as str] [chalk] - [form-data :as FormData] [sharetribe.flex-cli.api.client :as api.client :refer [do-multipart-post do-get]] [sharetribe.flex-cli.async-util :refer [ Date: Thu, 15 Jan 2026 13:55:24 +0200 Subject: [PATCH 2/2] Use native Node fetch instead of cljs-ajax Since v18, Node has had a native support for cljs-ajax. In addition, the native fetch seems to be able to handle binaries and streaming, which we need for downloading the asset zip The client implementation of do-* functions contain a bit of duplication which could be removed, but I didn't want to do it yet since the asset zip download may change things a bit. --- deps.edn | 4 +- package.json | 3 +- src/sharetribe/flex_cli/api/client.cljs | 134 ++++++++++++++---------- 3 files changed, 83 insertions(+), 58 deletions(-) diff --git a/deps.edn b/deps.edn index 9b48679..7f648f9 100644 --- a/deps.edn +++ b/deps.edn @@ -9,6 +9,4 @@ fipp {:mvn/version "0.6.18"} aysylu/loom {:mvn/version "1.0.2"} thheller/shadow-cljs {:mvn/version "2.15.12"} - - ;; Requires xmlhttprequest from NPM - cljs-ajax {:mvn/version "0.7.5"}}} + com.cognitect/transit-cljs {:mvn/version "0.8.280"}}} diff --git a/package.json b/package.json index de75102..4647393 100644 --- a/package.json +++ b/package.json @@ -31,7 +31,6 @@ "inquirer": "^6.2.2", "mkdirp": "^0.5.1", "open": "6.4.0", - "rimraf": "^3.0.0", - "xmlhttprequest": "^1.8.0" + "rimraf": "^3.0.0" } } diff --git a/src/sharetribe/flex_cli/api/client.cljs b/src/sharetribe/flex_cli/api/client.cljs index 9db8495..03412a7 100644 --- a/src/sharetribe/flex_cli/api/client.cljs +++ b/src/sharetribe/flex_cli/api/client.cljs @@ -1,5 +1,5 @@ (ns sharetribe.flex-cli.api.client - (:require [ajax.core :as ajax] + (:require [cognitect.transit :as t] [clojure.core.async :as async :refer [put! chan ex-data :res :response :errors first)) +(def transit-reader (t/reader :json)) +(def transit-writer (t/writer :json)) + +(defn- to-query-param [v] + (clj->js v)) + +(defn- construct-url [url query-params] + (let [url (js/URL. url)] + (doseq [[k v] query-params] + (.set (.-searchParams url) (name k) (to-query-param v))) + url)) + +(defn read-transit [s] + (try + {:success true + :data (t/read transit-reader s)} + (catch js/Error _e + {:success false}))) + +(defn- handle-response [out-chan response req] + (-> + (.text response) + (.then + (fn [body-str] + (let [parsed (read-transit body-str)] + (put! out-chan + (if (.-ok response) + (:data parsed) + (let [parsed (read-transit body-str)] + (handle-error req + (cond-> {:status (.-status response) + :status-text (.-statusText response)} + (:success parsed) (assoc :response (:data parsed)) + (not (:success parsed)) (assoc :original-text body-str))))))))))) + (defn do-get [client path query] (let [c (chan)] - (ajax/ajax-request - {:uri (str (config/value :api-base-url) path) - :method :get - :params query - :headers {"Authorization" (str "Apikey " (::api-key client)) - "User-Agent" user-agent} - :handler (fn [[ok? response]] - (put! c - (if ok? - response - (handle-error {:client client - :path path - :query query} - response)))) - :format (ajax/transit-request-format) - :response-format (ajax/transit-response-format)}) + (-> (js/fetch + (construct-url (str (config/value :api-base-url) path) query) + (clj->js + {:method "GET" + :headers {"Authorization" (str "Apikey " (::api-key client)) + "User-Agent" user-agent + "Accept" "application/transit+json"}})) + (.then (fn [response] + (handle-response c response {:client client + :path path + :query query}))) + ;; Unknown failure + (.catch (fn [error] (put! c (exception/exception :client/api-request-failed error))))) c)) (defn do-post [client path query body] (let [c (chan)] - (ajax/ajax-request - {:uri (str (config/value :api-base-url) path) - :method :post - :url-params query - :params body - :headers {"Authorization" (str "Apikey " (::api-key client)) - "User-Agent" user-agent} - :handler (fn [[ok? response]] - (put! c - (if ok? - response - (handle-error {:client client - :path path - :query query} - response)))) - :format (ajax/transit-request-format) - :response-format (ajax/transit-response-format)}) + (-> (js/fetch + (construct-url (str (config/value :api-base-url) path) query) + (clj->js + {:method "POST" + :body (t/write transit-writer body) + :headers {"Authorization" (str "Apikey " (::api-key client)) + "Content-Type" "application/transit+json" + "User-Agent" user-agent + "Accept" "application/transit+json"}})) + (.then (fn [response] + (handle-response c response {:client client + :path path + :query query}))) + + ;; Unknown failure + (.catch (fn [error] (put! c (exception/exception :client/api-request-failed error))))) c)) -(defn do-multipart-post [client path query ^js form-data] +(defn do-multipart-post [client path query form-data] (let [c (chan)] - (ajax/ajax-request - {:uri (str (config/value :api-base-url) path) - :method :post - :url-params query - :params form-data - :headers {"Authorization" (str "Apikey " (::api-key client)) - "User-Agent" user-agent} - :handler (fn [[ok? response]] - (put! c - (if ok? - response - (handle-error {:client client - :path path - :query query} - response)))) - :format {:write (fn [^js form-data] (.getBuffer form-data)) - :content-type (goog.object/get (.getHeaders form-data) "content-type")} - :response-format (ajax/transit-response-format)}) + (-> (js/fetch + (construct-url (str (config/value :api-base-url) path) query) + (clj->js + {:method "POST" + :body form-data + :headers {"Authorization" (str "Apikey " (::api-key client)) + "User-Agent" user-agent + "Accept" "application/transit+json"}})) + (.then (fn [response] + (handle-response c response {:client client + :path path + :query query}))) + + ;; Unknown failure + (.catch (fn [error] (put! c (exception/exception :client/api-request-failed error))))) c)) (defn new-client [api-key]