瀏覽代碼

Merge branch 'whiteboards' into enhance/whiteboards-ux

Konstantinos Kaloutas 3 年之前
父節點
當前提交
50b67ffcea

+ 9 - 4
deps/graph-parser/src/logseq/graph_parser/config.cljs

@@ -1,7 +1,8 @@
 (ns logseq.graph-parser.config
   "App config that is shared between graph-parser and rest of app"
   (:require [clojure.set :as set]
-            [clojure.string :as string]))
+            [clojure.string :as string]
+            [goog.object :as gobj]))
 
 (def app-name
   "Copy of frontend.config/app-name. Too small to couple to main app"
@@ -9,7 +10,9 @@
 
 (defonce asset-protocol "assets://")
 (defonce capacitor-protocol "capacitor://")
-(defonce capacitor-protocol-with-prefix (str capacitor-protocol "localhost/_capacitor_file_"))
+(defonce capacitor-prefix "_capacitor_file_")
+(defonce capacitor-protocol-with-prefix (str capacitor-protocol "localhost/" capacitor-prefix))
+(defonce capacitor-x-protocol-with-prefix (str (gobj/getValueByKeys js/globalThis "location" "href") capacitor-prefix))
 
 (defonce local-assets-dir "assets")
 
@@ -22,14 +25,16 @@
   [s]
   (when (string? s)
     (or (string/starts-with? s asset-protocol)
-        (string/starts-with? s capacitor-protocol))))
+        (string/starts-with? s capacitor-protocol)
+        (string/starts-with? s capacitor-x-protocol-with-prefix))))
 
 (defn remove-asset-protocol
   [s]
   (if (local-protocol-asset? s)
     (-> s
         (string/replace-first asset-protocol "")
-        (string/replace-first capacitor-protocol-with-prefix "file://"))
+        (string/replace-first capacitor-protocol-with-prefix "file://")
+        (string/replace-first capacitor-x-protocol-with-prefix "file://"))
     s))
 
 (defonce default-draw-directory "draws")

+ 1 - 1
deps/graph-parser/src/logseq/graph_parser/extract.cljc

@@ -204,7 +204,7 @@
 (defn extract-whiteboard-edn
   "Extracts whiteboard page from given edn file
    Whiteboard page edn is a subset of page schema
-   - it will only contain a single page (for now). The page properties contains 'bindings' etc
+   - it will only contain a single page (for now). The page properties are stored under :logseq.tldraw.* properties and contain 'bindings' etc
    - blocks will be adapted to tldraw shapes. All blocks's parent is the given page."
   [file content {:keys [verbose] :or {verbose true}}]
   (let [_ (when verbose (println "Parsing start: " file))

+ 2 - 1
deps/graph-parser/src/logseq/graph_parser/property.cljs

@@ -60,7 +60,8 @@
    #{:id :custom-id :background-color :background_color :heading :collapsed
      :created-at :updated-at :last-modified-at :created_at :last_modified_at
      :query-table :query-properties :query-sort-by :query-sort-desc :ls-type
-     :hl-type :hl-page :hl-stamp :logseq.macro-name :logseq.macro-arguments}
+     :hl-type :hl-page :hl-stamp :logseq.macro-name :logseq.macro-arguments
+     :logseq.tldraw.page :logseq.tldraw.shape}
    (set (map keyword markers))
    @built-in-extended-properties))
 

+ 1 - 1
package.json

@@ -85,7 +85,7 @@
         "@capacitor/status-bar": "^4.0.0",
         "@excalidraw/excalidraw": "0.10.0",
         "@kanru/rage-wasm": "^0.3.0",
-        "@logseq/capacitor-file-sync": "0.0.10",
+        "@logseq/capacitor-file-sync": "0.0.11",
         "@logseq/react-tweet-embed": "1.3.1-1",
         "@sentry/react": "^6.18.2",
         "@sentry/tracing": "^6.18.2",

+ 1 - 1
resources/package.json

@@ -37,7 +37,7 @@
     "https-proxy-agent": "5.0.0",
     "@sentry/electron": "2.5.1",
     "posthog-js": "1.10.2",
-    "@logseq/rsapi": "0.0.46",
+    "@logseq/rsapi": "0.0.48",
     "electron-deeplink": "1.0.10",
     "abort-controller": "3.0.0"
   },

