diff --git a/frontend/.yarn/patches/@zip.js-zip.js-npm-2.7.60-b6b814410b.patch b/frontend/.yarn/patches/@zip.js-zip.js-npm-2.7.60-b6b814410b.patch new file mode 100644 index 0000000000..2a413b3890 --- /dev/null +++ b/frontend/.yarn/patches/@zip.js-zip.js-npm-2.7.60-b6b814410b.patch @@ -0,0 +1,18 @@ +diff --git a/lib/zip-fs.js b/lib/zip-fs.js +index 1444c0f00e5f1ad6c13521f90a7f3c6659d81116..90e38baef5365c2abbcb9337f7ab37f800e883a4 100644 +--- a/lib/zip-fs.js ++++ b/lib/zip-fs.js +@@ -33,12 +33,7 @@ import { initShimAsyncCodec } from "./core/util/stream-codec-shim.js"; + import { terminateWorkers } from "./core/codec-pool.js"; + + let baseURL; +-try { +- baseURL = import.meta.url; +- // eslint-disable-next-line no-unused-vars +-} catch (_) { +- // ignored +-} ++ + configure({ baseURL }); + configureWebWorker(configure); + diff --git a/frontend/package.json b/frontend/package.json index 6bd8f77a0c..960c361112 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -14,7 +14,8 @@ "url": "https://github.com/penpot/penpot" }, "resolutions": { - "@vitejs/plugin-react": "^4.2.0" + "@vitejs/plugin-react": "^4.2.0", + "@zip.js/zip.js@npm:^2.7.44": "patch:@zip.js/zip.js@npm%3A2.7.60#~/.yarn/patches/@zip.js-zip.js-npm-2.7.60-b6b814410b.patch" }, "scripts": { "build:app:assets": "node ./scripts/build-app-assets.js", @@ -108,11 +109,11 @@ "@penpot/svgo": "penpot/svgo#v3.1", "@penpot/text-editor": "portal:./text-editor", "@tokens-studio/sd-transforms": "1.2.11", + "@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", "compression": "^1.7.5", "date-fns": "^4.1.0", "eventsource-parser": "^3.0.1", "js-beautify": "^1.15.4", - "jszip": "^3.10.1", "lodash": "^4.17.21", "lodash.debounce": "^4.0.8", "luxon": "^3.6.1", diff --git a/frontend/src/app/util/zip.cljs b/frontend/src/app/util/zip.cljs index 6b53775f74..0ddf6d90b5 100644 --- a/frontend/src/app/util/zip.cljs +++ b/frontend/src/app/util/zip.cljs @@ -5,32 +5,82 @@ ;; Copyright (c) KALEIDOS INC (ns app.util.zip - "Helpers for make zip file (using jszip)." + "Helpers for make zip file." (:require - ["jszip" :as zip] + ["@zip.js/zip.js" :as zip] + [app.util.array :as array] [promesa.core :as p])) -(defn load - [data] - (zip/loadAsync data)) +(defn reader + [blob] + (cond + (instance? js/Blob blob) + (let [breader (new zip/BlobReader blob)] + (new zip/ZipReader breader)) -(defn get-file - "Gets a single file from the zip archive" - ([zip path] - (get-file zip path "text")) + (instance? js/Uint8Array blob) + (let [breader (new zip/Uint8ArrayReader blob) + zreader (new zip/ZipReader breader #js {:useWebWorkers false})] + zreader) - ([zip path type] - (let [entry (.file zip path)] - (cond - (nil? entry) - (p/rejected (str "File not found: " path)) + (instance? js/ArrayBuffer blob) + (reader (js/Uint8Array. blob)) - (.-dir ^js entry) - (p/resolved {:dir path}) + :else + (throw (ex-info "invalid arguments" + {:type :internal + :code :invalid-type})))) - :else - (->> (.async ^js entry type) - (p/fmap (fn [content] - ;; (js/console.log "zip:process-file" 2 content) - {:path path - :content content}))))))) +(defn blob-writer + [& {:keys [mtype]}] + (new zip/BlobWriter (or mtype "application/octet-stream"))) + +(defn bytes-writer + [] + (new zip/Uint8ArrayWriter)) + +(defn writer + [stream-writer] + (new zip/ZipWriter stream-writer)) + +(defn add + [writer path content] + (assert (instance? zip/ZipWriter writer)) + (cond + (instance? js/Uint8Array content) + (.add writer path (new zip/Uint8ArrayReader content)) + + (instance? js/ArrayBuffer content) + (.add writer path (new zip/Uint8ArrayReader + (new js/Uint8Array content))) + + (instance? js/Blob content) + (.add writer path (new zip/BlobReader content)) + + + (string? content) + (.add writer path (new zip/TextReader content)) + + :else + (throw (ex-info "invalid arguments" + {:type :internal + :code :invalid-type})))) + + +(defn get-entry + [reader path] + (assert (instance? zip/ZipReader reader)) + (->> (.getEntries ^zip/ZipReader reader) + (p/fmap (fn [entries] + (array/find #(= (.-filename ^js %) path) entries))))) + +(defn read-as-text + [entry] + (let [writer (new zip/TextWriter)] + (.getData entry writer))) + +(defn close + [closeable] + (assert (or (instance? zip/ZipReader closeable) + (instance? zip/ZipWriter closeable))) + (.close ^js closeable)) diff --git a/frontend/src/app/worker/import.cljs b/frontend/src/app/worker/import.cljs index 57f611874f..49a1fcd813 100644 --- a/frontend/src/app/worker/import.cljs +++ b/frontend/src/app/worker/import.cljs @@ -30,9 +30,9 @@ (def conjv (fnil conj [])) (defn- read-zip-manifest - [zipfile] - (->> (rx/from (uz/get-file zipfile "manifest.json")) - (rx/map :content) + [zip-reader] + (->> (rx/from (uz/get-entry zip-reader "manifest.json")) + (rx/mapcat uz/read-as-text) (rx/map json/decode))) (defn slurp-uri @@ -121,14 +121,15 @@ (let [mtype (parse-mtype body)] (cond (= "application/zip" mtype) - (->> (rx/from (uz/load body)) - (rx/merge-map read-zip-manifest) - (rx/map - (fn [manifest] - (if (= (:type manifest) "penpot/export-files") - (let [manifest (decode-manifest manifest)] - (assoc file :type :binfile-v3 :files (:files manifest))) - (assoc file :type :legacy-zip :body body))))) + (let [zip-reader (uz/reader body)] + (->> (read-zip-manifest zip-reader) + (rx/map + (fn [manifest] + (if (= (:type manifest) "penpot/export-files") + (let [manifest (decode-manifest manifest)] + (assoc file :type :binfile-v3 :files (:files manifest))) + (assoc file :type :legacy-zip :body body)))) + (rx/finalize (partial uz/close zip-reader)))) (= "application/octet-stream" mtype) (rx/of (assoc file :type :binfile-v1)) diff --git a/frontend/yarn.lock b/frontend/yarn.lock index e347c24655..bb6715974a 100644 --- a/frontend/yarn.lock +++ b/frontend/yarn.lock @@ -2881,10 +2881,17 @@ __metadata: languageName: node linkType: hard -"@zip.js/zip.js@npm:^2.7.44": - version: 2.7.53 - resolution: "@zip.js/zip.js@npm:2.7.53" - checksum: 10c0/883527bf09ce7c312117536c79d5f07e736d87de802a6c19e39ba2e18027499dcb9359df94dfde13c9bcf6118a20b4f26a40f9892ee82d7cac3124d6986b15c8 +"@zip.js/zip.js@npm:2.7.60": + version: 2.7.60 + resolution: "@zip.js/zip.js@npm:2.7.60" + checksum: 10c0/466ff1729e36d9f500011475e230f2edb9c0e6e10f64d542e6ebc006dc70885bc909d69fd0c7b10126bdf722c761359ad1edfe295b6c7fed3169f0f63012a1cd + languageName: node + linkType: hard + +"@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": + version: 2.7.60 + resolution: "@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::version=2.7.60&hash=4a67b2" + checksum: 10c0/37e9a5dd708fd81b08d64b75ea44d70c903071165bbbc571fca7a1cb93f214fab6f63ed3c837a87a0205a6301bc78790c1505197570f112afa5311e3a16d2368 languageName: node linkType: hard @@ -5705,6 +5712,7 @@ __metadata: "@storybook/test-runner": "npm:^0.21.0" "@tokens-studio/sd-transforms": "npm:1.2.11" "@types/node": "npm:^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" autoprefixer: "npm:^10.4.20" compression: "npm:^1.7.5" concurrently: "npm:^9.1.2" @@ -5724,7 +5732,6 @@ __metadata: gulp-svg-sprite: "npm:^2.0.3" js-beautify: "npm:^1.15.4" jsdom: "npm:^26.1.0" - jszip: "npm:^3.10.1" lodash: "npm:^4.17.21" lodash.debounce: "npm:^4.0.8" luxon: "npm:^3.6.1" @@ -6386,13 +6393,6 @@ __metadata: languageName: node linkType: hard -"immediate@npm:~3.0.5": - version: 3.0.6 - resolution: "immediate@npm:3.0.6" - checksum: 10c0/f8ba7ede69bee9260241ad078d2d535848745ff5f6995c7c7cb41cfdc9ccc213f66e10fa5afb881f90298b24a3f7344b637b592beb4f54e582770cdce3f1f039 - languageName: node - linkType: hard - "immutable@npm:^5.0.2": version: 5.0.3 resolution: "immutable@npm:5.0.3" @@ -7686,18 +7686,6 @@ __metadata: languageName: node linkType: hard -"jszip@npm:^3.10.1": - version: 3.10.1 - resolution: "jszip@npm:3.10.1" - dependencies: - lie: "npm:~3.3.0" - pako: "npm:~1.0.2" - readable-stream: "npm:~2.3.6" - setimmediate: "npm:^1.0.5" - checksum: 10c0/58e01ec9c4960383fb8b38dd5f67b83ccc1ec215bf74c8a5b32f42b6e5fb79fada5176842a11409c4051b5b94275044851814a31076bf49e1be218d3ef57c863 - languageName: node - linkType: hard - "klaw-sync@npm:^6.0.0": version: 6.0.0 resolution: "klaw-sync@npm:6.0.0" @@ -7728,15 +7716,6 @@ __metadata: languageName: node linkType: hard -"lie@npm:~3.3.0": - version: 3.3.0 - resolution: "lie@npm:3.3.0" - dependencies: - immediate: "npm:~3.0.5" - checksum: 10c0/56dd113091978f82f9dc5081769c6f3b947852ecf9feccaf83e14a123bc630c2301439ce6182521e5fbafbde88e88ac38314327a4e0493a1bea7e0699a7af808 - languageName: node - linkType: hard - "lilconfig@npm:^3.1.1": version: 3.1.2 resolution: "lilconfig@npm:3.1.2" @@ -8812,13 +8791,6 @@ __metadata: languageName: node linkType: hard -"pako@npm:~1.0.2": - version: 1.0.11 - resolution: "pako@npm:1.0.11" - checksum: 10c0/86dd99d8b34c3930345b8bbeb5e1cd8a05f608eeb40967b293f72fe469d0e9c88b783a8777e4cc7dc7c91ce54c5e93d88ff4b4f060e6ff18408fd21030d9ffbe - languageName: node - linkType: hard - "parse-json@npm:^4.0.0": version: 4.0.0 resolution: "parse-json@npm:4.0.0"