From 5482ee211e8de4578dc17c4c8207902192874764 Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Wed, 18 Mar 2026 09:53:22 +0100 Subject: [PATCH] :bug: Fix unexpected corner case between SES hardening and transit (#8663) * Revert ":bug: Fix plugin sandbox freezing CLJS Proxy constructor breaking Transit encoding" This reverts commit 27a934dcfd579093b066c78d67eba782ba6229cb. * :bug: Fix unexpected corner case between SES hardening and transit The cause of the issue is a race condition between plugin loading and the first time js/Date objects are encoded using transit. Transit encoder populates the prototype of the Date object the first time a Date instance is encoded, but if SES freezes the Date prototype before transit, an strange exception will be raised on encoding any object that contains Date instances. Example of the exception: Cannot define property transit$guid$4a57baf3-8824-4930-915a-fa905479a036, object is not extensible --- frontend/src/app/main.cljs | 12 +++++++++++- frontend/src/app/util/object.cljc | 15 ++++----------- 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/frontend/src/app/main.cljs b/frontend/src/app/main.cljs index 870f8a82bb..7bf4afecc7 100644 --- a/frontend/src/app/main.cljs +++ b/frontend/src/app/main.cljs @@ -8,6 +8,8 @@ (:require [app.common.data.macros :as dm] [app.common.logging :as log] + [app.common.time :as ct] + [app.common.transit :as t] [app.common.types.objects-map] [app.common.uuid :as uuid] [app.config :as cf] @@ -100,6 +102,15 @@ (defn ^:export init [options] + ;; WORKAROUND: we set this really not usefull property for signal a + ;; sideffect and prevent GCC remove it. We need it because we need + ;; to populate the Date prototype with transit related properties + ;; before SES hardning is applied on loading MCP plugin + (unchecked-set js/globalThis "penpotStartDate" + (-> (ct/now) + (t/encode-str) + (t/decode-str))) + ;; Before initializing anything, check if the browser has loaded ;; stale JS from a previous deployment. If so, do a hard reload so ;; the browser fetches fresh assets matching the current index.html. @@ -110,7 +121,6 @@ (do (some-> (unchecked-get options "defaultTranslations") (i18n/set-default-translations)) - (mw/init!) (i18n/init) (cur/init-styles) diff --git a/frontend/src/app/util/object.cljc b/frontend/src/app/util/object.cljc index 9ff10e7b9f..090effd710 100644 --- a/frontend/src/app/util/object.cljc +++ b/frontend/src/app/util/object.cljc @@ -466,17 +466,10 @@ #?(:cljs (def Proxy - (let [ctor (app.util.object/class - :name "Proxy" - :extends js/Object - :constructor (constantly nil))] - ;; Remove the `constructor` data property from the prototype so that - ;; SES `harden` (used by the plugin sandbox) does not traverse from a - ;; proxy instance back to this constructor function and freeze it. - ;; If the constructor is frozen before Transit's `typeTag` helper sets - ;; its cache property, Transit throws "object is not extensible". - (js-delete (.-prototype ctor) "constructor") - ctor))) + (app.util.object/class + :name "Proxy" + :extends js/Object + :constructor (constantly nil)))) (defmacro reify "A domain specific variation of reify that creates anonymous objects