0
Fork 0
mirror of https://github.com/penpot/penpot.git synced 2025-04-09 21:41:23 -05:00

Merge pull request #5196 from penpot/niwinz-remove-graaljs

⬆️ Update deps (part 1) and remove graalvm js
This commit is contained in:
Alejandro 2024-10-29 08:48:50 +01:00 committed by GitHub
commit e7d7291947
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
58 changed files with 2738 additions and 46535 deletions

View file

@ -3,10 +3,10 @@
:deps
{penpot/common {:local/root "../common"}
org.clojure/clojure {:mvn/version "1.12.0-alpha12"}
org.clojure/clojure {:mvn/version "1.12.0"}
org.clojure/tools.namespace {:mvn/version "1.5.0"}
com.github.luben/zstd-jni {:mvn/version "1.5.6-3"}
com.github.luben/zstd-jni {:mvn/version "1.5.6-6"}
io.prometheus/simpleclient {:mvn/version "0.16.0"}
io.prometheus/simpleclient_hotspot {:mvn/version "0.16.0"}
@ -17,33 +17,33 @@
io.prometheus/simpleclient_httpserver {:mvn/version "0.16.0"}
io.lettuce/lettuce-core {:mvn/version "6.3.2.RELEASE"}
io.lettuce/lettuce-core {:mvn/version "6.4.0.RELEASE"}
java-http-clj/java-http-clj {:mvn/version "0.4.3"}
funcool/yetti
{:git/tag "v10.0"
:git/sha "520613f"
{:git/tag "v11.4"
:git/sha "ce50d42"
:git/url "https://github.com/funcool/yetti.git"
:exclusions [org.slf4j/slf4j-api]}
com.github.seancorfield/next.jdbc {:mvn/version "1.3.939"}
metosin/reitit-core {:mvn/version "0.7.0"}
nrepl/nrepl {:mvn/version "1.1.2"}
cider/cider-nrepl {:mvn/version "0.48.0"}
com.github.seancorfield/next.jdbc {:mvn/version "1.3.955"}
metosin/reitit-core {:mvn/version "0.7.2"}
nrepl/nrepl {:mvn/version "1.3.0"}
cider/cider-nrepl {:mvn/version "0.50.2"}
org.postgresql/postgresql {:mvn/version "42.7.3"}
org.xerial/sqlite-jdbc {:mvn/version "3.46.0.0"}
org.postgresql/postgresql {:mvn/version "42.7.4"}
org.xerial/sqlite-jdbc {:mvn/version "3.46.1.3"}
com.zaxxer/HikariCP {:mvn/version "5.1.0"}
com.zaxxer/HikariCP {:mvn/version "6.0.0"}
io.whitfin/siphash {:mvn/version "2.0.0"}
buddy/buddy-hashers {:mvn/version "2.0.167"}
buddy/buddy-sign {:mvn/version "3.5.351"}
buddy/buddy-sign {:mvn/version "3.6.1-359"}
com.github.ben-manes.caffeine/caffeine {:mvn/version "3.1.8"}
org.jsoup/jsoup {:mvn/version "1.17.2"}
org.jsoup/jsoup {:mvn/version "1.18.1"}
org.im4java/im4java
{:git/tag "1.4.0-penpot-2"
:git/sha "e2b3e16"
@ -58,7 +58,7 @@
;; Pretty Print specs
pretty-spec/pretty-spec {:mvn/version "0.1.4"}
software.amazon.awssdk/s3 {:mvn/version "2.25.63"}
software.amazon.awssdk/s3 {:mvn/version "2.28.26"}
}
:paths ["src" "resources" "target/classes"]
@ -74,7 +74,7 @@
:build
{:extra-deps
{io.github.clojure/tools.build {:git/tag "v0.10.3" :git/sha "15ead66"}}
{io.github.clojure/tools.build {:git/tag "v0.10.5" :git/sha "2a21b7a"}}
:ns-default build}
:test

View file

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="info" monitorInterval="30">
<Configuration status="fatal" monitorInterval="30">
<Appenders>
<Console name="console" target="SYSTEM_OUT">
<PatternLayout pattern="[%d{YYYY-MM-dd HH:mm:ss.SSS}] %level{length=1} %logger{36} - %msg%n"

View file

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="info" monitorInterval="30">
<Configuration status="fatal" monitorInterval="30">
<Appenders>
<Console name="console" target="SYSTEM_OUT">
<PatternLayout pattern="[%d{YYYY-MM-dd HH:mm:ss.SSS}] %level{length=1} %logger{36} - %msg%n"

View file

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="info" monitorInterval="30">
<Configuration status="fatal" monitorInterval="30">
<Appenders>
<Console name="console" target="SYSTEM_OUT">
<PatternLayout pattern="[%d{YYYY-MM-dd HH:mm:ss.SSS}] %level{length=1} %logger{36} - %msg%n"

View file

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="info" monitorInterval="60">
<Configuration status="fatal" monitorInterval="60">
<Appenders>
<Console name="console" target="SYSTEM_OUT">
<PatternLayout pattern="[%d{YYYY-MM-dd HH:mm:ss.SSS}] %level{length=1} %logger{36} - %msg%n"

View file

@ -7,6 +7,8 @@ set -ex
rm -rf target;
mkdir -p target/classes;
mkdir -p target/dist;
mkdir -p target/dist/scripts;
echo "$CURRENT_VERSION" > target/classes/version.txt;
cp ../CHANGES.md target/classes/changelog.md;
@ -15,6 +17,7 @@ mv target/penpot.jar target/dist/penpot.jar
cp resources/log4j2.xml target/dist/log4j2.xml
cp scripts/run.template.sh target/dist/run.sh;
cp scripts/manage.py target/dist/manage.py
cp scripts/svgo-cli.js target/dist/scripts/;
chmod +x target/dist/run.sh;
chmod +x target/dist/manage.py

214
backend/scripts/svgo-cli.js Normal file

File diff suppressed because one or more lines are too long

View file

@ -35,8 +35,8 @@
[clojure.spec.alpha :as s]
[cuerdas.core :as str]
[integrant.core :as ig]
[ring.request :as rreq]
[ring.response :as-alias rres]))
[yetti.request :as yreq]
[yetti.response :as-alias yres]))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; HELPERS
@ -492,8 +492,8 @@
(defn- redirect-response
[uri]
{::rres/status 302
::rres/headers {"location" (str uri)}})
{::yres/status 302
::yres/headers {"location" (str uri)}})
(defn- redirect-with-error
([error] (redirect-with-error error nil))
@ -598,7 +598,7 @@
(defn- get-external-session-id
[request]
(let [session-id (rreq/get-header request "x-external-session-id")]
(let [session-id (yreq/get-header request "x-external-session-id")]
(when (string? session-id)
(if (or (> (count session-id) 256)
(= session-id "null")
@ -618,8 +618,8 @@
state (tokens/generate (::setup/props cfg)
(d/without-nils params))
uri (build-auth-uri cfg state)]
{::rres/status 200
::rres/body {:redirect-uri uri}}))
{::yres/status 200
::yres/body {:redirect-uri uri}}))
(defn- callback-handler
[{:keys [::provider] :as cfg} request]

View file

@ -222,7 +222,7 @@
(defn copy-stream!
[^OutputStream output ^InputStream input ^long size]
(let [written (io/copy! input output :size size)]
(let [written (io/copy input output :size size)]
(l/trace :fn "copy-stream!" :position @*position* :size size :written written ::l/sync? true)
(swap! *position* + written)
written))
@ -251,11 +251,11 @@
(if (> s bfc/temp-file-threshold)
(with-open [^OutputStream output (io/output-stream p)]
(let [readed (io/copy! input output :offset 0 :size s)]
(let [readed (io/copy input output :offset 0 :size s)]
(l/trace :fn "read-stream*!" :expected s :readed readed :position @*position* ::l/sync? true)
(swap! *position* + readed)
[s p]))
[s (io/read-as-bytes input :size s)])))
[s (io/read input :size s)])))
(defmacro assert-read-label!
[input expected-label]
@ -699,7 +699,7 @@
(dm/assert!
"expected instance of jio/IOFactory for `input`"
(satisfies? jio/IOFactory output))
(io/coercible? output))
(let [id (uuid/next)
tp (dt/tpoint)

View file

@ -190,7 +190,7 @@
[{:keys [::sto/storage] :as cfg} id]
(let [sobj (sto/get-object storage id)
data (with-open [input (sto/get-object-data storage sobj)]
(io/read-as-bytes input))]
(io/read input))]
(l/trc :hint "write" :obj "storage-object" :id (str id) :size (:size sobj))
(write! cfg :storage-object id (meta sobj) data)))

View file

