diff --git a/exporter/deps.edn b/exporter/deps.edn index 6a113eeba..ccfc4c407 100644 --- a/exporter/deps.edn +++ b/exporter/deps.edn @@ -2,7 +2,7 @@ :deps {penpot/common {:local/root "../common"} binaryage/devtools {:mvn/version "RELEASE"} - metosin/reitit-core {:mvn/version "0.5.15"} + metosin/reitit-core {:mvn/version "0.5.16"} funcool/beicon {:mvn/version "2021.07.05-1"} } :aliases @@ -14,7 +14,7 @@ :dev {:extra-deps - {thheller/shadow-cljs {:mvn/version "2.17.3"}}} + {thheller/shadow-cljs {:mvn/version "2.17.8"}}} :shadow-cljs {:main-opts ["-m" "shadow.cljs.devtools.cli"]} diff --git a/exporter/package.json b/exporter/package.json index 81ef6612a..6c3dfd5a7 100644 --- a/exporter/package.json +++ b/exporter/package.json @@ -9,20 +9,19 @@ "author": "UXBOX LABS SL", "license": "SEE LICENSE IN <LICENSE>", "dependencies": { - "@sentry/node": "^6.16.1", - "@sentry/tracing": "^6.16.1", + "archiver": "^5.3.0", "cookies": "^0.8.0", "generic-pool": "^3.8.2", "inflation": "^2.0.0", - "jszip": "^3.7.0", - "luxon": "^2.3.0", - "puppeteer-core": "^13.1.1", - "raw-body": "^2.4.2", + "ioredis": "^4.28.5", + "luxon": "^2.3.1", + "playwright": "^1.19.2", + "raw-body": "^2.5.1", "xml-js": "^1.6.11", "xregexp": "^5.0.2" }, "devDependencies": { - "shadow-cljs": "^2.17.3", + "shadow-cljs": "^2.17.8", "source-map-support": "^0.5.21" } } diff --git a/exporter/src/app/browser.cljs b/exporter/src/app/browser.cljs index b16ad95cf..e12e6e79c 100644 --- a/exporter/src/app/browser.cljs +++ b/exporter/src/app/browser.cljs @@ -7,7 +7,7 @@ (ns app.browser (:require ["generic-pool" :as gp] - ["puppeteer-core" :as pp] + ["playwright" :as pw] [app.common.data :as d] [app.common.logging :as l] [app.common.uuid :as uuid] @@ -20,78 +20,72 @@ ;; --- BROWSER API (def default-timeout 30000) -(def default-viewport {:width 1920 :height 1080 :scale 1}) +(def default-viewport-width 1920) +(def default-viewport-height 1080) (def default-user-agent (str "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 " - "(KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36")) + "(KHTML, like Gecko) Chrome/99.0.3729.169 Safari/537.36")) -(defn set-cookie! - [page {:keys [key value domain]}] - (.setCookie ^js page #js {:name key - :value value - :domain domain})) +(defn create-cookies + [uri {:keys [name token] :or {name "auth-token"}}] + (let [domain (str (:host uri) + (when (:port uri) + (str ":" (:port uri))))] + #js [#js {:domain domain + :path "/" + :name name + :value token}])) -(defn configure-page! - [page {:keys [timeout cookie user-agent viewport]}] - (let [timeout (or timeout default-timeout) - user-agent (or user-agent default-user-agent) - viewport (merge default-viewport viewport)] - - (p/do! - (.setViewport ^js page #js {:width (:width viewport) - :height (:height viewport) - :deviceScaleFactor (:scale viewport)}) - (.setUserAgent ^js page user-agent) - (.setDefaultTimeout ^js page timeout) - (when cookie - (set-cookie! page cookie))))) - -(defn navigate! - ([page url] (navigate! page url nil)) - ([page url {:keys [wait-until] - :or {wait-until "networkidle2"}}] - (.goto ^js page url #js {:waitUntil wait-until}))) +(defn nav! + ([page url] (nav! page url nil)) + ([page url {:keys [wait-until timeout] :or {wait-until "networkidle" timeout 20000}}] + (.goto ^js page (str url) #js {:waitUntil wait-until :timeout timeout}))) (defn sleep [page ms] (.waitForTimeout ^js page ms)) (defn wait-for - ([page selector] (wait-for page selector nil)) - ([page selector {:keys [visible timeout] :or {visible false timeout 10000}}] - (.waitForSelector ^js page selector #js {:visible visible}))) + ([locator] (wait-for locator nil)) + ([locator {:keys [state timeout] :or {state "visible" timeout 10000}}] + (.waitFor ^js locator #js {:state state :timeout timeout}))) (defn screenshot - ([frame] (screenshot frame nil)) - ([frame {:keys [full-page? omit-background? type] - :or {type "png" - full-page? false - omit-background? false}}] + ([frame] (screenshot frame {})) + ([frame {:keys [full-page? omit-background? type quality] + :or {type "png" full-page? false omit-background? false quality 95}}] (let [options (-> (obj/new) (obj/set! "type" (name type)) (obj/set! "omitBackground" omit-background?) - (cond-> full-page? (-> (obj/set! "fullPage" true) - (obj/set! "clip" nil))))] + (cond-> (= "jpeg" type) (obj/set! "quality" quality)) + (cond-> full-page? (-> (obj/set! "fullPage" true) + (obj/set! "clip" nil))))] (.screenshot ^js frame options)))) +(defn emulate-media! + [page {:keys [media]}] + (.emulateMedia ^js page #js {:media media}) + page) + (defn pdf - ([page] (pdf page nil)) - ([page {:keys [viewport save-path]}] - (p/let [viewport (d/merge default-viewport viewport)] - (.emulateMediaType ^js page "screen") - (.pdf ^js page #js {:path save-path - :width (:width viewport) - :height (:height viewport) - :scale (:scale viewport) - :printBackground true - :preferCSSPageSize true})))) + ([page] (pdf page {})) + ([page {:keys [width height scale save-path] + :or {width default-viewport-width + height default-viewport-height + scale 1}}] + (.pdf ^js page #js {:path save-path + :width width + :height height + :scale scale + :printBackground true + :preferCSSPageSize true}))) (defn eval! [frame f] (.evaluate ^js frame f)) (defn select [frame selector] - (.$ ^js frame selector)) + (.locator ^js frame selector)) (defn select-all [frame selector] @@ -103,23 +97,14 @@ (defonce pool (atom nil)) (defonce pool-browser-id (atom 1)) -(def default-chrome-args - #js ["--no-sandbox" - "--font-render-hinting=none" - "--disable-setuid-sandbox" - "--disable-accelerated-2d-canvas" - "--disable-gpu"]) - (def browser-pool-factory (letfn [(create [] - (let [path (cf/get :browser-executable-path "/usr/bin/google-chrome")] - (-> (pp/launch #js {:executablePath path :args default-chrome-args}) - (p/then (fn [browser] - (let [id (deref pool-browser-id)] - (l/info :origin "factory" :action "create" :browser-id id) - (unchecked-set browser "__id" id) - (swap! pool-browser-id inc) - browser)))))) + (p/let [browser (.launch pw/chromium) + id (swap! pool-browser-id inc)] + (l/info :origin "factory" :action "create" :browser-id id) + (unchecked-set browser "__id" id) + browser)) + (destroy [obj] (let [id (unchecked-get obj "__id")] (l/info :origin "factory" :action "destroy" :browser-id id) @@ -137,14 +122,13 @@ (defn init [] (l/info :msg "initializing browser pool") - (let [opts #js {:max (cf/get :browser-pool-max 3) - :min (cf/get :browser-pool-min 0) + (let [opts #js {:max (cf/get :exporter-browser-pool-max 5) + :min (cf/get :exporter-browser-pool-min 0) :testOnBorrow true :evictionRunIntervalMillis 5000 :numTestsPerEvictionRun 5 :acquireTimeoutMillis 120000 ; 2min :idleTimeoutMillis 10000}] - (reset! pool (gp/createPool browser-pool-factory opts)) (p/resolved nil))) @@ -152,73 +136,40 @@ [] (when-let [pool (deref pool)] (l/info :msg "finalizing browser pool") - (-> (.drain ^js pool) - (p/then (fn [] (.clear ^js pool)))))) + (p/do! + (.drain ^js pool) + (.clear ^js pool)))) + +(defn- ex-ignore + [p] + (p/handle p (constantly nil))) (defn exec! - [callback] - (letfn [(release-browser [pool browser] - (let [id (unchecked-get browser "__id")] - (-> (p/do! (.release ^js pool browser)) - (p/handle (fn [res err] - (l/trace :action "exec:release-browser" :browser-id id) - (when err (js/console.log err)) - (if err - (p/rejected err) - (p/resolved res))))))) + [config handle] + (letfn [(handle-browser [browser] + (p/let [id (unchecked-get browser "__id") + context (.newContext ^js browser config)] + (l/trace :hint "exec:handle:start" :browser-id id) + (p/let [page (.newPage ^js context) + result (handle page)] + (.close ^js context) + (l/trace :hint "exec:handle:end" :browser-id id) + result))) - (destroy-browser [pool browser] - (let [id (unchecked-get browser "__id")] - (-> (p/do! (.destroy ^js pool browser)) - (p/handle (fn [res err] - (l/trace :action "exec:destroy-browser" :browser-id id) - (when err (js/console.log err)) - (if err - (p/rejected err) - (p/resolved res))))))) - - (handle-error [pool browser obj err] - (let [id (unchecked-get browser "__id")] - (if err - (do - (l/trace :action "exec:handle-error" :browser-id id) - (-> (p/do! (destroy-browser pool browser)) - (p/handle #(p/rejected err)))) - (p/resolved obj)))) - - (on-result [pool browser context result] - (let [id (unchecked-get browser "__id")] - (l/trace :action "exec:on-result" :browser-id id) - (-> (p/do! (.close ^js context)) - (p/handle (fn [_ err] - (if err - (destroy-browser pool browser) - (release-browser pool browser)))) - (p/handle #(p/resolved result))))) - - (on-page [pool browser context page] - (let [id (unchecked-get browser "__id")] - (l/trace :action "exec:on-page" :browser-id id) - (-> (p/do! (callback page)) - (p/handle (partial handle-error pool browser)) - (p/then (partial on-result pool browser context))))) - - (on-context [pool browser ctx] - (let [id (unchecked-get browser "__id")] - (l/trace :action "exec:on-context" :browser-id id) - (-> (p/do! (.newPage ^js ctx)) - (p/handle (partial handle-error pool browser)) - (p/then (partial on-page pool browser ctx))))) - - (on-acquire [pool browser err] - (let [id (unchecked-get browser "__id")] - (l/trace :action "exec:on-acquire" :browser-id id) - (if err - (js/console.log err) - (-> (p/do! (.createIncognitoBrowserContext ^js browser)) - (p/handle (partial handle-error pool browser)) - (p/then (partial on-context pool browser))))))] + (on-acquire [pool browser] + (-> (handle-browser browser) + (p/then (fn [result] + (.release ^js pool browser) + result)) + (p/catch (fn [cause] + (p/do! + (ex-ignore (.destroy ^js pool browser)) + (p/rejected cause)))))) + ] (when-let [pool (deref pool)] (-> (p/do! (.acquire ^js pool)) - (p/handle (partial on-acquire pool)))))) + (p/then (partial on-acquire pool)) + (p/catch (fn [cause] + (js/console.log "KKK" cause) + (p/rejected cause))))))) diff --git a/exporter/src/app/config.cljs b/exporter/src/app/config.cljs index f1abb6352..cb59fb6ab 100644 --- a/exporter/src/app/config.cljs +++ b/exporter/src/app/config.cljs @@ -13,38 +13,41 @@ [app.common.data :as d] [app.common.spec :as us] [app.common.version :as v] + [app.common.uri :as u] [cljs.core :as c] [cljs.pprint] [cljs.spec.alpha :as s] - [cuerdas.core :as str] - [lambdaisland.uri :as u])) + [cuerdas.core :as str])) (def defaults {:public-uri "http://localhost:3449" :tenant "dev" :host "devenv" :http-server-port 6061 - :browser-concurrency 5 - :browser-strategy :incognito}) + :http-server-host "localhost" + :redis-uri "redis://redis/0" + :exporter-domain-whitelist #{"localhost2:3449"}}) -(s/def ::browser-concurrency ::us/integer) -(s/def ::browser-executable-path ::us/string) -(s/def ::browser-strategy ::us/keyword) (s/def ::http-server-port ::us/integer) -(s/def ::public-uri ::us/string) -(s/def ::sentry-dsn ::us/string) +(s/def ::http-server-host ::us/string) +(s/def ::public-uri ::us/uri) (s/def ::tenant ::us/string) (s/def ::host ::us/string) +(s/def ::exporter-domain-whitelist ::us/set-of-str) +(s/def ::exporter-browser-pool-max ::us/integer) +(s/def ::exporter-browser-pool-min ::us/integer) + (s/def ::config (s/keys :opt-un [::public-uri - ::sentry-dsn ::host ::tenant ::http-server-port - ::browser-concurrency - ::browser-strategy - ::browser-executable-path])) + ::http-server-host + ::exporter-browser-pool-max + ::exporter-browser-pool-min + ::exporter-domain-whitelist])) + (defn- read-env [prefix] (let [env (unchecked-get process "env") @@ -62,10 +65,14 @@ (defn- prepare-config [] - (let [env (read-env "penpot") - env (d/without-nils env) - data (merge defaults env)] - (us/conform ::config data))) + (try + (let [env (read-env "penpot") + env (d/without-nils env) + data (merge defaults env)] + (us/conform ::config data)) + (catch :default cause + (js/console.log (us/pretty-explain (ex-data cause))) + (throw cause)))) (def config (atom (prepare-config))) diff --git a/exporter/src/app/core.cljs b/exporter/src/app/core.cljs index 1af7491f1..c3ebbd46a 100644 --- a/exporter/src/app/core.cljs +++ b/exporter/src/app/core.cljs @@ -6,24 +6,23 @@ (ns app.core (:require + ["process" :as proc] [app.browser :as bwr] + [app.redis :as redis] [app.common.logging :as l] [app.config] [app.http :as http] - [app.sentry :as sentry] [promesa.core :as p])) (enable-console-print!) (l/initialize!) -(sentry/init!) - -(defonce state (atom nil)) (defn start [& args] (l/info :msg "initializing") (p/do! (bwr/init) + (redis/init) (http/init))) (def main start) @@ -36,5 +35,9 @@ (l/info :msg "stoping") (p/do! (bwr/stop) + (redis/stop) (http/stop) (done))) + +(proc/on "uncaughtException" (fn [cause] + (js/console.error cause))) diff --git a/exporter/src/app/handlers.cljs b/exporter/src/app/handlers.cljs new file mode 100644 index 000000000..22e15bf1e --- /dev/null +++ b/exporter/src/app/handlers.cljs @@ -0,0 +1,98 @@ +;; 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) UXBOX Labs SL + +(ns app.handlers + (:require + [app.common.data.macros :as dm] + [app.common.exceptions :as ex] + [app.common.logging :as l] + [app.common.spec :as us] + [app.common.uri :as u] + [app.config :as cf] + [app.handlers.export-frames :as export-frames] + [app.handlers.export-shapes :as export-shapes] + [app.handlers.resources :as resources] + [app.util.transit :as t] + [clojure.spec.alpha :as s] + [cuerdas.core :as str] + [promesa.core :as p] + [reitit.core :as r])) + +(l/set-level! :info) + +(defn on-error + [error exchange] + (let [{:keys [type message code] :as data} (ex-data error)] + (cond + (or (= :validation type) + (= :assertion type)) + (let [explain (us/pretty-explain data) + data (-> data + (assoc :explain explain) + (dissoc ::s/problems ::s/value ::s/spec))] + (-> exchange + (assoc :response/status 400) + (assoc :response/body (t/encode data)) + (assoc :response/headers {"content-type" "application/transit+json"}))) + + (= :not-found type) + (-> exchange + (assoc :response/status 404) + (assoc :response/body (t/encode data)) + (assoc :response/headers {"content-type" "application/transit+json"})) + + (and (= :internal type) + (= :browser-not-ready code)) + (-> exchange + (assoc :response/status 503) + (assoc :response/body (t/encode data)) + (assoc :response/headers {"content-type" "application/transit+json"})) + + :else + (do + (l/error :msg "Unexpected error" :cause error) + (-> exchange + (assoc :response/status 500) + (assoc :response/body (t/encode data)) + (assoc :response/headers {"content-type" "application/transit+json"})))))) + +(defmulti command-spec :cmd) + +(s/def ::id ::us/string) +(s/def ::uri ::us/uri) +(s/def ::wait ::us/boolean) +(s/def ::cmd ::us/keyword) + +(defmethod command-spec :export-shapes [_] ::export-shapes/params) +(defmethod command-spec :export-frames [_] ::export-frames/params) +(defmethod command-spec :get-resource [_] (s/keys :req-un [::id])) + +(s/def ::params + (s/and (s/keys :req-un [::cmd] + :opt-un [::wait ::uri]) + (s/multi-spec command-spec :cmd))) + +(defn validate-uri! + [uri] + (let [white-list (cf/get :exporter-domain-whitelist #{}) + default (cf/get :public-uri)] + (when-not (or (contains? white-list (u/get-domain uri)) + (= (u/get-domain default) (u/get-domain uri))) + (ex/raise :type :validation + :code :domain-not-allowed + :hint "looks like the uri provided is not part of the white list")))) + +(defn handler + [{:keys [:request/params] :as exchange}] + (let [{:keys [cmd uri] :as params} (us/conform ::params params)] + (some-> uri validate-uri!) + (case cmd + :get-resource (resources/handler exchange) + :export-shapes (export-shapes/handler exchange params) + :export-frames (export-frames/handler exchange params) + (ex/raise :type :internal + :code :method-not-implemented + :hint (dm/fmt "method % not implemented" cmd))))) diff --git a/exporter/src/app/handlers/export_frames.cljs b/exporter/src/app/handlers/export_frames.cljs new file mode 100644 index 000000000..63440c3ac --- /dev/null +++ b/exporter/src/app/handlers/export_frames.cljs @@ -0,0 +1,152 @@ +;; 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) UXBOX Labs SL + +(ns app.handlers.export-frames + (:require + ["path" :as path] + [app.common.data.macros :as dm] + [app.common.exceptions :as exc :include-macros true] + [app.common.spec :as us] + [app.handlers.resources :as rsc] + [app.redis :as redis] + [app.renderer.pdf :as rp] + [app.util.shell :as sh] + [cljs.spec.alpha :as s] + [cuerdas.core :as str] + [promesa.core :as p])) + +(declare ^:private handle-export) +(declare ^:private create-pdf) +(declare ^:private export-frame) +(declare ^:private join-pdf) +(declare ^:private move-file) +(declare ^:private clean-tmp) + +(s/def ::name ::us/string) +(s/def ::file-id ::us/uuid) +(s/def ::page-id ::us/uuid) +(s/def ::frame-id ::us/uuid) +(s/def ::uri ::us/uri) + +(s/def ::export + (s/keys :req-un [::file-id ::page-id ::frame-id ::name])) + +(s/def ::exports + (s/every ::export :kind vector? :min-count 1)) + +(s/def ::params + (s/keys :req-un [::exports] + :opt-un [::uri ::name])) + +(defn handler + [{:keys [:request/auth-token] :as exchange} {:keys [exports uri] :as params}] + (let [xform (map #(assoc % :token auth-token :uri uri)) + exports (sequence xform exports)] + (handle-export exchange (assoc params :exports exports)))) + +(defn handle-export + [exchange {:keys [exports wait uri name] :as params}] + (let [topic (-> exports first :file-id str) + resource (rsc/create :pdf (or name (-> exports first :name))) + + on-progress (fn [progress] + (let [data {:type :export-update + :resource-id (:id resource) + :status "running" + :progress progress}] + (redis/pub! topic data))) + + on-complete (fn [resource] + (let [data {:type :export-update + :resource-id (:id resource) + :size (:size resource) + :status "ended"}] + (redis/pub! topic data))) + + on-error (fn [cause] + (let [data {:type :export-update + :resource-id (:id resource) + :status "error" + :cause (ex-message cause)}] + (redis/pub! topic data))) + + proc (create-pdf :resource resource + :items exports + :on-progress on-progress + :on-complete on-complete + :on-error on-error)] + (if wait + (p/then proc #(assoc exchange :response/body (dissoc % :path))) + (assoc exchange :response/body (dissoc resource :path))))) + +(defn create-pdf + [& {:keys [resource items on-progress on-complete on-error] + :or {on-progress identity + on-complete identity + on-error identity}}] + (p/let [progress (atom 0) + tmpdir (sh/create-tmpdir! "pdfexport") + file-id (-> items first :file-id) + items (into [] (map #(partial export-frame tmpdir %)) items) + xform (map (fn [export-fn] + #(p/finally + (export-fn) + (fn [result _] + (on-progress {:total (count items) + :done (swap! progress inc) + :name (:name result)})))))] + (-> (reduce (fn [res export-fn] + (p/let [res res + out (export-fn)] + (cons (:path out) res))) + (p/resolved nil) + (into '() xform items)) + (p/then (partial join-pdf tmpdir file-id)) + (p/then (partial move-file resource)) + (p/then (partial clean-tmp tmpdir)) + (p/then (fn [resource] + (-> (sh/stat (:path resource)) + (p/then #(merge resource %))))) + (p/finally (fn [result cause] + (if cause + (on-error cause) + (on-complete result))))))) + +(defn- export-frame + [tmpdir {:keys [file-id page-id frame-id token uri] :as params}] + (let [file-name (dm/fmt "%.pdf" frame-id) + save-path (path/join tmpdir file-name)] + (-> (rp/render {:name (dm/str frame-id) + :uri uri + :suffix "" + :token token + :file-id file-id + :page-id page-id + :object-id frame-id + :scale 1 + :save-path save-path}) + (p/then (fn [_] + {:name file-name + :path save-path}))))) + +(defn- join-pdf + [tmpdir file-id paths] + (let [output-path (path/join tmpdir (str file-id ".pdf")) + paths-str (str/join " " paths)] + (-> (sh/run-cmd! (str "pdfunite " paths-str " " output-path)) + (p/then (constantly output-path))))) + +(defn- move-file + [{:keys [path] :as resource} output-path] + (p/do + (sh/move! output-path path) + resource)) + +(defn- clean-tmp + [tdpath data] + (p/do! + (sh/rmdir! tdpath) + data)) diff --git a/exporter/src/app/handlers/export_shapes.cljs b/exporter/src/app/handlers/export_shapes.cljs new file mode 100644 index 000000000..d35a460a7 --- /dev/null +++ b/exporter/src/app/handlers/export_shapes.cljs @@ -0,0 +1,170 @@ +;; 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) UXBOX Labs SL + +(ns app.handlers.export-shapes + (:require + [app.common.exceptions :as exc :include-macros true] + [app.common.spec :as us] + [app.redis :as redis] + [app.handlers.resources :as rsc] + [app.renderer.bitmap :as rb] + [app.renderer.pdf :as rp] + [app.renderer.svg :as rs] + [cljs.spec.alpha :as s] + [cuerdas.core :as str] + [promesa.core :as p])) + +(declare ^:private handle-exports) +(declare ^:private handle-single-export) +(declare ^:private handle-multiple-export) +(declare ^:private run-export) +(declare ^:private assign-file-name) + +(s/def ::name ::us/string) +(s/def ::page-id ::us/uuid) +(s/def ::file-id ::us/uuid) +(s/def ::object-id ::us/uuid) +(s/def ::scale ::us/number) +(s/def ::suffix ::us/string) +(s/def ::type ::us/keyword) +(s/def ::suffix string?) +(s/def ::scale number?) +(s/def ::uri ::us/uri) +(s/def ::profile-id ::us/uuid) +(s/def ::wait ::us/boolean) + +(s/def ::export + (s/keys :req-un [::page-id ::file-id ::object-id ::type ::suffix ::scale ::name])) + +(s/def ::exports + (s/coll-of ::export :kind vector? :min-count 1)) + +(s/def ::params + (s/keys :req-un [::exports ::profile-id] + :opt-un [::uri ::wait ::name])) + +(defn handler + [{:keys [:request/auth-token] :as exchange} {:keys [exports] :as params}] + (let [xform (comp + (map #(assoc % :token auth-token)) + (assign-file-name)) + exports (into [] xform exports)] + (if (= 1 (count exports)) + (handle-single-export exchange (assoc params :export (first exports))) + (handle-multiple-export exchange (assoc params :exports exports))))) + +(defn- handle-single-export + [exchange {:keys [export wait uri profile-id name] :as params}] + (let [topic (str profile-id) + resource (rsc/create (:type export) (or name (:name export))) + + on-progress (fn [progress] + (let [data {:type :export-update + :resource-id (:id resource) + :status "running" + :progress progress}] + (redis/pub! topic data))) + + on-complete (fn [resource] + (let [data {:type :export-update + :resource-id (:id resource) + :size (:size resource) + :name (:name resource) + :status "ended"}] + (redis/pub! topic data))) + + on-error (fn [cause] + (let [data {:type :export-update + :resource-id (:id resource) + :name (:name resource) + :status "error" + :cause (ex-message cause)}] + (redis/pub! topic data))) + + proc (rsc/create-simple :task #(run-export export) + :resource resource + :on-progress on-progress + :on-error on-error + :on-complete on-complete)] + (if wait + (p/then proc #(assoc exchange :response/body (dissoc % :path))) + (assoc exchange :response/body (dissoc resource :path))))) + +(defn- handle-multiple-export + [exchange {:keys [exports wait uri profile-id name] :as params}] + (let [tasks (map #(fn [] (run-export %)) exports) + topic (str profile-id) + resource (rsc/create :zip (or name (-> exports first :name))) + + on-progress (fn [progress] + (let [data {:type :export-update + :resource-id (:id resource) + :name (:name resource) + :status "running" + :progress progress}] + (redis/pub! topic data))) + + on-complete (fn [resource] + (let [data {:type :export-update + :resource-id (:id resource) + :name (:name resource) + :size (:size resource) + :status "ended"}] + (redis/pub! topic data))) + + on-error (fn [cause] + (let [data {:type :export-update + :resource-id (:id resource) + :name (:name resource) + :status "error" + :cause (ex-message cause)}] + (redis/pub! topic data))) + + proc (rsc/create-zip :resource resource + :tasks tasks + :on-progress on-progress + :on-complete on-complete + :on-error on-error)] + (if wait + (p/then proc #(assoc exchange :response/body (dissoc % :path))) + (assoc exchange :response/body (dissoc resource :path))))) + +(defn- run-export + [{:keys [type] :as params}] + (p/let [res (case type + :png (rb/render params) + :jpeg (rb/render params) + :svg (rs/render params) + :pdf (rp/render params))] + (assoc res :type type))) + +(defn- assign-file-name + "A transducer that assocs a candidate filename and avoid duplicates." + [] + (letfn [(find-candidate [params used] + (loop [index 0] + (let [candidate (str (:name params) + (:suffix params "") + (when (pos? index) + (str "-" (inc index))) + (case (:type params) + :png ".png" + :jpeg ".jpg" + :svg ".svg" + :pdf ".pdf"))] + (if (contains? used candidate) + (recur (inc index)) + candidate))))] + (fn [rf] + (let [used (volatile! #{})] + (fn + ([] (rf)) + ([result] (rf result)) + ([result params] + (let [candidate (find-candidate params @used) + params (assoc params :filename candidate)] + (vswap! used conj candidate) + (rf result params)))))))) diff --git a/exporter/src/app/handlers/resources.cljs b/exporter/src/app/handlers/resources.cljs new file mode 100644 index 000000000..396c2cf65 --- /dev/null +++ b/exporter/src/app/handlers/resources.cljs @@ -0,0 +1,130 @@ +;; 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) UXBOX Labs SL + +(ns app.handlers.resources + "Temporal resouces management." + (:require + ["archiver" :as arc] + ["fs" :as fs] + ["os" :as os] + ["path" :as path] + [app.common.data :as d] + [app.common.data.macros :as dm] + [app.common.exceptions :as ex] + [app.common.uuid :as uuid] + [app.util.shell :as sh] + [cljs.core :as c] + [cuerdas.core :as str] + [promesa.core :as p])) + +(defn- get-path + [type id] + (path/join (os/tmpdir) (dm/str "exporter." (d/name type) "." id))) + +(defn- get-mtype + [type] + (case (d/name type) + "zip" "application/zip" + "jpeg" "image/jpeg" + "png" "image/png" + "pdf" "application/pdf")) + +(defn create + "Generates ephimeral resource object." + [type name] + (let [task-id (uuid/next)] + {:path (get-path type task-id) + :mtype (get-mtype type) + :name name + :id (dm/str (c/name type) "." task-id)})) + +(defn- write-as-zip! + [{:keys [id path]} items on-progress] + (let [^js zip (arc/create "zip") + ^js out (fs/createWriteStream path) + append! (fn [{:keys [data name] :as result}] + (.append zip data #js {:name name})) + progress (atom 0)] + (p/create + (fn [resolve reject] + (.on zip "error" #(reject %)) + (.on zip "end" resolve) + (.on zip "entry" (fn [data] + (let [name (unchecked-get data "name") + num (swap! progress inc)] + #_(when (= 2 num) + (.abort ^js zip) + (reject (js/Error. "unable to create zip file"))) + (on-progress + {:total (count items) + :done num})))) + (.pipe zip out) + (-> (reduce (fn [res export-fn] + (p/then res (fn [_] (-> (export-fn) (p/then append!))))) + (p/resolved 1) + items) + (p/then #(.finalize zip)) + (p/catch reject)))))) + +(defn create-simple + [& {:keys [task resource on-progress on-complete on-error] + :or {on-progress identity + on-complete identity + on-error identity} + :as params}] + (let [path (:path resource)] + (-> (task) + (p/then (fn [{:keys [data name]}] + (on-progress {:total 1 :done 1 :name name}) + (.writeFile fs/promises path data))) + (p/then #(sh/stat path)) + (p/then #(merge resource %)) + (p/finally (fn [result cause] + (if cause + (on-error cause) + (on-complete result))))))) + +(defn create-zip + "Creates a resource with multiple files merget into a single zip file." + [& {:keys [resource tasks on-error on-progress on-complete] + :or {on-error identity + on-progress identity + on-complete identity}}] + (let [{:keys [path id] :as resource} resource] + (-> (write-as-zip! resource tasks on-progress) + (p/then #(sh/stat path)) + (p/then #(merge resource %)) + (p/finally (fn [result cause] + (if cause + (on-error cause) + (on-complete result))))))) + +(defn- lookup + [id] + (p/let [[type task-id] (str/split id "." 2) + path (get-path type task-id) + mtype (get-mtype type) + stat (sh/stat path)] + + (when-not stat + (ex/raise :type :not-found)) + + {:stream (fs/createReadStream path) + :headers {"content-type" mtype + "content-length" (:size stat)}})) + +(defn handler + [{:keys [:request/params response] :as exchange}] + (when-not (contains? params :id) + (ex/raise :type :validation + :code :missing-id)) + + (-> (lookup (get params :id)) + (p/then (fn [{:keys [stream headers] :as resource}] + (-> exchange + (assoc :response/status 200) + (assoc :response/body stream) + (assoc :response/headers headers)))))) diff --git a/exporter/src/app/http.cljs b/exporter/src/app/http.cljs index 17e10a0bf..cb8156bfa 100644 --- a/exporter/src/app/http.cljs +++ b/exporter/src/app/http.cljs @@ -6,67 +6,162 @@ (ns app.http (:require + ["cookies" :as Cookies] + ["http" :as http] + ["inflation" :as inflate] + ["raw-body" :as raw-body] + ["stream" :as stream] [app.common.logging :as l] + [app.common.spec :as us] + [app.common.transit :as t] [app.config :as cf] - [app.http.export :refer [export-handler]] - [app.http.export-frames :refer [export-frames-handler]] - [app.http.impl :as impl] - [app.sentry :as sentry] - [app.util.transit :as t] + [app.handlers :as handlers] [cuerdas.core :as str] - [promesa.core :as p] - [reitit.core :as r])) + [lambdaisland.uri :as u] + [promesa.core :as p])) (l/set-level! :info) -(def routes - [["/export-frames" {:handler export-frames-handler}] - ["/export" {:handler export-handler}]]) +(defprotocol IStreamableResponseBody + (write-body! [_ response])) + +(extend-protocol IStreamableResponseBody + string + (write-body! [data response] + (.write ^js response data) + (.end ^js response)) + + js/Buffer + (write-body! [data response] + (.write ^js response data) + (.end ^js response)) + + stream/Stream + (write-body! [data response] + (.pipe ^js data response) + (.on ^js data "error" (fn [cause] + (js/console.error cause) + (.end response))))) + +(defn- handle-response + [{:keys [:response/body + :response/headers + :response/status + response] + :as exchange}] + (let [status (or status 200) + headers (clj->js headers) + body (or body "")] + (.writeHead ^js response status headers) + (write-body! body response))) + +(defn- parse-headers + [req] + (let [orig (unchecked-get req "headers")] + (persistent! + (reduce #(assoc! %1 (str/lower %2) (unchecked-get orig %2)) + (transient {}) + (js/Object.keys orig))))) + +(defn- wrap-body-params + [handler] + (let [opts #js {:limit "2mb" :encoding "utf8"}] + (fn [{:keys [:request/method :request/headers request] :as exchange}] + (let [ctype (get headers "content-type")] + (if (= method "post") + (-> (raw-body (inflate request) opts) + (p/then (fn [data] + (cond-> data + (= ctype "application/transit+json") + (t/decode-str)))) + (p/then (fn [data] + (handler (assoc exchange :request/body-params data))))) + (handler exchange)))))) + +(defn- wrap-params + [handler] + (fn [{:keys [:request/body-params :request/query-params] :as exchange}] + (handler (assoc exchange :request/params (merge query-params body-params))))) + +(defn- wrap-response-format + [handler] + (fn [exchange] + (p/then + (handler exchange) + (fn [{:keys [:response/body :response/status] :as exchange}] + (cond + (map? body) + (let [data (t/encode-str body {:type :json-verbose})] + (-> exchange + (assoc :response/body data) + (assoc :response/status 200) + (update :response/headers assoc "content-type" "application/transit+json") + (update :response/headers assoc "content-length" (count data)))) + + (and (nil? body) + (= 200 status)) + (-> exchange + (assoc :response/body "") + (assoc :response/status 204) + (assoc :response/headers {"content-length" 0})) + + :else + exchange))))) + +(defn- wrap-query-params + [handler] + (fn [{:keys [:request/uri] :as exchange}] + (handler (assoc exchange :request/query-params (u/query-string->map (:query uri)))))) + +(defn- wrap-error + [handler on-error] + (fn [exchange] + (-> (p/do (handler exchange)) + (p/catch (fn [cause] (on-error cause exchange)))))) + +(defn- wrap-auth + [handler cookie-name] + (fn [{:keys [:request/cookies] :as exchange}] + (let [token (.get ^js cookies cookie-name)] + (handler (cond-> exchange token (assoc :request/auth-token token)))))) + +(defn- create-adapter + [handler] + (fn [req res] + (let [cookies (Cookies. req res) + headers (parse-headers req) + uri (u/uri (unchecked-get req "url")) + exchange {:request/method (str/lower (unchecked-get req "method")) + :request/path (:path uri) + :request/uri uri + :request/headers headers + :request/cookies cookies + :request req + :response res}] + (-> (p/do (handler exchange)) + (p/then handle-response))))) + +(defn- create-server + [handler] + (.createServer ^js http (create-adapter handler))) (def instance (atom nil)) -(defn- on-error - [error request] - (let [{:keys [type message code] :as data} (ex-data error)] - (sentry/capture-exception error {::sentry/request request - :ex-data data}) - - (cond - (= :validation type) - (let [header (get-in request [:headers "accept"])] - (if (and (str/starts-with? header "text/html") - (= :spec-validation (:code data))) - {:status 400 - :headers {"content-type" "text/html"} - :body (str "<pre style='font-size:16px'>" (:explain data) "</pre>\n")} - {:status 400 - :headers {"content-type" "text/html"} - :body (str "<pre style='font-size:16px'>" (:explain data) "</pre>\n")})) - - (and (= :internal type) - (= :browser-not-ready code)) - {:status 503 - :headers {"x-error" (t/encode data)} - :body ""} - - :else - (do - (l/error :msg "Unexpected error" :error error) - (js/console.error error) - {:status 500 - :headers {"x-error" (t/encode data)} - :body ""})))) - (defn init [] - (let [router (r/router routes) - handler (impl/router-handler router) - server (impl/server handler on-error) + (let [handler (-> handlers/handler + (wrap-auth "auth-token") + (wrap-response-format) + (wrap-params) + (wrap-query-params) + (wrap-body-params) + (wrap-error handlers/on-error)) + server (create-server handler) port (cf/get :http-server-port 6061)] (.listen server port) (l/info :msg "welcome to penpot" - :module "exporter" - :version (:full @cf/version)) + :module "exporter" + :version (:full @cf/version)) (l/info :msg "starting http server" :port port) (reset! instance server))) diff --git a/exporter/src/app/http/export.cljs b/exporter/src/app/http/export.cljs deleted file mode 100644 index 493f53908..000000000 --- a/exporter/src/app/http/export.cljs +++ /dev/null @@ -1,125 +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) UXBOX Labs SL - -(ns app.http.export - (:require - [app.common.exceptions :as exc :include-macros true] - [app.common.spec :as us] - [app.renderer.bitmap :as rb] - [app.renderer.pdf :as rp] - [app.renderer.svg :as rs] - [app.zipfile :as zip] - [cljs.spec.alpha :as s] - [cuerdas.core :as str] - [promesa.core :as p])) - -(s/def ::name ::us/string) -(s/def ::page-id ::us/uuid) -(s/def ::file-id ::us/uuid) -(s/def ::object-id ::us/uuid) -(s/def ::scale ::us/number) -(s/def ::suffix ::us/string) -(s/def ::type ::us/keyword) -(s/def ::suffix string?) -(s/def ::scale number?) - -(s/def ::export (s/keys :req-un [::type ::suffix ::scale])) -(s/def ::exports (s/coll-of ::export :kind vector?)) - -(s/def ::handler-params - (s/keys :req-un [::page-id ::file-id ::object-id ::name ::exports])) - -(declare handle-single-export) -(declare handle-multiple-export) -(declare perform-export) -(declare attach-filename) - -(defn export-handler - [{:keys [params cookies] :as request}] - (let [{:keys [exports page-id file-id object-id name]} (us/conform ::handler-params params) - token (.get ^js cookies "auth-token")] - (case (count exports) - 0 (exc/raise :type :validation - :code :missing-exports) - - 1 (-> (first exports) - (assoc :name name) - (assoc :token token) - (assoc :file-id file-id) - (assoc :page-id page-id) - (assoc :object-id object-id) - (handle-single-export)) - - (->> exports - (map (fn [item] - (-> item - (assoc :name name) - (assoc :token token) - (assoc :file-id file-id) - (assoc :page-id page-id) - (assoc :object-id object-id)))) - (handle-multiple-export))))) - -(defn- handle-single-export - [params] - (p/let [result (perform-export params)] - {:status 200 - :body (:content result) - :headers {"content-type" (:mime-type result) - "content-length" (:length result)}})) - -(defn- handle-multiple-export - [exports] - (let [proms (->> exports - (attach-filename) - (map perform-export))] - (-> (p/all proms) - (p/then (fn [results] - (reduce #(zip/add! %1 (:filename %2) (:content %2)) (zip/create) results))) - (p/then (fn [fzip] - (.generateAsync ^js fzip #js {:type "uint8array"}))) - (p/then (fn [data] - {:status 200 - :headers {"content-type" "application/zip"} - :body data}))))) - -(defn- perform-export - [params] - (case (:type params) - :png (rb/render params) - :jpeg (rb/render params) - :svg (rs/render params) - :pdf (rp/render params))) - -(defn- find-filename-candidate - [params used] - (loop [index 0] - (let [candidate (str (:name params) - (:suffix params "") - (when (pos? index) - (str "-" (inc index))) - (case (:type params) - :png ".png" - :jpeg ".jpg" - :svg ".svg" - :pdf ".pdf"))] - (if (contains? used candidate) - (recur (inc index)) - candidate)))) - -(defn- attach-filename - [exports] - (loop [exports (seq exports) - used #{} - result []] - (if (nil? exports) - result - (let [export (first exports) - candidate (find-filename-candidate export used) - export (assoc export :filename candidate)] - (recur (next exports) - (conj used candidate) - (conj result export)))))) diff --git a/exporter/src/app/http/export_frames.cljs b/exporter/src/app/http/export_frames.cljs deleted file mode 100644 index 073caf0f3..000000000 --- a/exporter/src/app/http/export_frames.cljs +++ /dev/null @@ -1,73 +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) UXBOX Labs SL - -(ns app.http.export-frames - (:require - ["path" :as path] - [app.common.exceptions :as exc :include-macros true] - [app.common.spec :as us] - [app.renderer.pdf :as rp] - [app.util.shell :as sh] - [cljs.spec.alpha :as s] - [cuerdas.core :as str] - [promesa.core :as p])) - -(s/def ::name ::us/string) -(s/def ::file-id ::us/uuid) -(s/def ::page-id ::us/uuid) -(s/def ::frame-id ::us/uuid) -(s/def ::frame-ids (s/coll-of ::frame-id :kind vector?)) - -(s/def ::handler-params - (s/keys :req-un [::file-id ::page-id ::frame-ids])) - -(defn- export-frame - [tdpath file-id page-id token frame-id spaths] - (p/let [spath (path/join tdpath (str frame-id ".pdf")) - result (rp/render {:name (str frame-id) - :suffix "" - :token token - :file-id file-id - :page-id page-id - :object-id frame-id - :scale 1 - :save-path spath})] - (conj spaths spath))) - -(defn- join-files - [tdpath file-id paths] - (let [output-path (path/join tdpath (str file-id ".pdf")) - paths-str (str/join " " paths)] - (-> (sh/run-cmd! (str "pdfunite " paths-str " " output-path)) - (p/then (constantly output-path))))) - -(defn- clean-tmp-data - [tdpath data] - (p/do! - (sh/rmdir! tdpath) - data)) - -(defn export-frames-handler - [{:keys [params cookies] :as request}] - (let [{:keys [name file-id page-id frame-ids]} (us/conform ::handler-params params) - token (.get ^js cookies "auth-token")] - (if (seq frame-ids) - (p/let [tdpath (sh/create-tmpdir! "pdfexport-") - data (-> (reduce (fn [promise frame-id] - (p/then promise (partial export-frame tdpath file-id page-id token frame-id))) - (p/future []) - (reverse frame-ids)) - (p/then (partial join-files tdpath file-id)) - (p/then sh/read-file) - (p/then (partial clean-tmp-data tdpath)))] - {:status 200 - :body data - :headers {"content-type" "application/pdf" - "content-length" (.-length data)}}) - {:status 204 - :body "" - :headers {"content-type" "text/plain"}}))) - diff --git a/exporter/src/app/http/impl.cljs b/exporter/src/app/http/impl.cljs deleted file mode 100644 index b98e7d29f..000000000 --- a/exporter/src/app/http/impl.cljs +++ /dev/null @@ -1,95 +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) UXBOX Labs SL - -(ns app.http.impl - (:require - ["http" :as http] - ["cookies" :as Cookies] - ["inflation" :as inflate] - ["raw-body" :as raw-body] - [app.util.transit :as t] - [cuerdas.core :as str] - [lambdaisland.uri :as u] - [promesa.core :as p] - [reitit.core :as r])) - -(def methods-with-body - #{"POST" "PUT" "DELETE"}) - -(defn- match - [router {:keys [path query] :as request}] - (when-let [match (r/match-by-path router path)] - (assoc match :query-params (u/query-string->map query)))) - -(defn- handle-response - [req res] - (fn [{:keys [body headers status] :or {headers {} status 200}}] - (.writeHead ^js res status (clj->js headers)) - (.end ^js res body))) - -(defn- parse-headers - [req] - (let [orig (unchecked-get req "headers")] - (persistent! - (reduce #(assoc! %1 %2 (unchecked-get orig %2)) - (transient {}) - (js/Object.keys orig))))) - -(defn- parse-body - [req] - (let [headers (unchecked-get req "headers") - method (unchecked-get req "method") - ctype (unchecked-get headers "content-type") - opts #js {:limit "5mb" :encoding "utf8"}] - (when (contains? methods-with-body method) - (-> (raw-body (inflate req) opts) - (p/then (fn [data] - (cond-> data - (= ctype "application/transit+json") - (t/decode)))))))) - -(defn- handler-adapter - [handler on-error] - (fn [req res] - (let [cookies (new Cookies req res) - headers (parse-headers req) - uri (u/uri (unchecked-get req "url")) - request {:method (str/lower (unchecked-get req "method")) - :path (:path uri) - :query (:query uri) - :url uri - :headers headers - :cookies cookies - :internal-request req - :internal-response res}] - (-> (parse-body req) - (p/then (fn [body] - (let [request (assoc request :body body)] - (handler request)))) - (p/catch (fn [error] (on-error error request))) - (p/then (handle-response req res)))))) - -(defn router-handler - [router] - (fn [{:keys [body] :as request}] - (let [route (match router request) - params (merge {} - (:query-params route) - (:path-params route) - (when (map? body) body)) - request (assoc request - :route route - :params params) - - handler (get-in route [:data :handler])] - (if (and route handler) - (handler request) - {:status 404 - :body "Not found"})))) - -(defn server - [handler on-error] - (.createServer ^js http (handler-adapter handler on-error))) diff --git a/exporter/src/app/redis.cljs b/exporter/src/app/redis.cljs new file mode 100644 index 000000000..5d704bc86 --- /dev/null +++ b/exporter/src/app/redis.cljs @@ -0,0 +1,54 @@ +;; 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) UXBOX Labs SL + +(ns app.redis + (:require + ["ioredis" :as redis] + [app.common.data.macros :as dm] + [app.common.logging :as l] + [app.common.transit :as t] + [app.config :as cf])) + +(l/set-level! :trace) + +(def client (atom nil)) + +(defn- create-client + [uri] + (let [^js client (new redis uri)] + (.on client "connect" + (fn [] (l/info :hint "redis connection established" :uri uri))) + (.on client "error" + (fn [cause] (l/error :hint "error on redis connection" :cause cause))) + (.on client "close" + (fn [] (l/warn :hint "connection closed"))) + (.on client "reconnect" + (fn [ms] (l/warn :hint "reconnecting to redis" :ms ms))) + (.on client "end" + (fn [ms] (l/warn :hint "client ended, no more connections will be attempted"))) + client)) + +(defn init + [] + (swap! client (fn [prev] + (when prev (.disconnect ^js prev)) + (create-client (cf/get :redis-uri))))) + + +(defn stop + [] + (swap! client (fn [client] + (when client (.quit ^js client)) + nil))) + +(def ^:private tenant (cf/get :tenant)) + +(defn pub! + [topic payload] + (let [payload (if (map? payload) (t/encode-str payload) payload) + topic (dm/str tenant "." topic)] + (when-let [client @client] + (.publish ^js client topic payload)))) diff --git a/exporter/src/app/renderer/bitmap.cljs b/exporter/src/app/renderer/bitmap.cljs index 6d04283c3..2e06cbd62 100644 --- a/exporter/src/app/renderer/bitmap.cljs +++ b/exporter/src/app/renderer/bitmap.cljs @@ -16,46 +16,34 @@ [app.config :as cf] [cljs.spec.alpha :as s] [cuerdas.core :as str] - [lambdaisland.uri :as u] [promesa.core :as p])) -(defn create-cookie - [uri token] - (let [domain (str (:host uri) - (when (:port uri) - (str ":" (:port uri))))] - {:domain domain - :key "auth-token" - :value token})) - (defn screenshot-object - [{:keys [file-id page-id object-id token scale type]}] - (letfn [(handle [page] - (let [path (str "/render-object/" file-id "/" page-id "/" object-id) - uri (-> (u/uri (cf/get :public-uri)) - (assoc :path "/") - (assoc :fragment path)) - cookie (create-cookie uri token)] - (screenshot page (str uri) cookie))) - - (screenshot [page uri cookie] - (l/info :uri uri) - (let [viewport {:width 1920 - :height 1080 - :scale scale} - options {:viewport viewport - :cookie cookie}] - (p/do! - (bw/configure-page! page options) - (bw/navigate! page uri) - (bw/eval! page (js* "() => document.body.style.background = 'transparent'")) - (bw/wait-for page "#screenshot") - (p/let [dom (bw/select page "#screenshot")] - (case type - :png (bw/screenshot dom {:omit-background? true :type type}) - :jpeg (bw/screenshot dom {:omit-background? false :type type}))))))] - - (bw/exec! handle))) + [{:keys [file-id page-id object-id token scale type uri]}] + (p/let [path (str "/render-object/" file-id "/" page-id "/" object-id) + uri (-> (or uri (cf/get :public-uri)) + (assoc :path "/") + (assoc :fragment path))] + (bw/exec! + #js {:screen #js {:width bw/default-viewport-width + :height bw/default-viewport-height} + :viewport #js {:width bw/default-viewport-width + :height bw/default-viewport-height} + :locale "en-US" + :storageState #js {:cookies (bw/create-cookies uri {:token token})} + :deviceScaleFactor scale + :userAgent bw/default-user-agent} + (fn [page] + (l/info :uri uri) + (p/do! + (bw/nav! page (str uri)) + (p/let [node (bw/select page "#screenshot")] + (bw/wait-for node) + (bw/eval! page (js* "() => document.body.style.background = 'transparent'")) + (bw/sleep page 2000) ; the good old fix with sleep + (case type + :png (bw/screenshot node {:omit-background? true :type type}) + :jpeg (bw/screenshot node {:omit-background? false :type type})))))))) (s/def ::name ::us/string) (s/def ::suffix ::us/string) @@ -65,25 +53,32 @@ (s/def ::object-id ::us/uuid) (s/def ::scale ::us/number) (s/def ::token ::us/string) -(s/def ::filename ::us/string) +(s/def ::origin ::us/string) +(s/def ::uri ::us/uri) -(s/def ::render-params +(s/def ::params (s/keys :req-un [::name ::suffix ::type ::object-id ::page-id ::scale ::token ::file-id] - :opt-un [::filename])) + :opt-un [::origin ::uri])) (defn render [params] - (us/assert ::render-params params) - (p/let [content (screenshot-object params)] - {:content content - :filename (or (:filename params) - (str (:name params) - (:suffix params "") - (case (:type params) - :png ".png" - :jpeg ".jpg"))) - :length (alength content) - :mime-type (case (:type params) - :png "image/png" - :jpeg "image/jpeg")})) + (us/verify ::params params) + (when (and (:origin params) + (not (contains? (cf/get :origin-white-list) (:origin params)))) + (ex/raise :type :validation + :code :invalid-origin + :hint "invalid origin" + :origin (:origin params))) + + (p/let [content (screenshot-object params)] + {:data content + :name (str (:name params) + (:suffix params "") + (case (:type params) + :png ".png" + :jpeg ".jpg")) + :size (alength content) + :mtype (case (:type params) + :png "image/png" + :jpeg "image/jpeg")})) diff --git a/exporter/src/app/renderer/pdf.cljs b/exporter/src/app/renderer/pdf.cljs index b421befa0..6055a900c 100644 --- a/exporter/src/app/renderer/pdf.cljs +++ b/exporter/src/app/renderer/pdf.cljs @@ -13,46 +13,33 @@ [app.common.spec :as us] [app.config :as cf] [cljs.spec.alpha :as s] - [lambdaisland.uri :as u] [promesa.core :as p])) -(defn create-cookie - [uri token] - (let [domain (str (:host uri) - (when (:port uri) - (str ":" (:port uri))))] - {:domain domain - :key "auth-token" - :value token})) - (defn pdf-from-object - [{:keys [file-id page-id object-id token scale type save-path]}] - (letfn [(handle [page] - (let [path (str "/render-object/" file-id "/" page-id "/" object-id) - uri (-> (u/uri (cf/get :public-uri)) - (assoc :path "/") - (assoc :query "essential=t") - (assoc :fragment path)) - - cookie (create-cookie uri token)] - (pdf-from page (str uri) cookie))) - - (pdf-from [page uri cookie] - (l/info :uri uri) - (p/let [options {:cookie cookie}] - (bw/configure-page! page options) - (bw/navigate! page uri) - (bw/wait-for page "#screenshot") - ;; taking png screenshot before pdf, helps to make the - ;; pdf rendering works as expected. - (p/let [dom (bw/select page "#screenshot")] - (bw/screenshot dom {:full-page? true})) - - (if save-path - (bw/pdf page {:save-path save-path}) - (bw/pdf page))))] - - (bw/exec! handle))) + [{:keys [file-id page-id object-id token scale type save-path uri] :as params}] + (p/let [path (str "/render-object/" file-id "/" page-id "/" object-id) + uri (-> (or uri (cf/get :public-uri)) + (assoc :path "/") + (assoc :fragment path))] + (bw/exec! + #js {:screen #js {:width bw/default-viewport-width + :height bw/default-viewport-height} + :viewport #js {:width bw/default-viewport-width + :height bw/default-viewport-height} + :locale "en-US" + :storageState #js {:cookies (bw/create-cookies uri {:token token})} + :deviceScaleFactor scale + :userAgent bw/default-user-agent} + (fn [page] + (l/info :uri uri) + (p/do! + (bw/nav! page uri) + (p/let [dom (bw/select page "#screenshot")] + (bw/wait-for dom) + (bw/screenshot dom {:full-page? true}) + (if save-path + (bw/pdf page {:save-path save-path}) + (bw/pdf page)))))))) (s/def ::name ::us/string) (s/def ::suffix ::us/string) @@ -61,22 +48,21 @@ (s/def ::object-id ::us/uuid) (s/def ::scale ::us/number) (s/def ::token ::us/string) -(s/def ::filename ::us/string) (s/def ::save-path ::us/string) +(s/def ::uri ::us/uri) (s/def ::render-params (s/keys :req-un [::name ::suffix ::object-id ::page-id ::scale ::token ::file-id] - :opt-un [::filename ::save-path])) + :opt-un [::save-path ::uri])) (defn render [params] (us/assert ::render-params params) (p/let [content (pdf-from-object params)] - {:content content - :filename (or (:filename params) - (str (:name params) - (:suffix params "") - ".pdf")) - :length (alength content) - :mime-type "application/pdf"})) + {:data content + :name (str (:name params) + (:suffix params "") + ".pdf") + :size (alength content) + :mtype "application/pdf"})) diff --git a/exporter/src/app/renderer/svg.cljs b/exporter/src/app/renderer/svg.cljs index 45b0afc06..da5f6e768 100644 --- a/exporter/src/app/renderer/svg.cljs +++ b/exporter/src/app/renderer/svg.cljs @@ -15,12 +15,10 @@ [app.common.pages :as cp] [app.common.spec :as us] [app.config :as cf] - [app.renderer.bitmap :refer [create-cookie]] [app.util.shell :as sh] [cljs.spec.alpha :as s] [clojure.walk :as walk] [cuerdas.core :as str] - [lambdaisland.uri :as u] [promesa.core :as p])) (l/set-level! :trace) @@ -114,7 +112,7 @@ (defn- render-object - [{:keys [page-id file-id object-id token scale suffix type]}] + [{:keys [page-id file-id object-id token scale suffix type uri]}] (letfn [(convert-to-ppm [pngpath] (l/trace :fn :convert-to-ppm) (let [basepath (path/dirname pngpath) @@ -306,7 +304,7 @@ (-> (bw/select-all page "#screenshot foreignObject") (p/then (fn [nodes] (p/all (map (partial process-text-node page) nodes)))))) - (extract-svg [page] + (extract [page] (p/let [dom (bw/select page "#screenshot") xmldata (bw/eval! dom (fn [elem] (.-outerHTML ^js elem))) nodes (process-text-nodes page) @@ -322,35 +320,32 @@ ;; (cljs.pprint/pprint (xml->clj result)) ;; (println "-------") result)) + ] - (render-in-page [page {:keys [uri cookie] :as rctx}] - (let [viewport {:width 1920 - :height 1080 - :scale 4} - options {:viewport viewport - :timeout 15000 - :cookie cookie}] - (p/do! - (bw/configure-page! page options) - (bw/navigate! page uri) - (bw/wait-for page "#screenshot") - (bw/sleep page 2000) - ;; (bw/eval! page (js* "() => document.body.style.background = 'transparent'")) - page))) - - (handle [rctx page] - (p/let [page (render-in-page page rctx)] - (extract-svg page)))] - - (let [path (str "/render-object/" file-id "/" page-id "/" object-id "?render-texts=true") - uri (-> (u/uri (cf/get :public-uri)) + (p/let [path (str "/render-object/" file-id "/" page-id "/" object-id "?render-texts=true") + uri (-> (or uri (cf/get :public-uri)) (assoc :path "/") - (assoc :fragment path)) - cookie (create-cookie uri token) - rctx {:cookie cookie - :uri (str uri)}] - (l/info :uri (:uri rctx)) - (bw/exec! (partial handle rctx))))) + (assoc :fragment path))] + + (bw/exec! + #js {:screen #js {:width bw/default-viewport-width + :height bw/default-viewport-height} + :viewport #js {:width bw/default-viewport-width + :height bw/default-viewport-height} + :locale "en-US" + :storageState #js {:cookies (bw/create-cookies uri {:token token})} + :deviceScaleFactor scale + :userAgent bw/default-user-agent} + (fn [page] + (l/info :uri uri) + (p/do! + (bw/nav! page uri) + (p/let [dom (bw/select page "#screenshot")] + (js/console.log "FFFF" dom) + (bw/wait-for dom) + (bw/sleep page 2000)) + + (extract page))))))) (s/def ::name ::us/string) (s/def ::suffix ::us/string) @@ -360,21 +355,20 @@ (s/def ::object-id ::us/uuid) (s/def ::scale ::us/number) (s/def ::token ::us/string) -(s/def ::filename ::us/string) +(s/def ::uri ::us/uri) -(s/def ::render-params +(s/def ::params (s/keys :req-un [::name ::suffix ::type ::object-id ::page-id ::file-id ::scale ::token] - :opt-un [::filename])) + :opt-un [::uri])) (defn render [params] - (us/assert ::render-params params) + (us/assert ::params params) (p/let [content (render-object params)] - {:content content - :filename (or (:filename params) - (str (:name params) - (:suffix params "") - ".svg")) - :length (alength content) - :mime-type "image/svg+xml"})) + {:data content + :name (str (:name params) + (:suffix params "") + ".svg") + :size (alength content) + :mtype "image/svg+xml"})) diff --git a/exporter/src/app/sentry.cljs b/exporter/src/app/sentry.cljs deleted file mode 100644 index 4f7c9be5c..000000000 --- a/exporter/src/app/sentry.cljs +++ /dev/null @@ -1,44 +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) UXBOX Labs SL - -(ns app.sentry - (:require - ["@sentry/node" :as sentry] - ["@sentry/tracing" :as sentry-t] - [app.common.data :as d] - [app.config :as cf])) - -(defn init! - [] - (when-let [dsn (cf/get :sentry-dsn)] - (sentry/init - #js {:dsn dsn - :release (str "frontend@" (:base @cf/version)) - :serverName (cf/get :host) - :environment (cf/get :tenant) - :autoSessionTracking false - :attachStacktrace false - :maxBreadcrumbs 20 - :tracesSampleRate 1.0}))) - -(def parse-request (unchecked-get sentry/Handlers "parseRequest")) - -(defn capture-exception - [error {:keys [::request ::tags] :as context}] - (let [context (-> (dissoc context ::request ::tags) - (d/without-nils))] - (sentry/withScope - (fn [scope] - (.addEventProcessor ^js scope (fn [event] - (let [node-request (:internal-request request)] - (parse-request event node-request)))) - (doseq [[k v] tags] - (.setTag ^js scope (if (keyword? k) (name k) (str k)) (str v))) - - (doseq [[k v] context] - (.setContext ^js scope (if (keyword? k) (name k) (str k)) (clj->js v))) - - (sentry/captureException error))))) diff --git a/exporter/src/app/util/shell.cljs b/exporter/src/app/util/shell.cljs index 8c5cca905..ee9f5d1c5 100644 --- a/exporter/src/app/util/shell.cljs +++ b/exporter/src/app/util/shell.cljs @@ -7,7 +7,7 @@ (ns app.util.shell "Shell & FS utilities." (:require - ["child_process" :as chp] + ["child_process" :as proc] ["fs" :as fs] ["os" :as os] ["path" :as path] @@ -18,51 +18,44 @@ (defn create-tmpdir! [prefix] - (p/create - (fn [resolve reject] - (fs/mkdtemp (path/join (os/tmpdir) prefix) - (fn [err dir] - (if err - (reject err) - (resolve dir))))))) + (-> (.mkdtemp fs/promises prefix) + (p/then (fn [result] + (path/join (os/tmpdir) result))))) + + +(defn move! + [origin-path dest-path] + (.rename fs/promises origin-path dest-path)) + +(defn stat + [path] + (-> (.stat fs/promises path) + (p/then (fn [data] + {:created-at (inst-ms (.-ctime ^js data)) + :size (.-size data)})) + (p/catch (constantly nil)))) + +(defn rmdir! + [path] + (.rm fs/promises path #js {:recursive true})) (defn write-file! [fpath content] - (p/create - (fn [resolve reject] - (fs/writeFile fpath content (fn [err] - (if err - (reject err) - (resolve nil))))))) + (.writeFile fs/promises fpath content)) + (defn read-file [fpath] - (p/create - (fn [resolve reject] - (fs/readFile fpath (fn [err content] - (if err - (reject err) - (resolve content))))))) + (.readFile fs/promises fpath)) (defn run-cmd! [cmd] (p/create (fn [resolve reject] (l/trace :fn :run-cmd :cmd cmd) - (chp/exec cmd #js {:encoding "buffer"} - (fn [error stdout stderr] - ;; (l/trace :fn :run-cmd :stdout stdout) - (if error - (reject error) - (resolve stdout))))))) - -(defn rmdir! - [path] - (p/create - (fn [resolve reject] - (fs/rmdir path #js {:recursive true} - (fn [err] - (if err - (reject err) - (resolve nil))))))) - + (proc/exec cmd #js {:encoding "buffer"} + (fn [error stdout stderr] + ;; (l/trace :fn :run-cmd :stdout stdout) + (if error + (reject error) + (resolve stdout))))))) diff --git a/exporter/src/app/zipfile.cljs b/exporter/src/app/zipfile.cljs deleted file mode 100644 index bc54b327b..000000000 --- a/exporter/src/app/zipfile.cljs +++ /dev/null @@ -1,19 +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) UXBOX Labs SL - -(ns app.zipfile - (:require - ["jszip" :as jszip])) - -(defn create - [] - (new jszip)) - -(defn add! - [zfile name data] - (.file ^js zfile name data) - zfile) - diff --git a/exporter/yarn.lock b/exporter/yarn.lock index 3a0453162..32bc6a44b 100644 --- a/exporter/yarn.lock +++ b/exporter/yarn.lock @@ -10,74 +10,6 @@ core-js-pure "^3.16.0" regenerator-runtime "^0.13.4" -"@sentry/core@6.16.1": - version "6.16.1" - resolved "https://registry.yarnpkg.com/@sentry/core/-/core-6.16.1.tgz#d9f7a75f641acaddf21b6aafa7a32e142f68f17c" - integrity sha512-UFI0264CPUc5cR1zJH+S2UPOANpm6dLJOnsvnIGTjsrwzR0h8Hdl6rC2R/GPq+WNbnipo9hkiIwDlqbqvIU5vw== - dependencies: - "@sentry/hub" "6.16.1" - "@sentry/minimal" "6.16.1" - "@sentry/types" "6.16.1" - "@sentry/utils" "6.16.1" - tslib "^1.9.3" - -"@sentry/hub@6.16.1": - version "6.16.1" - resolved "https://registry.yarnpkg.com/@sentry/hub/-/hub-6.16.1.tgz#526e19db51f4412da8634734044c605b936a7b80" - integrity sha512-4PGtg6AfpqMkreTpL7ymDeQ/U1uXv03bKUuFdtsSTn/FRf9TLS4JB0KuTZCxfp1IRgAA+iFg6B784dDkT8R9eg== - dependencies: - "@sentry/types" "6.16.1" - "@sentry/utils" "6.16.1" - tslib "^1.9.3" - -"@sentry/minimal@6.16.1": - version "6.16.1" - resolved "https://registry.yarnpkg.com/@sentry/minimal/-/minimal-6.16.1.tgz#6a9506a92623d2ff1fc17d60989688323326772e" - integrity sha512-dq+mI1EQIvUM+zJtGCVgH3/B3Sbx4hKlGf2Usovm9KoqWYA+QpfVBholYDe/H2RXgO7LFEefDLvOdHDkqeJoyA== - dependencies: - "@sentry/hub" "6.16.1" - "@sentry/types" "6.16.1" - tslib "^1.9.3" - -"@sentry/node@^6.16.1": - version "6.16.1" - resolved "https://registry.yarnpkg.com/@sentry/node/-/node-6.16.1.tgz#d92916da3e95d23e1ada274e97d6bf369e74ac51" - integrity sha512-SeDDoug2kUxeF1D7JGPa3h5EXxKtmA01mITBPYx5xbJ0sMksnv5I5bC1SJ8arRRzq6+W1C4IEeDBQtrVCk6ixA== - dependencies: - "@sentry/core" "6.16.1" - "@sentry/hub" "6.16.1" - "@sentry/tracing" "6.16.1" - "@sentry/types" "6.16.1" - "@sentry/utils" "6.16.1" - cookie "^0.4.1" - https-proxy-agent "^5.0.0" - lru_map "^0.3.3" - tslib "^1.9.3" - -"@sentry/tracing@6.16.1", "@sentry/tracing@^6.16.1": - version "6.16.1" - resolved "https://registry.yarnpkg.com/@sentry/tracing/-/tracing-6.16.1.tgz#32fba3e07748e9a955055afd559a65996acb7d71" - integrity sha512-MPSbqXX59P+OEeST+U2V/8Hu/8QjpTUxTNeNyTHWIbbchdcMMjDbXTS3etCgajZR6Ro+DHElOz5cdSxH6IBGlA== - dependencies: - "@sentry/hub" "6.16.1" - "@sentry/minimal" "6.16.1" - "@sentry/types" "6.16.1" - "@sentry/utils" "6.16.1" - tslib "^1.9.3" - -"@sentry/types@6.16.1": - version "6.16.1" - resolved "https://registry.yarnpkg.com/@sentry/types/-/types-6.16.1.tgz#4917607115b30315757c2cf84f80bac5100b8ac0" - integrity sha512-Wh354g30UsJ5kYJbercektGX4ZMc9MHU++1NjeN2bTMnbofEcpUDWIiKeulZEY65IC1iU+1zRQQgtYO+/hgCUQ== - -"@sentry/utils@6.16.1": - version "6.16.1" - resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-6.16.1.tgz#1b9e14c2831b6e8b816f7021b9876133bf2be008" - integrity sha512-7ngq/i4R8JZitJo9Sl8PDnjSbDehOxgr1vsoMmerIsyRZ651C/8B+jVkMhaAPgSdyJ0AlE3O7DKKTP1FXFw9qw== - dependencies: - "@sentry/types" "6.16.1" - tslib "^1.9.3" - "@types/node@*": version "16.6.2" resolved "https://registry.yarnpkg.com/@types/node/-/node-16.6.2.tgz#331b7b9f8621c638284787c5559423822fdffc50" @@ -90,13 +22,42 @@ dependencies: "@types/node" "*" -agent-base@6: +agent-base@6, agent-base@^6.0.2: version "6.0.2" resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77" integrity sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ== dependencies: debug "4" +archiver-utils@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/archiver-utils/-/archiver-utils-2.1.0.tgz#e8a460e94b693c3e3da182a098ca6285ba9249e2" + integrity sha512-bEL/yUb/fNNiNTuUz979Z0Yg5L+LzLxGJz8x79lYmR54fmTIb6ob/hNQgkQnIUDWIFjZVQwl9Xs356I6BAMHfw== + dependencies: + glob "^7.1.4" + graceful-fs "^4.2.0" + lazystream "^1.0.0" + lodash.defaults "^4.2.0" + lodash.difference "^4.5.0" + lodash.flatten "^4.4.0" + lodash.isplainobject "^4.0.6" + lodash.union "^4.6.0" + normalize-path "^3.0.0" + readable-stream "^2.0.0" + +archiver@^5.3.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/archiver/-/archiver-5.3.0.tgz#dd3e097624481741df626267564f7dd8640a45ba" + integrity sha512-iUw+oDwK0fgNpvveEsdQ0Ase6IIKztBJU2U0E9MzszMfmVVUyv1QJhS2ITW9ZCqx8dktAxVAjWWkKehuZE8OPg== + dependencies: + archiver-utils "^2.1.0" + async "^3.2.0" + buffer-crc32 "^0.2.1" + readable-stream "^3.6.0" + readdir-glob "^1.0.0" + tar-stream "^2.2.0" + zip-stream "^4.1.0" + asn1.js@^5.2.0: version "5.4.1" resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-5.4.1.tgz#11a980b84ebb91781ce35b0fdc2ee294e3783f07" @@ -115,6 +76,11 @@ assert@^1.1.1: object-assign "^4.1.1" util "0.10.3" +async@^3.2.0: + version "3.2.3" + resolved "https://registry.yarnpkg.com/async/-/async-3.2.3.tgz#ac53dafd3f4720ee9e8a160628f18ea91df196c9" + integrity sha512-spZRyzKL5l5BZQrr/6m/SqFdBN0q3OCI0f9rjfBzCMBIP4p75P620rR3gTmaksNOhmzgdxcaxdNfMy6anrbM0g== + balanced-match@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" @@ -218,7 +184,7 @@ browserify-zlib@^0.2.0: dependencies: pako "~1.0.5" -buffer-crc32@~0.2.3: +buffer-crc32@^0.2.1, buffer-crc32@^0.2.13, buffer-crc32@~0.2.3: version "0.2.13" resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242" integrity sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI= @@ -242,7 +208,7 @@ buffer@^4.3.0: ieee754 "^1.1.4" isarray "^1.0.0" -buffer@^5.2.1, buffer@^5.5.0: +buffer@^5.5.0: version "5.7.1" resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0" integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ== @@ -255,15 +221,10 @@ builtin-status-codes@^3.0.0: resolved "https://registry.yarnpkg.com/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz#85982878e21b98e1c66425e03d0174788f569ee8" integrity sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug= -bytes@3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.1.tgz#3f018291cb4cbad9accb6e6970bca9c8889e879a" - integrity sha512-dWe4nWO/ruEOY7HkUJ5gFt1DCFV9zPRoJr8pV0/ASQermOZjtq8jMjOprC0Kd10GLN+l7xaUPvxzJFWtxGu8Fg== - -chownr@^1.1.1: - version "1.1.4" - resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b" - integrity sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg== +bytes@3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5" + integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg== cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: version "1.0.4" @@ -273,6 +234,26 @@ cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: inherits "^2.0.1" safe-buffer "^5.0.1" +cluster-key-slot@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/cluster-key-slot/-/cluster-key-slot-1.1.0.tgz#30474b2a981fb12172695833052bc0d01336d10d" + integrity sha512-2Nii8p3RwAPiFwsnZvukotvow2rIHM+yQ6ZcBXGHdniadkYGZYiGmkHJIbZPIV9nfv7m/U1IPMVVcAhoWFeklw== + +commander@8.3.0: + version "8.3.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-8.3.0.tgz#4837ea1b2da67b9c616a67afbb0fafee567bca66" + integrity sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww== + +compress-commons@^4.1.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/compress-commons/-/compress-commons-4.1.1.tgz#df2a09a7ed17447642bad10a85cc9a19e5c42a7d" + integrity sha512-QLdDLCKNV2dtoTorqgxngQCMA+gWXkM/Nwu7FpeBhk/RdkzimqC3jueb/FDmaZeXh+uby1jkBqE3xArsLBE5wQ== + dependencies: + buffer-crc32 "^0.2.13" + crc32-stream "^4.0.2" + normalize-path "^3.0.0" + readable-stream "^3.6.0" + concat-map@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" @@ -288,11 +269,6 @@ constants-browserify@^1.0.0: resolved "https://registry.yarnpkg.com/constants-browserify/-/constants-browserify-1.0.0.tgz#c20b96d8c617748aaf1c16021760cd27fcb8cb75" integrity sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U= -cookie@^0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.1.tgz#afd713fe26ebd21ba95ceb61f9a8116e50a537d1" - integrity sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA== - cookies@^0.8.0: version "0.8.0" resolved "https://registry.yarnpkg.com/cookies/-/cookies-0.8.0.tgz#1293ce4b391740a8406e3c9870e828c4b54f3f90" @@ -311,6 +287,22 @@ core-util-is@~1.0.0: resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= +crc-32@^1.2.0: + version "1.2.1" + resolved "https://registry.yarnpkg.com/crc-32/-/crc-32-1.2.1.tgz#436d2bcaad27bcb6bd073a2587139d3024a16460" + integrity sha512-Dn/xm/1vFFgs3nfrpEVScHoIslO9NZRITWGz/1E/St6u4xw99vfZzVkW0OSnzx2h9egej9xwMCEut6sqwokM/w== + dependencies: + exit-on-epipe "~1.0.1" + printj "~1.3.1" + +crc32-stream@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/crc32-stream/-/crc32-stream-4.0.2.tgz#c922ad22b38395abe9d3870f02fa8134ed709007" + integrity sha512-DxFZ/Hk473b/muq1VJ///PMNLj0ZMnzye9thBpmjpJKCc5eMgB95aK8zCGrGfQ90cWo561Te6HK9D+j4KPdM6w== + dependencies: + crc-32 "^1.2.0" + readable-stream "^3.4.0" + create-ecdh@^4.0.0: version "4.0.4" resolved "https://registry.yarnpkg.com/create-ecdh/-/create-ecdh-4.0.4.tgz#d6e7f4bffa66736085a0762fd3a632684dabcc4e" @@ -359,19 +351,26 @@ crypto-browserify@^3.11.0: randombytes "^2.0.0" randomfill "^1.0.3" -debug@4, debug@4.3.2, debug@^4.1.1: +debug@4, debug@^4.1.1: version "4.3.2" resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.2.tgz#f0a49c18ac8779e31d4a0c6029dfb76873c7428b" integrity sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw== dependencies: ms "2.1.2" -depd@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" - integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak= +debug@4.3.3, debug@^4.3.1: + version "4.3.3" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.3.tgz#04266e0b70a98d4462e6e288e38259213332b664" + integrity sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q== + dependencies: + ms "2.1.2" -depd@~2.0.0: +denque@^1.1.0: + version "1.5.1" + resolved "https://registry.yarnpkg.com/denque/-/denque-1.5.1.tgz#07f670e29c9a78f8faecb2566a1e2c11929c5cbf" + integrity sha512-XwE+iZ4D6ZUB7mfYRMb5wByE8L74HCn30FBN7sWnXksWc1LO1bPDl67pBR9o/kC4z/xSNAwkMYcGgqDV3BE3Hw== + +depd@2.0.0, depd@~2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df" integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw== @@ -384,11 +383,6 @@ des.js@^1.0.0: inherits "^2.0.1" minimalistic-assert "^1.0.0" -devtools-protocol@0.0.948846: - version "0.0.948846" - resolved "https://registry.yarnpkg.com/devtools-protocol/-/devtools-protocol-0.0.948846.tgz#bff47e2d1dba060130fa40ed2e5f78b916ba285f" - integrity sha512-5fGyt9xmMqUl2VI7+rnUkKCiAQIpLns8sfQtTENy5L70ktbNw0Z3TFJ1JoFNYdx/jffz4YXU45VF75wKZD7sZQ== - diffie-hellman@^5.0.0: version "5.0.3" resolved "https://registry.yarnpkg.com/diffie-hellman/-/diffie-hellman-5.0.3.tgz#40e8ee98f55a2149607146921c63e1ae5f3d2875" @@ -423,6 +417,11 @@ end-of-stream@^1.1.0, end-of-stream@^1.4.1: dependencies: once "^1.4.0" +escape-string-regexp@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz#a30304e99daa32e23b2fd20f51babd07cffca344" + integrity sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w== + events@^3.0.0: version "3.3.0" resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400" @@ -436,6 +435,11 @@ evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3: md5.js "^1.3.4" safe-buffer "^5.1.1" +exit-on-epipe@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/exit-on-epipe/-/exit-on-epipe-1.0.1.tgz#0bdd92e87d5285d267daa8171d0eb06159689692" + integrity sha512-h2z5mrROTxce56S+pnvAV890uu7ls7f1kEvVGJbw1OlFH3/mlJ5bkXu0KRyW94v37zzHPiUd55iLn3DA7TjWpw== + extract-zip@2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/extract-zip/-/extract-zip-2.0.1.tgz#663dca56fe46df890d5f131ef4a06d22bb8ba13a" @@ -454,14 +458,6 @@ fd-slicer@~1.1.0: dependencies: pend "~1.2.0" -find-up@^4.0.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" - integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== - dependencies: - locate-path "^5.0.0" - path-exists "^4.0.0" - fs-constants@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad" @@ -496,6 +492,23 @@ glob@^7.1.3: once "^1.3.0" path-is-absolute "^1.0.0" +glob@^7.1.4: + version "7.2.0" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.0.tgz#d15535af7732e02e948f4c41628bd910293f6023" + integrity sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + +graceful-fs@^4.2.0, graceful-fs@^4.2.4: + version "4.2.9" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.9.tgz#041b05df45755e587a24942279b9d113146e1c96" + integrity sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ== + hash-base@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-3.1.0.tgz#55c381d9e06e1d2997a883b4a3fddfe7f0d3af33" @@ -522,15 +535,15 @@ hmac-drbg@^1.0.1: minimalistic-assert "^1.0.0" minimalistic-crypto-utils "^1.0.1" -http-errors@1.8.1: - version "1.8.1" - resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.8.1.tgz#7c3f28577cbc8a207388455dbd62295ed07bd68c" - integrity sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g== +http-errors@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-2.0.0.tgz#b7774a1486ef73cf7667ac9ae0858c012c57b9d3" + integrity sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ== dependencies: - depd "~1.1.2" + depd "2.0.0" inherits "2.0.4" setprototypeof "1.2.0" - statuses ">= 1.5.0 < 2" + statuses "2.0.1" toidentifier "1.0.1" https-browserify@^1.0.0: @@ -538,7 +551,7 @@ https-browserify@^1.0.0: resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73" integrity sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM= -https-proxy-agent@5.0.0, https-proxy-agent@^5.0.0: +https-proxy-agent@5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz#e2a90542abb68a762e0a0850f6c9edadfd8506b2" integrity sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA== @@ -558,11 +571,6 @@ ieee754@^1.1.13, ieee754@^1.1.4: resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== -immediate@~3.0.5: - version "3.0.6" - resolved "https://registry.yarnpkg.com/immediate/-/immediate-3.0.6.tgz#9db1dbd0faf8de6fbe0f5dd5e56bb606280de69b" - integrity sha1-nbHb0Pr43m++D13V5Wu2BigN5ps= - inflation@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/inflation/-/inflation-2.0.0.tgz#8b417e47c28f925a45133d914ca1fd389107f30f" @@ -591,6 +599,28 @@ inherits@2.0.3: resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= +ioredis@^4.28.5: + version "4.28.5" + resolved "https://registry.yarnpkg.com/ioredis/-/ioredis-4.28.5.tgz#5c149e6a8d76a7f8fa8a504ffc85b7d5b6797f9f" + integrity sha512-3GYo0GJtLqgNXj4YhrisLaNNvWSNwSS2wS4OELGfGxH8I69+XfNdnmV1AyN+ZqMh0i7eX+SWjrwFKDBDgfBC1A== + dependencies: + cluster-key-slot "^1.1.0" + debug "^4.3.1" + denque "^1.1.0" + lodash.defaults "^4.2.0" + lodash.flatten "^4.4.0" + lodash.isarguments "^3.1.0" + p-map "^2.1.0" + redis-commands "1.7.0" + redis-errors "^1.2.0" + redis-parser "^3.0.0" + standard-as-callback "^2.1.0" + +ip@^1.1.5: + version "1.1.5" + resolved "https://registry.yarnpkg.com/ip/-/ip-1.1.5.tgz#bdded70114290828c0a039e72ef25f5aaec4354a" + integrity sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo= + isarray@^1.0.0, isarray@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" @@ -601,15 +631,10 @@ isexe@^2.0.0: resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= -jszip@^3.7.0: - version "3.7.1" - resolved "https://registry.yarnpkg.com/jszip/-/jszip-3.7.1.tgz#bd63401221c15625a1228c556ca8a68da6fda3d9" - integrity sha512-ghL0tz1XG9ZEmRMcEN2vt7xabrDdqHHeykgARpmZ0BiIctWxM47Vt63ZO2dnp4QYt/xJVLLy5Zv1l/xRdh2byg== - dependencies: - lie "~3.3.0" - pako "~1.0.2" - readable-stream "~2.3.6" - set-immediate-shim "~1.0.1" +jpeg-js@0.4.3: + version "0.4.3" + resolved "https://registry.yarnpkg.com/jpeg-js/-/jpeg-js-0.4.3.tgz#6158e09f1983ad773813704be80680550eff977b" + integrity sha512-ru1HWKek8octvUHFHvE5ZzQ1yAsJmIvRdGWvSoKV52XKyuyYA437QWDttXT8eZXDSbuMpHlLzPDZUPd6idIz+Q== keygrip@~1.1.0: version "1.1.0" @@ -618,29 +643,47 @@ keygrip@~1.1.0: dependencies: tsscmp "1.0.6" -lie@~3.3.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/lie/-/lie-3.3.0.tgz#dcf82dee545f46074daf200c7c1c5a08e0f40f6a" - integrity sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ== +lazystream@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/lazystream/-/lazystream-1.0.1.tgz#494c831062f1f9408251ec44db1cba29242a2638" + integrity sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw== dependencies: - immediate "~3.0.5" + readable-stream "^2.0.5" -locate-path@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0" - integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g== - dependencies: - p-locate "^4.1.0" +lodash.defaults@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/lodash.defaults/-/lodash.defaults-4.2.0.tgz#d09178716ffea4dde9e5fb7b37f6f0802274580c" + integrity sha1-0JF4cW/+pN3p5ft7N/bwgCJ0WAw= -lru_map@^0.3.3: - version "0.3.3" - resolved "https://registry.yarnpkg.com/lru_map/-/lru_map-0.3.3.tgz#b5c8351b9464cbd750335a79650a0ec0e56118dd" - integrity sha1-tcg1G5Rky9dQM1p5ZQoOwOVhGN0= +lodash.difference@^4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.difference/-/lodash.difference-4.5.0.tgz#9ccb4e505d486b91651345772885a2df27fd017c" + integrity sha1-nMtOUF1Ia5FlE0V3KIWi3yf9AXw= -luxon@^2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/luxon/-/luxon-2.3.0.tgz#bf16a7e642513c2a20a6230a6a41b0ab446d0045" - integrity sha512-gv6jZCV+gGIrVKhO90yrsn8qXPKD8HYZJtrUDSfEbow8Tkw84T9OnCyJhWvnJIaIF/tBuiAjZuQHUt1LddX2mg== +lodash.flatten@^4.4.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/lodash.flatten/-/lodash.flatten-4.4.0.tgz#f31c22225a9632d2bbf8e4addbef240aa765a61f" + integrity sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8= + +lodash.isarguments@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz#2f573d85c6a24289ff00663b491c1d338ff3458a" + integrity sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo= + +lodash.isplainobject@^4.0.6: + version "4.0.6" + resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb" + integrity sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs= + +lodash.union@^4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/lodash.union/-/lodash.union-4.6.0.tgz#48bb5088409f16f1821666641c44dd1aaae3cd88" + integrity sha1-SLtQiECfFvGCFmZkHETdGqrjzYg= + +luxon@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/luxon/-/luxon-2.3.1.tgz#f276b1b53fd9a740a60e666a541a7f6dbed4155a" + integrity sha512-I8vnjOmhXsMSlNMZlMkSOvgrxKJl0uOsEzdGgGNZuZPaS9KlefpE9KV95QFftlJSC+1UyCC9/I69R02cz/zcCA== md5.js@^1.3.4: version "1.3.5" @@ -659,6 +702,11 @@ miller-rabin@^4.0.0: bn.js "^4.0.0" brorand "^1.0.1" +mime@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/mime/-/mime-3.0.0.tgz#b374550dca3a0c18443b0c950a6a58f1931cf7a7" + integrity sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A== + minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" @@ -676,23 +724,11 @@ minimatch@^3.0.4: dependencies: brace-expansion "^1.1.7" -mkdirp-classic@^0.5.2: - version "0.5.3" - resolved "https://registry.yarnpkg.com/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz#fa10c9115cc6d8865be221ba47ee9bed78601113" - integrity sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A== - ms@2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== -node-fetch@2.6.5: - version "2.6.5" - resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.5.tgz#42735537d7f080a7e5f78b6c549b7146be1742fd" - integrity sha512-mmlIVHJEu5rnIxgEgez6b9GgWXbkZj5YZ7fx+2r94a2E+Uirsp6HsPTPlomfdHtpt/B0cdKviwkoaM6pyvUOpQ== - dependencies: - whatwg-url "^5.0.0" - node-libs-browser@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/node-libs-browser/-/node-libs-browser-2.2.1.tgz#b64f513d18338625f90346d27b0d235e631f6425" @@ -722,6 +758,11 @@ node-libs-browser@^2.2.1: util "^0.11.0" vm-browserify "^1.0.1" +normalize-path@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" + integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== + object-assign@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" @@ -739,26 +780,12 @@ os-browserify@^0.3.0: resolved "https://registry.yarnpkg.com/os-browserify/-/os-browserify-0.3.0.tgz#854373c7f5c2315914fc9bfc6bd8238fdda1ec27" integrity sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc= -p-limit@^2.2.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" - integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== - dependencies: - p-try "^2.0.0" +p-map@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/p-map/-/p-map-2.1.0.tgz#310928feef9c9ecc65b68b17693018a665cea175" + integrity sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw== -p-locate@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07" - integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A== - dependencies: - p-limit "^2.2.0" - -p-try@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" - integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== - -pako@~1.0.2, pako@~1.0.5: +pako@~1.0.5: version "1.0.11" resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.11.tgz#6c9599d340d54dfd3946380252a35705a6b992bf" integrity sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw== @@ -779,11 +806,6 @@ path-browserify@0.0.1: resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-0.0.1.tgz#e6c4ddd7ed3aa27c68a20cc4e50e1a4ee83bbc4a" integrity sha512-BapA40NHICOS+USX9SN4tyhq+A2RrN/Ws5F0Z5aMHDp98Fl86lX8Oti8B7uN93L4Ifv4fHOEA+pQw87gmMO/lQ== -path-exists@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" - integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== - path-is-absolute@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" @@ -805,12 +827,44 @@ pend@~1.2.0: resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50" integrity sha1-elfrVQpng/kRUzH89GY9XI4AelA= -pkg-dir@4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3" - integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ== +playwright-core@1.19.2: + version "1.19.2" + resolved "https://registry.yarnpkg.com/playwright-core/-/playwright-core-1.19.2.tgz#90b9209554f174c649abf495952fcb4335437218" + integrity sha512-OsL3sJZIo1UxKNWSP7zW7sk3FyUGG06YRHxHeBw51eIOxTCQRx5t+hXd0cvXashN2CHnd3hIZTs2aKa/im4hZQ== dependencies: - find-up "^4.0.0" + commander "8.3.0" + debug "4.3.3" + extract-zip "2.0.1" + https-proxy-agent "5.0.0" + jpeg-js "0.4.3" + mime "3.0.0" + pngjs "6.0.0" + progress "2.0.3" + proper-lockfile "4.1.2" + proxy-from-env "1.1.0" + rimraf "3.0.2" + socks-proxy-agent "6.1.1" + stack-utils "2.0.5" + ws "8.4.2" + yauzl "2.10.0" + yazl "2.5.1" + +playwright@^1.19.2: + version "1.19.2" + resolved "https://registry.yarnpkg.com/playwright/-/playwright-1.19.2.tgz#d9927ae8512482642356e50a286c5767dfb7a621" + integrity sha512-2JmGWr/Iw/Uu27bZULeHgjn8doNrRVxIYdhspMuMlfKNpzwAe/sfm7wH8uey6jiZxnPL4bC5V4ACQcF4dAGWnw== + dependencies: + playwright-core "1.19.2" + +pngjs@6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/pngjs/-/pngjs-6.0.0.tgz#ca9e5d2aa48db0228a52c419c3308e87720da821" + integrity sha512-TRzzuFRRmEoSW/p1KVAmiOgPco2Irlah+bGFCeNfJXxxYGwSw7YwAOAcd7X28K/m5bjBWKsC29KyoMfHbypayg== + +printj@~1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/printj/-/printj-1.3.1.tgz#9af6b1d55647a1587ac44f4c1654a4b95b8e12cb" + integrity sha512-GA3TdL8szPK4AQ2YnOe/b+Y1jUFwmmGMMK/qbY7VcE3Z7FU8JstbKiKRzO6CIiAKPhTO8m01NoQ0V5f3jc4OGg== process-nextick-args@~2.0.0: version "2.0.1" @@ -827,6 +881,15 @@ progress@2.0.3: resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== +proper-lockfile@4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/proper-lockfile/-/proper-lockfile-4.1.2.tgz#c8b9de2af6b2f1601067f98e01ac66baa223141f" + integrity sha512-TjNPblN4BwAWMXU8s9AEz4JmQxnD1NNL7bNOY/AKUzyamc379FWASUhc/K1pL2noVb+XmZKLL68cjzLsiOAMaA== + dependencies: + graceful-fs "^4.2.4" + retry "^0.12.0" + signal-exit "^3.0.2" + proxy-from-env@1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2" @@ -862,24 +925,6 @@ punycode@^1.2.4: resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" integrity sha1-wNWmOycYgArY4esPpSachN1BhF4= -puppeteer-core@^13.1.1: - version "13.1.1" - resolved "https://registry.yarnpkg.com/puppeteer-core/-/puppeteer-core-13.1.1.tgz#bd07b225732210c570fb8af1ff959bb91806dbdc" - integrity sha512-pXVcEFv5wgayHtwl5WBB8dyFHkdA7eLcAUuF9cprsoJQVU1sgA32OCfmXqNfvcej85Y5ceAcin09c8qLopdkfQ== - dependencies: - debug "4.3.2" - devtools-protocol "0.0.948846" - extract-zip "2.0.1" - https-proxy-agent "5.0.0" - node-fetch "2.6.5" - pkg-dir "4.2.0" - progress "2.0.3" - proxy-from-env "1.1.0" - rimraf "3.0.2" - tar-fs "2.1.1" - unbzip2-stream "1.4.3" - ws "8.2.3" - querystring-es3@^0.2.0: version "0.2.1" resolved "https://registry.yarnpkg.com/querystring-es3/-/querystring-es3-0.2.1.tgz#9ec61f79049875707d69414596fd907a4d711e73" @@ -905,17 +950,17 @@ randomfill@^1.0.3: randombytes "^2.0.5" safe-buffer "^5.1.0" -raw-body@^2.4.2: - version "2.4.2" - resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.4.2.tgz#baf3e9c21eebced59dd6533ac872b71f7b61cb32" - integrity sha512-RPMAFUJP19WIet/99ngh6Iv8fzAbqum4Li7AD6DtGaW2RpMB/11xDoalPiJMTbu6I3hkbMVkATvZrqb9EEqeeQ== +raw-body@^2.5.1: + version "2.5.1" + resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.5.1.tgz#fe1b1628b181b700215e5fd42389f98b71392857" + integrity sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig== dependencies: - bytes "3.1.1" - http-errors "1.8.1" + bytes "3.1.2" + http-errors "2.0.0" iconv-lite "0.4.24" unpipe "1.0.0" -readable-stream@^2.0.2, readable-stream@^2.3.3, readable-stream@^2.3.6, readable-stream@~2.3.6: +readable-stream@^2.0.0, readable-stream@^2.0.2, readable-stream@^2.0.5, readable-stream@^2.3.3, readable-stream@^2.3.6: version "2.3.7" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57" integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw== @@ -937,16 +982,45 @@ readable-stream@^3.1.1, readable-stream@^3.4.0, readable-stream@^3.6.0: string_decoder "^1.1.1" util-deprecate "^1.0.1" +readdir-glob@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/readdir-glob/-/readdir-glob-1.1.1.tgz#f0e10bb7bf7bfa7e0add8baffdc54c3f7dbee6c4" + integrity sha512-91/k1EzZwDx6HbERR+zucygRFfiPl2zkIYZtv3Jjr6Mn7SkKcVct8aVO+sSRiGMc6fLf72du3d92/uY63YPdEA== + dependencies: + minimatch "^3.0.4" + readline-sync@^1.4.7: version "1.4.10" resolved "https://registry.yarnpkg.com/readline-sync/-/readline-sync-1.4.10.tgz#41df7fbb4b6312d673011594145705bf56d8873b" integrity sha512-gNva8/6UAe8QYepIQH/jQ2qn91Qj0B9sYjMBBs3QOB8F2CXcKgLxQaJRP76sWVRQt+QU+8fAkCbCvjjMFu7Ycw== +redis-commands@1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/redis-commands/-/redis-commands-1.7.0.tgz#15a6fea2d58281e27b1cd1acfb4b293e278c3a89" + integrity sha512-nJWqw3bTFy21hX/CPKHth6sfhZbdiHP6bTawSgQBlKOVRG7EZkfHbbHwQJnrE4vsQf0CMNE+3gJ4Fmm16vdVlQ== + +redis-errors@^1.0.0, redis-errors@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/redis-errors/-/redis-errors-1.2.0.tgz#eb62d2adb15e4eaf4610c04afe1529384250abad" + integrity sha1-62LSrbFeTq9GEMBK/hUpOEJQq60= + +redis-parser@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/redis-parser/-/redis-parser-3.0.0.tgz#b66d828cdcafe6b4b8a428a7def4c6bcac31c8b4" + integrity sha1-tm2CjNyv5rS4pCin3vTGvKwxyLQ= + dependencies: + redis-errors "^1.0.0" + regenerator-runtime@^0.13.4: version "0.13.9" resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz#8925742a98ffd90814988d7566ad30ca3b263b52" integrity sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA== +retry@^0.12.0: + version "0.12.0" + resolved "https://registry.yarnpkg.com/retry/-/retry-0.12.0.tgz#1b42a6266a21f07421d1b0b54b7dc167b01c013b" + integrity sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs= + rimraf@3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" @@ -982,11 +1056,6 @@ sax@^1.2.4: resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== -set-immediate-shim@~1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz#4b2b1b27eb808a9f8dcc481a58e5e56f599f3f61" - integrity sha1-SysbJ+uAip+NzEgaWOXlb1mfP2E= - setimmediate@^1.0.4: version "1.0.5" resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" @@ -1010,10 +1079,10 @@ shadow-cljs-jar@1.3.2: resolved "https://registry.yarnpkg.com/shadow-cljs-jar/-/shadow-cljs-jar-1.3.2.tgz#97273afe1747b6a2311917c1c88d9e243c81957b" integrity sha512-XmeffAZHv8z7451kzeq9oKh8fh278Ak+UIOGGrapyqrFBB773xN8vMQ3O7J7TYLnb9BUwcqadKkmgaq7q6fhZg== -shadow-cljs@^2.17.3: - version "2.17.3" - resolved "https://registry.yarnpkg.com/shadow-cljs/-/shadow-cljs-2.17.3.tgz#748e31f67cffdc401691c0cd1bf733a1da53ab5d" - integrity sha512-GxyczUuCtACq/uEOvdTc61wT/aDOZFy8G/AGc322uTX/oUiZaeTJrwpClXe+0+e7VKG9E9RCqP/cjuG3cAG0fw== +shadow-cljs@^2.17.8: + version "2.17.8" + resolved "https://registry.yarnpkg.com/shadow-cljs/-/shadow-cljs-2.17.8.tgz#7ee27ccf7585991f6c042f66f07f17582c0b70af" + integrity sha512-O39cLA7ukEh+OeH1yZlaWjGFinPOsDD87TetAWPe1QBD9TZQ0Ail+2ovaXeAyZpJ+6Z37joFfival+LNuCgsmQ== dependencies: node-libs-browser "^2.2.1" readline-sync "^1.4.7" @@ -1022,6 +1091,33 @@ shadow-cljs@^2.17.3: which "^1.3.1" ws "^7.4.6" +signal-exit@^3.0.2: + version "3.0.7" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" + integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== + +smart-buffer@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/smart-buffer/-/smart-buffer-4.2.0.tgz#6e1d71fa4f18c05f7d0ff216dd16a481d0e8d9ae" + integrity sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg== + +socks-proxy-agent@6.1.1: + version "6.1.1" + resolved "https://registry.yarnpkg.com/socks-proxy-agent/-/socks-proxy-agent-6.1.1.tgz#e664e8f1aaf4e1fb3df945f09e3d94f911137f87" + integrity sha512-t8J0kG3csjA4g6FTbsMOWws+7R7vuRC8aQ/wy3/1OWmsgwA68zs/+cExQ0koSitUDXqhufF/YJr9wtNMZHw5Ew== + dependencies: + agent-base "^6.0.2" + debug "^4.3.1" + socks "^2.6.1" + +socks@^2.6.1: + version "2.6.2" + resolved "https://registry.yarnpkg.com/socks/-/socks-2.6.2.tgz#ec042d7960073d40d94268ff3bb727dc685f111a" + integrity sha512-zDZhHhZRY9PxRruRMR7kMhnf3I8hDs4S3f9RecfnGxvcBHQcKcIH/oUcEWffsfl1XxdYlA7nnlGbbTvPz9D8gA== + dependencies: + ip "^1.1.5" + smart-buffer "^4.2.0" + source-map-support@^0.4.15: version "0.4.18" resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.4.18.tgz#0286a6de8be42641338594e97ccea75f0a2c585f" @@ -1047,10 +1143,22 @@ source-map@^0.6.0: resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== -"statuses@>= 1.5.0 < 2": - version "1.5.0" - resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" - integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow= +stack-utils@2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-2.0.5.tgz#d25265fca995154659dbbfba3b49254778d2fdd5" + integrity sha512-xrQcmYhOsn/1kX+Vraq+7j4oE2j/6BFscZ0etmYg81xuM8Gq0022Pxb8+IqgOFUIaxHs0KaSb7T1+OegiNrNFA== + dependencies: + escape-string-regexp "^2.0.0" + +standard-as-callback@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/standard-as-callback/-/standard-as-callback-2.1.0.tgz#8953fc05359868a77b5b9739a665c5977bb7df45" + integrity sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A== + +statuses@2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.1.tgz#55cb000ccf1d48728bd23c685a063998cf1a1b63" + integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ== stream-browserify@^2.0.1: version "2.0.2" @@ -1085,17 +1193,7 @@ string_decoder@~1.1.1: dependencies: safe-buffer "~5.1.0" -tar-fs@2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/tar-fs/-/tar-fs-2.1.1.tgz#489a15ab85f1f0befabb370b7de4f9eb5cbe8784" - integrity sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng== - dependencies: - chownr "^1.1.1" - mkdirp-classic "^0.5.2" - pump "^3.0.0" - tar-stream "^2.1.4" - -tar-stream@^2.1.4: +tar-stream@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-2.2.0.tgz#acad84c284136b060dc3faa64474aa9aebd77287" integrity sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ== @@ -1106,11 +1204,6 @@ tar-stream@^2.1.4: inherits "^2.0.3" readable-stream "^3.1.1" -through@^2.3.8: - version "2.3.8" - resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" - integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= - timers-browserify@^2.0.4: version "2.0.12" resolved "https://registry.yarnpkg.com/timers-browserify/-/timers-browserify-2.0.12.tgz#44a45c11fbf407f34f97bccd1577c652361b00ee" @@ -1128,16 +1221,6 @@ toidentifier@1.0.1: resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35" integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA== -tr46@~0.0.3: - version "0.0.3" - resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" - integrity sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o= - -tslib@^1.9.3: - version "1.14.1" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" - integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== - tsscmp@1.0.6: version "1.0.6" resolved "https://registry.yarnpkg.com/tsscmp/-/tsscmp-1.0.6.tgz#85b99583ac3589ec4bfef825b5000aa911d605eb" @@ -1148,14 +1231,6 @@ tty-browserify@0.0.0: resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.0.tgz#a157ba402da24e9bf957f9aa69d524eed42901a6" integrity sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY= -unbzip2-stream@1.4.3: - version "1.4.3" - resolved "https://registry.yarnpkg.com/unbzip2-stream/-/unbzip2-stream-1.4.3.tgz#b0da04c4371311df771cdc215e87f2130991ace7" - integrity sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg== - dependencies: - buffer "^5.2.1" - through "^2.3.8" - unpipe@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" @@ -1193,19 +1268,6 @@ vm-browserify@^1.0.1: resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-1.1.2.tgz#78641c488b8e6ca91a75f511e7a3b32a86e5dda0" integrity sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ== -webidl-conversions@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" - integrity sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE= - -whatwg-url@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d" - integrity sha1-lmRU6HZUYuN2RNNib2dCzotwll0= - dependencies: - tr46 "~0.0.3" - webidl-conversions "^3.0.0" - which@^1.3.1: version "1.3.1" resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" @@ -1218,10 +1280,10 @@ wrappy@1: resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= -ws@8.2.3: - version "8.2.3" - resolved "https://registry.yarnpkg.com/ws/-/ws-8.2.3.tgz#63a56456db1b04367d0b721a0b80cae6d8becbba" - integrity sha512-wBuoj1BDpC6ZQ1B7DWQBYVLphPWkm8i9Y0/3YdHjHKHiohOJ1ws+3OccDWtH+PoC9DZD5WOTrJvNbWvjS6JWaA== +ws@8.4.2: + version "8.4.2" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.4.2.tgz#18e749868d8439f2268368829042894b6907aa0b" + integrity sha512-Kbk4Nxyq7/ZWqr/tarI9yIt/+iNNFOjBXEWgTb4ydaNHBNGgvf2QHbS9fdfsndfjFlFwEd4Al+mw83YkaD10ZA== ws@^7.4.6: version "7.5.3" @@ -1247,10 +1309,26 @@ xtend@^4.0.0: resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== -yauzl@^2.10.0: +yauzl@2.10.0, yauzl@^2.10.0: version "2.10.0" resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.10.0.tgz#c7eb17c93e112cb1086fa6d8e51fb0667b79a5f9" integrity sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk= dependencies: buffer-crc32 "~0.2.3" fd-slicer "~1.1.0" + +yazl@2.5.1: + version "2.5.1" + resolved "https://registry.yarnpkg.com/yazl/-/yazl-2.5.1.tgz#a3d65d3dd659a5b0937850e8609f22fffa2b5c35" + integrity sha512-phENi2PLiHnHb6QBVot+dJnaAZ0xosj7p3fWl+znIjBDlnMI2PsZCJZ306BPTFOaHf5qdDEI8x5qFrSOBN5vrw== + dependencies: + buffer-crc32 "~0.2.3" + +zip-stream@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/zip-stream/-/zip-stream-4.1.0.tgz#51dd326571544e36aa3f756430b313576dc8fc79" + integrity sha512-zshzwQW7gG7hjpBlgeQP9RuyPGNxvJdzR8SUM3QhxCnLjWN2E7j3dOvpeDcQoETfHx0urRS7EtmVToql7YpU4A== + dependencies: + archiver-utils "^2.1.0" + compress-commons "^4.1.0" + readable-stream "^3.6.0"