+ 3 - 0
src/electron/electron/file_sync_rsapi.cljs

@@ -47,6 +47,9 @@
 (defn decrypt-with-passphrase [passphrase data]
   (rsapi/ageDecryptWithPassphrase passphrase data))
 
+(defn cancel-all-requests []
+  (rsapi/cancelAllRequests))
+
 (defonce progress-notify-chan "file-sync-progress")
 (set-progress-callback (fn [error progress-info]
                          (when-not error

+ 3 - 0
src/electron/electron/handler.cljs

@@ -579,6 +579,9 @@
 (defmethod handle :decrypt-with-passphrase [_ args]
   (apply rsapi/decrypt-with-passphrase (rest args)))
 
+(defmethod handle :cancel-all-requests [_ args]
+  (apply rsapi/cancel-all-requests (rest args)))
+
 (defmethod handle :default [args]
   (logger/error "Error: no ipc handler for:" args))
 

+ 8 - 1
src/main/frontend/components/block.cljs

@@ -1895,7 +1895,14 @@
         priority (priority-cp t)
         tags (block-tags-cp t)
         bg-color (:background-color properties)
-        heading (:heading properties)
+        ;; `heading-level` is for backward compatiblity, will remove it in later releases
+        heading-level (:block/heading-level t)
+        heading (or
+                 (and heading-level
+                      (<= heading-level 6)
+                      heading-level)
+                 (:heading properties))
+        heading (if (true? heading) 2 heading)
         elem (if heading
                (keyword (str "h" heading
                              (when block-ref? ".inline")))

+ 47 - 57
src/main/frontend/components/file_sync.cljs

@@ -306,11 +306,8 @@
            (ui/icon "chevron-left" {:style {:font-size 24}}))])]]))
 
 (defn- sort-files
-  [progress files]
-  (sort-by (fn [f]
-             (let [percent (or (:percent (get progress f)) 0)]
-               (if (= percent 100) -1 percent)))
-           > files))
+  [files]
+  (sort-by (fn [f] (or (:size f) 0)) > files))
 
 (rum/defcs ^:large-vars/cleanup-todo indicator <
   rum/reactive
@@ -331,8 +328,8 @@
         sync-progress           (state/sub [:file-sync/progress (second @fs-sync/graphs-txid)])
         _                       (rum/react file-sync-handler/refresh-file-sync-component)
         synced-file-graph?      (file-sync-handler/synced-file-graph? current-repo)
-        uploading-files         (sort-files sync-progress (:current-local->remote-files sync-state))
-        downloading-files       (sort-files sync-progress (:current-remote->local-files sync-state))
+        uploading-files         (sort-files (:current-local->remote-files sync-state))
+        downloading-files       (sort-files (:current-remote->local-files sync-state))
         queuing-files           (:queued-local->remote-files sync-state)
         history-files           (:history sync-state)
         status                  (:state sync-state)
@@ -525,56 +522,49 @@
   [:div.cp__file-sync-related-normal-modal
    [:div.flex.justify-center.pb-4 [:span.icon-wrap (ui/icon "cloud-download")]]
 
-   [:h1.mb-5.text-2xl.text-center.font-bold "Sync a remote graph to local"]
-
-   [:div.folder-tip.flex.flex-col.items-center
-    {:style {:border-bottom-right-radius 0 :border-bottom-left-radius 0}}
-    [:h3
-     [:span.flex.space-x-2.leading-none.pb-1
-      (ui/icon "cloud-lock")
-      [:span (:GraphName graph)]
-      [:span.scale-75 (ui/icon "arrow-right")]
-      [:span (ui/icon "folder")]]]
-    [:h4.px-2.-mb-1.5 [:strong "UUID: "] (:GraphUUID graph)]]
-
-   [:div.-mt-1
-    (ui/button
-      "Open a local directory"
-      :class "w-full rounded-t-none py-4"
-      :on-click #(do
-                   (state/close-modal!)
-                   (fs-sync/<sync-stop)
-                   (->
-                    (page-handler/ls-dir-files!
-                     (fn [{:keys [url]}]
-                       (file-sync-handler/init-remote-graph url graph)
-                       (js/setTimeout (fn [] (repo-handler/refresh-repos!)) 200))
-
-                     {:empty-dir?-or-pred
-                      (fn [ret]
-                        (let [empty-dir? (nil? (second ret))]
-                          (if-let [root (first ret)]
-
-                            ;; verify directory
-                            (-> (if empty-dir?
-                                  (p/resolved nil)
-                                  (if (util/electron?)
-                                    (ipc/ipc :readGraphTxIdInfo root)
-                                    (fs-util/read-graphs-txid-info root)))
-
-                                (p/then (fn [^js info]
-                                          (when (and (not empty-dir?)
-                                                     (or (nil? info)
-                                                         (nil? (second info))
-                                                         (not= (second info) (:GraphUUID graph))))
-                                            (if (js/confirm "This directory is not empty, are you sure to sync the remote graph to it? Make sure to back up the directory first.")
-                                              (p/resolved nil)
-                                              (throw (js/Error. nil)))))))
-
-                            ;; cancel pick a directory
-                            (throw (js/Error. nil)))))})
-                    (p/catch (fn [])))))
-    [:p.text-xs.opacity-50.px-1 (ui/icon "alert-circle") " An empty directory or an existing remote graph!"]]])
+   [:h1.mb-5.text-2xl.text-center.font-bold (util/format "Sync graph \"%s\" to local"
+                                                         (:GraphName graph))]
+
+   (ui/button
+     "Open a local directory"
+     :class "block w-full py-4 mt-4"
+     :on-click #(do
+                  (state/close-modal!)
+                  (fs-sync/<sync-stop)
+                  (->
+                   (page-handler/ls-dir-files!
+                    (fn [{:keys [url]}]
+                      (file-sync-handler/init-remote-graph url graph)
+                      (js/setTimeout (fn [] (repo-handler/refresh-repos!)) 200))
+
+                    {:empty-dir?-or-pred
+                     (fn [ret]
+                       (let [empty-dir? (nil? (second ret))]
+                         (if-let [root (first ret)]
+
+                           ;; verify directory
+                           (-> (if empty-dir?
+                                 (p/resolved nil)
+                                 (if (util/electron?)
+                                   (ipc/ipc :readGraphTxIdInfo root)
+                                   (fs-util/read-graphs-txid-info root)))
+
+                               (p/then (fn [^js info]
+                                         (when (and (not empty-dir?)
+                                                    (or (nil? info)
+                                                        (nil? (second info))
+                                                        (not= (second info) (:GraphUUID graph))))
+                                           (if (js/confirm "This directory is not empty, are you sure to sync the remote graph to it? Make sure to back up the directory first.")
+                                             (p/resolved nil)
+                                             (throw (js/Error. nil)))))))
+
+                           ;; cancel pick a directory
+                           (throw (js/Error. nil)))))})
+                   (p/catch (fn [])))))
+
+   [:div.text-xs.opacity-50.px-1.flex-row.flex.items-center.p-2
+    (ui/icon "alert-circle")
+    [:span.ml-1 " An empty directory or an existing remote graph!"]]])
 
 (defn pick-dest-to-sync-panel [graph]
   (fn []

+ 2 - 0
src/main/frontend/db/model.cljs

@@ -54,6 +54,8 @@
     :block/repeated?
     :block/created-at
     :block/updated-at
+    ;; TODO: remove this in later releases
+    :block/heading-level
     :block/file
     {:block/page [:db/id :block/name :block/original-name :block/journal-day]}
     {:block/_parent ...}])