@ -236,7 +236,7 @@
(with-open [input (sto/get-object-data storage sobject)]
(.putNextEntry output (ZipEntry. (str "objects/" id ext)))
(io/copy! input output (:size sobject))
(io/copy input output :size (:size sobject))
(.closeEntry output))))))
(defn- export-file
@ -385,7 +385,7 @@
(defn- zip-entry-reader
[^ZipFile input ^ZipEntry entry]
(-> (zip-entry-stream input entry)
(jio/reader :encoding "UTF-8")))
(io/reader :encoding "UTF-8")))
(defn- zip-entry-storage-content
"Wraps a ZipFile and ZipEntry into a penpot storage compatible
@ -929,7 +929,7 @@
(dm/assert!
"expected instance of jio/IOFactory for `input`"
(satisfies? jio/IOFactory input))
(io/coercible? input))
(let [id (uuid/next)
tp (dt/tpoint)

View file

@ -41,6 +41,7 @@
[app.common.types.shape.path :as ctsp]
[app.common.types.shape.text :as ctsx]
[app.common.uuid :as uuid]
[app.config :as cf]
[app.db :as db]
[app.db.sql :as sql]
[app.features.fdata :as fdata]
@ -1298,7 +1299,7 @@
(let [[mtype data] (parse-datauri href)
size (alength ^bytes data)
path (tmp/tempfile :prefix "penpot.media.download.")
written (io/write-to-file! data path :size size)]
written (io/write* path data :size size)]
(when (not= written size)
(ex/raise :type :internal
@ -1381,7 +1382,9 @@
(defn get-optimized-svg
[sid]
(let [svg-text (get-sobject-content sid)
svg-text (svgo/optimize *system* svg-text)]
svg-text (if (contains? cf/flags :backend-svgo)
(svgo/optimize *system* svg-text)
svg-text)]
(csvg/parse svg-text)))
(def base-path "/data/cache")
@ -1484,11 +1487,6 @@
:file-id (str (:id fdata))
:id (str (:id mobj)))
(instance? org.graalvm.polyglot.PolyglotException cause)
(l/inf :hint "skip processing media object: invalid svg found"
:file-id (str (:id fdata))
:id (str (:id mobj)))
(= (:type edata) :not-found)
(l/inf :hint "skip processing media object: underlying object does not exist"
:file-id (str (:id fdata))

View file

@ -29,9 +29,9 @@
[promesa.exec :as px]
[reitit.core :as r]
[reitit.middleware :as rr]
[ring.request :as rreq]
[ring.response :as-alias rres]
[yetti.adapter :as yt]))
[yetti.adapter :as yt]
[yetti.request :as yreq]
[yetti.response :as-alias yres]))
(declare router-handler)
@ -100,12 +100,12 @@
(defn- not-found-handler
[_]
{::rres/status 404})
{::yres/status 404})
(defn- router-handler
[router]
(letfn [(resolve-handler [request]
(if-let [match (r/match-by-path router (rreq/path request))]
(if-let [match (r/match-by-path router (yreq/path request))]
(let [params (:path-params match)
result (:result match)
handler (or (:handler result) not-found-handler)
@ -114,11 +114,11 @@
(partial not-found-handler request)))
(on-error [cause request]
(let [{:keys [::rres/body] :as response} (errors/handle cause request)]
(let [{:keys [::yres/body] :as response} (errors/handle cause request)]
(cond-> response
(map? body)
(-> (update ::rres/headers assoc "content-type" "application/transit+json")
(assoc ::rres/body (t/encode-str body {:type :json-verbose}))))))]
(-> (update ::yres/headers assoc "content-type" "application/transit+json")
(assoc ::yres/body (t/encode-str body {:type :json-verbose}))))))]
(fn [request]
(let [handler (resolve-handler request)]

View file

@ -12,13 +12,13 @@
[app.main :as-alias main]
[app.setup :as-alias setup]
[app.tokens :as tokens]
[ring.request :as rreq]))
[yetti.request :as yreq]))
(def header-re #"^Token\s+(.*)")
(defn- get-token
[request]
(some->> (rreq/get-header request "authorization")
(some->> (yreq/get-header request "authorization")
(re-matches header-re)
(second)))

View file

@ -16,7 +16,7 @@
[app.util.time :as dt]
[clojure.spec.alpha :as s]
[integrant.core :as ig]
[ring.response :as-alias rres]))
[yetti.response :as-alias yres]))
(def ^:private cache-max-age
(dt/duration {:hours 24}))
@ -37,8 +37,8 @@
(defn- serve-object-from-s3
[{:keys [::sto/storage] :as cfg} obj]
(let [{:keys [host port] :as url} (sto/get-object-url storage obj {:max-age signature-max-age})]
{::rres/status 307
::rres/headers {"location" (str url)
{::yres/status 307
::yres/headers {"location" (str url)
"x-host" (cond-> host port (str ":" port))
"x-mtype" (-> obj meta :content-type)
"cache-control" (str "max-age=" (inst-ms cache-max-age))}}))
@ -51,8 +51,8 @@
headers {"x-accel-redirect" (:path purl)
"content-type" (:content-type mdata)
"cache-control" (str "max-age=" (inst-ms cache-max-age))}]
{::rres/status 204
::rres/headers headers}))
{::yres/status 204
::yres/headers headers}))
(defn- serve-object
"Helper function that returns the appropriate response depending on
@ -69,7 +69,7 @@
obj (sto/get-object storage id)]
(if obj
(serve-object cfg obj)
{::rres/status 404})))
{::yres/status 404})))
(defn- generic-handler
"A generic handler helper/common code for file-media based handlers."
@ -80,7 +80,7 @@
sobj (sto/get-object storage (kf mobj))]
(if sobj
(serve-object cfg sobj)
{::rres/status 404})))
{::yres/status 404})))
(defn file-objects-handler
"Handler that serves storage objects by file media id."

View file

@ -22,8 +22,8 @@
[cuerdas.core :as str]
[integrant.core :as ig]
[promesa.exec :as px]
[ring.request :as rreq]
[ring.response :as-alias rres]))
[yetti.request :as yreq]
[yetti.response :as-alias yres]))
(declare parse-json)
(declare handle-request)
@ -38,9 +38,9 @@
(defmethod ig/init-key ::routes
[_ cfg]
(letfn [(handler [request]
(let [data (-> request rreq/body slurp)]
(let [data (-> request yreq/body slurp)]
(px/run! :vthread (partial handle-request cfg data)))
{::rres/status 200})]
{::yres/status 200})]
["/sns" {:handler handler
:allowed-methods #{:post}}]))

View file

@ -33,8 +33,8 @@
[integrant.core :as ig]
[markdown.core :as md]
[markdown.transformers :as mdt]
[ring.request :as rreq]
[ring.response :as rres]))
[yetti.request :as yreq]
[yetti.response :as yres]))
;; (selmer.parser/cache-off!)
@ -44,9 +44,9 @@
(defn index-handler
[_cfg _request]
{::rres/status 200
::rres/headers {"content-type" "text/html"}
::rres/body (-> (io/resource "app/templates/debug.tmpl")
{::yres/status 200
::yres/headers {"content-type" "text/html"}
::yres/body (-> (io/resource "app/templates/debug.tmpl")
(tmpl/render {}))})
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@ -56,17 +56,17 @@
(defn prepare-response
[body]
(let [headers {"content-type" "application/transit+json"}]
{::rres/status 200
::rres/body body
::rres/headers headers}))
{::yres/status 200
::yres/body body
::yres/headers headers}))
(defn prepare-download-response
[body filename]
(let [headers {"content-disposition" (str "attachment; filename=" filename)
"content-type" "application/octet-stream"}]
{::rres/status 200
::rres/body body
::rres/headers headers}))
{::yres/status 200
::yres/body body
::yres/headers headers}))
(def sql:retrieve-range-of-changes
"select revn, changes from file_change where file_id=? and revn >= ? and revn <= ? order by revn")
@ -108,8 +108,8 @@
(db/update! conn :file
{:data data}
{:id file-id})
{::rres/status 201
::rres/body "OK CREATED"})))
{::yres/status 201
::yres/body "OK CREATED"})))
:else
(prepare-response (blob/decode data))))))
@ -123,7 +123,7 @@
[{:keys [::db/pool]} {:keys [::session/profile-id params] :as request}]
(let [profile (profile/get-profile pool profile-id)
project-id (:default-project-id profile)
data (some-> params :file :path io/read-as-bytes)]
data (some-> params :file :path io/read*)]
(if (and data project-id)
(let [fname (str "Imported file *: " (dt/now))
@ -138,8 +138,8 @@
{:data data
:deleted-at nil}
{:id file-id})
{::rres/status 200
::rres/body "OK UPDATED"})
{::yres/status 200
::yres/body "OK UPDATED"})
(db/run! pool (fn [{:keys [::db/conn] :as cfg}]
(create-file cfg {:id file-id
@ -149,15 +149,15 @@
(db/update! conn :file
{:data data}
{:id file-id})
{::rres/status 201
::rres/body "OK CREATED"}))))
{::yres/status 201
::yres/body "OK CREATED"}))))
{::rres/status 500
::rres/body "ERROR"})))
{::yres/status 500
::yres/body "ERROR"})))
(defn file-data-handler
[cfg request]
(case (rreq/method request)
(case (yreq/method request)
:get (retrieve-file-data cfg request)
:post (upload-file-data cfg request)
(ex/raise :type :http
@ -238,12 +238,12 @@
1 (render-template-v1 report)
2 (render-template-v2 report)
3 (render-template-v3 report))]
{::rres/status 200
::rres/body result
::rres/headers {"content-type" "text/html; charset=utf-8"
{::yres/status 200
::yres/body result
::yres/headers {"content-type" "text/html; charset=utf-8"
"x-robots-tag" "noindex"}})
{::rres/status 404
::rres/body "not found"})))
{::yres/status 404
::yres/body "not found"})))
(def sql:error-reports
"SELECT id, created_at,
@ -256,10 +256,10 @@
[{:keys [::db/pool]} _request]
(let [items (->> (db/exec! pool [sql:error-reports])
(map #(update % :created-at dt/format-instant :rfc1123)))]
{::rres/status 200
::rres/body (-> (io/resource "app/templates/error-list.tmpl")
{::yres/status 200
::yres/body (-> (io/resource "app/templates/error-list.tmpl")
(tmpl/render {:items items}))
::rres/headers {"content-type" "text/html; charset=utf-8"
::yres/headers {"content-type" "text/html; charset=utf-8"
"x-robots-tag" "noindex"}}))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@ -298,13 +298,13 @@
::bf.v1/project-id project-id
::bf.v1/input path)]
(bf.v1/import-files! cfg)
{::rres/status 200
::rres/headers {"content-type" "text/plain"}
::rres/body "OK CLONED"})
{::yres/status 200
::yres/headers {"content-type" "text/plain"}
::yres/body "OK CLONED"})
{::rres/status 200
::rres/body (io/input-stream path)
::rres/headers {"content-type" "application/octet-stream"
{::yres/status 200
::yres/body (io/input-stream path)
::yres/headers {"content-type" "application/octet-stream"
"content-disposition" (str "attachmen; filename=" (first file-ids) ".penpot")}}))))
@ -333,9 +333,9 @@
::bf.v1/project-id project-id
::bf.v1/input path)]
(bf.v1/import-files! cfg)
{::rres/status 200
::rres/headers {"content-type" "text/plain"}
::rres/body "OK"})))
{::yres/status 200
::yres/headers {"content-type" "text/plain"}
::yres/body "OK"})))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ACTIONS
@ -365,34 +365,34 @@
(db/update! conn :profile {:is-blocked true} {:id (:id profile)})
(db/delete! conn :http-session {:profile-id (:id profile)})
{::rres/status 200
::rres/headers {"content-type" "text/plain"}
::rres/body (str/ffmt "PROFILE '%' BLOCKED" (:email profile))})
{::yres/status 200
::yres/headers {"content-type" "text/plain"}
::yres/body (str/ffmt "PROFILE '%' BLOCKED" (:email profile))})
(contains? params :unblock)
(do
(db/update! conn :profile {:is-blocked false} {:id (:id profile)})
{::rres/status 200
::rres/headers {"content-type" "text/plain"}
::rres/body (str/ffmt "PROFILE '%' UNBLOCKED" (:email profile))})
{::yres/status 200
::yres/headers {"content-type" "text/plain"}
::yres/body (str/ffmt "PROFILE '%' UNBLOCKED" (:email profile))})
(contains? params :resend)
(if (:is-blocked profile)
{::rres/status 200
::rres/headers {"content-type" "text/plain"}
::rres/body "PROFILE ALREADY BLOCKED"}
{::yres/status 200
::yres/headers {"content-type" "text/plain"}
::yres/body "PROFILE ALREADY BLOCKED"}
(do
(#'auth/send-email-verification! cfg profile)
{::rres/status 200
::rres/headers {"content-type" "text/plain"}
::rres/body (str/ffmt "RESENDED FOR '%'" (:email profile))}))
{::yres/status 200
::yres/headers {"content-type" "text/plain"}
::yres/body (str/ffmt "RESENDED FOR '%'" (:email profile))}))
:else
(do
(db/update! conn :profile {:is-active true} {:id (:id profile)})
{::rres/status 200
::rres/headers {"content-type" "text/plain"}
::rres/body (str/ffmt "PROFILE '%' ACTIVATED" (:email profile))}))))))
{::yres/status 200
::yres/headers {"content-type" "text/plain"}
::yres/body (str/ffmt "PROFILE '%' ACTIVATED" (:email profile))}))))))
(defn- reset-file-version
@ -417,9 +417,9 @@
(db/tx-run! cfg srepl/process-file! file-id #(assoc % :version version))
{::rres/status 200
::rres/headers {"content-type" "text/plain"}
::rres/body "OK"}))
{::yres/status 200
::yres/headers {"content-type" "text/plain"}
::yres/body "OK"}))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@ -431,13 +431,13 @@
[{:keys [::db/pool]} _]
(try
(db/exec-one! pool ["select count(*) as count from server_prop;"])
{::rres/status 200
::rres/body "OK"}
{::yres/status 200
::yres/body "OK"}
(catch Throwable cause
(l/warn :hint "unable to execute query on health handler"
:cause cause)
{::rres/status 503
::rres/body "KO"})))
{::yres/status 503
::yres/body "KO"})))
(defn changelog-handler
[_ _]
@ -446,11 +446,11 @@
(md->html [text]
(md/md-to-html-string text :replacement-transformers (into [transform-emoji] mdt/transformer-vector)))]
(if-let [clog (io/resource "changelog.md")]
{::rres/status 200
::rres/headers {"content-type" "text/html; charset=utf-8"}
::rres/body (-> clog slurp md->html)}
{::rres/status 404
::rres/body "NOT FOUND"})))
{::yres/status 200
::yres/headers {"content-type" "text/html; charset=utf-8"}
::yres/body (-> clog slurp md->html)}
{::yres/status 404
::yres/body "NOT FOUND"})))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; INIT

View file

