From c363d4d937662113cca46943a6fd79fb3c8a6a6a Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Mon, 29 Sep 2025 13:44:14 +0200 Subject: [PATCH 1/8] :paperclip: Bump library version --- library/CHANGES.md | 5 +++++ library/package.json | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/library/CHANGES.md b/library/CHANGES.md index 6f6a732e86..7c0e8a358f 100644 --- a/library/CHANGES.md +++ b/library/CHANGES.md @@ -1,5 +1,10 @@ # CHANGELOG +## 1.0.8 + +- Update penpot runtime + + ## 1.0.7 - Add the ability to provide refereron creating build context diff --git a/library/package.json b/library/package.json index 622e739252..35f56919df 100644 --- a/library/package.json +++ b/library/package.json @@ -1,6 +1,6 @@ { "name": "@penpot/library", - "version": "1.0.7", + "version": "1.0.8", "license": "MPL-2.0", "author": "Kaleidos INC", "packageManager": "yarn@4.9.1+sha512.f95ce356460e05be48d66401c1ae64ef84d163dd689964962c6888a9810865e39097a5e9de748876c2e0bf89b232d583c33982773e9903ae7a76257270986538", From 21e2ee9904c5996a3f66681337e5d1ef2a46c81c Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Tue, 30 Sep 2025 21:53:04 +0200 Subject: [PATCH 2/8] :bug: Fix dependencies on library --- library/package.json | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/library/package.json b/library/package.json index 35f56919df..0d18437ef7 100644 --- a/library/package.json +++ b/library/package.json @@ -35,13 +35,11 @@ "watch:test": "node --test --watch", "watch": "yarn run clear:shadow-cache && clojure -M:dev:shadow-cljs watch library" }, - "dependencies": { - "@zip.js/zip.js": "patch:@zip.js/zip.js@npm%3A2.7.60#~/.yarn/patches/@zip.js-zip.js-npm-2.7.60-b6b814410b.patch", - "date-fns": "^4.1.0" - }, "devDependencies": { "@types/node": "^22.12.0", + "@zip.js/zip.js": "patch:@zip.js/zip.js@npm%3A2.7.60#~/.yarn/patches/@zip.js-zip.js-npm-2.7.60-b6b814410b.patch", "concurrently": "^9.1.2", + "date-fns": "^4.1.0", "nodemon": "^3.1.9", "source-map-support": "^0.5.21" } From 62563d28d0e5ebdfe6ad8ec0a8cc62153b6ed137 Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Tue, 30 Sep 2025 21:55:17 +0200 Subject: [PATCH 3/8] :paperclip: Bump library version to 1.0.9 Mainly fixes dependencies declaration on package.json file --- library/CHANGES.md | 5 +++++ library/package.json | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/library/CHANGES.md b/library/CHANGES.md index 7c0e8a358f..22cd12ea2e 100644 --- a/library/CHANGES.md +++ b/library/CHANGES.md @@ -1,5 +1,10 @@ # CHANGELOG +## 1.0.9 + +- Fix dependencies declaration on package.json + + ## 1.0.8 - Update penpot runtime diff --git a/library/package.json b/library/package.json index 0d18437ef7..13851f6d6d 100644 --- a/library/package.json +++ b/library/package.json @@ -1,6 +1,6 @@ { "name": "@penpot/library", - "version": "1.0.8", + "version": "1.0.9", "license": "MPL-2.0", "author": "Kaleidos INC", "packageManager": "yarn@4.9.1+sha512.f95ce356460e05be48d66401c1ae64ef84d163dd689964962c6888a9810865e39097a5e9de748876c2e0bf89b232d583c33982773e9903ae7a76257270986538", From 9f2dc06c959b5fd0c55e32550bce13e833b01feb Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Tue, 30 Sep 2025 13:49:30 +0200 Subject: [PATCH 4/8] :sparkles: Add missing srepl helper for disable objects-map feat --- backend/src/app/features/fdata.clj | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/backend/src/app/features/fdata.clj b/backend/src/app/features/fdata.clj index 43cf612068..50ebb10b57 100644 --- a/backend/src/app/features/fdata.clj +++ b/backend/src/app/features/fdata.clj @@ -49,6 +49,20 @@ (update :data update-data) (update :features conj "fdata/objects-map")))) +(defn disable-objects-map + [file & _opts] + (let [update-page + (fn [page] + (update page :objects #(into {} %))) + + update-data + (fn [fdata] + (update fdata :pages-index d/update-vals update-page))] + + (-> file + (update :data update-data) + (update :features disj "fdata/objects-map")))) + (defn process-objects "Apply a function to all objects-map on the file. Usualy used for convert the objects-map instances to plain maps" From 23d5bdd20b29c87cf1efc56f5079c7db3f19914c Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Tue, 30 Sep 2025 14:48:47 +0200 Subject: [PATCH 5/8] :bug: Add missing poppler-tools dependency on devenv --- docker/devenv/Dockerfile | 1 + 1 file changed, 1 insertion(+) diff --git a/docker/devenv/Dockerfile b/docker/devenv/Dockerfile index cdbe7f576a..96546b6ea8 100644 --- a/docker/devenv/Dockerfile +++ b/docker/devenv/Dockerfile @@ -310,6 +310,7 @@ RUN set -ex; \ fonts-wqy-zenhei \ fonts-tlwg-loma-otf \ fonts-freefont-ttf \ + poppler-utils \ \ libasound2t64 \ libatk-bridge2.0-0t64 \ From d0f34f06a9ff7fb766748d80d72be814ccdf97c4 Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Tue, 30 Sep 2025 14:52:42 +0200 Subject: [PATCH 6/8] :recycle: Make the exporter build as esm module --- exporter/deps.edn | 2 +- exporter/package.json | 3 ++- exporter/scripts/build | 3 --- exporter/shadow-cljs.edn | 17 +++++++++++++---- exporter/src/app/browser.cljs | 2 +- exporter/src/app/core.cljs | 12 ++++++------ exporter/src/app/http.cljs | 11 ++++++----- exporter/src/app/redis.cljs | 2 +- exporter/yarn.lock | 16 ++++++++-------- 9 files changed, 38 insertions(+), 30 deletions(-) diff --git a/exporter/deps.edn b/exporter/deps.edn index 6f93671f2a..2d74f0efa7 100644 --- a/exporter/deps.edn +++ b/exporter/deps.edn @@ -14,7 +14,7 @@ :dev {:extra-deps - {thheller/shadow-cljs {:mvn/version "3.1.5"}}} + {thheller/shadow-cljs {:mvn/version "3.2.1"}}} :shadow-cljs {:main-opts ["-m" "shadow.cljs.devtools.cli"] diff --git a/exporter/package.json b/exporter/package.json index ab394fe62d..5db4dc52c8 100644 --- a/exporter/package.json +++ b/exporter/package.json @@ -9,13 +9,14 @@ "type": "git", "url": "https://github.com/penpot/penpot" }, + "type": "module", "dependencies": { "archiver": "^7.0.1", "cookies": "^0.9.1", + "date-fns": "^4.1.0", "generic-pool": "^3.9.0", "inflation": "^2.1.0", "ioredis": "^5.6.1", - "luxon": "^3.6.1", "playwright": "^1.53.0", "raw-body": "^3.0.0", "svgo": "penpot/svgo#v3.1", diff --git a/exporter/scripts/build b/exporter/scripts/build index 4bd911fc00..26763973e2 100755 --- a/exporter/scripts/build +++ b/exporter/scripts/build @@ -13,9 +13,6 @@ rm -rf target # Build the application clojure -M:dev:shadow-cljs release main; -# Remove source -rm -rf target/app; - # Copy package*.json files cp ../.yarnrc.yml target/; cp yarn.lock target/; diff --git a/exporter/shadow-cljs.edn b/exporter/shadow-cljs.edn index 9107cbcb7a..ae963cf311 100644 --- a/exporter/shadow-cljs.edn +++ b/exporter/shadow-cljs.edn @@ -3,13 +3,22 @@ :builds {:main - {:target :node-script - :main app.core/main - :output-to "target/app.js" - :output-dir "target/app/" + {:target :esm + :runtime :node + :output-dir "target/" :devtools {:before-load-async app.core/stop :after-load app.core/start} + :modules + {:app + {:entries [] + :init-fn app.core/main}} + + :js-options + {:entry-keys ["module" "browser" "main"] + :export-conditions ["module" "import", "browser" "require" "default"] + :js-provider :import} + :compiler-options {:output-feature-set :es2020 :output-wrapper false} diff --git a/exporter/src/app/browser.cljs b/exporter/src/app/browser.cljs index 46330ced58..816fb1c954 100644 --- a/exporter/src/app/browser.cljs +++ b/exporter/src/app/browser.cljs @@ -7,7 +7,7 @@ (ns app.browser (:require ["generic-pool" :as gp] - ["generic-pool/lib/errors" :as gpe] + ["generic-pool/lib/errors.js" :as gpe] ["playwright" :as pw] [app.common.exceptions :as ex] [app.common.logging :as l] diff --git a/exporter/src/app/core.cljs b/exporter/src/app/core.cljs index 6d30b9220d..dae498f5d3 100644 --- a/exporter/src/app/core.cljs +++ b/exporter/src/app/core.cljs @@ -6,7 +6,7 @@ (ns app.core (:require - ["process" :as proc] + ["node:process" :as proc] [app.browser :as bwr] [app.common.logging :as l] [app.config :as cf] @@ -41,9 +41,9 @@ (http/stop) (done))) -(proc/on "uncaughtException" - (fn [cause] - (js/console.error cause))) +(.on proc/default "uncaughtException" + (fn [cause] + (js/console.error cause))) -(proc/on "SIGTERM" (fn [] (proc/exit 0))) -(proc/on "SIGINT" (fn [] (proc/exit 0))) +(.on proc/default "SIGTERM" (fn [] (proc/exit 0))) +(.on proc/default "SIGINT" (fn [] (proc/exit 0))) diff --git a/exporter/src/app/http.cljs b/exporter/src/app/http.cljs index acfb6e909d..0024ce8b86 100644 --- a/exporter/src/app/http.cljs +++ b/exporter/src/app/http.cljs @@ -6,11 +6,11 @@ (ns app.http (:require - ["cookies" :as Cookies] - ["http" :as http] - ["inflation" :as inflate] - ["raw-body" :as raw-body] - ["stream" :as stream] + ["cookies$default" :as Cookies] + ["inflation$default" :as inflate] + ["node:http" :as http] + ["node:stream$default" :as stream] + ["raw-body$default" :as raw-body] [app.common.logging :as l] [app.common.transit :as t] [app.config :as cf] @@ -169,6 +169,7 @@ (wrap-error handlers/on-error)) server (create-server handler) port (cf/get :http-server-port 6061)] + (.listen server port) (l/info :hint "welcome to penpot" :module "exporter" diff --git a/exporter/src/app/redis.cljs b/exporter/src/app/redis.cljs index b04ccd0dee..0cc38ba3a9 100644 --- a/exporter/src/app/redis.cljs +++ b/exporter/src/app/redis.cljs @@ -18,7 +18,7 @@ (defn- create-client [uri] - (let [^js client (new redis uri)] + (let [^js client (new redis/default uri)] (.on client "connect" (fn [] (l/info :hint "redis connection established" :uri uri))) (.on client "error" diff --git a/exporter/yarn.lock b/exporter/yarn.lock index ab798ac2f5..cb28ada3ae 100644 --- a/exporter/yarn.lock +++ b/exporter/yarn.lock @@ -411,6 +411,13 @@ __metadata: languageName: node linkType: hard +"date-fns@npm:^4.1.0": + version: 4.1.0 + resolution: "date-fns@npm:4.1.0" + checksum: 10c0/b79ff32830e6b7faa009590af6ae0fb8c3fd9ffad46d930548fbb5acf473773b4712ae887e156ba91a7b3dc30591ce0f517d69fd83bd9c38650fdc03b4e0bac8 + languageName: node + linkType: hard + "debug@npm:4, debug@npm:^4.3.4": version: 4.4.1 resolution: "debug@npm:4.4.1" @@ -553,10 +560,10 @@ __metadata: dependencies: archiver: "npm:^7.0.1" cookies: "npm:^0.9.1" + date-fns: "npm:^4.1.0" generic-pool: "npm:^3.9.0" inflation: "npm:^2.1.0" ioredis: "npm:^5.6.1" - luxon: "npm:^3.6.1" playwright: "npm:^1.53.0" raw-body: "npm:^3.0.0" source-map-support: "npm:^0.5.21" @@ -859,13 +866,6 @@ __metadata: languageName: node linkType: hard -"luxon@npm:^3.6.1": - version: 3.6.1 - resolution: "luxon@npm:3.6.1" - checksum: 10c0/906d57a9dc4d1de9383f2e9223e378c298607c1b4d17b6657b836a3cd120feb1c1de3b5d06d846a3417e1ca764de8476e8c23b3cd4083b5cdb870adcb06a99d5 - languageName: node - linkType: hard - "make-fetch-happen@npm:^14.0.3": version: 14.0.3 resolution: "make-fetch-happen@npm:14.0.3" From 3b81c1d7509dea1ff9ca76bf61a353310120afa7 Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Wed, 1 Oct 2025 10:47:47 +0200 Subject: [PATCH 7/8] Revert ":recycle: Make the exporter build as esm module" This reverts commit d0f34f06a9ff7fb766748d80d72be814ccdf97c4. --- exporter/deps.edn | 2 +- exporter/package.json | 3 +-- exporter/scripts/build | 3 +++ exporter/shadow-cljs.edn | 17 ++++------------- exporter/src/app/browser.cljs | 2 +- exporter/src/app/core.cljs | 12 ++++++------ exporter/src/app/http.cljs | 11 +++++------ exporter/src/app/redis.cljs | 2 +- exporter/yarn.lock | 16 ++++++++-------- 9 files changed, 30 insertions(+), 38 deletions(-) diff --git a/exporter/deps.edn b/exporter/deps.edn index 2d74f0efa7..6f93671f2a 100644 --- a/exporter/deps.edn +++ b/exporter/deps.edn @@ -14,7 +14,7 @@ :dev {:extra-deps - {thheller/shadow-cljs {:mvn/version "3.2.1"}}} + {thheller/shadow-cljs {:mvn/version "3.1.5"}}} :shadow-cljs {:main-opts ["-m" "shadow.cljs.devtools.cli"] diff --git a/exporter/package.json b/exporter/package.json index 5db4dc52c8..ab394fe62d 100644 --- a/exporter/package.json +++ b/exporter/package.json @@ -9,14 +9,13 @@ "type": "git", "url": "https://github.com/penpot/penpot" }, - "type": "module", "dependencies": { "archiver": "^7.0.1", "cookies": "^0.9.1", - "date-fns": "^4.1.0", "generic-pool": "^3.9.0", "inflation": "^2.1.0", "ioredis": "^5.6.1", + "luxon": "^3.6.1", "playwright": "^1.53.0", "raw-body": "^3.0.0", "svgo": "penpot/svgo#v3.1", diff --git a/exporter/scripts/build b/exporter/scripts/build index 26763973e2..4bd911fc00 100755 --- a/exporter/scripts/build +++ b/exporter/scripts/build @@ -13,6 +13,9 @@ rm -rf target # Build the application clojure -M:dev:shadow-cljs release main; +# Remove source +rm -rf target/app; + # Copy package*.json files cp ../.yarnrc.yml target/; cp yarn.lock target/; diff --git a/exporter/shadow-cljs.edn b/exporter/shadow-cljs.edn index ae963cf311..9107cbcb7a 100644 --- a/exporter/shadow-cljs.edn +++ b/exporter/shadow-cljs.edn @@ -3,22 +3,13 @@ :builds {:main - {:target :esm - :runtime :node - :output-dir "target/" + {:target :node-script + :main app.core/main + :output-to "target/app.js" + :output-dir "target/app/" :devtools {:before-load-async app.core/stop :after-load app.core/start} - :modules - {:app - {:entries [] - :init-fn app.core/main}} - - :js-options - {:entry-keys ["module" "browser" "main"] - :export-conditions ["module" "import", "browser" "require" "default"] - :js-provider :import} - :compiler-options {:output-feature-set :es2020 :output-wrapper false} diff --git a/exporter/src/app/browser.cljs b/exporter/src/app/browser.cljs index 816fb1c954..46330ced58 100644 --- a/exporter/src/app/browser.cljs +++ b/exporter/src/app/browser.cljs @@ -7,7 +7,7 @@ (ns app.browser (:require ["generic-pool" :as gp] - ["generic-pool/lib/errors.js" :as gpe] + ["generic-pool/lib/errors" :as gpe] ["playwright" :as pw] [app.common.exceptions :as ex] [app.common.logging :as l] diff --git a/exporter/src/app/core.cljs b/exporter/src/app/core.cljs index dae498f5d3..6d30b9220d 100644 --- a/exporter/src/app/core.cljs +++ b/exporter/src/app/core.cljs @@ -6,7 +6,7 @@ (ns app.core (:require - ["node:process" :as proc] + ["process" :as proc] [app.browser :as bwr] [app.common.logging :as l] [app.config :as cf] @@ -41,9 +41,9 @@ (http/stop) (done))) -(.on proc/default "uncaughtException" - (fn [cause] - (js/console.error cause))) +(proc/on "uncaughtException" + (fn [cause] + (js/console.error cause))) -(.on proc/default "SIGTERM" (fn [] (proc/exit 0))) -(.on proc/default "SIGINT" (fn [] (proc/exit 0))) +(proc/on "SIGTERM" (fn [] (proc/exit 0))) +(proc/on "SIGINT" (fn [] (proc/exit 0))) diff --git a/exporter/src/app/http.cljs b/exporter/src/app/http.cljs index 0024ce8b86..acfb6e909d 100644 --- a/exporter/src/app/http.cljs +++ b/exporter/src/app/http.cljs @@ -6,11 +6,11 @@ (ns app.http (:require - ["cookies$default" :as Cookies] - ["inflation$default" :as inflate] - ["node:http" :as http] - ["node:stream$default" :as stream] - ["raw-body$default" :as raw-body] + ["cookies" :as Cookies] + ["http" :as http] + ["inflation" :as inflate] + ["raw-body" :as raw-body] + ["stream" :as stream] [app.common.logging :as l] [app.common.transit :as t] [app.config :as cf] @@ -169,7 +169,6 @@ (wrap-error handlers/on-error)) server (create-server handler) port (cf/get :http-server-port 6061)] - (.listen server port) (l/info :hint "welcome to penpot" :module "exporter" diff --git a/exporter/src/app/redis.cljs b/exporter/src/app/redis.cljs index 0cc38ba3a9..b04ccd0dee 100644 --- a/exporter/src/app/redis.cljs +++ b/exporter/src/app/redis.cljs @@ -18,7 +18,7 @@ (defn- create-client [uri] - (let [^js client (new redis/default uri)] + (let [^js client (new redis uri)] (.on client "connect" (fn [] (l/info :hint "redis connection established" :uri uri))) (.on client "error" diff --git a/exporter/yarn.lock b/exporter/yarn.lock index cb28ada3ae..ab798ac2f5 100644 --- a/exporter/yarn.lock +++ b/exporter/yarn.lock @@ -411,13 +411,6 @@ __metadata: languageName: node linkType: hard -"date-fns@npm:^4.1.0": - version: 4.1.0 - resolution: "date-fns@npm:4.1.0" - checksum: 10c0/b79ff32830e6b7faa009590af6ae0fb8c3fd9ffad46d930548fbb5acf473773b4712ae887e156ba91a7b3dc30591ce0f517d69fd83bd9c38650fdc03b4e0bac8 - languageName: node - linkType: hard - "debug@npm:4, debug@npm:^4.3.4": version: 4.4.1 resolution: "debug@npm:4.4.1" @@ -560,10 +553,10 @@ __metadata: dependencies: archiver: "npm:^7.0.1" cookies: "npm:^0.9.1" - date-fns: "npm:^4.1.0" generic-pool: "npm:^3.9.0" inflation: "npm:^2.1.0" ioredis: "npm:^5.6.1" + luxon: "npm:^3.6.1" playwright: "npm:^1.53.0" raw-body: "npm:^3.0.0" source-map-support: "npm:^0.5.21" @@ -866,6 +859,13 @@ __metadata: languageName: node linkType: hard +"luxon@npm:^3.6.1": + version: 3.6.1 + resolution: "luxon@npm:3.6.1" + checksum: 10c0/906d57a9dc4d1de9383f2e9223e378c298607c1b4d17b6657b836a3cd120feb1c1de3b5d06d846a3417e1ca764de8476e8c23b3cd4083b5cdb870adcb06a99d5 + languageName: node + linkType: hard + "make-fetch-happen@npm:^14.0.3": version: 14.0.3 resolution: "make-fetch-happen@npm:14.0.3" From 01ef55e4f48c3b31bea436ff75b30235260a87f8 Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Wed, 1 Oct 2025 10:48:24 +0200 Subject: [PATCH 8/8] Revert ":sparkles: Add minor improvement to cljs impl logging" This reverts commit 960b76f76036c91f8c8980c4958bee699a69c148. --- common/src/app/common/logging.cljc | 58 +++++++++++++----------------- 1 file changed, 25 insertions(+), 33 deletions(-) diff --git a/common/src/app/common/logging.cljc b/common/src/app/common/logging.cljc index e678152b12..7a4df8ebef 100644 --- a/common/src/app/common/logging.cljc +++ b/common/src/app/common/logging.cljc @@ -49,7 +49,6 @@ [app.common.exceptions :as ex] [app.common.pprint :as pp] [app.common.schema :as sm] - [app.common.time :as ct] [app.common.uuid :as uuid] [cuerdas.core :as str] [promesa.exec :as px] @@ -222,42 +221,36 @@ #?(:clj (inst-ms (java.time.Instant/now)) :cljs (js/Date.now))) -(defn emit-log - [props cause context logger level sync?] - (let [props (cond-> props sync? deref) - ts (current-timestamp) - gcontext *context* - logfn (fn [] - (let [props (if sync? props (deref props)) - props (into (d/ordered-map) props) - context (if (and (empty? gcontext) - (empty? context)) - {} - (d/without-nils (merge gcontext context))) - - lrecord {::id (uuid/next) - ::timestamp ts - ::message (delay (build-message props)) - ::props props - ::context context - ::level level - ::logger logger} - lrecord (cond-> lrecord - (some? cause) - (assoc ::cause cause - ::trace (delay (build-stack-trace cause))))] - (swap! log-record (constantly lrecord))))] - (if sync? - (logfn) - (px/exec! *default-executor* logfn)))) - (defmacro log! "Emit a new log record to the global log-record state (asynchronously). " [& props] (let [{:keys [::level ::logger ::context ::sync? cause] :or {sync? false}} props props (into [] msg-props-xf props)] `(when (enabled? ~logger ~level) - (emit-log (delay ~props) ~cause ~context ~logger ~level ~sync?)))) + (let [props# (cond-> (delay ~props) ~sync? deref) + ts# (current-timestamp) + context# *context* + logfn# (fn [] + (let [props# (if ~sync? props# (deref props#)) + props# (into (d/ordered-map) props#) + cause# ~cause + context# (d/without-nils + (merge context# ~context)) + lrecord# {::id (uuid/next) + ::timestamp ts# + ::message (delay (build-message props#)) + ::props props# + ::context context# + ::level ~level + ::logger ~logger} + lrecord# (cond-> lrecord# + (some? cause#) + (assoc ::cause cause# + ::trace (delay (build-stack-trace cause#))))] + (swap! log-record (constantly lrecord#))))] + (if ~sync? + (logfn#) + (px/exec! *default-executor* logfn#)))))) #?(:clj (defn slf4j-log-handler @@ -283,8 +276,7 @@ (when (enabled? logger level) (let [hstyles (str/ffmt "font-weight: 600; color: %" (level->color level)) mstyles (str/ffmt "font-weight: 300; color: %" (level->color level)) - ts (ct/format-inst (ct/now) "kk:mm:ss.SSSS") - header (str/concat "%c" (level->name level) " " ts " [" logger "] ") + header (str/concat "%c" (level->name level) " [" logger "] ") message (str/concat header "%c" @message)] (js/console.group message hstyles mstyles)