+ 34 - 19
src/main/frontend/fs/sync.cljs

@@ -657,7 +657,8 @@
   (<update-remote-files [this graph-uuid base-path filepaths local-txid] "local -> remote, return err or txid")
   (<delete-remote-files [this graph-uuid base-path filepaths local-txid] "return err or txid")
   (<encrypt-fnames [this graph-uuid fnames])
-  (<decrypt-fnames [this graph-uuid fnames]))
+  (<decrypt-fnames [this graph-uuid fnames])
+  (<cancel-all-requests [this]))
 
 (defprotocol IRemoteAPI
   (<user-info [this] "user info")
@@ -718,6 +719,8 @@
           (recur (dec n)))
         r))))
 
+(declare <rsapi-cancel-all-requests)
+
 (deftype RSAPI [^:mutable graph-uuid' ^:mutable private-key' ^:mutable public-key']
   IToken
   (<get-token [this]
@@ -765,6 +768,7 @@
   (<update-local-files [this graph-uuid base-path filepaths]
     (println "update-local-files" graph-uuid base-path filepaths)
     (go
+      (<! (<rsapi-cancel-all-requests))
       (let [token (<! (<get-token this))]
         (<! (p->c (ipc/ipc "update-local-files" graph-uuid base-path filepaths token))))))
   (<download-version-files [this graph-uuid base-path filepaths]
@@ -782,6 +786,7 @@
 
   (<update-remote-files [this graph-uuid base-path filepaths local-txid]
     (go
+      (<! (<rsapi-cancel-all-requests))
       (let [token (<! (<get-token this))]
         (<! (<retry-rsapi
              #(p->c (ipc/ipc "update-remote-files" graph-uuid base-path filepaths local-txid token)))))))
@@ -794,10 +799,12 @@
           #(p->c (ipc/ipc "delete-remote-files" graph-uuid base-path filepaths local-txid token)))))))
   (<encrypt-fnames [_ graph-uuid fnames] (go (js->clj (<! (p->c (ipc/ipc "encrypt-fnames" graph-uuid fnames))))))
   (<decrypt-fnames [_ graph-uuid fnames] (go
-                                (let [r (<! (p->c (ipc/ipc "decrypt-fnames" graph-uuid fnames)))]
-                                  (if (instance? ExceptionInfo r)
-                                    (ex-info "decrypt-failed" {:fnames fnames} (ex-cause r))
-                                    (js->clj r))))))
+                                           (let [r (<! (p->c (ipc/ipc "decrypt-fnames" graph-uuid fnames)))]
+                                             (if (instance? ExceptionInfo r)
+                                               (ex-info "decrypt-failed" {:fnames fnames} (ex-cause r))
+                                               (js->clj r)))))
+  (<cancel-all-requests [_]
+    (p->c (ipc/ipc "cancel-all-requests"))))
 
 
 (deftype ^:large-vars/cleanup-todo CapacitorAPI [^:mutable graph-uuid' ^:mutable private-key ^:mutable public-key']
@@ -873,10 +880,10 @@
       (let [token (<! (<get-token this))
             r (<! (<retry-rsapi
                    #(p->c (.updateLocalVersionFiles mobile-util/file-sync
-                                                                (clj->js {:graphUUID graph-uuid
-                                                                          :basePath base-path
-                                                                          :filePaths filepaths
-                                                                          :token token})))))]
+                                                    (clj->js {:graphUUID graph-uuid
+                                                              :basePath base-path
+                                                              :filePaths filepaths
+                                                              :token token})))))]
         r)))
 
   (<delete-local-files [_ graph-uuid base-path filepaths]
@@ -903,15 +910,15 @@
 
   (<delete-remote-files [this graph-uuid _base-path filepaths local-txid]
     (go
-     (let [token (<! (<get-token this))
-           r (<! (p->c (.deleteRemoteFiles mobile-util/file-sync
-                                           (clj->js {:graphUUID graph-uuid
-                                                     :filePaths filepaths
-                                                     :txid local-txid
-                                                     :token token}))))]
-       (if (instance? ExceptionInfo r)
-         r
-         (get (js->clj r) "txid")))))
+      (let [token (<! (<get-token this))
+            r (<! (p->c (.deleteRemoteFiles mobile-util/file-sync
+                                            (clj->js {:graphUUID graph-uuid
+                                                      :filePaths filepaths
+                                                      :txid local-txid
+                                                      :token token}))))]
+        (if (instance? ExceptionInfo r)
+          r
+          (get (js->clj r) "txid")))))
 
   (<encrypt-fnames [_ graph-uuid fnames]
     (go
@@ -927,7 +934,9 @@
                                                     :filePaths fnames}))))]
           (if (instance? ExceptionInfo r)
             (ex-info "decrypt-failed" {:fnames fnames} (ex-cause r))
-            (get (js->clj r) "value"))))))
+            (get (js->clj r) "value")))))
+  (<cancel-all-requests [_]
+    (p->c (.cancelAllRequests mobile-util/file-sync))))
 
 (def rsapi (cond
              (util/electron?)
@@ -942,6 +951,11 @@
              :else
              nil))
 
