mirror of
https://github.com/penpot/penpot.git
synced 2025-03-28 15:41:25 -05:00
♻️ Refactor exporter
- Migrate from puppeteer to playwright - Fix many lifecycle and resource usage issues - Add redis integration - Enable multiple exportation - Enable asynchronos exportation (with progress reporting)
This commit is contained in:
parent
f0a9889f33
commit
4a9e38a221
21 changed files with 1366 additions and 1017 deletions
|
@ -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"]}
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)))))))
|
||||
|
|
|
@ -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)))
|
||||
|
|
|
@ -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)))
|
||||
|
|
98
exporter/src/app/handlers.cljs
Normal file
98
exporter/src/app/handlers.cljs
Normal file
|
@ -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)))))
|
152
exporter/src/app/handlers/export_frames.cljs
Normal file
152
exporter/src/app/handlers/export_frames.cljs
Normal file
|
@ -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))
|
170
exporter/src/app/handlers/export_shapes.cljs
Normal file
170
exporter/src/app/handlers/export_shapes.cljs
Normal file
|
@ -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))))))))
|
130
exporter/src/app/handlers/resources.cljs
Normal file
130
exporter/src/app/handlers/resources.cljs
Normal file
|
@ -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))))))
|
|
@ -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)))
|
||||
|
||||
|
|
|
@ -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))))))
|
|
@ -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"}})))
|
||||
|
|
@ -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)))
|
54
exporter/src/app/redis.cljs
Normal file
54
exporter/src/app/redis.cljs
Normal file
|
@ -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))))
|
|
@ -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")}))
|
||||
|
||||
|
|
|
@ -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"}))
|
||||
|
||||
|
|
|
@ -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"}))
|
||||
|
||||
|
|
|
@ -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)))))
|
|
@ -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)))))))
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
@ -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"
|
||||
|
|
Loading…
Add table
Reference in a new issue