@ -16,8 +16,8 @@
[app.http.session :as-alias session]
[app.util.inet :as inet]
[clojure.spec.alpha :as s]
[ring.request :as rreq]
[ring.response :as rres]))
[yetti.request :as yreq]
[yetti.response :as yres]))
(defn request->context
"Extracts error report relevant context data from request."
@ -29,10 +29,10 @@
{:request/path (:path request)
:request/method (:method request)
:request/params (:params request)
:request/user-agent (rreq/get-header request "user-agent")
:request/user-agent (yreq/get-header request "user-agent")
:request/ip-addr (inet/parse-request request)
:request/profile-id (:uid claims)
:version/frontend (or (rreq/get-header request "x-frontend-version") "unknown")
:version/frontend (or (yreq/get-header request "x-frontend-version") "unknown")
:version/backend (:full cf/version)}))
@ -46,34 +46,34 @@
(defmethod handle-error :authentication
[err _ _]
{::rres/status 401
::rres/body (ex-data err)})
{::yres/status 401
::yres/body (ex-data err)})
(defmethod handle-error :authorization
[err _ _]
{::rres/status 403
::rres/body (ex-data err)})
{::yres/status 403
::yres/body (ex-data err)})
(defmethod handle-error :restriction
[err _ _]
(let [{:keys [code] :as data} (ex-data err)]
(if (= code :method-not-allowed)
{::rres/status 405
::rres/body data}
{::rres/status 400
::rres/body data})))
{::yres/status 405
::yres/body data}
{::yres/status 400
::yres/body data})))
(defmethod handle-error :rate-limit
[err _ _]
(let [headers (-> err ex-data ::http/headers)]
{::rres/status 429
::rres/headers headers}))
{::yres/status 429
::yres/headers headers}))
(defmethod handle-error :concurrency-limit
[err _ _]
(let [headers (-> err ex-data ::http/headers)]
{::rres/status 429
::rres/headers headers}))
{::yres/status 429
::yres/headers headers}))
(defmethod handle-error :validation
[err request parent-cause]
@ -84,22 +84,22 @@
(= code :schema-validation)
(= code :data-validation))
(let [explain (ex/explain data)]
{::rres/status 400
::rres/body (-> data
{::yres/status 400
::yres/body (-> data
(dissoc ::s/problems ::s/value ::s/spec ::sm/explain)
(cond-> explain (assoc :explain explain)))})
(= code :request-body-too-large)
{::rres/status 413 ::rres/body data}
{::yres/status 413 ::yres/body data}
(= code :invalid-image)
(binding [l/*context* (request->context request)]
(let [cause (or parent-cause err)]
(l/warn :hint "unexpected error on processing image" :cause cause)
{::rres/status 400 ::rres/body data}))
{::yres/status 400 ::yres/body data}))
:else
{::rres/status 400 ::rres/body data})))
{::yres/status 400 ::yres/body data})))
(defmethod handle-error :assertion
[error request parent-cause]
@ -110,8 +110,8 @@
(= code :data-validation)
(let [explain (ex/explain data)]
(l/error :hint "data assertion error" :cause cause)
{::rres/status 500
::rres/body (-> data
{::yres/status 500
::yres/body (-> data
(dissoc ::sm/explain)
(cond-> explain (assoc :explain explain))
(assoc :type :server-error)
@ -120,8 +120,8 @@
(= code :spec-validation)
(let [explain (ex/explain data)]
(l/error :hint "spec assertion error" :cause cause)
{::rres/status 500
::rres/body (-> data
{::yres/status 500
::yres/body (-> data
(dissoc ::s/problems ::s/value ::s/spec)
(cond-> explain (assoc :explain explain))
(assoc :type :server-error)
@ -130,15 +130,15 @@
:else
(do
(l/error :hint "assertion error" :cause cause)
{::rres/status 500
::rres/body (-> data
{::yres/status 500
::yres/body (-> data
(assoc :type :server-error)
(assoc :code :assertion))})))))
(defmethod handle-error :not-found
[err _ _]
{::rres/status 404
::rres/body (ex-data err)})
{::yres/status 404
::yres/body (ex-data err)})
(defmethod handle-error :internal
[error request parent-cause]
@ -146,8 +146,8 @@
(let [cause (or parent-cause error)
data (ex-data error)]
(l/error :hint "internal error" :cause cause)
{::rres/status 500
::rres/body (-> data
{::yres/status 500
::yres/body (-> data
(assoc :type :server-error)
(update :code #(or % :unhandled))
(assoc :hint (ex-message error)))})))
@ -174,20 +174,20 @@
:cause cause)
(cond
(= state "57014")
{::rres/status 504
::rres/body {:type :server-error
{::yres/status 504
::yres/body {:type :server-error
:code :statement-timeout
:hint (ex-message error)}}
(= state "25P03")
{::rres/status 504
::rres/body {:type :server-error
{::yres/status 504
::yres/body {:type :server-error
:code :idle-in-transaction-timeout
:hint (ex-message error)}}
:else
{::rres/status 500
::rres/body {:type :server-error
{::yres/status 500
::yres/body {:type :server-error
:code :unexpected
:hint (ex-message error)
:state state}}))))
@ -201,16 +201,16 @@
(nil? edata)
(binding [l/*context* (request->context request)]
(l/error :hint "unexpected error" :cause cause)
{::rres/status 500
::rres/body {:type :server-error
{::yres/status 500
::yres/body {:type :server-error
:code :unexpected
:hint (ex-message error)}})
:else
(binding [l/*context* (request->context request)]
(l/error :hint "unhandled error" :cause cause)
{::rres/status 500
::rres/body (-> edata
{::yres/status 500
::yres/body (-> edata
(assoc :type :server-error)
(update :code #(or % :unhandled))
(assoc :hint (ex-message error)))}))))
@ -218,8 +218,8 @@
(defmethod handle-exception java.io.IOException
[cause _ _]
(l/wrn :hint "io exception" :cause cause)
{::rres/status 500
::rres/body {:type :server-error
{::yres/status 500
::yres/body {:type :server-error
:code :io-exception
:hint (ex-message cause)}})
@ -245,4 +245,4 @@
(defn handle'
[cause request]
(::rres/body (handle cause request)))
(::yres/body (handle cause request)))

View file

@ -15,10 +15,10 @@
[app.http.errors :as errors]
[app.util.pointer-map :as pmap]
[cuerdas.core :as str]
[ring.request :as rreq]
[ring.response :as rres]
[yetti.adapter :as yt]
[yetti.middleware :as ymw])
[yetti.middleware :as ymw]
[yetti.request :as yreq]
[yetti.response :as yres])
(:import
io.undertow.server.RequestTooBigException
java.io.InputStream
@ -37,17 +37,17 @@
(defn- get-reader
^java.io.BufferedReader
[request]
(let [^InputStream body (rreq/body request)]
(let [^InputStream body (yreq/body request)]
(java.io.BufferedReader.
(java.io.InputStreamReader. body))))
(defn wrap-parse-request
[handler]
(letfn [(process-request [request]
(let [header (rreq/get-header request "content-type")]
(let [header (yreq/get-header request "content-type")]
(cond
(str/starts-with? header "application/transit+json")
(with-open [^InputStream is (rreq/body request)]
(with-open [^InputStream is (yreq/body request)]
(let [params (t/read! (t/reader is))]
(-> request
(assoc :body-params params)
@ -85,7 +85,7 @@
(errors/handle cause request)))]
(fn [request]
(if (= (rreq/method request) :post)
(if (= (yreq/method request) :post)
(try
(-> request process-request handler)
(catch Throwable cause
@ -113,57 +113,53 @@
(defn wrap-format-response
[handler]
(letfn [(transit-streamable-body [data opts]
(reify rres/StreamableResponseBody
(-write-body-to-stream [_ _ output-stream]
(try
(with-open [^OutputStream bos (buffered-output-stream output-stream buffer-size)]
(let [tw (t/writer bos opts)]
(t/write! tw data)))
(catch java.io.IOException _)
(catch Throwable cause
(binding [l/*context* {:value data}]
(l/error :hint "unexpected error on encoding response"
:cause cause)))
(finally
(.close ^OutputStream output-stream))))))
(letfn [(transit-streamable-body [data opts _ output-stream]
(try
(with-open [^OutputStream bos (buffered-output-stream output-stream buffer-size)]
(let [tw (t/writer bos opts)]
(t/write! tw data)))
(catch java.io.IOException _)
(catch Throwable cause
(binding [l/*context* {:value data}]
(l/error :hint "unexpected error on encoding response"
:cause cause)))
(finally
(.close ^OutputStream output-stream))))
(json-streamable-body [data]
(reify rres/StreamableResponseBody
(-write-body-to-stream [_ _ output-stream]
(try
(let [encode (or (-> data meta :encode/json) identity)
data (encode data)]
(with-open [^OutputStream bos (buffered-output-stream output-stream buffer-size)]
(with-open [^java.io.OutputStreamWriter writer (java.io.OutputStreamWriter. bos)]
(json/write writer data :key-fn json/write-camel-key :value-fn write-json-value))))
(catch java.io.IOException _)
(catch Throwable cause
(binding [l/*context* {:value data}]
(l/error :hint "unexpected error on encoding response"
:cause cause)))
(finally
(.close ^OutputStream output-stream))))))
(json-streamable-body [data _ output-stream]
(try
(let [encode (or (-> data meta :encode/json) identity)
data (encode data)]
(with-open [^OutputStream bos (buffered-output-stream output-stream buffer-size)]
(with-open [^java.io.OutputStreamWriter writer (java.io.OutputStreamWriter. bos)]
(json/write writer data :key-fn json/write-camel-key :value-fn write-json-value))))
(catch java.io.IOException _)
(catch Throwable cause
(binding [l/*context* {:value data}]
(l/error :hint "unexpected error on encoding response"
:cause cause)))
(finally
(.close ^OutputStream output-stream))))
(format-response-with-json [response _]
(let [body (::rres/body response)]
(let [body (::yres/body response)]
(if (or (boolean? body) (coll? body))
(-> response
(update ::rres/headers assoc "content-type" "application/json")
(assoc ::rres/body (json-streamable-body body)))
(update ::yres/headers assoc "content-type" "application/json")
(assoc ::yres/body (yres/stream-body (partial json-streamable-body body))))
response)))
(format-response-with-transit [response request]
(let [body (::rres/body response)]
(let [body (::yres/body response)]
(if (or (boolean? body) (coll? body))
(let [qs (rreq/query request)
(let [qs (yreq/query request)
opts (if (or (contains? cf/flags :transit-readable-response)
(str/includes? qs "transit_verbose"))
{:type :json-verbose}
{:type :json})]
(-> response
(update ::rres/headers assoc "content-type" "application/transit+json")
(assoc ::rres/body (transit-streamable-body body opts))))
(update ::yres/headers assoc "content-type" "application/transit+json")
(assoc ::yres/body (yres/stream-body (partial transit-streamable-body body opts)))))
response)))
(format-from-params [{:keys [query-params] :as request}]
@ -172,7 +168,7 @@
(format-response [response request]
(let [accept (or (format-from-params request)
(rreq/get-header request "accept"))]
(yreq/get-header request "accept"))]
(cond
(or (= accept "application/transit+json")
(str/includes? accept "application/transit+json"))
@ -221,11 +217,11 @@
(defn wrap-cors
[handler]
(fn [request]
(let [response (if (= (rreq/method request) :options)
{::rres/status 200}
(let [response (if (= (yreq/method request) :options)
{::yres/status 200}
(handler request))
origin (rreq/get-header request "origin")]
(update response ::rres/headers with-cors-headers origin))))
origin (yreq/get-header request "origin")]
(update response ::yres/headers with-cors-headers origin))))
(def cors
{:name ::cors
@ -240,7 +236,7 @@
(when-let [allowed (:allowed-methods data)]
(fn [handler]
(fn [request]
(let [method (rreq/method request)]
(let [method (yreq/method request)]
(if (contains? allowed method)
(handler request)
{::rres/status 405}))))))})
{::yres/status 405}))))))})

View file

@ -22,8 +22,7 @@
[clojure.spec.alpha :as s]
[cuerdas.core :as str]
[integrant.core :as ig]
[ring.request :as rreq]
[yetti.request :as yrq]))
[yetti.request :as yreq]))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; DEFAULTS
@ -145,7 +144,7 @@
(us/assert! ::us/uuid profile-id)
(fn [request response]
(let [uagent (rreq/get-header request "user-agent")
(let [uagent (yreq/get-header request "user-agent")
params {:profile-id profile-id
:user-agent uagent
:created-at (dt/now)}
@ -161,7 +160,7 @@
(us/assert! ::manager manager)
(fn [request response]
(let [cname (cf/get :auth-token-cookie-name default-auth-token-cookie-name)
cookie (yrq/get-cookie request cname)]
cookie (yreq/get-cookie request cname)]
(l/trace :hint "delete" :profile-id (:profile-id request))
(some->> (:value cookie) (delete! manager))
(-> response
@ -183,7 +182,7 @@
(defn- get-token
[request]
(let [cname (cf/get :auth-token-cookie-name default-auth-token-cookie-name)
cookie (some-> (yrq/get-cookie request cname) :value)]
cookie (some-> (yreq/get-cookie request cname) :value)]
(when-not (str/empty? cookie)
cookie)))

View file

@ -16,7 +16,7 @@
[promesa.exec :as px]
[promesa.exec.csp :as sp]
[promesa.util :as pu]
[ring.response :as rres])
[yetti.response :as yres])
(:import
java.io.OutputStream))
@ -49,24 +49,24 @@
(defn response
[handler & {:keys [buf] :or {buf 32} :as opts}]
(fn [request]
{::rres/headers default-headers
::rres/status 200
::rres/body (reify rres/StreamableResponseBody
(-write-body-to-stream [_ _ output]
(binding [events/*channel* (sp/chan :buf buf :xf (keep encode))]
(let [listener (events/start-listener
(partial write! output)
(partial pu/close! output))]
(try
(let [result (handler)]
(events/tap :end result))
{::yres/headers default-headers
::yres/status 200
::yres/body (yres/stream-body
(fn [_ output]
(binding [events/*channel* (sp/chan :buf buf :xf (keep encode))]
(let [listener (events/start-listener
(partial write! output)
(partial pu/close! output))]
(try
(let [result (handler)]
(events/tap :end result))
(catch java.io.EOFException cause
(events/tap :error (errors/handle' cause request)))
(catch Throwable cause
(l/err :hint "unexpected error on processing sse response"
:cause cause)
(events/tap :error (errors/handle' cause request)))
(finally
(sp/close! events/*channel*)
(px/await! listener)))))))}))
(catch java.io.EOFException cause
(events/tap :error (errors/handle' cause request)))
(catch Throwable cause
(l/err :hint "unexpected error on processing sse response"
:cause cause)
(events/tap :error (errors/handle' cause request)))
(finally
(sp/close! events/*channel*)
(px/await! listener)))))))}))

View file

@ -21,7 +21,6 @@
[clojure.spec.alpha :as s]
[integrant.core :as ig]
[promesa.exec.csp :as sp]
[ring.websocket :as rws]
[yetti.websocket :as yws]))
(def recv-labels
@ -303,7 +302,7 @@
:else
(do
(l/trace :hint "websocket request" :profile-id profile-id :session-id session-id)
{::rws/listener (ws/listener request
{::yws/listener (ws/listener request
::ws/on-rcv-message (partial on-rcv-message cfg)
::ws/on-snd-message (partial on-snd-message cfg)
::ws/on-connect (partial on-connect cfg)

View file

@ -319,7 +319,6 @@
::mtx/metrics (ig/ref ::mtx/metrics)
::mbus/msgbus (ig/ref ::mbus/msgbus)
::rds/redis (ig/ref ::rds/redis)
::svgo/optimizer (ig/ref ::svgo/optimizer)
::rpc/climit (ig/ref ::rpc/climit)
::rpc/rlimit (ig/ref ::rpc/rlimit)
@ -430,9 +429,6 @@
;; module requires the migrations to run before initialize.
::migrations (ig/ref :app.migrations/migrations)}
::svgo/optimizer
{}
:app.loggers.audit.archive-task/handler
{::setup/props (ig/ref ::setup/props)
::db/pool (ig/ref ::db/pool)

View file

@ -225,7 +225,7 @@
(letfn [(ttf->otf [data]
(let [finput (tmp/tempfile :prefix "penpot.font." :suffix "")
foutput (fs/path (str finput ".otf"))
_ (io/write-to-file! data finput)
_ (io/write* finput data)
res (sh/sh "fontforge" "-lang=ff" "-c"
(str/fmt "Open('%s'); Generate('%s')"
(str finput)
@ -236,7 +236,7 @@
(otf->ttf [data]
(let [finput (tmp/tempfile :prefix "penpot.font." :suffix "")
foutput (fs/path (str finput ".ttf"))
_ (io/write-to-file! data finput)
_ (io/write* finput data)
res (sh/sh "fontforge" "-lang=ff" "-c"
(str/fmt "Open('%s'); Generate('%s')"
(str finput)
@ -250,14 +250,14 @@
;; command.
(let [finput (tmp/tempfile :prefix "penpot.font." :suffix "")
foutput (fs/path (str finput ".woff"))
_ (io/write-to-file! data finput)
_ (io/write* finput data)
res (sh/sh "sfnt2woff" (str finput))]
(when (zero? (:exit res))
foutput)))
(woff->sfnt [data]
(let [finput (tmp/tempfile :prefix "penpot" :suffix "")
_ (io/write-to-file! data finput)
_ (io/write* finput data)
res (sh/sh "woff2sfnt" (str finput)
:out-enc :bytes)]
(when (zero? (:exit res))

View file

@ -36,8 +36,8 @@
[cuerdas.core :as str]
[integrant.core :as ig]
[promesa.core :as p]
[ring.request :as rreq]
[ring.response :as rres]))
[yetti.request :as yreq]
[yetti.response :as yres]))
(s/def ::profile-id ::us/uuid)
@ -64,16 +64,16 @@
response (if (fn? result)
(result request)
(let [result (rph/unwrap result)]
{::rres/status (::http/status mdata 200)
::rres/headers (::http/headers mdata {})
::rres/body result}))]
{::yres/status (::http/status mdata 200)
::yres/headers (::http/headers mdata {})
::yres/body result}))]
(-> response
(handle-response-transformation request mdata)
(handle-before-comple-hook mdata))))
(defn get-external-session-id
[request]
(when-let [session-id (rreq/get-header request "x-external-session-id")]
(when-let [session-id (yreq/get-header request "x-external-session-id")]
(when-not (or (> (count session-id) 256)
(= session-id "null")
(str/blank? session-id))
@ -81,7 +81,7 @@
(defn- get-external-event-origin
[request]
(when-let [origin (rreq/get-header request "x-event-origin")]
(when-let [origin (yreq/get-header request "x-event-origin")]
(when-not (or (> (count origin) 256)
(= origin "null")
(str/blank? origin))
@ -92,7 +92,7 @@
internal async flow into ring async flow."
[methods {:keys [params path-params method] :as request}]
(let [handler-name (:type path-params)
etag (rreq/get-header request "if-none-match")
etag (yreq/get-header request "if-none-match")
profile-id (or (::session/profile-id request)
(::actoken/profile-id request))

View file

@ -25,7 +25,7 @@
[app.util.time :as dt]
[app.worker :as-alias wrk]
[promesa.exec :as px]
[ring.response :as rres]))
[yetti.response :as yres]))
(set! *warn-on-reflection* true)
@ -42,33 +42,33 @@
(defn stream-export-v1
[cfg {:keys [file-id include-libraries embed-assets] :as params}]
(reify rres/StreamableResponseBody
(-write-body-to-stream [_ _ output-stream]
(try
(-> cfg
(assoc ::bf.v1/ids #{file-id})
(assoc ::bf.v1/embed-assets embed-assets)
(assoc ::bf.v1/include-libraries include-libraries)
(bf.v1/export-files! output-stream))
(catch Throwable cause
(l/err :hint "exception on exporting file"
:file-id (str file-id)
:cause cause))))))
(yres/stream-body
(fn [_ output-stream]
(try
(-> cfg
(assoc ::bf.v1/ids #{file-id})
(assoc ::bf.v1/embed-assets embed-assets)
(assoc ::bf.v1/include-libraries include-libraries)
(bf.v1/export-files! output-stream))
(catch Throwable cause
(l/err :hint "exception on exporting file"
:file-id (str file-id)
:cause cause))))))
(defn stream-export-v3
[cfg {:keys [file-id include-libraries embed-assets] :as params}]
(reify rres/StreamableResponseBody
(-write-body-to-stream [_ _ output-stream]
(try
(-> cfg
(assoc ::bf.v3/ids #{file-id})
(assoc ::bf.v3/embed-assets embed-assets)
(assoc ::bf.v3/include-libraries include-libraries)
(bf.v3/export-files! output-stream))
(catch Throwable cause
(l/err :hint "exception on exporting file"
:file-id (str file-id)
:cause cause))))))
(yres/stream-body
(fn [_ output-stream]
(try
(-> cfg
(assoc ::bf.v3/ids #{file-id})
(assoc ::bf.v3/embed-assets embed-assets)
(assoc ::bf.v3/include-libraries include-libraries)
(bf.v3/export-files! output-stream))
(catch Throwable cause
(l/err :hint "exception on exporting file"
:file-id (str file-id)
:cause cause))))))
(sv/defmethod ::export-binfile
"Export a penpot file in a binary format."
@ -84,9 +84,9 @@
2 (throw (ex-info "not-implemented" {}))
3 (stream-export-v3 cfg params))]
{::rres/status 200
::rres/headers {"content-type" "application/octet-stream"}
::rres/body body})))
{::yres/status 200
::yres/headers {"content-type" "application/octet-stream"}
::yres/body body})))
;; --- Command: import-binfile

View file

@ -216,7 +216,7 @@
{:response-type :input-stream :sync? true})
{:keys [size mtype]} (parse-and-validate response)
path (tmp/tempfile :prefix "penpot.media.download.")
written (io/write-to-file! body path :size size)]
written (io/write* path body :size size)]
(when (not= written size)
(ex/raise :type :internal

View file

@ -29,7 +29,7 @@
[app.util.services :as-alias sv]
[buddy.core.codecs :as bc]
[buddy.core.hash :as bh]
[ring.response :as-alias rres]))
[yetti.response :as-alias yres]))
(def
^{:dynamic true
@ -59,7 +59,7 @@
key' (when (some? object)
(->> object (key-fn params) (fmt-key)))]
(if (and (some? key) (= key key'))
(fn [_] {::rres/status 304})
(fn [_] {::yres/status 304})
(let [params (if (some? object)
(assoc params ::object object)
params)

View file

@ -27,7 +27,7 @@
[cuerdas.core :as str]
[integrant.core :as ig]
[pretty-spec.core :as ps]
[ring.response :as-alias rres]))
[yetti.response :as-alias yres]))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; DOC (human readable)
@ -87,11 +87,11 @@
(let [params (:query-params request)
pstyle (:type params "js")
context (assoc context :param-style pstyle)]
{::rres/status 200
::rres/body (-> (io/resource "app/templates/api-doc.tmpl")
{::yres/status 200
::yres/body (-> (io/resource "app/templates/api-doc.tmpl")
(tmpl/render context))}))
(fn [_]
{::rres/status 404})))
{::yres/status 404})))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; OPENAPI / SWAGGER (v3.1)
@ -175,12 +175,12 @@
[context]
(if (contains? cf/flags :backend-openapi-doc)
(fn [_]
{::rres/status 200
::rres/headers {"content-type" "application/json; charset=utf-8"}
::rres/body (json/encode context)})
{::yres/status 200
::yres/headers {"content-type" "application/json; charset=utf-8"}
::yres/body (json/encode context)})
(fn [_]
{::rres/status 404})))
{::yres/status 404})))
(defn openapi-handler
[]
@ -191,12 +191,12 @@
context {:public-uri (cf/get :public-uri)
:swagger-js swagger-js
:swagger-css swagger-cs}]
{::rres/status 200
::rres/headers {"content-type" "text/html"}
::rres/body (-> (io/resource "app/templates/openapi.tmpl")
{::yres/status 200
::yres/headers {"content-type" "text/html"}
::yres/body (-> (io/resource "app/templates/openapi.tmpl")
(tmpl/render context))}))
(fn [_]
{::rres/status 404})))
{::yres/status 404})))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; MODULE INIT

View file

@ -11,7 +11,7 @@
[app.common.data.macros :as dm]
[app.http :as-alias http]
[app.rpc :as-alias rpc]
[ring.response :as-alias rres]))
[yetti.response :as-alias yres]))
;; A utilty wrapper object for wrap service responses that does not
;; implements the IObj interface that make possible attach metadata to
@ -77,4 +77,4 @@
(fn [_ response]
(let [exp (if (integer? max-age) max-age (inst-ms max-age))
val (dm/fmt "max-age=%" (int (/ exp 1000.0)))]
(update response ::rres/headers assoc "cache-control" val)))))
(update response ::yres/headers assoc "cache-control" val)))))

View file

@ -6,7 +6,6 @@
(ns app.storage.fs
(:require
[app.common.data.macros :as dm]
[app.common.exceptions :as ex]
[app.common.spec :as us]
[app.common.uri :as u]
@ -18,9 +17,13 @@
[datoteka.io :as io]
[integrant.core :as ig])
(:import
java.io.InputStream
java.io.OutputStream
java.nio.file.Files
java.nio.file.Path))
(set! *warn-on-reflection* true)
;; --- BACKEND INIT
(s/def ::directory ::us/string)
@ -58,9 +61,9 @@
(when-not (fs/exists? (fs/parent full))
(fs/create-dir (fs/parent full)))
(dm/with-open [src (io/input-stream content)
dst (io/output-stream full)]
(io/copy! src dst))
(with-open [^InputStream src (io/input-stream content)]
(with-open [^OutputStream dst (io/output-stream full)]
(io/copy src dst)))
object))
@ -78,8 +81,8 @@
(defmethod impl/get-object-bytes :fs
[backend object]
(dm/with-open [input (impl/get-object-data backend object)]
(io/read-as-bytes input)))
(with-open [^InputStream input (impl/get-object-data backend object)]
(io/read input)))
(defmethod impl/get-object-url :fs
[{:keys [::uri] :as backend} {:keys [id] :as object} _]

View file

@ -7,36 +7,32 @@
(ns app.svgo
"A SVG Optimizer service"
(:require
[app.common.jsrt :as jsrt]
[app.common.logging :as l]
[app.worker :as-alias wrk]
[integrant.core :as ig]
[promesa.exec.semaphore :as ps]
[promesa.util :as pu]))
[app.util.shell :as shell]
[datoteka.fs :as fs]
[promesa.exec.semaphore :as ps]))
(def ^:dynamic *semaphore*
"A dynamic variable that can optionally contain a traffic light to
appropriately delimit the use of resources, managed externally."
nil)
(set! *warn-on-reflection* true)
(defn optimize
[{pool ::optimizer} data]
[system data]
(try
(some-> *semaphore* ps/acquire!)
(jsrt/run! pool
(fn [context]
(jsrt/set! context "svgData" data)
(jsrt/eval! context "penpotSvgo.optimize(svgData, {plugins: ['safeAndFastPreset']})")))
(let [script (fs/join fs/*cwd* "scripts/svgo-cli.js")
cmd ["node" (str script)]
result (shell/exec! system
:cmd cmd
:in data)]
(if (= (:exit result) 0)
(:out result)
(do
(l/raw! :warn (str "Error on optimizing svg, returning svg as-is." (:err result)))
data)))
(finally
(some-> *semaphore* ps/release!))))
(defmethod ig/init-key ::optimizer
[_ _]
(l/inf :hint "initializing svg optimizer pool")
(let [init (jsrt/resource->source "app/common/svg/optimizer.js")]
(jsrt/pool :init init)))
(defmethod ig/halt-key! ::optimizer
[_ pool]
(l/info :hint "stopping svg optimizer pool")
(pu/close! pool))

View file

@ -8,7 +8,7 @@
"INET addr parsing and validation helpers"
(:require
[cuerdas.core :as str]
[ring.request :as rreq])
[yetti.request :as yreq])
(:import
com.google.common.net.InetAddresses
java.net.InetAddress))
@ -27,11 +27,11 @@
(defn parse-request
[request]
(or (some-> (rreq/get-header request "x-real-ip")
(or (some-> (yreq/get-header request "x-real-ip")
(normalize))
(some-> (rreq/get-header request "x-forwarded-for")
(some-> (yreq/get-header request "x-forwarded-for")
(str/split #"\s*,\s*")
(first)
(normalize))
(some-> (rreq/remote-addr request)
(some-> (yreq/remote-addr request)
(normalize))))

View file

@ -0,0 +1,71 @@
;; This Source Code Form is subject to the terms of the Mozilla Public
;; License, v. 2.0. If a copy of the MPL was not distributed with this
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
;;
;; Copyright (c) KALEIDOS INC
(ns app.util.shell
"A penpot specific, modern api for executing external (shell)
subprocesses"
(:require
[app.worker :as-alias wrk]
[datoteka.io :as io]
[promesa.exec :as px])
(:import
java.io.InputStream
java.io.OutputStream
java.util.List
org.apache.commons.io.IOUtils))
(set! *warn-on-reflection* true)
(defn- read-as-bytes
[in]
(with-open [^InputStream input (io/input-stream in)]
(io/read input)))
(defn- read-as-string
([in] (read-as-string in "UTF-8"))
([in enc]
(IOUtils/toString ^InputStream in ^String enc)))
(defn- read-with-enc
[stream enc]
(if (= enc :bytes)
(read-as-bytes stream)
(read-as-string stream enc)))
(defn- set-env
[penv k v]
(.put ^java.util.Map penv
^String k
^String v))
(defn exec!
[system & {:keys [cmd in out-enc in-enc env]
:or {out-enc "UTF-8"
in-enc "UTF-8"}}]
(assert (vector? cmd) "a command parameter should be a vector")
(assert (every? string? cmd) "the command should be a vector of strings")
(let [executor (::wrk/executor system)
builder (ProcessBuilder. ^List cmd)
env-map (.environment ^ProcessBuilder builder)
_ (reduce-kv set-env env-map env)
process (.start builder)]
(if in
(px/run! executor
(fn []
(with-open [^OutputStream stdin (.getOutputStream ^Process process)]
(io/write stdin in :encoding in-enc))))
(io/close (.getOutputStream ^Process process)))
(with-open [stdout (.getInputStream ^Process process)
stderr (.getErrorStream ^Process process)]
(let [out (px/submit! executor (fn [] (read-with-enc stdout out-enc)))
err (px/submit! executor (fn [] (read-as-string stderr)))
ext (.waitFor ^Process process)]
{:exit ext
:out @out
:err @err}))))

View file

@ -16,8 +16,7 @@
[promesa.exec :as px]
[promesa.exec.csp :as sp]
[promesa.util :as pu]
[ring.request :as rreq]
[ring.websocket :as rws]
[yetti.request :as yreq]
[yetti.websocket :as yws])
(:import
java.nio.ByteBuffer))
@ -85,7 +84,7 @@
hbeat-ch (sp/chan :buf (sp/sliding-buffer 6))
close-ch (sp/chan)
ip-addr (inet/parse-request request)
uagent (rreq/get-header request "user-agent")
uagent (yreq/get-header request "user-agent")
id (uuid/next)
state (atom {})
beats (atom #{})
@ -138,7 +137,7 @@
(defn- handle-ping!
[{:keys [::id ::beats ::channel] :as wsp} beat-id]
(l/trc :hint "send ping" :beat beat-id :conn-id (str id))
(rws/ping channel (encode-beat beat-id))
(yws/ping channel (encode-beat beat-id))
(let [issued (swap! beats conj (long beat-id))]
(not (>= (count issued) max-missed-heartbeats))))
@ -151,14 +150,14 @@
(loop [i 0]
(let [ping-ch (sp/timeout-chan heartbeat-interval)
[msg p] (sp/alts! [close-ch input-ch output-ch heartbeat-ch ping-ch])]
(when (rws/open? channel)
(when (yws/open? channel)
(cond
(identical? p ping-ch)
(if (handle-ping! wsp i)
(recur (inc i))
(do
(l/trc :hint "closing" :reason "missing to many pings")
(rws/close channel 8802 "missing to many pings")))
(yws/close channel 8802 "missing to many pings")))
(or (identical? p close-ch) (nil? msg))
(do :nothing)
@ -183,7 +182,7 @@
(identical? p output-ch)
(let [message (on-snd-message msg)
message (t/encode-str message {:type :json-verbose})]
(rws/send channel message)
(yws/send channel message)
(recur i))))))
(catch InterruptedException _cause
@ -202,13 +201,13 @@
(try
(handler wsp {:type :close})
(when (rws/open? channel)
(when (yws/open? channel)
;; NOTE: we need to ignore all exceptions here because
;; there can be a race condition that first returns that
;; channel is connected but on closing, will raise that
;; channel is already closed.
(ex/ignoring
(rws/close channel 8899 "terminated")))
(yws/close channel 8899 "terminated")))
(when-let [on-disconnect (::on-disconnect wsp)]
(on-disconnect))

View file

@ -47,8 +47,9 @@
[mockery.core :as mk]
[promesa.core :as p]
[promesa.exec :as px]
[ring.response :as rres]
[yetti.request :as yrq])
[ring.core.protocols :as rcp]
[yetti.request :as yrq]
[yetti.response :as yres])
(:import
java.io.PipedInputStream
java.io.PipedOutputStream
@ -548,12 +549,12 @@
(defn consume-sse
[callback]
(let [{:keys [::rres/status ::rres/body ::rres/headers] :as response} (callback {})
(let [{:keys [::yres/status ::yres/body ::yres/headers] :as response} (callback {})
output (PipedOutputStream.)
input (PipedInputStream. output)]
(try
(px/exec! :virtual #(rres/-write-body-to-stream body nil output))
(px/exec! :virtual #(rcp/write-body-to-stream body nil output))
(into []
(map (fn [event]
(let [[item1 item2] (re-seq #"(.*): (.*)\n?" event)]

View file

@ -12,7 +12,8 @@
[app.rpc :as-alias rpc]
[app.util.time :as dt]
[backend-tests.helpers :as th]
[clojure.test :as t]))
[clojure.test :as t]
[yetti.request]))
(t/use-fixtures :once th/state-init)
(t/use-fixtures :each th/database-reset)
@ -25,7 +26,7 @@
(def http-request
(reify
ring.request/Request
yetti.request/IRequest
(get-header [_ name]
(case name
"x-forwarded-for" "127.0.0.44"

View file

@ -44,5 +44,5 @@
{:keys [error result]} (th/command! (assoc params ::cond/key etag))]
(t/is (nil? error))
(t/is (fn? result))
(t/is (= 304 (-> (result nil) :ring.response/status))))))))
(t/is (= 304 (-> (result nil) :yetti.response/status))))))))

View file

@ -28,8 +28,7 @@
font-id (uuid/custom 10 1)
ttfdata (-> (io/resource "backend_tests/test_files/font-1.ttf")
io/input-stream
io/read-as-bytes)
(io/read*))
params {::th/type :create-font-variant
::rpc/profile-id (:id prof)
@ -65,8 +64,7 @@
font-id (uuid/custom 10 1)
data (-> (io/resource "backend_tests/test_files/font-1.woff")
io/input-stream
io/read-as-bytes)
(io/read*))
params {::th/type :create-font-variant
::rpc/profile-id (:id prof)
@ -100,12 +98,10 @@
font-id (uuid/custom 10 1)
data1 (-> (io/resource "backend_tests/test_files/font-1.woff")
io/input-stream
io/read-as-bytes)
(io/read*))
data2 (-> (io/resource "backend_tests/test_files/font-2.woff")
io/input-stream
io/read-as-bytes)]
(io/read*))]
;; Create front variant
(let [params {::th/type :create-font-variant
@ -162,12 +158,10 @@
font-id (uuid/custom 10 1)
data1 (-> (io/resource "backend_tests/test_files/font-1.woff")
io/input-stream
io/read-as-bytes)
(io/read*))
data2 (-> (io/resource "backend_tests/test_files/font-2.woff")
io/input-stream
io/read-as-bytes)]
(io/read*))]
;; Create front variant
(let [params {::th/type :create-font-variant
@ -224,12 +218,10 @@
font-id (uuid/custom 10 1)
data1 (-> (io/resource "backend_tests/test_files/font-1.woff")
io/input-stream
io/read-as-bytes)
(io/read*))
data2 (-> (io/resource "backend_tests/test_files/font-2.woff")
io/input-stream
io/read-as-bytes)
(io/read*))
params1 {::th/type :create-font-variant
::rpc/profile-id (:id prof)
:team-id team-id

View file

@ -47,11 +47,7 @@
(t/is (sto/object? mobj1))
(t/is (sto/object? mobj2))
(t/is (= 122785 (:size mobj1)))
;; This is because in ubuntu 21.04 generates different
;; thumbnail that in ubuntu 22.04. This hack should be removed
;; when we all use the ubuntu 22.04 devenv image.
(t/is (or (= 3302 (:size mobj2))
(= 3303 (:size mobj2))))))))
(t/is (= 3302 (:size mobj2)))))))
(t/deftest media-object-upload
(let [prof (th/create-profile* 1)
@ -166,11 +162,7 @@
(t/is (sto/object? mobj1))
(t/is (sto/object? mobj2))
(t/is (= 122785 (:size mobj1)))
;; This is because in ubuntu 21.04 generates different
;; thumbnail that in ubuntu 22.04. This hack should be removed
;; when we all use the ubuntu 22.04 devenv image.
(t/is (or (= 3302 (:size mobj2))
(= 3303 (:size mobj2))))))))
(t/is (= 3302 (:size mobj2)))))))
(t/deftest media-object-upload-command
(let [prof (th/create-profile* 1)

View file

@ -202,8 +202,7 @@
:is-shared false})
ttfdata (-> (io/resource "backend_tests/test_files/font-1.ttf")
io/input-stream
io/read-as-bytes)
(io/read*))
mfile {:filename "sample.jpg"
:path (th/tempfile "backend_tests/test_files/sample.jpg")

View file

@ -1,5 +1,5 @@
{:deps
{org.clojure/clojure {:mvn/version "1.11.2"}
{org.clojure/clojure {:mvn/version "1.12.0"}
org.clojure/data.json {:mvn/version "2.5.0"}
org.clojure/tools.cli {:mvn/version "1.1.230"}
org.clojure/clojurescript {:mvn/version "1.11.132"}
@ -7,19 +7,19 @@
org.clojure/data.fressian {:mvn/version "1.1.0"}
;; Logging
org.apache.logging.log4j/log4j-api {:mvn/version "2.23.1"}
org.apache.logging.log4j/log4j-core {:mvn/version "2.23.1"}
org.apache.logging.log4j/log4j-web {:mvn/version "2.23.1"}
org.apache.logging.log4j/log4j-jul {:mvn/version "2.23.1"}
org.apache.logging.log4j/log4j-slf4j2-impl {:mvn/version "2.23.1"}
org.slf4j/slf4j-api {:mvn/version "2.0.13"}
org.apache.logging.log4j/log4j-api {:mvn/version "2.24.1"}
org.apache.logging.log4j/log4j-core {:mvn/version "2.24.1"}
org.apache.logging.log4j/log4j-web {:mvn/version "2.24.1"}
org.apache.logging.log4j/log4j-jul {:mvn/version "2.24.1"}
org.apache.logging.log4j/log4j-slf4j2-impl {:mvn/version "2.24.1"}
org.slf4j/slf4j-api {:mvn/version "2.0.16"}
pl.tkowalcz.tjahzi/log4j2-appender {:mvn/version "0.9.32"}
selmer/selmer {:mvn/version "1.12.61"}
criterium/criterium {:mvn/version "0.4.6"}
metosin/jsonista {:mvn/version "0.3.8"}
metosin/malli {:mvn/version "0.16.1"}
metosin/jsonista {:mvn/version "0.3.11"}
metosin/malli {:mvn/version "0.16.4"}
expound/expound {:mvn/version "0.9.0"}
com.cognitect/transit-clj {:mvn/version "1.0.333"}
@ -27,9 +27,6 @@
java-http-clj/java-http-clj {:mvn/version "0.4.3"}
integrant/integrant {:mvn/version "0.8.1"}
org.apache.commons/commons-pool2 {:mvn/version "2.12.0"}
org.graalvm.js/js {:mvn/version "23.0.4"}
funcool/tubax {:mvn/version "2021.05.20-0"}
funcool/cuerdas {:mvn/version "2023.11.09-407"}
funcool/promesa
@ -37,8 +34,8 @@
:git/url "https://github.com/funcool/promesa"}
funcool/datoteka
{:git/sha "5ac3781"
:git/tag "3.0.0"
{:git/tag "4.0.0"
:git/sha "3372f3a"
:git/url "https://github.com/funcool/datoteka"}
lambdaisland/uri {:mvn/version "1.19.155"
@ -53,8 +50,8 @@
fipp/fipp {:mvn/version "0.6.26"}
io.github.eerohele/pp
{:git/tag "2024-01-04.60"
:git/sha "e8a9773"}
{:git/tag "2024-09-09.69"
:git/sha "de4b20f"}
io.aviso/pretty {:mvn/version "1.4.4"}
environ/environ {:mvn/version "1.2.0"}}
@ -63,7 +60,7 @@
{:dev
{:extra-deps
{org.clojure/tools.namespace {:mvn/version "RELEASE"}
thheller/shadow-cljs {:mvn/version "2.28.8"}
thheller/shadow-cljs {:mvn/version "2.28.18"}
com.clojure-goes-fast/clj-async-profiler {:mvn/version "RELEASE"}
com.bhauman/rebel-readline {:mvn/version "RELEASE"}
criterium/criterium {:mvn/version "RELEASE"}
@ -72,7 +69,7 @@
:build
{:extra-deps
{io.github.clojure/tools.build {:git/tag "v0.10.3" :git/sha "15ead66"}}
{io.github.clojure/tools.build {:git/tag "v0.10.5" :git/sha "2a21b7a"}}
:ns-default build}
:test

View file

@ -15,7 +15,7 @@
"sax": "^1.4.1"
},
"devDependencies": {
"shadow-cljs": "2.28.11",
"shadow-cljs": "2.28.18",
"source-map-support": "^0.5.21",
"ws": "^8.17.0"
},

View file

@ -1,77 +0,0 @@
;; This Source Code Form is subject to the terms of the Mozilla Public
;; License, v. 2.0. If a copy of the MPL was not distributed with this
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
;;
;; Copyright (c) KALEIDOS INC
(ns app.common.jsrt
"A JS runtime for the JVM"
(:refer-clojure :exclude [run!])
(:require
[clojure.java.io :as io])
(:import
org.apache.commons.pool2.ObjectPool
org.apache.commons.pool2.PooledObject
org.apache.commons.pool2.PooledObjectFactory
org.apache.commons.pool2.impl.DefaultPooledObject
org.apache.commons.pool2.impl.SoftReferenceObjectPool
org.graalvm.polyglot.Context
org.graalvm.polyglot.Source
org.graalvm.polyglot.Value))
(defn resource->source
[path]
(let [resource (io/resource path)]
(.. (Source/newBuilder "js" resource)
(build))))
(defn pool?
[o]
(instance? ObjectPool o))
(defn pool
[& {:keys [init]}]
(SoftReferenceObjectPool.
(reify PooledObjectFactory
(activateObject [_ _])
(destroyObject [_ o]
(let [context (.getObject ^PooledObject o)]
(.close ^java.lang.AutoCloseable context)))
(destroyObject [_ o _]
(let [context (.getObject ^PooledObject o)]
(.close ^java.lang.AutoCloseable context)))
(passivateObject [_ _])
(validateObject [_ _] true)
(makeObject [_]
(let [context (Context/create (into-array String ["js"]))]
(.initialize ^Context context "js")
(when (instance? Source init)
(.eval ^Context context ^Source init))
(DefaultPooledObject. context))))))
(defn run!
[^ObjectPool pool f]
(let [ctx (.borrowObject pool)]
(try
(f ctx)
(finally
(.returnObject pool ctx)))))
(defn eval!
[context data & {:keys [as] :or {as :string}}]
(let [result (.eval ^Context context "js" ^String data)]
(case as
(:string :str) (.asString ^Value result)
:long (.asLong ^Value result)
:int (.asInt ^Value result)
:float (.asFloat ^Value result)
:double (.asDouble ^Value result))))
(defn set!
[context attr value]
(let [bindings (.getBindings ^Context context "js")]
(.putMember ^Value bindings ^String attr ^String value)
context))

View file

@ -29,8 +29,7 @@
(defprotocol ILazySchema
(-validate [_ o])
(-explain [_ o])
(-decode [_ o]))
(-explain [_ o]))
(def default-options
{:registry sr/default-registry})
@ -337,9 +336,7 @@
(-validate [_ o]
(@validator o))
(-explain [_ o]
(@explainer o))
(-decode [_ o]
(@decoder o)))))
(@explainer o)))))
;; --- BUILTIN SCHEMAS

View file

@ -8,7 +8,6 @@
(:require
#?(:clj [clojure.xml :as xml]
:cljs [tubax.core :as tubax])
#?(:cljs ["./svg/optimizer.js" :as svgo])
[app.common.data :as d]
[app.common.data.macros :as dm]
[app.common.geom.matrix :as gmt]
@ -1052,10 +1051,3 @@
:clj (let [text (strip-doctype text)]
(dm/with-open [istream (IOUtils/toInputStream text "UTF-8")]
(xml/parse istream secure-parser-factory)))))
;; FIXME pass correct plugin set
#?(:cljs
(defn optimize
([input] (optimize input nil))
([input options]
(svgo/optimize input (clj->js options)))))

File diff suppressed because one or more lines are too long

View file

@ -4,8 +4,9 @@ LABEL maintainer="Penpot <docker@penpot.app>"
ENV LANG='en_US.UTF-8' \
LC_ALL='en_US.UTF-8' \
JAVA_HOME="/opt/jdk" \
PATH=/opt/jdk/bin:$PATH \
PATH=/opt/jdk/bin:/opt/node/bin:$PATH \
DEBIAN_FRONTEND=noninteractive \
NODE_VERSION=v20.18.0 \
TZ=Etc/UTC
RUN set -ex; \
@ -36,6 +37,27 @@ RUN set -ex; \
chown -R penpot:penpot /opt/data; \
rm -rf /var/lib/apt/lists/*;
RUN set -eux; \
ARCH="$(dpkg --print-architecture)"; \
case "${ARCH}" in \
aarch64|arm64) \
BINARY_URL="https://nodejs.org/dist/${NODE_VERSION}/node-${NODE_VERSION}-linux-arm64.tar.gz"; \
;; \
amd64|x86_64) \
BINARY_URL="https://nodejs.org/dist/${NODE_VERSION}/node-${NODE_VERSION}-linux-x64.tar.gz"; \
;; \
*) \
echo "Unsupported arch: ${ARCH}"; \
exit 1; \
;; \
esac; \
curl -LfsSo /tmp/nodejs.tar.gz ${BINARY_URL}; \
mkdir -p /opt/node; \
cd /opt/node; \
tar -xf /tmp/nodejs.tar.gz --strip-components=1; \
chown -R root /opt/node; \
rm -rf /tmp/nodejs.tar.gz;
RUN set -eux; \
ARCH="$(dpkg --print-architecture)"; \
case "${ARCH}" in \

View file

@ -1,9 +1,9 @@
{:paths ["src" "vendor" "resources" "test"]
:deps
{penpot/common {:local/root "../common"}
org.clojure/clojure {:mvn/version "1.11.3"}
org.clojure/clojure {:mvn/version "1.12.0"}
binaryage/devtools {:mvn/version "RELEASE"}
metosin/reitit-core {:mvn/version "0.7.0"}
metosin/reitit-core {:mvn/version "0.7.2"}
}
:aliases
{:outdated
@ -14,7 +14,7 @@
:dev
{:extra-deps
{thheller/shadow-cljs {:mvn/version "2.28.11"}}}
{thheller/shadow-cljs {:mvn/version "2.28.18"}}}
:shadow-cljs
{:main-opts ["-m" "shadow.cljs.devtools.cli"]}

View file

@ -15,14 +15,15 @@
"generic-pool": "^3.9.0",
"inflation": "^2.1.0",
"ioredis": "^5.4.1",
"luxon": "^3.4.4",
"playwright": "^1.44.1",
"raw-body": "^2.5.2",
"luxon": "^3.5.0",
"playwright": "^1.48.1",
"raw-body": "^3.0.0",
"svgo": "penpot/svgo#v3",
"xml-js": "^1.6.11",
"xregexp": "^5.1.1"
},
"devDependencies": {
"shadow-cljs": "2.28.11",
"shadow-cljs": "2.28.18",
"source-map-support": "^0.5.21"
},
"scripts": {

View file

@ -6,11 +6,11 @@
(ns app.renderer.svg
(:require
["svgo" :as svgo]
["xml-js" :as xml]
[app.browser :as bw]
[app.common.data :as d]
[app.common.logging :as l]
[app.common.svg :as svg]
[app.common.uri :as u]
[app.config :as cf]
[app.util.mime :as mime]
@ -319,7 +319,7 @@
result (str/replace result "&nbsp;" "&#160;")
result (if (contains? cf/flags :exporter-svgo)
(svg/optimize result)
(svgo/optimize result svgo/defaultOptions)
result)]
;; (println "------- ORIGIN:")

View file

@ -65,6 +65,13 @@ __metadata:
languageName: node
linkType: hard
"@trysound/sax@npm:0.2.0":
version: 0.2.0
resolution: "@trysound/sax@npm:0.2.0"
checksum: 10c0/44907308549ce775a41c38a815f747009ac45929a45d642b836aa6b0a536e4978d30b8d7d680bbd116e9dd73b7dbe2ef0d1369dcfc2d09e83ba381e485ecbe12
languageName: node
linkType: hard
"abbrev@npm:^2.0.0":
version: 2.0.0
resolution: "abbrev@npm:2.0.0"
@ -230,6 +237,13 @@ __metadata:
languageName: node
linkType: hard
"boolbase@npm:^1.0.0":
version: 1.0.0
resolution: "boolbase@npm:1.0.0"
checksum: 10c0/e4b53deb4f2b85c52be0e21a273f2045c7b6a6ea002b0e139c744cb6f95e9ec044439a52883b0d74dedd1ff3da55ed140cfdddfed7fb0cccbed373de5dce1bcf
languageName: node
linkType: hard
"brace-expansion@npm:^2.0.1":
version: 2.0.1
resolution: "brace-expansion@npm:2.0.1"
@ -593,6 +607,55 @@ __metadata:
languageName: node
linkType: hard
"css-select@npm:^5.1.0":
version: 5.1.0
resolution: "css-select@npm:5.1.0"
dependencies:
boolbase: "npm:^1.0.0"
css-what: "npm:^6.1.0"
domhandler: "npm:^5.0.2"
domutils: "npm:^3.0.1"
nth-check: "npm:^2.0.1"
checksum: 10c0/551c60dba5b54054741032c1793b5734f6ba45e23ae9e82761a3c0ed1acbb8cfedfa443aaba3a3c1a54cac12b456d2012a09d2cd5f0e82e430454c1b9d84d500
languageName: node
linkType: hard
"css-tree@npm:^3.0.0":
version: 3.0.0
resolution: "css-tree@npm:3.0.0"
dependencies:
mdn-data: "npm:2.10.0"
source-map-js: "npm:^1.0.1"
checksum: 10c0/43d44fdf7004ae91d73d486f17894fef77efa33747a6752b9241cf0f5fb47fabc16ec34a96a993651d9014dfdeee803d7c5fcd3548214252ee19f4e5c98999b2
languageName: node
linkType: hard
"css-tree@npm:~2.2.0":
version: 2.2.1
resolution: "css-tree@npm:2.2.1"
dependencies:
mdn-data: "npm:2.0.28"
source-map-js: "npm:^1.0.1"
checksum: 10c0/47e87b0f02f8ac22f57eceb65c58011dd142d2158128882a0bf963cf2eabb81a4ebbc2e3790c8289be7919fa8b83750c7b69272bd66772c708143b772ba3c186
languageName: node
linkType: hard
"css-what@npm:^6.1.0":
version: 6.1.0
resolution: "css-what@npm:6.1.0"
checksum: 10c0/a09f5a6b14ba8dcf57ae9a59474722e80f20406c53a61e9aedb0eedc693b135113ffe2983f4efc4b5065ae639442e9ae88df24941ef159c218b231011d733746
languageName: node
linkType: hard
"csso@npm:^5.0.5":
version: 5.0.5
resolution: "csso@npm:5.0.5"
dependencies:
css-tree: "npm:~2.2.0"
checksum: 10c0/ab4beb1e97dd7e207c10e9925405b45f15a6cd1b4880a8686ad573aa6d476aed28b4121a666cffd26c37a26179f7b54741f7c257543003bfb244d06a62ad569b
languageName: node
linkType: hard
"debug@npm:4, debug@npm:^4.3.4":
version: 4.3.4
resolution: "debug@npm:4.3.4"
@ -662,6 +725,17 @@ __metadata:
languageName: node
linkType: hard
"dom-serializer@npm:^2.0.0":
version: 2.0.0
resolution: "dom-serializer@npm:2.0.0"
dependencies:
domelementtype: "npm:^2.3.0"
domhandler: "npm:^5.0.2"
entities: "npm:^4.2.0"
checksum: 10c0/d5ae2b7110ca3746b3643d3ef60ef823f5f078667baf530cec096433f1627ec4b6fa8c072f09d079d7cda915fd2c7bc1b7b935681e9b09e591e1e15f4040b8e2
languageName: node
linkType: hard
"domain-browser@npm:^1.1.1":
version: 1.2.0
resolution: "domain-browser@npm:1.2.0"
@ -669,6 +743,33 @@ __metadata:
languageName: node
linkType: hard
"domelementtype@npm:^2.3.0":
version: 2.3.0
resolution: "domelementtype@npm:2.3.0"
checksum: 10c0/686f5a9ef0fff078c1412c05db73a0dce096190036f33e400a07e2a4518e9f56b1e324f5c576a0a747ef0e75b5d985c040b0d51945ce780c0dd3c625a18cd8c9
languageName: node
linkType: hard
"domhandler@npm:^5.0.2, domhandler@npm:^5.0.3":
version: 5.0.3
resolution: "domhandler@npm:5.0.3"
dependencies:
domelementtype: "npm:^2.3.0"
checksum: 10c0/bba1e5932b3e196ad6862286d76adc89a0dbf0c773e5ced1eb01f9af930c50093a084eff14b8de5ea60b895c56a04d5de8bbc4930c5543d029091916770b2d2a
languageName: node
linkType: hard
"domutils@npm:^3.0.1":
version: 3.1.0
resolution: "domutils@npm:3.1.0"
dependencies:
dom-serializer: "npm:^2.0.0"
domelementtype: "npm:^2.3.0"
domhandler: "npm:^5.0.3"
checksum: 10c0/342d64cf4d07b8a0573fb51e0a6312a88fb520c7fefd751870bf72fa5fc0f2e0cb9a3958a573610b1d608c6e2a69b8e9b4b40f0bfb8f87a71bce4f180cca1887
languageName: node
linkType: hard
"eastasianwidth@npm:^0.2.0":
version: 0.2.0
resolution: "eastasianwidth@npm:0.2.0"
@ -714,6 +815,13 @@ __metadata:
languageName: node
linkType: hard
"entities@npm:^4.2.0":
version: 4.5.0
resolution: "entities@npm:4.5.0"
checksum: 10c0/5b039739f7621f5d1ad996715e53d964035f75ad3b9a4d38c6b3804bb226e282ffeae2443624d8fdd9c47d8e926ae9ac009c54671243f0c3294c26af7cc85250
languageName: node
linkType: hard
"env-paths@npm:^2.2.0":
version: 2.2.1
resolution: "env-paths@npm:2.2.1"
@ -785,11 +893,12 @@ __metadata:
generic-pool: "npm:^3.9.0"
inflation: "npm:^2.1.0"
ioredis: "npm:^5.4.1"
luxon: "npm:^3.4.4"
playwright: "npm:^1.44.1"
raw-body: "npm:^2.5.2"
shadow-cljs: "npm:2.28.11"
luxon: "npm:^3.5.0"
playwright: "npm:^1.48.1"
raw-body: "npm:^3.0.0"
shadow-cljs: "npm:2.28.18"
source-map-support: "npm:^0.5.21"
svgo: "penpot/svgo#v3"
xml-js: "npm:^1.6.11"
xregexp: "npm:^5.1.1"
languageName: unknown
@ -1043,16 +1152,7 @@ __metadata:
languageName: node
linkType: hard
"iconv-lite@npm:0.4.24":
version: 0.4.24
resolution: "iconv-lite@npm:0.4.24"
dependencies:
safer-buffer: "npm:>= 2.1.2 < 3"
checksum: 10c0/c6886a24cc00f2a059767440ec1bc00d334a89f250db8e0f7feb4961c8727118457e27c495ba94d082e51d3baca378726cd110aaf7ded8b9bbfd6a44760cf1d4
languageName: node
linkType: hard
"iconv-lite@npm:^0.6.2":
"iconv-lite@npm:0.6.3, iconv-lite@npm:^0.6.2":
version: 0.6.3
resolution: "iconv-lite@npm:0.6.3"
dependencies:
@ -1224,7 +1324,7 @@ __metadata:
languageName: node
linkType: hard
"lodash@npm:^4.17.15":
"lodash@npm:^4.17.15, lodash@npm:^4.17.21":
version: 4.17.21
resolution: "lodash@npm:4.17.21"
checksum: 10c0/d8cbea072bb08655bb4c989da418994b073a608dffa608b09ac04b43a791b12aeae7cd7ad919aa4c925f33b48490b5cfe6c1f71d827956071dae2e7bb3a6b74c
@ -1238,10 +1338,10 @@ __metadata:
languageName: node
linkType: hard
"luxon@npm:^3.4.4":
version: 3.4.4
resolution: "luxon@npm:3.4.4"
checksum: 10c0/02e26a0b039c11fd5b75e1d734c8f0332c95510f6a514a9a0991023e43fb233884da02d7f966823ffb230632a733fc86d4a4b1e63c3fbe00058b8ee0f8c728af
"luxon@npm:^3.5.0":
version: 3.5.0
resolution: "luxon@npm:3.5.0"
checksum: 10c0/335789bba95077db831ef99894edadeb23023b3eb2137a1b56acd0d290082b691cf793143d69e30bc069ec95f0b49f36419f48e951c68014f19ffe12045e3494
languageName: node
linkType: hard
@ -1276,6 +1376,20 @@ __metadata:
languageName: node
linkType: hard
"mdn-data@npm:2.0.28":
version: 2.0.28
resolution: "mdn-data@npm:2.0.28"
checksum: 10c0/20000932bc4cd1cde9cba4e23f08cc4f816398af4c15ec81040ed25421d6bf07b5cf6b17095972577fb498988f40f4cb589e3169b9357bb436a12d8e07e5ea7b
languageName: node
linkType: hard
"mdn-data@npm:2.10.0":
version: 2.10.0
resolution: "mdn-data@npm:2.10.0"
checksum: 10c0/f6f1a6a6eb092bab250d06f6f6c7cb1733a77a17e7119aac829ad67d4322bbf6a30df3c6d88686e71942e66bd49274b2ddfede22a1d3df0d6c49a56fbd09eb7c
languageName: node
linkType: hard
"miller-rabin@npm:^4.0.0":
version: 4.0.1
resolution: "miller-rabin@npm:4.0.1"
@ -1503,6 +1617,15 @@ __metadata:
languageName: node
linkType: hard
"nth-check@npm:^2.0.1":
version: 2.1.1
resolution: "nth-check@npm:2.1.1"
dependencies:
boolbase: "npm:^1.0.0"
checksum: 10c0/5fee7ff309727763689cfad844d979aedd2204a817fbaaf0e1603794a7c20db28548d7b024692f953557df6ce4a0ee4ae46cd8ebd9b36cfb300b9226b567c479
languageName: node
linkType: hard
"object-inspect@npm:^1.13.1":
version: 1.13.1
resolution: "object-inspect@npm:1.13.1"
@ -1603,27 +1726,27 @@ __metadata:
languageName: node
linkType: hard
"playwright-core@npm:1.44.1":
version: 1.44.1
resolution: "playwright-core@npm:1.44.1"
"playwright-core@npm:1.48.1":
version: 1.48.1
resolution: "playwright-core@npm:1.48.1"
bin:
playwright-core: cli.js
checksum: 10c0/6ffa3a04822b3df86d7f47a97e4f20318c0c50868ba4311820e6626ecadaab1424fbd0a3d01f0b4228adc0c781115e44b801742a4970b88739f804d82f142d68
checksum: 10c0/2f75532b9b7dfa0e586f5660ac1d8ea729bbdbd28dd2c0711e7cfc1adfe5cf7448d7f15a018ec9851a8f50c0743c3990cb9df23064bed603627baeac4dce3915
languageName: node
linkType: hard
"playwright@npm:^1.44.1":
version: 1.44.1
resolution: "playwright@npm:1.44.1"
"playwright@npm:^1.48.1":
version: 1.48.1
resolution: "playwright@npm:1.48.1"
dependencies:
fsevents: "npm:2.3.2"
playwright-core: "npm:1.44.1"
playwright-core: "npm:1.48.1"
dependenciesMeta:
fsevents:
optional: true
bin:
playwright: cli.js
checksum: 10c0/de827d17746b18ae2ec67d510a640d8ceebf8ee8e3d8399bccffa83b76a967498ca377777e4e6a1daaef4b3c86cb2c44c7468de53d2d915acc61b3b89c032738
checksum: 10c0/96280ae656226e52015c0c69c4c19e9f594c19353a79012a19bd7b7175d7b409c1aed289a629df49ef897a57ccd24668ad15b86c283db10f76212a4db90a94ac
languageName: node
linkType: hard
@ -1728,15 +1851,15 @@ __metadata:
languageName: node
linkType: hard
"raw-body@npm:^2.5.2":
version: 2.5.2
resolution: "raw-body@npm:2.5.2"
"raw-body@npm:^3.0.0":
version: 3.0.0
resolution: "raw-body@npm:3.0.0"
dependencies:
bytes: "npm:3.1.2"
http-errors: "npm:2.0.0"
iconv-lite: "npm:0.4.24"
iconv-lite: "npm:0.6.3"
unpipe: "npm:1.0.0"
checksum: 10c0/b201c4b66049369a60e766318caff5cb3cc5a900efd89bdac431463822d976ad0670912c931fdbdcf5543207daf6f6833bca57aa116e1661d2ea91e12ca692c4
checksum: 10c0/f8daf4b724064a4811d118745a781ca0fb4676298b8adadfd6591155549cfea0a067523cf7dd3baeb1265fecc9ce5dfb2fc788c12c66b85202a336593ece0f87
languageName: node
linkType: hard
@ -1849,7 +1972,7 @@ __metadata:
languageName: node
linkType: hard
"safer-buffer@npm:>= 2.1.2 < 3, safer-buffer@npm:>= 2.1.2 < 3.0.0":
"safer-buffer@npm:>= 2.1.2 < 3.0.0":
version: 2.1.2
resolution: "safer-buffer@npm:2.1.2"
checksum: 10c0/7e3c8b2e88a1841c9671094bbaeebd94448111dd90a81a1f606f3f67708a6ec57763b3b47f06da09fc6054193e0e6709e77325415dc8422b04497a8070fa02d4
@ -1919,9 +2042,9 @@ __metadata:
languageName: node
linkType: hard
"shadow-cljs@npm:2.28.11":
version: 2.28.11
resolution: "shadow-cljs@npm:2.28.11"
"shadow-cljs@npm:2.28.18":
version: 2.28.18
resolution: "shadow-cljs@npm:2.28.18"
dependencies:
node-libs-browser: "npm:^2.2.1"
readline-sync: "npm:^1.4.7"
@ -1931,7 +2054,7 @@ __metadata:
ws: "npm:^7.4.6"
bin:
shadow-cljs: cli/runner.js
checksum: 10c0/c5c77d524ee8f44e4ae2ddc196af170d02405cc8731ea71f852c7b220fc1ba8aaf5cf33753fd8a7566c8749bb75d360f903dfb0d131bcdc6c2c33f44404bd6a3
checksum: 10c0/4732cd11a5722644a0a91ae5560a55f62432ae5317bd2d1fd5bf12af8354c81776f4fcfce5c477b43af1ac2ecd4a216887337e1b92cca37a1b8cb9c157a393c1
languageName: node
linkType: hard
@ -1998,6 +2121,13 @@ __metadata:
languageName: node
linkType: hard
"source-map-js@npm:^1.0.1":
version: 1.2.1
resolution: "source-map-js@npm:1.2.1"
checksum: 10c0/7bda1fc4c197e3c6ff17de1b8b2c20e60af81b63a52cb32ec5a5d67a20a7d42651e2cb34ebe93833c5a2a084377e17455854fee3e21e7925c64a51b6a52b0faf
languageName: node
linkType: hard
"source-map-support@npm:^0.4.15":
version: 0.4.18
resolution: "source-map-support@npm:0.4.18"
@ -2156,6 +2286,19 @@ __metadata:
languageName: node
linkType: hard
"svgo@penpot/svgo#v3":
version: 4.0.0
resolution: "svgo@https://github.com/penpot/svgo.git#commit=71c0db44c3c2665f2ffc0c4c5383acaebd5c524f"
dependencies:
"@trysound/sax": "npm:0.2.0"
css-select: "npm:^5.1.0"
css-tree: "npm:^3.0.0"
csso: "npm:^5.0.5"
lodash: "npm:^4.17.21"
checksum: 10c0/642c583372a610e484382cbf8a8fe28256dd354598d2e65ade2a3a63bf841b4d3dab4106f929f183ae3610007db2fc1413e82acc23793fe1a2e882bc923acc72
languageName: node
linkType: hard
"tar-stream@npm:^3.0.0":
version: 3.1.7
resolution: "tar-stream@npm:3.1.7"

View file

@ -3,7 +3,7 @@
{penpot/common
{:local/root "../common"}
org.clojure/clojure {:mvn/version "1.11.3"}
org.clojure/clojure {:mvn/version "1.12.0"}
binaryage/devtools {:mvn/version "RELEASE"}
metosin/reitit-core {:mvn/version "0.7.0"}
funcool/okulary {:mvn/version "2022.04.11-16"}
@ -42,7 +42,7 @@
:dev
{:extra-paths ["dev"]
:extra-deps
{thheller/shadow-cljs {:mvn/version "2.28.11"}
{thheller/shadow-cljs {:mvn/version "2.28.18"}
org.clojure/tools.namespace {:mvn/version "RELEASE"}
cider/cider-nrepl {:mvn/version "0.48.0"}}}

View file

@ -42,21 +42,20 @@
"watch:storybook:assets": "node ./scripts/watch-storybook.js"
},
"devDependencies": {
"@playwright/test": "1.44.1",
"@storybook/addon-essentials": "^8.2.2",
"@storybook/addon-themes": "^8.2.2",
"@storybook/blocks": "^8.2.2",
"@storybook/react": "^8.2.2",
"@storybook/react-vite": "^8.2.2",
"@types/node": "^20.11.20",
"autoprefixer": "^10.4.19",
"concurrently": "^8.2.2",
"@playwright/test": "1.48.1",
"@storybook/addon-essentials": "^8.3.6",
"@storybook/addon-themes": "^8.3.6",
"@storybook/blocks": "^8.3.6",
"@storybook/react": "^8.3.6",
"@storybook/react-vite": "^8.3.6",
"@types/node": "^22.7.7",
"autoprefixer": "^10.4.20",
"concurrently": "^9.0.1",
"draft-js": "git+https://github.com/penpot/draft-js.git#commit=4a99b2a6020b2af97f6dc5fa1b4275ec16b559a0",
"express": "^4.19.2",
"express": "^4.21.1",
"fancy-log": "^2.0.0",
"getopts": "^2.3.0",
"gettext-parser": "^8.0.0",
"gulp": "4.0.2",
"gulp-concat": "^2.6.1",
"gulp-gzip": "^1.4.2",
"gulp-mustache": "^5.0.0",
@ -65,54 +64,55 @@
"gulp-sass": "^5.1.0",
"gulp-sourcemaps": "^3.0.0",
"gulp-svg-sprite": "^2.0.3",
"jsdom": "^24.1.0",
"jsdom": "^25.0.1",
"map-stream": "0.0.7",
"marked": "^12.0.2",
"marked": "^14.1.3",
"mkdirp": "^3.0.1",
"mustache": "^4.2.0",
"nodemon": "^3.1.2",
"nodemon": "^3.1.7",
"npm-run-all": "^4.1.5",
"p-limit": "^5.0.0",
"postcss": "^8.4.38",
"p-limit": "^6.1.0",
"postcss": "^8.4.47",
"postcss-clean": "^1.2.2",
"prettier": "3.3.2",
"prettier": "3.3.3",
"pretty-time": "^1.1.0",
"prop-types": "^15.8.1",
"rimraf": "^5.0.7",
"sass": "^1.77.4",
"sass-embedded": "^1.77.2",
"shadow-cljs": "2.28.11",
"storybook": "^8.2.2",
"rimraf": "^6.0.1",
"sass": "^1.80.3",
"sass-embedded": "^1.80.3",
"shadow-cljs": "2.28.18",
"storybook": "^8.3.6",
"svg-sprite": "^2.0.4",
"typescript": "^5.4.5",
"vite": "^5.1.4",
"vitest": "^1.3.1",
"typescript": "^5.6.3",
"vite": "^5.4.9",
"vitest": "^2.1.3",
"wasm-pack": "^0.13.0",
"watcher": "^2.3.1",
"workerpool": "^9.1.1"
"workerpool": "^9.2.0"
},
"dependencies": {
"compression": "^1.7.4",
"date-fns": "^3.6.0",
"eventsource-parser": "^1.1.2",
"highlight.js": "^11.9.0",
"date-fns": "^4.1.0",
"eventsource-parser": "^3.0.0",
"highlight.js": "^11.10.0",
"js-beautify": "^1.15.1",
"jszip": "^3.10.1",
"lodash": "^4.17.21",
"luxon": "^3.4.4",
"luxon": "^3.5.0",
"mousetrap": "^1.6.5",
"opentype.js": "^1.3.4",
"postcss-modules": "^6.0.0",
"randomcolor": "^0.6.2",
"react": "18.3.1",
"react-dom": "18.3.1",
"react-error-boundary": "^4.0.13",
"react-error-boundary": "^4.1.2",
"react-virtualized": "^9.22.5",
"rxjs": "8.0.0-alpha.14",
"sax": "^1.4.1",
"source-map-support": "^0.5.21",
"svgo": "penpot/svgo#v3",
"tdigest": "^0.1.2",
"ua-parser-js": "^1.0.38",
"ua-parser-js": "^1.0.39",
"xregexp": "^5.1.1"
}
}

View file

@ -4,7 +4,15 @@
//
// Copyright (c) KALEIDOS INC
@mixin font-face($style-name, $file, $unicode-range, $weight: unquote("normal"), $style: unquote("normal")) {
@use "sass:string";
@mixin font-face(
$style-name,
$file,
$unicode-range,
$weight: unquote("normal"),
$style: string.unquote("normal")
) {
$filepath: "/fonts/" + $file;
@font-face {
@ -12,8 +20,8 @@
src:
url($filepath + ".woff2") format("woff2"),
url($filepath + ".ttf") format("truetype");
font-weight: unquote($weight);
font-style: unquote($style);
font-weight: string.unquote($weight);
font-style: string.unquote($style);
@if $unicode-range {
unicode-range: $unicode-range;
}

View file

@ -26,6 +26,7 @@ async function compileFile(path) {
"resources/styles",
],
sourceMap: false,
silenceDeprecations: ["import", "mixed-decls"],
});
// console.dir(result);
resolve({

View file

@ -6,6 +6,7 @@
(ns app.main.data.workspace.media
(:require
["svgo" :as svgo]
[app.common.data :as d]
[app.common.data.macros :as dm]
[app.common.exceptions :as ex]
@ -14,7 +15,6 @@
[app.common.logging :as log]
[app.common.math :as mth]
[app.common.schema :as sm]
[app.common.svg :refer [optimize]]
[app.common.svg.shapes-builder :as csvg.shapes-builder]
[app.common.types.container :as ctn]
[app.common.types.shape :as cts]
@ -37,15 +37,15 @@
[promesa.core :as p]
[tubax.core :as tubax]))
(def ^:private svgo-config
{:multipass false
:plugins ["safeAndFastPreset"]})
(defn- optimize
[input]
(svgo/optimize input svgo/defaultOptions))
(defn svg->clj
[[name text]]
(try
(let [text (if (contains? cf/flags :frontend-svgo)
(optimize text svgo-config)
(optimize text)
text)
data (-> (tubax/xml->clj text)
(assoc :name name))]

File diff suppressed because it is too large Load diff