+(defn <rsapi-cancel-all-requests []
+  (go
+    (when rsapi
+      (<! (<cancel-all-requests rsapi)))))
+
 ;;; ### remote & rs api exceptions
 (defn sync-stop-when-api-flying?
   [exp]
@@ -2803,6 +2817,7 @@
         (when ops-chan (async/close! ops-chan))
         (stop-local->remote! local->remote-syncer)
         (stop-remote->local! remote->local-syncer)
+        (<! (<rsapi-cancel-all-requests))
         (debug/pprint ["stop sync-manager, graph-uuid" graph-uuid "base-path" base-path])
         (swap! *sync-state sync-state--update-state ::stop)
         (loop []

+ 2 - 1
src/main/frontend/handler/editor.cljs

@@ -2795,7 +2795,8 @@
             value (gobj/get input "value")
             c (util/nth-safe value (dec current-pos))
             [key-code k code is-processed?]
-            (if (and (mobile-util/native-android?)
+            (if (and c
+                     (mobile-util/native-android?)
                      (or (= key-code 229)
                          (= key-code 0)))
               [(.charCodeAt value (dec current-pos))

+ 7 - 6
src/main/frontend/handler/events.cljs

@@ -163,12 +163,13 @@
      state/set-state! :sync-graph/init? false)))
 
 (defmethod handle :graph/switch [[_ graph opts]]
-  (if (or (not (false? (get @outliner-file/*writes-finished? graph)))
-          (:sync-graph/init? @state/state))
-    (graph-switch-on-persisted graph opts)
-    (notification/show!
-     "Please wait seconds until all changes are saved for the current graph."
-     :warning)))
+  (let [opts (if (false? (:persist? opts)) opts (assoc opts :persist? true))]
+    (if (or (not (false? (get @outliner-file/*writes-finished? graph)))
+           (:sync-graph/init? @state/state))
+      (graph-switch-on-persisted graph opts)
+     (notification/show!
+      "Please wait seconds until all changes are saved for the current graph."
+      :warning))))
 
 (defmethod handle :graph/pick-dest-to-sync [[_ graph]]
   (state/set-modal!

+ 7 - 7
src/main/frontend/state.cljs

@@ -233,24 +233,24 @@
 
      ;; file-sync
      :file-sync/jstour-inst                   nil
+     :file-sync/onboarding-state            (or (storage/get :file-sync/onboarding-state)
+                                                {:welcome false})
+
      :file-sync/remote-graphs               {:loading false :graphs nil}
      :file-sync/sync-manager                nil
-     :file-sync/sync-state-manager          nil
      :file-sync/sync-state                  nil
      :file-sync/sync-uploading-files        nil
      :file-sync/sync-downloading-files      nil
-     :file-sync/onboarding-state            (or (storage/get :file-sync/onboarding-state)
-                                                {:welcome false})
-
-     :encryption/graph-parsing?             false
-
-     :ui/loading?                           {}
      :file-sync/set-remote-graph-password-result {}
      ;; graph-uuid -> {file-path -> payload}
      :file-sync/progress                    {}
      :file-sync/start                       {}
      ;; graph -> epoch
      :file-sync/last-synced-at              {}
+
+     :encryption/graph-parsing?             false
+
+     :ui/loading?                           {}
      :feature/enable-sync?                  (storage/get :logseq-sync-enabled)
 
      :file/rename-event-chan                (async/chan 100)

+ 22 - 3
tldraw/apps/tldraw-logseq/src/lib/shapes/PencilShape.tsx

@@ -1,9 +1,15 @@
 /* eslint-disable @typescript-eslint/no-explicit-any */
 import { SvgPathUtils, TLDrawShape, TLDrawShapeProps } from '@tldraw/core'
 import { SVGContainer, TLComponentProps } from '@tldraw/react'
+import Vec from '@tldraw/vec'
 import { computed, makeObservable } from 'mobx'
 import { observer } from 'mobx-react-lite'
-import getStroke, { getStrokeOutlinePoints, getStrokePoints, StrokeOptions } from 'perfect-freehand'
+import getStroke, {
+  getStrokeOutlinePoints,
+  getStrokePoints,
+  StrokeOptions,
+  StrokePoint,
+} from 'perfect-freehand'
 import { CustomStyleProps, withClampedStyles } from './style-props'
 
 export interface PencilShapeProps extends TLDrawShapeProps, CustomStyleProps {
@@ -53,6 +59,17 @@ function getDrawStrokePathTDSnapshot(shape: PencilShapeProps) {
   return path
 }
 
+function getSolidStrokePathTDSnapshot(shape: PencilShapeProps) {
+  const { points } = shape
+  if (points.length < 2) return 'M 0 0 L 0 0'
+  const options = getFreehandOptions(shape)
+  const strokePoints = getDrawStrokePoints(shape, options)
+  const last = points[points.length - 1]
+  if (!Vec.isEqual(strokePoints[0].point, last)) strokePoints.push({ point: last } as StrokePoint)
+  const path = SvgPathUtils.getSvgPathFromStrokePoints(strokePoints)
+  return path
+}
+
 export class PencilShape extends TLDrawShape<PencilShapeProps> {
   constructor(props = {} as Partial<PencilShapeProps>) {
     super(props)
@@ -109,11 +126,13 @@ export class PencilShape extends TLDrawShape<PencilShapeProps> {
     } = this
     return (
       <path
+        pointerEvents="none"
         d={pointsPath}
-        strokeWidth={strokeWidth}
+        strokeWidth={strokeWidth / 2}
+        strokeLinejoin="round"
+        strokeLinecap="round"
         stroke={stroke}
         fill={stroke}
-        pointerEvents="all"
         strokeDasharray={strokeType === 'dashed' ? '12 4' : undefined}
       />
     )

+ 35 - 0
tldraw/packages/core/src/utils/SvgPathUtils.ts

@@ -1,3 +1,5 @@
+import type { StrokePoint } from 'perfect-freehand'
+
 export class SvgPathUtils {
   static getCurvedPathForPolygon(points: number[][]) {
     if (points.length < 3) {
@@ -69,6 +71,39 @@ export class SvgPathUtils {
 
     return result
   }
+
+  /**
+   * Turn an array of stroke points into a path of quadradic curves.
+   *
+   * @param points - The stroke points returned from perfect-freehand
+   */
+  static getSvgPathFromStrokePoints(points: StrokePoint[], closed = false): string {
+    const len = points.length
+
+    if (len < 4) {
+      return ``
+    }
+
+    let a = points[0].point
+    let b = points[1].point
+    const c = points[2].point
+
+    let result = `M${a[0].toFixed(2)},${a[1].toFixed(2)} Q${b[0].toFixed(2)},${b[1].toFixed(
+      2
+    )} ${average(b[0], c[0]).toFixed(2)},${average(b[1], c[1]).toFixed(2)} T`
+
+    for (let i = 2, max = len - 1; i < max; i++) {
+      a = points[i].point
+      b = points[i + 1].point
+      result += `${average(a[0], b[0]).toFixed(2)},${average(a[1], b[1]).toFixed(2)} `
+    }
+
+    if (closed) {
+      result += 'Z'
+    }
+
+    return result
+  }
 }
 
 function average(a: number, b: number): number {

+ 4 - 4
yarn.lock

@@ -480,10 +480,10 @@
   resolved "https://registry.yarnpkg.com/@kanru/rage-wasm/-/rage-wasm-0.3.0.tgz#de96b1fda1f781ff401d43b50d0f95b7338c4399"
   integrity sha512-2LMRS27nNJPqFNpRQL7kXG0kgBeIPo63KM6u0Xu6Es5XIS7LP4MFtdHkCg8Pt7IhMM7GuOa2YnzAZgKBxE1lcw==
 
-"@logseq/[email protected]0":
-  version "0.0.10"
-  resolved "https://registry.yarnpkg.com/@logseq/capacitor-file-sync/-/capacitor-file-sync-0.0.10.tgz#36575b369a4fff83e71b282c19cc948d60309809"
-  integrity sha512-O4bCHLym7+DnqCoO57D1Ii6ec6tcZBjp8SzFEYCKE9mvHsX5aFmCA61XUHgNEFovocQ3gBMJvi6GKSJBcGwT3Q==
+"@logseq/[email protected]1":
+  version "0.0.11"
+  resolved "https://registry.yarnpkg.com/@logseq/capacitor-file-sync/-/capacitor-file-sync-0.0.11.tgz#aa84f320d73c292d8dd9e483e0ccf73baa2e021b"
+  integrity sha512-ZCV/2fp8iPpShk+rk+6aH3aFZID7BKhSlyw/f4fcSCapbh6im638GR2fi9RPRc1eg+0vbtrx6UzG7Vbw+Kz2aQ==
 
 "@logseq/[email protected]":
   version "1.3.1-1"