Преглед изворни кода

Merge branch 'master' into feat/publish

Tienson Qin пре 2 година
родитељ
комит
2df645ae37
100 измењених фајлова са 8492 додато и 1406 уклоњено
  1. 6 2
      .clj-kondo/config.edn
  2. 0 1
      .clj-kondo/hooks/path_invalid_construct.clj
  3. 15 0
      .clj-kondo/hooks/regex_checks.clj
  4. 67 0
      .github/workflows/logseq-common.yml
  5. 2 2
      android/app/build.gradle
  6. 1 0
      deps.edn
  7. 9 0
      deps/common/.clj-kondo/config.edn
  8. 1 0
      deps/common/.gitignore
  9. 29 0
      deps/common/README.md
  10. 8 0
      deps/common/deps.edn
  11. 311 0
      deps/common/src/logseq/common/path.cljs
  12. 47 0
      deps/common/test/logseq/common/path_test.cljs
  13. 1 1
      deps/db/src/logseq/db/schema.cljs
  14. 1 1
      deps/graph-parser/src/logseq/graph_parser/config.cljs
  15. 12 12
      deps/graph-parser/src/logseq/graph_parser/extract.cljc
  16. 7 0
      docs/dev-practices.md
  17. 8 3
      e2e-tests/editor.spec.ts
  18. 1 7
      e2e-tests/fixtures.ts
  19. 4 3
      e2e-tests/hotkey.spec.ts
  20. 4 0
      e2e-tests/logseq-url.spec.ts
  21. 1 1
      e2e-tests/page-rename.spec.ts
  22. 2 2
      e2e-tests/page-search.spec.ts
  23. 12 19
      e2e-tests/utils.ts
  24. 59 8
      e2e-tests/whiteboards.spec.ts
  25. 1 0
      externs.js
  26. 4 4
      ios/App/App.xcodeproj/project.pbxproj
  27. 2 0
      packages/amplify/.gitignore
  28. 16 0
      packages/amplify/examples/index.html
  29. 87 0
      packages/amplify/examples/index.tsx
  30. 42 0
      packages/amplify/package.json
  31. 60 0
      packages/amplify/src/LSAuthenticator.tsx
  32. 99 0
      packages/amplify/src/amplify.ts
  33. 5516 0
      packages/amplify/yarn.lock
  34. 1 0
      public/index.html
  35. 0 0
      resources/css/amplify.css
  36. 1 0
      resources/electron.html
  37. 1 0
      resources/index.html
  38. 0 0
      resources/js/amplify.js
  39. 1 1
      resources/package.json
  40. 10 10
      src/electron/electron/backup_file.cljs
  41. 3 3
      src/electron/electron/configs.cljs
  42. 22 22
      src/electron/electron/core.cljs
  43. 4 4
      src/electron/electron/git.cljs
  44. 34 30
      src/electron/electron/handler.cljs
  45. 11 11
      src/electron/electron/plugin.cljs
  46. 4 4
      src/electron/electron/search.cljs
  47. 2 2
      src/electron/electron/server.cljs
  48. 4 4
      src/electron/electron/updater.cljs
  49. 0 3
      src/electron/electron/url.cljs
  50. 9 8
      src/electron/electron/utils.cljs
  51. 8 8
      src/electron/electron/window.cljs
  52. 142 137
      src/main/electron/listener.cljs
  53. 89 59
      src/main/frontend/components/block.cljs
  54. 1 1
      src/main/frontend/components/block.css
  55. 4 1
      src/main/frontend/components/content.cljs
  56. 2 1
      src/main/frontend/components/export.cljs
  57. 25 17
      src/main/frontend/components/file.cljs
  58. 48 56
      src/main/frontend/components/file_sync.cljs
  59. 6 4
      src/main/frontend/components/header.cljs
  60. 11 11
      src/main/frontend/components/page.cljs
  61. 12 9
      src/main/frontend/components/page_menu.cljs
  62. 41 7
      src/main/frontend/components/plugins.cljs
  63. 4 0
      src/main/frontend/components/plugins.css
  64. 19 7
      src/main/frontend/components/query/builder.cljs
  65. 10 1
      src/main/frontend/components/query/builder.css
  66. 47 34
      src/main/frontend/components/query_table.cljs
  67. 10 13
      src/main/frontend/components/repo.cljs
  68. 11 1
      src/main/frontend/components/right_sidebar.cljs
  69. 4 5
      src/main/frontend/components/settings.cljs
  70. 11 12
      src/main/frontend/components/sidebar.cljs
  71. 56 0
      src/main/frontend/components/user/config.js
  72. 87 0
      src/main/frontend/components/user/login.cljs
  73. 141 0
      src/main/frontend/components/user/login.css
  74. 7 22
      src/main/frontend/components/whiteboard.cljs
  75. 1 1
      src/main/frontend/components/whiteboard.css
  76. 99 84
      src/main/frontend/config.cljs
  77. 1 2
      src/main/frontend/core.cljs
  78. 15 12
      src/main/frontend/db.cljs
  79. 18 12
      src/main/frontend/db/conn.cljs
  80. 75 10
      src/main/frontend/db/migrate.cljs
  81. 1 2
      src/main/frontend/db/model.cljs
  82. 0 9
      src/main/frontend/dicts.cljc
  83. 2 2
      src/main/frontend/extensions/pdf/assets.cljs
  84. 2 2
      src/main/frontend/extensions/pdf/core.cljs
  85. 3 1
      src/main/frontend/extensions/tldraw.cljs
  86. 118 101
      src/main/frontend/fs.cljs
  87. 0 40
      src/main/frontend/fs/bfs.cljs
  88. 157 158
      src/main/frontend/fs/capacitor_fs.cljs
  89. 101 0
      src/main/frontend/fs/memory_fs.cljs
  90. 285 156
      src/main/frontend/fs/nfs.cljs
  91. 76 76
      src/main/frontend/fs/node.cljs
  92. 23 9
      src/main/frontend/fs/protocol.cljs
  93. 29 25
      src/main/frontend/fs/sync.cljs
  94. 76 49
      src/main/frontend/fs/watcher_handler.cljs
  95. 28 26
      src/main/frontend/handler.cljs
  96. 4 3
      src/main/frontend/handler/assets.cljs
  97. 26 12
      src/main/frontend/handler/code.cljs
  98. 4 2
      src/main/frontend/handler/common.cljs
  99. 7 32
      src/main/frontend/handler/common/file.cljs
  100. 3 6
      src/main/frontend/handler/config.cljs

+ 6 - 2
.clj-kondo/config.edn

@@ -11,6 +11,7 @@
 
  :linters
  {:path-invalid-construct/string-join {:level :info}
+  :regex-checks/double-escaped-regex {:level :warning}
   :aliased-namespace-symbol {:level :warning}
   ;; Disable until it doesn't trigger false positives on rum/defcontext
   :earmuffed-var-not-dynamic {:level :off}
@@ -52,7 +53,7 @@
              frontend.format.mldoc mldoc
              frontend.format.block block
              frontend.fs fs
-             frontend.fs.bfs bfs
+             frontend.fs.memory-fs memory-fs
              frontend.fs.capacitor-fs capacitor-fs
              frontend.fs.nfs nfs
              frontend.handler.extract extract
@@ -92,6 +93,7 @@
              frontend.util.url url-util
              frontend.util.thingatpt thingatpt
              lambdaisland.glogi log
+             logseq.common.path path
              logseq.graph-parser graph-parser
              logseq.graph-parser.text text
              logseq.graph-parser.block gp-block
@@ -104,6 +106,7 @@
              logseq.graph-parser.util.db db-util
              logseq.graph-parser.date-time-util date-time-util
              medley.core medley
+             "path" node-path
              promesa.core p}}
 
   :namespace-name-mismatch {:level :warning}
@@ -111,7 +114,8 @@
 
  :hooks {:analyze-call {rum.core/defc hooks.rum/defc
                         rum.core/defcs hooks.rum/defcs
-                        clojure.string/join hooks.path-invalid-construct/string-join}}
+                        clojure.string/join hooks.path-invalid-construct/string-join
+                        clojure.string/replace hooks.regex-checks/double-escaped-regex}}
  :lint-as {promesa.core/let clojure.core/let
            promesa.core/loop clojure.core/loop
            promesa.core/recur clojure.core/recur

+ 0 - 1
.clj-kondo/hooks/path_invalid_construct.clj

@@ -7,7 +7,6 @@
 (defn string-join
   [{:keys [node]}]
   (let [[_ sep-v & _args] (:children node)]
-    ;; (prn :string-join)
     (when (and (api/string-node? sep-v)
                (= ["/"] (:lines sep-v)))
       (api/reg-finding! (assoc (meta node)

+ 15 - 0
.clj-kondo/hooks/regex_checks.clj

@@ -0,0 +1,15 @@
+(ns hooks.regex-checks
+  "This hook try to find out those error-prone double escaping regex expressions"
+  (:require [clj-kondo.hooks-api :as api]))
+
+(def double-escaped-checker #"\(re-pattern .*\\\\\\\\[\?\#\|\.\^\$\\\+].*\)")
+
+(defn double-escaped-regex
+  [{:keys [node]}]
+  (let [[_ _content regex & _args] (:children node)
+        regex-string (str (api/sexpr regex))]
+    (when (and (= (api/tag regex) :regex)
+               (re-matches double-escaped-checker regex-string))
+     (api/reg-finding! (assoc (meta regex)
+                             :message (str "double slash (\\\\) found in this regular expression followed by a regex special character (, + , * , ? , ^ , $ , | , \\ ), have you mistakenly double escaped a special character? Only escaping one-time is required. No escape is required in character class []. (use #_{:clj-kondo/ignore [:regex-checks/double-escaped-regex]} to ignore)")
+                             :type :regex-checks/double-escaped-regex)))))

+ 67 - 0
.github/workflows/logseq-common.yml

@@ -0,0 +1,67 @@
+name: logseq/common CI
+
+on:
+  # Path filters ensure jobs only kick off if a change is made to common
+  push:
+    branches: [master]
+    paths:
+      - 'deps/common/**'
+      - '.github/workflows/logseq-common.yml'
+      - '!deps/common/**.md'
+  pull_request:
+    branches: [master]
+    paths:
+      - 'deps/common/**'
+      - '.github/workflows/logseq-common.yml'
+      - '!deps/common/**.md'
+
+defaults:
+  run:
+    working-directory: deps/common
+
+env:
+  CLOJURE_VERSION: '1.10.1.763'
+  JAVA_VERSION: '11'
+  # This is the latest node version we can run.
+  NODE_VERSION: '18'
+  BABASHKA_VERSION: '1.0.168'
+
+jobs:
+  test:
+    runs-on: ubuntu-latest
+
+    steps:
+      - name: Checkout
+        uses: actions/checkout@v3
+
+      - name: Set up Java
+        uses: actions/setup-java@v3
+        with:
+          distribution: 'zulu'
+          java-version: ${{ env.JAVA_VERSION }}
+
+      - name: Set up Clojure
+        uses: DeLaGuardo/[email protected]
+        with:
+          cli: ${{ env.CLOJURE_VERSION }}
+          bb: ${{ env.BABASHKA_VERSION }}
+
+      - name: Run clj-kondo lint
+        run: clojure -M:clj-kondo --parallel --lint src test
+
+      - name: Clojure cache
+        uses: actions/cache@v3
+        id: clojure-deps
+        with:
+          path: |
+            ~/.m2/repository
+            ~/.gitlibs
+          key: ${{ runner.os }}-clojure-deps-${{ hashFiles('deps.edn') }}
+          restore-keys: ${{ runner.os }}-clojure-deps-
+
+      - name: Fetch Clojure deps
+        if: steps.clojure-deps.outputs.cache-hit != 'true'
+        run: clojure -A:test -P
+
+      - name: Run ClojureScript tests
+        run: clojure -M:test

+ 2 - 2
android/app/build.gradle

@@ -6,8 +6,8 @@ android {
         applicationId "com.logseq.app"
         minSdkVersion rootProject.ext.minSdkVersion
         targetSdkVersion rootProject.ext.targetSdkVersion
-        versionCode 52
-        versionName "0.8.18"
+        versionCode 54
+        versionName "0.9.1"
         testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
         aaptOptions {
              // Files and dirs to omit from the packaged assets dir, modified to accommodate modern web apps.

+ 1 - 0
deps.edn

@@ -27,6 +27,7 @@
   camel-snake-kebab/camel-snake-kebab   {:mvn/version "0.4.2"}
   instaparse/instaparse                 {:mvn/version "1.4.10"}
   org.clojars.mmb90/cljs-cache          {:mvn/version "0.1.4"}
+  logseq/common                         {:local/root "deps/common"}
   logseq/graph-parser                   {:local/root "deps/graph-parser"}
   logseq/publish                        {:local/root "deps/publish"}
   metosin/malli                         {:mvn/version "0.10.0"}

+ 9 - 0
deps/common/.clj-kondo/config.edn

@@ -0,0 +1,9 @@
+{:linters
+ {:aliased-namespace-symbol {:level :warning}
+  :namespace-name-mismatch {:level :warning}
+  :used-underscored-binding {:level :warning}
+
+  :consistent-alias
+  {:aliases {clojure.string string}}}
+ :skip-comments true
+ :output {:progress true}}

+ 1 - 0
deps/common/.gitignore

@@ -0,0 +1 @@
+.clj-kondo/.cache

+ 29 - 0
deps/common/README.md

@@ -0,0 +1,29 @@
+## Description
+
+This library provides common util namespaces to share between the frontend and
+other non-frontend namespaces. This library is not supposed to depend on other logseq
+libraries.
+
+## API
+
+This library is under the parent namespace `logseq.common`.
+
+## Dev
+
+This follows the practices that [the Logseq frontend
+follows](/docs/dev-practices.md). Most of the same linters are used, with
+configurations that are specific to this library. See [this library's CI
+file](/.github/workflows/logseq-common.yml) for linting examples.
+
+### Testing
+
+To run ClojureScript tests:
+```
+clojure -M:test
+```
+
+To auto-run tests while writing tests:
+
+```
+clojure -M:test -w src
+```

+ 8 - 0
deps/common/deps.edn

@@ -0,0 +1,8 @@
+{:aliases
+ {:test {:extra-paths ["test"]
+         :extra-deps  {olical/cljs-test-runner   {:mvn/version "3.8.0"}
+                       org.clojure/clojurescript {:mvn/version "1.11.54"}}
+         :main-opts   ["-m" "cljs-test-runner.main"]}
+  :clj-kondo
+  {:replace-deps {clj-kondo/clj-kondo {:mvn/version "2022.12.08"}}
+   :main-opts  ["-m" "clj-kondo.main"]}}}

+ 311 - 0
deps/common/src/logseq/common/path.cljs

@@ -0,0 +1,311 @@
+(ns logseq.common.path
+  "Path manipulation functions, use '/' sep on all platforms.
+   Also handles URL paths."
+  (:require [clojure.string :as string]))
+
+(defn- safe-decode-uri-component
+  [uri]
+  (try
+    (js/decodeURIComponent uri)
+    (catch :default _
+      (js/console.error "decode-uri-component-failed" uri)
+      uri)))
+
+(defn is-file-url?
+  [s]
+  (and (string? s)
+       (or (string/starts-with? s "file://") ;; mobile platform
+           (string/starts-with? s "content://") ;; android only
+           (string/starts-with? s "assets://") ;; Electron asset, urlencoded
+           (string/starts-with? s "logseq://") ;; reserved for future fs protocol
+           (string/starts-with? s "memory://") ;; special memory fs
+           (string/starts-with? s "s3://"))))
+
+(defn filename
+  "File name of a path or URL.
+   Returns nil when it's a directory that ends with '/'."
+  [path]
+  (let [fname (if (string/ends-with? path "/")
+                nil
+                (last (string/split path #"/")))]
+    (if (and (seq fname) (is-file-url? path))
+      (safe-decode-uri-component fname)
+      fname)))
+
+(defn split-ext
+  "Split file name into stem and extension, for both path and URL"
+  [path]
+  (let [fname (filename path)
+        pos (string/last-index-of fname ".")]
+    (if-not (or (nil? pos) (zero? pos))
+      [(subs fname 0 pos)
+       (string/lower-case (subs fname (+ pos 1)))]
+      [fname ""])))
+
+(defn file-stem
+  "File name without extension"
+  [path]
+  (first (split-ext path)))
+
+(defn file-ext
+  "File extension, lowercased"
+  [path]
+  (second (split-ext path)))
+
+(defn safe-filename?
+  "Safe filename on all platforms"
+  [fname]
+  (and (not (string/blank? fname))
+       (< (count fname) 255)
+       (not (or (re-find #"[\/?<>\\:*|\"]" fname)
+                (re-find #"^\.+$" fname)
+                (re-find #"[\. ]$" fname)
+                (re-find #"(?i)^(COM[0-9]|CON|LPT[0-9]|NUL|PRN|AUX|com[0-9]|con|lpt[0-9]|nul|prn|aux)\..+" fname)
+                (re-find #"[\u0000-\u001f\u0080-\u009f]" fname)))))
+
+
+(defn- path-join-internal
+  "Joins the given path segments into a single path, handling relative paths,
+  '..' and '.' normalization."
+  [& segments]
+  (let [segments (remove string/blank? segments) ;; handle (path-join nil path)
+        segments (map #(string/replace % #"[/\\]+" "/") segments)
+        ;; a fix for clojure.string/split
+        split-fn (fn [s]
+                   (if (= s "/")
+                     [""]
+                     (string/split s #"/")))
+        join-fn (fn [segs]
+                  (case segs
+                    []   "."
+                    [""] "/"
+                    #_{:clj-kondo/ignore [:path-invalid-construct/string-join]}
+                    (string/join "/" segs)))]
+    (->> (filter seq segments)
+         (mapcat split-fn)
+         (reduce (fn [acc segment]
+                   (cond
+                     (= "" segment)
+                     [segment]
+
+                     (= ".." segment)
+                     (case (last acc)
+                       ".." (conj acc segment)
+                       ""   acc
+                       nil  [".."]
+                       (pop acc))
+
+                     (= "." segment)
+                     acc
+
+                     :else
+                     (conj acc segment)))
+                 [])
+         (join-fn))))
+
+(defn- uri-path-join-internal
+  "Joins the given URI path segments into a single path, handling relative paths,
+  '..' and '.' normalization."
+  [& segments]
+  (let [segments (remove nil? segments) ;; handle (path-join nil path)
+        segments (map #(string/replace % #"[/\\]+" "/") segments)
+        ;; a fix for clojure.string/split
+        split-fn (fn [s]
+                   (if (= s "/")
+                     [""]
+                     (string/split s #"/")))
+        join-fn (fn [segs]
+                  (case segs
+                    []   "."
+                    [""] "/"
+                    #_{:clj-kondo/ignore [:path-invalid-construct/string-join]}
+                    (string/join "/" segs)))]
+    (->> (filter seq segments)
+         (mapcat split-fn)
+         (map #(js/encodeURIComponent %))
+         (reduce (fn [acc segment]
+                   (cond
+                     (= "" segment)
+                     [segment]
+
+                     (= ".." segment)
+                     (case (last acc)
+                       ".." (conj acc segment)
+                       ""   acc
+                       nil  [".."]
+                       (pop acc))
+
+                     (= "." segment)
+                     acc
+
+                     :else
+                     (conj acc segment)))
+                 [])
+         (join-fn))))
+
+(defn url-join
+  "Segments are not URL-ecoded"
+  [base-url & segments]
+  (let [^js url (js/URL. base-url)
+        scheme (.-protocol url)
+        domain (or (not-empty (.-host url)) "")
+        path (safe-decode-uri-component (.-pathname url))
+        encoded-new-path (apply uri-path-join-internal path segments)]
+    (str scheme "//" domain encoded-new-path)))
+
+
+(defn path-join
+  "Join path segments, or URL base and path segments"
+  [base & segments]
+
+  (cond
+    ;; For debugging
+    ; (nil? base)
+    ; (js/console.log "path join with nil global directory" segments)
+    (= base "")
+    (js/console.error "BUG: should not join with empty dir" segments)
+    :else
+    nil)
+
+  (if (is-file-url? base)
+    (apply url-join base segments)
+    (apply path-join-internal base segments)))
+
+
+(defn- path-normalize-internal
+  "Normalize path using path-join, break into segment and re-join"
+  [path]
+  (path-join path))
+
+
+(defn url-normalize
+  [origin-url]
+  (let [^js url (js/URL. origin-url)
+        scheme (.-protocol url)
+        domain (or (not-empty (.-host url)) "")
+        path (safe-decode-uri-component (.-pathname url))
+        encoded-new-path (uri-path-join-internal path)]
+    (str scheme "//" domain encoded-new-path)))
+
+(defn path-normalize
+  "Normalize path or URL"
+  [path]
+  (if (is-file-url? path)
+    (url-normalize path)
+    (path-normalize-internal path)))
+
+(defn url-to-path
+  "Extract path part of a URL, decoded.
+
+   The reverse operation is (path-join protocol:// path)"
+  [original-url]
+  (if (is-file-url? original-url)
+    ;; NOTE: URL type is not consistent across all protocols
+    ;; Check file:// and assets://, pathname behavior is different
+    (let [^js url (js/URL. (string/replace original-url "assets://" "file://"))
+          path (safe-decode-uri-component (.-pathname url))
+          path (if (string/starts-with? path "///")
+                 (subs path 2)
+                 path)
+          path (if (re-find #"(?i)^/[a-zA-Z]:" path) ;; Win path fix
+                 (subs path 1)
+                 path)]
+      path)
+    original-url))
+
+(defn trim-dir-prefix
+  "Trim dir prefix from path"
+  [base-path sub-path]
+  (let [base-path (path-normalize base-path)
+        sub-path (path-normalize sub-path)
+        is-url? (is-file-url? base-path)]
+    (if (string/starts-with? sub-path base-path)
+      (if is-url?
+        (safe-decode-uri-component (string/replace (subs sub-path (count base-path)) #"^/+", ""))
+        (string/replace (subs sub-path (count base-path)) #"^/+", ""))
+      (do
+        (js/console.error "unhandled trim-base" base-path sub-path)
+        nil))))
+
+(defn relative-path
+  "Get relative path from base path.
+   Works for both path and URL."
+  [base-path sub-path]
+  (let [base-path (path-normalize base-path)
+        sub-path (path-normalize sub-path)
+        is-url? (is-file-url? base-path)]
+    (if (string/starts-with? sub-path base-path)
+      (if is-url?
+        (safe-decode-uri-component (string/replace (subs sub-path (count base-path)) #"^/+", ""))
+        (string/replace (subs sub-path (count base-path)) #"^/+", ""))
+      ;; append as many ..
+      ;; NOTE: This is a buggy impl, relative-path is different when base-path is a file or a dir
+      (let [base-segs (string/split base-path #"/" -1)
+            path-segs (string/split sub-path #"/" -1)
+            common-segs (take-while #(= (first %) (second %)) (map vector base-segs path-segs))
+            base-segs (drop (count common-segs) base-segs)
+            remain-segs (drop (count common-segs) path-segs)
+            base-prefix (apply str (repeat (max 0 (dec (count base-segs))) "../"))]
+        (js/console.error (js/Error. "buggy relative-path") base-path sub-path)
+        #_{:clj-kondo/ignore [:path-invalid-construct/string-join]}
+        (if is-url?
+          (safe-decode-uri-component (str base-prefix (string/join "/" remain-segs)))
+          (str base-prefix (string/join "/" remain-segs)))))))
+
+
+(defn parent
+  "Parent, containing directory"
+  [path]
+  (if (string/includes? path "/")
+    ;; ugly but works
+    (path-normalize (str path "/.."))
+    nil))
+
+
+(defn resolve-relative-path
+  "Assume current-path is a file"
+  [current-path rel-path]
+  (if-let [base-dir (parent current-path)]
+    (path-join base-dir rel-path)
+    rel-path))
+
+(defn get-relative-path
+  "Assume current-path is a file, and target-path is a file or directory.
+   Return relative path from current-path to target-path.
+   Works for both path and URL. Also works for relative path.
+   The opposite operation is `resolve-relative-path`"
+  [current-path target-path]
+  (let [base-path (parent current-path)
+        sub-path (path-normalize target-path)
+        is-url? (is-file-url? base-path)
+        base-segs (if base-path
+                    (string/split base-path #"/" -1)
+                    [])
+        path-segs (string/split sub-path #"/" -1)
+        common-segs (take-while #(= (first %) (second %)) (map vector base-segs path-segs))
+        base-segs (drop (count common-segs) base-segs)
+        remain-segs (drop (count common-segs) path-segs)
+        base-prefix (apply str (repeat (max 0 (count base-segs)) "../"))]
+    #_{:clj-kondo/ignore [:path-invalid-construct/string-join]}
+    (if is-url?
+      (safe-decode-uri-component (str base-prefix (string/join "/" remain-segs)))
+      (str base-prefix (string/join "/" remain-segs)))))
+
+;; compat
+(defn basename
+  [path]
+  (let [path (string/replace path #"/$" "")]
+    (filename path)))
+
+(defn dirname
+  [path]
+  (parent path))
+
+(defn absolute?
+  "Whether path `p` is absolute."
+  [p]
+  (let [p (path-normalize p)]
+    (boolean (or (is-file-url? p)
+                 (string/starts-with? p "/")
+                 ;; is windows dir
+                 (re-find #"^[a-zA-Z]:[/\\]" p)))))

+ 47 - 0
deps/common/test/logseq/common/path_test.cljs

@@ -0,0 +1,47 @@
+(ns logseq.common.path-test
+  (:require [cljs.test :refer [deftest is testing]]
+            [logseq.common.path :as path]))
+
+(deftest filename
+  (is (= nil (path/filename "/path/to/dir/")))
+  (is (= "file-name" (path/filename "/path/to/dir/file-name")))
+  (is (= "file-name" (path/filename "dir/file-name"))))
+
+(deftest split-ext
+  (is (= ["some-song" "mp3"] (path/split-ext "some-song.MP3")))
+  (is (= ["some-song" ""] (path/split-ext "some-song")))
+  (is (= ["some-file.edn" "txt"] (path/split-ext "some-file.edn.txt"))))
+
+(deftest safe-file-name?
+  (testing "safe-file-name"
+    (is (path/safe-filename? "foo"))
+    (is (path/safe-filename? "foo bar"))
+    (is (path/safe-filename? "foo-bar"))
+    (is (path/safe-filename? "foo_bar"))
+    (is (path/safe-filename? "foo.bar"))
+    (is (path/safe-filename? "foo..bar"))
+    (is (path/safe-filename? "foo...bar"))
+    (is (not (path/safe-filename? "foo/bar")))
+    (is (not (path/safe-filename? "foo?bar")))
+    (is (not (path/safe-filename? "foo<bar")))
+    (is (not (path/safe-filename? "foo>bar")))))
+
+
+(deftest path-join
+  (testing "path-join"
+    (is (= "foo/bar" (path/path-join "foo" "bar")))
+    (is (= "foo/bar" (path/path-join "foo/" "bar")))
+    (is (= "foo/bar" (path/path-join nil "foo" "bar"))
+        "global dir")
+    (is (= "/foo/bar/baz/asdf" (path/path-join "/foo/bar//baz/asdf/quux/..")))
+    (is (= "assets:///foo.bar/baz" (path/path-join "assets:///foo.bar" "baz")))
+    (is (= "assets:///foo.bar/baz" (path/path-join "assets:///foo.bar/" "baz")))))
+
+(deftest path-absolute
+  (testing "absolute"
+    (is (true? (path/absolute? "D:\\sources\\sources.md")))
+    (is (true? (path/absolute? "/home/xxx/logseq/test.md")))
+    (is (false? (path/absolute? "logseq/test.md")))
+    (is (false? (path/absolute? "test.md")))
+    (is (false? (path/absolute? "test")))
+    (is (false? (path/absolute? "D:test.md")))))

+ 1 - 1
deps/db/src/logseq/db/schema.cljs

@@ -1,7 +1,7 @@
 (ns logseq.db.schema
   "Main db schema for the Logseq app")
 
-(defonce version 1)
+(defonce version 2)
 (defonce ast-version 1)
 ;; A page is a special block, a page can corresponds to multiple files with the same ":block/name".
 (def ^:large-vars/data-var schema

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

@@ -32,7 +32,7 @@
   [s]
   (if (local-protocol-asset? s)
     (-> s
-        (string/replace-first asset-protocol "")
+        (string/replace-first asset-protocol "file://")
         (string/replace-first capacitor-protocol-with-prefix "file://")
         (string/replace-first capacitor-x-protocol-with-prefix "file://"))
     s))

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

@@ -36,12 +36,13 @@
    uri-encoded? - since paths on mobile are uri-encoded, need to decode them first
    filename-format - the format used to parse file name
    "
-  [file ast uri-encoded? filename-format]
+  [file-path ast uri-encoded? filename-format]
   ;; headline
   (let [ast  (map first ast)
-        file (if uri-encoded? (js/decodeURI file) file)]
+        file (if uri-encoded? (js/decodeURI file-path) file-path)]
     ;; check backward compatibility?
-    (if (string/includes? file "pages/contents.")
+    ;; FIXME: use pre-config dir
+    (if (string/starts-with? file "pages/contents.")
       "Contents"
       (let [first-block (last (first (filter gp-block/heading-block? ast)))
             property-name (when (contains? #{"Properties" "Property_Drawer"} (ffirst ast))
@@ -128,10 +129,9 @@
 
 ;; TODO: performance improvement
 (defn- extract-pages-and-blocks
-  "uri-encoded? - if is true, apply URL decode on the file path"
-  [format ast properties file content {:keys [date-formatter db uri-encoded? filename-format] :as options}]
+  [format ast properties file content {:keys [date-formatter db filename-format] :as options}]
   (try
-    (let [page (get-page-name file ast uri-encoded? filename-format)
+    (let [page (get-page-name file ast false filename-format)
           [page page-name _journal-day] (gp-block/convert-page-if-journal page date-formatter)
           options' (assoc options :page-name page-name)
           blocks (->> (gp-block/extract-blocks ast content false format options')
@@ -185,15 +185,15 @@
 
 (defn extract
   "Extracts pages, blocks and ast from given file"
-  [file content {:keys [user-config verbose] :or {verbose true} :as options}]
+  [file-path content {:keys [user-config verbose] :or {verbose true} :as options}]
   (if (string/blank? content)
     []
-    (let [format (gp-util/get-format file)
-          _ (when verbose (println "Parsing start: " file))
+    (let [format (gp-util/get-format file-path)
+          _ (when verbose (println "Parsing start: " file-path))
           ast (gp-mldoc/->edn content (gp-mldoc/default-config format
                                         ;; {:parse_outline_only? true}
-                                        ))]
-      (when verbose (println "Parsing finished: " file))
+                                                               ))]
+      (when verbose (println "Parsing finished: " file-path))
       (let [first-block (ffirst ast)
             properties (let [properties (and (gp-property/properties-ast? first-block)
                                              (->> (last first-block)
@@ -210,7 +210,7 @@
                                      (fn [v]
                                        (string/replace (or v "") "\\" "")))
                              properties)))
-            [pages blocks] (extract-pages-and-blocks format ast properties file content options)]
+            [pages blocks] (extract-pages-and-blocks format ast properties file-path content options)]
         {:pages pages
          :blocks blocks
          :ast ast}))))

+ 7 - 0
docs/dev-practices.md

@@ -246,6 +246,13 @@ page](https://github.com/metosin/malli/blob/master/docs/clojurescript-function-i
 
 Currently the codebase is not formatted/indented consistently. We loosely follow https://github.com/bbatsov/clojure-style-guide. [cljfmt](https://cljdoc.org/d/cljfmt/) is a common formatter used for Clojure, analogous to Prettier for other languages. You can do so easily with the [Calva](https://marketplace.visualstudio.com/items?itemName=betterthantomorrow.calva) extension in [VSCode](https://code.visualstudio.com/): It will (mostly) indent your code correctly as you type, and you can move your cursor to the start of the line(s) you've written and press `Tab` to auto-indent all Clojure forms nested under the one starting on the current line.
 
+## Naming
+
+We strive to use explicit names that are self explanatory so that our codebase is readable and maintainable. Sometimes we use abbreviations for frequently occurring concepts. Some common abbreviations:
+
+* `rpath` - Relative path e.g. `logseq/config.edn`
+* `fpath` -  Full path e.g. `/full/path/to/logseq/config.edn`
+
 ## Development Tools
 
 ### Babashka tasks

+ 8 - 3
e2e-tests/editor.spec.ts

@@ -168,15 +168,14 @@ test('copy & paste block ref and replace its content', async ({ page, block }) =
   await createRandomPage(page)
 
   await block.mustType('Some random text')
-  // FIXME: https://github.com/logseq/logseq/issues/7541
-  await page.waitForTimeout(1000)
 
   await page.keyboard.press(modKey + '+c')
 
   await page.press('textarea >> nth=0', 'Enter')
   await block.waitForBlocks(2)
-
+  await page.waitForTimeout(100)
   await page.keyboard.press(modKey + '+v')
+  await page.waitForTimeout(100)
   await page.keyboard.press('Enter')
 
   // Check if the newly created block-ref has the same referenced content
@@ -189,10 +188,16 @@ test('copy & paste block ref and replace its content', async ({ page, block }) =
 
   await expect(page.locator('textarea >> nth=0')).not.toHaveValue('Some random text')
 
+  // FIXME: Sometimes the cursor is in the end of the editor
+  for (let i = 0; i < 4; i++) {
+    await page.press('textarea >> nth=0', 'ArrowLeft')
+  }
+
   // Trigger replace-block-reference-with-content-at-point
   await page.keyboard.press(modKey + '+Shift+r')
 
   await expect(page.locator('textarea >> nth=0')).toHaveValue('Some random text')
+
   await block.escapeEditing()
 
   await expect(page.locator('.block-ref >> text="Some random text"')).toHaveCount(0);

+ 1 - 7
e2e-tests/fixtures.ts

@@ -121,12 +121,6 @@ base.beforeEach(async () => {
     await page.keyboard.press('Escape')
     await page.keyboard.press('Escape')
 
-    /*
-    const locator = page.locator('.notification-close-button').first()
-    while (await locator.isVisible()) {
-      locator.click() // ignore error
-    }
-    */
     await expect(page.locator('.notification-close-button')).not.toBeVisible()
 
     const rightSidebar = page.locator('.cp__right-sidebar-inner')
@@ -297,7 +291,7 @@ export let traceAll = function(){
   test.beforeAll(async () => {
     await context.tracing.startChunk();
   })
-  
+
   test.afterAll(async () => {
     await context.tracing.stopChunk({ path: getTracingFilePath() });
   })

+ 4 - 3
e2e-tests/hotkey.spec.ts

@@ -1,8 +1,9 @@
 import { expect } from '@playwright/test'
 import { test } from './fixtures'
-import { createRandomPage, newBlock, lastBlock, modKey, IsLinux } from './utils'
+import { createRandomPage, enterNextBlock, lastBlock, modKey, IsLinux } from './utils'
 
 test('open search dialog', async ({ page }) => {
+  await page.waitForTimeout(200)
   await page.keyboard.press(modKey + '+k')
 
   await page.waitForSelector('[placeholder="Search or create page"]')
@@ -25,7 +26,7 @@ test('insert link #3278', async ({ page }) => {
   await page.fill('textarea >> nth=0', '[Logseq Website](https://logseq.com)')
 
   // Case 2: link with label
-  await newBlock(page)
+  await enterNextBlock(page)
   await page.type('textarea >> nth=0', 'Logseq')
   await page.press('textarea >> nth=0', selectAll)
   await page.press('textarea >> nth=0', hotKey)
@@ -34,7 +35,7 @@ test('insert link #3278', async ({ page }) => {
   expect(await page.inputValue('textarea >> nth=0')).toBe('[Logseq](https://logseq.com/)')
 
   // Case 3: link with URL
-  await newBlock(page)
+  await enterNextBlock(page)
   await page.type('textarea >> nth=0', 'https://logseq.com/')
   await page.press('textarea >> nth=0', selectAll)
   await page.press('textarea >> nth=0', hotKey)

+ 4 - 0
e2e-tests/logseq-url.spec.ts

@@ -15,6 +15,9 @@ test("Logseq URLs (same graph)", async ({ page, block }) => {
   await createRandomPage(page)
   await block.mustFill("") // to enter editing mode
   await page.keyboard.press(paste_key)
+  // paste returns a promise which is async, so we need give it a little bit
+  // more time
+  await page.waitForTimeout(100)
   let cursor_locator = page.locator('textarea >> nth=0')
   expect(await cursor_locator.inputValue()).toContain("page=" + page_title)
   await cursor_locator.press("Enter")
@@ -32,6 +35,7 @@ test("Logseq URLs (same graph)", async ({ page, block }) => {
   await createRandomPage(page)
   await block.mustFill("") // to enter editing mode
   await page.keyboard.press(paste_key)
+  await page.waitForTimeout(100)
   cursor_locator = page.locator('textarea >> nth=0')
   expect(await cursor_locator.inputValue()).toContain("block-id=")
   await cursor_locator.press("Enter")

+ 1 - 1
e2e-tests/page-rename.spec.ts

@@ -1,6 +1,6 @@
 import { expect, Page } from '@playwright/test'
 import { test } from './fixtures'
-import { IsMac, createPage, randomLowerString, newBlock, newInnerBlock, randomString, lastBlock } from './utils'
+import { IsMac, createPage, randomLowerString, newInnerBlock, randomString, lastBlock } from './utils'
 
 /***
  * Test rename feature

+ 2 - 2
e2e-tests/page-search.spec.ts

@@ -1,7 +1,7 @@
 import { expect, Page } from '@playwright/test'
 import { test } from './fixtures'
 import { Block } from './types'
-import { modKey, createRandomPage, newBlock, newInnerBlock, randomString, lastBlock, enterNextBlock } from './utils'
+import { modKey, createRandomPage, newInnerBlock, randomString, lastBlock, enterNextBlock } from './utils'
 import { searchPage, closeSearchBox } from './util/search-modal'
 
 /***
@@ -61,7 +61,7 @@ test('Search CJK', async ({ page, block }) => {
 
   // check if CJK are indexed
   const results = await searchPage(page, '进度')
-  await expect(results.length).toEqual(4) // 1 page + 1 block + 1 page content
+  await expect(results.length).toEqual(5) // 1 page + 1 block + 1 page content + new whiteboard
   await closeSearchBox(page)
 })
 

+ 12 - 19
e2e-tests/utils.ts

@@ -1,6 +1,7 @@
 import { Page, Locator } from 'playwright'
 import { expect, ConsoleMessage } from '@playwright/test'
 import * as pathlib from 'path'
+import { modKey } from './util/basic'
 
 // TODO: The file should be a facade of utils in the /util folder
 // No more additional functions should be added to this file
@@ -34,6 +35,9 @@ export async function lastBlock(page: Page): Promise<Locator> {
  * @param page The Playwright Page object.
  */
 export async function enterNextBlock(page: Page): Promise<Locator> {
+  // Move cursor to the end of the editor
+  await page.press('textarea >> nth=0', modKey + '+a') // select all
+  await page.press('textarea >> nth=0', 'ArrowRight')
   let blockCount = await page.locator('.page-blocks-inner .ls-block').count()
   await page.press('textarea >> nth=0', 'Enter')
   await page.waitForTimeout(10)
@@ -53,15 +57,6 @@ export async function newInnerBlock(page: Page): Promise<Locator> {
   return page.locator('textarea >> nth=0')
 }
 
-// Deprecated by block.enterNext
-export async function newBlock(page: Page): Promise<Locator> {
-  let blockNumber = await page.locator('.page-blocks-inner .ls-block').count()
-  await lastBlock(page)
-  await page.press('textarea >> nth=0', 'Enter')
-  await page.waitForSelector(`.page-blocks-inner .ls-block >> nth=${blockNumber} >> textarea`, { state: 'visible' })
-  return page.locator('textarea >> nth=0')
-}
-
 export async function escapeToCodeEditor(page: Page): Promise<void> {
   await page.press('.block-editor textarea', 'Escape')
   await page.waitForSelector('.CodeMirror pre', { state: 'visible' })
@@ -148,15 +143,13 @@ export async function loadLocalGraph(page: Page, path: string): Promise<void> {
 
   // If there is an error notification from a previous test graph being deleted,
   // close it first so it doesn't cover up the UI
-  let locator = page.locator('.notification-close-button').first()
-  while (await locator?.isVisible()) {
-    try { // don't fail if unable to click (likely disappeared already)
-      await locator.click()
-    } catch (error) {}
-    await page.waitForTimeout(250)
-
-    expect(locator.isVisible()).resolves.toBe(false)
+  let n = await page.locator('.notification-close-button').count()
+  if (n > 1) {
+    await page.locator('button >> text="Clear all"').click()
+  } else if (n == 1) {
+    await page.locator('.notification-close-button').click()
   }
+  await expect(page.locator('.notification-close-button').first()).not.toBeVisible({ timeout: 2000 })
 
   console.log('Graph loaded for ' + path)
 }
@@ -173,8 +166,8 @@ export async function editFirstBlock(page: Page) {
 /**
  * Wait for a console message with a given prefix to appear, and return the full text of the message
  * Or reject after a timeout
- * 
- * @param page 
+ *
+ * @param page
  * @param prefix - the prefix to look for
  * @param timeout - the timeout in ms
  * @returns the full text of the console message

+ 59 - 8
e2e-tests/whiteboards.spec.ts

@@ -3,18 +3,29 @@ import { test } from './fixtures'
 import { modKey } from './utils'
 
 test('enable whiteboards', async ({ page }) => {
-  await expect(page.locator('.nav-header .whiteboard')).toBeHidden()
-  await page.click('#head .toolbar-dots-btn')
-  await page.click('#head .dropdown-wrapper >> text=Settings')
-  await page.click('.settings-modal a[data-id=features]')
-  await page.click('text=Whiteboards >> .. >> .ui__toggle')
-  await page.waitForTimeout(1000)
-  await page.keyboard.press('Escape')
+  if (await page.$('.nav-header .whiteboard') === null) {
+    await page.click('#head .toolbar-dots-btn')
+    await page.click('#head .dropdown-wrapper >> text=Settings')
+    await page.click('.settings-modal a[data-id=features]')
+    await page.click('text=Whiteboards >> .. >> .ui__toggle')
+    await page.waitForTimeout(1000)
+    await page.keyboard.press('Escape')
+  }
+
   await expect(page.locator('.nav-header .whiteboard')).toBeVisible()
 })
 
-test('create new whiteboard', async ({ page }) => {
+test('should display onboarding tour', async ({ page }) => {
+  // ensure onboarding tour is going to be triggered locally
+  await page.evaluate(`window.localStorage.removeItem('whiteboard-onboarding-tour?')`)
   await page.click('.nav-header .whiteboard')
+
+  await expect(page.locator('.cp__whiteboard-welcome')).toBeVisible()
+  await page.click('.cp__whiteboard-welcome button.bg-gray-600')
+  await expect(page.locator('.cp__whiteboard-welcome')).toBeHidden()
+})
+
+test('create new whiteboard', async ({ page }) => {
   await page.click('#tl-create-whiteboard')
   await expect(page.locator('.logseq-tldraw')).toBeVisible()
 })
@@ -128,10 +139,50 @@ test('connect rectangles with an arrow', async ({ page }) => {
   await page.mouse.up()
   await page.keyboard.press('Escape')
 
+  await expect(page.locator('.logseq-tldraw .tl-line-container')).toHaveCount(1)
+})
+
+test('delete the first rectangle', async ({ page }) => {
+  await page.keyboard.press('Escape')
+  await page.waitForTimeout(1000)
+  await page.click('.logseq-tldraw .tl-box-container:first-of-type')
+  await page.keyboard.press('Delete')
+
+  await expect(page.locator('.logseq-tldraw .tl-box-container')).toHaveCount(1)
+  await expect(page.locator('.logseq-tldraw .tl-line-container')).toHaveCount(0)
+})
+
+test('undo the delete action', async ({ page }) => {
+  await page.keyboard.press(modKey + '+z')
 
+  await expect(page.locator('.logseq-tldraw .tl-box-container')).toHaveCount(2)
   await expect(page.locator('.logseq-tldraw .tl-line-container')).toHaveCount(1)
 })
 
+test('move arrow to back', async ({ page }) => {
+  await page.keyboard.press('Escape')
+  await page.waitForTimeout(1000)
+  await page.click('.logseq-tldraw .tl-line-container')
+  await page.keyboard.press('Shift+[')
+
+  await expect(page.locator('.logseq-tldraw .tl-canvas .tl-layer > div:first-of-type > div:first-of-type')).toHaveClass('tl-line-container')
+})
+
+test('move arrow to front', async ({ page }) => {
+  await page.keyboard.press('Escape')
+  await page.waitForTimeout(1000)
+  await page.click('.logseq-tldraw .tl-line-container')
+  await page.keyboard.press('Shift+]')
+
+  await expect(page.locator('.logseq-tldraw .tl-canvas .tl-layer > div:first-of-type > div:first-of-type')).not.toHaveClass('tl-line-container')
+})
+
+test('undo the move action', async ({ page }) => {
+  await page.keyboard.press(modKey + '+z')
+
+  await expect(page.locator('.logseq-tldraw .tl-canvas .tl-layer > div:first-of-type > div:first-of-type')).toHaveClass('tl-line-container')
+})
+
 test('cleanup the shapes', async ({ page }) => {
   await page.keyboard.press(`${modKey}+a`)
   await page.keyboard.press('Delete')

+ 1 - 0
externs.js

@@ -139,6 +139,7 @@ dummy.DOCUMENT = function() {};
 dummy.DOCUMENT_TYPE = function() {};
 dummy.ELEMENT = function() {};
 dummy.TEXT = function() {};
+dummy.isAbsolute = function() {};
 
 /**
  * @typedef {{

+ 4 - 4
ios/App/App.xcodeproj/project.pbxproj

@@ -515,7 +515,7 @@
 				INFOPLIST_FILE = App/Info.plist;
 				IPHONEOS_DEPLOYMENT_TARGET = 13.0;
 				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
-				MARKETING_VERSION = 0.8.18;
+				MARKETING_VERSION = 0.9.1;
 				OTHER_SWIFT_FLAGS = "$(inherited) \"-D\" \"COCOAPODS\" \"-DDEBUG\"";
 				PRODUCT_BUNDLE_IDENTIFIER = com.logseq.logseq;
 				PRODUCT_NAME = "$(TARGET_NAME)";
@@ -542,7 +542,7 @@
 				INFOPLIST_FILE = App/Info.plist;
 				IPHONEOS_DEPLOYMENT_TARGET = 13.0;
 				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
-				MARKETING_VERSION = 0.8.18;
+				MARKETING_VERSION = 0.9.1;
 				PRODUCT_BUNDLE_IDENTIFIER = com.logseq.logseq;
 				PRODUCT_NAME = "$(TARGET_NAME)";
 				SWIFT_ACTIVE_COMPILATION_CONDITIONS = "";
@@ -567,7 +567,7 @@
 				INFOPLIST_KEY_NSHumanReadableCopyright = "";
 				IPHONEOS_DEPLOYMENT_TARGET = 13.0;
 				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks";
-				MARKETING_VERSION = 0.8.18;
+				MARKETING_VERSION = 0.9.1;
 				MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
 				MTL_FAST_MATH = YES;
 				PRODUCT_BUNDLE_IDENTIFIER = com.logseq.logseq.ShareViewController;
@@ -594,7 +594,7 @@
 				INFOPLIST_KEY_NSHumanReadableCopyright = "";
 				IPHONEOS_DEPLOYMENT_TARGET = 13.0;
 				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks";
-				MARKETING_VERSION = 0.8.18;
+				MARKETING_VERSION = 0.9.1;
 				MTL_FAST_MATH = YES;
 				PRODUCT_BUNDLE_IDENTIFIER = com.logseq.logseq.ShareViewController;
 				PRODUCT_NAME = "$(TARGET_NAME)";

+ 2 - 0
packages/amplify/.gitignore

@@ -0,0 +1,2 @@
+.parcel-cache
+dist

+ 16 - 0
packages/amplify/examples/index.html

@@ -0,0 +1,16 @@
+<!doctype html>
+<html lang="en">
+<head>
+    <meta charset="UTF-8">
+    <meta name="viewport"
+          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
+    <meta http-equiv="X-UA-Compatible" content="ie=edge">
+    <title>Document</title>
+    <script crossorigin src="https://unpkg.com/react@17/umd/react.development.js"></script>
+    <script crossorigin src="https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script>
+</head>
+<body>
+<div id="app"></div>
+<script type="module" src="./index.tsx"></script>
+</body>
+</html>

+ 87 - 0
packages/amplify/examples/index.tsx

@@ -0,0 +1,87 @@
+import * as React from 'react'
+import * as ReactDOM from 'react-dom'
+import { Amplify } from 'aws-amplify'
+import { Authenticator } from '@aws-amplify/ui-react'
+import '@aws-amplify/ui-react/styles.css'
+
+function setupConfigure () {
+  Amplify.configure({
+    Auth: {
+      // REQUIRED only for Federated Authentication - Amazon Cognito Identity Pool ID
+      // identityPoolId: 'XX-XXXX-X:XXXXXXXX-XXXX-1234-abcd-1234567890ab',
+
+      // REQUIRED - Amazon Cognito Region
+      region: 'us-east-1',
+
+      // OPTIONAL - Amazon Cognito Federated Identity Pool Region
+      // Required only if it's different from Amazon Cognito Region
+      // identityPoolRegion: 'XX-XXXX-X',
+
+      // OPTIONAL - Amazon Cognito User Pool ID
+      userPoolId: 'us-east-1_ldvDmC9Fe',
+
+      // OPTIONAL - Amazon Cognito Web Client ID (26-char alphanumeric string)
+      userPoolWebClientId: '41m82unjghlea984vjpk887qcr',
+
+      // OPTIONAL - Enforce user authentication prior to accessing AWS resources or not
+      // mandatorySignIn: false,
+
+      // OPTIONAL - This is used when autoSignIn is enabled for Auth.signUp
+      // 'code' is used for Auth.confirmSignUp, 'link' is used for email link verification
+      // signUpVerificationMethod: 'code', // 'code' | 'link'
+
+      // OPTIONAL - Configuration for cookie storage
+      // Note: if the secure flag is set to true, then the cookie transmission requires a secure protocol
+      cookieStorage: {
+        domain: 'localhost',
+        path: '/',
+        expires: 365,
+        sameSite: 'strict',
+        secure: true,
+      },
+
+      // OPTIONAL - customized storage object
+      // storage: MyStorage,
+
+      // OPTIONAL - Manually set the authentication flow type. Default is 'USER_SRP_AUTH'
+      authenticationFlowType: 'USER_SRP_AUTH',
+
+      //
+      // // OPTIONAL - Manually set key value pairs that can be passed to Cognito Lambda Triggers
+      // clientMetadata: {myCustomKey: 'myCustomValue'},
+      //
+      // // OPTIONAL - Hosted UI configuration
+      // oauth: {
+      //     domain: 'your_cognito_domain',
+      //     scope: ['phone', 'email', 'profile', 'openid', 'aws.cognito.signin.user.admin'],
+      //     redirectSignIn: 'http://localhost:3000/',
+      //     redirectSignOut: 'http://localhost:3000/',
+      //     responseType: 'code' // or 'token', note that REFRESH token will only be generated when the responseType is code
+    }
+  })
+}
+
+export default function App () {
+  return (
+    <div style={{ display: 'flex', justifyContent: 'center', height: '90vh', alignItems: 'center' }}>
+      <Authenticator signUpAttributes={['email']}
+                     socialProviders={['google']}>
+        {({ signOut, user }) => (
+          <main>
+            <h1>Hello {user.username}</h1>
+            <button onClick={signOut}>Sign out</button>
+          </main>
+        )}
+      </Authenticator>
+    </div>)
+}
+
+function main () {
+  setupConfigure()
+
+  // mount
+  ReactDOM.render(<App/>, document.getElementById('app'))
+}
+
+// bootstrap
+main()

+ 42 - 0
packages/amplify/package.json

@@ -0,0 +1,42 @@
+{
+  "name": "logseq-amplify",
+  "version": "0.0.1",
+  "description": "Amplify components for Logseq",
+  "license": "MIT",
+  "scripts": {
+    "dev:amplify": "parcel watch ./src/amplify.ts --dist-dir ../src/main/frontend/ --no-hmr --no-source-maps",
+    "dev:examples": "parcel serve ./examples/index.html",
+    "build:amplify": "parcel build ./src/amplify.ts --dist-dir ../../resources/js --no-source-maps && mv ../../resources/js/amplify.css ../../resources/css/"
+  },
+  "devDependencies": {
+    "buffer": "^5.5.0",
+    "parcel": "^2.8.3",
+    "punycode": "^1.4.1"
+  },
+  "dependencies": {
+    "@aws-amplify/ui-react": "^4.3.8",
+    "aws-amplify": "^5.0.15",
+    "aws-amplify-react": "^5.1.43",
+    "react": "^17",
+    "react-dom": "^17"
+  },
+  "alias": {
+    "react": {
+      "global": "React"
+    },
+    "react-dom": {
+      "global": "ReactDOM"
+    },
+    "react/jsx-dev-runtime": "./node_modules/react/jsx-dev-runtime.js",
+    "react/jsx-runtime": "./node_modules/react/jsx-runtime.js"
+  },
+  "targets": {
+    "default": {
+      "outputFormat": "global",
+      "includeNodeModules": {
+        "react": false,
+        "react-dom": false
+      }
+    }
+  }
+}

+ 60 - 0
packages/amplify/src/LSAuthenticator.tsx

@@ -0,0 +1,60 @@
+import { Authenticator, CheckboxField, useAuthenticator, AccountSettings } from '@aws-amplify/ui-react'
+
+export function LSAuthenticator({ termsLink, children }: any) {
+  return (<div>
+    <Authenticator
+      formFields={{
+        signUp: {
+          email: { order: 1 },
+          username: { order: 2 },
+          password: { order: 3 },
+          confirm_password: { order: 4 },
+        }
+      }}
+      loginMechanisms={['username']}
+      socialProviders={['google']}
+      components={{
+        SignUp: {
+          FormFields() {
+            const { validationErrors } = useAuthenticator()
+
+            return (
+              <>
+                {/* Re-use default `Authenticator.SignUp.FormFields` */}
+                <Authenticator.SignUp.FormFields/>
+
+                {/* Append & require Terms & Conditions field to sign up  */}
+                <CheckboxField
+                  errorMessage={validationErrors.acknowledgement as string}
+                  hasError={!!validationErrors.acknowledgement}
+                  name="acknowledgement"
+                  value="yes"
+                  label={(<a href={termsLink}>I agree with the Terms & Conditions</a>)}
+                />
+              </>
+            )
+          },
+        },
+      }}
+      services={{
+        async validateCustomSignUp(formData) {
+          if (!formData.acknowledgement) {
+            return {
+              acknowledgement: '',
+            }
+          }
+        }
+      }}
+    >
+      {children}
+    </Authenticator>
+  </div>)
+}
+
+export function LSAuthenticatorChangePassword(
+  {onSuccess, onError}
+) {
+  return (
+    <AccountSettings.ChangePassword onSuccess={onSuccess} onError={onError}/>
+  )
+}

+ 99 - 0
packages/amplify/src/amplify.ts

@@ -0,0 +1,99 @@
+import '@aws-amplify/ui-react/styles.css'
+import { Amplify, Auth, Hub, I18n } from 'aws-amplify'
+import { LSAuthenticator, LSAuthenticatorChangePassword } from './LSAuthenticator'
+import { dict } from 'aws-amplify-react/lib-esm/AmplifyI18n'
+
+// fix i18n
+dict.zh['Reset Password'] = '重置密码'
+dict.zh['Enter your username'] = '请输入用户名'
+dict.zh['Enter your email'] = '请输入邮箱'
+dict.zh['Enter your password'] = '请输入密码'
+dict.zh['Confirm Password'] = '确认密码'
+dict.zh['Please confirm your Password'] = '请确认密码'
+dict.zh['Incorrect username or password.'] = '用户名或者密码不正确。如果您的邮箱未验证,请尝试使用用户名(非邮箱)登录,以保证再次邮箱验证流程。'
+
+// @ts-ignore attach defaults
+dict.en = {
+  'Incorrect username or password.': 'Incorrect username or password!   ' +
+    'For unconfirmed users, please input your username instead of Email to receive the code.'
+}
+
+const fixesMapping = {
+  'Sign Up': ['Sign up', 'Create Account'],
+  'Sign In': ['Sign in'],
+  'Sign Out': 'Sign out',
+  'Send Code': 'Send code',
+  'Forgot Password': ['Forgot your password?'],
+  'Enter your email': ['Enter your Email'],
+  'Enter your password': ['Enter your Password'],
+  'Enter your username': ['Enter your Username']
+}
+
+Object.keys(dict).forEach((k) => {
+  const target = dict[k]
+  Object.entries(fixesMapping).forEach(([k1, v1]) => {
+    if (target?.hasOwnProperty(k1)) {
+      const vs = Array.isArray(v1) ? v1 : [v1]
+      vs.forEach(it => {
+        target[it] = target[k1]
+      })
+    }
+  })
+})
+
+I18n.putVocabularies(dict)
+
+function setupAuthConfigure(config) {
+
+  const {
+    region,
+    userPoolId,
+    userPoolWebClientId,
+    identityPoolId,
+    oauthDomain,
+    oauthProviders
+  } = config
+
+  Amplify.configure({
+    'aws_project_region': region,
+    'aws_cognito_identity_pool_id': identityPoolId,
+    'aws_cognito_region': region,
+    'aws_user_pools_id': userPoolId,
+    'aws_user_pools_web_client_id': userPoolWebClientId,
+    'authenticationFlowType': 'USER_SRP_AUTH',
+    'oauth': {
+      'domain': oauthDomain,
+      'scope': [
+        'phone',
+        'email',
+        'openid',
+        'profile',
+        'aws.cognito.signin.user.admin'
+      ],
+      'redirectSignIn': 'https://logseq.com/public/auth_callback.html',
+      'redirectSignOut': 'https://logseq.com/public/auth_callback.html',
+      'responseType': 'code'
+    },
+    'federationTarget': 'COGNITO_USER_POOLS',
+    'aws_cognito_social_providers': oauthProviders || [
+      'GOOGLE'
+    ],
+    'aws_cognito_signup_attributes': [
+      'EMAIL'
+    ],
+    'aws_cognito_password_protection_settings': {
+      'passwordPolicyMinLength': 8,
+      'passwordPolicyCharacters': []
+    },
+    'aws_cognito_verification_mechanisms': [
+      'EMAIL'
+    ]
+  })
+}
+
+//@ts-ignore
+window.LSAmplify = {
+  setupAuthConfigure,
+  LSAuthenticator, LSAuthenticatorChangePassword,
+  Auth, Amplify, Hub, I18n
+}

+ 5516 - 0
packages/amplify/yarn.lock

@@ -0,0 +1,5516 @@
+# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
+# yarn lockfile v1
+
+
+"@aws-amplify/[email protected]":
+  version "6.0.15"
+  resolved "https://registry.yarnpkg.com/@aws-amplify/analytics/-/analytics-6.0.15.tgz#524047e8ce16a4049c1019f407f3d3fa5474555a"
+  integrity sha512-jn+ykLgaLlGdA83K6rNyZsUA2uiNB/D5w6kxTJtpFvk50/1S+Axl/hdl5ben5lsRyumtrnUrOJgc4XV8vrG9Qg==
+  dependencies:
+    "@aws-amplify/cache" "5.0.15"
+    "@aws-amplify/core" "5.0.15"
+    "@aws-sdk/client-firehose" "3.6.1"
+    "@aws-sdk/client-kinesis" "3.6.1"
+    "@aws-sdk/client-personalize-events" "3.6.1"
+    "@aws-sdk/client-pinpoint" "3.6.1"
+    "@aws-sdk/util-utf8-browser" "3.6.1"
+    lodash "^4.17.20"
+    tslib "^1.8.0"
+    uuid "^3.2.1"
+
+"@aws-amplify/[email protected]":
+  version "3.1.3"
+  resolved "https://registry.yarnpkg.com/@aws-amplify/api-graphql/-/api-graphql-3.1.3.tgz#4c780c90bbe748ca309ed3ade59348018de2b395"
+  integrity sha512-OHEU2XtvypSzeOPjvNZMlvD4p3lKM9pzBdLgsmxWgB3Qi6RLbYEuvTJGRTZRW1V3OHkGX4uMUUElLs8lTIbYgQ==
+  dependencies:
+    "@aws-amplify/api-rest" "3.0.15"
+    "@aws-amplify/auth" "5.1.9"
+    "@aws-amplify/cache" "5.0.15"
+    "@aws-amplify/core" "5.0.15"
+    "@aws-amplify/pubsub" "5.0.15"
+    graphql "15.8.0"
+    tslib "^1.8.0"
+    uuid "^3.2.1"
+    zen-observable-ts "0.8.19"
+
+"@aws-amplify/[email protected]":
+  version "3.0.15"
+  resolved "https://registry.yarnpkg.com/@aws-amplify/api-rest/-/api-rest-3.0.15.tgz#f01ae4f0970f8696eec6f26360acbc73d4b887e0"
+  integrity sha512-khn9PDLKhq+esxBLq5vM6K2Y3X2hSRrJuNQvA6MSsI2IQXT1eW9irSWYITDF323BrZAjF/QeaBB16xQ5XNKrNw==
+  dependencies:
+    "@aws-amplify/core" "5.0.15"
+    axios "0.26.0"
+    tslib "^1.8.0"
+
+"@aws-amplify/[email protected]":
+  version "5.0.15"
+  resolved "https://registry.yarnpkg.com/@aws-amplify/api/-/api-5.0.15.tgz#06a9b1690fe7b445e87a22d61f5c3c7d8608f241"
+  integrity sha512-z4R45Rr03c6CTk2hMaSXU3Ka/C/EDWQR+G4miJSe54FGmvywAXAvJ4aewfKlCCLuNHlzsGNdHhjKf8ld9SY/fA==
+  dependencies:
+    "@aws-amplify/api-graphql" "3.1.3"
+    "@aws-amplify/api-rest" "3.0.15"
+    tslib "^1.8.0"
+
+"@aws-amplify/[email protected]":
+  version "5.1.9"
+  resolved "https://registry.yarnpkg.com/@aws-amplify/auth/-/auth-5.1.9.tgz#c9b68dfbb4892e45506d2c16d67006a780911a08"
+  integrity sha512-PmPG3xA1HTU0OfVs+HokXie631xO8NgTokXLdBISVegg5ogDZBDRXKibf1h3MAPmqV5xTfywr+u3INKuwgawVQ==
+  dependencies:
+    "@aws-amplify/core" "5.0.15"
+    amazon-cognito-identity-js "6.1.2"
+    tslib "^1.8.0"
+
+"@aws-amplify/[email protected]":
+  version "5.0.15"
+  resolved "https://registry.yarnpkg.com/@aws-amplify/cache/-/cache-5.0.15.tgz#f5eb6258cd8d28c8750f5d23d2005b76eaf0c3d1"
+  integrity sha512-dP7pUIqATyVyKOIHxdDBNlwAnPU9TeU3Bujjy3OR7dAcSjCyCxnWiZGDG45a5BhYIwMd3iz/AoVh1cwkHphdKQ==
+  dependencies:
+    "@aws-amplify/core" "5.0.15"
+    tslib "^1.8.0"
+
+"@aws-amplify/[email protected]":
+  version "5.0.15"
+  resolved "https://registry.yarnpkg.com/@aws-amplify/core/-/core-5.0.15.tgz#4ec307ebba46877cffcae188794ad8453a39c508"
+  integrity sha512-BgskrlR/0oZSw8I1C8nuqiflzdbHcYr07+aSR0C7//mldtF594QzJaVE41R+s8lLsU4X7bLFTG1/oWUmswrkDg==
+  dependencies:
+    "@aws-crypto/sha256-js" "1.2.2"
+    "@aws-sdk/client-cloudwatch-logs" "3.6.1"
+    "@aws-sdk/client-cognito-identity" "3.6.1"
+    "@aws-sdk/credential-provider-cognito-identity" "3.6.1"
+    "@aws-sdk/types" "3.6.1"
+    "@aws-sdk/util-hex-encoding" "3.6.1"
+    tslib "^1.8.0"
+    universal-cookie "^4.0.4"
+    zen-observable-ts "0.8.19"
+
+"@aws-amplify/[email protected]":
+  version "4.0.15"
+  resolved "https://registry.yarnpkg.com/@aws-amplify/datastore/-/datastore-4.0.15.tgz#eb674320b3caabe0bf8dc683ea51b738909d624d"
+  integrity sha512-MjLq5nrUKl61WDdh0dvQWe8IhktAC7u4kBGN7iznCT0VkQi1LD1M/nMsSXNkJulhO2uQpZeHZ6fJROXB5Df70Q==
+  dependencies:
+    "@aws-amplify/api" "5.0.15"
+    "@aws-amplify/auth" "5.1.9"
+    "@aws-amplify/core" "5.0.15"
+    "@aws-amplify/pubsub" "5.0.15"
+    amazon-cognito-identity-js "6.1.2"
+    idb "5.0.6"
+    immer "9.0.6"
+    ulid "2.3.0"
+    uuid "3.4.0"
+    zen-observable-ts "0.8.19"
+    zen-push "0.2.1"
+
+"@aws-amplify/[email protected]":
+  version "2.0.15"
+  resolved "https://registry.yarnpkg.com/@aws-amplify/geo/-/geo-2.0.15.tgz#256504a6ac3fa2d55cf6964727c244fbe0c19961"
+  integrity sha512-SUkBgIs49BPk8Go/ZqqhW9pBrwOxHm+YI/jHSvzv4glsMAEMfat8CK2MtPpgQcg8QZkbVgzkxKWf4dBj2ko8dA==
+  dependencies:
+    "@aws-amplify/core" "5.0.15"
+    "@aws-sdk/client-location" "3.186.0"
+    "@turf/boolean-clockwise" "6.5.0"
+    camelcase-keys "6.2.2"
+    tslib "^1.8.0"
+
+"@aws-amplify/[email protected]":
+  version "5.0.15"
+  resolved "https://registry.yarnpkg.com/@aws-amplify/interactions/-/interactions-5.0.15.tgz#81504331717e7914cc99a6d8fe6277e60db6ebf6"
+  integrity sha512-lJzVszVMnTFi/MePhEUWGnx+Sgo8smlip7pZZCQ21G7PnEh5Yy84Jqg4f6zpGV+bRi9gMaKPLQlBMM31BTQXJw==
+  dependencies:
+    "@aws-amplify/core" "5.0.15"
+    "@aws-sdk/client-lex-runtime-service" "3.186.0"
+    "@aws-sdk/client-lex-runtime-v2" "3.186.0"
+    base-64 "1.0.0"
+    fflate "0.7.3"
+    pako "2.0.4"
+    tslib "^1.8.0"
+
+"@aws-amplify/[email protected]":
+  version "1.0.15"
+  resolved "https://registry.yarnpkg.com/@aws-amplify/notifications/-/notifications-1.0.15.tgz#10fa345a1b9f8b840bb1e57352aae09faa847bdb"
+  integrity sha512-MO5d2sHGlA68nhWkIw05ciopfZWDbR4hPC7ZkN/yRavoIBYSXSe+/DA5CDfmyjxM+8Rcg120IWqQb6SFFoq24w==
+  dependencies:
+    "@aws-amplify/cache" "5.0.15"
+    "@aws-amplify/core" "5.0.15"
+    "@aws-sdk/client-pinpoint" "3.186.0"
+    lodash "^4.17.21"
+    uuid "^3.2.1"
+
+"@aws-amplify/[email protected]":
+  version "5.0.15"
+  resolved "https://registry.yarnpkg.com/@aws-amplify/predictions/-/predictions-5.0.15.tgz#fea03a1e2fae6081b2cac135a1ceffff3f0f5f8d"
+  integrity sha512-MTdFRquHDSdmNwbTby6LGr3Dg4MOydwEft2mRAMlGj7OPuTSBbWeDB/bLxK3Gxl0Ql+fRMfKpf63EfkHjjv4xQ==
+  dependencies:
+    "@aws-amplify/core" "5.0.15"
+    "@aws-amplify/storage" "5.1.5"
+    "@aws-sdk/client-comprehend" "3.6.1"
+    "@aws-sdk/client-polly" "3.6.1"
+    "@aws-sdk/client-rekognition" "3.6.1"
+    "@aws-sdk/client-textract" "3.6.1"
+    "@aws-sdk/client-translate" "3.6.1"
+    "@aws-sdk/eventstream-marshaller" "3.6.1"
+    "@aws-sdk/util-utf8-node" "3.6.1"
+    tslib "^1.8.0"
+    uuid "^3.2.1"
+
+"@aws-amplify/[email protected]":
+  version "5.0.15"
+  resolved "https://registry.yarnpkg.com/@aws-amplify/pubsub/-/pubsub-5.0.15.tgz#8769c9efd7d5a67efd43ccf55feb5cae355d99e0"
+  integrity sha512-MMd6bHhLZTYJ7DwXeia43zyWIJkKWkuqgKZxeo9quStNQjt+KP/a2Z8EXAc18J7BUSGhTWxHvvv2lbYVI5X2Xw==
+  dependencies:
+    "@aws-amplify/auth" "5.1.9"
+    "@aws-amplify/cache" "5.0.15"
+    "@aws-amplify/core" "5.0.15"
+    graphql "15.8.0"
+    paho-mqtt "^1.1.0"
+    tslib "^1.8.0"
+    uuid "^3.2.1"
+    zen-observable-ts "0.8.19"
+
+"@aws-amplify/[email protected]":
+  version "5.1.5"
+  resolved "https://registry.yarnpkg.com/@aws-amplify/storage/-/storage-5.1.5.tgz#04cf1da252f3295626058ae18430ff150ce89ea5"
+  integrity sha512-ppFxwZD+pjkVFba70BsLEsQg70hl/8/m1iKLQJQFsToYlvLkeayk4QChCW1sL+8IPWdAV1v/c3ayOUmVA/utVg==
+  dependencies:
+    "@aws-amplify/core" "5.0.15"
+    "@aws-sdk/client-s3" "3.6.1"
+    "@aws-sdk/s3-request-presigner" "3.6.1"
+    "@aws-sdk/util-create-request" "3.6.1"
+    "@aws-sdk/util-format-url" "3.6.1"
+    axios "0.26.0"
+    events "^3.1.0"
+    tslib "^1.8.0"
+
+"@aws-amplify/[email protected]":
+  version "2.1.13"
+  resolved "https://registry.yarnpkg.com/@aws-amplify/ui-react-core/-/ui-react-core-2.1.13.tgz#c98beefbd3d1d58bde8947763863d9287d429111"
+  integrity sha512-jUzzULKM/0wQWuCoZKS6qc4zrqcGR7tgVcwTysBGJMjY5F8JJG0cTKR/1La+gUGPRT2W+/YiS62FwsD80ngysw==
+  dependencies:
+    "@aws-amplify/ui" "5.5.5"
+    "@xstate/react" "3.0.1"
+    lodash "4.17.21"
+    xstate "^4.33.6"
+
+"@aws-amplify/ui-react@^4.3.8":
+  version "4.3.8"
+  resolved "https://registry.yarnpkg.com/@aws-amplify/ui-react/-/ui-react-4.3.8.tgz#8efe9c923cd020537388dc1d5bc88a889e6c5c7f"
+  integrity sha512-5aOX5/1aVVE7uuNQhTsgPtvdN7nti9Ytcq7G75tX9BoGXu7yxWfXIdUKQhk3B6mcL+P4iXahsSy9b3oQ006YSQ==
+  dependencies:
+    "@aws-amplify/ui" "5.5.5"
+    "@aws-amplify/ui-react-core" "2.1.13"
+    "@radix-ui/react-accordion" "1.0.0"
+    "@radix-ui/react-direction" "1.0.0"
+    "@radix-ui/react-dropdown-menu" "1.0.0"
+    "@radix-ui/react-slider" "1.0.0"
+    "@radix-ui/react-tabs" "1.0.0"
+    "@xstate/react" "3.0.0"
+    classnames "2.3.1"
+    deepmerge "4.2.2"
+    lodash "4.17.21"
+    mapbox-gl "1.13.1"
+    maplibre-gl "2.1.9"
+    maplibre-gl-js-amplify "3.0.2"
+    qrcode "1.5.0"
+    react-generate-context "1.0.1"
+    react-map-gl "7.0.15"
+    tinycolor2 "1.4.2"
+    tslib "2.4.1"
+
+"@aws-amplify/[email protected]":
+  version "5.5.5"
+  resolved "https://registry.yarnpkg.com/@aws-amplify/ui/-/ui-5.5.5.tgz#c57906eec90c2aac8192de6a99faf18a00afc624"
+  integrity sha512-l4YECWJ72ZtottroyZ5ZZnxYT4QuoTKzZofg6ic/XAMH6pjUCtqNiqp0+K0tEqN7UlKQd1ggPkdMSpgsbaaEUQ==
+  dependencies:
+    csstype "^3.1.1"
+    lodash "4.17.21"
+    style-dictionary "3.7.1"
+    tslib "2.4.1"
+
+"@aws-amplify/[email protected]":
+  version "4.0.15"
+  resolved "https://registry.yarnpkg.com/@aws-amplify/xr/-/xr-4.0.15.tgz#34d94a80f8e4c8c21bd349e74651723f8f480aa7"
+  integrity sha512-+yT5rzE49hGLXyylThWB1zZc6Kvxdwz7l2YykEFqsFbb70pfZayr4pYnhg+wcVYBN5jDLlF5Gc+oquzhc9oP8w==
+  dependencies:
+    "@aws-amplify/core" "5.0.15"
+    tslib "^1.8.0"
+
+"@aws-crypto/[email protected]":
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/@aws-crypto/crc32/-/crc32-2.0.0.tgz#4ad432a3c03ec3087c5540ff6e41e6565d2dc153"
+  integrity sha512-TvE1r2CUueyXOuHdEigYjIZVesInd9KN+K/TFFNfkkxRThiNxO6i4ZqqAVMoEjAamZZ1AA8WXJkjCz7YShHPQA==
+  dependencies:
+    "@aws-crypto/util" "^2.0.0"
+    "@aws-sdk/types" "^3.1.0"
+    tslib "^1.11.1"
+
+"@aws-crypto/crc32@^1.0.0":
+  version "1.2.2"
+  resolved "https://registry.yarnpkg.com/@aws-crypto/crc32/-/crc32-1.2.2.tgz#4a758a596fa8cb3ab463f037a78c2ca4992fe81f"
+  integrity sha512-8K0b1672qbv05chSoKpwGZ3fhvVp28Fg3AVHVkEHFl2lTLChO7wD/hTyyo8ING7uc31uZRt7bNra/hA74Td7Tw==
+  dependencies:
+    "@aws-crypto/util" "^1.2.2"
+    "@aws-sdk/types" "^3.1.0"
+    tslib "^1.11.1"
+
+"@aws-crypto/ie11-detection@^1.0.0":
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/@aws-crypto/ie11-detection/-/ie11-detection-1.0.0.tgz#d3a6af29ba7f15458f79c41d1cd8cac3925e726a"
+  integrity sha512-kCKVhCF1oDxFYgQrxXmIrS5oaWulkvRcPz+QBDMsUr2crbF4VGgGT6+uQhSwJFdUAQ2A//Vq+uT83eJrkzFgXA==
+  dependencies:
+    tslib "^1.11.1"
+
+"@aws-crypto/ie11-detection@^2.0.0":
+  version "2.0.2"
+  resolved "https://registry.yarnpkg.com/@aws-crypto/ie11-detection/-/ie11-detection-2.0.2.tgz#9c39f4a5558196636031a933ec1b4792de959d6a"
+  integrity sha512-5XDMQY98gMAf/WRTic5G++jfmS/VLM0rwpiOpaainKi4L0nqWMSB1SzsrEG5rjFZGYN6ZAefO+/Yta2dFM0kMw==
+  dependencies:
+    tslib "^1.11.1"
+
+"@aws-crypto/[email protected]":
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/@aws-crypto/sha256-browser/-/sha256-browser-2.0.0.tgz#741c9024df55ec59b51e5b1f5d806a4852699fb5"
+  integrity sha512-rYXOQ8BFOaqMEHJrLHul/25ckWH6GTJtdLSajhlqGMx0PmSueAuvboCuZCTqEKlxR8CQOwRarxYMZZSYlhRA1A==
+  dependencies:
+    "@aws-crypto/ie11-detection" "^2.0.0"
+    "@aws-crypto/sha256-js" "^2.0.0"
+    "@aws-crypto/supports-web-crypto" "^2.0.0"
+    "@aws-crypto/util" "^2.0.0"
+    "@aws-sdk/types" "^3.1.0"
+    "@aws-sdk/util-locate-window" "^3.0.0"
+    "@aws-sdk/util-utf8-browser" "^3.0.0"
+    tslib "^1.11.1"
+
+"@aws-crypto/sha256-browser@^1.0.0":
+  version "1.2.2"
+  resolved "https://registry.yarnpkg.com/@aws-crypto/sha256-browser/-/sha256-browser-1.2.2.tgz#004d806e3bbae130046c259ec3279a02d4a0b576"
+  integrity sha512-0tNR4kBtJp+9S0kis4+JLab3eg6QWuIeuPhzaYoYwNUXGBgsWIkktA2mnilet+EGWzf3n1zknJXC4X4DVyyXbg==
+  dependencies:
+    "@aws-crypto/ie11-detection" "^1.0.0"
+    "@aws-crypto/sha256-js" "^1.2.2"
+    "@aws-crypto/supports-web-crypto" "^1.0.0"
+    "@aws-crypto/util" "^1.2.2"
+    "@aws-sdk/types" "^3.1.0"
+    "@aws-sdk/util-locate-window" "^3.0.0"
+    tslib "^1.11.1"
+
+"@aws-crypto/[email protected]", "@aws-crypto/sha256-js@^1.0.0", "@aws-crypto/sha256-js@^1.2.2":
+  version "1.2.2"
+  resolved "https://registry.yarnpkg.com/@aws-crypto/sha256-js/-/sha256-js-1.2.2.tgz#02acd1a1fda92896fc5a28ec7c6e164644ea32fc"
+  integrity sha512-Nr1QJIbW/afYYGzYvrF70LtaHrIRtd4TNAglX8BvlfxJLZ45SAmueIKYl5tWoNBPzp65ymXGFK0Bb1vZUpuc9g==
+  dependencies:
+    "@aws-crypto/util" "^1.2.2"
+    "@aws-sdk/types" "^3.1.0"
+    tslib "^1.11.1"
+
+"@aws-crypto/[email protected]":
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/@aws-crypto/sha256-js/-/sha256-js-2.0.0.tgz#f1f936039bdebd0b9e2dd834d65afdc2aac4efcb"
+  integrity sha512-VZY+mCY4Nmrs5WGfitmNqXzaE873fcIZDu54cbaDaaamsaTOP1DBImV9F4pICc3EHjQXujyE8jig+PFCaew9ig==
+  dependencies:
+    "@aws-crypto/util" "^2.0.0"
+    "@aws-sdk/types" "^3.1.0"
+    tslib "^1.11.1"
+
+"@aws-crypto/sha256-js@^2.0.0":
+  version "2.0.2"
+  resolved "https://registry.yarnpkg.com/@aws-crypto/sha256-js/-/sha256-js-2.0.2.tgz#c81e5d378b8a74ff1671b58632779986e50f4c99"
+  integrity sha512-iXLdKH19qPmIC73fVCrHWCSYjN/sxaAvZ3jNNyw6FclmHyjLKg0f69WlC9KTnyElxCR5MO9SKaG00VwlJwyAkQ==
+  dependencies:
+    "@aws-crypto/util" "^2.0.2"
+    "@aws-sdk/types" "^3.110.0"
+    tslib "^1.11.1"
+
+"@aws-crypto/supports-web-crypto@^1.0.0":
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/@aws-crypto/supports-web-crypto/-/supports-web-crypto-1.0.0.tgz#c40901bc17ac1e875e248df16a2b47ad8bfd9a93"
+  integrity sha512-IHLfv+WmVH89EW4n6a5eE8/hUlz6qkWGMn/v4r5ZgzcXdTC5nolii2z3k46y01hWRiC2PPhOdeSLzMUCUMco7g==
+  dependencies:
+    tslib "^1.11.1"
+
+"@aws-crypto/supports-web-crypto@^2.0.0":
+  version "2.0.2"
+  resolved "https://registry.yarnpkg.com/@aws-crypto/supports-web-crypto/-/supports-web-crypto-2.0.2.tgz#9f02aafad8789cac9c0ab5faaebb1ab8aa841338"
+  integrity sha512-6mbSsLHwZ99CTOOswvCRP3C+VCWnzBf+1SnbWxzzJ9lR0mA0JnY2JEAhp8rqmTE0GPFy88rrM27ffgp62oErMQ==
+  dependencies:
+    tslib "^1.11.1"
+
+"@aws-crypto/util@^1.2.2":
+  version "1.2.2"
+  resolved "https://registry.yarnpkg.com/@aws-crypto/util/-/util-1.2.2.tgz#b28f7897730eb6538b21c18bd4de22d0ea09003c"
+  integrity sha512-H8PjG5WJ4wz0UXAFXeJjWCW1vkvIJ3qUUD+rGRwJ2/hj+xT58Qle2MTql/2MGzkU+1JLAFuR6aJpLAjHwhmwwg==
+  dependencies:
+    "@aws-sdk/types" "^3.1.0"
+    "@aws-sdk/util-utf8-browser" "^3.0.0"
+    tslib "^1.11.1"
+
+"@aws-crypto/util@^2.0.0", "@aws-crypto/util@^2.0.2":
+  version "2.0.2"
+  resolved "https://registry.yarnpkg.com/@aws-crypto/util/-/util-2.0.2.tgz#adf5ff5dfbc7713082f897f1d01e551ce0edb9c0"
+  integrity sha512-Lgu5v/0e/BcrZ5m/IWqzPUf3UYFTy/PpeED+uc9SWUR1iZQL8XXbGQg10UfllwwBryO3hFF5dizK+78aoXC1eA==
+  dependencies:
+    "@aws-sdk/types" "^3.110.0"
+    "@aws-sdk/util-utf8-browser" "^3.0.0"
+    tslib "^1.11.1"
+
+"@aws-sdk/[email protected]":
+  version "3.186.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/abort-controller/-/abort-controller-3.186.0.tgz#dfaccd296d57136930582e1a19203d6cb60debc7"
+  integrity sha512-JFvvvtEcbYOvVRRXasi64Dd1VcOz5kJmPvtzsJ+HzMHvPbGGs/aopOJAZQJMJttzJmJwVTay0QL6yag9Kk8nYA==
+  dependencies:
+    "@aws-sdk/types" "3.186.0"
+    tslib "^2.3.1"
+
+"@aws-sdk/[email protected]":
+  version "3.6.1"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/abort-controller/-/abort-controller-3.6.1.tgz#75812875bbef6ad17e0e3a6d96aab9df636376f9"
+  integrity sha512-X81XkxX/2Tvv9YNcEto/rcQzPIdKJHFSnl9hBl/qkSdCFV/GaQ2XNWfKm5qFXMLlZNFS0Fn5CnBJ83qnBm47vg==
+  dependencies:
+    "@aws-sdk/types" "3.6.1"
+    tslib "^1.8.0"
+
+"@aws-sdk/[email protected]":
+  version "3.6.1"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/chunked-blob-reader-native/-/chunked-blob-reader-native-3.6.1.tgz#21c2c8773c3cd8403c2a953fd0e9e4f69c120214"
+  integrity sha512-vP6bc2v9h442Srmo7t2QcIbPjk5IqLSf4jGnKDAes8z+7eyjCtKugRP3lOM1fJCfGlPIsJGYnexxYdEGw008vA==
+  dependencies:
+    "@aws-sdk/util-base64-browser" "3.6.1"
+    tslib "^1.8.0"
+
+"@aws-sdk/[email protected]":
+  version "3.6.1"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/chunked-blob-reader/-/chunked-blob-reader-3.6.1.tgz#63363025dcecc2f9dd47ae5c282d79c01b327d82"
+  integrity sha512-QBGUBoD8D5nsM/EKoc0rjpApa5NE5pQVzw1caE8sG00QMMPkCXWSB/gTVKVY0GOAhJFoA/VpVPQchIlZcOrBFg==
+  dependencies:
+    tslib "^1.8.0"
+
+"@aws-sdk/[email protected]":
+  version "3.6.1"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/client-cloudwatch-logs/-/client-cloudwatch-logs-3.6.1.tgz#5e8dba495a2ba9a901b0a1a2d53edef8bd452398"
+  integrity sha512-QOxIDnlVTpnwJ26Gap6RGz61cDLH6TKrIp30VqwdMeT1pCGy8mn9rWln6XA+ymkofHy/08RfpGp+VN4axwd4Lw==
+  dependencies:
+    "@aws-crypto/sha256-browser" "^1.0.0"
+    "@aws-crypto/sha256-js" "^1.0.0"
+    "@aws-sdk/config-resolver" "3.6.1"
+    "@aws-sdk/credential-provider-node" "3.6.1"
+    "@aws-sdk/fetch-http-handler" "3.6.1"
+    "@aws-sdk/hash-node" "3.6.1"
+    "@aws-sdk/invalid-dependency" "3.6.1"
+    "@aws-sdk/middleware-content-length" "3.6.1"
+    "@aws-sdk/middleware-host-header" "3.6.1"
+    "@aws-sdk/middleware-logger" "3.6.1"
+    "@aws-sdk/middleware-retry" "3.6.1"
+    "@aws-sdk/middleware-serde" "3.6.1"
+    "@aws-sdk/middleware-signing" "3.6.1"
+    "@aws-sdk/middleware-stack" "3.6.1"
+    "@aws-sdk/middleware-user-agent" "3.6.1"
+    "@aws-sdk/node-config-provider" "3.6.1"
+    "@aws-sdk/node-http-handler" "3.6.1"
+    "@aws-sdk/protocol-http" "3.6.1"
+    "@aws-sdk/smithy-client" "3.6.1"
+    "@aws-sdk/types" "3.6.1"
+    "@aws-sdk/url-parser" "3.6.1"
+    "@aws-sdk/url-parser-native" "3.6.1"
+    "@aws-sdk/util-base64-browser" "3.6.1"
+    "@aws-sdk/util-base64-node" "3.6.1"
+    "@aws-sdk/util-body-length-browser" "3.6.1"
+    "@aws-sdk/util-body-length-node" "3.6.1"
+    "@aws-sdk/util-user-agent-browser" "3.6.1"
+    "@aws-sdk/util-user-agent-node" "3.6.1"
+    "@aws-sdk/util-utf8-browser" "3.6.1"
+    "@aws-sdk/util-utf8-node" "3.6.1"
+    tslib "^2.0.0"
+
+"@aws-sdk/[email protected]":
+  version "3.6.1"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/client-cognito-identity/-/client-cognito-identity-3.6.1.tgz#36992a4fef7eff1f2b1dbee30850e30ebdfc15bb"
+  integrity sha512-FMj2GR9R5oCKb3/NI16GIvWeHcE4uX42fBAaQKPbjg2gALFDx9CcJYsdOtDP37V89GtPyZilLv6GJxrwJKzYGg==
+  dependencies:
+    "@aws-crypto/sha256-browser" "^1.0.0"
+    "@aws-crypto/sha256-js" "^1.0.0"
+    "@aws-sdk/config-resolver" "3.6.1"
+    "@aws-sdk/credential-provider-node" "3.6.1"
+    "@aws-sdk/fetch-http-handler" "3.6.1"
+    "@aws-sdk/hash-node" "3.6.1"
+    "@aws-sdk/invalid-dependency" "3.6.1"
+    "@aws-sdk/middleware-content-length" "3.6.1"
+    "@aws-sdk/middleware-host-header" "3.6.1"
+    "@aws-sdk/middleware-logger" "3.6.1"
+    "@aws-sdk/middleware-retry" "3.6.1"
+    "@aws-sdk/middleware-serde" "3.6.1"
+    "@aws-sdk/middleware-signing" "3.6.1"
+    "@aws-sdk/middleware-stack" "3.6.1"
+    "@aws-sdk/middleware-user-agent" "3.6.1"
+    "@aws-sdk/node-config-provider" "3.6.1"
+    "@aws-sdk/node-http-handler" "3.6.1"
+    "@aws-sdk/protocol-http" "3.6.1"
+    "@aws-sdk/smithy-client" "3.6.1"
+    "@aws-sdk/types" "3.6.1"
+    "@aws-sdk/url-parser" "3.6.1"
+    "@aws-sdk/url-parser-native" "3.6.1"
+    "@aws-sdk/util-base64-browser" "3.6.1"
+    "@aws-sdk/util-base64-node" "3.6.1"
+    "@aws-sdk/util-body-length-browser" "3.6.1"
+    "@aws-sdk/util-body-length-node" "3.6.1"
+    "@aws-sdk/util-user-agent-browser" "3.6.1"
+    "@aws-sdk/util-user-agent-node" "3.6.1"
+    "@aws-sdk/util-utf8-browser" "3.6.1"
+    "@aws-sdk/util-utf8-node" "3.6.1"
+    tslib "^2.0.0"
+
+"@aws-sdk/[email protected]":
+  version "3.6.1"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/client-comprehend/-/client-comprehend-3.6.1.tgz#d640d510b49feafa94ac252cdd7942cbe5537249"
+  integrity sha512-Y2ixlSTjjAp2HJhkUArtYqC/X+zG5Qqu3Bl+Ez22u4u4YnG8HsNFD6FE1axuWSdSa5AFtWTEt+Cz2Ghj/tDySA==
+  dependencies:
+    "@aws-crypto/sha256-browser" "^1.0.0"
+    "@aws-crypto/sha256-js" "^1.0.0"
+    "@aws-sdk/config-resolver" "3.6.1"
+    "@aws-sdk/credential-provider-node" "3.6.1"
+    "@aws-sdk/fetch-http-handler" "3.6.1"
+    "@aws-sdk/hash-node" "3.6.1"
+    "@aws-sdk/invalid-dependency" "3.6.1"
+    "@aws-sdk/middleware-content-length" "3.6.1"
+    "@aws-sdk/middleware-host-header" "3.6.1"
+    "@aws-sdk/middleware-logger" "3.6.1"
+    "@aws-sdk/middleware-retry" "3.6.1"
+    "@aws-sdk/middleware-serde" "3.6.1"
+    "@aws-sdk/middleware-signing" "3.6.1"
+    "@aws-sdk/middleware-stack" "3.6.1"
+    "@aws-sdk/middleware-user-agent" "3.6.1"
+    "@aws-sdk/node-config-provider" "3.6.1"
+    "@aws-sdk/node-http-handler" "3.6.1"
+    "@aws-sdk/protocol-http" "3.6.1"
+    "@aws-sdk/smithy-client" "3.6.1"
+    "@aws-sdk/types" "3.6.1"
+    "@aws-sdk/url-parser" "3.6.1"
+    "@aws-sdk/url-parser-native" "3.6.1"
+    "@aws-sdk/util-base64-browser" "3.6.1"
+    "@aws-sdk/util-base64-node" "3.6.1"
+    "@aws-sdk/util-body-length-browser" "3.6.1"
+    "@aws-sdk/util-body-length-node" "3.6.1"
+    "@aws-sdk/util-user-agent-browser" "3.6.1"
+    "@aws-sdk/util-user-agent-node" "3.6.1"
+    "@aws-sdk/util-utf8-browser" "3.6.1"
+    "@aws-sdk/util-utf8-node" "3.6.1"
+    tslib "^2.0.0"
+    uuid "^3.0.0"
+
+"@aws-sdk/[email protected]":
+  version "3.6.1"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/client-firehose/-/client-firehose-3.6.1.tgz#87a8ef0c18267907b3ce712e6d3de8f36b0a7c7b"
+  integrity sha512-KhiKCm+cJmnRFuAEyO3DBpFVDNix1XcVikdxk2lvYbFWkM1oUZoBpudxaJ+fPf2W3stF3CXIAOP+TnGqSZCy9g==
+  dependencies:
+    "@aws-crypto/sha256-browser" "^1.0.0"
+    "@aws-crypto/sha256-js" "^1.0.0"
+    "@aws-sdk/config-resolver" "3.6.1"
+    "@aws-sdk/credential-provider-node" "3.6.1"
+    "@aws-sdk/fetch-http-handler" "3.6.1"
+    "@aws-sdk/hash-node" "3.6.1"
+    "@aws-sdk/invalid-dependency" "3.6.1"
+    "@aws-sdk/middleware-content-length" "3.6.1"
+    "@aws-sdk/middleware-host-header" "3.6.1"
+    "@aws-sdk/middleware-logger" "3.6.1"
+    "@aws-sdk/middleware-retry" "3.6.1"
+    "@aws-sdk/middleware-serde" "3.6.1"
+    "@aws-sdk/middleware-signing" "3.6.1"
+    "@aws-sdk/middleware-stack" "3.6.1"
+    "@aws-sdk/middleware-user-agent" "3.6.1"
+    "@aws-sdk/node-config-provider" "3.6.1"
+    "@aws-sdk/node-http-handler" "3.6.1"
+    "@aws-sdk/protocol-http" "3.6.1"
+    "@aws-sdk/smithy-client" "3.6.1"
+    "@aws-sdk/types" "3.6.1"
+    "@aws-sdk/url-parser" "3.6.1"
+    "@aws-sdk/url-parser-native" "3.6.1"
+    "@aws-sdk/util-base64-browser" "3.6.1"
+    "@aws-sdk/util-base64-node" "3.6.1"
+    "@aws-sdk/util-body-length-browser" "3.6.1"
+    "@aws-sdk/util-body-length-node" "3.6.1"
+    "@aws-sdk/util-user-agent-browser" "3.6.1"
+    "@aws-sdk/util-user-agent-node" "3.6.1"
+    "@aws-sdk/util-utf8-browser" "3.6.1"
+    "@aws-sdk/util-utf8-node" "3.6.1"
+    tslib "^2.0.0"
+
+"@aws-sdk/[email protected]":
+  version "3.6.1"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/client-kinesis/-/client-kinesis-3.6.1.tgz#48583cc854f9108bc8ff6168005d9a05b24bae31"
+  integrity sha512-Ygo+92LxHeUZmiyhiHT+k7hIOhJd6S7ckCEVUsQs2rfwe9bAygUY/3cCoZSqgWy7exFRRKsjhzStcyV6i6jrVQ==
+  dependencies:
+    "@aws-crypto/sha256-browser" "^1.0.0"
+    "@aws-crypto/sha256-js" "^1.0.0"
+    "@aws-sdk/config-resolver" "3.6.1"
+    "@aws-sdk/credential-provider-node" "3.6.1"
+    "@aws-sdk/eventstream-serde-browser" "3.6.1"
+    "@aws-sdk/eventstream-serde-config-resolver" "3.6.1"
+    "@aws-sdk/eventstream-serde-node" "3.6.1"
+    "@aws-sdk/fetch-http-handler" "3.6.1"
+    "@aws-sdk/hash-node" "3.6.1"
+    "@aws-sdk/invalid-dependency" "3.6.1"
+    "@aws-sdk/middleware-content-length" "3.6.1"
+    "@aws-sdk/middleware-host-header" "3.6.1"
+    "@aws-sdk/middleware-logger" "3.6.1"
+    "@aws-sdk/middleware-retry" "3.6.1"
+    "@aws-sdk/middleware-serde" "3.6.1"
+    "@aws-sdk/middleware-signing" "3.6.1"
+    "@aws-sdk/middleware-stack" "3.6.1"
+    "@aws-sdk/middleware-user-agent" "3.6.1"
+    "@aws-sdk/node-config-provider" "3.6.1"
+    "@aws-sdk/node-http-handler" "3.6.1"
+    "@aws-sdk/protocol-http" "3.6.1"
+    "@aws-sdk/smithy-client" "3.6.1"
+    "@aws-sdk/types" "3.6.1"
+    "@aws-sdk/url-parser" "3.6.1"
+    "@aws-sdk/url-parser-native" "3.6.1"
+    "@aws-sdk/util-base64-browser" "3.6.1"
+    "@aws-sdk/util-base64-node" "3.6.1"
+    "@aws-sdk/util-body-length-browser" "3.6.1"
+    "@aws-sdk/util-body-length-node" "3.6.1"
+    "@aws-sdk/util-user-agent-browser" "3.6.1"
+    "@aws-sdk/util-user-agent-node" "3.6.1"
+    "@aws-sdk/util-utf8-browser" "3.6.1"
+    "@aws-sdk/util-utf8-node" "3.6.1"
+    "@aws-sdk/util-waiter" "3.6.1"
+    tslib "^2.0.0"
+
+"@aws-sdk/[email protected]":
+  version "3.186.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/client-lex-runtime-service/-/client-lex-runtime-service-3.186.0.tgz#81deea7402cb76e7f2dce56bc5778e51909e1374"
+  integrity sha512-EgjQvFxa/o1urxpnWV2A/D0k4m763NqrPLuL074LR+cOkNxVl9W27aYL/tddDBmmDzzx4KcuRL6/n+UBZIheTg==
+  dependencies:
+    "@aws-crypto/sha256-browser" "2.0.0"
+    "@aws-crypto/sha256-js" "2.0.0"
+    "@aws-sdk/client-sts" "3.186.0"
+    "@aws-sdk/config-resolver" "3.186.0"
+    "@aws-sdk/credential-provider-node" "3.186.0"
+    "@aws-sdk/fetch-http-handler" "3.186.0"
+    "@aws-sdk/hash-node" "3.186.0"
+    "@aws-sdk/invalid-dependency" "3.186.0"
+    "@aws-sdk/middleware-content-length" "3.186.0"
+    "@aws-sdk/middleware-host-header" "3.186.0"
+    "@aws-sdk/middleware-logger" "3.186.0"
+    "@aws-sdk/middleware-recursion-detection" "3.186.0"
+    "@aws-sdk/middleware-retry" "3.186.0"
+    "@aws-sdk/middleware-serde" "3.186.0"
+    "@aws-sdk/middleware-signing" "3.186.0"
+    "@aws-sdk/middleware-stack" "3.186.0"
+    "@aws-sdk/middleware-user-agent" "3.186.0"
+    "@aws-sdk/node-config-provider" "3.186.0"
+    "@aws-sdk/node-http-handler" "3.186.0"
+    "@aws-sdk/protocol-http" "3.186.0"
+    "@aws-sdk/smithy-client" "3.186.0"
+    "@aws-sdk/types" "3.186.0"
+    "@aws-sdk/url-parser" "3.186.0"
+    "@aws-sdk/util-base64-browser" "3.186.0"
+    "@aws-sdk/util-base64-node" "3.186.0"
+    "@aws-sdk/util-body-length-browser" "3.186.0"
+    "@aws-sdk/util-body-length-node" "3.186.0"
+    "@aws-sdk/util-defaults-mode-browser" "3.186.0"
+    "@aws-sdk/util-defaults-mode-node" "3.186.0"
+    "@aws-sdk/util-user-agent-browser" "3.186.0"
+    "@aws-sdk/util-user-agent-node" "3.186.0"
+    "@aws-sdk/util-utf8-browser" "3.186.0"
+    "@aws-sdk/util-utf8-node" "3.186.0"
+    tslib "^2.3.1"
+
+"@aws-sdk/[email protected]":
+  version "3.186.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/client-lex-runtime-v2/-/client-lex-runtime-v2-3.186.0.tgz#36d153f80e1dbc466c541fd70002d5f9846c9afa"
+  integrity sha512-oDN07yCWc9gsEYL44KSjPj8wdHHcf5Kti+w31fE7JHZqvRXxLsLx7G+kEcPmSTRk3Y4wDPXJozL6sDUAOAEb7A==
+  dependencies:
+    "@aws-crypto/sha256-browser" "2.0.0"
+    "@aws-crypto/sha256-js" "2.0.0"
+    "@aws-sdk/client-sts" "3.186.0"
+    "@aws-sdk/config-resolver" "3.186.0"
+    "@aws-sdk/credential-provider-node" "3.186.0"
+    "@aws-sdk/eventstream-handler-node" "3.186.0"
+    "@aws-sdk/eventstream-serde-browser" "3.186.0"
+    "@aws-sdk/eventstream-serde-config-resolver" "3.186.0"
+    "@aws-sdk/eventstream-serde-node" "3.186.0"
+    "@aws-sdk/fetch-http-handler" "3.186.0"
+    "@aws-sdk/hash-node" "3.186.0"
+    "@aws-sdk/invalid-dependency" "3.186.0"
+    "@aws-sdk/middleware-content-length" "3.186.0"
+    "@aws-sdk/middleware-eventstream" "3.186.0"
+    "@aws-sdk/middleware-host-header" "3.186.0"
+    "@aws-sdk/middleware-logger" "3.186.0"
+    "@aws-sdk/middleware-recursion-detection" "3.186.0"
+    "@aws-sdk/middleware-retry" "3.186.0"
+    "@aws-sdk/middleware-serde" "3.186.0"
+    "@aws-sdk/middleware-signing" "3.186.0"
+    "@aws-sdk/middleware-stack" "3.186.0"
+    "@aws-sdk/middleware-user-agent" "3.186.0"
+    "@aws-sdk/node-config-provider" "3.186.0"
+    "@aws-sdk/node-http-handler" "3.186.0"
+    "@aws-sdk/protocol-http" "3.186.0"
+    "@aws-sdk/smithy-client" "3.186.0"
+    "@aws-sdk/types" "3.186.0"
+    "@aws-sdk/url-parser" "3.186.0"
+    "@aws-sdk/util-base64-browser" "3.186.0"
+    "@aws-sdk/util-base64-node" "3.186.0"
+    "@aws-sdk/util-body-length-browser" "3.186.0"
+    "@aws-sdk/util-body-length-node" "3.186.0"
+    "@aws-sdk/util-defaults-mode-browser" "3.186.0"
+    "@aws-sdk/util-defaults-mode-node" "3.186.0"
+    "@aws-sdk/util-user-agent-browser" "3.186.0"
+    "@aws-sdk/util-user-agent-node" "3.186.0"
+    "@aws-sdk/util-utf8-browser" "3.186.0"
+    "@aws-sdk/util-utf8-node" "3.186.0"
+    tslib "^2.3.1"
+
+"@aws-sdk/[email protected]":
+  version "3.186.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/client-location/-/client-location-3.186.0.tgz#0801433a1c3fb1fe534771daf67b5d57ffd474f4"
+  integrity sha512-RXT1Z7jgYrPEdD1VkErH9Wm+z6y7c/ua1Pu9VQ8weu9vtD15S8Qnyd1m4HS8ZPQUUM/gTxs/fL9+s53wRWpfGQ==
+  dependencies:
+    "@aws-crypto/sha256-browser" "2.0.0"
+    "@aws-crypto/sha256-js" "2.0.0"
+    "@aws-sdk/client-sts" "3.186.0"
+    "@aws-sdk/config-resolver" "3.186.0"
+    "@aws-sdk/credential-provider-node" "3.186.0"
+    "@aws-sdk/fetch-http-handler" "3.186.0"
+    "@aws-sdk/hash-node" "3.186.0"
+    "@aws-sdk/invalid-dependency" "3.186.0"
+    "@aws-sdk/middleware-content-length" "3.186.0"
+    "@aws-sdk/middleware-host-header" "3.186.0"
+    "@aws-sdk/middleware-logger" "3.186.0"
+    "@aws-sdk/middleware-recursion-detection" "3.186.0"
+    "@aws-sdk/middleware-retry" "3.186.0"
+    "@aws-sdk/middleware-serde" "3.186.0"
+    "@aws-sdk/middleware-signing" "3.186.0"
+    "@aws-sdk/middleware-stack" "3.186.0"
+    "@aws-sdk/middleware-user-agent" "3.186.0"
+    "@aws-sdk/node-config-provider" "3.186.0"
+    "@aws-sdk/node-http-handler" "3.186.0"
+    "@aws-sdk/protocol-http" "3.186.0"
+    "@aws-sdk/smithy-client" "3.186.0"
+    "@aws-sdk/types" "3.186.0"
+    "@aws-sdk/url-parser" "3.186.0"
+    "@aws-sdk/util-base64-browser" "3.186.0"
+    "@aws-sdk/util-base64-node" "3.186.0"
+    "@aws-sdk/util-body-length-browser" "3.186.0"
+    "@aws-sdk/util-body-length-node" "3.186.0"
+    "@aws-sdk/util-defaults-mode-browser" "3.186.0"
+    "@aws-sdk/util-defaults-mode-node" "3.186.0"
+    "@aws-sdk/util-user-agent-browser" "3.186.0"
+    "@aws-sdk/util-user-agent-node" "3.186.0"
+    "@aws-sdk/util-utf8-browser" "3.186.0"
+    "@aws-sdk/util-utf8-node" "3.186.0"
+    tslib "^2.3.1"
+
+"@aws-sdk/[email protected]":
+  version "3.6.1"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/client-personalize-events/-/client-personalize-events-3.6.1.tgz#86942bb64108cfc2f6c31a8b54aab6fa7f7be00f"
+  integrity sha512-x9Jl/7emSQsB6GwBvjyw5BiSO26CnH4uvjNit6n54yNMtJ26q0+oIxkplnUDyjLTfLRe373c/z5/4dQQtDffkw==
+  dependencies:
+    "@aws-crypto/sha256-browser" "^1.0.0"
+    "@aws-crypto/sha256-js" "^1.0.0"
+    "@aws-sdk/config-resolver" "3.6.1"
+    "@aws-sdk/credential-provider-node" "3.6.1"
+    "@aws-sdk/fetch-http-handler" "3.6.1"
+    "@aws-sdk/hash-node" "3.6.1"
+    "@aws-sdk/invalid-dependency" "3.6.1"
+    "@aws-sdk/middleware-content-length" "3.6.1"
+    "@aws-sdk/middleware-host-header" "3.6.1"
+    "@aws-sdk/middleware-logger" "3.6.1"
+    "@aws-sdk/middleware-retry" "3.6.1"
+    "@aws-sdk/middleware-serde" "3.6.1"
+    "@aws-sdk/middleware-signing" "3.6.1"
+    "@aws-sdk/middleware-stack" "3.6.1"
+    "@aws-sdk/middleware-user-agent" "3.6.1"
+    "@aws-sdk/node-config-provider" "3.6.1"
+    "@aws-sdk/node-http-handler" "3.6.1"
+    "@aws-sdk/protocol-http" "3.6.1"
+    "@aws-sdk/smithy-client" "3.6.1"
+    "@aws-sdk/types" "3.6.1"
+    "@aws-sdk/url-parser" "3.6.1"
+    "@aws-sdk/url-parser-native" "3.6.1"
+    "@aws-sdk/util-base64-browser" "3.6.1"
+    "@aws-sdk/util-base64-node" "3.6.1"
+    "@aws-sdk/util-body-length-browser" "3.6.1"
+    "@aws-sdk/util-body-length-node" "3.6.1"
+    "@aws-sdk/util-user-agent-browser" "3.6.1"
+    "@aws-sdk/util-user-agent-node" "3.6.1"
+    "@aws-sdk/util-utf8-browser" "3.6.1"
+    "@aws-sdk/util-utf8-node" "3.6.1"
+    tslib "^2.0.0"
+
+"@aws-sdk/[email protected]":
+  version "3.186.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/client-pinpoint/-/client-pinpoint-3.186.0.tgz#d0e63ee9883024e89bc56cf0e01baf01eda00f55"
+  integrity sha512-gTVIU+c4WSgvNDTIXTfVFqrHbMtxcjviqZMop+N62OtJO+xQ8tg9nKmfIlhTuErV7BrI4u3djk7bYE+atfP9dQ==
+  dependencies:
+    "@aws-crypto/sha256-browser" "2.0.0"
+    "@aws-crypto/sha256-js" "2.0.0"
+    "@aws-sdk/client-sts" "3.186.0"
+    "@aws-sdk/config-resolver" "3.186.0"
+    "@aws-sdk/credential-provider-node" "3.186.0"
+    "@aws-sdk/fetch-http-handler" "3.186.0"
+    "@aws-sdk/hash-node" "3.186.0"
+    "@aws-sdk/invalid-dependency" "3.186.0"
+    "@aws-sdk/middleware-content-length" "3.186.0"
+    "@aws-sdk/middleware-host-header" "3.186.0"
+    "@aws-sdk/middleware-logger" "3.186.0"
+    "@aws-sdk/middleware-recursion-detection" "3.186.0"
+    "@aws-sdk/middleware-retry" "3.186.0"
+    "@aws-sdk/middleware-serde" "3.186.0"
+    "@aws-sdk/middleware-signing" "3.186.0"
+    "@aws-sdk/middleware-stack" "3.186.0"
+    "@aws-sdk/middleware-user-agent" "3.186.0"
+    "@aws-sdk/node-config-provider" "3.186.0"
+    "@aws-sdk/node-http-handler" "3.186.0"
+    "@aws-sdk/protocol-http" "3.186.0"
+    "@aws-sdk/smithy-client" "3.186.0"
+    "@aws-sdk/types" "3.186.0"
+    "@aws-sdk/url-parser" "3.186.0"
+    "@aws-sdk/util-base64-browser" "3.186.0"
+    "@aws-sdk/util-base64-node" "3.186.0"
+    "@aws-sdk/util-body-length-browser" "3.186.0"
+    "@aws-sdk/util-body-length-node" "3.186.0"
+    "@aws-sdk/util-defaults-mode-browser" "3.186.0"
+    "@aws-sdk/util-defaults-mode-node" "3.186.0"
+    "@aws-sdk/util-user-agent-browser" "3.186.0"
+    "@aws-sdk/util-user-agent-node" "3.186.0"
+    "@aws-sdk/util-utf8-browser" "3.186.0"
+    "@aws-sdk/util-utf8-node" "3.186.0"
+    tslib "^2.3.1"
+
+"@aws-sdk/[email protected]":
+  version "3.6.1"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/client-pinpoint/-/client-pinpoint-3.6.1.tgz#6b93f46475ae2667d77053be51ea62f52e330155"
+  integrity sha512-dueBedp91EKAHxcWLR3aNx/eUEdxdF9niEQTzOO2O4iJL2yvO2Hh7ZYiO7B3g7FuuICTpWSHd//Y9mGmSVLMCg==
+  dependencies:
+    "@aws-crypto/sha256-browser" "^1.0.0"
+    "@aws-crypto/sha256-js" "^1.0.0"
+    "@aws-sdk/config-resolver" "3.6.1"
+    "@aws-sdk/credential-provider-node" "3.6.1"
+    "@aws-sdk/fetch-http-handler" "3.6.1"
+    "@aws-sdk/hash-node" "3.6.1"
+    "@aws-sdk/invalid-dependency" "3.6.1"
+    "@aws-sdk/middleware-content-length" "3.6.1"
+    "@aws-sdk/middleware-host-header" "3.6.1"
+    "@aws-sdk/middleware-logger" "3.6.1"
+    "@aws-sdk/middleware-retry" "3.6.1"
+    "@aws-sdk/middleware-serde" "3.6.1"
+    "@aws-sdk/middleware-signing" "3.6.1"
+    "@aws-sdk/middleware-stack" "3.6.1"
+    "@aws-sdk/middleware-user-agent" "3.6.1"
+    "@aws-sdk/node-config-provider" "3.6.1"
+    "@aws-sdk/node-http-handler" "3.6.1"
+    "@aws-sdk/protocol-http" "3.6.1"
+    "@aws-sdk/smithy-client" "3.6.1"
+    "@aws-sdk/types" "3.6.1"
+    "@aws-sdk/url-parser" "3.6.1"
+    "@aws-sdk/url-parser-native" "3.6.1"
+    "@aws-sdk/util-base64-browser" "3.6.1"
+    "@aws-sdk/util-base64-node" "3.6.1"
+    "@aws-sdk/util-body-length-browser" "3.6.1"
+    "@aws-sdk/util-body-length-node" "3.6.1"
+    "@aws-sdk/util-user-agent-browser" "3.6.1"
+    "@aws-sdk/util-user-agent-node" "3.6.1"
+    "@aws-sdk/util-utf8-browser" "3.6.1"
+    "@aws-sdk/util-utf8-node" "3.6.1"
+    tslib "^2.0.0"
+
+"@aws-sdk/[email protected]":
+  version "3.6.1"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/client-polly/-/client-polly-3.6.1.tgz#869deb186e57fca29737bfa7af094599d7879841"
+  integrity sha512-y6fxVYndGS7z2KqHViPCqagBEOsZlxBUYUJZuD6WWTiQrI0Pwe5qG02oKJVaa5OmxE20QLf6bRBWj2rQpeF4IQ==
+  dependencies:
+    "@aws-crypto/sha256-browser" "^1.0.0"
+    "@aws-crypto/sha256-js" "^1.0.0"
+    "@aws-sdk/config-resolver" "3.6.1"
+    "@aws-sdk/credential-provider-node" "3.6.1"
+    "@aws-sdk/fetch-http-handler" "3.6.1"
+    "@aws-sdk/hash-node" "3.6.1"
+    "@aws-sdk/invalid-dependency" "3.6.1"
+    "@aws-sdk/middleware-content-length" "3.6.1"
+    "@aws-sdk/middleware-host-header" "3.6.1"
+    "@aws-sdk/middleware-logger" "3.6.1"
+    "@aws-sdk/middleware-retry" "3.6.1"
+    "@aws-sdk/middleware-serde" "3.6.1"
+    "@aws-sdk/middleware-signing" "3.6.1"
+    "@aws-sdk/middleware-stack" "3.6.1"
+    "@aws-sdk/middleware-user-agent" "3.6.1"
+    "@aws-sdk/node-config-provider" "3.6.1"
+    "@aws-sdk/node-http-handler" "3.6.1"
+    "@aws-sdk/protocol-http" "3.6.1"
+    "@aws-sdk/smithy-client" "3.6.1"
+    "@aws-sdk/types" "3.6.1"
+    "@aws-sdk/url-parser" "3.6.1"
+    "@aws-sdk/url-parser-native" "3.6.1"
+    "@aws-sdk/util-base64-browser" "3.6.1"
+    "@aws-sdk/util-base64-node" "3.6.1"
+    "@aws-sdk/util-body-length-browser" "3.6.1"
+    "@aws-sdk/util-body-length-node" "3.6.1"
+    "@aws-sdk/util-user-agent-browser" "3.6.1"
+    "@aws-sdk/util-user-agent-node" "3.6.1"
+    "@aws-sdk/util-utf8-browser" "3.6.1"
+    "@aws-sdk/util-utf8-node" "3.6.1"
+    tslib "^2.0.0"
+
+"@aws-sdk/[email protected]":
+  version "3.6.1"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/client-rekognition/-/client-rekognition-3.6.1.tgz#710ba6d4509a2caa417cf0702ba81b5b65aa73eb"
+  integrity sha512-Ia4FEog9RrI0IoDRbOJO6djwhVAAaEZutxEKrWbjrVz4bgib28L+V+yAio2SUneeirj8pNYXwBKPfoYOUqGHhA==
+  dependencies:
+    "@aws-crypto/sha256-browser" "^1.0.0"
+    "@aws-crypto/sha256-js" "^1.0.0"
+    "@aws-sdk/config-resolver" "3.6.1"
+    "@aws-sdk/credential-provider-node" "3.6.1"
+    "@aws-sdk/fetch-http-handler" "3.6.1"
+    "@aws-sdk/hash-node" "3.6.1"
+    "@aws-sdk/invalid-dependency" "3.6.1"
+    "@aws-sdk/middleware-content-length" "3.6.1"
+    "@aws-sdk/middleware-host-header" "3.6.1"
+    "@aws-sdk/middleware-logger" "3.6.1"
+    "@aws-sdk/middleware-retry" "3.6.1"
+    "@aws-sdk/middleware-serde" "3.6.1"
+    "@aws-sdk/middleware-signing" "3.6.1"
+    "@aws-sdk/middleware-stack" "3.6.1"
+    "@aws-sdk/middleware-user-agent" "3.6.1"
+    "@aws-sdk/node-config-provider" "3.6.1"
+    "@aws-sdk/node-http-handler" "3.6.1"
+    "@aws-sdk/protocol-http" "3.6.1"
+    "@aws-sdk/smithy-client" "3.6.1"
+    "@aws-sdk/types" "3.6.1"
+    "@aws-sdk/url-parser" "3.6.1"
+    "@aws-sdk/url-parser-native" "3.6.1"
+    "@aws-sdk/util-base64-browser" "3.6.1"
+    "@aws-sdk/util-base64-node" "3.6.1"
+    "@aws-sdk/util-body-length-browser" "3.6.1"
+    "@aws-sdk/util-body-length-node" "3.6.1"
+    "@aws-sdk/util-user-agent-browser" "3.6.1"
+    "@aws-sdk/util-user-agent-node" "3.6.1"
+    "@aws-sdk/util-utf8-browser" "3.6.1"
+    "@aws-sdk/util-utf8-node" "3.6.1"
+    "@aws-sdk/util-waiter" "3.6.1"
+    tslib "^2.0.0"
+
+"@aws-sdk/[email protected]":
+  version "3.6.1"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/client-s3/-/client-s3-3.6.1.tgz#aab1e0e92b353d9d51152d9347b7e1809f3593d0"
+  integrity sha512-59cTmZj92iwgNoAeJirK5sZNQNXLc/oI3luqrEHRNLuOh70bjdgad70T0a5k2Ysd/v/QNamqJxnCJMPuX1bhgw==
+  dependencies:
+    "@aws-crypto/sha256-browser" "^1.0.0"
+    "@aws-crypto/sha256-js" "^1.0.0"
+    "@aws-sdk/config-resolver" "3.6.1"
+    "@aws-sdk/credential-provider-node" "3.6.1"
+    "@aws-sdk/eventstream-serde-browser" "3.6.1"
+    "@aws-sdk/eventstream-serde-config-resolver" "3.6.1"
+    "@aws-sdk/eventstream-serde-node" "3.6.1"
+    "@aws-sdk/fetch-http-handler" "3.6.1"
+    "@aws-sdk/hash-blob-browser" "3.6.1"
+    "@aws-sdk/hash-node" "3.6.1"
+    "@aws-sdk/hash-stream-node" "3.6.1"
+    "@aws-sdk/invalid-dependency" "3.6.1"
+    "@aws-sdk/md5-js" "3.6.1"
+    "@aws-sdk/middleware-apply-body-checksum" "3.6.1"
+    "@aws-sdk/middleware-bucket-endpoint" "3.6.1"
+    "@aws-sdk/middleware-content-length" "3.6.1"
+    "@aws-sdk/middleware-expect-continue" "3.6.1"
+    "@aws-sdk/middleware-host-header" "3.6.1"
+    "@aws-sdk/middleware-location-constraint" "3.6.1"
+    "@aws-sdk/middleware-logger" "3.6.1"
+    "@aws-sdk/middleware-retry" "3.6.1"
+    "@aws-sdk/middleware-sdk-s3" "3.6.1"
+    "@aws-sdk/middleware-serde" "3.6.1"
+    "@aws-sdk/middleware-signing" "3.6.1"
+    "@aws-sdk/middleware-ssec" "3.6.1"
+    "@aws-sdk/middleware-stack" "3.6.1"
+    "@aws-sdk/middleware-user-agent" "3.6.1"
+    "@aws-sdk/node-config-provider" "3.6.1"
+    "@aws-sdk/node-http-handler" "3.6.1"
+    "@aws-sdk/protocol-http" "3.6.1"
+    "@aws-sdk/smithy-client" "3.6.1"
+    "@aws-sdk/types" "3.6.1"
+    "@aws-sdk/url-parser" "3.6.1"
+    "@aws-sdk/url-parser-native" "3.6.1"
+    "@aws-sdk/util-base64-browser" "3.6.1"
+    "@aws-sdk/util-base64-node" "3.6.1"
+    "@aws-sdk/util-body-length-browser" "3.6.1"
+    "@aws-sdk/util-body-length-node" "3.6.1"
+    "@aws-sdk/util-user-agent-browser" "3.6.1"
+    "@aws-sdk/util-user-agent-node" "3.6.1"
+    "@aws-sdk/util-utf8-browser" "3.6.1"
+    "@aws-sdk/util-utf8-node" "3.6.1"
+    "@aws-sdk/util-waiter" "3.6.1"
+    "@aws-sdk/xml-builder" "3.6.1"
+    fast-xml-parser "^3.16.0"
+    tslib "^2.0.0"
+
+"@aws-sdk/[email protected]":
+  version "3.186.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/client-sso/-/client-sso-3.186.0.tgz#233bdd1312dbf88ef9452f8a62c3c3f1ac580330"
+  integrity sha512-qwLPomqq+fjvp42izzEpBEtGL2+dIlWH5pUCteV55hTEwHgo+m9LJPIrMWkPeoMBzqbNiu5n6+zihnwYlCIlEA==
+  dependencies:
+    "@aws-crypto/sha256-browser" "2.0.0"
+    "@aws-crypto/sha256-js" "2.0.0"
+    "@aws-sdk/config-resolver" "3.186.0"
+    "@aws-sdk/fetch-http-handler" "3.186.0"
+    "@aws-sdk/hash-node" "3.186.0"
+    "@aws-sdk/invalid-dependency" "3.186.0"
+    "@aws-sdk/middleware-content-length" "3.186.0"
+    "@aws-sdk/middleware-host-header" "3.186.0"
+    "@aws-sdk/middleware-logger" "3.186.0"
+    "@aws-sdk/middleware-recursion-detection" "3.186.0"
+    "@aws-sdk/middleware-retry" "3.186.0"
+    "@aws-sdk/middleware-serde" "3.186.0"
+    "@aws-sdk/middleware-stack" "3.186.0"
+    "@aws-sdk/middleware-user-agent" "3.186.0"
+    "@aws-sdk/node-config-provider" "3.186.0"
+    "@aws-sdk/node-http-handler" "3.186.0"
+    "@aws-sdk/protocol-http" "3.186.0"
+    "@aws-sdk/smithy-client" "3.186.0"
+    "@aws-sdk/types" "3.186.0"
+    "@aws-sdk/url-parser" "3.186.0"
+    "@aws-sdk/util-base64-browser" "3.186.0"
+    "@aws-sdk/util-base64-node" "3.186.0"
+    "@aws-sdk/util-body-length-browser" "3.186.0"
+    "@aws-sdk/util-body-length-node" "3.186.0"
+    "@aws-sdk/util-defaults-mode-browser" "3.186.0"
+    "@aws-sdk/util-defaults-mode-node" "3.186.0"
+    "@aws-sdk/util-user-agent-browser" "3.186.0"
+    "@aws-sdk/util-user-agent-node" "3.186.0"
+    "@aws-sdk/util-utf8-browser" "3.186.0"
+    "@aws-sdk/util-utf8-node" "3.186.0"
+    tslib "^2.3.1"
+
+"@aws-sdk/[email protected]":
+  version "3.186.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/client-sts/-/client-sts-3.186.0.tgz#12514601b0b01f892ddb11d8a2ab4bee1b03cbf1"
+  integrity sha512-lyAPI6YmIWWYZHQ9fBZ7QgXjGMTtktL5fk8kOcZ98ja+8Vu0STH1/u837uxqvZta8/k0wijunIL3jWUhjsNRcg==
+  dependencies:
+    "@aws-crypto/sha256-browser" "2.0.0"
+    "@aws-crypto/sha256-js" "2.0.0"
+    "@aws-sdk/config-resolver" "3.186.0"
+    "@aws-sdk/credential-provider-node" "3.186.0"
+    "@aws-sdk/fetch-http-handler" "3.186.0"
+    "@aws-sdk/hash-node" "3.186.0"
+    "@aws-sdk/invalid-dependency" "3.186.0"
+    "@aws-sdk/middleware-content-length" "3.186.0"
+    "@aws-sdk/middleware-host-header" "3.186.0"
+    "@aws-sdk/middleware-logger" "3.186.0"
+    "@aws-sdk/middleware-recursion-detection" "3.186.0"
+    "@aws-sdk/middleware-retry" "3.186.0"
+    "@aws-sdk/middleware-sdk-sts" "3.186.0"
+    "@aws-sdk/middleware-serde" "3.186.0"
+    "@aws-sdk/middleware-signing" "3.186.0"
+    "@aws-sdk/middleware-stack" "3.186.0"
+    "@aws-sdk/middleware-user-agent" "3.186.0"
+    "@aws-sdk/node-config-provider" "3.186.0"
+    "@aws-sdk/node-http-handler" "3.186.0"
+    "@aws-sdk/protocol-http" "3.186.0"
+    "@aws-sdk/smithy-client" "3.186.0"
+    "@aws-sdk/types" "3.186.0"
+    "@aws-sdk/url-parser" "3.186.0"
+    "@aws-sdk/util-base64-browser" "3.186.0"
+    "@aws-sdk/util-base64-node" "3.186.0"
+    "@aws-sdk/util-body-length-browser" "3.186.0"
+    "@aws-sdk/util-body-length-node" "3.186.0"
+    "@aws-sdk/util-defaults-mode-browser" "3.186.0"
+    "@aws-sdk/util-defaults-mode-node" "3.186.0"
+    "@aws-sdk/util-user-agent-browser" "3.186.0"
+    "@aws-sdk/util-user-agent-node" "3.186.0"
+    "@aws-sdk/util-utf8-browser" "3.186.0"
+    "@aws-sdk/util-utf8-node" "3.186.0"
+    entities "2.2.0"
+    fast-xml-parser "3.19.0"
+    tslib "^2.3.1"
+
+"@aws-sdk/[email protected]":
+  version "3.6.1"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/client-textract/-/client-textract-3.6.1.tgz#b8972f53f0353222b4c052adc784291e602be6aa"
+  integrity sha512-nLrBzWDt3ToiGVFF4lW7a/eZpI2zjdvu7lwmOWyXX8iiPzhBVVEfd5oOorRyJYBsGMslp4sqV8TBkU5Ld/a97Q==
+  dependencies:
+    "@aws-crypto/sha256-browser" "^1.0.0"
+    "@aws-crypto/sha256-js" "^1.0.0"
+    "@aws-sdk/config-resolver" "3.6.1"
+    "@aws-sdk/credential-provider-node" "3.6.1"
+    "@aws-sdk/fetch-http-handler" "3.6.1"
+    "@aws-sdk/hash-node" "3.6.1"
+    "@aws-sdk/invalid-dependency" "3.6.1"
+    "@aws-sdk/middleware-content-length" "3.6.1"
+    "@aws-sdk/middleware-host-header" "3.6.1"
+    "@aws-sdk/middleware-logger" "3.6.1"
+    "@aws-sdk/middleware-retry" "3.6.1"
+    "@aws-sdk/middleware-serde" "3.6.1"
+    "@aws-sdk/middleware-signing" "3.6.1"
+    "@aws-sdk/middleware-stack" "3.6.1"
+    "@aws-sdk/middleware-user-agent" "3.6.1"
+    "@aws-sdk/node-config-provider" "3.6.1"
+    "@aws-sdk/node-http-handler" "3.6.1"
+    "@aws-sdk/protocol-http" "3.6.1"
+    "@aws-sdk/smithy-client" "3.6.1"
+    "@aws-sdk/types" "3.6.1"
+    "@aws-sdk/url-parser" "3.6.1"
+    "@aws-sdk/url-parser-native" "3.6.1"
+    "@aws-sdk/util-base64-browser" "3.6.1"
+    "@aws-sdk/util-base64-node" "3.6.1"
+    "@aws-sdk/util-body-length-browser" "3.6.1"
+    "@aws-sdk/util-body-length-node" "3.6.1"
+    "@aws-sdk/util-user-agent-browser" "3.6.1"
+    "@aws-sdk/util-user-agent-node" "3.6.1"
+    "@aws-sdk/util-utf8-browser" "3.6.1"
+    "@aws-sdk/util-utf8-node" "3.6.1"
+    tslib "^2.0.0"
+
+"@aws-sdk/[email protected]":
+  version "3.6.1"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/client-translate/-/client-translate-3.6.1.tgz#ce855c9fe7885b930d4039c2e45c869e3c0a6656"
+  integrity sha512-RIHY+Og1i43B5aWlfUUk0ZFnNfM7j2vzlYUwOqhndawV49GFf96M3pmskR5sKEZI+5TXY77qR9TgZ/r3UxVCRQ==
+  dependencies:
+    "@aws-crypto/sha256-browser" "^1.0.0"
+    "@aws-crypto/sha256-js" "^1.0.0"
+    "@aws-sdk/config-resolver" "3.6.1"
+    "@aws-sdk/credential-provider-node" "3.6.1"
+    "@aws-sdk/fetch-http-handler" "3.6.1"
+    "@aws-sdk/hash-node" "3.6.1"
+    "@aws-sdk/invalid-dependency" "3.6.1"
+    "@aws-sdk/middleware-content-length" "3.6.1"
+    "@aws-sdk/middleware-host-header" "3.6.1"
+    "@aws-sdk/middleware-logger" "3.6.1"
+    "@aws-sdk/middleware-retry" "3.6.1"
+    "@aws-sdk/middleware-serde" "3.6.1"
+    "@aws-sdk/middleware-signing" "3.6.1"
+    "@aws-sdk/middleware-stack" "3.6.1"
+    "@aws-sdk/middleware-user-agent" "3.6.1"
+    "@aws-sdk/node-config-provider" "3.6.1"
+    "@aws-sdk/node-http-handler" "3.6.1"
+    "@aws-sdk/protocol-http" "3.6.1"
+    "@aws-sdk/smithy-client" "3.6.1"
+    "@aws-sdk/types" "3.6.1"
+    "@aws-sdk/url-parser" "3.6.1"
+    "@aws-sdk/url-parser-native" "3.6.1"
+    "@aws-sdk/util-base64-browser" "3.6.1"
+    "@aws-sdk/util-base64-node" "3.6.1"
+    "@aws-sdk/util-body-length-browser" "3.6.1"
+    "@aws-sdk/util-body-length-node" "3.6.1"
+    "@aws-sdk/util-user-agent-browser" "3.6.1"
+    "@aws-sdk/util-user-agent-node" "3.6.1"
+    "@aws-sdk/util-utf8-browser" "3.6.1"
+    "@aws-sdk/util-utf8-node" "3.6.1"
+    tslib "^2.0.0"
+    uuid "^3.0.0"
+
+"@aws-sdk/[email protected]":
+  version "3.186.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/config-resolver/-/config-resolver-3.186.0.tgz#68bbf82b572f03ee3ec9ac84d000147e1050149b"
+  integrity sha512-l8DR7Q4grEn1fgo2/KvtIfIHJS33HGKPQnht8OPxkl0dMzOJ0jxjOw/tMbrIcPnr2T3Fi7LLcj3dY1Fo1poruQ==
+  dependencies:
+    "@aws-sdk/signature-v4" "3.186.0"
+    "@aws-sdk/types" "3.186.0"
+    "@aws-sdk/util-config-provider" "3.186.0"
+    "@aws-sdk/util-middleware" "3.186.0"
+    tslib "^2.3.1"
+
+"@aws-sdk/[email protected]":
+  version "3.6.1"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/config-resolver/-/config-resolver-3.6.1.tgz#3bcc5e6a0ebeedf0981b0540e1f18a72b4dafebf"
+  integrity sha512-qjP1g3jLIm+XvOIJ4J7VmZRi87vsDmTRzIFePVeG+EFWwYQLxQjTGMdIj3yKTh1WuZ0HByf47mGcpiS4HZLm1Q==
+  dependencies:
+    "@aws-sdk/signature-v4" "3.6.1"
+    "@aws-sdk/types" "3.6.1"
+    tslib "^1.8.0"
+
+"@aws-sdk/[email protected]":
+  version "3.6.1"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-cognito-identity/-/credential-provider-cognito-identity-3.6.1.tgz#df928951612a34832c2df15fb899251d828c2df3"
+  integrity sha512-uJ9q+yq+Dhdo32gcv0p/AT7sKSAUH0y4ts9XRK/vx0dW9Q3XJy99mOJlq/6fkh4LfWeavJJlaCo9lSHNMWXx4w==
+  dependencies:
+    "@aws-sdk/client-cognito-identity" "3.6.1"
+    "@aws-sdk/property-provider" "3.6.1"
+    "@aws-sdk/types" "3.6.1"
+    tslib "^1.8.0"
+
+"@aws-sdk/[email protected]":
+  version "3.186.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-env/-/credential-provider-env-3.186.0.tgz#55dec9c4c29ebbdff4f3bce72de9e98f7a1f92e1"
+  integrity sha512-N9LPAqi1lsQWgxzmU4NPvLPnCN5+IQ3Ai1IFf3wM6FFPNoSUd1kIA2c6xaf0BE7j5Kelm0raZOb4LnV3TBAv+g==
+  dependencies:
+    "@aws-sdk/property-provider" "3.186.0"
+    "@aws-sdk/types" "3.186.0"
+    tslib "^2.3.1"
+
+"@aws-sdk/[email protected]":
+  version "3.6.1"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-env/-/credential-provider-env-3.6.1.tgz#d8b2dd36836432a9b8ec05a5cf9fe428b04c9964"
+  integrity sha512-coeFf/HnhpGidcAN1i1NuFgyFB2M6DeN1zNVy4f6s4mAh96ftr9DgWM1CcE3C+cLHEdpNqleVgC/2VQpyzOBLQ==
+  dependencies:
+    "@aws-sdk/property-provider" "3.6.1"
+    "@aws-sdk/types" "3.6.1"
+    tslib "^1.8.0"
+
+"@aws-sdk/[email protected]":
+  version "3.186.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-imds/-/credential-provider-imds-3.186.0.tgz#73e0f62832726c7734b4f6c50a02ab0d869c00e1"
+  integrity sha512-iJeC7KrEgPPAuXjCZ3ExYZrRQvzpSdTZopYgUm5TnNZ8S1NU/4nvv5xVy61JvMj3JQAeG8UDYYgC421Foc8wQw==
+  dependencies:
+    "@aws-sdk/node-config-provider" "3.186.0"
+    "@aws-sdk/property-provider" "3.186.0"
+    "@aws-sdk/types" "3.186.0"
+    "@aws-sdk/url-parser" "3.186.0"
+    tslib "^2.3.1"
+
+"@aws-sdk/[email protected]":
+  version "3.6.1"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-imds/-/credential-provider-imds-3.6.1.tgz#b5a8b8ef15eac26c58e469451a6c7c34ab3ca875"
+  integrity sha512-bf4LMI418OYcQbyLZRAW8Q5AYM2IKrNqOnIcfrFn2f17ulG7TzoWW3WN/kMOw4TC9+y+vIlCWOv87GxU1yP0Bg==
+  dependencies:
+    "@aws-sdk/property-provider" "3.6.1"
+    "@aws-sdk/types" "3.6.1"
+    tslib "^1.8.0"
+
+"@aws-sdk/[email protected]":
+  version "3.186.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.186.0.tgz#3b3873ccae855ee3f6f15dcd8212c5ca4ec01bf3"
+  integrity sha512-ecrFh3MoZhAj5P2k/HXo/hMJQ3sfmvlommzXuZ/D1Bj2yMcyWuBhF1A83Fwd2gtYrWRrllsK3IOMM5Jr8UIVZA==
+  dependencies:
+    "@aws-sdk/credential-provider-env" "3.186.0"
+    "@aws-sdk/credential-provider-imds" "3.186.0"
+    "@aws-sdk/credential-provider-sso" "3.186.0"
+    "@aws-sdk/credential-provider-web-identity" "3.186.0"
+    "@aws-sdk/property-provider" "3.186.0"
+    "@aws-sdk/shared-ini-file-loader" "3.186.0"
+    "@aws-sdk/types" "3.186.0"
+    tslib "^2.3.1"
+
+"@aws-sdk/[email protected]":
+  version "3.6.1"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.6.1.tgz#0da6d9341e621f8e0815814ed017b88e268fbc3d"
+  integrity sha512-3jguW6+ttRNddRZvbrs1yb3F1jrUbqyv0UfRoHuOGthjTt+L9sDpJaJGugYnT3bS9WBu1NydLVE2kDV++mJGVw==
+  dependencies:
+    "@aws-sdk/property-provider" "3.6.1"
+    "@aws-sdk/shared-ini-file-loader" "3.6.1"
+    "@aws-sdk/types" "3.6.1"
+    tslib "^1.8.0"
+
+"@aws-sdk/[email protected]":
+  version "3.186.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-node/-/credential-provider-node-3.186.0.tgz#0be58623660b41eed3a349a89b31a01d4cc773ea"
+  integrity sha512-HIt2XhSRhEvVgRxTveLCzIkd/SzEBQfkQ6xMJhkBtfJw1o3+jeCk+VysXM0idqmXytctL0O3g9cvvTHOsUgxOA==
+  dependencies:
+    "@aws-sdk/credential-provider-env" "3.186.0"
+    "@aws-sdk/credential-provider-imds" "3.186.0"
+    "@aws-sdk/credential-provider-ini" "3.186.0"
+    "@aws-sdk/credential-provider-process" "3.186.0"
+    "@aws-sdk/credential-provider-sso" "3.186.0"
+    "@aws-sdk/credential-provider-web-identity" "3.186.0"
+    "@aws-sdk/property-provider" "3.186.0"
+    "@aws-sdk/shared-ini-file-loader" "3.186.0"
+    "@aws-sdk/types" "3.186.0"
+    tslib "^2.3.1"
+
+"@aws-sdk/[email protected]":
+  version "3.6.1"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-node/-/credential-provider-node-3.6.1.tgz#0055292a4f0f49d053e8dfcc9174d8d2cf6862bb"
+  integrity sha512-VAHOcsqkPrF1k/fA62pv9c75lUWe5bHpcbFX83C3EUPd2FXV10Lfkv6bdWhyZPQy0k8T+9/yikHH3c7ZQeFE5A==
+  dependencies:
+    "@aws-sdk/credential-provider-env" "3.6.1"
+    "@aws-sdk/credential-provider-imds" "3.6.1"
+    "@aws-sdk/credential-provider-ini" "3.6.1"
+    "@aws-sdk/credential-provider-process" "3.6.1"
+    "@aws-sdk/property-provider" "3.6.1"
+    "@aws-sdk/shared-ini-file-loader" "3.6.1"
+    "@aws-sdk/types" "3.6.1"
+    tslib "^1.8.0"
+
+"@aws-sdk/[email protected]":
+  version "3.186.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-process/-/credential-provider-process-3.186.0.tgz#e3be60983261a58c212f5c38b6fb76305bbb8ce7"
+  integrity sha512-ATRU6gbXvWC1TLnjOEZugC/PBXHBoZgBADid4fDcEQY1vF5e5Ux1kmqkJxyHtV5Wl8sE2uJfwWn+FlpUHRX67g==
+  dependencies:
+    "@aws-sdk/property-provider" "3.186.0"
+    "@aws-sdk/shared-ini-file-loader" "3.186.0"
+    "@aws-sdk/types" "3.186.0"
+    tslib "^2.3.1"
+
+"@aws-sdk/[email protected]":
+  version "3.6.1"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-process/-/credential-provider-process-3.6.1.tgz#5bf851f3ee232c565b8c82608926df0ad28c1958"
+  integrity sha512-d0/TpMoEV4qMYkdpyyjU2Otse9X2jC1DuxWajHOWZYEw8oejMvXYTZ10hNaXZvAcNM9q214rp+k4mkt6gIcI6g==
+  dependencies:
+    "@aws-sdk/credential-provider-ini" "3.6.1"
+    "@aws-sdk/property-provider" "3.6.1"
+    "@aws-sdk/shared-ini-file-loader" "3.6.1"
+    "@aws-sdk/types" "3.6.1"
+    tslib "^1.8.0"
+
+"@aws-sdk/[email protected]":
+  version "3.186.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.186.0.tgz#e1aa466543b3b0877d45b885a1c11b329232df22"
+  integrity sha512-mJ+IZljgXPx99HCmuLgBVDPLepHrwqnEEC/0wigrLCx6uz3SrAWmGZsNbxSEtb2CFSAaczlTHcU/kIl7XZIyeQ==
+  dependencies:
+    "@aws-sdk/client-sso" "3.186.0"
+    "@aws-sdk/property-provider" "3.186.0"
+    "@aws-sdk/shared-ini-file-loader" "3.186.0"
+    "@aws-sdk/types" "3.186.0"
+    tslib "^2.3.1"
+
+"@aws-sdk/[email protected]":
+  version "3.186.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.186.0.tgz#db43f37f7827b553490dd865dbaa9a2c45f95494"
+  integrity sha512-KqzI5eBV72FE+8SuOQAu+r53RXGVHg4AuDJmdXyo7Gc4wS/B9FNElA8jVUjjYgVnf0FSiri+l41VzQ44dCopSA==
+  dependencies:
+    "@aws-sdk/property-provider" "3.186.0"
+    "@aws-sdk/types" "3.186.0"
+    tslib "^2.3.1"
+
+"@aws-sdk/[email protected]":
+  version "3.186.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/eventstream-codec/-/eventstream-codec-3.186.0.tgz#9da9608866b38179edf72987f2bc3b865d11db13"
+  integrity sha512-3kLcJ0/H+zxFlhTlE1SGoFpzd/SitwXOsTSlYVwrwdISKRjooGg0BJpm1CSTkvmWnQIUlYijJvS96TAJ+fCPIA==
+  dependencies:
+    "@aws-crypto/crc32" "2.0.0"
+    "@aws-sdk/types" "3.186.0"
+    "@aws-sdk/util-hex-encoding" "3.186.0"
+    tslib "^2.3.1"
+
+"@aws-sdk/[email protected]":
+  version "3.186.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/eventstream-handler-node/-/eventstream-handler-node-3.186.0.tgz#d58aec9a8617ed1a9a3800d5526333deb3efebb2"
+  integrity sha512-S8eAxCHyFAGSH7F6GHKU2ckpiwFPwJUQwMzewISLg3wzLQeu6lmduxBxVaV3/SoEbEMsbNmrgw9EXtw3Vt/odQ==
+  dependencies:
+    "@aws-sdk/eventstream-codec" "3.186.0"
+    "@aws-sdk/types" "3.186.0"
+    tslib "^2.3.1"
+
+"@aws-sdk/[email protected]":
+  version "3.6.1"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/eventstream-marshaller/-/eventstream-marshaller-3.6.1.tgz#6abfbdf3639249d1a77686cbcae5d8e47bcba989"
+  integrity sha512-ZvN3Nvxn2Gul08L9MOSN123LwSO0E1gF/CqmOGZtEWzPnoSX/PWM9mhPPeXubyw2KdlXylOodYYw3EAATk3OmA==
+  dependencies:
+    "@aws-crypto/crc32" "^1.0.0"
+    "@aws-sdk/types" "3.6.1"
+    "@aws-sdk/util-hex-encoding" "3.6.1"
+    tslib "^1.8.0"
+
+"@aws-sdk/[email protected]":
+  version "3.186.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/eventstream-serde-browser/-/eventstream-serde-browser-3.186.0.tgz#2a0bd942f977b3e2f1a77822ac091ddebe069475"
+  integrity sha512-0r2c+yugBdkP5bglGhGOgztjeHdHTKqu2u6bvTByM0nJShNO9YyqWygqPqDUOE5axcYQE1D0aFDGzDtP3mGJhw==
+  dependencies:
+    "@aws-sdk/eventstream-serde-universal" "3.186.0"
+    "@aws-sdk/types" "3.186.0"
+    tslib "^2.3.1"
+
+"@aws-sdk/[email protected]":
+  version "3.6.1"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/eventstream-serde-browser/-/eventstream-serde-browser-3.6.1.tgz#1253bd5215745f79d534fc9bc6bd006ee7a0f239"
+  integrity sha512-J8B30d+YUfkBtgWRr7+9AfYiPnbG28zjMlFGsJf8Wxr/hDCfff+Z8NzlBYFEbS7McXXhRiIN8DHUvCtolJtWJQ==
+  dependencies:
+    "@aws-sdk/eventstream-marshaller" "3.6.1"
+    "@aws-sdk/eventstream-serde-universal" "3.6.1"
+    "@aws-sdk/types" "3.6.1"
+    tslib "^1.8.0"
+
+"@aws-sdk/[email protected]":
+  version "3.186.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/eventstream-serde-config-resolver/-/eventstream-serde-config-resolver-3.186.0.tgz#6c277058bb0fa14752f0b6d7043576e0b5f13da4"
+  integrity sha512-xhwCqYrAX5c7fg9COXVw6r7Sa3BO5cCfQMSR5S1QisE7do8K1GDKEHvUCheOx+RLon+P3glLjuNBMdD0HfCVNA==
+  dependencies:
+    "@aws-sdk/types" "3.186.0"
+    tslib "^2.3.1"
+
+"@aws-sdk/[email protected]":
+  version "3.6.1"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/eventstream-serde-config-resolver/-/eventstream-serde-config-resolver-3.6.1.tgz#ebb5c1614f55d0ebb225defac1f76c420e188086"
+  integrity sha512-72pCzcT/KeD4gPgRVBSQzEzz4JBim8bNwPwZCGaIYdYAsAI8YMlvp0JNdis3Ov9DFURc87YilWKQlAfw7CDJxA==
+  dependencies:
+    "@aws-sdk/types" "3.6.1"
+    tslib "^1.8.0"
+
+"@aws-sdk/[email protected]":
+  version "3.186.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/eventstream-serde-node/-/eventstream-serde-node-3.186.0.tgz#dabeab714f447790c5dd31d401c5a3822b795109"
+  integrity sha512-9p/gdukJYfmA+OEYd6MfIuufxrrfdt15lBDM3FODuc9j09LSYSRHSxthkIhiM5XYYaaUM+4R0ZlSMdaC3vFDFQ==
+  dependencies:
+    "@aws-sdk/eventstream-serde-universal" "3.186.0"
+    "@aws-sdk/types" "3.186.0"
+    tslib "^2.3.1"
+
+"@aws-sdk/[email protected]":
+  version "3.6.1"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/eventstream-serde-node/-/eventstream-serde-node-3.6.1.tgz#705e12bea185905a198d7812af10e3a679dfc841"
+  integrity sha512-rjBbJFjCrEcm2NxZctp+eJmyPxKYayG3tQZo8PEAQSViIlK5QexQI3fgqNAeCtK7l/SFAAvnOMRZF6Z3NdUY6A==
+  dependencies:
+    "@aws-sdk/eventstream-marshaller" "3.6.1"
+    "@aws-sdk/eventstream-serde-universal" "3.6.1"
+    "@aws-sdk/types" "3.6.1"
+    tslib "^1.8.0"
+
+"@aws-sdk/[email protected]":
+  version "3.186.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/eventstream-serde-universal/-/eventstream-serde-universal-3.186.0.tgz#85a88a2cd5c336b1271976fa8db70654ec90fbf4"
+  integrity sha512-rIgPmwUxn2tzainBoh+cxAF+b7o01CcW+17yloXmawsi0kiR7QK7v9m/JTGQPWKtHSsPOrtRzuiWQNX57SlcsQ==
+  dependencies:
+    "@aws-sdk/eventstream-codec" "3.186.0"
+    "@aws-sdk/types" "3.186.0"
+    tslib "^2.3.1"
+
+"@aws-sdk/[email protected]":
+  version "3.6.1"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/eventstream-serde-universal/-/eventstream-serde-universal-3.6.1.tgz#5be6865adb55436cbc90557df3a3c49b53553470"
+  integrity sha512-rpRu97yAGHr9GQLWMzcGICR2PxNu1dHU/MYc9Kb6UgGeZd4fod4o1zjhAJuj98cXn2xwHNFM4wMKua6B4zKrZg==
+  dependencies:
+    "@aws-sdk/eventstream-marshaller" "3.6.1"
+    "@aws-sdk/types" "3.6.1"
+    tslib "^1.8.0"
+
+"@aws-sdk/[email protected]":
+  version "3.186.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/fetch-http-handler/-/fetch-http-handler-3.186.0.tgz#c1adc5f741e1ba9ad9d3fb13c9c2afdc88530a85"
+  integrity sha512-k2v4AAHRD76WnLg7arH94EvIclClo/YfuqO7NoQ6/KwOxjRhs4G6TgIsAZ9E0xmqoJoV81Xqy8H8ldfy9F8LEw==
+  dependencies:
+    "@aws-sdk/protocol-http" "3.186.0"
+    "@aws-sdk/querystring-builder" "3.186.0"
+    "@aws-sdk/types" "3.186.0"
+    "@aws-sdk/util-base64-browser" "3.186.0"
+    tslib "^2.3.1"
+
+"@aws-sdk/[email protected]":
+  version "3.6.1"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/fetch-http-handler/-/fetch-http-handler-3.6.1.tgz#c5fb4a4ee158161fca52b220d2c11dddcda9b092"
+  integrity sha512-N8l6ZbwhINuWG5hsl625lmIQmVjzsqRPmlgh061jm5D90IhsM5/3A3wUxpB/k0av1dmuMRw/m0YtBU5w4LOwvw==
+  dependencies:
+    "@aws-sdk/protocol-http" "3.6.1"
+    "@aws-sdk/querystring-builder" "3.6.1"
+    "@aws-sdk/types" "3.6.1"
+    "@aws-sdk/util-base64-browser" "3.6.1"
+    tslib "^1.8.0"
+
+"@aws-sdk/[email protected]":
+  version "3.6.1"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/hash-blob-browser/-/hash-blob-browser-3.6.1.tgz#f44a1857b75769e21cd6091211171135e03531e6"
+  integrity sha512-9jPaZ/e3F8gf9JZd44DD6MvbYV6bKnn99rkG3GFIINOy9etoxPrLehp2bH2DK/j0ow60RNuwgUjj5qHV/zF67g==
+  dependencies:
+    "@aws-sdk/chunked-blob-reader" "3.6.1"
+    "@aws-sdk/chunked-blob-reader-native" "3.6.1"
+    "@aws-sdk/types" "3.6.1"
+    tslib "^1.8.0"
+
+"@aws-sdk/[email protected]":
+  version "3.186.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/hash-node/-/hash-node-3.186.0.tgz#8cb13aae8f46eb360fed76baf5062f66f27dfb70"
+  integrity sha512-G3zuK8/3KExDTxqrGqko+opOMLRF0BwcwekV/wm3GKIM/NnLhHblBs2zd/yi7VsEoWmuzibfp6uzxgFpEoJ87w==
+  dependencies:
+    "@aws-sdk/types" "3.186.0"
+    "@aws-sdk/util-buffer-from" "3.186.0"
+    tslib "^2.3.1"
+
+"@aws-sdk/[email protected]":
+  version "3.6.1"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/hash-node/-/hash-node-3.6.1.tgz#72d75ec3b9c7e7f9b0c498805364f1f897165ce9"
+  integrity sha512-iKEpzpyaG9PYCnaOGwTIf0lffsF/TpsXrzAfnBlfeOU/3FbgniW2z/yq5xBbtMDtLobtOYC09kUFwDnDvuveSA==
+  dependencies:
+    "@aws-sdk/types" "3.6.1"
+    "@aws-sdk/util-buffer-from" "3.6.1"
+    tslib "^1.8.0"
+
+"@aws-sdk/[email protected]":
+  version "3.6.1"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/hash-stream-node/-/hash-stream-node-3.6.1.tgz#91c77e382ef3d0472160a49b1109395a4a70c801"
+  integrity sha512-ePaWjCItIWxuSxA/UnUM/keQ3IAOsQz3FYSxu0KK8K0e1bKTEUgDIG9oMLBq7jIl9TzJG0HBXuPfMe73QHUNug==
+  dependencies:
+    "@aws-sdk/types" "3.6.1"
+    tslib "^1.8.0"
+
+"@aws-sdk/[email protected]":
+  version "3.186.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/invalid-dependency/-/invalid-dependency-3.186.0.tgz#aa6331ccf404cb659ec38483116080e4b82b0663"
+  integrity sha512-hjeZKqORhG2DPWYZ776lQ9YO3gjw166vZHZCZU/43kEYaCZHsF4mexHwHzreAY6RfS25cH60Um7dUh1aeVIpkw==
+  dependencies:
+    "@aws-sdk/types" "3.186.0"
+    tslib "^2.3.1"
+
+"@aws-sdk/[email protected]":
+  version "3.6.1"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/invalid-dependency/-/invalid-dependency-3.6.1.tgz#fd2519f5482c6d6113d38a73b7143fd8d5b5b670"
+  integrity sha512-d0RLqK7yeDCZJKopnGmGXo2rYkQNE7sGKVmBHQD1j1kKZ9lWwRoJeWqo834JNPZzY5XRvZG5SuIjJ1kFy8LpyQ==
+  dependencies:
+    "@aws-sdk/types" "3.6.1"
+    tslib "^1.8.0"
+
+"@aws-sdk/[email protected]":
+  version "3.186.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/is-array-buffer/-/is-array-buffer-3.186.0.tgz#7700e36f29d416c2677f4bf8816120f96d87f1b7"
+  integrity sha512-fObm+P6mjWYzxoFY4y2STHBmSdgKbIAXez0xope563mox62I8I4hhVPUCaDVydXvDpJv8tbedJMk0meJl22+xA==
+  dependencies:
+    tslib "^2.3.1"
+
+"@aws-sdk/[email protected]":
+  version "3.6.1"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/is-array-buffer/-/is-array-buffer-3.6.1.tgz#96df5d64b2d599947f81b164d5d92623f85c659c"
+  integrity sha512-qm2iDJmCrxlQE2dsFG+TujPe7jw4DF+4RTrsFMhk/e3lOl3MAzQ6Fc2kXtgeUcVrZVFTL8fQvXE1ByYyI6WbCw==
+  dependencies:
+    tslib "^1.8.0"
+
+"@aws-sdk/[email protected]":
+  version "3.6.1"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/md5-js/-/md5-js-3.6.1.tgz#bffe21106fba0174d73ccc2c29ca1c5364d2af2d"
+  integrity sha512-lzCqkZF1sbzGFDyq1dI+lR3AmlE33rbC/JhZ5fzw3hJZvfZ6Beq3Su7YwDo65IWEu0zOKYaNywTeOloXP/CkxQ==
+  dependencies:
+    "@aws-sdk/types" "3.6.1"
+    "@aws-sdk/util-utf8-browser" "3.6.1"
+    tslib "^1.8.0"
+
+"@aws-sdk/[email protected]":
+  version "3.6.1"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-apply-body-checksum/-/middleware-apply-body-checksum-3.6.1.tgz#dece86e489531981b8aa2786dafbbef69edce1d6"
+  integrity sha512-IncmXR1MPk6aYvmD37It8dP6wVMzaxxzgrkIU2ACkN5UVwA+/0Sr3ZNd9dNwjpyoH1AwpL9BetnlJaWtT6K5ew==
+  dependencies:
+    "@aws-sdk/is-array-buffer" "3.6.1"
+    "@aws-sdk/protocol-http" "3.6.1"
+    "@aws-sdk/types" "3.6.1"
+    tslib "^1.8.0"
+
+"@aws-sdk/[email protected]":
+  version "3.6.1"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-bucket-endpoint/-/middleware-bucket-endpoint-3.6.1.tgz#7ebdd79fac0f78d8af549f4fd799d4f7d02e78de"
+  integrity sha512-Frcqn2RQDNHy+e2Q9hv3ejT3mQWtGlfZESbXEF6toR4M0R8MmEVqIB/ohI6VKBj11lRmGwvpPsR6zz+PJ8HS7A==
+  dependencies:
+    "@aws-sdk/protocol-http" "3.6.1"
+    "@aws-sdk/types" "3.6.1"
+    "@aws-sdk/util-arn-parser" "3.6.1"
+    tslib "^1.8.0"
+
+"@aws-sdk/[email protected]":
+  version "3.186.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-content-length/-/middleware-content-length-3.186.0.tgz#8cc7aeec527738c46fdaf4a48b17c5cbfdc7ce58"
+  integrity sha512-Ol3c1ks3IK1s+Okc/rHIX7w2WpXofuQdoAEme37gHeml+8FtUlWH/881h62xfMdf+0YZpRuYv/eM7lBmJBPNJw==
+  dependencies:
+    "@aws-sdk/protocol-http" "3.186.0"
+    "@aws-sdk/types" "3.186.0"
+    tslib "^2.3.1"
+
+"@aws-sdk/[email protected]":
+  version "3.6.1"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-content-length/-/middleware-content-length-3.6.1.tgz#f9c00a4045b2b56c1ff8bcbb3dec9c3d42332992"
+  integrity sha512-QRcocG9f5YjYzbjs2HjKla6ZIjvx8Y8tm1ZSFOPey81m18CLif1O7M3AtJXvxn+0zeSck9StFdhz5gfjVNYtDg==
+  dependencies:
+    "@aws-sdk/protocol-http" "3.6.1"
+    "@aws-sdk/types" "3.6.1"
+    tslib "^1.8.0"
+
+"@aws-sdk/[email protected]":
+  version "3.186.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-eventstream/-/middleware-eventstream-3.186.0.tgz#64a66102ed2e182182473948f131f23dda84e729"
+  integrity sha512-7yjFiitTGgfKL6cHK3u3HYFnld26IW5aUAFuEd6ocR/FjliysfBd8g0g1bw3bRfIMgCDD8OIOkXK8iCk2iYGWQ==
+  dependencies:
+    "@aws-sdk/protocol-http" "3.186.0"
+    "@aws-sdk/types" "3.186.0"
+    tslib "^2.3.1"
+
+"@aws-sdk/[email protected]":
+  version "3.6.1"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-expect-continue/-/middleware-expect-continue-3.6.1.tgz#56e56db572f81dd4fa8803e85bd1f36005f9fffa"
+  integrity sha512-vvMOqVYU3uvdJzg/X6NHewZUEBZhSqND1IEcdahLb6RmvDhsS39iS97VZmEFsjj/UFGoePtYjrrdEgRG9Rm1kQ==
+  dependencies:
+    "@aws-sdk/middleware-header-default" "3.6.1"
+    "@aws-sdk/protocol-http" "3.6.1"
+    "@aws-sdk/types" "3.6.1"
+    tslib "^1.8.0"
+
+"@aws-sdk/[email protected]":
+  version "3.6.1"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-header-default/-/middleware-header-default-3.6.1.tgz#a3a108d22cbdd1e1754910625fafb2f2a67fbcfc"
+  integrity sha512-YD137iIctXVH8Eut0WOBalvvA+uL0jM0UXZ9N2oKrC8kPQPpqjK9lYGFKZQFsl/XlQHAjJi+gCAFrYsBntRWJQ==
+  dependencies:
+    "@aws-sdk/protocol-http" "3.6.1"
+    "@aws-sdk/types" "3.6.1"
+    tslib "^1.8.0"
+
+"@aws-sdk/[email protected]":
+  version "3.186.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-host-header/-/middleware-host-header-3.186.0.tgz#fce4f1219ce1835e2348c787d8341080b0024e34"
+  integrity sha512-5bTzrRzP2IGwyF3QCyMGtSXpOOud537x32htZf344IvVjrqZF/P8CDfGTkHkeBCIH+wnJxjK+l/QBb3ypAMIqQ==
+  dependencies:
+    "@aws-sdk/protocol-http" "3.186.0"
+    "@aws-sdk/types" "3.186.0"
+    tslib "^2.3.1"
+
+"@aws-sdk/[email protected]":
+  version "3.6.1"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-host-header/-/middleware-host-header-3.6.1.tgz#6e1b4b95c5bfea5a4416fa32f11d8fa2e6edaeff"
+  integrity sha512-nwq8R2fGBRZQE0Fr/jiOgqfppfiTQCUoD8hyX3qSS7Qc2uqpsDOt2TnnoZl56mpQYkF/344IvMAkp+ew6wR73w==
+  dependencies:
+    "@aws-sdk/protocol-http" "3.6.1"
+    "@aws-sdk/types" "3.6.1"
+    tslib "^1.8.0"
+
+"@aws-sdk/[email protected]":
+  version "3.6.1"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-location-constraint/-/middleware-location-constraint-3.6.1.tgz#6fc2dd6a42968f011eb060ca564e9f749649eb01"
+  integrity sha512-nFisTc0O5D+4I+sRxiiLPasC/I4NDc3s+hgbPPt/b3uAdrujJjhwFBOSaTx8qQvz/xJPAA8pUA/bfWIyeZKi/w==
+  dependencies:
+    "@aws-sdk/types" "3.6.1"
+    tslib "^1.8.0"
+
+"@aws-sdk/[email protected]":
+  version "3.186.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-logger/-/middleware-logger-3.186.0.tgz#8a027fbbb1b8098ccc888bce51f34b000c0a0550"
+  integrity sha512-/1gGBImQT8xYh80pB7QtyzA799TqXtLZYQUohWAsFReYB7fdh5o+mu2rX0FNzZnrLIh2zBUNs4yaWGsnab4uXg==
+  dependencies:
+    "@aws-sdk/types" "3.186.0"
+    tslib "^2.3.1"
+
+"@aws-sdk/[email protected]":
+  version "3.6.1"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-logger/-/middleware-logger-3.6.1.tgz#78b3732cf188d5e4df13488db6418f7f98a77d6d"
+  integrity sha512-zxaSLpwKlja7JvK20UsDTxPqBZUo3rbDA1uv3VWwpxzOrEWSlVZYx/KLuyGWGkx9V71ZEkf6oOWWJIstS0wyQQ==
+  dependencies:
+    "@aws-sdk/types" "3.6.1"
+    tslib "^1.8.0"
+
+"@aws-sdk/[email protected]":
+  version "3.186.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.186.0.tgz#9d9d3212e9a954b557840bb80415987f4484487e"
+  integrity sha512-Za7k26Kovb4LuV5tmC6wcVILDCt0kwztwSlB991xk4vwNTja8kKxSt53WsYG8Q2wSaW6UOIbSoguZVyxbIY07Q==
+  dependencies:
+    "@aws-sdk/protocol-http" "3.186.0"
+    "@aws-sdk/types" "3.186.0"
+    tslib "^2.3.1"
+
+"@aws-sdk/[email protected]":
+  version "3.186.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-retry/-/middleware-retry-3.186.0.tgz#0ff9af58d73855863683991a809b40b93c753ad1"
+  integrity sha512-/VI9emEKhhDzlNv9lQMmkyxx3GjJ8yPfXH3HuAeOgM1wx1BjCTLRYEWnTbQwq7BDzVENdneleCsGAp7yaj80Aw==
+  dependencies:
+    "@aws-sdk/protocol-http" "3.186.0"
+    "@aws-sdk/service-error-classification" "3.186.0"
+    "@aws-sdk/types" "3.186.0"
+    "@aws-sdk/util-middleware" "3.186.0"
+    tslib "^2.3.1"
+    uuid "^8.3.2"
+
+"@aws-sdk/[email protected]":
+  version "3.6.1"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-retry/-/middleware-retry-3.6.1.tgz#202aadb1a3bf0e1ceabcd8319a5fa308b32db247"
+  integrity sha512-WHeo4d2jsXxBP+cec2SeLb0btYXwYXuE56WLmNt0RvJYmiBzytUeGJeRa9HuwV574kgigAuHGCeHlPO36G4Y0Q==
+  dependencies:
+    "@aws-sdk/protocol-http" "3.6.1"
+    "@aws-sdk/service-error-classification" "3.6.1"
+    "@aws-sdk/types" "3.6.1"
+    react-native-get-random-values "^1.4.0"
+    tslib "^1.8.0"
+    uuid "^3.0.0"
+
+"@aws-sdk/[email protected]":
+  version "3.6.1"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-sdk-s3/-/middleware-sdk-s3-3.6.1.tgz#371f8991ac82432982153c035ab9450d8df14546"
+  integrity sha512-HEA9kynNTsOSIIz8p5GEEAH03pnn+SSohwPl80sGqkmI1yl1tzjqgYZRii0e6acJTh4j9655XFzSx36hYPeB2w==
+  dependencies:
+    "@aws-sdk/protocol-http" "3.6.1"
+    "@aws-sdk/types" "3.6.1"
+    "@aws-sdk/util-arn-parser" "3.6.1"
+    tslib "^1.8.0"
+
+"@aws-sdk/[email protected]":
+  version "3.186.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-sdk-sts/-/middleware-sdk-sts-3.186.0.tgz#18f3d6b7b42c1345b5733ac3e3119d370a403e94"
+  integrity sha512-GDcK0O8rjtnd+XRGnxzheq1V2jk4Sj4HtjrxW/ROyhzLOAOyyxutBt+/zOpDD6Gba3qxc69wE+Cf/qngOkEkDw==
+  dependencies:
+    "@aws-sdk/middleware-signing" "3.186.0"
+    "@aws-sdk/property-provider" "3.186.0"
+    "@aws-sdk/protocol-http" "3.186.0"
+    "@aws-sdk/signature-v4" "3.186.0"
+    "@aws-sdk/types" "3.186.0"
+    tslib "^2.3.1"
+
+"@aws-sdk/[email protected]":
+  version "3.186.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-serde/-/middleware-serde-3.186.0.tgz#f7944241ad5fb31cb15cd250c9e92147942b9ec6"
+  integrity sha512-6FEAz70RNf18fKL5O7CepPSwTKJEIoyG9zU6p17GzKMgPeFsxS5xO94Hcq5tV2/CqeHliebjqhKY7yi+Pgok7g==
+  dependencies:
+    "@aws-sdk/types" "3.186.0"
+    tslib "^2.3.1"
+
+"@aws-sdk/[email protected]":
+  version "3.6.1"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-serde/-/middleware-serde-3.6.1.tgz#734c7d16c2aa9ccc01f6cca5e2f6aa2993b6739d"
+  integrity sha512-EdQCFZRERfP3uDuWcPNuaa2WUR3qL1WFDXafhcx+7ywQxagdYqBUWKFJlLYi6njbkOKXFM+eHBzoXGF0OV3MJA==
+  dependencies:
+    "@aws-sdk/types" "3.6.1"
+    tslib "^1.8.0"
+
+"@aws-sdk/[email protected]":
+  version "3.186.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-signing/-/middleware-signing-3.186.0.tgz#37633bf855667b4841464e0044492d0aec5778b9"
+  integrity sha512-riCJYG/LlF/rkgVbHkr4xJscc0/sECzDivzTaUmfb9kJhAwGxCyNqnTvg0q6UO00kxSdEB9zNZI2/iJYVBijBQ==
+  dependencies:
+    "@aws-sdk/property-provider" "3.186.0"
+    "@aws-sdk/protocol-http" "3.186.0"
+    "@aws-sdk/signature-v4" "3.186.0"
+    "@aws-sdk/types" "3.186.0"
+    "@aws-sdk/util-middleware" "3.186.0"
+    tslib "^2.3.1"
+
+"@aws-sdk/[email protected]":
+  version "3.6.1"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-signing/-/middleware-signing-3.6.1.tgz#e70a2f35d85d70e33c9fddfb54b9520f6382db16"
+  integrity sha512-1woKq+1sU3eausdl8BNdAMRZMkSYuy4mxhLsF0/qAUuLwo1eJLLUCOQp477tICawgu4O4q2OAyUHk7wMqYnQCg==
+  dependencies:
+    "@aws-sdk/protocol-http" "3.6.1"
+    "@aws-sdk/signature-v4" "3.6.1"
+    "@aws-sdk/types" "3.6.1"
+    tslib "^1.8.0"
+
+"@aws-sdk/[email protected]":
+  version "3.6.1"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-ssec/-/middleware-ssec-3.6.1.tgz#c7dd80e4c1e06be9050c742af7879619b400f0d1"
+  integrity sha512-svuH6s91uKUTORt51msiL/ZBjtYSW32c3uVoWxludd/PEf6zO5wCmUEsKoyVwa88L7rrCq+81UBv5A8S5kc3Cw==
+  dependencies:
+    "@aws-sdk/types" "3.6.1"
+    tslib "^1.8.0"
+
+"@aws-sdk/[email protected]":
+  version "3.186.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-stack/-/middleware-stack-3.186.0.tgz#da3445fe74b867ee6d7eec4f0dde28aaca1125d6"
+  integrity sha512-fENMoo0pW7UBrbuycPf+3WZ+fcUgP9PnQ0jcOK3WWZlZ9d2ewh4HNxLh4EE3NkNYj4VIUFXtTUuVNHlG8trXjQ==
+  dependencies:
+    tslib "^2.3.1"
+
+"@aws-sdk/[email protected]":
+  version "3.6.1"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-stack/-/middleware-stack-3.6.1.tgz#d7483201706bb5935a62884e9b60f425f1c6434f"
+  integrity sha512-EPsIxMi8LtCt7YwTFpWGlVGYJc0q4kwFbOssY02qfqdCnyqi2y5wo089dH7OdxUooQ0D7CPsXM1zTTuzvm+9Fw==
+  dependencies:
+    tslib "^1.8.0"
+
+"@aws-sdk/[email protected]":
+  version "3.186.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.186.0.tgz#6d881e9cea5fe7517e220f3a47c2f3557c7f27fc"
+  integrity sha512-fb+F2PF9DLKOVMgmhkr+ltN8ZhNJavTla9aqmbd01846OLEaN1n5xEnV7p8q5+EznVBWDF38Oz9Ae5BMt3Hs7w==
+  dependencies:
+    "@aws-sdk/protocol-http" "3.186.0"
+    "@aws-sdk/types" "3.186.0"
+    tslib "^2.3.1"
+
+"@aws-sdk/[email protected]":
+  version "3.6.1"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.6.1.tgz#6845dfb3bc6187897f348c2c87dec833e6a65c99"
+  integrity sha512-YvXvwllNDVvxQ30vIqLsx+P6jjnfFEQUmhlv64n98gOme6h2BqoyQDcC3yHRGctuxRZEsR7W/H1ASTKC+iabbQ==
+  dependencies:
+    "@aws-sdk/protocol-http" "3.6.1"
+    "@aws-sdk/types" "3.6.1"
+    tslib "^1.8.0"
+
+"@aws-sdk/[email protected]":
+  version "3.186.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/node-config-provider/-/node-config-provider-3.186.0.tgz#64259429d39f2ef5a76663162bf2e8db6032a322"
+  integrity sha512-De93mgmtuUUeoiKXU8pVHXWKPBfJQlS/lh1k2H9T2Pd9Tzi0l7p5ttddx4BsEx4gk+Pc5flNz+DeptiSjZpa4A==
+  dependencies:
+    "@aws-sdk/property-provider" "3.186.0"
+    "@aws-sdk/shared-ini-file-loader" "3.186.0"
+    "@aws-sdk/types" "3.186.0"
+    tslib "^2.3.1"
+
+"@aws-sdk/[email protected]":
+  version "3.6.1"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/node-config-provider/-/node-config-provider-3.6.1.tgz#cb85d06329347fde566f08426f8714b1f65d2fb7"
+  integrity sha512-x2Z7lm0ZhHYqMybvkaI5hDKfBkaLaXhTDfgrLl9TmBZ3QHO4fIHgeL82VZ90Paol+OS+jdq2AheLmzbSxv3HrA==
+  dependencies:
+    "@aws-sdk/property-provider" "3.6.1"
+    "@aws-sdk/shared-ini-file-loader" "3.6.1"
+    "@aws-sdk/types" "3.6.1"
+    tslib "^1.8.0"
+
+"@aws-sdk/[email protected]":
+  version "3.186.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/node-http-handler/-/node-http-handler-3.186.0.tgz#8be1598a9187637a767dc337bf22fe01461e86eb"
+  integrity sha512-CbkbDuPZT9UNJ4dAZJWB3BV+Z65wFy7OduqGkzNNrKq6ZYMUfehthhUOTk8vU6RMe/0FkN+J0fFXlBx/bs/cHw==
+  dependencies:
+    "@aws-sdk/abort-controller" "3.186.0"
+    "@aws-sdk/protocol-http" "3.186.0"
+    "@aws-sdk/querystring-builder" "3.186.0"
+    "@aws-sdk/types" "3.186.0"
+    tslib "^2.3.1"
+
+"@aws-sdk/[email protected]":
+  version "3.6.1"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/node-http-handler/-/node-http-handler-3.6.1.tgz#4b65c4dcc0cf46ba44cb6c3bf29c5f817bb8d9a7"
+  integrity sha512-6XSaoqbm9ZF6T4UdBCcs/Gn2XclwBotkdjj46AxO+9vRAgZDP+lH/8WwZsvfqJhhRhS0qxWrks98WGJwmaTG8g==
+  dependencies:
+    "@aws-sdk/abort-controller" "3.6.1"
+    "@aws-sdk/protocol-http" "3.6.1"
+    "@aws-sdk/querystring-builder" "3.6.1"
+    "@aws-sdk/types" "3.6.1"
+    tslib "^1.8.0"
+
+"@aws-sdk/[email protected]":
+  version "3.186.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/property-provider/-/property-provider-3.186.0.tgz#af41e615662a2749d3ff7da78c41f79f4be95b3b"
+  integrity sha512-nWKqt36UW3xV23RlHUmat+yevw9up+T+953nfjcmCBKtgWlCWu/aUzewTRhKj3VRscbN+Wer95SBw9Lr/MMOlQ==
+  dependencies:
+    "@aws-sdk/types" "3.186.0"
+    tslib "^2.3.1"
+
+"@aws-sdk/[email protected]":
+  version "3.6.1"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/property-provider/-/property-provider-3.6.1.tgz#d973fc87d199d32c44d947e17f2ee2dd140a9593"
+  integrity sha512-2gR2DzDySXKFoj9iXLm1TZBVSvFIikEPJsbRmAZx5RBY+tp1IXWqZM6PESjaLdLg/ZtR0QhW2ZcRn0fyq2JfnQ==
+  dependencies:
+    "@aws-sdk/types" "3.6.1"
+    tslib "^1.8.0"
+
+"@aws-sdk/[email protected]":
+  version "3.186.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/protocol-http/-/protocol-http-3.186.0.tgz#99115870846312dd4202b5e2cc68fe39324b9bfa"
+  integrity sha512-l/KYr/UBDUU5ginqTgHtFfHR3X6ljf/1J1ThIiUg3C3kVC/Zwztm7BEOw8hHRWnWQGU/jYasGYcrcPLdQqFZyQ==
+  dependencies:
+    "@aws-sdk/types" "3.186.0"
+    tslib "^2.3.1"
+
+"@aws-sdk/[email protected]":
+  version "3.6.1"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/protocol-http/-/protocol-http-3.6.1.tgz#d3d276846bec19ddb339d06bbc48116d17bbc656"
+  integrity sha512-WkQz7ncVYTLvCidDfXWouDzqxgSNPZDz3Bql+7VhZeITnzAEcr4hNMyEqMAVYBVugGmkG2W6YiUqNNs1goOcDA==
+  dependencies:
+    "@aws-sdk/types" "3.6.1"
+    tslib "^1.8.0"
+
+"@aws-sdk/[email protected]":
+  version "3.186.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/querystring-builder/-/querystring-builder-3.186.0.tgz#a380db0e1c71004932d9e2f3e6dc6761d1165c47"
+  integrity sha512-mweCpuLufImxfq/rRBTEpjGuB4xhQvbokA+otjnUxlPdIobytLqEs7pCGQfLzQ7+1ZMo8LBXt70RH4A2nSX/JQ==
+  dependencies:
+    "@aws-sdk/types" "3.186.0"
+    "@aws-sdk/util-uri-escape" "3.186.0"
+    tslib "^2.3.1"
+
+"@aws-sdk/[email protected]":
+  version "3.6.1"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/querystring-builder/-/querystring-builder-3.6.1.tgz#4c769829a3760ef065d0d3801f297a7f0cd324d4"
+  integrity sha512-ESe255Yl6vB1AMNqaGSQow3TBYYnpw0AFjE40q2VyiNrkbaqKmW2EzjeCy3wEmB1IfJDHy3O12ZOMUMOnjFT8g==
+  dependencies:
+    "@aws-sdk/types" "3.6.1"
+    "@aws-sdk/util-uri-escape" "3.6.1"
+    tslib "^1.8.0"
+
+"@aws-sdk/[email protected]":
+  version "3.186.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/querystring-parser/-/querystring-parser-3.186.0.tgz#4db6d31ad4df0d45baa2a35e371fbaa23e45ddd2"
+  integrity sha512-0iYfEloghzPVXJjmnzHamNx1F1jIiTW9Svy5ZF9LVqyr/uHZcQuiWYsuhWloBMLs8mfWarkZM02WfxZ8buAuhg==
+  dependencies:
+    "@aws-sdk/types" "3.186.0"
+    tslib "^2.3.1"
+
+"@aws-sdk/[email protected]":
+  version "3.6.1"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/querystring-parser/-/querystring-parser-3.6.1.tgz#e3fa5a710429c7dd411e802a0b82beb48012cce2"
+  integrity sha512-hh6dhqamKrWWaDSuO2YULci0RGwJWygoy8hpCRxs/FpzzHIcbm6Cl6Jhrn5eKBzOBv+PhCcYwbfad0kIZZovcQ==
+  dependencies:
+    "@aws-sdk/types" "3.6.1"
+    tslib "^1.8.0"
+
+"@aws-sdk/[email protected]":
+  version "3.6.1"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/s3-request-presigner/-/s3-request-presigner-3.6.1.tgz#ec83c70171692862a7f7ebbd151242a5af443695"
+  integrity sha512-OI7UHCKBwuiO/RmHHewBKnL2NYqdilXRmpX67TJ4tTszIrWP2+vpm3lIfrx/BM8nf8nKTzgkO98uFhoJsEhmTg==
+  dependencies:
+    "@aws-sdk/protocol-http" "3.6.1"
+    "@aws-sdk/signature-v4" "3.6.1"
+    "@aws-sdk/smithy-client" "3.6.1"
+    "@aws-sdk/types" "3.6.1"
+    "@aws-sdk/util-create-request" "3.6.1"
+    "@aws-sdk/util-format-url" "3.6.1"
+    tslib "^1.8.0"
+
+"@aws-sdk/[email protected]":
+  version "3.186.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/service-error-classification/-/service-error-classification-3.186.0.tgz#6e4e1d4b53d68bd28c28d9cf0b3b4cb6a6a59dbb"
+  integrity sha512-DRl3ORk4tF+jmH5uvftlfaq0IeKKpt0UPAOAFQ/JFWe+TjOcQd/K+VC0iiIG97YFp3aeFmH1JbEgsNxd+8fdxw==
+
+"@aws-sdk/[email protected]":
+  version "3.6.1"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/service-error-classification/-/service-error-classification-3.6.1.tgz#296fe62ac61338341e8a009c9a2dab013a791903"
+  integrity sha512-kZ7ZhbrN1f+vrSRkTJvXsu7BlOyZgym058nPA745+1RZ1Rtv4Ax8oknf2RvJyj/1qRUi8LBaAREjzQ3C8tmLBA==
+
+"@aws-sdk/[email protected]":
+  version "3.186.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/shared-ini-file-loader/-/shared-ini-file-loader-3.186.0.tgz#a2d285bb3c4f8d69f7bfbde7a5868740cd3f7795"
+  integrity sha512-2FZqxmICtwN9CYid4dwfJSz/gGFHyStFQ3HCOQ8DsJUf2yREMSBsVmKqsyWgOrYcQ98gPcD5GIa7QO5yl3XF6A==
+  dependencies:
+    "@aws-sdk/types" "3.186.0"
+    tslib "^2.3.1"
+
+"@aws-sdk/[email protected]":
+  version "3.6.1"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/shared-ini-file-loader/-/shared-ini-file-loader-3.6.1.tgz#2b7182cbb0d632ad7c9712bebffdeee24a6f7eb6"
+  integrity sha512-BnLHtsNLOoow6rPV+QVi6jnovU5g1m0YzoUG0BQYZ1ALyVlWVr0VvlUX30gMDfdYoPMp+DHvF8GXdMuGINq6kQ==
+  dependencies:
+    tslib "^1.8.0"
+
+"@aws-sdk/[email protected]":
+  version "3.186.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/signature-v4/-/signature-v4-3.186.0.tgz#bbd56e71af95548abaeec6307ea1dfe7bd26b4e4"
+  integrity sha512-18i96P5c4suMqwSNhnEOqhq4doqqyjH4fn0YV3F8TkekHPIWP4mtIJ0PWAN4eievqdtcKgD/GqVO6FaJG9texw==
+  dependencies:
+    "@aws-sdk/is-array-buffer" "3.186.0"
+    "@aws-sdk/types" "3.186.0"
+    "@aws-sdk/util-hex-encoding" "3.186.0"
+    "@aws-sdk/util-middleware" "3.186.0"
+    "@aws-sdk/util-uri-escape" "3.186.0"
+    tslib "^2.3.1"
+
+"@aws-sdk/[email protected]":
+  version "3.6.1"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/signature-v4/-/signature-v4-3.6.1.tgz#b20a3cf3e891131f83b012651f7d4af2bf240611"
+  integrity sha512-EAR0qGVL4AgzodZv4t+BSuBfyOXhTNxDxom50IFI1MqidR9vI6avNZKcPHhgXbm7XVcsDGThZKbzQ2q7MZ2NTA==
+  dependencies:
+    "@aws-sdk/is-array-buffer" "3.6.1"
+    "@aws-sdk/types" "3.6.1"
+    "@aws-sdk/util-hex-encoding" "3.6.1"
+    "@aws-sdk/util-uri-escape" "3.6.1"
+    tslib "^1.8.0"
+
+"@aws-sdk/[email protected]":
+  version "3.186.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/smithy-client/-/smithy-client-3.186.0.tgz#67514544fb55d7eff46300e1e73311625cf6f916"
+  integrity sha512-rdAxSFGSnrSprVJ6i1BXi65r4X14cuya6fYe8dSdgmFSa+U2ZevT97lb3tSINCUxBGeMXhENIzbVGkRZuMh+DQ==
+  dependencies:
+    "@aws-sdk/middleware-stack" "3.186.0"
+    "@aws-sdk/types" "3.186.0"
+    tslib "^2.3.1"
+
+"@aws-sdk/[email protected]":
+  version "3.6.1"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/smithy-client/-/smithy-client-3.6.1.tgz#683fef89802e318922f8529a5433592d71a7ce9d"
+  integrity sha512-AVpRK4/iUxNeDdAm8UqP0ZgtgJMQeWcagTylijwelhWXyXzHUReY1sgILsWcdWnoy6gq845W7K2VBhBleni8+w==
+  dependencies:
+    "@aws-sdk/middleware-stack" "3.6.1"
+    "@aws-sdk/types" "3.6.1"
+    tslib "^1.8.0"
+
+"@aws-sdk/[email protected]":
+  version "3.186.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/types/-/types-3.186.0.tgz#f6fb6997b6a364f399288bfd5cd494bc680ac922"
+  integrity sha512-NatmSU37U+XauMFJCdFI6nougC20JUFZar+ump5wVv0i54H+2Refg1YbFDxSs0FY28TSB9jfhWIpfFBmXgL5MQ==
+
+"@aws-sdk/[email protected]":
+  version "3.6.1"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/types/-/types-3.6.1.tgz#00686db69e998b521fcd4a5f81ef0960980f80c4"
+  integrity sha512-4Dx3eRTrUHLxhFdLJL8zdNGzVsJfAxtxPYYGmIddUkO2Gj3WA1TGjdfG4XN/ClI6e1XonCHafQX3UYO/mgnH3g==
+
+"@aws-sdk/types@^3.1.0", "@aws-sdk/types@^3.110.0":
+  version "3.272.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/types/-/types-3.272.0.tgz#83670e4009c2e72f1fdf55816c55c9f8b5935e0a"
+  integrity sha512-MmmL6vxMGP5Bsi+4wRx4mxYlU/LX6M0noOXrDh/x5FfG7/4ZOar/nDxqDadhJtNM88cuWVHZWY59P54JzkGWmA==
+  dependencies:
+    tslib "^2.3.1"
+
+"@aws-sdk/[email protected]":
+  version "3.6.1"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/url-parser-native/-/url-parser-native-3.6.1.tgz#a5e787f98aafa777e73007f9490df334ef3389a2"
+  integrity sha512-3O+ktsrJoE8YQCho9L41YXO8EWILXrSeES7amUaV3mgIV5w4S3SB/r4RkmylpqRpQF7Ry8LFiAnMqH1wa4WBPA==
+  dependencies:
+    "@aws-sdk/querystring-parser" "3.6.1"
+    "@aws-sdk/types" "3.6.1"
+    tslib "^1.8.0"
+    url "^0.11.0"
+
+"@aws-sdk/[email protected]":
+  version "3.186.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/url-parser/-/url-parser-3.186.0.tgz#e42f845cd405c1920fdbdcc796a350d4ace16ae9"
+  integrity sha512-jfdJkKqJZp8qjjwEjIGDqbqTuajBsddw02f86WiL8bPqD8W13/hdqbG4Fpwc+Bm6GwR6/4MY6xWXFnk8jDUKeA==
+  dependencies:
+    "@aws-sdk/querystring-parser" "3.186.0"
+    "@aws-sdk/types" "3.186.0"
+    tslib "^2.3.1"
+
+"@aws-sdk/[email protected]":
+  version "3.6.1"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/url-parser/-/url-parser-3.6.1.tgz#f5d89fb21680469a61cb9fe08a7da3ef887884dd"
+  integrity sha512-pWFIePDx0PMCleQRsQDWoDl17YiijOLj0ZobN39rQt+wv5PhLSZDz9PgJsqS48nZ6hqsKgipRcjiBMhn5NtFcQ==
+  dependencies:
+    "@aws-sdk/querystring-parser" "3.6.1"
+    "@aws-sdk/types" "3.6.1"
+    tslib "^1.8.0"
+
+"@aws-sdk/[email protected]":
+  version "3.6.1"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/util-arn-parser/-/util-arn-parser-3.6.1.tgz#aa60b1bfa752ad3fa331f22fea4f703b741d1d6d"
+  integrity sha512-NFdYeuhaSrgnBG6Pt3zHNU7QwvhHq6sKUTWZShUayLMJYYbQr6IjmYVlPST4c84b+lyDoK68y/Zga621VfIdBg==
+  dependencies:
+    tslib "^1.8.0"
+
+"@aws-sdk/[email protected]":
+  version "3.186.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/util-base64-browser/-/util-base64-browser-3.186.0.tgz#0310482752163fa819718ce9ea9250836b20346d"
+  integrity sha512-TpQL8opoFfzTwUDxKeon/vuc83kGXpYqjl6hR8WzmHoQgmFfdFlV+0KXZOohra1001OP3FhqvMqaYbO8p9vXVQ==
+  dependencies:
+    tslib "^2.3.1"
+
+"@aws-sdk/[email protected]":
+  version "3.6.1"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/util-base64-browser/-/util-base64-browser-3.6.1.tgz#eddea1311b41037fc3fddd889d3e0a9882363215"
+  integrity sha512-+DHAIgt0AFARDVC7J0Z9FkSmJhBMlkYdOPeAAgO0WaQoKj7rtsLQJ7P3v3aS1paKN5/sk5xNY7ziVB6uHtOvHA==
+  dependencies:
+    tslib "^1.8.0"
+
+"@aws-sdk/[email protected]":
+  version "3.186.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/util-base64-node/-/util-base64-node-3.186.0.tgz#500bd04b1ef7a6a5c0a2d11c0957a415922e05c7"
+  integrity sha512-wH5Y/EQNBfGS4VkkmiMyZXU+Ak6VCoFM1GKWopV+sj03zR2D4FHexi4SxWwEBMpZCd6foMtihhbNBuPA5fnh6w==
+  dependencies:
+    "@aws-sdk/util-buffer-from" "3.186.0"
+    tslib "^2.3.1"
+
+"@aws-sdk/[email protected]":
+  version "3.6.1"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/util-base64-node/-/util-base64-node-3.6.1.tgz#a79c233861e50d3a30728c72b736afdee07d4009"
+  integrity sha512-oiqzpsvtTSS92+cL3ykhGd7t3qBJKeHvrgOwUyEf1wFWHQ2DPJR+dIMy5rMFRXWLKCl3w7IddY2rJCkLYMjaqQ==
+  dependencies:
+    "@aws-sdk/util-buffer-from" "3.6.1"
+    tslib "^1.8.0"
+
+"@aws-sdk/[email protected]":
+  version "3.186.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/util-body-length-browser/-/util-body-length-browser-3.186.0.tgz#a898eda9f874f6974a9c5c60fcc76bcb6beac820"
+  integrity sha512-zKtjkI/dkj9oGkjo+7fIz+I9KuHrVt1ROAeL4OmDESS8UZi3/O8uMDFMuCp8jft6H+WFuYH6qRVWAVwXMiasXw==
+  dependencies:
+    tslib "^2.3.1"
+
+"@aws-sdk/[email protected]":
+  version "3.6.1"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/util-body-length-browser/-/util-body-length-browser-3.6.1.tgz#2e8088f2d9a5a8258b4f56079a8890f538c2797e"
+  integrity sha512-IdWwE3rm/CFDk2F+IwTZOFTnnNW5SB8y1lWiQ54cfc7y03hO6jmXNnpZGZ5goHhT+vf1oheNQt1J47m0pM/Irw==
+  dependencies:
+    tslib "^1.8.0"
+
+"@aws-sdk/[email protected]":
+  version "3.186.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/util-body-length-node/-/util-body-length-node-3.186.0.tgz#95efbacbd13cb739b942c126c5d16ecf6712d4db"
+  integrity sha512-U7Ii8u8Wvu9EnBWKKeuwkdrWto3c0j7LG677Spe6vtwWkvY70n9WGfiKHTgBpVeLNv8jvfcx5+H0UOPQK1o9SQ==
+  dependencies:
+    tslib "^2.3.1"
+
+"@aws-sdk/[email protected]":
+  version "3.6.1"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/util-body-length-node/-/util-body-length-node-3.6.1.tgz#6e4f2eae46c5a7b0417a12ca7f4b54c390d4cacd"
+  integrity sha512-CUG3gc18bSOsqViQhB3M4AlLpAWV47RE6yWJ6rLD0J6/rSuzbwbjzxM39q0YTAVuSo/ivdbij+G9c3QCirC+QQ==
+  dependencies:
+    tslib "^1.8.0"
+
+"@aws-sdk/[email protected]":
+  version "3.186.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/util-buffer-from/-/util-buffer-from-3.186.0.tgz#01f7edb683d2f40374d0ca8ef2d16346dc8040a1"
+  integrity sha512-be2GCk2lsLWg/2V5Y+S4/9pOMXhOQo4DR4dIqBdR2R+jrMMHN9Xsr5QrkT6chcqLaJ/SBlwiAEEi3StMRmCOXA==
+  dependencies:
+    "@aws-sdk/is-array-buffer" "3.186.0"
+    tslib "^2.3.1"
+
+"@aws-sdk/[email protected]":
+  version "3.6.1"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/util-buffer-from/-/util-buffer-from-3.6.1.tgz#24184ce74512f764d84002201b7f5101565e26f9"
+  integrity sha512-OGUh2B5NY4h7iRabqeZ+EgsrzE1LUmNFzMyhoZv0tO4NExyfQjxIYXLQQvydeOq9DJUbCw+yrRZrj8vXNDQG+g==
+  dependencies:
+    "@aws-sdk/is-array-buffer" "3.6.1"
+    tslib "^1.8.0"
+
+"@aws-sdk/[email protected]":
+  version "3.186.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/util-config-provider/-/util-config-provider-3.186.0.tgz#52ce3711edceadfac1b75fccc7c615e90c33fb2f"
+  integrity sha512-71Qwu/PN02XsRLApyxG0EUy/NxWh/CXxtl2C7qY14t+KTiRapwbDkdJ1cMsqYqghYP4BwJoj1M+EFMQSSlkZQQ==
+  dependencies:
+    tslib "^2.3.1"
+
+"@aws-sdk/[email protected]":
+  version "3.6.1"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/util-create-request/-/util-create-request-3.6.1.tgz#ecc4364551c7b3d0d9834ca3f56528fb8b083838"
+  integrity sha512-jR1U8WpwXl+xZ9ThS42Jr5MXuegQ7QioHsZjQn3V5pbm8CXTkBF0B2BcULQu/2G1XtHOJb8qUZQlk/REoaORfQ==
+  dependencies:
+    "@aws-sdk/middleware-stack" "3.6.1"
+    "@aws-sdk/smithy-client" "3.6.1"
+    "@aws-sdk/types" "3.6.1"
+    tslib "^1.8.0"
+
+"@aws-sdk/[email protected]":
+  version "3.186.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/util-defaults-mode-browser/-/util-defaults-mode-browser-3.186.0.tgz#d30b2f572e273d7d98287274c37c9ee00b493507"
+  integrity sha512-U8GOfIdQ0dZ7RRVpPynGteAHx4URtEh+JfWHHVfS6xLPthPHWTbyRhkQX++K/F8Jk+T5U8Anrrqlea4TlcO2DA==
+  dependencies:
+    "@aws-sdk/property-provider" "3.186.0"
+    "@aws-sdk/types" "3.186.0"
+    bowser "^2.11.0"
+    tslib "^2.3.1"
+
+"@aws-sdk/[email protected]":
+  version "3.186.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/util-defaults-mode-node/-/util-defaults-mode-node-3.186.0.tgz#8572453ba910fd2ab08d2cfee130ce5a0db83ba7"
+  integrity sha512-N6O5bpwCiE4z8y7SPHd7KYlszmNOYREa+mMgtOIXRU3VXSEHVKVWTZsHKvNTTHpW0qMqtgIvjvXCo3vsch5l3A==
+  dependencies:
+    "@aws-sdk/config-resolver" "3.186.0"
+    "@aws-sdk/credential-provider-imds" "3.186.0"
+    "@aws-sdk/node-config-provider" "3.186.0"
+    "@aws-sdk/property-provider" "3.186.0"
+    "@aws-sdk/types" "3.186.0"
+    tslib "^2.3.1"
+
+"@aws-sdk/[email protected]":
+  version "3.6.1"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/util-format-url/-/util-format-url-3.6.1.tgz#a011444aed0c47698d65095bcce95d7b4716324b"
+  integrity sha512-FvhcXcqLyJ0j0WdlmGs7PtjCCv8NaY4zBuXYO2iwAmqoy2SIZXQL63uAvmilqWj25q47ASAsUwSFLReCCfMklQ==
+  dependencies:
+    "@aws-sdk/querystring-builder" "3.6.1"
+    "@aws-sdk/types" "3.6.1"
+    tslib "^1.8.0"
+
+"@aws-sdk/[email protected]":
+  version "3.186.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/util-hex-encoding/-/util-hex-encoding-3.186.0.tgz#7ed58b923997c6265f4dce60c8704237edb98895"
+  integrity sha512-UL9rdgIZz1E/jpAfaKH8QgUxNK9VP5JPgoR0bSiaefMjnsoBh0x/VVMsfUyziOoJCMLebhJzFowtwrSKEGsxNg==
+  dependencies:
+    tslib "^2.3.1"
+
+"@aws-sdk/[email protected]":
+  version "3.6.1"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/util-hex-encoding/-/util-hex-encoding-3.6.1.tgz#84954fcc47b74ffbd2911ba5113e93bd9b1c6510"
+  integrity sha512-pzsGOHtU2eGca4NJgFg94lLaeXDOg8pcS9sVt4f9LmtUGbrqRveeyBv0XlkHeZW2n0IZBssPHipVYQFlk7iaRA==
+  dependencies:
+    tslib "^1.8.0"
+
+"@aws-sdk/util-locate-window@^3.0.0":
+  version "3.208.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/util-locate-window/-/util-locate-window-3.208.0.tgz#0f598fc238a1256e4bcb64d01459f03a922dd4c3"
+  integrity sha512-iua1A2+P7JJEDHVgvXrRJSvsnzG7stYSGQnBVphIUlemwl6nN5D+QrgbjECtrbxRz8asYFHSzhdhECqN+tFiBg==
+  dependencies:
+    tslib "^2.3.1"
+
+"@aws-sdk/[email protected]":
+  version "3.186.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/util-middleware/-/util-middleware-3.186.0.tgz#ba2e286b206cbead306b6d2564f9d0495f384b40"
+  integrity sha512-fddwDgXtnHyL9mEZ4s1tBBsKnVQHqTUmFbZKUUKPrg9CxOh0Y/zZxEa5Olg/8dS/LzM1tvg0ATkcyd4/kEHIhg==
+  dependencies:
+    tslib "^2.3.1"
+
+"@aws-sdk/[email protected]":
+  version "3.186.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/util-uri-escape/-/util-uri-escape-3.186.0.tgz#1752a93dfe58ec88196edb6929806807fd8986da"
+  integrity sha512-imtOrJFpIZAipAg8VmRqYwv1G/x4xzyoxOJ48ZSn1/ZGnKEEnB6n6E9gwYRebi4mlRuMSVeZwCPLq0ey5hReeQ==
+  dependencies:
+    tslib "^2.3.1"
+
+"@aws-sdk/[email protected]":
+  version "3.6.1"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/util-uri-escape/-/util-uri-escape-3.6.1.tgz#433e87458bb510d0e457a86c0acf12b046a5068c"
+  integrity sha512-tgABiT71r0ScRJZ1pMX0xO0QPMMiISCtumph50IU5VDyZWYgeIxqkMhIcrL1lX0QbNCMgX0n6rZxGrrbjDNavA==
+  dependencies:
+    tslib "^1.8.0"
+
+"@aws-sdk/[email protected]":
+  version "3.186.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.186.0.tgz#02e214887d30a69176c6a6c2d6903ce774b013b4"
+  integrity sha512-fbRcTTutMk4YXY3A2LePI4jWSIeHOT8DaYavpc/9Xshz/WH9RTGMmokeVOcClRNBeDSi5cELPJJ7gx6SFD3ZlQ==
+  dependencies:
+    "@aws-sdk/types" "3.186.0"
+    bowser "^2.11.0"
+    tslib "^2.3.1"
+
+"@aws-sdk/[email protected]":
+  version "3.6.1"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.6.1.tgz#11b9cc8743392761adb304460f4b54ec8acc2ee6"
+  integrity sha512-KhJ4VED4QpuBVPXoTjb5LqspX1xHWJTuL8hbPrKfxj+cAaRRW2CNEe7PPy2CfuHtPzP3dU3urtGTachbwNb0jg==
+  dependencies:
+    "@aws-sdk/types" "3.6.1"
+    bowser "^2.11.0"
+    tslib "^1.8.0"
+
+"@aws-sdk/[email protected]":
+  version "3.186.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.186.0.tgz#1ef74973442c8650c7b64ff2fd15cf3c09d8c004"
+  integrity sha512-oWZR7hN6NtOgnT6fUvHaafgbipQc2xJCRB93XHiF9aZGptGNLJzznIOP7uURdn0bTnF73ejbUXWLQIm8/6ue6w==
+  dependencies:
+    "@aws-sdk/node-config-provider" "3.186.0"
+    "@aws-sdk/types" "3.186.0"
+    tslib "^2.3.1"
+
+"@aws-sdk/[email protected]":
+  version "3.6.1"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.6.1.tgz#98384095fa67d098ae7dd26f3ccaad028e8aebb6"
+  integrity sha512-PWwL5EDRwhkXX40m5jjgttlBmLA7vDhHBen1Jcle0RPIDFRVPSE7GgvLF3y4r3SNH0WD6hxqadT50bHQynXW6w==
+  dependencies:
+    "@aws-sdk/node-config-provider" "3.6.1"
+    "@aws-sdk/types" "3.6.1"
+    tslib "^1.8.0"
+
+"@aws-sdk/[email protected]":
+  version "3.186.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/util-utf8-browser/-/util-utf8-browser-3.186.0.tgz#5fee6385cfc3effa2be704edc2998abfd6633082"
+  integrity sha512-n+IdFYF/4qT2WxhMOCeig8LndDggaYHw3BJJtfIBZRiS16lgwcGYvOUmhCkn0aSlG1f/eyg9YZHQG0iz9eLdHQ==
+  dependencies:
+    tslib "^2.3.1"
+
+"@aws-sdk/[email protected]":
+  version "3.6.1"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/util-utf8-browser/-/util-utf8-browser-3.6.1.tgz#97a8770cae9d29218adc0f32c7798350261377c7"
+  integrity sha512-gZPySY6JU5gswnw3nGOEHl3tYE7vPKvtXGYoS2NRabfDKRejFvu+4/nNW6SSpoOxk6LSXsrWB39NO51k+G4PVA==
+  dependencies:
+    tslib "^1.8.0"
+
+"@aws-sdk/util-utf8-browser@^3.0.0":
+  version "3.259.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/util-utf8-browser/-/util-utf8-browser-3.259.0.tgz#3275a6f5eb334f96ca76635b961d3c50259fd9ff"
+  integrity sha512-UvFa/vR+e19XookZF8RzFZBrw2EUkQWxiBW0yYQAhvk3C+QVGl0H3ouca8LDBlBfQKXwmW3huo/59H8rwb1wJw==
+  dependencies:
+    tslib "^2.3.1"
+
+"@aws-sdk/[email protected]":
+  version "3.186.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/util-utf8-node/-/util-utf8-node-3.186.0.tgz#722d9b0f5675ae2e9d79cf67322126d9c9d8d3d8"
+  integrity sha512-7qlE0dOVdjuRbZTb7HFywnHHCrsN7AeQiTnsWT63mjXGDbPeUWQQw3TrdI20um3cxZXnKoeudGq8K6zbXyQ4iA==
+  dependencies:
+    "@aws-sdk/util-buffer-from" "3.186.0"
+    tslib "^2.3.1"
+
+"@aws-sdk/[email protected]":
+  version "3.6.1"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/util-utf8-node/-/util-utf8-node-3.6.1.tgz#18534c2069b61f5739ee4cdc70060c9f4b4c4c4f"
+  integrity sha512-4s0vYfMUn74XLn13rUUhNsmuPMh0j1d4rF58wXtjlVUU78THxonnN8mbCLC48fI3fKDHTmDDkeEqy7+IWP9VyA==
+  dependencies:
+    "@aws-sdk/util-buffer-from" "3.6.1"
+    tslib "^1.8.0"
+
+"@aws-sdk/[email protected]":
+  version "3.6.1"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/util-waiter/-/util-waiter-3.6.1.tgz#5c66c2da33ff98468726fefddc2ca7ac3352c17d"
+  integrity sha512-CQMRteoxW1XZSzPBVrTsOTnfzsEGs8N/xZ8BuBnXLBjoIQmRKVxIH9lgphm1ohCtVHoSWf28XH/KoOPFULQ4Tg==
+  dependencies:
+    "@aws-sdk/abort-controller" "3.6.1"
+    "@aws-sdk/types" "3.6.1"
+    tslib "^1.8.0"
+
+"@aws-sdk/[email protected]":
+  version "3.6.1"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/xml-builder/-/xml-builder-3.6.1.tgz#d85d7db5e8e30ba74de93ddf0cf6197e6e4b15ea"
+  integrity sha512-+HOCH4a0XO+I09okd0xdVP5Q5c9ZsEsDvnogiOcBQxoMivWhPUCo9pjXP3buCvVKP2oDHXQplBKSjGHvGaKFdg==
+  dependencies:
+    tslib "^1.8.0"
+
+"@babel/code-frame@^7.0.0":
+  version "7.18.6"
+  resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.18.6.tgz#3b25d38c89600baa2dcc219edfa88a74eb2c427a"
+  integrity sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==
+  dependencies:
+    "@babel/highlight" "^7.18.6"
+
+"@babel/helper-validator-identifier@^7.18.6":
+  version "7.19.1"
+  resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz#7eea834cf32901ffdc1a7ee555e2f9c27e249ca2"
+  integrity sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==
+
+"@babel/highlight@^7.18.6":
+  version "7.18.6"
+  resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.18.6.tgz#81158601e93e2563795adcbfbdf5d64be3f2ecdf"
+  integrity sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==
+  dependencies:
+    "@babel/helper-validator-identifier" "^7.18.6"
+    chalk "^2.0.0"
+    js-tokens "^4.0.0"
+
+"@babel/runtime@^7.13.10":
+  version "7.21.0"
+  resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.21.0.tgz#5b55c9d394e5fcf304909a8b00c07dc217b56673"
+  integrity sha512-xwII0//EObnq89Ji5AKYQaRYiW/nZ3llSv29d49IuxPhKbtJoLP+9QUUZ4nVragQVtaVGeZrpB+ZtG/Pdy/POw==
+  dependencies:
+    regenerator-runtime "^0.13.11"
+
+"@floating-ui/core@^0.7.3":
+  version "0.7.3"
+  resolved "https://registry.yarnpkg.com/@floating-ui/core/-/core-0.7.3.tgz#d274116678ffae87f6b60e90f88cc4083eefab86"
+  integrity sha512-buc8BXHmG9l82+OQXOFU3Kr2XQx9ys01U/Q9HMIrZ300iLc8HLMgh7dcCqgYzAzf4BkoQvDcXf5Y+CuEZ5JBYg==
+
+"@floating-ui/dom@^0.5.3":
+  version "0.5.4"
+  resolved "https://registry.yarnpkg.com/@floating-ui/dom/-/dom-0.5.4.tgz#4eae73f78bcd4bd553ae2ade30e6f1f9c73fe3f1"
+  integrity sha512-419BMceRLq0RrmTSDxn8hf9R3VCJv2K9PUfugh5JyEFmdjzDo+e8U5EdR8nzKq8Yj1htzLm3b6eQEEam3/rrtg==
+  dependencies:
+    "@floating-ui/core" "^0.7.3"
+
+"@floating-ui/[email protected]":
+  version "0.7.2"
+  resolved "https://registry.yarnpkg.com/@floating-ui/react-dom/-/react-dom-0.7.2.tgz#0bf4ceccb777a140fc535c87eb5d6241c8e89864"
+  integrity sha512-1T0sJcpHgX/u4I1OzIEhlcrvkUN8ln39nz7fMoE/2HDHrPiMFoOGR7++GYyfUmIQHkkrTinaeQsO3XWubjSvGg==
+  dependencies:
+    "@floating-ui/dom" "^0.5.3"
+    use-isomorphic-layout-effect "^1.1.1"
+
+"@jridgewell/gen-mapping@^0.3.0":
+  version "0.3.2"
+  resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz#c1aedc61e853f2bb9f5dfe6d4442d3b565b253b9"
+  integrity sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==
+  dependencies:
+    "@jridgewell/set-array" "^1.0.1"
+    "@jridgewell/sourcemap-codec" "^1.4.10"
+    "@jridgewell/trace-mapping" "^0.3.9"
+
+"@jridgewell/[email protected]":
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz#2203b118c157721addfe69d47b70465463066d78"
+  integrity sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==
+
+"@jridgewell/set-array@^1.0.1":
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.2.tgz#7c6cf998d6d20b914c0a55a91ae928ff25965e72"
+  integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==
+
+"@jridgewell/source-map@^0.3.2":
+  version "0.3.2"
+  resolved "https://registry.yarnpkg.com/@jridgewell/source-map/-/source-map-0.3.2.tgz#f45351aaed4527a298512ec72f81040c998580fb"
+  integrity sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==
+  dependencies:
+    "@jridgewell/gen-mapping" "^0.3.0"
+    "@jridgewell/trace-mapping" "^0.3.9"
+
+"@jridgewell/[email protected]", "@jridgewell/sourcemap-codec@^1.4.10":
+  version "1.4.14"
+  resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz#add4c98d341472a289190b424efbdb096991bb24"
+  integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==
+
+"@jridgewell/trace-mapping@^0.3.9":
+  version "0.3.17"
+  resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz#793041277af9073b0951a7fe0f0d8c4c98c36985"
+  integrity sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==
+  dependencies:
+    "@jridgewell/resolve-uri" "3.1.0"
+    "@jridgewell/sourcemap-codec" "1.4.14"
+
+"@lezer/common@^0.15.0", "@lezer/common@^0.15.7":
+  version "0.15.12"
+  resolved "https://registry.yarnpkg.com/@lezer/common/-/common-0.15.12.tgz#2f21aec551dd5fd7d24eb069f90f54d5bc6ee5e9"
+  integrity sha512-edfwCxNLnzq5pBA/yaIhwJ3U3Kz8VAUOTRg0hhxaizaI1N+qxV7EXDv/kLCkLeq2RzSFvxexlaj5Mzfn2kY0Ig==
+
+"@lezer/lr@^0.15.4":
+  version "0.15.8"
+  resolved "https://registry.yarnpkg.com/@lezer/lr/-/lr-0.15.8.tgz#1564a911e62b0a0f75ca63794a6aa8c5dc63db21"
+  integrity sha512-bM6oE6VQZ6hIFxDNKk8bKPa14hqFrV07J/vHGOeiAbJReIaQXmkVb6xQu4MR+JBTLa5arGRyAAjJe1qaQt3Uvg==
+  dependencies:
+    "@lezer/common" "^0.15.0"
+
+"@lmdb/[email protected]":
+  version "2.5.2"
+  resolved "https://registry.yarnpkg.com/@lmdb/lmdb-darwin-arm64/-/lmdb-darwin-arm64-2.5.2.tgz#bc66fa43286b5c082e8fee0eacc17995806b6fbe"
+  integrity sha512-+F8ioQIUN68B4UFiIBYu0QQvgb9FmlKw2ctQMSBfW2QBrZIxz9vD9jCGqTCPqZBRbPHAS/vG1zSXnKqnS2ch/A==
+
+"@lmdb/[email protected]":
+  version "2.5.2"
+  resolved "https://registry.yarnpkg.com/@lmdb/lmdb-darwin-x64/-/lmdb-darwin-x64-2.5.2.tgz#89d8390041bce6bab24a82a20392be22faf54ffc"
+  integrity sha512-KvPH56KRLLx4KSfKBx0m1r7GGGUMXm0jrKmNE7plbHlesZMuPJICtn07HYgQhj1LNsK7Yqwuvnqh1QxhJnF1EA==
+
+"@lmdb/[email protected]":
+  version "2.5.2"
+  resolved "https://registry.yarnpkg.com/@lmdb/lmdb-linux-arm64/-/lmdb-linux-arm64-2.5.2.tgz#14fe4c96c2bb1285f93797f45915fa35ee047268"
+  integrity sha512-aLl89VHL/wjhievEOlPocoefUyWdvzVrcQ/MHQYZm2JfV1jUsrbr/ZfkPPUFvZBf+VSE+Q0clWs9l29PCX1hTQ==
+
+"@lmdb/[email protected]":
+  version "2.5.2"
+  resolved "https://registry.yarnpkg.com/@lmdb/lmdb-linux-arm/-/lmdb-linux-arm-2.5.2.tgz#05bde4573ab10cf21827339fe687148f2590cfa1"
+  integrity sha512-5kQAP21hAkfW5Bl+e0P57dV4dGYnkNIpR7f/GAh6QHlgXx+vp/teVj4PGRZaKAvt0GX6++N6hF8NnGElLDuIDw==
+
+"@lmdb/[email protected]":
+  version "2.5.2"
+  resolved "https://registry.yarnpkg.com/@lmdb/lmdb-linux-x64/-/lmdb-linux-x64-2.5.2.tgz#d2f85afd857d2c33d2caa5b057944574edafcfee"
+  integrity sha512-xUdUfwDJLGjOUPH3BuPBt0NlIrR7f/QHKgu3GZIXswMMIihAekj2i97oI0iWG5Bok/b+OBjHPfa8IU9velnP/Q==
+
+"@lmdb/[email protected]":
+  version "2.5.2"
+  resolved "https://registry.yarnpkg.com/@lmdb/lmdb-win32-x64/-/lmdb-win32-x64-2.5.2.tgz#28f643fbc0bec30b07fbe95b137879b6b4d1c9c5"
+  integrity sha512-zrBczSbXKxEyK2ijtbRdICDygRqWSRPpZMN5dD1T8VMEW5RIhIbwFWw2phDRXuBQdVDpSjalCIUMWMV2h3JaZA==
+
+"@mapbox/[email protected]":
+  version "0.4.0"
+  resolved "https://registry.yarnpkg.com/@mapbox/extent/-/extent-0.4.0.tgz#3e591f32e1f0c3981c864239f7b0ac06e610f8a9"
+  integrity sha512-MSoKw3qPceGuupn04sdaJrFeLKvcSETVLZCGS8JA9x6zXQL3FWiKaIXYIZEDXd5jpXpWlRxinCZIN49yRy0C9A==
+
+"@mapbox/geojson-area@^0.2.2":
+  version "0.2.2"
+  resolved "https://registry.yarnpkg.com/@mapbox/geojson-area/-/geojson-area-0.2.2.tgz#18d7814aa36bf23fbbcc379f8e26a22927debf10"
+  integrity sha512-bBqqFn1kIbLBfn7Yq1PzzwVkPYQr9lVUeT8Dhd0NL5n76PBuXzOcuLV7GOSbEB1ia8qWxH4COCvFpziEu/yReA==
+  dependencies:
+    wgs84 "0.0.0"
+
+"@mapbox/[email protected]":
+  version "0.0.2"
+  resolved "https://registry.yarnpkg.com/@mapbox/geojson-coords/-/geojson-coords-0.0.2.tgz#f73d5744c832de0f05c48899f16a4288cefb2606"
+  integrity sha512-YuVzpseee/P1T5BWyeVVPppyfmuXYHFwZHmybkqaMfu4BWlOf2cmMGKj2Rr92MwfSTOCSUA0PAsVGRG8akY0rg==
+  dependencies:
+    "@mapbox/geojson-normalize" "0.0.1"
+    geojson-flatten "^1.0.4"
+
+"@mapbox/geojson-extent@^1.0.0", "@mapbox/geojson-extent@^1.0.1":
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/@mapbox/geojson-extent/-/geojson-extent-1.0.1.tgz#bd99a6b66ba98e63a29511c9cd1bbd1df4c1e203"
+  integrity sha512-hh8LEO3djT4fqfr8sSC6wKt+p0TMiu+KOLMBUiFOyj+zGq7+IXwQGl0ppCVDkyzCewyd9LoGe9zAvDxXrLfhLw==
+  dependencies:
+    "@mapbox/extent" "0.4.0"
+    "@mapbox/geojson-coords" "0.0.2"
+    rw "~0.1.4"
+    traverse "~0.6.6"
+
+"@mapbox/[email protected]", "@mapbox/geojson-normalize@^0.0.1":
+  version "0.0.1"
+  resolved "https://registry.yarnpkg.com/@mapbox/geojson-normalize/-/geojson-normalize-0.0.1.tgz#1da1e6b3a7add3ad29909b30f438f60581b7cd80"
+  integrity sha512-82V7YHcle8lhgIGqEWwtXYN5cy0QM/OHq3ypGhQTbvHR57DF0vMHMjjVSQKFfVXBe/yWCBZTyOuzvK7DFFnx5Q==
+
+"@mapbox/geojson-rewind@^0.5.0", "@mapbox/geojson-rewind@^0.5.1":
+  version "0.5.2"
+  resolved "https://registry.yarnpkg.com/@mapbox/geojson-rewind/-/geojson-rewind-0.5.2.tgz#591a5d71a9cd1da1a0bf3420b3bea31b0fc7946a"
+  integrity sha512-tJaT+RbYGJYStt7wI3cq4Nl4SXxG8W7JDG5DMJu97V25RnbNg3QtQtf+KD+VLjNpWKYsRvXDNmNrBgEETr1ifA==
+  dependencies:
+    get-stream "^6.0.1"
+    minimist "^1.2.6"
+
+"@mapbox/geojson-types@^1.0.2":
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/@mapbox/geojson-types/-/geojson-types-1.0.2.tgz#9aecf642cb00eab1080a57c4f949a65b4a5846d6"
+  integrity sha512-e9EBqHHv3EORHrSfbR9DqecPNn+AmuAoQxV6aL8Xu30bJMJR1o8PZLZzpk1Wq7/NfCbuhmakHTPYRhoqLsXRnw==
+
+"@mapbox/jsonlint-lines-primitives@^2.0.2":
+  version "2.0.2"
+  resolved "https://registry.yarnpkg.com/@mapbox/jsonlint-lines-primitives/-/jsonlint-lines-primitives-2.0.2.tgz#ce56e539f83552b58d10d672ea4d6fc9adc7b234"
+  integrity sha512-rY0o9A5ECsTQRVhv7tL/OyDpGAoUB4tTvLiW1DSzQGq4bvTPhNw1VpSNjDJc5GFZ2XuyOtSWSVN05qOtcD71qQ==
+
+"@mapbox/[email protected]":
+  version "1.3.0"
+  resolved "https://registry.yarnpkg.com/@mapbox/mapbox-gl-draw/-/mapbox-gl-draw-1.3.0.tgz#7a30fb99488cb47a32c25e99c3c62413b04bbaed"
+  integrity sha512-B+KWK+dAgzLHMNyKVuuMRfjeSlQ77MhNLdfpQQpbp3pkhnrdmydDe3ixto1Ua78hktNut0WTrAaD8gYu4PVcjA==
+  dependencies:
+    "@mapbox/geojson-area" "^0.2.2"
+    "@mapbox/geojson-extent" "^1.0.0"
+    "@mapbox/geojson-normalize" "^0.0.1"
+    "@mapbox/point-geometry" "^0.1.0"
+    hat "0.0.3"
+    lodash.isequal "^4.5.0"
+    xtend "^4.0.2"
+
+"@mapbox/mapbox-gl-draw@^1.3.0":
+  version "1.4.1"
+  resolved "https://registry.yarnpkg.com/@mapbox/mapbox-gl-draw/-/mapbox-gl-draw-1.4.1.tgz#96dcec4d3957150de854423ac15856fde43d1452"
+  integrity sha512-g6F49KZagF9269/IoF6vZJeail6qtoc5mVF3eVRikNT7UFnY0QASfe2y53mgE99s6GrHdpV+PZuFxaL71hkMhg==
+  dependencies:
+    "@mapbox/geojson-area" "^0.2.2"
+    "@mapbox/geojson-extent" "^1.0.1"
+    "@mapbox/geojson-normalize" "^0.0.1"
+    "@mapbox/point-geometry" "^0.1.0"
+    hat "0.0.3"
+    lodash.isequal "^4.5.0"
+    xtend "^4.0.2"
+
+"@mapbox/mapbox-gl-supported@^1.5.0":
+  version "1.5.0"
+  resolved "https://registry.yarnpkg.com/@mapbox/mapbox-gl-supported/-/mapbox-gl-supported-1.5.0.tgz#f60b6a55a5d8e5ee908347d2ce4250b15103dc8e"
+  integrity sha512-/PT1P6DNf7vjEEiPkVIRJkvibbqWtqnyGaBz3nfRdcxclNSnSdaLU5tfAgcD7I8Yt5i+L19s406YLl1koLnLbg==
+
+"@mapbox/mapbox-gl-supported@^2.0.1":
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/@mapbox/mapbox-gl-supported/-/mapbox-gl-supported-2.0.1.tgz#c15367178d8bfe4765e6b47b542fe821ce259c7b"
+  integrity sha512-HP6XvfNIzfoMVfyGjBckjiAOQK9WfX0ywdLubuPMPv+Vqf5fj0uCbgBQYpiqcWZT6cbyyRnTSXDheT1ugvF6UQ==
+
+"@mapbox/[email protected]", "@mapbox/point-geometry@^0.1.0", "@mapbox/point-geometry@~0.1.0":
+  version "0.1.0"
+  resolved "https://registry.yarnpkg.com/@mapbox/point-geometry/-/point-geometry-0.1.0.tgz#8a83f9335c7860effa2eeeca254332aa0aeed8f2"
+  integrity sha512-6j56HdLTwWGO0fJPlrZtdU/B13q8Uwmo18Ck2GnGgN9PCFyKTZ3UbXeEdRFh18i9XQ92eH2VdtpJHpBD3aripQ==
+
+"@mapbox/tiny-sdf@^1.1.1":
+  version "1.2.5"
+  resolved "https://registry.yarnpkg.com/@mapbox/tiny-sdf/-/tiny-sdf-1.2.5.tgz#424c620a96442b20402552be70a7f62a8407cc59"
+  integrity sha512-cD8A/zJlm6fdJOk6DqPUV8mcpyJkRz2x2R+/fYcWDYG3oWbG7/L7Yl/WqQ1VZCjnL9OTIMAn6c+BC5Eru4sQEw==
+
+"@mapbox/tiny-sdf@^2.0.4":
+  version "2.0.6"
+  resolved "https://registry.yarnpkg.com/@mapbox/tiny-sdf/-/tiny-sdf-2.0.6.tgz#9a1d33e5018093e88f6a4df2343e886056287282"
+  integrity sha512-qMqa27TLw+ZQz5Jk+RcwZGH7BQf5G/TrutJhspsca/3SHwmgKQ1iq+d3Jxz5oysPVYTGP6aXxCo5Lk9Er6YBAA==
+
+"@mapbox/unitbezier@^0.0.0":
+  version "0.0.0"
+  resolved "https://registry.yarnpkg.com/@mapbox/unitbezier/-/unitbezier-0.0.0.tgz#15651bd553a67b8581fb398810c98ad86a34524e"
+  integrity sha512-HPnRdYO0WjFjRTSwO3frz1wKaU649OBFPX3Zo/2WZvuRi6zMiRGui8SnPQiQABgqCf8YikDe5t3HViTVw1WUzA==
+
+"@mapbox/unitbezier@^0.0.1":
+  version "0.0.1"
+  resolved "https://registry.yarnpkg.com/@mapbox/unitbezier/-/unitbezier-0.0.1.tgz#d32deb66c7177e9e9dfc3bbd697083e2e657ff01"
+  integrity sha512-nMkuDXFv60aBr9soUG5q+GvZYL+2KZHVvsqFCzqnkGEf46U2fvmytHaEVc1/YZbiLn8X+eR3QzX1+dwDO1lxlw==
+
+"@mapbox/vector-tile@^1.3.1":
+  version "1.3.1"
+  resolved "https://registry.yarnpkg.com/@mapbox/vector-tile/-/vector-tile-1.3.1.tgz#d3a74c90402d06e89ec66de49ec817ff53409666"
+  integrity sha512-MCEddb8u44/xfQ3oD+Srl/tNcQoqTw3goGk2oLsrFxOTc3dUp+kAnby3PvAeeBYSMSjSPD1nd1AJA6W49WnoUw==
+  dependencies:
+    "@mapbox/point-geometry" "~0.1.0"
+
+"@mapbox/whoots-js@^3.1.0":
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/@mapbox/whoots-js/-/whoots-js-3.1.0.tgz#497c67a1cef50d1a2459ba60f315e448d2ad87fe"
+  integrity sha512-Es6WcD0nO5l+2BOQS4uLfNPYQaNDfbot3X1XUoloz+x0mPDS3eeORZJl06HXjwBG1fOGwCRnzK88LMdxKRrd6Q==
+
+"@maplibre/maplibre-gl-geocoder@^1.5.0":
+  version "1.5.0"
+  resolved "https://registry.yarnpkg.com/@maplibre/maplibre-gl-geocoder/-/maplibre-gl-geocoder-1.5.0.tgz#6b413525b361b4759df0fd17429e12b78f03b3a4"
+  integrity sha512-PsAbV7WFIOu5QYZne95FiXoV7AV1/6ULMjQxgInhZ5DdB0hDLjciQPegnyDgkzI8JfeqoUMZVS/MglZnSZYhyQ==
+  dependencies:
+    lodash.debounce "^4.0.6"
+    subtag "^0.5.0"
+    suggestions-list "^0.0.2"
+    xtend "^4.0.1"
+
+"@mischnic/json-sourcemap@^0.1.0":
+  version "0.1.0"
+  resolved "https://registry.yarnpkg.com/@mischnic/json-sourcemap/-/json-sourcemap-0.1.0.tgz#38af657be4108140a548638267d02a2ea3336507"
+  integrity sha512-dQb3QnfNqmQNYA4nFSN/uLaByIic58gOXq4Y4XqLOWmOrw73KmJPt/HLyG0wvn1bnR6mBKs/Uwvkh+Hns1T0XA==
+  dependencies:
+    "@lezer/common" "^0.15.7"
+    "@lezer/lr" "^0.15.4"
+    json5 "^2.2.1"
+
+"@msgpackr-extract/[email protected]":
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/@msgpackr-extract/msgpackr-extract-darwin-arm64/-/msgpackr-extract-darwin-arm64-3.0.0.tgz#d31a238c943ffc34bab73ad6ce7a6466d65888ef"
+  integrity sha512-5qpnNHUyyEj9H3sm/4Um/bnx1lrQGhe8iqry/1d+cQYCRd/gzYA0YLeq0ezlk4hKx4vO+dsEsNyeowqRqslwQA==
+
+"@msgpackr-extract/[email protected]":
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/@msgpackr-extract/msgpackr-extract-darwin-x64/-/msgpackr-extract-darwin-x64-3.0.0.tgz#2f6fbbec3d3f0bbe9c6678c899f1c1a6e25ed980"
+  integrity sha512-ZphTFFd6SFweNAMKD+QJCrWpgkjf4qBuHltiMkKkD6FFrB3NOTRVmetAGTkJ57pa+s6J0yCH06LujWB9rZe94g==
+
+"@msgpackr-extract/[email protected]":
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/@msgpackr-extract/msgpackr-extract-linux-arm64/-/msgpackr-extract-linux-arm64-3.0.0.tgz#19875441da50b9aa8f8e726eb097a4cead435a3f"
+  integrity sha512-NEX6hdSvP4BmVyegaIbrGxvHzHvTzzsPaxXCsUt0mbLbPpEftsvNwaEVKOowXnLoeuGeD4MaqSwL3BUK2elsUA==
+
+"@msgpackr-extract/[email protected]":
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/@msgpackr-extract/msgpackr-extract-linux-arm/-/msgpackr-extract-linux-arm-3.0.0.tgz#3b855ac72cc16e89db2f72adf47ddc964c20a53d"
+  integrity sha512-ztKVV1dO/sSZyGse0PBCq3Pk1PkYjsA/dsEWE7lfrGoAK3i9HpS2o7XjGQ7V4va6nX+xPPOiuYpQwa4Bi6vlww==
+
+"@msgpackr-extract/[email protected]":
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/@msgpackr-extract/msgpackr-extract-linux-x64/-/msgpackr-extract-linux-x64-3.0.0.tgz#455f1d5bb00e87f78c67711f26e7bff9f1457684"
+  integrity sha512-9uvdAkZMOPCY7SPRxZLW8XGqBOVNVEhqlgffenN8shA1XR9FWVsSM13nr/oHtNgXg6iVyML7RwWPyqUeThlwxg==
+
+"@msgpackr-extract/[email protected]":
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/@msgpackr-extract/msgpackr-extract-win32-x64/-/msgpackr-extract-win32-x64-3.0.0.tgz#03c6bfcd3acb179ea69546c20d50895b9d623ada"
+  integrity sha512-Wg0+9615kHKlr9iLVcG5I+/CHnf6w3x5UADRv8Ad16yA0Bu5l9eVOROjV7aHPG6uC8ZPFIVVaoSjDChD+Y0pzg==
+
+"@parcel/[email protected]":
+  version "2.8.3"
+  resolved "https://registry.yarnpkg.com/@parcel/bundler-default/-/bundler-default-2.8.3.tgz#d64739dbc2dbd59d6629861bf77a8083aced5229"
+  integrity sha512-yJvRsNWWu5fVydsWk3O2L4yIy3UZiKWO2cPDukGOIWMgp/Vbpp+2Ct5IygVRtE22bnseW/E/oe0PV3d2IkEJGg==
+  dependencies:
+    "@parcel/diagnostic" "2.8.3"
+    "@parcel/graph" "2.8.3"
+    "@parcel/hash" "2.8.3"
+    "@parcel/plugin" "2.8.3"
+    "@parcel/utils" "2.8.3"
+    nullthrows "^1.1.1"
+
+"@parcel/[email protected]":
+  version "2.8.3"
+  resolved "https://registry.yarnpkg.com/@parcel/cache/-/cache-2.8.3.tgz#169e130cf59913c0ed9fadce1a450e68f710e16f"
+  integrity sha512-k7xv5vSQrJLdXuglo+Hv3yF4BCSs1tQ/8Vbd6CHTkOhf7LcGg6CPtLw053R/KdMpd/4GPn0QrAsOLdATm1ELtQ==
+  dependencies:
+    "@parcel/fs" "2.8.3"
+    "@parcel/logger" "2.8.3"
+    "@parcel/utils" "2.8.3"
+    lmdb "2.5.2"
+
+"@parcel/[email protected]":
+  version "2.8.3"
+  resolved "https://registry.yarnpkg.com/@parcel/codeframe/-/codeframe-2.8.3.tgz#84fb529ef70def7f5bc64f6c59b18d24826f5fcc"
+  integrity sha512-FE7sY53D6n/+2Pgg6M9iuEC6F5fvmyBkRE4d9VdnOoxhTXtkEqpqYgX7RJ12FAQwNlxKq4suBJQMgQHMF2Kjeg==
+  dependencies:
+    chalk "^4.1.0"
+
+"@parcel/[email protected]":
+  version "2.8.3"
+  resolved "https://registry.yarnpkg.com/@parcel/compressor-raw/-/compressor-raw-2.8.3.tgz#301753df8c6de967553149639e8a4179b88f0c95"
+  integrity sha512-bVDsqleBUxRdKMakWSlWC9ZjOcqDKE60BE+Gh3JSN6WJrycJ02P5wxjTVF4CStNP/G7X17U+nkENxSlMG77ySg==
+  dependencies:
+    "@parcel/plugin" "2.8.3"
+
+"@parcel/[email protected]":
+  version "2.8.3"
+  resolved "https://registry.yarnpkg.com/@parcel/config-default/-/config-default-2.8.3.tgz#9a43486e7c702e96c68052c37b79098d7240e35b"
+  integrity sha512-o/A/mbrO6X/BfGS65Sib8d6SSG45NYrNooNBkH/o7zbOBSRQxwyTlysleK1/3Wa35YpvFyLOwgfakqCtbGy4fw==
+  dependencies:
+    "@parcel/bundler-default" "2.8.3"
+    "@parcel/compressor-raw" "2.8.3"
+    "@parcel/namer-default" "2.8.3"
+    "@parcel/optimizer-css" "2.8.3"
+    "@parcel/optimizer-htmlnano" "2.8.3"
+    "@parcel/optimizer-image" "2.8.3"
+    "@parcel/optimizer-svgo" "2.8.3"
+    "@parcel/optimizer-terser" "2.8.3"
+    "@parcel/packager-css" "2.8.3"
+    "@parcel/packager-html" "2.8.3"
+    "@parcel/packager-js" "2.8.3"
+    "@parcel/packager-raw" "2.8.3"
+    "@parcel/packager-svg" "2.8.3"
+    "@parcel/reporter-dev-server" "2.8.3"
+    "@parcel/resolver-default" "2.8.3"
+    "@parcel/runtime-browser-hmr" "2.8.3"
+    "@parcel/runtime-js" "2.8.3"
+    "@parcel/runtime-react-refresh" "2.8.3"
+    "@parcel/runtime-service-worker" "2.8.3"
+    "@parcel/transformer-babel" "2.8.3"
+    "@parcel/transformer-css" "2.8.3"
+    "@parcel/transformer-html" "2.8.3"
+    "@parcel/transformer-image" "2.8.3"
+    "@parcel/transformer-js" "2.8.3"
+    "@parcel/transformer-json" "2.8.3"
+    "@parcel/transformer-postcss" "2.8.3"
+    "@parcel/transformer-posthtml" "2.8.3"
+    "@parcel/transformer-raw" "2.8.3"
+    "@parcel/transformer-react-refresh-wrap" "2.8.3"
+    "@parcel/transformer-svg" "2.8.3"
+
+"@parcel/[email protected]":
+  version "2.8.3"
+  resolved "https://registry.yarnpkg.com/@parcel/core/-/core-2.8.3.tgz#22a69f36095d53736ab10bf42697d9aa5f4e382b"
+  integrity sha512-Euf/un4ZAiClnlUXqPB9phQlKbveU+2CotZv7m7i+qkgvFn5nAGnrV4h1OzQU42j9dpgOxWi7AttUDMrvkbhCQ==
+  dependencies:
+    "@mischnic/json-sourcemap" "^0.1.0"
+    "@parcel/cache" "2.8.3"
+    "@parcel/diagnostic" "2.8.3"
+    "@parcel/events" "2.8.3"
+    "@parcel/fs" "2.8.3"
+    "@parcel/graph" "2.8.3"
+    "@parcel/hash" "2.8.3"
+    "@parcel/logger" "2.8.3"
+    "@parcel/package-manager" "2.8.3"
+    "@parcel/plugin" "2.8.3"
+    "@parcel/source-map" "^2.1.1"
+    "@parcel/types" "2.8.3"
+    "@parcel/utils" "2.8.3"
+    "@parcel/workers" "2.8.3"
+    abortcontroller-polyfill "^1.1.9"
+    base-x "^3.0.8"
+    browserslist "^4.6.6"
+    clone "^2.1.1"
+    dotenv "^7.0.0"
+    dotenv-expand "^5.1.0"
+    json5 "^2.2.0"
+    msgpackr "^1.5.4"
+    nullthrows "^1.1.1"
+    semver "^5.7.1"
+
+"@parcel/[email protected]":
+  version "2.8.3"
+  resolved "https://registry.yarnpkg.com/@parcel/diagnostic/-/diagnostic-2.8.3.tgz#d560276d5d2804b48beafa1feaf3fc6b2ac5e39d"
+  integrity sha512-u7wSzuMhLGWZjVNYJZq/SOViS3uFG0xwIcqXw12w54Uozd6BH8JlhVtVyAsq9kqnn7YFkw6pXHqAo5Tzh4FqsQ==
+  dependencies:
+    "@mischnic/json-sourcemap" "^0.1.0"
+    nullthrows "^1.1.1"
+
+"@parcel/[email protected]":
+  version "2.8.3"
+  resolved "https://registry.yarnpkg.com/@parcel/events/-/events-2.8.3.tgz#205f8d874e6ecc2cbdb941bf8d54bae669e571af"
+  integrity sha512-hoIS4tAxWp8FJk3628bsgKxEvR7bq2scCVYHSqZ4fTi/s0+VymEATrRCUqf+12e5H47uw1/ZjoqrGtBI02pz4w==
+
+"@parcel/[email protected]":
+  version "2.8.3"
+  resolved "https://registry.yarnpkg.com/@parcel/fs-search/-/fs-search-2.8.3.tgz#1c7d812c110b808758f44c56e61dfffdb09e9451"
+  integrity sha512-DJBT2N8knfN7Na6PP2mett3spQLTqxFrvl0gv+TJRp61T8Ljc4VuUTb0hqBj+belaASIp3Q+e8+SgaFQu7wLiQ==
+  dependencies:
+    detect-libc "^1.0.3"
+
+"@parcel/[email protected]":
+  version "2.8.3"
+  resolved "https://registry.yarnpkg.com/@parcel/fs/-/fs-2.8.3.tgz#80536afe877fc8a2bd26be5576b9ba27bb4c5754"
+  integrity sha512-y+i+oXbT7lP0e0pJZi/YSm1vg0LDsbycFuHZIL80pNwdEppUAtibfJZCp606B7HOjMAlNZOBo48e3hPG3d8jgQ==
+  dependencies:
+    "@parcel/fs-search" "2.8.3"
+    "@parcel/types" "2.8.3"
+    "@parcel/utils" "2.8.3"
+    "@parcel/watcher" "^2.0.7"
+    "@parcel/workers" "2.8.3"
+
+"@parcel/[email protected]":
+  version "2.8.3"
+  resolved "https://registry.yarnpkg.com/@parcel/graph/-/graph-2.8.3.tgz#00ffe8ec032e74fee57199e54529f1da7322571d"
+  integrity sha512-26GL8fYZPdsRhSXCZ0ZWliloK6DHlMJPWh6Z+3VVZ5mnDSbYg/rRKWmrkhnr99ZWmL9rJsv4G74ZwvDEXTMPBg==
+  dependencies:
+    nullthrows "^1.1.1"
+
+"@parcel/[email protected]":
+  version "2.8.3"
+  resolved "https://registry.yarnpkg.com/@parcel/hash/-/hash-2.8.3.tgz#bc2499a27395169616cad2a99e19e69b9098f6e9"
+  integrity sha512-FVItqzjWmnyP4ZsVgX+G00+6U2IzOvqDtdwQIWisCcVoXJFCqZJDy6oa2qDDFz96xCCCynjRjPdQx2jYBCpfYw==
+  dependencies:
+    detect-libc "^1.0.3"
+    xxhash-wasm "^0.4.2"
+
+"@parcel/[email protected]":
+  version "2.8.3"
+  resolved "https://registry.yarnpkg.com/@parcel/logger/-/logger-2.8.3.tgz#e14e4debafb3ca9e87c07c06780f9afc38b2712c"
+  integrity sha512-Kpxd3O/Vs7nYJIzkdmB6Bvp3l/85ydIxaZaPfGSGTYOfaffSOTkhcW9l6WemsxUrlts4za6CaEWcc4DOvaMOPA==
+  dependencies:
+    "@parcel/diagnostic" "2.8.3"
+    "@parcel/events" "2.8.3"
+
+"@parcel/[email protected]":
+  version "2.8.3"
+  resolved "https://registry.yarnpkg.com/@parcel/markdown-ansi/-/markdown-ansi-2.8.3.tgz#1337d421bb1133ad178f386a8e1b746631bba4a1"
+  integrity sha512-4v+pjyoh9f5zuU/gJlNvNFGEAb6J90sOBwpKJYJhdWXLZMNFCVzSigxrYO+vCsi8G4rl6/B2c0LcwIMjGPHmFQ==
+  dependencies:
+    chalk "^4.1.0"
+
+"@parcel/[email protected]":
+  version "2.8.3"
+  resolved "https://registry.yarnpkg.com/@parcel/namer-default/-/namer-default-2.8.3.tgz#5304bee74beb4b9c1880781bdbe35be0656372f4"
+  integrity sha512-tJ7JehZviS5QwnxbARd8Uh63rkikZdZs1QOyivUhEvhN+DddSAVEdQLHGPzkl3YRk0tjFhbqo+Jci7TpezuAMw==
+  dependencies:
+    "@parcel/diagnostic" "2.8.3"
+    "@parcel/plugin" "2.8.3"
+    nullthrows "^1.1.1"
+
+"@parcel/[email protected]":
+  version "2.8.3"
+  resolved "https://registry.yarnpkg.com/@parcel/node-resolver-core/-/node-resolver-core-2.8.3.tgz#581df074a27646400b3fed9da95297b616a7db8f"
+  integrity sha512-12YryWcA5Iw2WNoEVr/t2HDjYR1iEzbjEcxfh1vaVDdZ020PiGw67g5hyIE/tsnG7SRJ0xdRx1fQ2hDgED+0Ww==
+  dependencies:
+    "@parcel/diagnostic" "2.8.3"
+    "@parcel/utils" "2.8.3"
+    nullthrows "^1.1.1"
+    semver "^5.7.1"
+
+"@parcel/[email protected]":
+  version "2.8.3"
+  resolved "https://registry.yarnpkg.com/@parcel/optimizer-css/-/optimizer-css-2.8.3.tgz#420a333f4b78f7ff15e69217dfed34421b1143ee"
+  integrity sha512-JotGAWo8JhuXsQDK0UkzeQB0UR5hDAKvAviXrjqB4KM9wZNLhLleeEAW4Hk8R9smCeQFP6Xg/N/NkLDpqMwT3g==
+  dependencies:
+    "@parcel/diagnostic" "2.8.3"
+    "@parcel/plugin" "2.8.3"
+    "@parcel/source-map" "^2.1.1"
+    "@parcel/utils" "2.8.3"
+    browserslist "^4.6.6"
+    lightningcss "^1.16.1"
+    nullthrows "^1.1.1"
+
+"@parcel/[email protected]":
+  version "2.8.3"
+  resolved "https://registry.yarnpkg.com/@parcel/optimizer-htmlnano/-/optimizer-htmlnano-2.8.3.tgz#a71ab6f0f24160ef9f573266064438eff65e96d0"
+  integrity sha512-L8/fHbEy8Id2a2E0fwR5eKGlv9VYDjrH9PwdJE9Za9v1O/vEsfl/0T/79/x129l5O0yB6EFQkFa20MiK3b+vOg==
+  dependencies:
+    "@parcel/plugin" "2.8.3"
+    htmlnano "^2.0.0"
+    nullthrows "^1.1.1"
+    posthtml "^0.16.5"
+    svgo "^2.4.0"
+
+"@parcel/[email protected]":
+  version "2.8.3"
+  resolved "https://registry.yarnpkg.com/@parcel/optimizer-image/-/optimizer-image-2.8.3.tgz#ea49b4245b4f7d60b38c7585c6311fb21d341baa"
+  integrity sha512-SD71sSH27SkCDNUNx9A3jizqB/WIJr3dsfp+JZGZC42tpD/Siim6Rqy9M4To/BpMMQIIiEXa5ofwS+DgTEiEHQ==
+  dependencies:
+    "@parcel/diagnostic" "2.8.3"
+    "@parcel/plugin" "2.8.3"
+    "@parcel/utils" "2.8.3"
+    "@parcel/workers" "2.8.3"
+    detect-libc "^1.0.3"
+
+"@parcel/[email protected]":
+  version "2.8.3"
+  resolved "https://registry.yarnpkg.com/@parcel/optimizer-svgo/-/optimizer-svgo-2.8.3.tgz#04da4efec6b623679539a84961bff6998034ba8a"
+  integrity sha512-9KQed99NZnQw3/W4qBYVQ7212rzA9EqrQG019TIWJzkA9tjGBMIm2c/nXpK1tc3hQ3e7KkXkFCQ3C+ibVUnHNA==
+  dependencies:
+    "@parcel/diagnostic" "2.8.3"
+    "@parcel/plugin" "2.8.3"
+    "@parcel/utils" "2.8.3"
+    svgo "^2.4.0"
+
+"@parcel/[email protected]":
+  version "2.8.3"
+  resolved "https://registry.yarnpkg.com/@parcel/optimizer-terser/-/optimizer-terser-2.8.3.tgz#3a06d98d09386a1a0ae1be85376a8739bfba9618"
+  integrity sha512-9EeQlN6zIeUWwzrzu6Q2pQSaYsYGah8MtiQ/hog9KEPlYTP60hBv/+utDyYEHSQhL7y5ym08tPX5GzBvwAD/dA==
+  dependencies:
+    "@parcel/diagnostic" "2.8.3"
+    "@parcel/plugin" "2.8.3"
+    "@parcel/source-map" "^2.1.1"
+    "@parcel/utils" "2.8.3"
+    nullthrows "^1.1.1"
+    terser "^5.2.0"
+
+"@parcel/[email protected]":
+  version "2.8.3"
+  resolved "https://registry.yarnpkg.com/@parcel/package-manager/-/package-manager-2.8.3.tgz#ddd0d62feae3cf0fb6cc0537791b3a16296ad458"
+  integrity sha512-tIpY5pD2lH53p9hpi++GsODy6V3khSTX4pLEGuMpeSYbHthnOViobqIlFLsjni+QA1pfc8NNNIQwSNdGjYflVA==
+  dependencies:
+    "@parcel/diagnostic" "2.8.3"
+    "@parcel/fs" "2.8.3"
+    "@parcel/logger" "2.8.3"
+    "@parcel/types" "2.8.3"
+    "@parcel/utils" "2.8.3"
+    "@parcel/workers" "2.8.3"
+    semver "^5.7.1"
+
+"@parcel/[email protected]":
+  version "2.8.3"
+  resolved "https://registry.yarnpkg.com/@parcel/packager-css/-/packager-css-2.8.3.tgz#0eff34268cb4f5dfb53c1bbca85f5567aeb1835a"
+  integrity sha512-WyvkMmsurlHG8d8oUVm7S+D+cC/T3qGeqogb7sTI52gB6uiywU7lRCizLNqGFyFGIxcVTVHWnSHqItBcLN76lA==
+  dependencies:
+    "@parcel/plugin" "2.8.3"
+    "@parcel/source-map" "^2.1.1"
+    "@parcel/utils" "2.8.3"
+    nullthrows "^1.1.1"
+
+"@parcel/[email protected]":
+  version "2.8.3"
+  resolved "https://registry.yarnpkg.com/@parcel/packager-html/-/packager-html-2.8.3.tgz#f9263b891aa4dd46c6e2fa2b07025a482132fff1"
+  integrity sha512-OhPu1Hx1RRKJodpiu86ZqL8el2Aa4uhBHF6RAL1Pcrh2EhRRlPf70Sk0tC22zUpYL7es+iNKZ/n0Rl+OWSHWEw==
+  dependencies:
+    "@parcel/plugin" "2.8.3"
+    "@parcel/types" "2.8.3"
+    "@parcel/utils" "2.8.3"
+    nullthrows "^1.1.1"
+    posthtml "^0.16.5"
+
+"@parcel/[email protected]":
+  version "2.8.3"
+  resolved "https://registry.yarnpkg.com/@parcel/packager-js/-/packager-js-2.8.3.tgz#3ed11565915d73d12192b6901c75a6b820e4a83a"
+  integrity sha512-0pGKC3Ax5vFuxuZCRB+nBucRfFRz4ioie19BbDxYnvBxrd4M3FIu45njf6zbBYsI9eXqaDnL1b3DcZJfYqtIzw==
+  dependencies:
+    "@parcel/diagnostic" "2.8.3"
+    "@parcel/hash" "2.8.3"
+    "@parcel/plugin" "2.8.3"
+    "@parcel/source-map" "^2.1.1"
+    "@parcel/utils" "2.8.3"
+    globals "^13.2.0"
+    nullthrows "^1.1.1"
+
+"@parcel/[email protected]":
+  version "2.8.3"
+  resolved "https://registry.yarnpkg.com/@parcel/packager-raw/-/packager-raw-2.8.3.tgz#bdec826df991e186cb58691cc45d12ad5c06676e"
+  integrity sha512-BA6enNQo1RCnco9MhkxGrjOk59O71IZ9DPKu3lCtqqYEVd823tXff2clDKHK25i6cChmeHu6oB1Rb73hlPqhUA==
+  dependencies:
+    "@parcel/plugin" "2.8.3"
+
+"@parcel/[email protected]":
+  version "2.8.3"
+  resolved "https://registry.yarnpkg.com/@parcel/packager-svg/-/packager-svg-2.8.3.tgz#7233315296001c531cb55ca96b5f2ef672343630"
+  integrity sha512-mvIoHpmv5yzl36OjrklTDFShLUfPFTwrmp1eIwiszGdEBuQaX7JVI3Oo2jbVQgcN4W7J6SENzGQ3Q5hPTW3pMw==
+  dependencies:
+    "@parcel/plugin" "2.8.3"
+    "@parcel/types" "2.8.3"
+    "@parcel/utils" "2.8.3"
+    posthtml "^0.16.4"
+
+"@parcel/[email protected]":
+  version "2.8.3"
+  resolved "https://registry.yarnpkg.com/@parcel/plugin/-/plugin-2.8.3.tgz#7bb30a5775eaa6473c27f002a0a3ee7308d6d669"
+  integrity sha512-jZ6mnsS4D9X9GaNnvrixDQwlUQJCohDX2hGyM0U0bY2NWU8Km97SjtoCpWjq+XBCx/gpC4g58+fk9VQeZq2vlw==
+  dependencies:
+    "@parcel/types" "2.8.3"
+
+"@parcel/[email protected]":
+  version "2.8.3"
+  resolved "https://registry.yarnpkg.com/@parcel/reporter-cli/-/reporter-cli-2.8.3.tgz#12a4743b51b8fe6837f53c20e01bbf1f7336e8e4"
+  integrity sha512-3sJkS6tFFzgIOz3u3IpD/RsmRxvOKKiQHOTkiiqRt1l44mMDGKS7zANRnJYsQzdCsgwc9SOP30XFgJwtoVlMbw==
+  dependencies:
+    "@parcel/plugin" "2.8.3"
+    "@parcel/types" "2.8.3"
+    "@parcel/utils" "2.8.3"
+    chalk "^4.1.0"
+    term-size "^2.2.1"
+
+"@parcel/[email protected]":
+  version "2.8.3"
+  resolved "https://registry.yarnpkg.com/@parcel/reporter-dev-server/-/reporter-dev-server-2.8.3.tgz#a0daa5cc015642684cea561f4e0e7116bbffdc1c"
+  integrity sha512-Y8C8hzgzTd13IoWTj+COYXEyCkXfmVJs3//GDBsH22pbtSFMuzAZd+8J9qsCo0EWpiDow7V9f1LischvEh3FbQ==
+  dependencies:
+    "@parcel/plugin" "2.8.3"
+    "@parcel/utils" "2.8.3"
+
+"@parcel/[email protected]":
+  version "2.8.3"
+  resolved "https://registry.yarnpkg.com/@parcel/resolver-default/-/resolver-default-2.8.3.tgz#5ae41e537ae4a793c1abb47f094482b9e2ac3535"
+  integrity sha512-k0B5M/PJ+3rFbNj4xZSBr6d6HVIe6DH/P3dClLcgBYSXAvElNDfXgtIimbjCyItFkW9/BfcgOVKEEIZOeySH/A==
+  dependencies:
+    "@parcel/node-resolver-core" "2.8.3"
+    "@parcel/plugin" "2.8.3"
+
+"@parcel/[email protected]":
+  version "2.8.3"
+  resolved "https://registry.yarnpkg.com/@parcel/runtime-browser-hmr/-/runtime-browser-hmr-2.8.3.tgz#1fa74e1fbd1030b0a920c58afa3a9eb7dc4bcd1e"
+  integrity sha512-2O1PYi2j/Q0lTyGNV3JdBYwg4rKo6TEVFlYGdd5wCYU9ZIN9RRuoCnWWH2qCPj3pjIVtBeppYxzfVjPEHINWVg==
+  dependencies:
+    "@parcel/plugin" "2.8.3"
+    "@parcel/utils" "2.8.3"
+
+"@parcel/[email protected]":
+  version "2.8.3"
+  resolved "https://registry.yarnpkg.com/@parcel/runtime-js/-/runtime-js-2.8.3.tgz#0baa4c8fbf77eabce05d01ccc186614968ffc0cd"
+  integrity sha512-IRja0vNKwvMtPgIqkBQh0QtRn0XcxNC8HU1jrgWGRckzu10qJWO+5ULgtOeR4pv9krffmMPqywGXw6l/gvJKYQ==
+  dependencies:
+    "@parcel/plugin" "2.8.3"
+    "@parcel/utils" "2.8.3"
+    nullthrows "^1.1.1"
+
+"@parcel/[email protected]":
+  version "2.8.3"
+  resolved "https://registry.yarnpkg.com/@parcel/runtime-react-refresh/-/runtime-react-refresh-2.8.3.tgz#381a942fb81e8f5ac6c7e0ee1b91dbf34763c3f8"
+  integrity sha512-2v/qFKp00MfG0234OdOgQNAo6TLENpFYZMbVbAsPMY9ITiqG73MrEsrGXVoGbYiGTMB/Toer/lSWlJxtacOCuA==
+  dependencies:
+    "@parcel/plugin" "2.8.3"
+    "@parcel/utils" "2.8.3"
+    react-error-overlay "6.0.9"
+    react-refresh "^0.9.0"
+
+"@parcel/[email protected]":
+  version "2.8.3"
+  resolved "https://registry.yarnpkg.com/@parcel/runtime-service-worker/-/runtime-service-worker-2.8.3.tgz#54d92da9ff1dfbd27db0e84164a22fa59e99b348"
+  integrity sha512-/Skkw+EeRiwzOJso5fQtK8c9b452uWLNhQH1ISTodbmlcyB4YalAiSsyHCtMYD0c3/t5Sx4ZS7vxBAtQd0RvOw==
+  dependencies:
+    "@parcel/plugin" "2.8.3"
+    "@parcel/utils" "2.8.3"
+    nullthrows "^1.1.1"
+
+"@parcel/source-map@^2.1.1":
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/@parcel/source-map/-/source-map-2.1.1.tgz#fb193b82dba6dd62cc7a76b326f57bb35000a782"
+  integrity sha512-Ejx1P/mj+kMjQb8/y5XxDUn4reGdr+WyKYloBljpppUy8gs42T+BNoEOuRYqDVdgPc6NxduzIDoJS9pOFfV5Ew==
+  dependencies:
+    detect-libc "^1.0.3"
+
+"@parcel/[email protected]":
+  version "2.8.3"
+  resolved "https://registry.yarnpkg.com/@parcel/transformer-babel/-/transformer-babel-2.8.3.tgz#286bc6cb9afe4c0259f0b28e0f2f47322a24b130"
+  integrity sha512-L6lExfpvvC7T/g3pxf3CIJRouQl+sgrSzuWQ0fD4PemUDHvHchSP4SNUVnd6gOytF3Y1KpnEZIunQGi5xVqQCQ==
+  dependencies:
+    "@parcel/diagnostic" "2.8.3"
+    "@parcel/plugin" "2.8.3"
+    "@parcel/source-map" "^2.1.1"
+    "@parcel/utils" "2.8.3"
+    browserslist "^4.6.6"
+    json5 "^2.2.0"
+    nullthrows "^1.1.1"
+    semver "^5.7.0"
+
+"@parcel/[email protected]":
+  version "2.8.3"
+  resolved "https://registry.yarnpkg.com/@parcel/transformer-css/-/transformer-css-2.8.3.tgz#d6c44100204e73841ad8e0f90472172ea8b9120c"
+  integrity sha512-xTqFwlSXtnaYen9ivAgz+xPW7yRl/u4QxtnDyDpz5dr8gSeOpQYRcjkd4RsYzKsWzZcGtB5EofEk8ayUbWKEUg==
+  dependencies:
+    "@parcel/diagnostic" "2.8.3"
+    "@parcel/plugin" "2.8.3"
+    "@parcel/source-map" "^2.1.1"
+    "@parcel/utils" "2.8.3"
+    browserslist "^4.6.6"
+    lightningcss "^1.16.1"
+    nullthrows "^1.1.1"
+
+"@parcel/[email protected]":
+  version "2.8.3"
+  resolved "https://registry.yarnpkg.com/@parcel/transformer-html/-/transformer-html-2.8.3.tgz#5c68b28ee6b8c7a13b8aee87f7957ad3227bd83f"
+  integrity sha512-kIZO3qsMYTbSnSpl9cnZog+SwL517ffWH54JeB410OSAYF1ouf4n5v9qBnALZbuCCmPwJRGs4jUtE452hxwN4g==
+  dependencies:
+    "@parcel/diagnostic" "2.8.3"
+    "@parcel/hash" "2.8.3"
+    "@parcel/plugin" "2.8.3"
+    nullthrows "^1.1.1"
+    posthtml "^0.16.5"
+    posthtml-parser "^0.10.1"
+    posthtml-render "^3.0.0"
+    semver "^5.7.1"
+    srcset "4"
+
+"@parcel/[email protected]":
+  version "2.8.3"
+  resolved "https://registry.yarnpkg.com/@parcel/transformer-image/-/transformer-image-2.8.3.tgz#73805b2bfc3c8919d7737544e5f8be39e3f303fe"
+  integrity sha512-cO4uptcCGTi5H6bvTrAWEFUsTNhA4kCo8BSvRSCHA2sf/4C5tGQPHt3JhdO0GQLPwZRCh/R41EkJs5HZ8A8DAg==
+  dependencies:
+    "@parcel/plugin" "2.8.3"
+    "@parcel/utils" "2.8.3"
+    "@parcel/workers" "2.8.3"
+    nullthrows "^1.1.1"
+
+"@parcel/[email protected]":
+  version "2.8.3"
+  resolved "https://registry.yarnpkg.com/@parcel/transformer-js/-/transformer-js-2.8.3.tgz#fe400df428394d1e7fe5afb6dea5c7c858e44f03"
+  integrity sha512-9Qd6bib+sWRcpovvzvxwy/PdFrLUXGfmSW9XcVVG8pvgXsZPFaNjnNT8stzGQj1pQiougCoxMY4aTM5p1lGHEQ==
+  dependencies:
+    "@parcel/diagnostic" "2.8.3"
+    "@parcel/plugin" "2.8.3"
+    "@parcel/source-map" "^2.1.1"
+    "@parcel/utils" "2.8.3"
+    "@parcel/workers" "2.8.3"
+    "@swc/helpers" "^0.4.12"
+    browserslist "^4.6.6"
+    detect-libc "^1.0.3"
+    nullthrows "^1.1.1"
+    regenerator-runtime "^0.13.7"
+    semver "^5.7.1"
+
+"@parcel/[email protected]":
+  version "2.8.3"
+  resolved "https://registry.yarnpkg.com/@parcel/transformer-json/-/transformer-json-2.8.3.tgz#25deb3a5138cc70a83269fc5d39d564609354d36"
+  integrity sha512-B7LmVq5Q7bZO4ERb6NHtRuUKWGysEeaj9H4zelnyBv+wLgpo4f5FCxSE1/rTNmP9u1qHvQ3scGdK6EdSSokGPg==
+  dependencies:
+    "@parcel/plugin" "2.8.3"
+    json5 "^2.2.0"
+
+"@parcel/[email protected]":
+  version "2.8.3"
+  resolved "https://registry.yarnpkg.com/@parcel/transformer-postcss/-/transformer-postcss-2.8.3.tgz#df4fdc1c90893823445f2a8eb8e2bdd0349ccc58"
+  integrity sha512-e8luB/poIlz6jBsD1Izms+6ElbyzuoFVa4lFVLZnTAChI3UxPdt9p/uTsIO46HyBps/Bk8ocvt3J4YF84jzmvg==
+  dependencies:
+    "@parcel/diagnostic" "2.8.3"
+    "@parcel/hash" "2.8.3"
+    "@parcel/plugin" "2.8.3"
+    "@parcel/utils" "2.8.3"
+    clone "^2.1.1"
+    nullthrows "^1.1.1"
+    postcss-value-parser "^4.2.0"
+    semver "^5.7.1"
+
+"@parcel/[email protected]":
+  version "2.8.3"
+  resolved "https://registry.yarnpkg.com/@parcel/transformer-posthtml/-/transformer-posthtml-2.8.3.tgz#7c3912a5a631cb26485f6464e0d6eeabb6f1e718"
+  integrity sha512-pkzf9Smyeaw4uaRLsT41RGrPLT5Aip8ZPcntawAfIo+KivBQUV0erY1IvHYjyfFzq1ld/Fo2Ith9He6mxpPifA==
+  dependencies:
+    "@parcel/plugin" "2.8.3"
+    "@parcel/utils" "2.8.3"
+    nullthrows "^1.1.1"
+    posthtml "^0.16.5"
+    posthtml-parser "^0.10.1"
+    posthtml-render "^3.0.0"
+    semver "^5.7.1"
+
+"@parcel/[email protected]":
+  version "2.8.3"
+  resolved "https://registry.yarnpkg.com/@parcel/transformer-raw/-/transformer-raw-2.8.3.tgz#3a22213fe18a5f83fd78889cb49f06e059cfead7"
+  integrity sha512-G+5cXnd2/1O3nV/pgRxVKZY/HcGSseuhAe71gQdSQftb8uJEURyUHoQ9Eh0JUD3MgWh9V+nIKoyFEZdf9T0sUQ==
+  dependencies:
+    "@parcel/plugin" "2.8.3"
+
+"@parcel/[email protected]":
+  version "2.8.3"
+  resolved "https://registry.yarnpkg.com/@parcel/transformer-react-refresh-wrap/-/transformer-react-refresh-wrap-2.8.3.tgz#8b0392638405dd470a886002229f7889d5464822"
+  integrity sha512-q8AAoEvBnCf/nPvgOwFwKZfEl/thwq7c2duxXkhl+tTLDRN2vGmyz4355IxCkavSX+pLWSQ5MexklSEeMkgthg==
+  dependencies:
+    "@parcel/plugin" "2.8.3"
+    "@parcel/utils" "2.8.3"
+    react-refresh "^0.9.0"
+
+"@parcel/[email protected]":
+  version "2.8.3"
+  resolved "https://registry.yarnpkg.com/@parcel/transformer-svg/-/transformer-svg-2.8.3.tgz#4df959cba4ebf45d7aaddd540f752e6e84df38b2"
+  integrity sha512-3Zr/gBzxi1ZH1fftH/+KsZU7w5GqkmxlB0ZM8ovS5E/Pl1lq1t0xvGJue9m2VuQqP8Mxfpl5qLFmsKlhaZdMIQ==
+  dependencies:
+    "@parcel/diagnostic" "2.8.3"
+    "@parcel/hash" "2.8.3"
+    "@parcel/plugin" "2.8.3"
+    nullthrows "^1.1.1"
+    posthtml "^0.16.5"
+    posthtml-parser "^0.10.1"
+    posthtml-render "^3.0.0"
+    semver "^5.7.1"
+
+"@parcel/[email protected]":
+  version "2.8.3"
+  resolved "https://registry.yarnpkg.com/@parcel/types/-/types-2.8.3.tgz#3306bc5391b6913bd619914894b8cd84a24b30fa"
+  integrity sha512-FECA1FB7+0UpITKU0D6TgGBpGxYpVSMNEENZbSJxFSajNy3wrko+zwBKQmFOLOiPcEtnGikxNs+jkFWbPlUAtw==
+  dependencies:
+    "@parcel/cache" "2.8.3"
+    "@parcel/diagnostic" "2.8.3"
+    "@parcel/fs" "2.8.3"
+    "@parcel/package-manager" "2.8.3"
+    "@parcel/source-map" "^2.1.1"
+    "@parcel/workers" "2.8.3"
+    utility-types "^3.10.0"
+
+"@parcel/[email protected]":
+  version "2.8.3"
+  resolved "https://registry.yarnpkg.com/@parcel/utils/-/utils-2.8.3.tgz#0d56c9e8e22c119590a5e044a0e01031965da40e"
+  integrity sha512-IhVrmNiJ+LOKHcCivG5dnuLGjhPYxQ/IzbnF2DKNQXWBTsYlHkJZpmz7THoeLtLliGmSOZ3ZCsbR8/tJJKmxjA==
+  dependencies:
+    "@parcel/codeframe" "2.8.3"
+    "@parcel/diagnostic" "2.8.3"
+    "@parcel/hash" "2.8.3"
+    "@parcel/logger" "2.8.3"
+    "@parcel/markdown-ansi" "2.8.3"
+    "@parcel/source-map" "^2.1.1"
+    chalk "^4.1.0"
+
+"@parcel/watcher@^2.0.7":
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/@parcel/watcher/-/watcher-2.1.0.tgz#5f32969362db4893922c526a842d8af7a8538545"
+  integrity sha512-8s8yYjd19pDSsBpbkOHnT6Z2+UJSuLQx61pCFM0s5wSRvKCEMDjd/cHY3/GI1szHIWbpXpsJdg3V6ISGGx9xDw==
+  dependencies:
+    is-glob "^4.0.3"
+    micromatch "^4.0.5"
+    node-addon-api "^3.2.1"
+    node-gyp-build "^4.3.0"
+
+"@parcel/[email protected]":
+  version "2.8.3"
+  resolved "https://registry.yarnpkg.com/@parcel/workers/-/workers-2.8.3.tgz#255450ccf4db234082407e4ddda5fd575f08c235"
+  integrity sha512-+AxBnKgjqVpUHBcHLWIHcjYgKIvHIpZjN33mG5LG9XXvrZiqdWvouEzqEXlVLq5VzzVbKIQQcmsvRy138YErkg==
+  dependencies:
+    "@parcel/diagnostic" "2.8.3"
+    "@parcel/logger" "2.8.3"
+    "@parcel/types" "2.8.3"
+    "@parcel/utils" "2.8.3"
+    chrome-trace-event "^1.0.2"
+    nullthrows "^1.1.1"
+
+"@radix-ui/[email protected]":
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/@radix-ui/number/-/number-1.0.0.tgz#4c536161d0de750b3f5d55860fc3de46264f897b"
+  integrity sha512-Ofwh/1HX69ZfJRiRBMTy7rgjAzHmwe4kW9C9Y99HTRUcYLUuVT0KESFj15rPjRgKJs20GPq8Bm5aEDJ8DuA3vA==
+  dependencies:
+    "@babel/runtime" "^7.13.10"
+
+"@radix-ui/[email protected]":
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/@radix-ui/primitive/-/primitive-1.0.0.tgz#e1d8ef30b10ea10e69c76e896f608d9276352253"
+  integrity sha512-3e7rn8FDMin4CgeL7Z/49smCA3rFYY3Ha2rUQ7HRWFadS5iCRw08ZgVT1LaNTCNqgvrUiyczLflrVrF0SRQtNA==
+  dependencies:
+    "@babel/runtime" "^7.13.10"
+
+"@radix-ui/[email protected]":
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/@radix-ui/react-accordion/-/react-accordion-1.0.0.tgz#bf69dc1f13fce05d6d7560ff79954c49abc1b71b"
+  integrity sha512-F4vrzev+f1gjrWiU+IFQIzN43fYyvQ+AN0OicHYoDddis53xnPC0DKm16Ks4/XjvmqbISAR/FscYX0vymEHxcA==
+  dependencies:
+    "@babel/runtime" "^7.13.10"
+    "@radix-ui/primitive" "1.0.0"
+    "@radix-ui/react-collapsible" "1.0.0"
+    "@radix-ui/react-collection" "1.0.0"
+    "@radix-ui/react-compose-refs" "1.0.0"
+    "@radix-ui/react-context" "1.0.0"
+    "@radix-ui/react-id" "1.0.0"
+    "@radix-ui/react-primitive" "1.0.0"
+    "@radix-ui/react-use-controllable-state" "1.0.0"
+
+"@radix-ui/[email protected]":
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/@radix-ui/react-arrow/-/react-arrow-1.0.0.tgz#c461f4c2cab3317e3d42a1ae62910a4cbb0192a1"
+  integrity sha512-1MUuv24HCdepi41+qfv125EwMuxgQ+U+h0A9K3BjCO/J8nVRREKHHpkD9clwfnjEDk9hgGzCnff4aUKCPiRepw==
+  dependencies:
+    "@babel/runtime" "^7.13.10"
+    "@radix-ui/react-primitive" "1.0.0"
+
+"@radix-ui/[email protected]":
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/@radix-ui/react-collapsible/-/react-collapsible-1.0.0.tgz#0d94fc847c2d4bee1ab646d15c87bd3be6448873"
+  integrity sha512-NfZqWntvPsC43szs0NvumRjmTTJTLgaDOAnmVGDZaGsg2u6LcJwUT7YeYSKnlxWRQWN4pwwEfoYdWrtoutfO8g==
+  dependencies:
+    "@babel/runtime" "^7.13.10"
+    "@radix-ui/primitive" "1.0.0"
+    "@radix-ui/react-compose-refs" "1.0.0"
+    "@radix-ui/react-context" "1.0.0"
+    "@radix-ui/react-id" "1.0.0"
+    "@radix-ui/react-presence" "1.0.0"
+    "@radix-ui/react-primitive" "1.0.0"
+    "@radix-ui/react-use-controllable-state" "1.0.0"
+    "@radix-ui/react-use-layout-effect" "1.0.0"
+
+"@radix-ui/[email protected]":
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/@radix-ui/react-collection/-/react-collection-1.0.0.tgz#0ec4c72fabd35a03b5787075ac799e3b17ca5710"
+  integrity sha512-8i1pf5dKjnq90Z8udnnXKzdCEV3/FYrfw0n/b6NvB6piXEn3fO1bOh7HBcpG8XrnIXzxlYu2oCcR38QpyLS/mg==
+  dependencies:
+    "@babel/runtime" "^7.13.10"
+    "@radix-ui/react-compose-refs" "1.0.0"
+    "@radix-ui/react-context" "1.0.0"
+    "@radix-ui/react-primitive" "1.0.0"
+    "@radix-ui/react-slot" "1.0.0"
+
+"@radix-ui/[email protected]":
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/@radix-ui/react-compose-refs/-/react-compose-refs-1.0.0.tgz#37595b1f16ec7f228d698590e78eeed18ff218ae"
+  integrity sha512-0KaSv6sx787/hK3eF53iOkiSLwAGlFMx5lotrqD2pTjB18KbybKoEIgkNZTKC60YECDQTKGTRcDBILwZVqVKvA==
+  dependencies:
+    "@babel/runtime" "^7.13.10"
+
+"@radix-ui/[email protected]":
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/@radix-ui/react-context/-/react-context-1.0.0.tgz#f38e30c5859a9fb5e9aa9a9da452ee3ed9e0aee0"
+  integrity sha512-1pVM9RfOQ+n/N5PJK33kRSKsr1glNxomxONs5c49MliinBY6Yw2Q995qfBUUo0/Mbg05B/sGA0gkgPI7kmSHBg==
+  dependencies:
+    "@babel/runtime" "^7.13.10"
+
+"@radix-ui/[email protected]":
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/@radix-ui/react-direction/-/react-direction-1.0.0.tgz#a2e0b552352459ecf96342c79949dd833c1e6e45"
+  integrity sha512-2HV05lGUgYcA6xgLQ4BKPDmtL+QbIZYH5fCOTAOOcJ5O0QbWS3i9lKaurLzliYUDhORI2Qr3pyjhJh44lKA3rQ==
+  dependencies:
+    "@babel/runtime" "^7.13.10"
+
+"@radix-ui/[email protected]":
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.0.0.tgz#35b7826fa262fd84370faef310e627161dffa76b"
+  integrity sha512-n7kDRfx+LB1zLueRDvZ1Pd0bxdJWDUZNQ/GWoxDn2prnuJKRdxsjulejX/ePkOsLi2tTm6P24mDqlMSgQpsT6g==
+  dependencies:
+    "@babel/runtime" "^7.13.10"
+    "@radix-ui/primitive" "1.0.0"
+    "@radix-ui/react-compose-refs" "1.0.0"
+    "@radix-ui/react-primitive" "1.0.0"
+    "@radix-ui/react-use-callback-ref" "1.0.0"
+    "@radix-ui/react-use-escape-keydown" "1.0.0"
+
+"@radix-ui/[email protected]":
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/@radix-ui/react-dropdown-menu/-/react-dropdown-menu-1.0.0.tgz#687959e1bcdd5e8eb0de406484aff28d0974c593"
+  integrity sha512-Ptben3TxPWrZLbInO7zjAK73kmjYuStsxfg6ujgt+EywJyREoibhZYnsSNqC+UiOtl4PdW/MOHhxVDtew5fouQ==
+  dependencies:
+    "@babel/runtime" "^7.13.10"
+    "@radix-ui/primitive" "1.0.0"
+    "@radix-ui/react-compose-refs" "1.0.0"
+    "@radix-ui/react-context" "1.0.0"
+    "@radix-ui/react-id" "1.0.0"
+    "@radix-ui/react-menu" "1.0.0"
+    "@radix-ui/react-primitive" "1.0.0"
+    "@radix-ui/react-use-controllable-state" "1.0.0"
+
+"@radix-ui/[email protected]":
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/@radix-ui/react-focus-guards/-/react-focus-guards-1.0.0.tgz#339c1c69c41628c1a5e655f15f7020bf11aa01fa"
+  integrity sha512-UagjDk4ijOAnGu4WMUPj9ahi7/zJJqNZ9ZAiGPp7waUWJO0O1aWXi/udPphI0IUjvrhBsZJGSN66dR2dsueLWQ==
+  dependencies:
+    "@babel/runtime" "^7.13.10"
+
+"@radix-ui/[email protected]":
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/@radix-ui/react-focus-scope/-/react-focus-scope-1.0.0.tgz#95a0c1188276dc8933b1eac5f1cdb6471e01ade5"
+  integrity sha512-C4SWtsULLGf/2L4oGeIHlvWQx7Rf+7cX/vKOAD2dXW0A1b5QXwi3wWeaEgW+wn+SEVrraMUk05vLU9fZZz5HbQ==
+  dependencies:
+    "@babel/runtime" "^7.13.10"
+    "@radix-ui/react-compose-refs" "1.0.0"
+    "@radix-ui/react-primitive" "1.0.0"
+    "@radix-ui/react-use-callback-ref" "1.0.0"
+
+"@radix-ui/[email protected]":
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/@radix-ui/react-id/-/react-id-1.0.0.tgz#8d43224910741870a45a8c9d092f25887bb6d11e"
+  integrity sha512-Q6iAB/U7Tq3NTolBBQbHTgclPmGWE3OlktGGqrClPozSw4vkQ1DfQAOtzgRPecKsMdJINE05iaoDUG8tRzCBjw==
+  dependencies:
+    "@babel/runtime" "^7.13.10"
+    "@radix-ui/react-use-layout-effect" "1.0.0"
+
+"@radix-ui/[email protected]":
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/@radix-ui/react-menu/-/react-menu-1.0.0.tgz#f1e07778c0011aa0c5be260fee88491d3aadf261"
+  integrity sha512-icW4C64T6nHh3Z4Q1fxO1RlSShouFF4UpUmPV8FLaJZfphDljannKErDuALDx4ClRLihAPZ9i+PrLNPoWS2DMA==
+  dependencies:
+    "@babel/runtime" "^7.13.10"
+    "@radix-ui/primitive" "1.0.0"
+    "@radix-ui/react-collection" "1.0.0"
+    "@radix-ui/react-compose-refs" "1.0.0"
+    "@radix-ui/react-context" "1.0.0"
+    "@radix-ui/react-direction" "1.0.0"
+    "@radix-ui/react-dismissable-layer" "1.0.0"
+    "@radix-ui/react-focus-guards" "1.0.0"
+    "@radix-ui/react-focus-scope" "1.0.0"
+    "@radix-ui/react-id" "1.0.0"
+    "@radix-ui/react-popper" "1.0.0"
+    "@radix-ui/react-portal" "1.0.0"
+    "@radix-ui/react-presence" "1.0.0"
+    "@radix-ui/react-primitive" "1.0.0"
+    "@radix-ui/react-roving-focus" "1.0.0"
+    "@radix-ui/react-slot" "1.0.0"
+    "@radix-ui/react-use-callback-ref" "1.0.0"
+    aria-hidden "^1.1.1"
+    react-remove-scroll "2.5.4"
+
+"@radix-ui/[email protected]":
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/@radix-ui/react-popper/-/react-popper-1.0.0.tgz#fb4f937864bf39c48f27f55beee61fa9f2bef93c"
+  integrity sha512-k2dDd+1Wl0XWAMs9ZvAxxYsB9sOsEhrFQV4CINd7IUZf0wfdye4OHen9siwxvZImbzhgVeKTJi68OQmPRvVdMg==
+  dependencies:
+    "@babel/runtime" "^7.13.10"
+    "@floating-ui/react-dom" "0.7.2"
+    "@radix-ui/react-arrow" "1.0.0"
+    "@radix-ui/react-compose-refs" "1.0.0"
+    "@radix-ui/react-context" "1.0.0"
+    "@radix-ui/react-primitive" "1.0.0"
+    "@radix-ui/react-use-layout-effect" "1.0.0"
+    "@radix-ui/react-use-rect" "1.0.0"
+    "@radix-ui/react-use-size" "1.0.0"
+    "@radix-ui/rect" "1.0.0"
+
+"@radix-ui/[email protected]":
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/@radix-ui/react-portal/-/react-portal-1.0.0.tgz#7220b66743394fabb50c55cb32381395cc4a276b"
+  integrity sha512-a8qyFO/Xb99d8wQdu4o7qnigNjTPG123uADNecz0eX4usnQEj7o+cG4ZX4zkqq98NYekT7UoEQIjxBNWIFuqTA==
+  dependencies:
+    "@babel/runtime" "^7.13.10"
+    "@radix-ui/react-primitive" "1.0.0"
+
+"@radix-ui/[email protected]":
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/@radix-ui/react-presence/-/react-presence-1.0.0.tgz#814fe46df11f9a468808a6010e3f3ca7e0b2e84a"
+  integrity sha512-A+6XEvN01NfVWiKu38ybawfHsBjWum42MRPnEuqPsBZ4eV7e/7K321B5VgYMPv3Xx5An6o1/l9ZuDBgmcmWK3w==
+  dependencies:
+    "@babel/runtime" "^7.13.10"
+    "@radix-ui/react-compose-refs" "1.0.0"
+    "@radix-ui/react-use-layout-effect" "1.0.0"
+
+"@radix-ui/[email protected]":
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/@radix-ui/react-primitive/-/react-primitive-1.0.0.tgz#376cd72b0fcd5e0e04d252ed33eb1b1f025af2b0"
+  integrity sha512-EyXe6mnRlHZ8b6f4ilTDrXmkLShICIuOTTj0GX4w1rp+wSxf3+TD05u1UOITC8VsJ2a9nwHvdXtOXEOl0Cw/zQ==
+  dependencies:
+    "@babel/runtime" "^7.13.10"
+    "@radix-ui/react-slot" "1.0.0"
+
+"@radix-ui/[email protected]":
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/@radix-ui/react-roving-focus/-/react-roving-focus-1.0.0.tgz#aadeb65d5dbcdbdd037078156ae1f57c2ff754ee"
+  integrity sha512-lHvO4MhvoWpeNbiJAoyDsEtbKqP2jkkdwsMVJ3kfqbkC71J/aXE6Th6gkZA1xHEqSku+t+UgoDjvE7Z3gsBpcg==
+  dependencies:
+    "@babel/runtime" "^7.13.10"
+    "@radix-ui/primitive" "1.0.0"
+    "@radix-ui/react-collection" "1.0.0"
+    "@radix-ui/react-compose-refs" "1.0.0"
+    "@radix-ui/react-context" "1.0.0"
+    "@radix-ui/react-direction" "1.0.0"
+    "@radix-ui/react-id" "1.0.0"
+    "@radix-ui/react-primitive" "1.0.0"
+    "@radix-ui/react-use-callback-ref" "1.0.0"
+    "@radix-ui/react-use-controllable-state" "1.0.0"
+
+"@radix-ui/[email protected]":
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/@radix-ui/react-slider/-/react-slider-1.0.0.tgz#4cabadd243aa088eb45ac710cd7cdc518fafb07e"
+  integrity sha512-LMZET7vn7HYwYSjsc9Jcen8Vn4cJXZZxQT7T+lGlqp+F+FofX+H86TBF2yDq+L51d99f1KLEsflTGBz9WRLSig==
+  dependencies:
+    "@babel/runtime" "^7.13.10"
+    "@radix-ui/number" "1.0.0"
+    "@radix-ui/primitive" "1.0.0"
+    "@radix-ui/react-collection" "1.0.0"
+    "@radix-ui/react-compose-refs" "1.0.0"
+    "@radix-ui/react-context" "1.0.0"
+    "@radix-ui/react-direction" "1.0.0"
+    "@radix-ui/react-primitive" "1.0.0"
+    "@radix-ui/react-use-controllable-state" "1.0.0"
+    "@radix-ui/react-use-layout-effect" "1.0.0"
+    "@radix-ui/react-use-previous" "1.0.0"
+    "@radix-ui/react-use-size" "1.0.0"
+
+"@radix-ui/[email protected]":
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/@radix-ui/react-slot/-/react-slot-1.0.0.tgz#7fa805b99891dea1e862d8f8fbe07f4d6d0fd698"
+  integrity sha512-3mrKauI/tWXo1Ll+gN5dHcxDPdm/Df1ufcDLCecn+pnCIVcdWE7CujXo8QaXOWRJyZyQWWbpB8eFwHzWXlv5mQ==
+  dependencies:
+    "@babel/runtime" "^7.13.10"
+    "@radix-ui/react-compose-refs" "1.0.0"
+
+"@radix-ui/[email protected]":
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/@radix-ui/react-tabs/-/react-tabs-1.0.0.tgz#135c67f1f2bd9ada69a3f6e38dd897d459af5fe5"
+  integrity sha512-oKUwEDsySVC0uuSEH7SHCVt1+ijmiDFAI9p+fHCtuZdqrRDKIFs09zp5nrmu4ggP6xqSx9lj1VSblnDH+n3IBA==
+  dependencies:
+    "@babel/runtime" "^7.13.10"
+    "@radix-ui/primitive" "1.0.0"
+    "@radix-ui/react-context" "1.0.0"
+    "@radix-ui/react-direction" "1.0.0"
+    "@radix-ui/react-id" "1.0.0"
+    "@radix-ui/react-presence" "1.0.0"
+    "@radix-ui/react-primitive" "1.0.0"
+    "@radix-ui/react-roving-focus" "1.0.0"
+    "@radix-ui/react-use-controllable-state" "1.0.0"
+
+"@radix-ui/[email protected]":
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.0.0.tgz#9e7b8b6b4946fe3cbe8f748c82a2cce54e7b6a90"
+  integrity sha512-GZtyzoHz95Rhs6S63D2t/eqvdFCm7I+yHMLVQheKM7nBD8mbZIt+ct1jz4536MDnaOGKIxynJ8eHTkVGVVkoTg==
+  dependencies:
+    "@babel/runtime" "^7.13.10"
+
+"@radix-ui/[email protected]":
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.0.0.tgz#a64deaafbbc52d5d407afaa22d493d687c538b7f"
+  integrity sha512-FohDoZvk3mEXh9AWAVyRTYR4Sq7/gavuofglmiXB2g1aKyboUD4YtgWxKj8O5n+Uak52gXQ4wKz5IFST4vtJHg==
+  dependencies:
+    "@babel/runtime" "^7.13.10"
+    "@radix-ui/react-use-callback-ref" "1.0.0"
+
+"@radix-ui/[email protected]":
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.0.0.tgz#aef375db4736b9de38a5a679f6f49b45a060e5d1"
+  integrity sha512-JwfBCUIfhXRxKExgIqGa4CQsiMemo1Xt0W/B4ei3fpzpvPENKpMKQ8mZSB6Acj3ebrAEgi2xiQvcI1PAAodvyg==
+  dependencies:
+    "@babel/runtime" "^7.13.10"
+    "@radix-ui/react-use-callback-ref" "1.0.0"
+
+"@radix-ui/[email protected]":
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.0.0.tgz#2fc19e97223a81de64cd3ba1dc42ceffd82374dc"
+  integrity sha512-6Tpkq+R6LOlmQb1R5NNETLG0B4YP0wc+klfXafpUCj6JGyaUc8il7/kUZ7m59rGbXGczE9Bs+iz2qloqsZBduQ==
+  dependencies:
+    "@babel/runtime" "^7.13.10"
+
+"@radix-ui/[email protected]":
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/@radix-ui/react-use-previous/-/react-use-previous-1.0.0.tgz#e48a69c3a7d8078a967084038df66d0d181c56ac"
+  integrity sha512-RG2K8z/K7InnOKpq6YLDmT49HGjNmrK+fr82UCVKT2sW0GYfVnYp4wZWBooT/EYfQ5faA9uIjvsuMMhH61rheg==
+  dependencies:
+    "@babel/runtime" "^7.13.10"
+
+"@radix-ui/[email protected]":
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/@radix-ui/react-use-rect/-/react-use-rect-1.0.0.tgz#b040cc88a4906b78696cd3a32b075ed5b1423b3e"
+  integrity sha512-TB7pID8NRMEHxb/qQJpvSt3hQU4sqNPM1VCTjTRjEOa7cEop/QMuq8S6fb/5Tsz64kqSvB9WnwsDHtjnrM9qew==
+  dependencies:
+    "@babel/runtime" "^7.13.10"
+    "@radix-ui/rect" "1.0.0"
+
+"@radix-ui/[email protected]":
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/@radix-ui/react-use-size/-/react-use-size-1.0.0.tgz#a0b455ac826749419f6354dc733e2ca465054771"
+  integrity sha512-imZ3aYcoYCKhhgNpkNDh/aTiU05qw9hX+HHI1QDBTyIlcFjgeFlKKySNGMwTp7nYFLQg/j0VA2FmCY4WPDDHMg==
+  dependencies:
+    "@babel/runtime" "^7.13.10"
+    "@radix-ui/react-use-layout-effect" "1.0.0"
+
+"@radix-ui/[email protected]":
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/@radix-ui/rect/-/rect-1.0.0.tgz#0dc8e6a829ea2828d53cbc94b81793ba6383bf3c"
+  integrity sha512-d0O68AYy/9oeEy1DdC07bz1/ZXX+DqCskRd3i4JzLSTXwefzaepQrKjXC7aNM8lTHjFLDO0pDgaEiQ7jEk+HVg==
+  dependencies:
+    "@babel/runtime" "^7.13.10"
+
+"@swc/helpers@^0.4.12":
+  version "0.4.14"
+  resolved "https://registry.yarnpkg.com/@swc/helpers/-/helpers-0.4.14.tgz#1352ac6d95e3617ccb7c1498ff019654f1e12a74"
+  integrity sha512-4C7nX/dvpzB7za4Ql9K81xK3HPxCpHMgwTZVyf+9JQ6VUbn9jjZVN7/Nkdz/Ugzs2CSjqnL/UPXroiVBVHUWUw==
+  dependencies:
+    tslib "^2.4.0"
+
+"@trysound/[email protected]":
+  version "0.2.0"
+  resolved "https://registry.yarnpkg.com/@trysound/sax/-/sax-0.2.0.tgz#cccaab758af56761eb7bf37af6f03f326dd798ad"
+  integrity sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==
+
+"@turf/along@^6.0.1", "@turf/along@^6.5.0":
+  version "6.5.0"
+  resolved "https://registry.yarnpkg.com/@turf/along/-/along-6.5.0.tgz#ab12eec58a14de60fe243a62d31a474f415c8fef"
+  integrity sha512-LLyWQ0AARqJCmMcIEAXF4GEu8usmd4Kbz3qk1Oy5HoRNpZX47+i5exQtmIWKdqJ1MMhW26fCTXgpsEs5zgJ5gw==
+  dependencies:
+    "@turf/bearing" "^6.5.0"
+    "@turf/destination" "^6.5.0"
+    "@turf/distance" "^6.5.0"
+    "@turf/helpers" "^6.5.0"
+    "@turf/invariant" "^6.5.0"
+
+"@turf/bbox@*":
+  version "6.5.0"
+  resolved "https://registry.yarnpkg.com/@turf/bbox/-/bbox-6.5.0.tgz#bec30a744019eae420dac9ea46fb75caa44d8dc5"
+  integrity sha512-RBbLaao5hXTYyyg577iuMtDB8ehxMlUqHEJiMs8jT1GHkFhr6sYre3lmLsPeYEi/ZKj5TP5tt7fkzNdJ4GIVyw==
+  dependencies:
+    "@turf/helpers" "^6.5.0"
+    "@turf/meta" "^6.5.0"
+
+"@turf/bearing@^6.5.0":
+  version "6.5.0"
+  resolved "https://registry.yarnpkg.com/@turf/bearing/-/bearing-6.5.0.tgz#462a053c6c644434bdb636b39f8f43fb0cd857b0"
+  integrity sha512-dxINYhIEMzgDOztyMZc20I7ssYVNEpSv04VbMo5YPQsqa80KO3TFvbuCahMsCAW5z8Tncc8dwBlEFrmRjJG33A==
+  dependencies:
+    "@turf/helpers" "^6.5.0"
+    "@turf/invariant" "^6.5.0"
+
+"@turf/[email protected]":
+  version "6.5.0"
+  resolved "https://registry.yarnpkg.com/@turf/boolean-clockwise/-/boolean-clockwise-6.5.0.tgz#34573ecc18f900080f00e4ff364631a8b1135794"
+  integrity sha512-45+C7LC5RMbRWrxh3Z0Eihsc8db1VGBO5d9BLTOAwU4jR6SgsunTfRWR16X7JUwIDYlCVEmnjcXJNi/kIU3VIw==
+  dependencies:
+    "@turf/helpers" "^6.5.0"
+    "@turf/invariant" "^6.5.0"
+
+"@turf/circle@^6.0.1", "@turf/circle@^6.5.0":
+  version "6.5.0"
+  resolved "https://registry.yarnpkg.com/@turf/circle/-/circle-6.5.0.tgz#dc017d8c0131d1d212b7c06f76510c22bbeb093c"
+  integrity sha512-oU1+Kq9DgRnoSbWFHKnnUdTmtcRUMmHoV9DjTXu9vOLNV5OWtAAh1VZ+mzsioGGzoDNT/V5igbFOkMfBQc0B6A==
+  dependencies:
+    "@turf/destination" "^6.5.0"
+    "@turf/helpers" "^6.5.0"
+
+"@turf/destination@^6.5.0":
+  version "6.5.0"
+  resolved "https://registry.yarnpkg.com/@turf/destination/-/destination-6.5.0.tgz#30a84702f9677d076130e0440d3223ae503fdae1"
+  integrity sha512-4cnWQlNC8d1tItOz9B4pmJdWpXqS0vEvv65bI/Pj/genJnsL7evI0/Xw42RvEGROS481MPiU80xzvwxEvhQiMQ==
+  dependencies:
+    "@turf/helpers" "^6.5.0"
+    "@turf/invariant" "^6.5.0"
+
+"@turf/distance@^6.0.1", "@turf/distance@^6.5.0":
+  version "6.5.0"
+  resolved "https://registry.yarnpkg.com/@turf/distance/-/distance-6.5.0.tgz#21f04d5f86e864d54e2abde16f35c15b4f36149a"
+  integrity sha512-xzykSLfoURec5qvQJcfifw/1mJa+5UwByZZ5TZ8iaqjGYN0vomhV9aiSLeYdUGtYRESZ+DYC/OzY+4RclZYgMg==
+  dependencies:
+    "@turf/helpers" "^6.5.0"
+    "@turf/invariant" "^6.5.0"
+
+"@turf/[email protected]", "@turf/helpers@^6.1.4", "@turf/helpers@^6.5.0":
+  version "6.5.0"
+  resolved "https://registry.yarnpkg.com/@turf/helpers/-/helpers-6.5.0.tgz#f79af094bd6b8ce7ed2bd3e089a8493ee6cae82e"
+  integrity sha512-VbI1dV5bLFzohYYdgqwikdMVpe7pJ9X3E+dlr425wa2/sMJqYDhTO++ec38/pcPvPE6oD9WEEeU3Xu3gza+VPw==
+
+"@turf/invariant@^6.5.0":
+  version "6.5.0"
+  resolved "https://registry.yarnpkg.com/@turf/invariant/-/invariant-6.5.0.tgz#970afc988023e39c7ccab2341bd06979ddc7463f"
+  integrity sha512-Wv8PRNCtPD31UVbdJE/KVAWKe7l6US+lJItRR/HOEW3eh+U/JwRCSUl/KZ7bmjM/C+zLNoreM2TU6OoLACs4eg==
+  dependencies:
+    "@turf/helpers" "^6.5.0"
+
+"@turf/length@^6.0.2", "@turf/length@^6.5.0":
+  version "6.5.0"
+  resolved "https://registry.yarnpkg.com/@turf/length/-/length-6.5.0.tgz#ff4e9072d5f997e1c32a1311d214d184463f83fa"
+  integrity sha512-5pL5/pnw52fck3oRsHDcSGrj9HibvtlrZ0QNy2OcW8qBFDNgZ4jtl6U7eATVoyWPKBHszW3dWETW+iLV7UARig==
+  dependencies:
+    "@turf/distance" "^6.5.0"
+    "@turf/helpers" "^6.5.0"
+    "@turf/meta" "^6.5.0"
+
+"@turf/line-intersect@^6.5.0":
+  version "6.5.0"
+  resolved "https://registry.yarnpkg.com/@turf/line-intersect/-/line-intersect-6.5.0.tgz#dea48348b30c093715d2195d2dd7524aee4cf020"
+  integrity sha512-CS6R1tZvVQD390G9Ea4pmpM6mJGPWoL82jD46y0q1KSor9s6HupMIo1kY4Ny+AEYQl9jd21V3Scz20eldpbTVA==
+  dependencies:
+    "@turf/helpers" "^6.5.0"
+    "@turf/invariant" "^6.5.0"
+    "@turf/line-segment" "^6.5.0"
+    "@turf/meta" "^6.5.0"
+    geojson-rbush "3.x"
+
+"@turf/line-segment@^6.5.0":
+  version "6.5.0"
+  resolved "https://registry.yarnpkg.com/@turf/line-segment/-/line-segment-6.5.0.tgz#ee73f3ffcb7c956203b64ed966d96af380a4dd65"
+  integrity sha512-jI625Ho4jSuJESNq66Mmi290ZJ5pPZiQZruPVpmHkUw257Pew0alMmb6YrqYNnLUuiVVONxAAKXUVeeUGtycfw==
+  dependencies:
+    "@turf/helpers" "^6.5.0"
+    "@turf/invariant" "^6.5.0"
+    "@turf/meta" "^6.5.0"
+
+"@turf/line-slice@^6.5.0":
+  version "6.5.0"
+  resolved "https://registry.yarnpkg.com/@turf/line-slice/-/line-slice-6.5.0.tgz#7b6e0c8e8e93fdb4e65c3b9a123a2ec93a21bdb0"
+  integrity sha512-vDqJxve9tBHhOaVVFXqVjF5qDzGtKWviyjbyi2QnSnxyFAmLlLnBfMX8TLQCAf2GxHibB95RO5FBE6I2KVPRuw==
+  dependencies:
+    "@turf/helpers" "^6.5.0"
+    "@turf/invariant" "^6.5.0"
+    "@turf/nearest-point-on-line" "^6.5.0"
+
+"@turf/[email protected]", "@turf/meta@^6.5.0":
+  version "6.5.0"
+  resolved "https://registry.yarnpkg.com/@turf/meta/-/meta-6.5.0.tgz#b725c3653c9f432133eaa04d3421f7e51e0418ca"
+  integrity sha512-RrArvtsV0vdsCBegoBtOalgdSOfkBrTJ07VkpiCnq/491W67hnMWmDu7e6Ztw0C3WldRYTXkg3SumfdzZxLBHA==
+  dependencies:
+    "@turf/helpers" "^6.5.0"
+
+"@turf/nearest-point-on-line@^6.5.0":
+  version "6.5.0"
+  resolved "https://registry.yarnpkg.com/@turf/nearest-point-on-line/-/nearest-point-on-line-6.5.0.tgz#8e1cd2cdc0b5acaf4c8d8b3b33bb008d3cb99e7b"
+  integrity sha512-WthrvddddvmymnC+Vf7BrkHGbDOUu6Z3/6bFYUGv1kxw8tiZ6n83/VG6kHz4poHOfS0RaNflzXSkmCi64fLBlg==
+  dependencies:
+    "@turf/bearing" "^6.5.0"
+    "@turf/destination" "^6.5.0"
+    "@turf/distance" "^6.5.0"
+    "@turf/helpers" "^6.5.0"
+    "@turf/invariant" "^6.5.0"
+    "@turf/line-intersect" "^6.5.0"
+    "@turf/meta" "^6.5.0"
+
+"@types/cookie@^0.3.3":
+  version "0.3.3"
+  resolved "https://registry.yarnpkg.com/@types/cookie/-/cookie-0.3.3.tgz#85bc74ba782fb7aa3a514d11767832b0e3bc6803"
+  integrity sha512-LKVP3cgXBT9RYj+t+9FDKwS5tdI+rPBXaNSkma7hvqy35lc7mAokC2zsqWJH0LaqIt3B962nuYI77hsJoT1gow==
+
+"@types/geojson@*", "@types/geojson@^7946.0.8":
+  version "7946.0.10"
+  resolved "https://registry.yarnpkg.com/@types/geojson/-/geojson-7946.0.10.tgz#6dfbf5ea17142f7f9a043809f1cd4c448cb68249"
+  integrity sha512-Nmh0K3iWQJzniTuPRcJn5hxXkfB1T1pgB89SBig5PlJQU5yocazeu4jATJlaA0GYFKWMqDdvYemoSnF2pXgLVA==
+
+"@types/[email protected]":
+  version "7946.0.8"
+  resolved "https://registry.yarnpkg.com/@types/geojson/-/geojson-7946.0.8.tgz#30744afdb385e2945e22f3b033f897f76b1f12ca"
+  integrity sha512-1rkryxURpr6aWP7R786/UQOkJ3PcpQiWkAXBmdWc7ryFWqN6a4xfK7BtjXvFBKO9LjQ+MWQSWxYeZX1OApnArA==
+
+"@types/mapbox-gl@^2.6.0":
+  version "2.7.10"
+  resolved "https://registry.yarnpkg.com/@types/mapbox-gl/-/mapbox-gl-2.7.10.tgz#a3a32a366bad8966c0a40b78209ed430ba018ce1"
+  integrity sha512-nMVEcu9bAcenvx6oPWubQSPevsekByjOfKjlkr+8P91vawtkxTnopDoXXq1Qn/f4cg3zt0Z2W9DVsVsKRNXJTw==
+  dependencies:
+    "@types/geojson" "*"
+
+"@types/mapbox__point-geometry@*", "@types/mapbox__point-geometry@^0.1.2":
+  version "0.1.2"
+  resolved "https://registry.yarnpkg.com/@types/mapbox__point-geometry/-/mapbox__point-geometry-0.1.2.tgz#488a9b76e8457d6792ea2504cdd4ecdd9860a27e"
+  integrity sha512-D0lgCq+3VWV85ey1MZVkE8ZveyuvW5VAfuahVTQRpXFQTxw03SuIf1/K4UQ87MMIXVKzpFjXFiFMZzLj2kU+iA==
+
+"@types/mapbox__vector-tile@^1.3.0":
+  version "1.3.0"
+  resolved "https://registry.yarnpkg.com/@types/mapbox__vector-tile/-/mapbox__vector-tile-1.3.0.tgz#8fa1379dbaead1e1b639b8d96cfd174404c379d6"
+  integrity sha512-kDwVreQO5V4c8yAxzZVQLE5tyWF+IPToAanloQaSnwfXmIcJ7cyOrv8z4Ft4y7PsLYmhWXmON8MBV8RX0Rgr8g==
+  dependencies:
+    "@types/geojson" "*"
+    "@types/mapbox__point-geometry" "*"
+    "@types/pbf" "*"
+
+"@types/parse-json@^4.0.0":
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0"
+  integrity sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==
+
+"@types/pbf@*", "@types/pbf@^3.0.2":
+  version "3.0.2"
+  resolved "https://registry.yarnpkg.com/@types/pbf/-/pbf-3.0.2.tgz#8d291ad68b4b8c533e96c174a2e3e6399a59ed61"
+  integrity sha512-EDrLIPaPXOZqDjrkzxxbX7UlJSeQVgah3i0aA4pOSzmK9zq3BIh7/MZIQxED7slJByvKM4Gc6Hypyu2lJzh3SQ==
+
+"@xstate/[email protected]":
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/@xstate/react/-/react-3.0.0.tgz#888d9a6f128c70b632c18ad55f1f851f6ab092ba"
+  integrity sha512-KHSCfwtb8gZ7QH2luihvmKYI+0lcdHQOmGNRUxUEs4zVgaJCyd8csCEmwPsudpliLdUmyxX2pzUBojFkINpotw==
+  dependencies:
+    use-isomorphic-layout-effect "^1.0.0"
+    use-sync-external-store "^1.0.0"
+
+"@xstate/[email protected]":
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/@xstate/react/-/react-3.0.1.tgz#937eeb5d5d61734ab756ca40146f84a6fe977095"
+  integrity sha512-/tq/gg92P9ke8J+yDNDBv5/PAxBvXJf2cYyGDByzgtl5wKaxKxzDT82Gj3eWlCJXkrBg4J5/V47//gRJuVH2fA==
+  dependencies:
+    use-isomorphic-layout-effect "^1.0.0"
+    use-sync-external-store "^1.0.0"
+
+abortcontroller-polyfill@^1.1.9:
+  version "1.7.5"
+  resolved "https://registry.yarnpkg.com/abortcontroller-polyfill/-/abortcontroller-polyfill-1.7.5.tgz#6738495f4e901fbb57b6c0611d0c75f76c485bed"
+  integrity sha512-JMJ5soJWP18htbbxJjG7bG6yuI6pRhgJ0scHHTfkUjf6wjP912xZWvM+A4sJK3gqd9E8fcPbDnOefbA9Th/FIQ==
+
+acorn@^8.5.0:
+  version "8.8.2"
+  resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.8.2.tgz#1b2f25db02af965399b9776b0c2c391276d37c4a"
+  integrity sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==
+
[email protected]:
+  version "6.1.2"
+  resolved "https://registry.yarnpkg.com/amazon-cognito-identity-js/-/amazon-cognito-identity-js-6.1.2.tgz#975df21b0590098c2d3f455f48dbba255560bbf5"
+  integrity sha512-Ptutf9SLvKEM1Kr2kTPUvu/9THjQ0Si1l80iZYcS8NqScAAiDg8WjOOhQeJPcQDXt3Vym91luZ6zNW/3ErjEdQ==
+  dependencies:
+    "@aws-crypto/sha256-js" "1.2.2"
+    buffer "4.9.2"
+    fast-base64-decode "^1.0.0"
+    isomorphic-unfetch "^3.0.0"
+    js-cookie "^2.2.1"
+
+ansi-regex@^5.0.1:
+  version "5.0.1"
+  resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304"
+  integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==
+
+ansi-styles@^3.2.1:
+  version "3.2.1"
+  resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d"
+  integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==
+  dependencies:
+    color-convert "^1.9.0"
+
+ansi-styles@^4.0.0, ansi-styles@^4.1.0:
+  version "4.3.0"
+  resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937"
+  integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==
+  dependencies:
+    color-convert "^2.0.1"
+
+aria-hidden@^1.1.1:
+  version "1.2.2"
+  resolved "https://registry.yarnpkg.com/aria-hidden/-/aria-hidden-1.2.2.tgz#8c4f7cc88d73ca42114106fdf6f47e68d31475b8"
+  integrity sha512-6y/ogyDTk/7YAe91T3E2PR1ALVKyM2QbTio5HwM+N1Q6CMlCKhvClyIjkckBswa0f2xJhjsfzIGa1yVSe1UMVA==
+  dependencies:
+    tslib "^2.0.0"
+
+aws-amplify-react@^5.1.43:
+  version "5.1.43"
+  resolved "https://registry.yarnpkg.com/aws-amplify-react/-/aws-amplify-react-5.1.43.tgz#aa07b30da2e061fe55959252fc95a5a6726c1a01"
+  integrity sha512-dhetRbT1qLXrH6p30J8VwVz0t/zzMyMopb/ciMSxhuukfgGo8/8dsiIYgABdrvoZojwhlY24M7RHPAMIPva+Vg==
+  dependencies:
+    qrcode.react "^0.8.0"
+    regenerator-runtime "^0.11.1"
+
+aws-amplify@^5.0.15:
+  version "5.0.15"
+  resolved "https://registry.yarnpkg.com/aws-amplify/-/aws-amplify-5.0.15.tgz#bf0e52892f327d36925b744ed2afbe880e5c6cd5"
+  integrity sha512-qIELCzAweJ7hYqbEshkawr2GQbkQeNOGl0ZaVu2slbyOLujYuIhCWOPrzpQkrApt9WIIdJDPqiB12F93PBbmQw==
+  dependencies:
+    "@aws-amplify/analytics" "6.0.15"
+    "@aws-amplify/api" "5.0.15"
+    "@aws-amplify/auth" "5.1.9"
+    "@aws-amplify/cache" "5.0.15"
+    "@aws-amplify/core" "5.0.15"
+    "@aws-amplify/datastore" "4.0.15"
+    "@aws-amplify/geo" "2.0.15"
+    "@aws-amplify/interactions" "5.0.15"
+    "@aws-amplify/notifications" "1.0.15"
+    "@aws-amplify/predictions" "5.0.15"
+    "@aws-amplify/pubsub" "5.0.15"
+    "@aws-amplify/storage" "5.1.5"
+    "@aws-amplify/xr" "4.0.15"
+    tslib "^2.0.0"
+
[email protected]:
+  version "0.26.0"
+  resolved "https://registry.yarnpkg.com/axios/-/axios-0.26.0.tgz#9a318f1c69ec108f8cd5f3c3d390366635e13928"
+  integrity sha512-lKoGLMYtHvFrPVt3r+RBMp9nh34N0M8zEfCWqdWZx6phynIEhQqAdydpyBAAG211zlhX9Rgu08cOamy6XjE5Og==
+  dependencies:
+    follow-redirects "^1.14.8"
+
+balanced-match@^1.0.0:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee"
+  integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==
+
[email protected]:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/base-64/-/base-64-1.0.0.tgz#09d0f2084e32a3fd08c2475b973788eee6ae8f4a"
+  integrity sha512-kwDPIFCGx0NZHog36dj+tHiwP4QMzsZ3AgMViUBKI0+V5n4U0ufTCUMhnQ04diaRI8EX/QcPfql7zlhZ7j4zgg==
+
+base-x@^3.0.8:
+  version "3.0.9"
+  resolved "https://registry.yarnpkg.com/base-x/-/base-x-3.0.9.tgz#6349aaabb58526332de9f60995e548a53fe21320"
+  integrity sha512-H7JU6iBHTal1gp56aKoaa//YUxEaAOUiydvrV/pILqIHXTtqxSkATOnDA2u+jZ/61sD+L/412+7kzXRtWukhpQ==
+  dependencies:
+    safe-buffer "^5.0.1"
+
+base64-js@^1.0.2, base64-js@^1.3.1:
+  version "1.5.1"
+  resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a"
+  integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==
+
+boolbase@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e"
+  integrity sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==
+
+bowser@^2.11.0:
+  version "2.11.0"
+  resolved "https://registry.yarnpkg.com/bowser/-/bowser-2.11.0.tgz#5ca3c35757a7aa5771500c70a73a9f91ef420a8f"
+  integrity sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA==
+
+brace-expansion@^1.1.7:
+  version "1.1.11"
+  resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
+  integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==
+  dependencies:
+    balanced-match "^1.0.0"
+    concat-map "0.0.1"
+
+braces@^3.0.2:
+  version "3.0.2"
+  resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107"
+  integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==
+  dependencies:
+    fill-range "^7.0.1"
+
+browserslist@^4.6.6:
+  version "4.21.5"
+  resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.21.5.tgz#75c5dae60063ee641f977e00edd3cfb2fb7af6a7"
+  integrity sha512-tUkiguQGW7S3IhB7N+c2MV/HZPSCPAAiYBZXLsBhFB/PCy6ZKKsZrmBayHV9fdGV/ARIfJ14NkxKzRDjvp7L6w==
+  dependencies:
+    caniuse-lite "^1.0.30001449"
+    electron-to-chromium "^1.4.284"
+    node-releases "^2.0.8"
+    update-browserslist-db "^1.0.10"
+
+buffer-from@^1.0.0:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5"
+  integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==
+
[email protected]:
+  version "4.9.2"
+  resolved "https://registry.yarnpkg.com/buffer/-/buffer-4.9.2.tgz#230ead344002988644841ab0244af8c44bbe3ef8"
+  integrity sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==
+  dependencies:
+    base64-js "^1.0.2"
+    ieee754 "^1.1.4"
+    isarray "^1.0.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==
+  dependencies:
+    base64-js "^1.3.1"
+    ieee754 "^1.1.13"
+
+callsites@^3.0.0:
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73"
+  integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==
+
+camel-case@^4.1.2:
+  version "4.1.2"
+  resolved "https://registry.yarnpkg.com/camel-case/-/camel-case-4.1.2.tgz#9728072a954f805228225a6deea6b38461e1bd5a"
+  integrity sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==
+  dependencies:
+    pascal-case "^3.1.2"
+    tslib "^2.0.3"
+
[email protected]:
+  version "6.2.2"
+  resolved "https://registry.yarnpkg.com/camelcase-keys/-/camelcase-keys-6.2.2.tgz#5e755d6ba51aa223ec7d3d52f25778210f9dc3c0"
+  integrity sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==
+  dependencies:
+    camelcase "^5.3.1"
+    map-obj "^4.0.0"
+    quick-lru "^4.0.1"
+
+camelcase@^5.0.0, camelcase@^5.3.1:
+  version "5.3.1"
+  resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320"
+  integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==
+
+caniuse-lite@^1.0.30001449:
+  version "1.0.30001457"
+  resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001457.tgz#6af34bb5d720074e2099432aa522c21555a18301"
+  integrity sha512-SDIV6bgE1aVbK6XyxdURbUE89zY7+k1BBBaOwYwkNCglXlel/E7mELiHC64HQ+W0xSKlqWhV9Wh7iHxUjMs4fA==
+
+capital-case@^1.0.4:
+  version "1.0.4"
+  resolved "https://registry.yarnpkg.com/capital-case/-/capital-case-1.0.4.tgz#9d130292353c9249f6b00fa5852bee38a717e669"
+  integrity sha512-ds37W8CytHgwnhGGTi88pcPyR15qoNkOpYwmMMfnWqqWgESapLqvDx6huFjQ5vqWSn2Z06173XNA7LtMOeUh1A==
+  dependencies:
+    no-case "^3.0.4"
+    tslib "^2.0.3"
+    upper-case-first "^2.0.2"
+
+chalk@^2.0.0:
+  version "2.4.2"
+  resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"
+  integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==
+  dependencies:
+    ansi-styles "^3.2.1"
+    escape-string-regexp "^1.0.5"
+    supports-color "^5.3.0"
+
+chalk@^4.0.0, chalk@^4.1.0:
+  version "4.1.2"
+  resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01"
+  integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==
+  dependencies:
+    ansi-styles "^4.1.0"
+    supports-color "^7.1.0"
+
+change-case@^4.1.2:
+  version "4.1.2"
+  resolved "https://registry.yarnpkg.com/change-case/-/change-case-4.1.2.tgz#fedfc5f136045e2398c0410ee441f95704641e12"
+  integrity sha512-bSxY2ws9OtviILG1EiY5K7NNxkqg/JnRnFxLtKQ96JaviiIxi7djMrSd0ECT9AC+lttClmYwKw53BWpOMblo7A==
+  dependencies:
+    camel-case "^4.1.2"
+    capital-case "^1.0.4"
+    constant-case "^3.0.4"
+    dot-case "^3.0.4"
+    header-case "^2.0.4"
+    no-case "^3.0.4"
+    param-case "^3.0.4"
+    pascal-case "^3.1.2"
+    path-case "^3.0.4"
+    sentence-case "^3.0.4"
+    snake-case "^3.0.4"
+    tslib "^2.0.3"
+
+chrome-trace-event@^1.0.2:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz#1015eced4741e15d06664a957dbbf50d041e26ac"
+  integrity sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==
+
[email protected]:
+  version "2.3.1"
+  resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.3.1.tgz#dfcfa3891e306ec1dad105d0e88f4417b8535e8e"
+  integrity sha512-OlQdbZ7gLfGarSqxesMesDa5uz7KFbID8Kpq/SxIoNGDqY8lSYs0D+hhtBXhcdB3rcbXArFr7vlHheLk1voeNA==
+
+cliui@^6.0.0:
+  version "6.0.0"
+  resolved "https://registry.yarnpkg.com/cliui/-/cliui-6.0.0.tgz#511d702c0c4e41ca156d7d0e96021f23e13225b1"
+  integrity sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==
+  dependencies:
+    string-width "^4.2.0"
+    strip-ansi "^6.0.0"
+    wrap-ansi "^6.2.0"
+
+clone@^2.1.1:
+  version "2.1.2"
+  resolved "https://registry.yarnpkg.com/clone/-/clone-2.1.2.tgz#1b7f4b9f591f1e8f83670401600345a02887435f"
+  integrity sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==
+
+color-convert@^1.9.0:
+  version "1.9.3"
+  resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8"
+  integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==
+  dependencies:
+    color-name "1.1.3"
+
+color-convert@^2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3"
+  integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==
+  dependencies:
+    color-name "~1.1.4"
+
[email protected]:
+  version "1.1.3"
+  resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25"
+  integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==
+
+color-name@~1.1.4:
+  version "1.1.4"
+  resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
+  integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
+
+commander@^2.20.0:
+  version "2.20.3"
+  resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33"
+  integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==
+
+commander@^7.0.0, commander@^7.2.0:
+  version "7.2.0"
+  resolved "https://registry.yarnpkg.com/commander/-/commander-7.2.0.tgz#a36cb57d0b501ce108e4d20559a150a391d97ab7"
+  integrity sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==
+
+commander@^8.3.0:
+  version "8.3.0"
+  resolved "https://registry.yarnpkg.com/commander/-/commander-8.3.0.tgz#4837ea1b2da67b9c616a67afbb0fafee567bca66"
+  integrity sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==
+
[email protected]:
+  version "0.0.1"
+  resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
+  integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==
+
+constant-case@^3.0.4:
+  version "3.0.4"
+  resolved "https://registry.yarnpkg.com/constant-case/-/constant-case-3.0.4.tgz#3b84a9aeaf4cf31ec45e6bf5de91bdfb0589faf1"
+  integrity sha512-I2hSBi7Vvs7BEuJDr5dDHfzb/Ruj3FyvFyh7KLilAjNQw3Be+xgqUBA2W6scVEcL0hL1dwPRtIqEPVUCKkSsyQ==
+  dependencies:
+    no-case "^3.0.4"
+    tslib "^2.0.3"
+    upper-case "^2.0.2"
+
+cookie@^0.4.0:
+  version "0.4.2"
+  resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.2.tgz#0e41f24de5ecf317947c82fc789e06a884824432"
+  integrity sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==
+
+cosmiconfig@^7.0.1:
+  version "7.1.0"
+  resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-7.1.0.tgz#1443b9afa596b670082ea46cbd8f6a62b84635f6"
+  integrity sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==
+  dependencies:
+    "@types/parse-json" "^4.0.0"
+    import-fresh "^3.2.1"
+    parse-json "^5.0.0"
+    path-type "^4.0.0"
+    yaml "^1.10.0"
+
+css-select@^4.1.3:
+  version "4.3.0"
+  resolved "https://registry.yarnpkg.com/css-select/-/css-select-4.3.0.tgz#db7129b2846662fd8628cfc496abb2b59e41529b"
+  integrity sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==
+  dependencies:
+    boolbase "^1.0.0"
+    css-what "^6.0.1"
+    domhandler "^4.3.1"
+    domutils "^2.8.0"
+    nth-check "^2.0.1"
+
+css-tree@^1.1.2, css-tree@^1.1.3:
+  version "1.1.3"
+  resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-1.1.3.tgz#eb4870fb6fd7707327ec95c2ff2ab09b5e8db91d"
+  integrity sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==
+  dependencies:
+    mdn-data "2.0.14"
+    source-map "^0.6.1"
+
+css-what@^6.0.1:
+  version "6.1.0"
+  resolved "https://registry.yarnpkg.com/css-what/-/css-what-6.1.0.tgz#fb5effcf76f1ddea2c81bdfaa4de44e79bac70f4"
+  integrity sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==
+
+csscolorparser@~1.0.3:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/csscolorparser/-/csscolorparser-1.0.3.tgz#b34f391eea4da8f3e98231e2ccd8df9c041f171b"
+  integrity sha512-umPSgYwZkdFoUrH5hIq5kf0wPSXiro51nPw0j2K/c83KflkPSTBGMz6NJvMB+07VlL0y7VPo6QJcDjcgKTTm3w==
+
+csso@^4.2.0:
+  version "4.2.0"
+  resolved "https://registry.yarnpkg.com/csso/-/csso-4.2.0.tgz#ea3a561346e8dc9f546d6febedd50187cf389529"
+  integrity sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA==
+  dependencies:
+    css-tree "^1.1.2"
+
+csstype@^3.1.1:
+  version "3.1.1"
+  resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.1.tgz#841b532c45c758ee546a11d5bd7b7b473c8c30b9"
+  integrity sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw==
+
+debounce@^1.2.1:
+  version "1.2.1"
+  resolved "https://registry.yarnpkg.com/debounce/-/debounce-1.2.1.tgz#38881d8f4166a5c5848020c11827b834bcb3e0a5"
+  integrity sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug==
+
+decamelize@^1.2.0:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290"
+  integrity sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==
+
[email protected]:
+  version "4.2.2"
+  resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.2.2.tgz#44d2ea3679b8f4d4ffba33f03d865fc1e7bf4955"
+  integrity sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==
+
+detect-libc@^1.0.3:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b"
+  integrity sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==
+
+detect-node-es@^1.1.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/detect-node-es/-/detect-node-es-1.1.0.tgz#163acdf643330caa0b4cd7c21e7ee7755d6fa493"
+  integrity sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==
+
+dijkstrajs@^1.0.1:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/dijkstrajs/-/dijkstrajs-1.0.2.tgz#2e48c0d3b825462afe75ab4ad5e829c8ece36257"
+  integrity sha512-QV6PMaHTCNmKSeP6QoXhVTw9snc9VD8MulTT0Bd99Pacp4SS1cjcrYPgBPmibqKVtMJJfqC6XvOXgPMEEPH/fg==
+
+dom-serializer@^1.0.1:
+  version "1.4.1"
+  resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-1.4.1.tgz#de5d41b1aea290215dc45a6dae8adcf1d32e2d30"
+  integrity sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==
+  dependencies:
+    domelementtype "^2.0.1"
+    domhandler "^4.2.0"
+    entities "^2.0.0"
+
+domelementtype@^2.0.1, domelementtype@^2.2.0:
+  version "2.3.0"
+  resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-2.3.0.tgz#5c45e8e869952626331d7aab326d01daf65d589d"
+  integrity sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==
+
+domhandler@^4.2.0, domhandler@^4.2.2, domhandler@^4.3.1:
+  version "4.3.1"
+  resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-4.3.1.tgz#8d792033416f59d68bc03a5aa7b018c1ca89279c"
+  integrity sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==
+  dependencies:
+    domelementtype "^2.2.0"
+
+domutils@^2.8.0:
+  version "2.8.0"
+  resolved "https://registry.yarnpkg.com/domutils/-/domutils-2.8.0.tgz#4437def5db6e2d1f5d6ee859bd95ca7d02048135"
+  integrity sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==
+  dependencies:
+    dom-serializer "^1.0.1"
+    domelementtype "^2.2.0"
+    domhandler "^4.2.0"
+
+dot-case@^3.0.4:
+  version "3.0.4"
+  resolved "https://registry.yarnpkg.com/dot-case/-/dot-case-3.0.4.tgz#9b2b670d00a431667a8a75ba29cd1b98809ce751"
+  integrity sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==
+  dependencies:
+    no-case "^3.0.4"
+    tslib "^2.0.3"
+
+dotenv-expand@^5.1.0:
+  version "5.1.0"
+  resolved "https://registry.yarnpkg.com/dotenv-expand/-/dotenv-expand-5.1.0.tgz#3fbaf020bfd794884072ea26b1e9791d45a629f0"
+  integrity sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA==
+
+dotenv@^7.0.0:
+  version "7.0.0"
+  resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-7.0.0.tgz#a2be3cd52736673206e8a85fb5210eea29628e7c"
+  integrity sha512-M3NhsLbV1i6HuGzBUH8vXrtxOk+tWmzWKDMbAVSUp3Zsjm7ywFeuwrUXhmhQyRK1q5B5GGy7hcXPbj3bnfZg2g==
+
+earcut@^2.2.2, earcut@^2.2.3:
+  version "2.2.4"
+  resolved "https://registry.yarnpkg.com/earcut/-/earcut-2.2.4.tgz#6d02fd4d68160c114825d06890a92ecaae60343a"
+  integrity sha512-/pjZsA1b4RPHbeWZQn66SWS8nZZWLQQ23oE3Eam7aroEFGEvwKAsJfZ9ytiEMycfzXWpca4FA9QIOehf7PocBQ==
+
+electron-to-chromium@^1.4.284:
+  version "1.4.304"
+  resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.304.tgz#d6eb7fea4073aacc471cf117df08b4b4978dc6ad"
+  integrity sha512-6c8M+ojPgDIXN2NyfGn8oHASXYnayj+gSEnGeLMKb9zjsySeVB/j7KkNAAG9yDcv8gNlhvFg5REa1N/kQU6pgA==
+
+emoji-regex@^8.0.0:
+  version "8.0.0"
+  resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37"
+  integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==
+
+encode-utf8@^1.0.3:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/encode-utf8/-/encode-utf8-1.0.3.tgz#f30fdd31da07fb596f281beb2f6b027851994cda"
+  integrity sha512-ucAnuBEhUK4boH2HjVYG5Q2mQyPorvv0u/ocS+zhdw0S8AlHYY+GOFhP1Gio5z4icpP2ivFSvhtFjQi8+T9ppw==
+
[email protected], entities@^2.0.0:
+  version "2.2.0"
+  resolved "https://registry.yarnpkg.com/entities/-/entities-2.2.0.tgz#098dc90ebb83d8dffa089d55256b351d34c4da55"
+  integrity sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==
+
+entities@^3.0.1:
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/entities/-/entities-3.0.1.tgz#2b887ca62585e96db3903482d336c1006c3001d4"
+  integrity sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q==
+
+error-ex@^1.3.1:
+  version "1.3.2"
+  resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf"
+  integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==
+  dependencies:
+    is-arrayish "^0.2.1"
+
+escalade@^3.1.1:
+  version "3.1.1"
+  resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40"
+  integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==
+
+escape-string-regexp@^1.0.5:
+  version "1.0.5"
+  resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
+  integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==
+
+events@^3.1.0:
+  version "3.3.0"
+  resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400"
+  integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==
+
+fast-base64-decode@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/fast-base64-decode/-/fast-base64-decode-1.0.0.tgz#b434a0dd7d92b12b43f26819300d2dafb83ee418"
+  integrity sha512-qwaScUgUGBYeDNRnbc/KyllVU88Jk1pRHPStuF/lO7B0/RTRLj7U0lkdTAutlBblY08rwZDff6tNU9cjv6j//Q==
+
[email protected]:
+  version "3.19.0"
+  resolved "https://registry.yarnpkg.com/fast-xml-parser/-/fast-xml-parser-3.19.0.tgz#cb637ec3f3999f51406dd8ff0e6fc4d83e520d01"
+  integrity sha512-4pXwmBplsCPv8FOY1WRakF970TjNGnGnfbOnLqjlYvMiF1SR3yOHyxMR/YCXpPTOspNF5gwudqktIP4VsWkvBg==
+
+fast-xml-parser@^3.16.0:
+  version "3.21.1"
+  resolved "https://registry.yarnpkg.com/fast-xml-parser/-/fast-xml-parser-3.21.1.tgz#152a1d51d445380f7046b304672dd55d15c9e736"
+  integrity sha512-FTFVjYoBOZTJekiUsawGsSYV9QL0A+zDYCRj7y34IO6Jg+2IMYEtQa+bbictpdpV8dHxXywqU7C0gRDEOFtBFg==
+  dependencies:
+    strnum "^1.0.4"
+
[email protected]:
+  version "0.7.3"
+  resolved "https://registry.yarnpkg.com/fflate/-/fflate-0.7.3.tgz#288b034ff0e9c380eaa2feff48c787b8371b7fa5"
+  integrity sha512-0Zz1jOzJWERhyhsimS54VTqOteCNwRtIlh8isdL0AXLo0g7xNTfTL7oWrkmCnPhZGocKIkWHBistBrrpoNH3aw==
+
+fill-range@^7.0.1:
+  version "7.0.1"
+  resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40"
+  integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==
+  dependencies:
+    to-regex-range "^5.0.1"
+
+find-up@^4.1.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"
+
+follow-redirects@^1.14.8:
+  version "1.15.2"
+  resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.2.tgz#b460864144ba63f2681096f274c4e57026da2c13"
+  integrity sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==
+
+fs-extra@^10.0.0:
+  version "10.1.0"
+  resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-10.1.0.tgz#02873cfbc4084dde127eaa5f9905eef2325d1abf"
+  integrity sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==
+  dependencies:
+    graceful-fs "^4.2.0"
+    jsonfile "^6.0.1"
+    universalify "^2.0.0"
+
+fs.realpath@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
+  integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==
+
+fuzzy@^0.1.1:
+  version "0.1.3"
+  resolved "https://registry.yarnpkg.com/fuzzy/-/fuzzy-0.1.3.tgz#4c76ec2ff0ac1a36a9dccf9a00df8623078d4ed8"
+  integrity sha512-/gZffu4ykarLrCiP3Ygsa86UAo1E5vEVlvTrpkKywXSbP9Xhln3oSp9QSV57gEq3JFFpGJ4GZ+5zdEp3FcUh4w==
+
+geojson-flatten@^1.0.4:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/geojson-flatten/-/geojson-flatten-1.1.1.tgz#601aae07ba6406281ebca683573dcda69eba04c7"
+  integrity sha512-k/6BCd0qAt7vdqdM1LkLfAy72EsLDy0laNwX0x2h49vfYCiQkRc4PSra8DNEdJ10EKRpwEvDXMb0dBknTJuWpQ==
+
[email protected]:
+  version "3.2.0"
+  resolved "https://registry.yarnpkg.com/geojson-rbush/-/geojson-rbush-3.2.0.tgz#8b543cf0d56f99b78faf1da52bb66acad6dfc290"
+  integrity sha512-oVltQTXolxvsz1sZnutlSuLDEcQAKYC/uXt9zDzJJ6bu0W+baTI8LZBaTup5afzibEH4N3jlq2p+a152wlBJ7w==
+  dependencies:
+    "@turf/bbox" "*"
+    "@turf/helpers" "6.x"
+    "@turf/meta" "6.x"
+    "@types/geojson" "7946.0.8"
+    rbush "^3.0.1"
+
+geojson-vt@^3.2.1:
+  version "3.2.1"
+  resolved "https://registry.yarnpkg.com/geojson-vt/-/geojson-vt-3.2.1.tgz#f8adb614d2c1d3f6ee7c4265cad4bbf3ad60c8b7"
+  integrity sha512-EvGQQi/zPrDA6zr6BnJD/YhwAkBP8nnJ9emh3EnHQKVMfg/MRVtPbMYdgVy/IaEmn4UfagD2a6fafPDL5hbtwg==
+
+get-caller-file@^2.0.1:
+  version "2.0.5"
+  resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e"
+  integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==
+
+get-nonce@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/get-nonce/-/get-nonce-1.0.1.tgz#fdf3f0278073820d2ce9426c18f07481b1e0cdf3"
+  integrity sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==
+
+get-port@^4.2.0:
+  version "4.2.0"
+  resolved "https://registry.yarnpkg.com/get-port/-/get-port-4.2.0.tgz#e37368b1e863b7629c43c5a323625f95cf24b119"
+  integrity sha512-/b3jarXkH8KJoOMQc3uVGHASwGLPq3gSFJ7tgJm2diza+bydJPTGOibin2steecKeOylE8oY2JERlVWkAJO6yw==
+
+get-stream@^6.0.1:
+  version "6.0.1"
+  resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7"
+  integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==
+
+gl-matrix@^3.2.1, gl-matrix@^3.4.3:
+  version "3.4.3"
+  resolved "https://registry.yarnpkg.com/gl-matrix/-/gl-matrix-3.4.3.tgz#fc1191e8320009fd4d20e9339595c6041ddc22c9"
+  integrity sha512-wcCp8vu8FT22BnvKVPjXa/ICBWRq/zjFfdofZy1WSpQZpphblv12/bOQLBC1rMM7SGOFS9ltVmKOHil5+Ml7gA==
+
+glob@^7.2.0:
+  version "7.2.3"
+  resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b"
+  integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==
+  dependencies:
+    fs.realpath "^1.0.0"
+    inflight "^1.0.4"
+    inherits "2"
+    minimatch "^3.1.1"
+    once "^1.3.0"
+    path-is-absolute "^1.0.0"
+
+globals@^13.2.0:
+  version "13.20.0"
+  resolved "https://registry.yarnpkg.com/globals/-/globals-13.20.0.tgz#ea276a1e508ffd4f1612888f9d1bad1e2717bf82"
+  integrity sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==
+  dependencies:
+    type-fest "^0.20.2"
+
+graceful-fs@^4.1.6, graceful-fs@^4.2.0:
+  version "4.2.10"
+  resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.10.tgz#147d3a006da4ca3ce14728c7aefc287c367d7a6c"
+  integrity sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==
+
[email protected]:
+  version "15.8.0"
+  resolved "https://registry.yarnpkg.com/graphql/-/graphql-15.8.0.tgz#33410e96b012fa3bdb1091cc99a94769db212b38"
+  integrity sha512-5gghUc24tP9HRznNpV2+FIoq3xKkj5dTQqf4v0CpdPbFVwFkWoxOM+o+2OC9ZSvjEMTjfmG9QT+gcvggTwW1zw==
+
+grid-index@^1.1.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/grid-index/-/grid-index-1.1.0.tgz#97f8221edec1026c8377b86446a7c71e79522ea7"
+  integrity sha512-HZRwumpOGUrHyxO5bqKZL0B0GlUpwtCAzZ42sgxUPniu33R1LSFH5yrIcBCHjkctCAh3mtWKcKd9J4vDDdeVHA==
+
+has-flag@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd"
+  integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==
+
+has-flag@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b"
+  integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==
+
[email protected]:
+  version "0.0.3"
+  resolved "https://registry.yarnpkg.com/hat/-/hat-0.0.3.tgz#bb014a9e64b3788aed8005917413d4ff3d502d8a"
+  integrity sha512-zpImx2GoKXy42fVDSEad2BPKuSQdLcqsCYa48K3zHSzM/ugWuYjLDr8IXxpVuL7uCLHw56eaiLxCRthhOzf5ug==
+
+header-case@^2.0.4:
+  version "2.0.4"
+  resolved "https://registry.yarnpkg.com/header-case/-/header-case-2.0.4.tgz#5a42e63b55177349cf405beb8d775acabb92c063"
+  integrity sha512-H/vuk5TEEVZwrR0lp2zed9OCo1uAILMlx0JEMgC26rzyJJ3N1v6XkwHHXJQdR2doSjcGPM6OKPYoJgf0plJ11Q==
+  dependencies:
+    capital-case "^1.0.4"
+    tslib "^2.0.3"
+
+htmlnano@^2.0.0:
+  version "2.0.3"
+  resolved "https://registry.yarnpkg.com/htmlnano/-/htmlnano-2.0.3.tgz#50ee639ed63357d4a6c01309f52a35892e4edc2e"
+  integrity sha512-S4PGGj9RbdgW8LhbILNK7W9JhmYP8zmDY7KDV/8eCiJBQJlbmltp5I0gv8c5ntLljfdxxfmJ+UJVSqyH4mb41A==
+  dependencies:
+    cosmiconfig "^7.0.1"
+    posthtml "^0.16.5"
+    timsort "^0.3.0"
+
+htmlparser2@^7.1.1:
+  version "7.2.0"
+  resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-7.2.0.tgz#8817cdea38bbc324392a90b1990908e81a65f5a5"
+  integrity sha512-H7MImA4MS6cw7nbyURtLPO1Tms7C5H602LRETv95z1MxO/7CP7rDVROehUYeYBUYEON94NXXDEPmZuq+hX4sog==
+  dependencies:
+    domelementtype "^2.0.1"
+    domhandler "^4.2.2"
+    domutils "^2.8.0"
+    entities "^3.0.1"
+
[email protected]:
+  version "5.0.6"
+  resolved "https://registry.yarnpkg.com/idb/-/idb-5.0.6.tgz#8c94624f5a8a026abe3bef3c7166a5febd1cadc1"
+  integrity sha512-/PFvOWPzRcEPmlDt5jEvzVZVs0wyd/EvGvkDIcbBpGuMMLQKrTPG0TxvE2UJtgZtCQCmOtM2QD7yQJBVEjKGOw==
+
+ieee754@^1.1.12, ieee754@^1.1.13, ieee754@^1.1.4:
+  version "1.2.1"
+  resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352"
+  integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==
+
[email protected]:
+  version "9.0.6"
+  resolved "https://registry.yarnpkg.com/immer/-/immer-9.0.6.tgz#7a96bf2674d06c8143e327cbf73539388ddf1a73"
+  integrity sha512-G95ivKpy+EvVAnAab4fVa4YGYn24J1SpEktnJX7JJ45Bd7xqME/SCplFzYFmTbrkwZbQ4xJK1xMTUYBkN6pWsQ==
+
+import-fresh@^3.2.1:
+  version "3.3.0"
+  resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b"
+  integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==
+  dependencies:
+    parent-module "^1.0.0"
+    resolve-from "^4.0.0"
+
+inflight@^1.0.4:
+  version "1.0.6"
+  resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
+  integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==
+  dependencies:
+    once "^1.3.0"
+    wrappy "1"
+
+inherits@2:
+  version "2.0.4"
+  resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
+  integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
+
+invariant@^2.2.4:
+  version "2.2.4"
+  resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6"
+  integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==
+  dependencies:
+    loose-envify "^1.0.0"
+
+is-arrayish@^0.2.1:
+  version "0.2.1"
+  resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d"
+  integrity sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==
+
+is-extglob@^2.1.1:
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2"
+  integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==
+
+is-fullwidth-code-point@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d"
+  integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==
+
+is-glob@^4.0.3:
+  version "4.0.3"
+  resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084"
+  integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==
+  dependencies:
+    is-extglob "^2.1.1"
+
+is-json@^2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/is-json/-/is-json-2.0.1.tgz#6be166d144828a131d686891b983df62c39491ff"
+  integrity sha512-6BEnpVn1rcf3ngfmViLM6vjUjGErbdrL4rwlv+u1NO1XO8kqT4YGL8+19Q+Z/bas8tY90BTWMk2+fW1g6hQjbA==
+
+is-number@^7.0.0:
+  version "7.0.0"
+  resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b"
+  integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==
+
+isarray@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
+  integrity sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==
+
+isomorphic-unfetch@^3.0.0:
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/isomorphic-unfetch/-/isomorphic-unfetch-3.1.0.tgz#87341d5f4f7b63843d468438128cb087b7c3e98f"
+  integrity sha512-geDJjpoZ8N0kWexiwkX8F9NkTsXhetLPVbZFQ+JTW239QNOwvB0gniuR1Wc6f0AMTn7/mFGyXvHTifrCp/GH8Q==
+  dependencies:
+    node-fetch "^2.6.1"
+    unfetch "^4.2.0"
+
+js-cookie@^2.2.1:
+  version "2.2.1"
+  resolved "https://registry.yarnpkg.com/js-cookie/-/js-cookie-2.2.1.tgz#69e106dc5d5806894562902aa5baec3744e9b2b8"
+  integrity sha512-HvdH2LzI/EAZcUwA8+0nKNtWHqS+ZmijLA30RwZA0bo7ToCckjK5MkGhjED9KoRcXO6BaGI3I9UIzSA1FKFPOQ==
+
+"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
+  integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==
+
+json-parse-even-better-errors@^2.3.0:
+  version "2.3.1"
+  resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d"
+  integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==
+
+json5@^2.2.0, json5@^2.2.1:
+  version "2.2.3"
+  resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283"
+  integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==
+
+jsonc-parser@^3.0.0:
+  version "3.2.0"
+  resolved "https://registry.yarnpkg.com/jsonc-parser/-/jsonc-parser-3.2.0.tgz#31ff3f4c2b9793f89c67212627c51c6394f88e76"
+  integrity sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==
+
+jsonfile@^6.0.1:
+  version "6.1.0"
+  resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.1.0.tgz#bc55b2634793c679ec6403094eb13698a6ec0aae"
+  integrity sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==
+  dependencies:
+    universalify "^2.0.0"
+  optionalDependencies:
+    graceful-fs "^4.1.6"
+
+kdbush@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/kdbush/-/kdbush-3.0.0.tgz#f8484794d47004cc2d85ed3a79353dbe0abc2bf0"
+  integrity sha512-hRkd6/XW4HTsA9vjVpY9tuXJYLSlelnkTmVFu4M9/7MIYQtFcHpbugAU7UbOfjOiVSVYl2fqgBuJ32JUmRo5Ew==
+
[email protected]:
+  version "1.19.0"
+  resolved "https://registry.yarnpkg.com/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.19.0.tgz#56ab071e932f845dbb7667f44f5b78441175a343"
+  integrity sha512-wIJmFtYX0rXHsXHSr4+sC5clwblEMji7HHQ4Ub1/CznVRxtCFha6JIt5JZaNf8vQrfdZnBxLLC6R8pC818jXqg==
+
[email protected]:
+  version "1.19.0"
+  resolved "https://registry.yarnpkg.com/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.19.0.tgz#c867308b88859ba61a2c46c82b1ca52ff73a1bd0"
+  integrity sha512-Lif1wD6P4poaw9c/4Uh2z+gmrWhw/HtXFoeZ3bEsv6Ia4tt8rOJBdkfVaUJ6VXmpKHALve+iTyP2+50xY1wKPw==
+
[email protected]:
+  version "1.19.0"
+  resolved "https://registry.yarnpkg.com/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.19.0.tgz#0f921dc45f2e5c3aea70fab98844ac0e5f2f81be"
+  integrity sha512-P15VXY5682mTXaiDtbnLYQflc8BYb774j2R84FgDLJTN6Qp0ZjWEFyN1SPqyfTj2B2TFjRHRUvQSSZ7qN4Weig==
+
[email protected]:
+  version "1.19.0"
+  resolved "https://registry.yarnpkg.com/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.19.0.tgz#027f9df9c7f4ffa127c37a71726245a5794d7ba2"
+  integrity sha512-zwXRjWqpev8wqO0sv0M1aM1PpjHz6RVIsBcxKszIG83Befuh4yNysjgHVplF9RTU7eozGe3Ts7r6we1+Qkqsww==
+
[email protected]:
+  version "1.19.0"
+  resolved "https://registry.yarnpkg.com/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.19.0.tgz#85ea987da868524eac6db94f8e1eaa23d0b688a3"
+  integrity sha512-vSCKO7SDnZaFN9zEloKSZM5/kC5gbzUjoJQ43BvUpyTFUX7ACs/mDfl2Eq6fdz2+uWhUh7vf92c4EaaP4udEtA==
+
[email protected]:
+  version "1.19.0"
+  resolved "https://registry.yarnpkg.com/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.19.0.tgz#02bec89579ab4153dccc0def755d1fd9e3ee7f3c"
+  integrity sha512-0AFQKvVzXf9byrXUq9z0anMGLdZJS+XSDqidyijI5njIwj6MdbvX2UZK/c4FfNmeRa2N/8ngTffoIuOUit5eIQ==
+
[email protected]:
+  version "1.19.0"
+  resolved "https://registry.yarnpkg.com/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.19.0.tgz#e36a5df8193ae961d22974635e4c100a1823bb8c"
+  integrity sha512-SJoM8CLPt6ECCgSuWe+g0qo8dqQYVcPiW2s19dxkmSI5+Uu1GIRzyKA0b7QqmEXolA+oSJhQqCmJpzjY4CuZAg==
+
[email protected]:
+  version "1.19.0"
+  resolved "https://registry.yarnpkg.com/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.19.0.tgz#0854dbd153035eca1396e2227c708ad43655a61c"
+  integrity sha512-C+VuUTeSUOAaBZZOPT7Etn/agx/MatzJzGRkeV+zEABmPuntv1zihncsi+AyGmjkkzq3wVedEy7h0/4S84mUtg==
+
+lightningcss@^1.16.1:
+  version "1.19.0"
+  resolved "https://registry.yarnpkg.com/lightningcss/-/lightningcss-1.19.0.tgz#fbbad0975de66252e38d96b5bdd2a62f2dd0ffbf"
+  integrity sha512-yV5UR7og+Og7lQC+70DA7a8ta1uiOPnWPJfxa0wnxylev5qfo4P+4iMpzWAdYWOca4jdNQZii+bDL/l+4hUXIA==
+  dependencies:
+    detect-libc "^1.0.3"
+  optionalDependencies:
+    lightningcss-darwin-arm64 "1.19.0"
+    lightningcss-darwin-x64 "1.19.0"
+    lightningcss-linux-arm-gnueabihf "1.19.0"
+    lightningcss-linux-arm64-gnu "1.19.0"
+    lightningcss-linux-arm64-musl "1.19.0"
+    lightningcss-linux-x64-gnu "1.19.0"
+    lightningcss-linux-x64-musl "1.19.0"
+    lightningcss-win32-x64-msvc "1.19.0"
+
+lines-and-columns@^1.1.6:
+  version "1.2.4"
+  resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632"
+  integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==
+
[email protected]:
+  version "2.5.2"
+  resolved "https://registry.yarnpkg.com/lmdb/-/lmdb-2.5.2.tgz#37e28a9fb43405f4dc48c44cec0e13a14c4a6ff1"
+  integrity sha512-V5V5Xa2Hp9i2XsbDALkBTeHXnBXh/lEmk9p22zdr7jtuOIY9TGhjK6vAvTpOOx9IKU4hJkRWZxn/HsvR1ELLtA==
+  dependencies:
+    msgpackr "^1.5.4"
+    node-addon-api "^4.3.0"
+    node-gyp-build-optional-packages "5.0.3"
+    ordered-binary "^1.2.4"
+    weak-lru-cache "^1.2.2"
+  optionalDependencies:
+    "@lmdb/lmdb-darwin-arm64" "2.5.2"
+    "@lmdb/lmdb-darwin-x64" "2.5.2"
+    "@lmdb/lmdb-linux-arm" "2.5.2"
+    "@lmdb/lmdb-linux-arm64" "2.5.2"
+    "@lmdb/lmdb-linux-x64" "2.5.2"
+    "@lmdb/lmdb-win32-x64" "2.5.2"
+
+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.debounce@^4.0.6:
+  version "4.0.8"
+  resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af"
+  integrity sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==
+
+lodash.isequal@^4.5.0:
+  version "4.5.0"
+  resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0"
+  integrity sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==
+
[email protected], lodash@^4.17.15, lodash@^4.17.20, lodash@^4.17.21:
+  version "4.17.21"
+  resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
+  integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
+
+loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.4.0:
+  version "1.4.0"
+  resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf"
+  integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==
+  dependencies:
+    js-tokens "^3.0.0 || ^4.0.0"
+
+lower-case@^2.0.2:
+  version "2.0.2"
+  resolved "https://registry.yarnpkg.com/lower-case/-/lower-case-2.0.2.tgz#6fa237c63dbdc4a82ca0fd882e4722dc5e634e28"
+  integrity sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==
+  dependencies:
+    tslib "^2.0.3"
+
+map-obj@^4.0.0:
+  version "4.3.0"
+  resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-4.3.0.tgz#9304f906e93faae70880da102a9f1df0ea8bb05a"
+  integrity sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==
+
[email protected]:
+  version "1.13.1"
+  resolved "https://registry.yarnpkg.com/mapbox-gl/-/mapbox-gl-1.13.1.tgz#322efe75ab4c764fc4c776da1506aad58d5a5b9d"
+  integrity sha512-GSyubcoSF5MyaP8z+DasLu5v7KmDK2pp4S5+VQ5WdVQUOaAqQY4jwl4JpcdNho3uWm2bIKs7x1l7q3ynGmW60g==
+  dependencies:
+    "@mapbox/geojson-rewind" "^0.5.0"
+    "@mapbox/geojson-types" "^1.0.2"
+    "@mapbox/jsonlint-lines-primitives" "^2.0.2"
+    "@mapbox/mapbox-gl-supported" "^1.5.0"
+    "@mapbox/point-geometry" "^0.1.0"
+    "@mapbox/tiny-sdf" "^1.1.1"
+    "@mapbox/unitbezier" "^0.0.0"
+    "@mapbox/vector-tile" "^1.3.1"
+    "@mapbox/whoots-js" "^3.1.0"
+    csscolorparser "~1.0.3"
+    earcut "^2.2.2"
+    geojson-vt "^3.2.1"
+    gl-matrix "^3.2.1"
+    grid-index "^1.1.0"
+    minimist "^1.2.5"
+    murmurhash-js "^1.0.0"
+    pbf "^3.2.1"
+    potpack "^1.0.1"
+    quickselect "^2.0.0"
+    rw "^1.3.3"
+    supercluster "^7.1.0"
+    tinyqueue "^2.0.3"
+    vt-pbf "^3.1.1"
+
+maplibre-gl-draw-circle@^0.1.1:
+  version "0.1.1"
+  resolved "https://registry.yarnpkg.com/maplibre-gl-draw-circle/-/maplibre-gl-draw-circle-0.1.1.tgz#2b3ff6433c0b82dfc63b3ea555d8074492150180"
+  integrity sha512-CGdPcoTj9nWHn0Pa37tCoIyVKnN3AozWZjF2C64jnoWw1yzV4tOsUm+VWPbRRotJVKFQoEKHL8/5EjuS1FNiXQ==
+  dependencies:
+    "@mapbox/mapbox-gl-draw" "1.3.0"
+    "@turf/along" "^6.0.1"
+    "@turf/circle" "^6.0.1"
+    "@turf/distance" "^6.0.1"
+    "@turf/helpers" "^6.1.4"
+    "@turf/length" "^6.0.2"
+
[email protected]:
+  version "3.0.2"
+  resolved "https://registry.yarnpkg.com/maplibre-gl-js-amplify/-/maplibre-gl-js-amplify-3.0.2.tgz#ccb7f97e4ec31ca0c0dc287b11fb739d45131f86"
+  integrity sha512-zCnpB6jPKvROLa45yqNkliffrHWu6Z2hZCLVk098/BeWEJjU54eBTxEgezGkIKdD/qPTohq6tf9t/6SEWYsOQA==
+  dependencies:
+    "@mapbox/mapbox-gl-draw" "^1.3.0"
+    "@maplibre/maplibre-gl-geocoder" "^1.5.0"
+    "@turf/along" "^6.5.0"
+    "@turf/circle" "^6.5.0"
+    "@turf/distance" "^6.5.0"
+    "@turf/helpers" "^6.5.0"
+    "@turf/length" "^6.5.0"
+    "@turf/line-slice" "^6.5.0"
+    debounce "^1.2.1"
+    maplibre-gl-draw-circle "^0.1.1"
+
[email protected]:
+  version "2.1.9"
+  resolved "https://registry.yarnpkg.com/maplibre-gl/-/maplibre-gl-2.1.9.tgz#042f3ef4224fa890ecf7a410145243f1fc943dcd"
+  integrity sha512-pnWJmILeZpgA5QSI7K7xFK3yrkyYTd9srw3fCi2Ca52Phm78hsznPwUErEQcZLfxXKn/1h9t8IPdj0TH0NBNbg==
+  dependencies:
+    "@mapbox/geojson-rewind" "^0.5.1"
+    "@mapbox/jsonlint-lines-primitives" "^2.0.2"
+    "@mapbox/mapbox-gl-supported" "^2.0.1"
+    "@mapbox/point-geometry" "^0.1.0"
+    "@mapbox/tiny-sdf" "^2.0.4"
+    "@mapbox/unitbezier" "^0.0.1"
+    "@mapbox/vector-tile" "^1.3.1"
+    "@mapbox/whoots-js" "^3.1.0"
+    "@types/geojson" "^7946.0.8"
+    "@types/mapbox__point-geometry" "^0.1.2"
+    "@types/mapbox__vector-tile" "^1.3.0"
+    "@types/pbf" "^3.0.2"
+    csscolorparser "~1.0.3"
+    earcut "^2.2.3"
+    geojson-vt "^3.2.1"
+    gl-matrix "^3.4.3"
+    murmurhash-js "^1.0.0"
+    pbf "^3.2.1"
+    potpack "^1.0.2"
+    quickselect "^2.0.0"
+    supercluster "^7.1.4"
+    tinyqueue "^2.0.3"
+    vt-pbf "^3.1.3"
+
[email protected]:
+  version "2.0.14"
+  resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.14.tgz#7113fc4281917d63ce29b43446f701e68c25ba50"
+  integrity sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==
+
+micromatch@^4.0.5:
+  version "4.0.5"
+  resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6"
+  integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==
+  dependencies:
+    braces "^3.0.2"
+    picomatch "^2.3.1"
+
+minimatch@^3.1.1:
+  version "3.1.2"
+  resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b"
+  integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==
+  dependencies:
+    brace-expansion "^1.1.7"
+
+minimist@^1.2.5, minimist@^1.2.6:
+  version "1.2.8"
+  resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c"
+  integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==
+
+msgpackr-extract@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/msgpackr-extract/-/msgpackr-extract-3.0.0.tgz#5b5c5fbfff25be5ee5b5a82a9cbe02e37f72bed0"
+  integrity sha512-oy6KCk1+X4Bn5m6Ycq5N1EWl9npqG/cLrE8ga8NX7ZqfqYUUBS08beCQaGq80fjbKBySur0E6x//yZjzNJDt3A==
+  dependencies:
+    node-gyp-build-optional-packages "5.0.7"
+  optionalDependencies:
+    "@msgpackr-extract/msgpackr-extract-darwin-arm64" "3.0.0"
+    "@msgpackr-extract/msgpackr-extract-darwin-x64" "3.0.0"
+    "@msgpackr-extract/msgpackr-extract-linux-arm" "3.0.0"
+    "@msgpackr-extract/msgpackr-extract-linux-arm64" "3.0.0"
+    "@msgpackr-extract/msgpackr-extract-linux-x64" "3.0.0"
+    "@msgpackr-extract/msgpackr-extract-win32-x64" "3.0.0"
+
+msgpackr@^1.5.4:
+  version "1.8.3"
+  resolved "https://registry.yarnpkg.com/msgpackr/-/msgpackr-1.8.3.tgz#78c1b91359f72707f4abeaca40cc423bd2d75185"
+  integrity sha512-m2JefwcKNzoHYXkH/5jzHRxAw7XLWsAdvu0FOJ+OLwwozwOV/J6UA62iLkfIMbg7G8+dIuRwgg6oz+QoQ4YkoA==
+  optionalDependencies:
+    msgpackr-extract "^3.0.0"
+
+murmurhash-js@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/murmurhash-js/-/murmurhash-js-1.0.0.tgz#b06278e21fc6c37fa5313732b0412bcb6ae15f51"
+  integrity sha512-TvmkNhkv8yct0SVBSy+o8wYzXjE4Zz3PCesbfs8HiCXXdcTuocApFv11UWlNFWKYsP2okqrhb7JNlSm9InBhIw==
+
+no-case@^3.0.4:
+  version "3.0.4"
+  resolved "https://registry.yarnpkg.com/no-case/-/no-case-3.0.4.tgz#d361fd5c9800f558551a8369fc0dcd4662b6124d"
+  integrity sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==
+  dependencies:
+    lower-case "^2.0.2"
+    tslib "^2.0.3"
+
+node-addon-api@^3.2.1:
+  version "3.2.1"
+  resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-3.2.1.tgz#81325e0a2117789c0128dab65e7e38f07ceba161"
+  integrity sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A==
+
+node-addon-api@^4.3.0:
+  version "4.3.0"
+  resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-4.3.0.tgz#52a1a0b475193e0928e98e0426a0d1254782b77f"
+  integrity sha512-73sE9+3UaLYYFmDsFZnqCInzPyh3MqIwZO9cw58yIqAZhONrrabrYyYe3TuIqtIiOuTXVhsGau8hcrhhwSsDIQ==
+
+node-fetch@^2.6.1:
+  version "2.6.9"
+  resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.9.tgz#7c7f744b5cc6eb5fd404e0c7a9fec630a55657e6"
+  integrity sha512-DJm/CJkZkRjKKj4Zi4BsKVZh3ValV5IR5s7LVZnW+6YMh0W1BfNA8XSs6DLMGYlId5F3KnA70uu2qepcR08Qqg==
+  dependencies:
+    whatwg-url "^5.0.0"
+
[email protected]:
+  version "5.0.3"
+  resolved "https://registry.yarnpkg.com/node-gyp-build-optional-packages/-/node-gyp-build-optional-packages-5.0.3.tgz#92a89d400352c44ad3975010368072b41ad66c17"
+  integrity sha512-k75jcVzk5wnnc/FMxsf4udAoTEUv2jY3ycfdSd3yWu6Cnd1oee6/CfZJApyscA4FJOmdoixWwiwOyf16RzD5JA==
+
[email protected]:
+  version "5.0.7"
+  resolved "https://registry.yarnpkg.com/node-gyp-build-optional-packages/-/node-gyp-build-optional-packages-5.0.7.tgz#5d2632bbde0ab2f6e22f1bbac2199b07244ae0b3"
+  integrity sha512-YlCCc6Wffkx0kHkmam79GKvDQ6x+QZkMjFGrIMxgFNILFvGSbCp2fCBC55pGTT9gVaz8Na5CLmxt/urtzRv36w==
+
+node-gyp-build@^4.3.0:
+  version "4.6.0"
+  resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.6.0.tgz#0c52e4cbf54bbd28b709820ef7b6a3c2d6209055"
+  integrity sha512-NTZVKn9IylLwUzaKjkas1e4u2DLNcV4rdYagA4PWdPwW87Bi7z+BznyKSRwS/761tV/lzCGXplWsiaMjLqP2zQ==
+
+node-releases@^2.0.8:
+  version "2.0.10"
+  resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.10.tgz#c311ebae3b6a148c89b1813fd7c4d3c024ef537f"
+  integrity sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w==
+
+nth-check@^2.0.1:
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-2.1.1.tgz#c9eab428effce36cd6b92c924bdb000ef1f1ed1d"
+  integrity sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==
+  dependencies:
+    boolbase "^1.0.0"
+
+nullthrows@^1.1.1:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/nullthrows/-/nullthrows-1.1.1.tgz#7818258843856ae971eae4208ad7d7eb19a431b1"
+  integrity sha512-2vPPEi+Z7WqML2jZYddDIfy5Dqb0r2fze2zTxNNknZaFpVHU3mFB3R+DWeJWGVx0ecvttSGlJTI+WG+8Z4cDWw==
+
+object-assign@^4.1.1:
+  version "4.1.1"
+  resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
+  integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==
+
+once@^1.3.0:
+  version "1.4.0"
+  resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
+  integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==
+  dependencies:
+    wrappy "1"
+
+ordered-binary@^1.2.4:
+  version "1.4.0"
+  resolved "https://registry.yarnpkg.com/ordered-binary/-/ordered-binary-1.4.0.tgz#6bb53d44925f3b8afc33d1eed0fa15693b211389"
+  integrity sha512-EHQ/jk4/a9hLupIKxTfUsQRej1Yd/0QLQs3vGvIqg5ZtCYSzNhkzHoZc7Zf4e4kUlDaC3Uw8Q/1opOLNN2OKRQ==
+
+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-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==
+
+paho-mqtt@^1.1.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/paho-mqtt/-/paho-mqtt-1.1.0.tgz#8c10e29eb162e966fb15188d965c3dce505de9d9"
+  integrity sha512-KPbL9KAB0ASvhSDbOrZBaccXS+/s7/LIofbPyERww8hM5Ko71GUJQ6Nmg0BWqj8phAIT8zdf/Sd/RftHU9i2HA==
+
[email protected]:
+  version "2.0.4"
+  resolved "https://registry.yarnpkg.com/pako/-/pako-2.0.4.tgz#6cebc4bbb0b6c73b0d5b8d7e8476e2b2fbea576d"
+  integrity sha512-v8tweI900AUkZN6heMU/4Uy4cXRc2AYNRggVmTR+dEncawDJgCdLMximOVA2p4qO57WMynangsfGRb5WD6L1Bg==
+
+param-case@^3.0.4:
+  version "3.0.4"
+  resolved "https://registry.yarnpkg.com/param-case/-/param-case-3.0.4.tgz#7d17fe4aa12bde34d4a77d91acfb6219caad01c5"
+  integrity sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==
+  dependencies:
+    dot-case "^3.0.4"
+    tslib "^2.0.3"
+
+parcel@^2.8.3:
+  version "2.8.3"
+  resolved "https://registry.yarnpkg.com/parcel/-/parcel-2.8.3.tgz#1ff71d7317274fd367379bc7310a52c6b75d30c2"
+  integrity sha512-5rMBpbNE72g6jZvkdR5gS2nyhwIXaJy8i65osOqs/+5b7zgf3eMKgjSsDrv6bhz3gzifsba6MBJiZdBckl+vnA==
+  dependencies:
+    "@parcel/config-default" "2.8.3"
+    "@parcel/core" "2.8.3"
+    "@parcel/diagnostic" "2.8.3"
+    "@parcel/events" "2.8.3"
+    "@parcel/fs" "2.8.3"
+    "@parcel/logger" "2.8.3"
+    "@parcel/package-manager" "2.8.3"
+    "@parcel/reporter-cli" "2.8.3"
+    "@parcel/reporter-dev-server" "2.8.3"
+    "@parcel/utils" "2.8.3"
+    chalk "^4.1.0"
+    commander "^7.0.0"
+    get-port "^4.2.0"
+    v8-compile-cache "^2.0.0"
+
+parent-module@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2"
+  integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==
+  dependencies:
+    callsites "^3.0.0"
+
+parse-json@^5.0.0:
+  version "5.2.0"
+  resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd"
+  integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==
+  dependencies:
+    "@babel/code-frame" "^7.0.0"
+    error-ex "^1.3.1"
+    json-parse-even-better-errors "^2.3.0"
+    lines-and-columns "^1.1.6"
+
+pascal-case@^3.1.2:
+  version "3.1.2"
+  resolved "https://registry.yarnpkg.com/pascal-case/-/pascal-case-3.1.2.tgz#b48e0ef2b98e205e7c1dae747d0b1508237660eb"
+  integrity sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==
+  dependencies:
+    no-case "^3.0.4"
+    tslib "^2.0.3"
+
+path-case@^3.0.4:
+  version "3.0.4"
+  resolved "https://registry.yarnpkg.com/path-case/-/path-case-3.0.4.tgz#9168645334eb942658375c56f80b4c0cb5f82c6f"
+  integrity sha512-qO4qCFjXqVTrcbPt/hQfhTQ+VhFsqNKOPtytgNKkKxSoEp3XPUQ8ObFuePylOIok5gjn69ry8XiULxCwot3Wfg==
+  dependencies:
+    dot-case "^3.0.4"
+    tslib "^2.0.3"
+
+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"
+  integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==
+
+path-type@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b"
+  integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==
+
+pbf@^3.2.1:
+  version "3.2.1"
+  resolved "https://registry.yarnpkg.com/pbf/-/pbf-3.2.1.tgz#b4c1b9e72af966cd82c6531691115cc0409ffe2a"
+  integrity sha512-ClrV7pNOn7rtmoQVF4TS1vyU0WhYRnP92fzbfF75jAIwpnzdJXf8iTd4CMEqO4yUenH6NDqLiwjqlh6QgZzgLQ==
+  dependencies:
+    ieee754 "^1.1.12"
+    resolve-protobuf-schema "^2.1.0"
+
+picocolors@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c"
+  integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==
+
+picomatch@^2.3.1:
+  version "2.3.1"
+  resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42"
+  integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==
+
+pngjs@^5.0.0:
+  version "5.0.0"
+  resolved "https://registry.yarnpkg.com/pngjs/-/pngjs-5.0.0.tgz#e79dd2b215767fd9c04561c01236df960bce7fbb"
+  integrity sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw==
+
+postcss-value-parser@^4.2.0:
+  version "4.2.0"
+  resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz#723c09920836ba6d3e5af019f92bc0971c02e514"
+  integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==
+
+posthtml-parser@^0.10.1:
+  version "0.10.2"
+  resolved "https://registry.yarnpkg.com/posthtml-parser/-/posthtml-parser-0.10.2.tgz#df364d7b179f2a6bf0466b56be7b98fd4e97c573"
+  integrity sha512-PId6zZ/2lyJi9LiKfe+i2xv57oEjJgWbsHGGANwos5AvdQp98i6AtamAl8gzSVFGfQ43Glb5D614cvZf012VKg==
+  dependencies:
+    htmlparser2 "^7.1.1"
+
+posthtml-parser@^0.11.0:
+  version "0.11.0"
+  resolved "https://registry.yarnpkg.com/posthtml-parser/-/posthtml-parser-0.11.0.tgz#25d1c7bf811ea83559bc4c21c189a29747a24b7a"
+  integrity sha512-QecJtfLekJbWVo/dMAA+OSwY79wpRmbqS5TeXvXSX+f0c6pW4/SE6inzZ2qkU7oAMCPqIDkZDvd/bQsSFUnKyw==
+  dependencies:
+    htmlparser2 "^7.1.1"
+
+posthtml-render@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/posthtml-render/-/posthtml-render-3.0.0.tgz#97be44931496f495b4f07b99e903cc70ad6a3205"
+  integrity sha512-z+16RoxK3fUPgwaIgH9NGnK1HKY9XIDpydky5eQGgAFVXTCSezalv9U2jQuNV+Z9qV1fDWNzldcw4eK0SSbqKA==
+  dependencies:
+    is-json "^2.0.1"
+
+posthtml@^0.16.4, posthtml@^0.16.5:
+  version "0.16.6"
+  resolved "https://registry.yarnpkg.com/posthtml/-/posthtml-0.16.6.tgz#e2fc407f67a64d2fa3567afe770409ffdadafe59"
+  integrity sha512-JcEmHlyLK/o0uGAlj65vgg+7LIms0xKXe60lcDOTU7oVX/3LuEuLwrQpW3VJ7de5TaFKiW4kWkaIpJL42FEgxQ==
+  dependencies:
+    posthtml-parser "^0.11.0"
+    posthtml-render "^3.0.0"
+
+potpack@^1.0.1, potpack@^1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/potpack/-/potpack-1.0.2.tgz#23b99e64eb74f5741ffe7656b5b5c4ddce8dfc14"
+  integrity sha512-choctRBIV9EMT9WGAZHn3V7t0Z2pMQyl0EZE6pFc/6ml3ssw7Dlf/oAOvFwjm1HVsqfQN8GfeFyJ+d8tRzqueQ==
+
+prop-types@^15.6.0:
+  version "15.8.1"
+  resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5"
+  integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==
+  dependencies:
+    loose-envify "^1.4.0"
+    object-assign "^4.1.1"
+    react-is "^16.13.1"
+
+protocol-buffers-schema@^3.3.1:
+  version "3.6.0"
+  resolved "https://registry.yarnpkg.com/protocol-buffers-schema/-/protocol-buffers-schema-3.6.0.tgz#77bc75a48b2ff142c1ad5b5b90c94cd0fa2efd03"
+  integrity sha512-TdDRD+/QNdrCGCE7v8340QyuXd4kIWIgapsE2+n/SaGiSSbomYl4TjHlvIoCWRpE7wFt02EpB35VVA2ImcBVqw==
+
[email protected]:
+  version "1.3.2"
+  resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d"
+  integrity sha512-RofWgt/7fL5wP1Y7fxE7/EmTLzQVnB0ycyibJ0OOHIlJqTNzglYFxVwETOcIoJqJmpDXJ9xImDv+Fq34F/d4Dw==
+
+punycode@^1.4.1:
+  version "1.4.1"
+  resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e"
+  integrity sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==
+
[email protected]:
+  version "0.0.0"
+  resolved "https://registry.yarnpkg.com/qr.js/-/qr.js-0.0.0.tgz#cace86386f59a0db8050fa90d9b6b0e88a1e364f"
+  integrity sha512-c4iYnWb+k2E+vYpRimHqSu575b1/wKl4XFeJGpFmrJQz5I88v9aY2czh7s0w36srfCM1sXgC/xpoJz5dJfq+OQ==
+
+qrcode.react@^0.8.0:
+  version "0.8.0"
+  resolved "https://registry.yarnpkg.com/qrcode.react/-/qrcode.react-0.8.0.tgz#413b31cc3b62910e39513f7bead945e01c4c34fb"
+  integrity sha512-16wKpuFvLwciIq2YAsfmPUCnSR8GrYPsXRK5KVdcIuX0+W/MKZbBkFhl44ttRx4TWZHqRjfztoWOxdPF0Hb9JA==
+  dependencies:
+    prop-types "^15.6.0"
+    qr.js "0.0.0"
+
[email protected]:
+  version "1.5.0"
+  resolved "https://registry.yarnpkg.com/qrcode/-/qrcode-1.5.0.tgz#95abb8a91fdafd86f8190f2836abbfc500c72d1b"
+  integrity sha512-9MgRpgVc+/+47dFvQeD6U2s0Z92EsKzcHogtum4QB+UNd025WOJSHvn/hjk9xmzj7Stj95CyUAs31mrjxliEsQ==
+  dependencies:
+    dijkstrajs "^1.0.1"
+    encode-utf8 "^1.0.3"
+    pngjs "^5.0.0"
+    yargs "^15.3.1"
+
[email protected]:
+  version "0.2.0"
+  resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620"
+  integrity sha512-X/xY82scca2tau62i9mDyU9K+I+djTMUsvwf7xnUX5GLvVzgJybOJf4Y6o9Zx3oJK/LSXg5tTZBjwzqVPaPO2g==
+
+quick-lru@^4.0.1:
+  version "4.0.1"
+  resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-4.0.1.tgz#5b8878f113a58217848c6482026c73e1ba57727f"
+  integrity sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==
+
+quickselect@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/quickselect/-/quickselect-2.0.0.tgz#f19680a486a5eefb581303e023e98faaf25dd018"
+  integrity sha512-RKJ22hX8mHe3Y6wH/N3wCM6BWtjaxIyyUIkpHOvfFnxdI4yD4tBXEBKSbriGujF6jnSVkJrffuo6vxACiSSxIw==
+
+rbush@^3.0.1:
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/rbush/-/rbush-3.0.1.tgz#5fafa8a79b3b9afdfe5008403a720cc1de882ecf"
+  integrity sha512-XRaVO0YecOpEuIvbhbpTrZgoiI6xBlz6hnlr6EHhd+0x9ase6EmeN+hdwwUaJvLcsFFQ8iWVF1GAK1yB0BWi0w==
+  dependencies:
+    quickselect "^2.0.0"
+
+react-dom@^17:
+  version "17.0.2"
+  resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-17.0.2.tgz#ecffb6845e3ad8dbfcdc498f0d0a939736502c23"
+  integrity sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==
+  dependencies:
+    loose-envify "^1.1.0"
+    object-assign "^4.1.1"
+    scheduler "^0.20.2"
+
[email protected]:
+  version "6.0.9"
+  resolved "https://registry.yarnpkg.com/react-error-overlay/-/react-error-overlay-6.0.9.tgz#3c743010c9359608c375ecd6bc76f35d93995b0a"
+  integrity sha512-nQTTcUu+ATDbrSD1BZHr5kgSD4oF8OFjxun8uAaL8RwPBacGBNPf/yAuVVdx17N8XNzRDMrZ9XcKZHCjPW+9ew==
+
[email protected]:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/react-generate-context/-/react-generate-context-1.0.1.tgz#4454cfecb0b3f27502185dfa5c63d5f5ec14b936"
+  integrity sha512-rOFGh3KgC2Ot66DmVCcT1p8lVJCmmCjzGE5WK/KsyDFi43wpIbW1PYcr04cQ3mbF4LaIkY6SpK7k1DOgwtpUXA==
+
+react-is@^16.13.1:
+  version "16.13.1"
+  resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
+  integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==
+
[email protected]:
+  version "7.0.15"
+  resolved "https://registry.yarnpkg.com/react-map-gl/-/react-map-gl-7.0.15.tgz#ded08ccff49012099a9945b6c2ef7f266dfbde49"
+  integrity sha512-l7x8lBhIEcHTreSgrc7hsKv5HsMY1wQg2PVXuKAPmQtgRZc9C3NGwurVJFe24gOlAwzta5UavAHWDiZdU1ZNCw==
+  dependencies:
+    "@types/mapbox-gl" "^2.6.0"
+
+react-native-get-random-values@^1.4.0:
+  version "1.8.0"
+  resolved "https://registry.yarnpkg.com/react-native-get-random-values/-/react-native-get-random-values-1.8.0.tgz#1cb4bd4bd3966a356e59697b8f372999fe97cb16"
+  integrity sha512-H/zghhun0T+UIJLmig3+ZuBCvF66rdbiWUfRSNS6kv5oDSpa1ZiVyvRWtuPesQpT8dXj+Bv7WJRQOUP+5TB1sA==
+  dependencies:
+    fast-base64-decode "^1.0.0"
+
+react-refresh@^0.9.0:
+  version "0.9.0"
+  resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.9.0.tgz#71863337adc3e5c2f8a6bfddd12ae3bfe32aafbf"
+  integrity sha512-Gvzk7OZpiqKSkxsQvO/mbTN1poglhmAV7gR/DdIrRrSMXraRQQlfikRJOr3Nb9GTMPC5kof948Zy6jJZIFtDvQ==
+
+react-remove-scroll-bar@^2.3.3:
+  version "2.3.4"
+  resolved "https://registry.yarnpkg.com/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.4.tgz#53e272d7a5cb8242990c7f144c44d8bd8ab5afd9"
+  integrity sha512-63C4YQBUt0m6ALadE9XV56hV8BgJWDmmTPY758iIJjfQKt2nYwoUrPk0LXRXcB/yIj82T1/Ixfdpdk68LwIB0A==
+  dependencies:
+    react-style-singleton "^2.2.1"
+    tslib "^2.0.0"
+
[email protected]:
+  version "2.5.4"
+  resolved "https://registry.yarnpkg.com/react-remove-scroll/-/react-remove-scroll-2.5.4.tgz#afe6491acabde26f628f844b67647645488d2ea0"
+  integrity sha512-xGVKJJr0SJGQVirVFAUZ2k1QLyO6m+2fy0l8Qawbp5Jgrv3DeLalrfMNBFSlmz5kriGGzsVBtGVnf4pTKIhhWA==
+  dependencies:
+    react-remove-scroll-bar "^2.3.3"
+    react-style-singleton "^2.2.1"
+    tslib "^2.1.0"
+    use-callback-ref "^1.3.0"
+    use-sidecar "^1.1.2"
+
+react-style-singleton@^2.2.1:
+  version "2.2.1"
+  resolved "https://registry.yarnpkg.com/react-style-singleton/-/react-style-singleton-2.2.1.tgz#f99e420492b2d8f34d38308ff660b60d0b1205b4"
+  integrity sha512-ZWj0fHEMyWkHzKYUr2Bs/4zU6XLmq9HsgBURm7g5pAVfyn49DgUiNgY2d4lXRlYSiCif9YBGpQleewkcqddc7g==
+  dependencies:
+    get-nonce "^1.0.0"
+    invariant "^2.2.4"
+    tslib "^2.0.0"
+
+react@^17:
+  version "17.0.2"
+  resolved "https://registry.yarnpkg.com/react/-/react-17.0.2.tgz#d0b5cc516d29eb3eee383f75b62864cfb6800037"
+  integrity sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==
+  dependencies:
+    loose-envify "^1.1.0"
+    object-assign "^4.1.1"
+
+regenerator-runtime@^0.11.1:
+  version "0.11.1"
+  resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9"
+  integrity sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==
+
+regenerator-runtime@^0.13.11, regenerator-runtime@^0.13.7:
+  version "0.13.11"
+  resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz#f6dca3e7ceec20590d07ada785636a90cdca17f9"
+  integrity sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==
+
+require-directory@^2.1.1:
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42"
+  integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==
+
+require-main-filename@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b"
+  integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==
+
+resolve-from@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6"
+  integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==
+
+resolve-protobuf-schema@^2.1.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/resolve-protobuf-schema/-/resolve-protobuf-schema-2.1.0.tgz#9ca9a9e69cf192bbdaf1006ec1973948aa4a3758"
+  integrity sha512-kI5ffTiZWmJaS/huM8wZfEMer1eRd7oJQhDuxeCLe3t7N7mX3z94CN0xPxBQxFYQTSNz9T0i+v6inKqSdK8xrQ==
+  dependencies:
+    protocol-buffers-schema "^3.3.1"
+
+rw@^1.3.3:
+  version "1.3.3"
+  resolved "https://registry.yarnpkg.com/rw/-/rw-1.3.3.tgz#3f862dfa91ab766b14885ef4d01124bfda074fb4"
+  integrity sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==
+
+rw@~0.1.4:
+  version "0.1.4"
+  resolved "https://registry.yarnpkg.com/rw/-/rw-0.1.4.tgz#4903cbd80248ae0ede685bf58fd236a7a9b29a3e"
+  integrity sha512-vSj3D96kMcjNyqPcp65wBRIDImGSrUuMxngNNxvw8MQaO+aQ6llzRPH7XcJy5zrpb3wU++045+Uz/IDIM684iw==
+
+safe-buffer@^5.0.1:
+  version "5.2.1"
+  resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6"
+  integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==
+
+scheduler@^0.20.2:
+  version "0.20.2"
+  resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.20.2.tgz#4baee39436e34aa93b4874bddcbf0fe8b8b50e91"
+  integrity sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ==
+  dependencies:
+    loose-envify "^1.1.0"
+    object-assign "^4.1.1"
+
+semver@^5.7.0, semver@^5.7.1:
+  version "5.7.1"
+  resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7"
+  integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==
+
+sentence-case@^3.0.4:
+  version "3.0.4"
+  resolved "https://registry.yarnpkg.com/sentence-case/-/sentence-case-3.0.4.tgz#3645a7b8c117c787fde8702056225bb62a45131f"
+  integrity sha512-8LS0JInaQMCRoQ7YUytAo/xUu5W2XnQxV2HI/6uM6U7CITS1RqPElr30V6uIqyMKM9lJGRVFy5/4CuzcixNYSg==
+  dependencies:
+    no-case "^3.0.4"
+    tslib "^2.0.3"
+    upper-case-first "^2.0.2"
+
+set-blocking@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7"
+  integrity sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==
+
+snake-case@^3.0.4:
+  version "3.0.4"
+  resolved "https://registry.yarnpkg.com/snake-case/-/snake-case-3.0.4.tgz#4f2bbd568e9935abdfd593f34c691dadb49c452c"
+  integrity sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg==
+  dependencies:
+    dot-case "^3.0.4"
+    tslib "^2.0.3"
+
+source-map-support@~0.5.20:
+  version "0.5.21"
+  resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f"
+  integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==
+  dependencies:
+    buffer-from "^1.0.0"
+    source-map "^0.6.0"
+
+source-map@^0.6.0, source-map@^0.6.1:
+  version "0.6.1"
+  resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"
+  integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==
+
+srcset@4:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/srcset/-/srcset-4.0.0.tgz#336816b665b14cd013ba545b6fe62357f86e65f4"
+  integrity sha512-wvLeHgcVHKO8Sc/H/5lkGreJQVeYMm9rlmt8PuR1xE31rIuXhuzznUUqAt8MqLhB3MqJdFzlNAfpcWnxiFUcPw==
+
+stable@^0.1.8:
+  version "0.1.8"
+  resolved "https://registry.yarnpkg.com/stable/-/stable-0.1.8.tgz#836eb3c8382fe2936feaf544631017ce7d47a3cf"
+  integrity sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==
+
+string-width@^4.1.0, string-width@^4.2.0:
+  version "4.2.3"
+  resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
+  integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
+  dependencies:
+    emoji-regex "^8.0.0"
+    is-fullwidth-code-point "^3.0.0"
+    strip-ansi "^6.0.1"
+
+strip-ansi@^6.0.0, strip-ansi@^6.0.1:
+  version "6.0.1"
+  resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
+  integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
+  dependencies:
+    ansi-regex "^5.0.1"
+
+strnum@^1.0.4:
+  version "1.0.5"
+  resolved "https://registry.yarnpkg.com/strnum/-/strnum-1.0.5.tgz#5c4e829fe15ad4ff0d20c3db5ac97b73c9b072db"
+  integrity sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==
+
[email protected]:
+  version "3.7.1"
+  resolved "https://registry.yarnpkg.com/style-dictionary/-/style-dictionary-3.7.1.tgz#d61c980513d7bb0a1946a9fab31491a672d0f6a2"
+  integrity sha512-yYU9Z/J8Znj9T9oJVjo8VOYamrOxv0UbBKPjhSt+PharxrhyQCM4RWb71fgEfv2pK9KO8G83/0ChDNQZ1mn0wQ==
+  dependencies:
+    chalk "^4.0.0"
+    change-case "^4.1.2"
+    commander "^8.3.0"
+    fs-extra "^10.0.0"
+    glob "^7.2.0"
+    json5 "^2.2.0"
+    jsonc-parser "^3.0.0"
+    lodash "^4.17.15"
+    tinycolor2 "^1.4.1"
+
+subtag@^0.5.0:
+  version "0.5.0"
+  resolved "https://registry.yarnpkg.com/subtag/-/subtag-0.5.0.tgz#1728a8df5257fb98ded4fb981b2ac7af10cf58ba"
+  integrity sha512-CaIBcTSb/nyk4xiiSOtZYz1B+F12ZxW8NEp54CdT+84vmh/h4sUnHGC6+KQXUfED8u22PQjCYWfZny8d2ELXwg==
+
+suggestions-list@^0.0.2:
+  version "0.0.2"
+  resolved "https://registry.yarnpkg.com/suggestions-list/-/suggestions-list-0.0.2.tgz#3c5f501833e697a726a1bf58fbc454d57ffa0e98"
+  integrity sha512-Yw0fdq14c6RQWQIfE1/8WEi9Dp8rjyCD6FhYA/Tit2/ADbE9Y4ADG4ezlvivsa8Civ5nz++pyVVBMjOMlgIUJw==
+  dependencies:
+    fuzzy "^0.1.1"
+    xtend "^4.0.0"
+
+supercluster@^7.1.0, supercluster@^7.1.4:
+  version "7.1.5"
+  resolved "https://registry.yarnpkg.com/supercluster/-/supercluster-7.1.5.tgz#65a6ce4a037a972767740614c19051b64b8be5a3"
+  integrity sha512-EulshI3pGUM66o6ZdH3ReiFcvHpM3vAigyK+vcxdjpJyEbIIrtbmBdY23mGgnI24uXiGFvrGq9Gkum/8U7vJWg==
+  dependencies:
+    kdbush "^3.0.0"
+
+supports-color@^5.3.0:
+  version "5.5.0"
+  resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f"
+  integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==
+  dependencies:
+    has-flag "^3.0.0"
+
+supports-color@^7.1.0:
+  version "7.2.0"
+  resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da"
+  integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==
+  dependencies:
+    has-flag "^4.0.0"
+
+svgo@^2.4.0:
+  version "2.8.0"
+  resolved "https://registry.yarnpkg.com/svgo/-/svgo-2.8.0.tgz#4ff80cce6710dc2795f0c7c74101e6764cfccd24"
+  integrity sha512-+N/Q9kV1+F+UeWYoSiULYo4xYSDQlTgb+ayMobAXPwMnLvop7oxKMo9OzIrX5x3eS4L4f2UHhc9axXwY8DpChg==
+  dependencies:
+    "@trysound/sax" "0.2.0"
+    commander "^7.2.0"
+    css-select "^4.1.3"
+    css-tree "^1.1.3"
+    csso "^4.2.0"
+    picocolors "^1.0.0"
+    stable "^0.1.8"
+
+term-size@^2.2.1:
+  version "2.2.1"
+  resolved "https://registry.yarnpkg.com/term-size/-/term-size-2.2.1.tgz#2a6a54840432c2fb6320fea0f415531e90189f54"
+  integrity sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg==
+
+terser@^5.2.0:
+  version "5.16.4"
+  resolved "https://registry.yarnpkg.com/terser/-/terser-5.16.4.tgz#51284b440b93242291a98f2a9903c024cfb70e6e"
+  integrity sha512-5yEGuZ3DZradbogeYQ1NaGz7rXVBDWujWlx1PT8efXO6Txn+eWbfKqB2bTDVmFXmePFkoLU6XI8UektMIEA0ug==
+  dependencies:
+    "@jridgewell/source-map" "^0.3.2"
+    acorn "^8.5.0"
+    commander "^2.20.0"
+    source-map-support "~0.5.20"
+
+timsort@^0.3.0:
+  version "0.3.0"
+  resolved "https://registry.yarnpkg.com/timsort/-/timsort-0.3.0.tgz#405411a8e7e6339fe64db9a234de11dc31e02bd4"
+  integrity sha512-qsdtZH+vMoCARQtyod4imc2nIJwg9Cc7lPRrw9CzF8ZKR0khdr8+2nX80PBhET3tcyTtJDxAffGh2rXH4tyU8A==
+
[email protected]:
+  version "1.4.2"
+  resolved "https://registry.yarnpkg.com/tinycolor2/-/tinycolor2-1.4.2.tgz#3f6a4d1071ad07676d7fa472e1fac40a719d8803"
+  integrity sha512-vJhccZPs965sV/L2sU4oRQVAos0pQXwsvTLkWYdqJ+a8Q5kPFzJTuOFwy7UniPli44NKQGAglksjvOcpo95aZA==
+
+tinycolor2@^1.4.1:
+  version "1.6.0"
+  resolved "https://registry.yarnpkg.com/tinycolor2/-/tinycolor2-1.6.0.tgz#f98007460169b0263b97072c5ae92484ce02d09e"
+  integrity sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw==
+
+tinyqueue@^2.0.3:
+  version "2.0.3"
+  resolved "https://registry.yarnpkg.com/tinyqueue/-/tinyqueue-2.0.3.tgz#64d8492ebf39e7801d7bd34062e29b45b2035f08"
+  integrity sha512-ppJZNDuKGgxzkHihX8v9v9G5f+18gzaTfrukGrq6ueg0lmH4nqVnA2IPG0AEH3jKEk2GRJCUhDoqpoiw3PHLBA==
+
+to-regex-range@^5.0.1:
+  version "5.0.1"
+  resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4"
+  integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==
+  dependencies:
+    is-number "^7.0.0"
+
+tr46@~0.0.3:
+  version "0.0.3"
+  resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a"
+  integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==
+
+traverse@~0.6.6:
+  version "0.6.7"
+  resolved "https://registry.yarnpkg.com/traverse/-/traverse-0.6.7.tgz#46961cd2d57dd8706c36664acde06a248f1173fe"
+  integrity sha512-/y956gpUo9ZNCb99YjxG7OaslxZWHfCHAUUfshwqOXmxUIvqLjVO581BT+gM59+QV9tFe6/CGG53tsA1Y7RSdg==
+
[email protected]:
+  version "2.4.1"
+  resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.1.tgz#0d0bfbaac2880b91e22df0768e55be9753a5b17e"
+  integrity sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==
+
+tslib@^1.11.1, tslib@^1.8.0, 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==
+
+tslib@^2.0.0, tslib@^2.0.3, tslib@^2.1.0, tslib@^2.3.1, tslib@^2.4.0:
+  version "2.5.0"
+  resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.5.0.tgz#42bfed86f5787aeb41d031866c8f402429e0fddf"
+  integrity sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==
+
+type-fest@^0.20.2:
+  version "0.20.2"
+  resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4"
+  integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==
+
[email protected]:
+  version "2.3.0"
+  resolved "https://registry.yarnpkg.com/ulid/-/ulid-2.3.0.tgz#93063522771a9774121a84d126ecd3eb9804071f"
+  integrity sha512-keqHubrlpvT6G2wH0OEfSW4mquYRcbe/J8NMmveoQOjUqmo+hXtO+ORCpWhdbZ7k72UtY61BL7haGxW6enBnjw==
+
+unfetch@^4.2.0:
+  version "4.2.0"
+  resolved "https://registry.yarnpkg.com/unfetch/-/unfetch-4.2.0.tgz#7e21b0ef7d363d8d9af0fb929a5555f6ef97a3be"
+  integrity sha512-F9p7yYCn6cIW9El1zi0HI6vqpeIvBsr3dSuRO6Xuppb1u5rXpCPmMvLSyECLhybr9isec8Ohl0hPekMVrEinDA==
+
+universal-cookie@^4.0.4:
+  version "4.0.4"
+  resolved "https://registry.yarnpkg.com/universal-cookie/-/universal-cookie-4.0.4.tgz#06e8b3625bf9af049569ef97109b4bb226ad798d"
+  integrity sha512-lbRVHoOMtItjWbM7TwDLdl8wug7izB0tq3/YVKhT/ahB4VDvWMyvnADfnJI8y6fSvsjh51Ix7lTGC6Tn4rMPhw==
+  dependencies:
+    "@types/cookie" "^0.3.3"
+    cookie "^0.4.0"
+
+universalify@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.0.tgz#75a4984efedc4b08975c5aeb73f530d02df25717"
+  integrity sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==
+
+update-browserslist-db@^1.0.10:
+  version "1.0.10"
+  resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz#0f54b876545726f17d00cd9a2561e6dade943ff3"
+  integrity sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==
+  dependencies:
+    escalade "^3.1.1"
+    picocolors "^1.0.0"
+
+upper-case-first@^2.0.2:
+  version "2.0.2"
+  resolved "https://registry.yarnpkg.com/upper-case-first/-/upper-case-first-2.0.2.tgz#992c3273f882abd19d1e02894cc147117f844324"
+  integrity sha512-514ppYHBaKwfJRK/pNC6c/OxfGa0obSnAl106u97Ed0I625Nin96KAjttZF6ZL3e1XLtphxnqrOi9iWgm+u+bg==
+  dependencies:
+    tslib "^2.0.3"
+
+upper-case@^2.0.2:
+  version "2.0.2"
+  resolved "https://registry.yarnpkg.com/upper-case/-/upper-case-2.0.2.tgz#d89810823faab1df1549b7d97a76f8662bae6f7a"
+  integrity sha512-KgdgDGJt2TpuwBUIjgG6lzw2GWFRCW9Qkfkiv0DxqHHLYJHmtmdUIKcZd8rHgFSjopVTlw6ggzCm1b8MFQwikg==
+  dependencies:
+    tslib "^2.0.3"
+
+url@^0.11.0:
+  version "0.11.0"
+  resolved "https://registry.yarnpkg.com/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1"
+  integrity sha512-kbailJa29QrtXnxgq+DdCEGlbTeYM2eJUxsz6vjZavrCYPMIFHMKQmSKYAIuUK2i7hgPm28a8piX5NTUtM/LKQ==
+  dependencies:
+    punycode "1.3.2"
+    querystring "0.2.0"
+
+use-callback-ref@^1.3.0:
+  version "1.3.0"
+  resolved "https://registry.yarnpkg.com/use-callback-ref/-/use-callback-ref-1.3.0.tgz#772199899b9c9a50526fedc4993fc7fa1f7e32d5"
+  integrity sha512-3FT9PRuRdbB9HfXhEq35u4oZkvpJ5kuYbpqhCfmiZyReuRgpnhDlbr2ZEnnuS0RrJAPn6l23xjFg9kpDM+Ms7w==
+  dependencies:
+    tslib "^2.0.0"
+
+use-isomorphic-layout-effect@^1.0.0, use-isomorphic-layout-effect@^1.1.1:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.1.2.tgz#497cefb13d863d687b08477d9e5a164ad8c1a6fb"
+  integrity sha512-49L8yCO3iGT/ZF9QttjwLF/ZD9Iwto5LnH5LmEdk/6cFmXddqi2ulF0edxTwjj+7mqvpVVGQWvbXZdn32wRSHA==
+
+use-sidecar@^1.1.2:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/use-sidecar/-/use-sidecar-1.1.2.tgz#2f43126ba2d7d7e117aa5855e5d8f0276dfe73c2"
+  integrity sha512-epTbsLuzZ7lPClpz2TyryBfztm7m+28DlEv2ZCQ3MDr5ssiwyOwGH/e5F9CkfWjJ1t4clvI58yF822/GUkjjhw==
+  dependencies:
+    detect-node-es "^1.1.0"
+    tslib "^2.0.0"
+
+use-sync-external-store@^1.0.0:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz#7dbefd6ef3fe4e767a0cf5d7287aacfb5846928a"
+  integrity sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==
+
+utility-types@^3.10.0:
+  version "3.10.0"
+  resolved "https://registry.yarnpkg.com/utility-types/-/utility-types-3.10.0.tgz#ea4148f9a741015f05ed74fd615e1d20e6bed82b"
+  integrity sha512-O11mqxmi7wMKCo6HKFt5AhO4BwY3VV68YU07tgxfz8zJTIxr4BpsezN49Ffwy9j3ZpwwJp4fkRwjRzq3uWE6Rg==
+
[email protected], uuid@^3.0.0, uuid@^3.2.1:
+  version "3.4.0"
+  resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee"
+  integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==
+
+uuid@^8.3.2:
+  version "8.3.2"
+  resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2"
+  integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==
+
+v8-compile-cache@^2.0.0:
+  version "2.3.0"
+  resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee"
+  integrity sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==
+
+vt-pbf@^3.1.1, vt-pbf@^3.1.3:
+  version "3.1.3"
+  resolved "https://registry.yarnpkg.com/vt-pbf/-/vt-pbf-3.1.3.tgz#68fd150756465e2edae1cc5c048e063916dcfaac"
+  integrity sha512-2LzDFzt0mZKZ9IpVF2r69G9bXaP2Q2sArJCmcCgvfTdCCZzSyz4aCLoQyUilu37Ll56tCblIZrXFIjNUpGIlmA==
+  dependencies:
+    "@mapbox/point-geometry" "0.1.0"
+    "@mapbox/vector-tile" "^1.3.1"
+    pbf "^3.2.1"
+
+weak-lru-cache@^1.2.2:
+  version "1.2.2"
+  resolved "https://registry.yarnpkg.com/weak-lru-cache/-/weak-lru-cache-1.2.2.tgz#fdbb6741f36bae9540d12f480ce8254060dccd19"
+  integrity sha512-DEAoo25RfSYMuTGc9vPJzZcZullwIqRDSI9LOy+fkCJPi6hykCnfKaXTuPBDuXAUcqHXyOgFtHNp/kB2FjYHbw==
+
+webidl-conversions@^3.0.0:
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871"
+  integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==
+
[email protected]:
+  version "0.0.0"
+  resolved "https://registry.yarnpkg.com/wgs84/-/wgs84-0.0.0.tgz#34fdc555917b6e57cf2a282ed043710c049cdc76"
+  integrity sha512-ANHlY4Rb5kHw40D0NJ6moaVfOCMrp9Gpd1R/AIQYg2ko4/jzcJ+TVXYYF6kXJqQwITvEZP4yEthjM7U6rYlljQ==
+
+whatwg-url@^5.0.0:
+  version "5.0.0"
+  resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d"
+  integrity sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==
+  dependencies:
+    tr46 "~0.0.3"
+    webidl-conversions "^3.0.0"
+
+which-module@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a"
+  integrity sha512-B+enWhmw6cjfVC7kS8Pj9pCrKSc5txArRyaYGe088shv/FGWH+0Rjx/xPgtsWfsUtS27FkP697E4DDhgrgoc0Q==
+
+wrap-ansi@^6.2.0:
+  version "6.2.0"
+  resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-6.2.0.tgz#e9393ba07102e6c91a3b221478f0257cd2856e53"
+  integrity sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==
+  dependencies:
+    ansi-styles "^4.0.0"
+    string-width "^4.1.0"
+    strip-ansi "^6.0.0"
+
+wrappy@1:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
+  integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==
+
+xstate@^4.33.6:
+  version "4.36.0"
+  resolved "https://registry.yarnpkg.com/xstate/-/xstate-4.36.0.tgz#8bc633e4670be37c4e1adb28b4649b0a951ef7f1"
+  integrity sha512-AUI+KPgyy3g4PDpZWzUy/5ubd8VymbqikNmrJx5AQfqh+AQnemkBiabGROno+am1wUl2yeuT3UDrzUTSidfa6g==
+
+xtend@^4.0.0, xtend@^4.0.1, xtend@^4.0.2:
+  version "4.0.2"
+  resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54"
+  integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==
+
+xxhash-wasm@^0.4.2:
+  version "0.4.2"
+  resolved "https://registry.yarnpkg.com/xxhash-wasm/-/xxhash-wasm-0.4.2.tgz#752398c131a4dd407b5132ba62ad372029be6f79"
+  integrity sha512-/eyHVRJQCirEkSZ1agRSCwriMhwlyUcFkXD5TPVSLP+IPzjsqMVzZwdoczLp1SoQU0R3dxz1RpIK+4YNQbCVOA==
+
+y18n@^4.0.0:
+  version "4.0.3"
+  resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.3.tgz#b5f259c82cd6e336921efd7bfd8bf560de9eeedf"
+  integrity sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==
+
+yaml@^1.10.0:
+  version "1.10.2"
+  resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b"
+  integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==
+
+yargs-parser@^18.1.2:
+  version "18.1.3"
+  resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-18.1.3.tgz#be68c4975c6b2abf469236b0c870362fab09a7b0"
+  integrity sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==
+  dependencies:
+    camelcase "^5.0.0"
+    decamelize "^1.2.0"
+
+yargs@^15.3.1:
+  version "15.4.1"
+  resolved "https://registry.yarnpkg.com/yargs/-/yargs-15.4.1.tgz#0d87a16de01aee9d8bec2bfbf74f67851730f4f8"
+  integrity sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==
+  dependencies:
+    cliui "^6.0.0"
+    decamelize "^1.2.0"
+    find-up "^4.1.0"
+    get-caller-file "^2.0.1"
+    require-directory "^2.1.1"
+    require-main-filename "^2.0.0"
+    set-blocking "^2.0.0"
+    string-width "^4.2.0"
+    which-module "^2.0.0"
+    y18n "^4.0.0"
+    yargs-parser "^18.1.2"
+
[email protected]:
+  version "0.8.19"
+  resolved "https://registry.yarnpkg.com/zen-observable-ts/-/zen-observable-ts-0.8.19.tgz#c094cd20e83ddb02a11144a6e2a89706946b5694"
+  integrity sha512-u1a2rpE13G+jSzrg3aiCqXU5tN2kw41b+cBZGmnc+30YimdkKiDj9bTowcB41eL77/17RF/h+393AuVgShyheQ==
+  dependencies:
+    tslib "^1.9.3"
+    zen-observable "^0.8.0"
+
+zen-observable@^0.7.0:
+  version "0.7.1"
+  resolved "https://registry.yarnpkg.com/zen-observable/-/zen-observable-0.7.1.tgz#f84075c0ee085594d3566e1d6454207f126411b3"
+  integrity sha512-OI6VMSe0yeqaouIXtedC+F55Sr6r9ppS7+wTbSexkYdHbdt4ctTuPNXP/rwm7GTVI63YBc+EBT0b0tl7YnJLRg==
+
+zen-observable@^0.8.0:
+  version "0.8.15"
+  resolved "https://registry.yarnpkg.com/zen-observable/-/zen-observable-0.8.15.tgz#96415c512d8e3ffd920afd3889604e30b9eaac15"
+  integrity sha512-PQ2PC7R9rslx84ndNBZB/Dkv8V8fZEpk83RLgXtYd0fwUgEjseMn1Dgajh2x6S8QbZAFa9p2qVCEuYZNgve0dQ==
+
[email protected]:
+  version "0.2.1"
+  resolved "https://registry.yarnpkg.com/zen-push/-/zen-push-0.2.1.tgz#ddc33b90f66f9a84237d5f1893970f6be60c3c28"
+  integrity sha512-Qv4qvc8ZIue51B/0zmeIMxpIGDVhz4GhJALBvnKs/FRa2T7jy4Ori9wFwaHVt0zWV7MIFglKAHbgnVxVTw7U1w==
+  dependencies:
+    zen-observable "^0.7.0"

+ 1 - 0
public/index.html

@@ -51,6 +51,7 @@
 <script defer src="/static/js/highlight.min.js"></script>
 <script defer src="/static/js/interact.min.js"></script>
 <script defer src="/static/js/main.js"></script>
+<script defer src="/static/js/amplify.js"></script>
 <script defer src="/static/js/tabler.min.js"></script>
 <script defer src="/static/js/code-editor.js"></script>
 <script defer src="/static/js/tldraw.js"></script>

Разлика између датотеке није приказан због своје велике величине
+ 0 - 0
resources/css/amplify.css


+ 1 - 0
resources/electron.html

@@ -52,6 +52,7 @@ const portal = new MagicPortal(worker);
 <script defer src="./js/interact.min.js"></script>
 <script defer src="./js/lsplugin.core.js"></script>
 <script defer src="./js/main.js"></script>
+<script defer src="./js/amplify.js"></script>
 <script defer src="./js/tabler.min.js"></script>
 <script defer src="./js/code-editor.js"></script>
 <script defer src="./js/excalidraw.js"></script>

+ 1 - 0
resources/index.html

@@ -51,6 +51,7 @@ const portal = new MagicPortal(worker);
 <script defer src="./js/interact.min.js"></script>
 <script defer src="./js/lsplugin.core.js"></script>
 <script defer src="./js/main.js"></script>
+<script defer src="./js/amplify.js"></script>
 <script defer src="./js/tabler.min.js"></script>
 <script defer src="./js/code-editor.js"></script>
 <script defer src="./js/excalidraw.js"></script>

Разлика између датотеке није приказан због своје велике величине
+ 0 - 0
resources/js/amplify.js


+ 1 - 1
resources/package.json

@@ -1,7 +1,7 @@
 {
   "name": "Logseq",
   "productName": "Logseq",
-  "version": "0.8.18",
+  "version": "0.9.1",
   "main": "electron.js",
   "author": "Logseq",
   "license": "AGPL-3.0",

+ 10 - 10
src/electron/electron/backup_file.cljs

@@ -1,6 +1,6 @@
 (ns electron.backup-file
   (:require [clojure.string :as string]
-            ["path" :as path]
+            ["path" :as node-path]
             ["fs" :as fs]
             ["fs-extra" :as fs-extra]))
 
@@ -10,11 +10,11 @@
 (defn- get-backup-dir*
   [repo relative-path bak-dir]
   (let [relative-path* (string/replace relative-path repo "")
-        bak-dir (path/join repo bak-dir)
-        path (path/join bak-dir relative-path*)
-        parsed-path (path/parse path)]
-    (path/join (.-dir parsed-path)
-               (.-name parsed-path))))
+        bak-dir (node-path/join repo bak-dir)
+        path (node-path/join bak-dir relative-path*)
+        parsed-path (node-path/parse path)]
+    (node-path/join (.-dir parsed-path)
+                    (.-name parsed-path))))
 
 (defn get-backup-dir
   [repo relative-path]
@@ -31,7 +31,7 @@
         files (mapv #(.-name %) files)
         old-versioned-files (drop 6 (reverse (sort files)))]
     (doseq [file old-versioned-files]
-      (fs-extra/removeSync (path/join dir file)))))
+      (fs-extra/removeSync (node-path/join dir file)))))
 
 (defn backup-file
   "backup CONTENT under DIR :backup-dir or :version-file-dir
@@ -42,9 +42,9 @@
   (let [dir* (case dir
                :backup-dir (get-backup-dir repo relative-path)
                :version-file-dir (get-version-file-dir repo relative-path))
-        new-path (path/join dir*
-                            (str (string/replace (.toISOString (js/Date.)) ":" "_")
-                                 ".Desktop" ext))]
+        new-path (node-path/join dir*
+                                 (str (string/replace (.toISOString (js/Date.)) ":" "_")
+                                      ".Desktop" ext))]
     (fs-extra/ensureDirSync dir*)
     (fs/writeFileSync new-path content)
     (fs/statSync new-path)

+ 3 - 3
src/electron/electron/configs.cljs

@@ -1,14 +1,14 @@
 (ns electron.configs
   (:require
     ["fs-extra" :as ^js fs]
-    ["path" :as ^js path]
+    ["path" :as ^js node-path]
     ["electron" :refer [^js app] :as electron]
     [cljs.reader :as reader]))
 
 ;; FIXME: move configs.edn to where it should be
-(defonce dot-root (.join path (.getPath app "home") ".logseq"))
+(defonce dot-root (.join node-path (.getPath app "home") ".logseq"))
 (defonce cfg-root (.getPath app "userData"))
-(defonce cfg-path (.join path cfg-root "configs.edn"))
+(defonce cfg-path (.join node-path cfg-root "configs.edn"))
 
 (defn- ensure-cfg
   []

+ 22 - 22
src/electron/electron/core.cljs

@@ -13,7 +13,7 @@
             [cljs-bean.core :as bean]
             [electron.fs-watcher :as fs-watcher]
             ["fs-extra" :as fs]
-            ["path" :as path]
+            ["path" :as node-path]
             ["os" :as os]
             ["electron" :refer [BrowserWindow Menu app protocol ipcMain dialog shell] :as electron]
             ["electron-deeplink" :refer [Deeplink]]
@@ -31,7 +31,7 @@
 (defonce LSP_PROTOCOL (str FILE_LSP_SCHEME "://"))
 (defonce PLUGIN_URL (str LSP_PROTOCOL "logseq.io/"))
 (defonce STATIC_URL (str LSP_PROTOCOL "logseq.com/"))
-(defonce PLUGINS_ROOT (.join path (.homedir os) ".logseq/plugins"))
+(defonce PLUGINS_ROOT (.join node-path (.homedir os) ".logseq/plugins"))
 
 (defonce *setup-fn (volatile! nil))
 (defonce *teardown-fn (volatile! nil))
@@ -68,8 +68,8 @@
    (fn [^js request callback]
      (let [url (.-url request)
            url (decode-protected-assets-schema-path url)
-           path (js/decodeURI url)
-           path (string/replace path "assets://" "")]
+           path (string/replace url "assets://" "")
+           path (js/decodeURIComponent path)]
        (callback #js {:path path}))))
 
   (.registerFileProtocol
@@ -83,7 +83,7 @@
 
            path' (.-pathname url')
            path' (utils/safe-decode-uri-component path')
-           path' (.join path ROOT path')]
+           path' (.join node-path ROOT path')]
 
        (callback #js {:path path'}))))
 
@@ -96,51 +96,51 @@
           asset-filenames (->> (js->clj asset-filenames) (remove nil?))
           root-dir (or output-path (handler/open-dir-dialog))]
     (when root-dir
-      (let [static-dir (path/join root-dir "static")
-            assets-from-dir (path/join repo-path "assets")
-            assets-to-dir (path/join root-dir "assets")
-            index-html-path (path/join root-dir "index.html")]
+      (let [static-dir (node-path/join root-dir "static")
+            assets-from-dir (node-path/join repo-path "assets")
+            assets-to-dir (node-path/join root-dir "assets")
+            index-html-path (node-path/join root-dir "index.html")]
         (p/let [_ (. fs ensureDir static-dir)
                 _ (. fs ensureDir assets-to-dir)
                 _ (p/all (concat
                           [(. fs writeFile index-html-path html)
 
 
-                           (. fs copy (path/join app-path "404.html") (path/join root-dir "404.html"))]
+                           (. fs copy (node-path/join app-path "404.html") (node-path/join root-dir "404.html"))]
 
                           (map
                            (fn [filename]
-                             (-> (. fs copy (path/join assets-from-dir filename) (path/join assets-to-dir filename))
+                             (-> (. fs copy (node-path/join assets-from-dir filename) (node-path/join assets-to-dir filename))
                                  (p/catch
                                   (fn [e]
                                     (logger/error "Failed to copy"
-                                            (str {:from (path/join assets-from-dir filename)
-                                                  :to (path/join assets-to-dir filename)})
+                                            (str {:from (node-path/join assets-from-dir filename)
+                                                  :to (node-path/join assets-to-dir filename)})
                                             e)))))
                            asset-filenames)
 
                           (map
                            (fn [part]
-                             (. fs copy (path/join app-path part) (path/join static-dir part)))
+                             (. fs copy (node-path/join app-path part) (node-path/join static-dir part)))
                            ["css" "fonts" "icons" "img" "js"])))
                 export-css (if (fs/existsSync export-css-path) (. fs readFile export-css-path) "")
-                _ (. fs writeFile (path/join static-dir "css" "export.css")  export-css)
+                _ (. fs writeFile (node-path/join static-dir "css" "export.css")  export-css)
                 custom-css (if (fs/existsSync custom-css-path) (. fs readFile custom-css-path) "")
-                _ (. fs writeFile (path/join static-dir "css" "custom.css") custom-css)
+                _ (. fs writeFile (node-path/join static-dir "css" "custom.css") custom-css)
                 js-files ["main.js" "code-editor.js" "excalidraw.js" "tldraw.js"]
                 _ (p/all (map (fn [file]
-                                (. fs removeSync (path/join static-dir "js" file)))
+                                (. fs removeSync (node-path/join static-dir "js" file)))
                               js-files))
                 _ (p/all (map (fn [file]
                                 (. fs moveSync
-                                   (path/join static-dir "js" "publishing" file)
-                                   (path/join static-dir "js" file)))
+                                   (node-path/join static-dir "js" "publishing" file)
+                                   (node-path/join static-dir "js" file)))
                               js-files))
-                _ (. fs removeSync (path/join static-dir "js" "publishing"))
+                _ (. fs removeSync (node-path/join static-dir "js" "publishing"))
                 ;; remove source map files
                 ;; TODO: ugly, replace with ls-files and filter with ".map"
                 _ (p/all (map (fn [file]
-                                (. fs removeSync (path/join static-dir "js" (str file ".map"))))
+                                (. fs removeSync (node-path/join static-dir "js" (str file ".map"))))
                               ["main.js" "code-editor.js" "excalidraw.js"]))]
 
           (send-to-renderer
@@ -200,7 +200,7 @@
 (defn- set-app-menu! []
   (let [about-fn (fn []
                    (.showMessageBox dialog (clj->js {:title "Logseq"
-                                                     :icon (path/join js/__dirname "icons/logseq.png")
+                                                     :icon (node-path/join js/__dirname "icons/logseq.png")
                                                      :message (str "Version " updater/electron-version)})))
         template (if mac?
                    [{:label (.-name app)

+ 4 - 4
src/electron/electron/git.cljs

@@ -7,7 +7,7 @@
             [promesa.core :as p]
             [clojure.string :as string]
             ["fs-extra" :as fs]
-            ["path" :as path]
+            ["path" :as node-path]
             ["os" :as os]))
 
 (def log-error (partial logger/error "[Git]"))
@@ -17,7 +17,7 @@
   (when-let [graph-path (some-> (state/get-graph-path)
                                 (string/replace "/" "_")
                                 (string/replace ":" "comma"))]
-    (let [dir (.join path (.homedir os) ".logseq" "git" graph-path ".git")]
+    (let [dir (.join node-path (.homedir os) ".logseq" "git" graph-path ".git")]
       (. fs ensureDirSync dir)
       dir)))
 
@@ -44,7 +44,7 @@
 (defn git-dir-exists?
   []
   (try
-    (let [p (.join path (state/get-graph-path) ".git")]
+    (let [p (.join node-path (state/get-graph-path) ".git")]
       (.isDirectory (fs/statSync p)))
     (catch :default _e
       nil)))
@@ -56,7 +56,7 @@
           _ (when (string/blank? graph-path)
               (utils/send-to-renderer "getCurrentGraph" {})
               (throw (js/Error. "Empty graph path")))
-          p (.join path graph-path ".git")]
+          p (.join node-path graph-path ".git")]
       (when (and (fs/existsSync p)
                  (.isFile (fs/statSync p)))
         (let [content (string/trim (.toString (fs/readFileSync p)))

+ 34 - 30
src/electron/electron/handler.cljs

@@ -9,7 +9,7 @@
             ["fs" :as fs]
             ["fs-extra" :as fs-extra]
             ["os" :as os]
-            ["path" :as path]
+            ["path" :as node-path]
             [cljs-bean.core :as bean]
             [cljs.reader :as reader]
             [clojure.core.async :as async]
@@ -51,7 +51,7 @@
                  (remove #(string/starts-with? (.-name ^js %) "."))
                  (map #(do
                          [(.isDirectory %)
-                          (.join path dir (.-name %))])))))
+                          (.join node-path dir (.-name %))])))))
         [true root-dir])
        (filter (complement first))
        (map second)
@@ -94,10 +94,10 @@
              (string? new-content)
              (string-some-deleted? db-content new-content))
     (logger/info ::backup "backup db file" path)
-    (backup-file/backup-file repo :backup-dir path (path/extname path) db-content)))
+    (backup-file/backup-file repo :backup-dir path (node-path/extname path) db-content)))
 
 (defmethod handle :addVersionFile [_window [_ repo path content]]
-  (backup-file/backup-file repo :version-file-dir path (path/extname path) content))
+  (backup-file/backup-file repo :version-file-dir path (node-path/extname path) content))
 
 (defmethod handle :openFileBackupDir [_window [_ repo path]]
   (when (string? path)
@@ -128,7 +128,7 @@
       (catch :default e
         (logger/warn ::write-file path e)
         (let [backup-path (try
-                            (backup-file/backup-file repo :backup-dir path (path/extname path) content)
+                            (backup-file/backup-file repo :backup-dir path (node-path/extname path) content)
                             (catch :default e
                               (logger/error ::write-file "backup file failed:" e)))]
           (utils/send-to-renderer window "notification" {:type "error"
@@ -152,24 +152,24 @@
 
 (defn get-ext
   [p]
-  (-> (.extname path p)
+  (-> (.extname node-path p)
       (subs 1)
       keyword))
 
 (defn- get-files
+  "Returns vec of file-objs"
   [path]
-  (let [result (->>
-                (readdir path)
-                (remove (partial utils/ignored-path? path))
-                (filter #(contains? allowed-formats (get-ext %)))
-                (map (fn [path]
-                       (let [stat (fs/statSync path)]
-                         (when-not (.isDirectory stat)
-                           {:path    (utils/fix-win-path! path)
-                            :content (utils/read-file path)
-                            :stat    stat}))))
-                (remove nil?))]
-    (vec (cons {:path (utils/fix-win-path! path)} result))))
+  (->> (readdir path)
+       (remove (partial utils/ignored-path? path))
+       (filter #(contains? allowed-formats (get-ext %)))
+       (map (fn [path]
+              (let [stat (fs/statSync path)]
+                (when-not (.isDirectory stat)
+                  {:path    (utils/fix-win-path! path)
+                   :content (utils/read-file path)
+                   :stat    stat}))))
+       (remove nil?)
+       vec))
 
 (defn open-dir-dialog []
   (p/let [result (.showOpenDialog dialog (bean/->js
@@ -193,12 +193,14 @@
 
 (defmethod handle :openDir [^js window _messages]
   (logger/info ::open-dir "open folder selection dialog")
-  (p/let [path (open-dir-dialog)]
+  (p/let [path (open-dir-dialog)
+          path (utils/fix-win-path! path)]
     (logger/debug ::open-dir {:path path})
     (if path
       (try
-        (p/resolved (bean/->js (get-files path)))
-        (catch js/Error e 
+        (p/resolved (bean/->js {:path path
+                                :files (get-files path)}))
+        (catch js/Error e
           (do
             (utils/send-to-renderer window "notification" {:type "error"
                                                            :payload (str "Opening the specified directory failed.\n"
@@ -209,7 +211,9 @@
 
 (defmethod handle :getFiles [_window [_ path]]
   (logger/debug ::get-files {:path path})
-  (get-files path))
+  (p/let [files (get-files path)]
+    (bean/->js {:path path
+                :files files})))
 
 (defn- sanitize-graph-name
   [graph-name]
@@ -228,8 +232,8 @@
 (defn- get-graphs-dir
   []
   (let [dir (if utils/ci?
-              (.resolve path js/__dirname "../tmp/graphs")
-              (.join path (.homedir os) ".logseq" "graphs"))]
+              (.resolve node-path js/__dirname "../tmp/graphs")
+              (.join node-path (.homedir os) ".logseq" "graphs"))]
     (fs-extra/ensureDirSync dir)
     dir))
 
@@ -239,7 +243,7 @@
   (let [dir (get-graphs-dir)]
     (->> (readdir dir)
          (remove #{dir})
-         (map #(path/basename % ".transit"))
+         (map #(node-path/basename % ".transit"))
          (map graph-name->path))))
 
 ;; TODO support alias mechanism
@@ -259,7 +263,7 @@
 (defn- read-txid-info!
   [root]
   (try
-    (let [txid-path (.join path root "logseq/graphs-txid.edn")]
+    (let [txid-path (.join node-path root "logseq/graphs-txid.edn")]
       (when (fs/existsSync txid-path)
         (when-let [sync-meta (and (not (string/blank? root))
                                   (.toString (.readFileSync fs txid-path)))]
@@ -285,7 +289,7 @@
   (when graph-name
     (let [graph-name (sanitize-graph-name graph-name)
           dir (get-graphs-dir)]
-      (.join path dir (str graph-name ".transit")))))
+      (.join node-path dir (str graph-name ".transit")))))
 
 (defn- get-serialized-graph
   [graph-name]
@@ -362,7 +366,7 @@
 
   (let [path (.getPath ^object app "userData")]
     (doseq [dir ["search" "IndexedDB"]]
-      (let [path (path/join path dir)]
+      (let [path (node-path/join path dir)]
         (try
           (fs-extra/removeSync path)
           (catch :default e
@@ -426,7 +430,7 @@
   (zipmap urls (for [url urls]
                  (try
                    (and (fs-extra/pathExistsSync url)
-                        (fs-extra/pathExistsSync (path/join url "package.json")))
+                        (fs-extra/pathExistsSync (node-path/join url "package.json")))
                    (catch :default _e false)))))
 
 (defmethod handle :relaunchApp []
@@ -452,7 +456,7 @@
 
 (defmethod handle :getAssetsFiles [^js win [_ {:keys [exts]}]]
   (when-let [graph-path (state/get-window-graph-path win)]
-    (when-let [assets-path (.join path graph-path "assets")]
+    (when-let [assets-path (.join node-path graph-path "assets")]
       (when (fs-extra/pathExistsSync assets-path)
         (p/let [^js files (js-utils/getAllFiles assets-path (clj->js exts))]
           files)))))

+ 11 - 11
src/electron/electron/plugin.cljs

@@ -4,7 +4,7 @@
             ["semver" :as semver]
             ["os" :as os]
             ["fs-extra" :as fs]
-            ["path" :as path]
+            ["path" :as node-path]
             [clojure.string :as string]
             [electron.utils :refer [fetch extract-zip] :as utils]
             [electron.logger :as logger]
@@ -21,7 +21,7 @@
 
 (defn dotdir-file?
   [file]
-  (and file (string/starts-with? (path/normalize file) cfgs/dot-root)))
+  (and file (string/starts-with? (node-path/normalize file) cfgs/dot-root)))
 
 (defn assetsdir-file?
   [file]
@@ -94,10 +94,10 @@
                       (fn [resolve1 reject1]
                         (let [body (.-body res)
                               *downloaded (atom 0)
-                              dest-basename (path/basename dl-url)
+                              dest-basename (node-path/basename dl-url)
                               dest-basename (if-not (string/ends-with? dest-basename ".zip")
                                               (str id "_" dest-basename ".zip") dest-basename)
-                              tmp-dest-file (path/join (os/tmpdir) (str dest-basename ".pending"))
+                              tmp-dest-file (node-path/join (os/tmpdir) (str dest-basename ".pending"))
                               dest-file (.createWriteStream fs tmp-dest-file)]
                           (doto body
                             (.on "data" (fn [chunk]
@@ -121,22 +121,22 @@
                                      pkg? (fn [root]
                                             (when-let [^js stat (fs/statSync root)]
                                               (when (.isDirectory stat)
-                                                (fs/pathExistsSync (.join path root "package.json")))))]
+                                                (fs/pathExistsSync (.join node-path root "package.json")))))]
                                  (if (pkg? zip-extracted-path)
                                    "."
-                                   (last (take-while #(pkg? (.join path zip-extracted-path %)) dirs))))
+                                   (last (take-while #(pkg? (.join node-path zip-extracted-path %)) dirs))))
 
             _ (when-not tmp-extracted-root
                 (throw (js/Error. :invalid-plugin-package)))
 
-            tmp-extracted-root (.join path zip-extracted-path tmp-extracted-root)
+            tmp-extracted-root (.join node-path zip-extracted-path tmp-extracted-root)
 
             _ (and (fs/existsSync dot-extract-to)
                    (fs/removeSync dot-extract-to))
 
             _ (fs/moveSync tmp-extracted-root dot-extract-to)
 
-            _ (let [src (.join path dot-extract-to "package.json")
+            _ (let [src (.join node-path dot-extract-to "package.json")
                     ^js sponsors (bean/->js sponsors)
                     ^js pkg (fs/readJsonSync src)]
                 (set! (.-repo pkg) repo)
@@ -201,7 +201,7 @@
                              (debug "[Download URL Error]" asset)
                              (throw (js/Error. [:release-asset-not-found (js/JSON.stringify asset)])))
 
-                         dest (.join path cfgs/dot-root "plugins" (:id item))
+                         dest (.join node-path cfgs/dot-root "plugins" (:id item))
                          _ (when-not only-check (download-asset-zip item dl-url latest-version dest))
                          _ (debug (str "[" (if only-check "Checked" "Updated") "DONE]") latest-version)]
 
@@ -230,8 +230,8 @@
 (defn uninstall!
   [id]
   (let [id (string/replace id #"^[.\/]+" "")
-        plugin-path (.join path (utils/get-ls-dotdir-root) "plugins" id)
-        settings-path (.join path (utils/get-ls-dotdir-root) "settings" (str id ".json"))]
+        plugin-path (.join node-path (utils/get-ls-dotdir-root) "plugins" id)
+        settings-path (.join node-path (utils/get-ls-dotdir-root) "settings" (str id ".json"))]
     (debug "[Uninstall]" plugin-path)
     (when (fs/pathExistsSync plugin-path)
       (fs/removeSync plugin-path)

+ 4 - 4
src/electron/electron/search.cljs

@@ -1,6 +1,6 @@
 (ns electron.search
   "Provides both page level and block level index"
-  (:require ["path" :as path]
+  (:require ["path" :as node-path]
             ["fs-extra" :as fs]
             ["better-sqlite3" :as sqlite3]
             [clojure.string :as string]
@@ -113,7 +113,7 @@
 (defn get-search-dir
   []
   (let [path (.getPath ^object app "userData")]
-    (path/join path "search")))
+    (node-path/join path "search")))
 
 (defn ensure-search-dir!
   []
@@ -123,14 +123,14 @@
   [db-name]
   (let [db-name (sanitize-db-name db-name)
         search-dir (get-search-dir)]
-    [db-name (path/join search-dir db-name)]))
+    [db-name (node-path/join search-dir db-name)]))
 
 (defn get-db-path
   "Search cache paths"
   [db-name]
   (let [db-name (sanitize-db-name db-name)
         search-dir (get-search-dir)]
-    [db-name (path/join search-dir db-name)]))
+    [db-name (node-path/join search-dir db-name)]))
 
 (defn open-db!
   [db-name]

+ 2 - 2
src/electron/electron/server.cljs

@@ -3,7 +3,7 @@
             ["@fastify/cors" :as FastifyCORS]
             ["electron" :refer [ipcMain]]
             ["fs-extra" :as fs-extra]
-            ["path" :as path]
+            ["path" :as node-path]
             [clojure.string :as string]
             [promesa.core :as p]
             [cljs-bean.core :as bean]
@@ -141,7 +141,7 @@
                       (.addHook "preHandler" api-pre-handler!)
                       (.post "/api" api-handler!)
                       (.get "/" (fn [_ ^js rep]
-                                  (let [html (fs-extra/readFileSync (.join path js/__dirname "./docs/api_server.html"))
+                                  (let [html (fs-extra/readFileSync (.join node-path js/__dirname "./docs/api_server.html"))
                                         HOST (get-host)
                                         PORT (get-port)
                                         html (-> (str html)

+ 4 - 4
src/electron/electron/updater.cljs

@@ -9,7 +9,7 @@
             ["semver" :as semver]
             ["os" :as os]
             ["fs" :as fs]
-            ["path" :as path]
+            ["path" :as node-path]
             ["electron" :refer [ipcMain app autoUpdater]]))
 
 (def *update-ready-to-install (atom nil))
@@ -61,7 +61,7 @@
              artifact (when-let [remote-version (and artifact (re-find #"\d+\.\d+\.\d+" (:url artifact)))]
                         (when (and (. semver valid remote-version)
                                    (. semver lt electron-version remote-version)) artifact))
-             
+
              url (if-not artifact (do (emit "update-not-available" nil) (throw nil)) (:url artifact))
              _ (if url (emit "update-available" (bean/->js artifact)) (throw (js/Error. "download url not exists")))
                ;; start download FIXME: user's preference about auto download
@@ -75,8 +75,8 @@
                                 body (.-body dl-res)
                                 start-at (.now js/Date)
                                 *downloaded (atom 0)
-                                dest-basename (path/basename url)
-                                tmp-dest-file (path/join (os/tmpdir) (str dest-basename ".pending"))
+                                dest-basename (node-path/basename url)
+                                tmp-dest-file (node-path/join (os/tmpdir) (str dest-basename ".pending"))
                                 dest-file (.createWriteStream fs tmp-dest-file)]
                             (doto body
                               (.on "data" (fn [chunk]

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

@@ -90,9 +90,6 @@
   [^js win parsed-url]
   (let [url-host (.-host parsed-url)] ;; return "" when no pathname provided
     (cond
-      (= "auth-callback" url-host)
-      (send-to-renderer win "loginCallback" (.get (.-searchParams parsed-url) "code"))
-
       (= "x-callback-url" url-host)
       (x-callback-url-handler win parsed-url)
 

+ 9 - 8
src/electron/electron/utils.cljs

@@ -2,7 +2,7 @@
   (:require ["@logseq/rsapi" :as rsapi]
             ["electron" :refer [app BrowserWindow]]
             ["fs-extra" :as fs]
-            ["path" :as path]
+            ["path" :as node-path]
             [clojure.string :as string]
             [electron.configs :as cfgs]
             [electron.logger :as logger]
@@ -37,28 +37,28 @@
 
 (defn fix-win-path!
   [path]
-  (when path
+  (when (not-empty path)
     (if win32?
       (string/replace path "\\" "/")
       path)))
 
 (defn get-ls-dotdir-root
   []
-  (let [lg-dir (path/join (.getPath app "home") ".logseq")]
+  (let [lg-dir (node-path/join (.getPath app "home") ".logseq")]
     (when-not (fs/existsSync lg-dir)
       (fs/mkdirSync lg-dir))
     (fix-win-path! lg-dir)))
 
 (defn get-ls-default-plugins
   []
-  (let [plugins-root (path/join (get-ls-dotdir-root) "plugins")
+  (let [plugins-root (node-path/join (get-ls-dotdir-root) "plugins")
         _ (when-not (fs/existsSync plugins-root)
             (fs/mkdirSync plugins-root))
         dirs (js->clj (fs/readdirSync plugins-root #js{"withFileTypes" true}))
         dirs (->> dirs
                   (filter #(.isDirectory %))
                   (filter (fn [f] (not (some #(string/starts-with? (.-name f) %) ["_" "."]))))
-                  (map #(path/join plugins-root (.-name %))))]
+                  (map #(node-path/join plugins-root (.-name %))))]
     dirs))
 
 (defn- set-fetch-agent-proxy
@@ -211,14 +211,14 @@
      (some #(string/ends-with? path %)
            [".DS_Store" "logseq/graphs-txid.edn"])
      ;; hidden directory or file
-     (let [relpath (path/relative dir path)]
+     (let [relpath (node-path/relative dir path)]
        (or (re-find #"/\.[^.]+" relpath)
            (re-find #"^\.[^.]+" relpath))))))
 
 (defn should-read-content?
   "Skip reading content of file while using file-watcher"
   [path]
-  (let [ext (string/lower-case (path/extname path))]
+  (let [ext (string/lower-case (node-path/extname path))]
     (contains? #{".md" ".markdown" ".org" ".js" ".edn" ".css"} ext)))
 
 (defn read-file
@@ -261,7 +261,8 @@
 (defn get-graph-dir
   "required by all internal state in the electron section"
   [graph-name]
-  (string/replace graph-name "logseq_local_" ""))
+  (when (string/includes? graph-name "logseq_local_")
+    (string/replace-first graph-name "logseq_local_" "")))
 
 (defn get-graph-name
   "reversing `get-graph-dir`"

+ 8 - 8
src/electron/electron/window.cljs

@@ -5,7 +5,7 @@
             [electron.context-menu :as context-menu]
             [electron.logger :as logger]
             ["electron" :refer [BrowserWindow app session shell] :as electron]
-            ["path" :as path]
+            ["path" :as node-path]
             ["url" :as URL]
             [electron.state :as state]
             [cljs-bean.core :as bean]
@@ -16,8 +16,8 @@
 
 (def MAIN_WINDOW_ENTRY (if dev?
                          ;;"http://localhost:3001"
-                         (str "file://" (path/join js/__dirname "index.html"))
-                         (str "file://" (path/join js/__dirname "electron.html"))))
+                         (str "file://" (node-path/join js/__dirname "index.html"))
+                         (str "file://" (node-path/join js/__dirname "electron.html"))))
 
 (defn create-main-window!
   ([]
@@ -45,13 +45,13 @@
                        ;; Remove OverlayScrollbars and transition `.scrollbar-spacing`
                        ;; to use `scollbar-gutter` after the feature is implemented in browsers.
                        :enableBlinkFeatures     'OverlayScrollbars'
-                       :preload                 (path/join js/__dirname "js/preload.js")}}
+                       :preload                 (node-path/join js/__dirname "js/preload.js")}}
 
                      (seq opts)
                      (merge opts)
 
                      linux?
-                     (assoc :icon (path/join js/__dirname "icons/logseq.png")))
+                     (assoc :icon (node-path/join js/__dirname "icons/logseq.png")))
          win       (BrowserWindow. (clj->js win-opts))]
      (.manage win-state win)
      (.onBeforeSendHeaders (.. session -defaultSession -webRequest)
@@ -136,8 +136,8 @@
                   url (if-not win32? (string/replace url "file://" "") url)]
               (logger/info "new-window" url)
               (if (some #(string/includes?
-                          (.normalize path url)
-                          (.join path (. app getAppPath) %))
+                          (.normalize node-path url)
+                          (.join node-path (. app getAppPath) %))
                         ["index.html" "electron.html"])
                 (logger/info "pass-window" url)
                 (open-default-app! url open))))
@@ -173,7 +173,7 @@
                              {:plugins          true
                               :nodeIntegration  false
                               :webSecurity      (not dev?)
-                              :preload          (path/join js/__dirname "js/preload.js")
+                              :preload          (node-path/join js/__dirname "js/preload.js")
                               :nativeWindowOpen true}}}
                            features)
                     (do (open-external! url) {:action "deny"}))

+ 142 - 137
src/main/electron/listener.cljs

@@ -19,8 +19,15 @@
             [frontend.handler.user :as user]
             [frontend.state :as state]
             [frontend.ui :as ui]
+            [logseq.common.path :as path]
+            [logseq.graph-parser.util :as gp-util]
             [promesa.core :as p]))
 
+(defn- safe-api-call
+  "Force the callback result to be nil, otherwise, ipc calls could lead to
+  window crash."
+  [k f]
+  (js/window.apis.on k (fn [data] (f data) nil)))
 
 (defn persist-dbs!
   []
@@ -35,153 +42,151 @@
 
 (defn listen-persistent-dbs!
   []
-  ;; TODO: move "file-watcher" to electron.ipc.channels
-  (js/window.apis.on
-   "persistent-dbs"
-   (fn [_req]
-     (persist-dbs!))))
+  (safe-api-call "persistent-dbs" (fn [_data] (persist-dbs!))))
 
 
 (defn ^:large-vars/cleanup-todo listen-to-electron!
   []
   ;; TODO: move "file-watcher" to electron.ipc.channels
-  (js/window.apis.on "file-watcher"
+  (safe-api-call "file-watcher"
                      (fn [data]
-                       (let [{:keys [type payload]} (bean/->clj data)]
+                       (let [{:keys [type payload]} (bean/->clj data)
+                             path (gp-util/path-normalize (:path payload))
+                             dir (:dir payload)
+                             payload (assoc payload :path (path/relative-path dir path))]
                          (watcher-handler/handle-changed! type payload)
                          (when (file-sync-handler/enable-sync?)
                            (sync/file-watch-handler type payload)))))
 
-  (js/window.apis.on "file-sync-progress"
-                     (fn [data]
-                       (let [payload (bean/->clj data)]
-                         (state/set-state! [:file-sync/graph-state (:graphUUID payload) :file-sync/progress (:file payload)] payload))))
-
-  (js/window.apis.on "notification"
-                     (fn [data]
-                       (let [{:keys [type payload]} (bean/->clj data)
-                             type (keyword type)
-                             comp [:div (str payload)]]
-                         (notification/show! comp type false))))
-
-  (js/window.apis.on "graphUnlinked"
-                     (fn [data]
-                       (let [repo (bean/->clj data)]
-                         (repo-handler/remove-repo! repo))))
-
-  (js/window.apis.on "setGitUsernameAndEmail"
-                     (fn []
-                       (state/pub-event! [:modal/set-git-username-and-email])))
-
-  (js/window.apis.on "getCurrentGraph"
-                     (fn []
-                       (when-let [graph (state/get-current-repo)]
-                         (ipc/ipc "setCurrentGraph" graph))))
-
-  (js/window.apis.on "redirect"
-                     (fn [data]
-                       (let [{:keys [payload]} (bean/->clj data)
-                             payload (update payload :to keyword)]
-                         (route-handler/redirect! payload))))
-
-  (js/window.apis.on "redirectWhenExists"
-                     ;;  Redirect to the given page or block when the provided page or block exists.
-                     ;;  Either :page-name or :block-id is required.
-                     ;;  :page-name : the original-name of the page.
-                     ;;  :block-id : uuid.
-                     (fn [data]
-                       (let [{:keys [page-name block-id file]} (bean/->clj data)]
-                         (cond
-                           page-name
-                           (let [db-page-name (db-model/get-redirect-page-name page-name)
-                                 whiteboard? (db-model/whiteboard-page? db-page-name)]
-                             ;; No error handling required, as a page name is always valid
-                             ;; Open new page if the page does not exist
-                             (if whiteboard?
-                               (route-handler/redirect-to-whiteboard! page-name {:block-id block-id})
-                               (editor-handler/insert-first-page-block-if-not-exists! db-page-name)))
-
-                           block-id
-                           (if (db-model/get-block-by-uuid block-id)
-                             (route-handler/redirect-to-page! block-id)
-                             (notification/show! (str "Open link failed. Block-id `" block-id "` doesn't exist in the graph.") :error false))
-
-                           file
-                           (if-let [db-page-name (db-model/get-file-page file false)]
-                             (route-handler/redirect-to-page! db-page-name)
-                             (notification/show! (str "Open link failed. File `" file "` doesn't exist in the graph.") :error false))))))
-
-  (js/window.apis.on "dbsync"
-                     (fn [data]
-                       (let [{:keys [graph tx-data]} (bean/->clj data)
-                             tx-data (db/string->db (:data tx-data))]
-                         (when-let [conn (db/get-db graph false)]
-                           (d/transact! conn tx-data {:dbsync? true}))
-                         (ui-handler/re-render-root!))))
-
-  (js/window.apis.on "persistGraph"
-                     ;; electron is requesting window for persisting a graph in it's db
-                     ;; fire back "broadcastPersistGraphDone" on done
-                     (fn [data]
-                       (let [repo (bean/->clj data)
-                             before-f #(notification/show!
-                                        (ui/loading (t :graph/persist))
-                                        :warning)
-                             after-f #(ipc/ipc "broadcastPersistGraphDone")
-                             error-f (fn []
-                                       (after-f)
-                                       (notification/show!
-                                        (t :graph/persist-error)
-                                        :error))
-                             handlers {:before     before-f
-                                       :on-success after-f
-                                       :on-error   error-f}]
-                         (repo-handler/persist-db! repo handlers))))
-
-  (js/window.apis.on "foundInPage"
-                     (fn [data]
-                       (let [data' (bean/->clj data)]
-                         (state/set-state! [:ui/find-in-page :matches] data')
-                         (dom/remove-style! (dom/by-id "search-in-page-input") :visibility)
-                         (dom/set-text! (dom/by-id "search-in-page-placeholder") "")
-                         (ui/focus-element "search-in-page-input")
-                         true)))
-
-  (js/window.apis.on "loginCallback"
-                     (fn [code]
-                       (user/login-callback code)))
-
-  (js/window.apis.on "quickCapture"
-                     (fn [args]
-                       (state/pub-event! [:editor/quick-capture args])))
-
-  (js/window.apis.on "openNewWindowOfGraph"
-                     ;; Handle open new window in renderer, until the destination graph doesn't rely on setting local storage
-                     ;; No db cache persisting ensured. Should be handled by the caller
-                     (fn [repo]
-                       (ui-handler/open-new-window! repo)))
-
-  (js/window.apis.on "invokeLogseqAPI"
-                     (fn [^js data]
-                       (let [sync-id (.-syncId data)
-                             method  (.-method data)
-                             args    (.-args data)
-                             ret-fn! #(ipc/invoke (str :electron.server/sync! sync-id) %)]
-
-                         (try
-                           (println "invokeLogseqAPI:" method)
-                           (let [^js apis (aget js/window.logseq "api")]
-                             (when-not (aget apis method)
-                               (throw (js/Error. (str "MethodNotExist: " method))))
-                             (-> (p/promise (apply js-invoke apis method args))
-                                 (p/then #(ret-fn! %))
-                                 (p/catch #(ret-fn! {:error %}))))
-                           (catch js/Error e
-                             (ret-fn! {:error (.-message e)}))))))
-
-  (js/window.apis.on "syncAPIServerState"
-                     (fn [^js data]
-                       (state/set-state! :electron/server (bean/->clj data)))))
+  (safe-api-call "file-sync-progress"
+                 (fn [data]
+                   (let [payload (bean/->clj data)]
+                     (state/set-state! [:file-sync/graph-state (:graphUUID payload) :file-sync/progress (:file payload)] payload))))
+
+  (safe-api-call "notification"
+                 (fn [data]
+                   (let [{:keys [type payload]} (bean/->clj data)
+                         type (keyword type)
+                         comp [:div (str payload)]]
+                     (notification/show! comp type false))))
+
+  (safe-api-call "graphUnlinked"
+                 (fn [data]
+                   (let [repo (bean/->clj data)]
+                     (repo-handler/remove-repo! repo))))
+
+  (safe-api-call "setGitUsernameAndEmail"
+                 (fn []
+                   (state/pub-event! [:modal/set-git-username-and-email])))
+
+  (safe-api-call "getCurrentGraph"
+                 (fn []
+                   (when-let [graph (state/get-current-repo)]
+                     (ipc/ipc "setCurrentGraph" graph))))
+
+  (safe-api-call "redirect"
+                 (fn [data]
+                   (let [{:keys [payload]} (bean/->clj data)
+                         payload (update payload :to keyword)]
+                     (route-handler/redirect! payload))))
+
+  (safe-api-call "redirectWhenExists"
+                 ;;  Redirect to the given page or block when the provided page or block exists.
+                 ;;  Either :page-name or :block-id is required.
+                 ;;  :page-name : the original-name of the page.
+                 ;;  :block-id : uuid.
+                 (fn [data]
+                   (let [{:keys [page-name block-id file]} (bean/->clj data)]
+                     (cond
+                       page-name
+                       (let [db-page-name (db-model/get-redirect-page-name page-name)
+                             whiteboard? (db-model/whiteboard-page? db-page-name)]
+                         ;; No error handling required, as a page name is always valid
+                         ;; Open new page if the page does not exist
+                         (if whiteboard?
+                           (route-handler/redirect-to-whiteboard! page-name {:block-id block-id})
+                           (editor-handler/insert-first-page-block-if-not-exists! db-page-name)))
+
+                       block-id
+                       (if (db-model/get-block-by-uuid block-id)
+                         (route-handler/redirect-to-page! block-id)
+                         (notification/show! (str "Open link failed. Block-id `" block-id "` doesn't exist in the graph.") :error false))
+
+                       file
+                       (if-let [db-page-name (db-model/get-file-page file false)]
+                         (route-handler/redirect-to-page! db-page-name)
+                         (notification/show! (str "Open link failed. File `" file "` doesn't exist in the graph.") :error false))))))
+
+  (safe-api-call "dbsync"
+                 (fn [data]
+                   (let [{:keys [graph tx-data]} (bean/->clj data)
+                         tx-data (db/string->db (:data tx-data))]
+                     (when-let [conn (db/get-db graph false)]
+                       (d/transact! conn tx-data {:dbsync? true}))
+                     (ui-handler/re-render-root!))))
+
+  (safe-api-call "persistGraph"
+                 ;; electron is requesting window for persisting a graph in it's db
+                 ;; fire back "broadcastPersistGraphDone" on done
+                 (fn [data]
+                   (let [repo (bean/->clj data)
+                         before-f #(notification/show!
+                                    (ui/loading (t :graph/persist))
+                                    :warning)
+                         after-f #(ipc/ipc "broadcastPersistGraphDone")
+                         error-f (fn []
+                                   (after-f)
+                                   (notification/show!
+                                    (t :graph/persist-error)
+                                    :error))
+                         handlers {:before     before-f
+                                   :on-success after-f
+                                   :on-error   error-f}]
+                     (repo-handler/persist-db! repo handlers))))
+
+  (safe-api-call "foundInPage"
+                 (fn [data]
+                   (let [data' (bean/->clj data)]
+                     (state/set-state! [:ui/find-in-page :matches] data')
+                     (dom/remove-style! (dom/by-id "search-in-page-input") :visibility)
+                     (dom/set-text! (dom/by-id "search-in-page-placeholder") "")
+                     (ui/focus-element "search-in-page-input"))))
+
+  (safe-api-call "loginCallback"
+                 (fn [code]
+                   (user/login-callback code)))
+
+  (safe-api-call "quickCapture"
+                 (fn [args]
+                   (state/pub-event! [:editor/quick-capture args])))
+
+  (safe-api-call "openNewWindowOfGraph"
+                 ;; Handle open new window in renderer, until the destination graph doesn't rely on setting local storage
+                 ;; No db cache persisting ensured. Should be handled by the caller
+                 (fn [repo]
+                   (ui-handler/open-new-window! repo)))
+
+  (safe-api-call "invokeLogseqAPI"
+                 (fn [^js data]
+                   (let [sync-id (.-syncId data)
+                         method  (.-method data)
+                         args    (.-args data)
+                         ret-fn! #(ipc/invoke (str :electron.server/sync! sync-id) %)]
+
+                     (try
+                       (println "invokeLogseqAPI:" method)
+                       (let [^js apis (aget js/window.logseq "api")]
+                         (when-not (aget apis method)
+                           (throw (js/Error. (str "MethodNotExist: " method))))
+                         (-> (p/promise (apply js-invoke apis method args))
+                             (p/then #(ret-fn! %))
+                             (p/catch #(ret-fn! {:error %}))))
+                       (catch js/Error e
+                         (ret-fn! {:error (.-message e)}))))))
+
+  (safe-api-call "syncAPIServerState"
+                 (fn [^js data]
+                   (state/set-state! :electron/server (bean/->clj data)))))
 
 (defn listen!
   []

+ 89 - 59
src/main/frontend/components/block.cljs

@@ -81,7 +81,8 @@
             [reitit.frontend.easy :as rfe]
             [rum.core :as rum]
             [shadow.loader :as loader]
-            [datascript.impl.entity :as e]))
+            [datascript.impl.entity :as e]
+            [logseq.common.path :as path]))
 
 (defn safe-read-string
   ([s]
@@ -155,6 +156,7 @@
 
 (defn- get-file-absolute-path
   [config path]
+  (js/console.error "TODO: buggy path fn")
   (let [path (string/replace path "file:" "")
         block-id (:block/uuid config)
         current-file (and block-id
@@ -198,10 +200,14 @@
                     (if (and (gp-config/local-protocol-asset? src)
                              (file-sync/current-graph-sync-on?))
                       (let [*exist? (::exist? state)
-                            asset-path (gp-config/remove-asset-protocol src)]
+                            ;; special handling for asset:// protocol
+                            ;; Capacitor uses a special URL for assets loading
+                            asset-path (gp-config/remove-asset-protocol src)
+                            asset-path (fs/asset-path-normalize asset-path)]
                         (if (string/blank? asset-path)
                           (reset! *exist? false)
-                          (p/let [exist? (fs/file-or-href-exists? "" asset-path)]
+                          ;; FIXME(andelf): possible bug here
+                          (p/let [exist? (fs/asset-href-exists? asset-path)]
                             (reset! *exist? (boolean exist?))))
                         (assoc state ::asset-path asset-path ::asset-file? true))
                       state)))
@@ -274,7 +280,7 @@
   {:will-unmount (fn [state]
                    (reset! *resizing-image? false)
                    state)}
-  [state config title src metadata full_text local?]
+  [state config title src metadata full-text local?]
   (let [size (get state ::size)]
     (ui/resize-provider
      (ui/resize-consumer
@@ -291,7 +297,7 @@
                        (when (and @size @*resizing-image?)
                          (when-let [block-id (:block/uuid config)]
                            (let [size (bean/->clj @size)]
-                             (editor-handler/resize-image! block-id metadata full_text size))))
+                             (editor-handler/resize-image! block-id metadata full-text size))))
                        (when @*resizing-image?
                             ;; TODO: need a better way to prevent the clicking to edit current block
                          (js/setTimeout #(reset! *resizing-image? false) 200)))
@@ -308,7 +314,7 @@
           :title   title}
          metadata)]
        [:.asset-overlay]
-       (let [image-src (string/replace src #"^assets://" "")]
+       (let [image-src (fs/asset-path-normalize src)]
          [:.asset-action-bar {:aria-hidden "true"}
           ;; the image path bar
           (when (util/electron?)
@@ -323,30 +329,31 @@
                             (js/window.apis.openExternal image-src)))}
              image-src])
           [:.flex
-           [:button.asset-action-btn
-            {:title (t :asset/delete)
-             :tabIndex "-1"
-             :on-mouse-down util/stop
-             :on-click
-             (fn [e]
-               (when-let [block-id (:block/uuid config)]
-                 (let [confirm-fn (ui/make-confirm-modal
-                                   {:title         (t :asset/confirm-delete (.toLocaleLowerCase (t :text/image)))
-                                    :sub-title     (if local? :asset/physical-delete "")
-                                    :sub-checkbox? local?
-                                    :on-confirm    (fn [_e {:keys [close-fn sub-selected]}]
-                                                     (close-fn)
-                                                     (editor-handler/delete-asset-of-block!
-                                                      {:block-id    block-id
-                                                       :local?      local?
-                                                       :delete-local? (and sub-selected (first sub-selected))
-                                                       :repo        (state/get-current-repo)
-                                                       :href        src
-                                                       :title       title
-                                                       :full-text   full_text}))})]
-                   (util/stop e)
-                   (state/set-modal! confirm-fn))))}
-            (ui/icon "trash")]
+           (when-not config/publishing?
+             [:button.asset-action-btn
+              {:title (t :asset/delete)
+               :tabIndex "-1"
+               :on-mouse-down util/stop
+               :on-click
+               (fn [e]
+                 (when-let [block-id (:block/uuid config)]
+                   (let [confirm-fn (ui/make-confirm-modal
+                                     {:title         (t :asset/confirm-delete (.toLocaleLowerCase (t :text/image)))
+                                      :sub-title     (if local? :asset/physical-delete "")
+                                      :sub-checkbox? local?
+                                      :on-confirm    (fn [_e {:keys [close-fn sub-selected]}]
+                                                       (close-fn)
+                                                       (editor-handler/delete-asset-of-block!
+                                                        {:block-id    block-id
+                                                         :local?      local?
+                                                         :delete-local? (and sub-selected (first sub-selected))
+                                                         :repo        (state/get-current-repo)
+                                                         :href        src
+                                                         :title       title
+                                                         :full-text   full-text}))})]
+                     (util/stop e)
+                     (state/set-modal! confirm-fn))))}
+              (ui/icon "trash")])
 
            [:button.asset-action-btn
             {:title         (t :asset/copy)
@@ -382,7 +389,9 @@
       (p/then (editor-handler/make-asset-url href) #(reset! src %)))
 
     (when @src
-      (let [ext (keyword (util/get-file-ext @src))
+      ;; NOTE(andelf): Under nfs context, src might be a bare blob:http://..../uuid URI without ext info
+      (let [ext (keyword (or (util/get-file-ext @src)
+                             (util/get-file-ext href)))
             repo (state/get-current-repo)
             repo-dir (config/get-repo-dir repo)
             path (str repo-dir href)
@@ -391,8 +400,7 @@
                        (when (mobile-util/native-platform?)
                          ;; File URL must be legal, so filename muse be URI-encoded
                          (let [[rel-dir basename] (util/get-dir-and-basename href)
-                               basename (js/encodeURIComponent basename)
-                               asset-url (str repo-dir rel-dir "/" basename)]
+                               asset-url (path/path-join repo-dir rel-dir basename)]
                            (.share Share (clj->js {:url asset-url
                                                    :title "Open file with your favorite app"})))))]
 
@@ -703,7 +711,7 @@
                         (gp-util/url? path)
                         path
 
-                        (util/absolute-path? path)
+                        (path/absolute? path)
                         path
 
                         :else
@@ -1001,7 +1009,7 @@
 
 (defn- relative-assets-path->absolute-path
   [path]
-  (if (util/absolute-path? path)
+  (if (path/absolute? path)
     path
     (.. util/node-path
         (join (config/get-repo-dir (state/get-current-repo))
@@ -1676,7 +1684,7 @@
         (util/stop e))
 
     :else
-    (route-handler/redirect-to-page! uuid)))
+    (when uuid (route-handler/redirect-to-page! uuid))))
 
 (rum/defc block-children < rum/reactive
   [config block children collapsed?]
@@ -2072,6 +2080,7 @@
                                       (remove (property/hidden-properties))
                                       pre-block?
                                       (remove hidden-editable-page-properties))
+            properties-order (distinct properties-order)
             ordered-properties (if (seq properties-order)
                                  (map (fn [k] [k (get properties k)]) properties-order)
                                  properties)]
@@ -2505,7 +2514,7 @@
 
 (rum/defc breadcrumb-fragment
   [config block label opts]
-  [:a {:on-mouse-down
+  [:a {:on-mouse-up
        (fn [e]
          (cond
            (gobj/get e "shiftKey")
@@ -2534,7 +2543,10 @@
            (route-handler/redirect-to-page! (:block/uuid block))))}
    label])
 
-(rum/defc breadcrumb-separator [] [:span.mx-2.opacity-50 "➤"])
+(rum/defc breadcrumb-separator
+  []
+  (ui/icon "chevron-right" {:style {:font-size 20}
+                            :class "opacity-50 mx-1"}))
 
 (defn breadcrumb
   "block-id - uuid of the target block of breadcrumb. page uuid is also acceptable"
@@ -2570,24 +2582,29 @@
                                                                    content)
                                        config (assoc config :block/uuid uuid)]
                                    [block
-                                    (if (seq title)
-                                      (->elem :span (map-inline config title))
-                                      (->elem :div (markup-elements-cp config body)))]))))
+                                    (when title
+                                      (if (seq title)
+                                        (->elem :span (map-inline config title))
+                                        (->elem :div (markup-elements-cp config body))))]))))
               breadcrumb (->> (into [] parents-props)
                               (concat [page-name-props] (when more? [:more]))
                               (filterv identity)
-                              (map (fn [x] (if (vector? x)
+                              (map (fn [x] (if (and (vector? x) (second x))
                                              (let [[block label] x]
                                                (rum/with-key (breadcrumb-fragment config block label opts) (:block/uuid block)))
                                              [:span.opacity-70 "⋯"])))
                               (interpose (breadcrumb-separator)))]
-          [:div.breadcrumb.block-parents.flex-row.flex-1
+          [:div.breadcrumb.block-parents.flex.flex-row.flex-1.flex-wrap.items-center
            {:class (when (seq breadcrumb)
                      (str (when-not (:search? config)
                             " my-2")
                           (when indent?
                             " ml-4")))}
-           breadcrumb (when end-separator? (breadcrumb-separator))])))))
+           (when (and (false? (:top-level? config))
+                      (seq parents))
+             (breadcrumb-separator))
+           breadcrumb
+           (when end-separator? (breadcrumb-separator))])))))
 
 (defn- block-drag-over
   [event uuid top? block-id *move-to]
@@ -3197,14 +3214,17 @@
          [:div.text-sm.mt-2.opacity-90 "No matched result"])])))
 
 (rum/defc query-title
-  [config title]
+  [config title {:keys [result-count]}]
   [:div.custom-query-title.flex.justify-between.w-full
    [:span.title-text (cond
                        (vector? title) title
                        (string? title) (inline-text config
                                                     (get-in config [:block :block/format] :markdown)
                                                     title)
-                       :else title)]])
+                       :else title)]
+   (when result-count
+     [:span.opacity-60.text-sm.ml-2.results-count
+      (str result-count (if (> result-count 1) " results" " result"))])])
 
 (rum/defcs ^:large-vars/cleanup-todo custom-query* < rum/reactive
   (rum/local nil ::query-result)
@@ -3259,11 +3279,14 @@
               [:div.flex.flex-1.flex-row
                (ui/icon "search" {:size 14})
                [:div.ml-1 (str "Live query" (when dsl-page-query? " for pages"))]]
-              (when-not collapsed?'
+              (when (or (not dsl-query?) (not collapsed?'))
                 [:div.flex.flex-row.items-center.fade-in
                  (when (> (count result) 0)
                    [:span.results-count
-                    (str (count result) (if (> (count result) 1) " results" " result"))])
+                    (let [result-count (if (and (not table?) (map? result))
+                                         (apply + (map (comp count val) result))
+                                         (count result))]
+                      (str result-count (if (> result-count 1) " results" " result")))])
 
                  (when (and current-block (not view-f) (nil? table-view?) (not page-list?))
                    (if table?
@@ -3292,14 +3315,16 @@
                                                       :on-mouse-down (fn [e]
                                                                        (util/stop e)
                                                                        (trigger-custom-query! state *query-error))}))]])])
-           (if built-in?
-             (ui/foldable
-              (query-title config title)
-              (fn []
-                (custom-query-inner config q opts))
-              {})
+           (if (or built-in? (not dsl-query?))
+             [:div {:style {:margin-left 2}}
+              (ui/foldable
+               (query-title config title (when built-in? {:result-count (count result)}))
+               (fn []
+                 (custom-query-inner config q opts))
+               {:default-collapsed? collapsed?
+                :title-trigger? true})]
              [:div.bd
-              (query-title config title)
+              (query-title config title {})
               (when-not collapsed?'
                 (custom-query-inner config q opts))])])))))
 
@@ -3684,10 +3709,15 @@
                  [:div
                   (page-cp config page)
                   (when alias? [:span.text-sm.font-medium.opacity-50 " Alias"])]
-                 (for [[parent blocks] parent-blocks]
-                   (rum/with-key
-                     (breadcrumb-with-container blocks config)
-                     (:db/id parent)))
+                 (let [{top-level-blocks true others false} (group-by
+                                                             (fn [b] (= (:db/id page) (:db/id (first b))))
+                                                             parent-blocks)
+                       sorted-parent-blocks (concat top-level-blocks others)]
+                   (for [[parent blocks] sorted-parent-blocks]
+                     (let [top-level? (= (:db/id parent) (:db/id page))]
+                       (rum/with-key
+                         (breadcrumb-with-container blocks (assoc config :top-level? top-level?))
+                         (:db/id parent)))))
                  {:debug-id page
                   :trigger-once? false})])))))]
 

+ 1 - 1
src/main/frontend/components/block.css

@@ -659,4 +659,4 @@ html.is-mac {
       cursor: pointer;
     }
   }
-}
+}

+ 4 - 1
src/main/frontend/components/content.cljs

@@ -20,6 +20,7 @@
             [frontend.state :as state]
             [frontend.ui :as ui]
             [frontend.util :as util]
+            [frontend.modules.shortcut.core :as shortcut]
             [logseq.graph-parser.util :as gp-util]
             [logseq.graph-parser.util.block-ref :as block-ref]
             [frontend.util.url :as url-util]
@@ -85,6 +86,7 @@
               #(swap! *template-including-parent? not))])
 
 (rum/defcs block-template < rum/reactive
+  (shortcut/disable-all-shortcuts)
   (rum/local false ::edit?)
   (rum/local "" ::input)
   {:will-unmount (fn [state]
@@ -400,7 +402,8 @@
                           (and block-id (parse-uuid block-id))
                           (let [block (.closest target ".ls-block")]
                             (when block
-                              (util/select-highlight! [block]))
+                              (state/clear-selection!)
+                              (state/conj-selection-block! block :down))
                             (common-handler/show-custom-context-menu!
                              e
                              (block-context-menu-content target (uuid block-id))))

+ 2 - 1
src/main/frontend/components/export.cljs

@@ -207,5 +207,6 @@
      [:div.mt-4
       (ui/button (if @*copied? "Copied to clipboard!" "Copy to clipboard")
                  :on-click (fn []
-                             (util/copy-to-clipboard! @*content (when (= tp :html) @*content))
+                             (util/copy-to-clipboard! @*content
+                                                      :html (when (= tp :html) @*content))
                              (reset! *copied? true)))]]))

+ 25 - 17
src/main/frontend/components/file.cljs

@@ -5,21 +5,23 @@
             [datascript.core :as d]
             [frontend.components.lazy-editor :as lazy-editor]
             [frontend.components.svg :as svg]
+            [frontend.config :as config]
             [frontend.context.i18n :refer [t]]
             [frontend.date :as date]
             [frontend.db :as db]
+            [frontend.fs :as fs]
             [frontend.handler.export :as export-handler]
             [frontend.state :as state]
-            [frontend.util :as util]
-            [frontend.fs :as fs]
-            [frontend.config :as config]
             [frontend.ui :as ui]
+            [frontend.util :as util]
+            [goog.object :as gobj]
+            [goog.string :as gstring]
             [logseq.graph-parser.config :as gp-config]
             [logseq.graph-parser.util :as gp-util]
-            [goog.object :as gobj]
+            [promesa.core :as p]
             [reitit.frontend.easy :as rfe]
             [rum.core :as rum]
-            [promesa.core :as p]))
+            [logseq.common.path :as path]))
 
 (defn- get-path
   [state]
@@ -29,7 +31,8 @@
 (rum/defc files-all < rum/reactive
   []
   (when-let [current-repo (state/sub :git/current-repo)]
-    (let [files (db/get-files current-repo)
+    (let [files (db/get-files current-repo) ; [[string]]
+          files (sort-by first gstring/intAwareCompare files)
           mobile? (util/mobile?)]
       [:table.table-auto
        [:thead
@@ -70,22 +73,19 @@
    (files-all)
    ])
 
+;; FIXME: misuse of rpath and fpath
 (rum/defcs file-inner < rum/reactive
   {:will-mount (fn [state]
                  (let [*content (atom nil)
                        [path format] (:rum/args state)
                        repo-dir (config/get-repo-dir (state/get-current-repo))
                        [dir path] (cond
-                                    (string/starts-with? path repo-dir)
-                                    [repo-dir (-> (string/replace-first path repo-dir "")
-                                                  (string/replace #"^/+" ""))]
-
-                                    ;; browser-fs
+                                    ;; assume local file, relative path
                                     (not (string/starts-with? path "/"))
                                     [repo-dir path]
 
-                                    :else
-                                    ["" path])]
+                                    :else ;; global file on native platform
+                                    [nil path])]
                    (when (and format (contains? (gp-config/text-formats) format))
                      (p/let [content (fs/read-file dir path)]
                        (reset! *content (or content ""))))
@@ -97,13 +97,21 @@
                    (state/clear-file-component!)
                    state)}
   [state path format]
-  (let [original-name (db/get-file-page path)
+  (let [repo-dir (config/get-repo-dir (state/get-current-repo))
+        rel-path (when (string/starts-with? path repo-dir)
+                   (path/trim-dir-prefix repo-dir path))
+        original-name (db/get-file-page (or path rel-path))
+        in-db? (when-not (path/absolute? path)
+                 (boolean (db/get-file (or path rel-path))))
+        file-fpath (if in-db?
+                     (path/path-join repo-dir path)
+                     path)
         random-id (str (d/squuid))
         content (rum/react (::file-content state))]
     [:div.file {:id (str "file-edit-wrapper-" random-id)
                 :key path}
      [:h1.title
-      [:bdi (js/decodeURI path)]]
+      [:bdi (or original-name rel-path path)]]
      (when original-name
        [:div.text-sm.mb-4.ml-1 "Page: "
         [:a.bg-base-2.p-1.ml-1 {:style {:border-radius 4}
@@ -127,7 +135,7 @@
      (cond
        ;; image type
        (and format (contains? (gp-config/img-formats) format))
-       [:img {:src (util/node-path.join "file://" path)}]
+       [:img {:src (path/path-join "file://" path)}]
 
        (and format
             (contains? (gp-config/text-formats) format)
@@ -135,7 +143,7 @@
        (let [content' (string/trim content)
              mode (util/get-file-ext path)]
          (lazy-editor/editor {:file?     true
-                              :file-path path}
+                              :file-path file-fpath}
                              (str "file-edit-" random-id)
                              {:data-lang mode}
                              content'

+ 48 - 56
src/main/frontend/components/file_sync.cljs

@@ -193,10 +193,10 @@
 (rum/defc sync-now
   []
   (ui/button "Sync now"
-    :class "block cursor-pointer"
-    :small? true
-    :on-click #(async/offer! fs-sync/immediately-local->remote-chan true)
-    :style {:color "#ffffff"}))
+             :class "block cursor-pointer"
+             :small? true
+             :on-click #(async/offer! fs-sync/immediately-local->remote-chan true)
+             :style {:color "#ffffff"}))
 
 (def *last-calculated-time (atom nil))
 
@@ -285,8 +285,7 @@
             (not online?) "Currently having connection issues..."
             idle-&-no-active? "Everything is synced!"
             syncing? "Currently syncing your graph..."
-            :else "Waiting..."
-            )]]
+            :else "Waiting...")]]
         [:div.ar
          (when queuing? (sync-now))]]
 
@@ -395,7 +394,7 @@
                                                        (if (= (:url r) current-repo)
                                                          (dissoc r :GraphUUID :GraphName :remote?)
                                                          r))
-                                                  (state/get-repos)))
+                                                     (state/get-repos)))
                                                (create-remote-graph-fn))
 
                                            (second @graphs-txid) ; sync not started yet
@@ -448,7 +447,7 @@
             (concat
              (map (fn [f] {:title [:div.file-item
                                    {:key (str "downloading-" f)}
-                                   (gp-util/safe-decode-uri-component f)]
+                                   f]
                            :key   (str "downloading-" f)
                            :icon  (if enabled-progress-panel?
                                     (let [progress (get sync-progress f)
@@ -457,8 +456,7 @@
                                                (< percent 100))
                                         (indicator-progress-pie percent)
                                         (ui/icon "circle-check")))
-                                    (ui/icon "arrow-narrow-down"))
-                           }) downloading-files)
+                                    (ui/icon "arrow-narrow-down"))}) downloading-files)
 
              (map (fn [e] (let [icon (case (.-type e)
                                        "add" "plus"
@@ -467,17 +465,13 @@
                                 path (fs-sync/relative-path e)]
                             {:title [:div.file-item
                                      {:key (str "queue-" path)}
-                                     (try
-                                       (gp-util/safe-decode-uri-component path)
-                                       (catch :default _
-                                         (prn "Wrong path: " path)
-                                         path))]
+                                     path]
                              :key   (str "queue-" path)
                              :icon  (ui/icon icon)})) (take 10 queuing-files))
 
              (map (fn [f] {:title [:div.file-item
                                    {:key (str "uploading-" f)}
-                                   (gp-util/safe-decode-uri-component f)]
+                                   f]
                            :key   (str "uploading-" f)
                            :icon  (if enabled-progress-panel?
                                     (let [progress (get sync-progress f)
@@ -486,8 +480,7 @@
                                                (< percent 100))
                                         (indicator-progress-pie percent)
                                         (ui/icon "circle-check")))
-                                    (ui/icon "arrow-up"))
-                           }) uploading-files)
+                                    (ui/icon "arrow-up"))}) uploading-files)
 
              (when (seq history-files)
                (map-indexed (fn [i f] (:time f)
@@ -500,7 +493,7 @@
                                                         (if page-name
                                                           (rfe/push-state :page {:name page-name})
                                                           (rfe/push-state :file {:path full-path})))}
-                                           [:span.file-sync-item (gp-util/safe-decode-uri-component (:path f))]
+                                           [:span.file-sync-item (:path f)]
                                            [:div.opacity-50 (ui/humanity-time-ago (:time f) nil)]]})))
                             (take 10 history-files)))))
 
@@ -531,41 +524,41 @@
                                                          (: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 [])))))
+    "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))
+
+                   {:on-open-dir
+                    (fn [result]
+                      (prn ::on-open-dir result)
+                      (let [empty-dir? (not (seq (:files result)))
+                            root (:path result)]
+                        (cond
+                          (string/blank? root)
+                          (p/rejected (js/Error. nil))  ;; cancel pick a directory
+
+                          empty-dir?
+                          (p/resolved nil)
+
+                          :else ; dir is not empty
+                          (-> (if (util/electron?)
+                                (ipc/ipc :readGraphTxIdInfo root)
+                                (fs-util/read-graphs-txid-info root))
+                              (p/then (fn [^js info]
+                                        (when (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)
+                                            (p/rejected (js/Error. nil))))))))))}) ;; cancel pick a non-empty directory
+                  (p/catch (fn [])))))
 
    [:div.text-xs.opacity-50.px-1.flex-row.flex.items-center.p-2
     (ui/icon "alert-circle")
@@ -754,8 +747,7 @@
                                  ;; Logseq sync available
                                  (maybe-onboarding-show :sync-initiate))
                                (close-fn)
-                               (set-loading? false))
-                             ))]]))
+                               (set-loading? false))))]]))
 
 (rum/defc onboarding-unavailable-file-sync
   [close-fn]

+ 6 - 4
src/main/frontend/components/header.cljs

@@ -47,10 +47,12 @@
     (when-not (or config/publishing?
                   logged?
                   (not sync-enabled?))
-      [:a.button.text-sm.font-medium.block {:on-click #(js/window.open config/LOGIN-URL)}
-       [:span (t :login)]
-       (when loading?
-         [:span.ml-2 (ui/loading "")])])))
+      [:span.flex.space-x-2
+       [:a.button.text-sm.font-medium.block
+        {:on-click #(state/pub-event! [:user/login])}
+        [:span (t :login)]
+        (when loading?
+          [:span.ml-2 (ui/loading "")])]])))
 
 (rum/defc publish < rum/reactive
   < {:key-fn #(identity "publish-button")}

+ 11 - 11
src/main/frontend/components/page.cljs

@@ -315,7 +315,7 @@
                          repo
                          (:db/id page)
                          :page))
-                      (when (and (not hls-page?) (not fmt-journal?))
+                      (when (and (not hls-page?) (not fmt-journal?) (not config/publishing?))
                         (reset! *input-value (if untitled? "" old-name))
                         (reset! *edit? true))))}
        (when (not= icon "") [:span.page-icon icon])
@@ -410,7 +410,8 @@
                   (= page-name (util/page-name-sanity-lc (date/journal-name))))
           *control-show? (::control-show? state)
           *all-collapsed? (::all-collapsed? state)
-          *current-block-page (::current-page state)]
+          *current-block-page (::current-page state)
+          block-or-whiteboard? (or block? whiteboard?)]
       [:div.flex-1.page.relative
        (merge (if (seq (:block/tags page))
                 (let [page-names (model/get-page-names-by-ids (map :db/id (:block/tags page)))]
@@ -467,21 +468,20 @@
          (tagged-pages repo page-name))
 
        ;; referenced blocks
-       (when-not (or block? whiteboard?)
+       (when-not block-or-whiteboard?
          [:div {:key "page-references"}
           (rum/with-key
             (reference/references route-page-name)
             (str route-page-name "-refs"))])
 
-       (let [block-or-whiteboard? (or block? whiteboard?)]
-         (when-not block-or-whiteboard?
-           (when (not journal?)
-             (hierarchy/structures route-page-name)))
+       (when-not block-or-whiteboard?
+         (when (not journal?)
+           (hierarchy/structures route-page-name)))
 
-         (when-not block-or-whiteboard?
-           (when-not sidebar?
-             [:div {:key "page-unlinked-references"}
-              (reference/unlinked-references route-page-name)])))])))
+       (when-not block-or-whiteboard?
+         (when-not sidebar?
+           [:div {:key "page-unlinked-references"}
+            (reference/unlinked-references route-page-name)]))])))
 
 (defonce layout (atom [js/window.innerWidth js/window.innerHeight]))
 

+ 12 - 9
src/main/frontend/components/page_menu.cljs

@@ -16,7 +16,8 @@
             [electron.ipc :as ipc]
             [frontend.config :as config]
             [frontend.handler.user :as user-handler]
-            [frontend.handler.file-sync :as file-sync-handler]))
+            [frontend.handler.file-sync :as file-sync-handler]
+            [logseq.common.path :as path]))
 
 (defn- delete-page!
   [page-name]
@@ -72,7 +73,7 @@
           favorited? (contains? (set (map util/page-name-sanity-lc favorites))
                                 page-name)
           developer-mode? (state/sub [:ui/developer-mode?])
-          file-path (when (util/electron?) (page-util/get-page-file-path page-name))
+          file-rpath (when (util/electron?) (page-util/get-page-file-rpath page-name))
           _ (state/sub :auth/id-token)
           file-sync-graph-uuid (and (user-handler/logged-in?)
                                     (file-sync-handler/enable-sync?)
@@ -125,11 +126,13 @@
           ;; (such as open-in-finder & open-with-default-app) into a sub-menu of
           ;; this one. However this component doesn't yet exist. PRs are welcome!
           ;; Details: https://github.com/logseq/logseq/pull/3003#issuecomment-952820676
-          (when file-path
-            [{:title   (t :page/open-in-finder)
-              :options {:on-click #(js/window.apis.showItemInFolder file-path)}}
-             {:title   (t :page/open-with-default-app)
-              :options {:on-click #(js/window.apis.openPath file-path)}}])
+          (when file-rpath
+            (let [repo-dir (config/get-repo-dir repo)
+                  file-fpath (path/path-join repo-dir file-rpath)]
+              [{:title   (t :page/open-in-finder)
+                :options {:on-click #(js/window.apis.showItemInFolder file-fpath)}}
+               {:title   (t :page/open-with-default-app)
+                :options {:on-click #(js/window.apis.openPath file-fpath)}}]))
 
           (when (state/get-current-page)
             {:title   (t :export-page)
@@ -146,12 +149,12 @@
                           (if public? false true))
                          (state/close-modal!))}})
 
-          (when (and (util/electron?) file-path
+          (when (and (util/electron?) file-rpath
                      (not (file-sync-handler/synced-file-graph? repo)))
             {:title   (t :page/open-backup-directory)
              :options {:on-click
                        (fn []
-                         (ipc/ipc "openFileBackupDir" (config/get-local-dir repo) file-path))}})
+                         (ipc/ipc "openFileBackupDir" (config/get-local-dir repo) file-rpath))}})
 
           (when config/lsp-enabled?
             (for [[_ {:keys [label] :as cmd} action pid] (state/get-plugins-commands-with-type :page-menu-item)]

+ 41 - 7
src/main/frontend/components/plugins.cljs

@@ -4,6 +4,7 @@
             [cljs-bean.core :as bean]
             [frontend.context.i18n :refer [t]]
             [frontend.ui :as ui]
+            [frontend.rum :as frontend-rum]
             [frontend.handler.ui :as ui-handler]
             [frontend.handler.plugin-config :as plugin-config-handler]
             [frontend.handler.common.plugin :as plugin-common-handler]
@@ -1024,6 +1025,37 @@
       :icon    (ui/icon "adjustments")}])
    {:trigger-class "toolbar-plugins-manager-trigger"}))
 
+(rum/defc header-ui-items-list-wrap
+  [children]
+  (let [*wrap-el (rum/use-ref nil)
+        [right-sidebar-resized] (frontend-rum/use-atom ui-handler/*right-sidebar-resized-at)]
+
+    (rum/use-effect!
+      (fn []
+        (when-let [^js wrap-el (rum/deref *wrap-el)]
+          (let [^js header-el       (.closest wrap-el ".cp__header")
+                ^js header-l        (.querySelector header-el "* > .l")
+                ^js header-r        (.querySelector header-el "* > .r")
+                set-max-width!      #(when (number? %) (set! (.-maxWidth (.-style wrap-el)) (str % "px")))
+                calc-wrap-max-width #(let [width-l (.-offsetWidth header-l)
+                                           width-t (-> (js/document.querySelector "#main-content-container") (.-offsetWidth))
+                                           children (to-array (.-children header-r))
+                                           width-c'  (reduce (fn [acc ^js e]
+                                                              (when (some-> e (.-classList) (.contains "ui-items-container") (not))
+                                                                (+ acc (or (.-offsetWidth e) 0)))) 0 children)]
+                                       (when-let [width-t (and (number? width-t)
+                                                               (if-not (state/get-left-sidebar-open?)
+                                                                 (- width-t width-l) width-t))]
+                                         (set-max-width! (max (- width-t width-c' 100) 76))))]
+            (.addEventListener js/window "resize" calc-wrap-max-width)
+            (js/setTimeout calc-wrap-max-width 16)
+            #(.removeEventListener js/window "resize" calc-wrap-max-width))))
+      [right-sidebar-resized])
+
+    [:div.list-wrap
+     {:ref *wrap-el}
+     children]))
+
 (rum/defcs hook-ui-items < rum/reactive
                            < {:key-fn #(identity "plugin-hook-items")}
                            "type of :toolbar, :pagebar"
@@ -1044,12 +1076,13 @@
                                    items)
                               items))]
 
-        [:div {:class     (str "ui-items-container")
-               :data-type (name type)}
-         (conj (for [[_ {:keys [key pinned?] :as opts} pid] items]
-                 (when (or (not toolbar?)
-                           (not (set? pinned-items)) pinned?)
-                   (rum/with-key (ui-item-renderer pid type opts) key))))
+        [:div.ui-items-container
+         {:data-type (name type)}
+         (header-ui-items-list-wrap
+           (for [[_ {:keys [key pinned?] :as opts} pid] items]
+             (when (or (not toolbar?)
+                       (not (set? pinned-items)) pinned?)
+               (rum/with-key (ui-item-renderer pid type opts) key))))
 
          ;; manage plugin buttons
          (when toolbar?
@@ -1143,7 +1176,8 @@
   [{:keys [t current-repo db-restoring? nfs-granted?]}]
   (rum/use-effect!
    (fn []
-     (when (and (not db-restoring?)
+     (when (and (not-empty current-repo)
+                (not db-restoring?)
                 (or (not util/nfs?) nfs-granted?))
        (ui-handler/exec-js-if-exists-&-allowed! t)))
    [current-repo db-restoring? nfs-granted?])

+ 4 - 0
src/main/frontend/components/plugins.css

@@ -814,6 +814,10 @@
   &[data-type=toolbar] {
     @apply flex items-center;
 
+    > .list-wrap {
+      @apply flex items-center flex-nowrap overflow-x-hidden transition-[max-width];
+    }
+
     > .injected-ui-item-toolbar {
       @apply hover:opacity-100 transition-opacity;
     }

+ 19 - 7
src/main/frontend/components/query/builder.cljs

@@ -270,8 +270,12 @@
       (page-ref/->page-ref (second clause))
 
       (= (keyword f) :page-tags)
-      (if (string? (second clause))
+      (cond
+        (string? (second clause))
         (str "#" (second clause))
+        (symbol? (second clause))
+        (str "#" (str (second clause)))
+        :else
         (str "#" (second (second clause))))
 
       (contains? #{:property :page-property} (keyword f))
@@ -287,7 +291,15 @@
              (last clause)))
 
       (= (keyword f) :between)
-      (str "between: " (second (second clause)) " - " (second (last clause)))
+      (let [start (if (or (keyword? (second clause))
+                          (symbol? (second clause)))
+                    (name (second clause))
+                    (second (second clause)))
+            end (if (or (keyword? (last clause))
+                        (symbol? (last clause)))
+                  (name (last  clause))
+                  (second (last clause)))]
+        (str "between: " start " ~ " end))
 
       (contains? #{:task :priority} (keyword f))
       (str (name f) ": "
@@ -312,7 +324,7 @@
        [:a.flex.text-sm.query-clause {:on-click toggle-fn}
         clause]
 
-       [:div.flex.flex-row.items-center.gap-2.p-1.rounded.border
+       [:div.flex.flex-row.items-center.gap-2.p-1.rounded.border.query-clause-btn
         [:a.flex.query-clause {:on-click toggle-fn}
          (dsl-human-output clause)]]))
    (fn [{:keys [toggle-fn]}]
@@ -368,9 +380,9 @@
      (let [kind (keyword (first clause))]
        (if (query-builder/operators-set kind)
          [:div.operator-clause.flex.flex-row.items-center {:data-level (count loc)}
-          [:div.text-4xl.mr-1.font-thin "("]
+          [:div.clause-bracket "("]
           (clauses-group *tree *find (conj loc 0) kind (rest clause))
-          [:div.text-4xl.ml-1.font-thin ")"]]
+          [:div.clause-bracket ")"]]
          (clause-inner *tree loc clause)))]))
 
 (rum/defc clauses-group
@@ -378,7 +390,7 @@
   (let [parens? (and (= loc [0])
                      (> (count clauses) 1))]
     [:div.clauses-group
-     (when parens? [:div.text-4xl.mr-1.font-thin "("])
+     (when parens? [:div.clause-bracket "("])
      (when-not (and (= loc [0])
                     (= kind :and)
                     (<= (count clauses) 1))
@@ -390,7 +402,7 @@
                     (clause *tree *find (update loc (dec (count loc)) #(+ % i 1)) item))
                   clauses)
 
-     (when parens? [:div.text-4xl.ml-1.font-thin ")"])
+     (when parens? [:div.clause-bracket ")"])
 
      (when (not= loc [0])
        (add-filter *find *tree loc []))]))

+ 10 - 1
src/main/frontend/components/query/builder.css

@@ -29,7 +29,7 @@
     }
 
     .clauses-group {
-        @apply flex flex-row gap-1 flex-wrap items-center text-sm;
+        @apply flex flex-row gap-2 flex-wrap items-center text-sm;
     }
 
     a.query-clause, a.add-filter {
@@ -43,4 +43,13 @@
     .filter-item select {
         border: none;
     }
+
+    .clause-bracket {
+        @apply text-4xl ml-1 font-thin opacity-30;
+        font-family: "Inter";
+    }
+
+    .query-clause-btn {
+        border-color: var(--ls-border-color);
+    }
 }

+ 47 - 34
src/main/frontend/components/query_table.cljs

@@ -93,7 +93,7 @@
   (let [keys (->> (distinct (mapcat keys (map :block/properties result)))
                   (remove (property/built-in-properties))
                   (remove #{:template}))
-        keys (if page? (cons :page keys) (cons :block keys))
+        keys (if page? (cons :page keys) (concat '(:block :page) keys))
         keys (if page? (distinct (concat keys [:created-at :updated-at])) keys)]
     keys))
 
@@ -112,7 +112,41 @@
                included-columns)
        columns))))
 
-;; Table rows are called items
+(defn- build-column-value
+  "Builds a column's tuple value for a query table given a row, column and
+  options"
+  [row column {:keys [page? ->elem map-inline config]}]
+  (case column
+    :page
+    [:string (if page?
+               (or (:block/original-name row)
+                   (:block/name row))
+               (or (get-in row [:block/page :block/original-name])
+                   (get-in row [:block/page :block/name])))]
+
+    :block       ; block title
+    (let [content (:block/content row)
+          {:block/keys [title]} (block/parse-title-and-body
+                                 (:block/uuid row)
+                                 (:block/format row)
+                                 (:block/pre-block? row)
+                                 content)]
+      (if (seq title)
+        [:element (->elem :div (map-inline config title))]
+        [:string content]))
+
+    :created-at
+    [:string (when-let [created-at (:block/created-at row)]
+               (date/int->local-time-2 created-at))]
+
+    :updated-at
+    [:string (when-let [updated-at (:block/updated-at row)]
+               (date/int->local-time-2 updated-at))]
+
+    [:string (or (get-in row [:block/properties-text-values column])
+                 ;; Fallback to property relationships for page blocks
+                 (get-in row [:block/properties column]))]))
+
 (rum/defcs result-table < rum/reactive
   (rum/local false ::select?)
   (rum/local false ::mouse-down?)
@@ -145,37 +179,16 @@
                              (name column))]
               (sortable-title title column sort-state (:block/uuid current-block))))]]
         [:tbody
-         (for [item result']
-           (let [format (:block/format item)]
+         (for [row result']
+           (let [format (:block/format row)]
              [:tr.cursor
               (for [column columns]
-                (let [value (case column
-                              :page
-                              [:string (or (:block/original-name item)
-                                           (:block/name item))]
-
-                              :block       ; block title
-                              (let [content (:block/content item)
-                                    {:block/keys [title]} (block/parse-title-and-body
-                                                           (:block/uuid item)
-                                                           (:block/format item)
-                                                           (:block/pre-block? item)
-                                                           content)]
-                                (if (seq title)
-                                  [:element (->elem :div (map-inline config title))]
-                                  [:string content]))
-
-                              :created-at
-                              [:string (when-let [created-at (:block/created-at item)]
-                                         (date/int->local-time-2 created-at))]
-
-                              :updated-at
-                              [:string (when-let [updated-at (:block/updated-at item)]
-                                         (date/int->local-time-2 updated-at))]
-
-                              [:string (or (get-in item [:block/properties-text-values column])
-                                           ;; Fallback to property relationships for page blocks
-                                           (get-in item [:block/properties column]))])]
+                (let [value (build-column-value row
+                                                column
+                                                {:page? page?
+                                                 :->elem ->elem
+                                                 :map-inline map-inline
+                                                 :config config})]
                   [:td.whitespace-nowrap {:on-mouse-down (fn []
                                                            (reset! *mouse-down? true)
                                                            (reset! select? false))
@@ -184,7 +197,7 @@
                                                          (when (and @*mouse-down? (not @select?))
                                                            (state/sidebar-add-block!
                                                             (state/get-current-repo)
-                                                            (:db/id item)
+                                                            (:db/id row)
                                                             :block-ref)
                                                            (reset! *mouse-down? false)))}
                    (when value
@@ -192,8 +205,8 @@
                        (second value)
                        (let [value (second value)]
                          (if (coll? value)
-                           (let [vals (for [item value]
-                                        (page-cp {} {:block/name item}))]
+                           (let [vals (for [row value]
+                                        (page-cp {} {:block/name row}))]
                              (interpose [:span ", "] vals))
                            (cond
                              (boolean? value) (str value)

+ 10 - 13
src/main/frontend/components/repo.cljs

@@ -38,7 +38,7 @@
                graph-name (text-util/get-graph-name-from-path local-dir)]
            [:a.flex.items-center {:title    local-dir
                                   :on-click #(on-click graph)}
-            [:span graph-name (and GraphName [:strong.px-1 "(" GraphName ")"])]
+            [:span graph-name (when GraphName [:strong.px-1 "(" GraphName ")"])]
             (when remote? [:strong.pr-1.flex.items-center (ui/icon "cloud")])])
 
          [:a.flex.items-center {:title    GraphUUID
@@ -47,6 +47,7 @@
           (when remote? [:strong.pl-1.flex.items-center (ui/icon "cloud")])])])))
 
 (rum/defc repos-inner
+  "Graph list in `All graphs` page"
   [repos]
   (for [{:keys [url remote? GraphUUID GraphName] :as repo} repos
         :let [only-cloud? (and remote? (nil? url))]]
@@ -164,9 +165,7 @@
                        (when (and nfs-repo?
                                   (not= current-repo config/local-repo)
                                   (or (nfs-handler/supported?)
-                                      (mobile-util/native-platform?))
-                                  ;; Disable refresh temporally for nfs
-                                  (not util/nfs?))
+                                      (mobile-util/native-platform?)))
                          {:title (t :sync-from-local-files)
                           :hover-detail (t :sync-from-local-files-detail)
                           :options {:on-click #(state/pub-event! [:graph/ask-for-re-fresh])}}))
@@ -184,7 +183,7 @@
     (->>
      (concat repo-links
              [(when (seq repo-links) {:hr true})
-              (if (or (nfs-handler/supported?) (mobile-util/native-platform?)) 
+              (if (or (nfs-handler/supported?) (mobile-util/native-platform?))
                 {:title (t :new-graph) :options {:on-click #(state/pub-event! [:graph/setup-a-repo])}}
                 {:title (t :new-graph) :options {:href (rfe/href :repos)}}) ;; Brings to the repos page for showing fallback message
               {:title (t :all-graphs) :options {:href (rfe/href :repos)}}
@@ -207,19 +206,17 @@
                     (repo-handler/combine-local-&-remote-graphs repos remotes) repos)
             links (repos-dropdown-links repos current-repo multiple-windows?)
             render-content (fn [{:keys [toggle-fn]}]
-                             (let [valid-remotes-but-locals? (and (seq repos) (not (some :url repos)))
-                                   remote? (when-not valid-remotes-but-locals?
-                                             (:remote? (first (filter #(= current-repo (:url %)) repos))))
-                                   repo-path (if-not valid-remotes-but-locals?
-                                               (db/get-repo-name current-repo) "")
-                                   short-repo-name (if-not valid-remotes-but-locals?
-                                                     (db/get-short-repo-name repo-path) "Select a Graph")]
+                             (let [remote? (:remote? (first (filter #(= current-repo (:url %)) repos)))
+                                   repo-name (db/get-repo-name current-repo)
+                                   short-repo-name (if repo-name
+                                                    (db/get-short-repo-name repo-name)
+                                                    "Select a Graph")]
                                [:a.item.group.flex.items-center.p-2.text-sm.font-medium.rounded-md
 
                                 {:on-click (fn []
                                              (check-multiple-windows? state)
                                              (toggle-fn))
-                                 :title    repo-path}       ;; show full path on hover
+                                 :title    repo-name}       ;; show full path on hover
                                 [:span.flex.relative
                                  {:style {:top 1}}
                                  (ui/icon "database" {:size 16 :id "database-icon"})]

+ 11 - 1
src/main/frontend/components/right_sidebar.cljs

@@ -177,7 +177,9 @@
         max-ratio 0.7
         keyboard-step 5
         add-resizing-class #(.. js/document.documentElement -classList (add "is-resizing-buf"))
-        remove-resizing-class #(.. js/document.documentElement -classList (remove "is-resizing-buf"))
+        remove-resizing-class (fn []
+                                (.. js/document.documentElement -classList (remove "is-resizing-buf"))
+                                (reset! ui-handler/*right-sidebar-resized-at (js/Date.now)))
         set-width! (fn [ratio element]
                      (when (and el-ref element)
                        (let [width (str (* ratio 100) "%")]
@@ -233,6 +235,14 @@
              (.on "keyup" remove-resizing-class)))
        #())
      [])
+
+    (rum/use-effect!
+      (fn []
+        ;; sidebar animation duration
+        (js/setTimeout
+          #(reset! ui-handler/*right-sidebar-resized-at (js/Date.now)) 300))
+      [sidebar-open?])
+
     [:.resizer {:ref el-ref
                 :role "separator"
                 :aria-orientation "vertical"

+ 4 - 5
src/main/frontend/components/settings.cljs

@@ -717,8 +717,7 @@
   (ui/toggle enabled?
              (fn []
                (let [value (not enabled?)]
-                 (when (user-handler/feature-available? :whiteboard)
-                   (config-handler/set-config! :feature/enable-whiteboards? value))))
+                 (config-handler/set-config! :feature/enable-whiteboards? value)))
              true))
 
 (defn whiteboards-switcher-row [enabled?]
@@ -749,6 +748,7 @@
             :on-key-press  (fn [e]
                              (when (= "Enter" (util/ekey e))
                                (update-home-page e)))}]]]])
+     (whiteboards-switcher-row enable-whiteboards?)
      (when (and (util/electron?) config/feature-plugin-system-on?)
        (plugin-system-switcher-row))
      (when (and (util/electron?) (state/developer-mode?))
@@ -769,7 +769,7 @@
                                   :icon "login"
                                   :on-click (fn []
                                               (state/close-settings!)
-                                              (js/window.open config/LOGIN-URL))})
+                                              (state/pub-event! [:user/login]))})
            [:p.text-sm.opacity-50 (t :settings-page/login-prompt)]])])
 
      (when-not web-platform?
@@ -784,8 +784,7 @@
           [:a.mx-1 {:href "https://blog.logseq.com/how-to-setup-and-use-logseq-sync/"
                     :target "_blank"}
            "here"]
-          "for instructions on how to set up and use Sync."]
-         (whiteboards-switcher-row enable-whiteboards?)]])
+          "for instructions on how to set up and use Sync."]]])
 
      ;; (when-not web-platform?
      ;;   [:<>

+ 11 - 12
src/main/frontend/components/sidebar.cljs

@@ -37,10 +37,10 @@
             [frontend.util.cursor :as cursor]
             [goog.dom :as gdom]
             [goog.object :as gobj]
-            [logseq.graph-parser.util :as gp-util]
             [react-draggable]
             [reitit.frontend.easy :as rfe]
-            [rum.core :as rum]))
+            [rum.core :as rum]
+            [logseq.common.path :as path]))
 
 (rum/defc nav-content-item < rum/reactive
   [name {:keys [class]} child]
@@ -368,11 +368,12 @@
 
          (when enable-whiteboards?
            (sidebar-item
-            {:class           "whiteboard"
-             :title           (t :right-side-bar/whiteboards)
-             :href            (rfe/href :whiteboards)
-             :active          (and (not srs-open?) (#{:whiteboard :whiteboards} route-name))
-             :icon            "whiteboard"
+            {:class            "whiteboard"
+             :title            (t :right-side-bar/whiteboards)
+             :href             (rfe/href :whiteboards)
+             :on-click-handler (fn [_e] (whiteboard-handler/onboarding-show))
+             :active           (and (not srs-open?) (#{:whiteboard :whiteboards} route-name))
+             :icon             "whiteboard"
              :icon-extension? true}))
 
          (when (state/enable-flashcards? (state/get-current-repo))
@@ -560,11 +561,9 @@
   (let [finished (or (:finished state) 0)
         total (:total state)
         width (js/Math.round (* (.toFixed (/ finished total) 2) 100))
-        file-basename (util/node-path.basename
-                       (:current-parsing-file state))
-        display-filename (if (mobile-util/native-platform?)
-                           (gp-util/safe-decode-uri-component file-basename)
-                           file-basename)
+        display-filename (some-> (:current-parsing-file state)
+                                 not-empty
+                                 path/filename)
         left-label [:div.flex.flex-row.font-bold
                     (t :parsing-files)
                     [:div.hidden.md:flex.flex-row

+ 56 - 0
src/main/frontend/components/user/config.js

@@ -0,0 +1,56 @@
+import {Amplify} from '@aws-amplify/core';
+
+Amplify.configure({
+    Auth: {
+        // REQUIRED only for Federated Authentication - Amazon Cognito Identity Pool ID
+        // identityPoolId: 'XX-XXXX-X:XXXXXXXX-XXXX-1234-abcd-1234567890ab',
+
+        // REQUIRED - Amazon Cognito Region
+        region: 'us-east-1',
+
+        // OPTIONAL - Amazon Cognito Federated Identity Pool Region
+        // Required only if it's different from Amazon Cognito Region
+        // identityPoolRegion: 'XX-XXXX-X',
+
+        // OPTIONAL - Amazon Cognito User Pool ID
+        userPoolId: 'us-east-1_ldvDmC9Fe',
+
+        // OPTIONAL - Amazon Cognito Web Client ID (26-char alphanumeric string)
+        userPoolWebClientId: '41m82unjghlea984vjpk887qcr',
+
+        // OPTIONAL - Enforce user authentication prior to accessing AWS resources or not
+        // mandatorySignIn: false,
+
+        // OPTIONAL - This is used when autoSignIn is enabled for Auth.signUp
+        // 'code' is used for Auth.confirmSignUp, 'link' is used for email link verification
+        // signUpVerificationMethod: 'code', // 'code' | 'link'
+
+        // OPTIONAL - Configuration for cookie storage
+        // Note: if the secure flag is set to true, then the cookie transmission requires a secure protocol
+        cookieStorage: {
+            domain: "localhost",
+            path: "/",
+            expires: 365,
+            sameSite: "strict",
+            secure: true,
+        },
+
+        // OPTIONAL - customized storage object
+        // storage: MyStorage,
+
+        // OPTIONAL - Manually set the authentication flow type. Default is 'USER_SRP_AUTH'
+        authenticationFlowType: 'USER_SRP_AUTH',
+
+        //
+        // // OPTIONAL - Manually set key value pairs that can be passed to Cognito Lambda Triggers
+        // clientMetadata: {myCustomKey: 'myCustomValue'},
+        //
+        // // OPTIONAL - Hosted UI configuration
+        // oauth: {
+        //     domain: 'your_cognito_domain',
+        //     scope: ['phone', 'email', 'profile', 'openid', 'aws.cognito.signin.user.admin'],
+        //     redirectSignIn: 'http://localhost:3000/',
+        //     redirectSignOut: 'http://localhost:3000/',
+        //     responseType: 'code' // or 'token', note that REFRESH token will only be generated when the responseType is code
+    }
+});

+ 87 - 0
src/main/frontend/components/user/login.cljs

@@ -0,0 +1,87 @@
+(ns frontend.components.user.login
+  (:require [rum.core :as rum]
+            [frontend.rum :refer [adapt-class]]
+            [frontend.modules.shortcut.core :as shortcut]
+            [frontend.handler.user :as user]
+            [cljs-bean.core :as bean]
+            [frontend.handler.notification :as notification]
+            [frontend.state :as state]
+            [frontend.config :as config]))
+
+(declare setupAuthConfigure! LSAuthenticator)
+
+(defn sign-out!
+  []
+  (try (.signOut js/LSAmplify.Auth)
+       (catch :default e (js/console.warn e))))
+
+(defn- setup-configure!
+  []
+  #_:clj-kondo/ignore
+  (def setupAuthConfigure! (.-setupAuthConfigure js/LSAmplify))
+  #_:clj-kondo/ignore
+  (def LSAuthenticator
+    (adapt-class (.-LSAuthenticator js/LSAmplify)))
+
+  (.setLanguage js/LSAmplify.I18n (or (:preferred-language @state/state) "en"))
+  (setupAuthConfigure!
+    #js {:region              config/REGION,
+         :userPoolId          config/USER-POOL-ID,
+         :userPoolWebClientId config/COGNITO-CLIENT-ID,
+         :identityPoolId      config/IDENTITY-POOL-ID,
+         :oauthDomain         config/OAUTH-DOMAIN}))
+
+(rum/defc user-pane
+  [_sign-out! user]
+  (let [session  (:signInUserSession user)
+        username (:username user)]
+
+    (rum/use-effect!
+      (fn []
+        (when session
+          (user/login-callback session)
+          (notification/show! (str "Hi, " username " :)") :success)
+          (state/close-modal!)))
+      [])
+
+    nil))
+
+(rum/defc page-impl
+  []
+  (let [[ready?, set-ready?] (rum/use-state false)
+        *ref-el (rum/use-ref nil)]
+
+    (rum/use-effect!
+      (fn [] (setup-configure!)
+        (set-ready? true)
+        (when-let [^js el (rum/deref *ref-el)]
+          (js/setTimeout #(some-> (.querySelector el "input[name=username]")
+                                  (.focus)) 100))) [])
+
+    [:div.cp__user-login
+     {:ref *ref-el}
+     (when ready?
+       (LSAuthenticator
+         {:termsLink "https://blog.logseq.com/terms/"}
+         (fn [^js op]
+           (let [sign-out!      (.-signOut op)
+                 ^js user-proxy (.-user op)
+                 ^js user       (try (js/JSON.parse (js/JSON.stringify user-proxy))
+                                     (catch js/Error e
+                                       (js/console.error "Error: Amplify user payload:" e)))
+                 user'          (bean/->clj user)]
+             (user-pane sign-out! user')))))]))
+
+(rum/defcs page <
+  (shortcut/disable-all-shortcuts)
+  [_state]
+  (page-impl))
+
+(defn open-login-modal!
+  []
+  (state/set-modal!
+    (fn [_close] (page))
+    {:close-btn?      true
+     :label           "user-login"
+     :close-backdrop? false
+     :center?         true}))

+ 141 - 0
src/main/frontend/components/user/login.css

@@ -0,0 +1,141 @@
+.cp__user-login {
+  [data-amplify-authenticator] [data-amplify-router] {
+    --amplify-components-authenticator-router-background-color: var(--ls-primary-background-color);
+    --amplify-components-field-label-color: var(--ls-primary-text-color);
+    --amplify-components-authenticator-router-border-color: var(--ls-border-color);
+    --amplify-components-tabs-item-color: var(--ls-primary-text-color);
+    --amplify-components-tabs-item-active-color: var(--ls-primary-text-color);
+    --amplify-components-tabs-item-hover-color: var(--ls-primary-text-color);
+    --amplify-components-tabs-item-active-border-color: var(--ls-tertiary-background-color);
+    --amplify-components-tabs-border-width: 0;
+    --amplify-components-authenticator-state-inactive-background-color: var(--ls-tertiary-background-color);
+    --amplify-components-tabs-item-active-background-color: var(--ls-primary-background-color);
+    --amplify-components-button-border-color: var(--ls-border-color);
+    --amplify-components-textfield-border-color: var(--ls-border-color);
+    --amplify-components-button-primary-background-color: var(--color-indigo-600);
+    --amplify-components-text-color: var(--ls-primary-text-color);
+    --amplify-components-button-hover-background-color: var(--ls-primary-background-color);
+    --amplify-components-button-border-width: 0;
+    --amplify-internal-button-loading-background-color: var(--ls-header-button-background);
+    --amplify-components-authenticator-router-border-width: 1px;
+    --amplify-components-button-color: var(--ls-primary-text-color);
+    --amplify-components-divider-label-background-color: var(--ls-primary-background-color);
+    --amplify-components-divider-label-color: var(--ls-primary-text-color);
+    --amplify-components-heading-color: var(--ls-primary-text-color);
+    --amplify-components-button-link-hover-background-color: transparent;
+    --amplify-components-button-link-active-background-color: transparent;
+    --amplify-components-textfield-color: var(--ls-primary-text-color);
+    --amplify-components-checkbox-icon-background-color: var(--color-indigo-600);
+  }
+
+  [data-amplify-authenticator] [data-amplify-router] {
+    @apply overflow-hidden rounded-[6px] shadow-2xl;
+  }
+
+  [data-amplify-authenticator] [data-amplify-container] {
+    place-self: unset;
+  }
+
+  [data-amplify-authenticator] [data-amplify-form] {
+    @apply px-4 py-2;
+
+    @screen sm {
+      @apply px-6 py-4;
+    }
+  }
+}
+
+@media (min-width: 30rem) {
+  [data-amplify-authenticator] [data-amplify-container] {
+    width: 100%;
+  }
+}
+
+.ui__modal[label=user-login] {
+  @apply flex items-center top-0;
+
+  .ui__modal-panel {
+    transition: transform .3s;
+    transform: translateY(-50px);
+  }
+
+  .panel-content {
+    @apply p-0 min-w-fit relative max-w-[600px] sm:max-w-[90vw] sm:w-[500px];
+  }
+
+  .ui__modal-close-wrap {
+    @apply z-10 top-[4px];
+  }
+}
+
+.cp__user {
+  &-login {
+    ::placeholder {
+      color: var(--ls-primary-text-color);
+      opacity: .3;
+    }
+
+    [data-indicator-position=top] > .amplify-tabs-item {
+      margin-top: 0;
+    }
+
+    .amplify-tabs-item {
+      transition: none;
+
+      &:focus {
+        color: var(--ls-primary-text-color);
+      }
+
+      &:hover {
+        opacity: .9;
+      }
+    }
+
+    .amplify-field-group {
+      @apply relative;
+
+      .amplify-button {
+        color: var(--ls-primary-text-color);
+
+        &:active, &:hover, &:focus {
+          background-color: transparent;
+        }
+      }
+    }
+
+    .amplify-field-group__outer-end {
+      @apply absolute right-0 top-0 bottom-0;
+    }
+
+    .amplify-input {
+      border-radius: 4px !important;
+    }
+
+    .amplify-checkboxfield {
+      @apply text-sm;
+
+      .amplify-field__error-message {
+        color: var(--ls-primary-text-color);
+        opacity: .4;
+      }
+    }
+
+    .amplify-text--error {
+      color: var(--ls-error-text-color);
+    }
+  }
+}
+
+html {
+  &.is-mobile .ui__modal[label=user-login] .panel-content {
+    @apply pt-0;
+  }
+
+  &.has-mobile-keyboard .ui__modal[label=user-login] {
+    transform: translateY(calc(-50px - 6%));
+  }
+}
+
+.federated-sign-in-container {
+  display: none;
+}

+ 7 - 22
src/main/frontend/components/whiteboard.cljs

@@ -10,19 +10,17 @@
             [frontend.db.model :as model]
             [frontend.handler.common :as common-handler]
             [frontend.handler.route :as route-handler]
-            [frontend.handler.user :as user-handler]
             [frontend.handler.config :as config-handler]
             [frontend.handler.whiteboard :as whiteboard-handler]
             [frontend.rum :refer [use-bounding-client-rect use-breakpoint
                                   use-click-outside]]
             [frontend.state :as state]
-            [frontend.storage :as storage]
-            [frontend.config :as config]
             [frontend.ui :as ui]
             [frontend.util :as util]
             [promesa.core :as p]
             [rum.core :as rum]
-            [shadow.loader :as loader]))
+            [shadow.loader :as loader]
+            [frontend.config :as config]))
 
 (defonce tldraw-loaded? (atom false))
 (rum/defc tldraw-app < rum/reactive
@@ -237,7 +235,7 @@
         [:div.gap-8.grid.grid-rows-auto
          {:style {:visibility (when (nil? container-width) "hidden")
                   :grid-template-columns (str "repeat(" cols ", minmax(0, 1fr))")}}
-         (dashboard-create-card)
+         (when-not config/publishing? (dashboard-create-card))
          (for [whiteboard-name whiteboard-names]
            [:<> {:key whiteboard-name}
             (dashboard-preview-card whiteboard-name
@@ -294,27 +292,14 @@
 
 (rum/defc whiteboard-route
   [route-match]
-  (when (user-handler/feature-available? :whiteboard)
-    (let [name (get-in route-match [:parameters :path :name])
-          {:keys [block-id]} (get-in route-match [:parameters :query])]
-      (whiteboard-page name block-id))))
-
-(defn onboarding-show
-  []
-  (when (and (user-handler/feature-available? :whiteboard)
-             (not (or (state/sub :whiteboard/onboarding-tour?)
-                      (config/demo-graph?)
-                      (util/mobile?))))
-    (state/pub-event! [:whiteboard/onboarding])
-    (state/set-state! [:whiteboard/onboarding-tour?] true)
-    (storage/set :whiteboard-onboarding-tour? true)))
+  (let [name (get-in route-match [:parameters :path :name])
+        {:keys [block-id]} (get-in route-match [:parameters :query])]
+    (whiteboard-page name block-id)))
 
 (rum/defc onboarding-welcome
   [close-fn]
   [:div.cp__whiteboard-welcome
-   [:span.head-bg
-
-    [:strong (t :on-boarding/closed-feature (name (:whiteboard user-handler/feature-matrix)))]]
+   [:span.head-bg]
 
    [:h1.text-2xl.font-bold.flex-col.sm:flex-row
     (t :on-boarding/welcome-whiteboard-modal-title)]

+ 1 - 1
src/main/frontend/components/whiteboard.css

@@ -165,7 +165,7 @@ input.tl-text-input {
     width: calc(100% - 20px);
 
     > .title {
-      @apply whitespace-nowrap min-w-[80px];
+      @apply whitespace-nowrap min-w-[100px];
     }
   }
 

+ 99 - 84
src/main/frontend/config.cljs

@@ -5,6 +5,7 @@
             [frontend.mobile.util :as mobile-util]
             [frontend.state :as state]
             [frontend.util :as util]
+            [logseq.common.path :as path]
             [logseq.graph-parser.config :as gp-config]
             [logseq.graph-parser.util :as gp-util]
             [shadow.resource :as rc]))
@@ -32,14 +33,24 @@
         "https://logseq-prod.auth.us-east-1.amazoncognito.com/login?client_id=3c7np6bjtb4r1k1bi9i049ops5&response_type=code&scope=email+openid+phone&redirect_uri=logseq%3A%2F%2Fauth-callback")
       (def API-DOMAIN "api.logseq.com")
       (def WS-URL "wss://ws.logseq.com/file-sync?graphuuid=%s")
-      (def COGNITO-IDP "https://cognito-idp.us-east-1.amazonaws.com/"))
+      (def COGNITO-IDP "https://cognito-idp.us-east-1.amazonaws.com/")
+      (def COGNITO-CLIENT-ID "69cs1lgme7p8kbgld8n5kseii6")
+      (def REGION "us-east-1")
+      (def USER-POOL-ID "us-east-1_dtagLnju8")
+      (def IDENTITY-POOL-ID "us-east-1:d6d3b034-1631-402b-b838-b44513e93ee0")
+      (def OAUTH-DOMAIN "logseq-prod.auth.us-east-1.amazoncognito.com"))
 
   (do (def FILE-SYNC-PROD? false)
       (def LOGIN-URL
         "https://logseq-test2.auth.us-east-2.amazoncognito.com/login?client_id=3ji1a0059hspovjq5fhed3uil8&response_type=code&scope=email+openid+phone&redirect_uri=logseq%3A%2F%2Fauth-callback")
       (def API-DOMAIN "api-dev.logseq.com")
       (def WS-URL "wss://ws-dev.logseq.com/file-sync?graphuuid=%s")
-      (def COGNITO-IDP "https://cognito-idp.us-east-2.amazonaws.com/")))
+      (def COGNITO-IDP "https://cognito-idp.us-east-2.amazonaws.com/")
+      (def COGNITO-CLIENT-ID "1qi1uijg8b6ra70nejvbptis0q")
+      (def REGION "us-east-2")
+      (def USER-POOL-ID "us-east-2_kAqZcxIeM")
+      (def IDENTITY-POOL-ID "us-east-2:cc7d2ad3-84d0-4faf-98fe-628f6b52c0a5")
+      (def OAUTH-DOMAIN "logseq-test2.auth.us-east-2.amazoncognito.com")))
 
 ;; Feature flags
 ;; =============
@@ -102,7 +113,7 @@
   #{:mp3 :ogg :mpeg :wav :m4a :flac :wma :aac})
 
 (def video-formats
-  #{:mp4 :webm :mov})
+  #{:mp4 :webm :mov :flv :avi :mkv})
 
 (def media-formats (set/union (gp-config/img-formats) audio-formats))
 
@@ -120,10 +131,32 @@
                        (string/replace-first "." ""))
                      (util/safe-lower-case)
                      (keyword))]
-     (some
-      (fn [s]
-        (contains? s input))
-      formats))))
+     (boolean
+       (some
+         (fn [s]
+           (contains? s input))
+         formats)))))
+
+(defn ext-of-video?
+  ([s] (ext-of-video? s true))
+  ([s html5?]
+   (when-let [s (and (string? s) (util/get-file-ext s))]
+     (let [video-formats (cond-> video-formats
+                                 html5? (disj :mkv))]
+       (extname-of-supported? s [video-formats])))))
+
+(defn ext-of-audio?
+  ([s] (ext-of-audio? s true))
+  ([s html5?]
+   (when-let [s (and (string? s) (util/get-file-ext s))]
+     (let [audio-formats (cond-> audio-formats
+                                 html5? (disj :wma :ogg))]
+       (extname-of-supported? s [audio-formats])))))
+
+(defn ext-of-image?
+  [s]
+  (when-let [s (and (string? s) (util/get-file-ext s))]
+    (extname-of-supported? s [image-formats])))
 
 (def mobile?
   "Triggering condition: Mobile phones
@@ -296,8 +329,8 @@
   "Demo graph or nil graph?"
   ([]
    (demo-graph? (state/get-current-repo)))
-  ([graph]
-   (or (nil? graph) (= graph local-repo))))
+  ([repo-url]
+   (or (nil? repo-url) (= repo-url local-repo))))
 
 (defonce recycle-dir ".recycle")
 (def config-file "config.edn")
@@ -307,10 +340,16 @@
 (def custom-js-file "custom.js")
 (def config-default-content (rc/inline "config.edn"))
 
+;; NOTE: repo-url is the unique identifier of a repo.
+;; - `local` => in-memory demo graph
+;; - `logseq_local_/absolute/path/to/graph` => local graph, native fs backend
+;; - `logseq_local_x:/absolute/path/to/graph` => local graph, native fs backend, on Windows
+;; - `logseq_local_GraphName` => local graph, browser fs backend
+;; - Use `""` while writing global files
+
 (defonce idb-db-prefix "logseq-db/")
 (defonce local-db-prefix "logseq_local_")
 (defonce local-handle "handle")
-(defonce local-handle-prefix (str local-handle "/" local-db-prefix))
 
 (defn local-db?
   [s]
@@ -325,6 +364,7 @@
   [s]
   (string/replace s local-db-prefix ""))
 
+;; FIXME(andelf): this is not the reverse op of get-repo-dir, should be fixed
 (defn get-local-repo
   [dir]
   (str local-db-prefix dir))
@@ -332,19 +372,39 @@
 (defn get-repo-dir
   [repo-url]
   (cond
+    (nil? repo-url)
+    (do
+      (js/console.error "BUG: nil repo")
+      nil)
+
     (and (util/electron?) (local-db? repo-url))
     (get-local-dir repo-url)
 
     (and (mobile-util/native-platform?) (local-db? repo-url))
     (let [dir (get-local-dir repo-url)]
-      (if (string/starts-with? dir "file:")
+      (if (string/starts-with? dir "file://")
         dir
-        (str "file:///" (string/replace dir #"^/+" ""))))
+        (path/path-join "file://" dir)))
+
+    ;; Special handling for demo graph
+    (= repo-url "local")
+    "memory:///local"
+
+    ;; nfs, browser-fs-access
+    ;; Format: logseq_local_{dir-name}
+    (local-db? repo-url)
+    (string/replace-first repo-url local-db-prefix "")
+
+    ;; unit test
+    (= repo-url "test-db")
+    "/test-db"
 
     :else
-    (str "/"
-         (->> (take-last 2 (string/split repo-url #"/"))
-              (string/join "_")))))
+    (do
+      (js/console.error "BUG: This should be unreachable! get-repo-dir" repo-url)
+      (str "/"
+           (->> (take-last 2 (string/split repo-url #"/"))
+                (string/join "_"))))))
 
 (defn get-string-repo-dir
   [repo-dir]
@@ -363,105 +423,60 @@
               last
               gp-util/safe-decode-uri-component
               (str "/" (string/capitalize app-name) "/")))
-    (get-repo-dir repo-dir)))
+    (get-repo-dir (get-local-repo repo-dir))))
 
-(defn get-repo-path
+(defn get-repo-fpath
   [repo-url path]
   (if (and (or (util/electron?) (mobile-util/native-platform?))
            (local-db? repo-url))
-    path
+    (path/path-join (get-repo-dir repo-url) path)
     (util/node-path.join (get-repo-dir repo-url) path)))
 
-;; FIXME: There is another normalize-file-protocol-path at src/main/frontend/fs/capacitor_fs.cljs
-(defn get-file-path
-  "Normalization happens here"
-  [repo-url relative-path]
-  (when (and repo-url relative-path)
-    (let [path (cond
-                 (demo-graph?)
-                 nil
-
-                 (and (util/electron?) (local-db? repo-url))
-                 (let [dir (get-repo-dir repo-url)]
-                   (if (string/starts-with? relative-path dir)
-                     relative-path
-                     (str dir "/"
-                          (string/replace relative-path #"^/" ""))))
-
-                 (and (mobile-util/native-ios?) (local-db? repo-url))
-                 (let [dir (get-repo-dir repo-url)]
-                   (util/safe-path-join dir relative-path))
-
-                 (and (mobile-util/native-android?) (local-db? repo-url))
-                 (let [dir (get-repo-dir repo-url)
-                       dir (if (or (string/starts-with? dir "file:")
-                                   (string/starts-with? dir "content:"))
-                             dir
-                             (str "file:///" (string/replace dir #"^/+" "")))]
-                   (util/safe-path-join dir relative-path))
-
-                 (= "/" (first relative-path))
-                 (subs relative-path 1)
-
-                 :else
-                 relative-path)]
-      (and (not-empty path) (gp-util/path-normalize path)))))
-
-;; NOTE: js/encodeURIComponent cannot be used here
-(defn get-page-file-path
-  "Get the path to the page file for the given page. This is used when creating new files."
-  [repo-url sub-dir page-name ext]
-  (let [page-basename (if (mobile-util/native-platform?)
-                        (js/encodeURI page-name)
-                        page-name)]
-    (get-file-path repo-url (str sub-dir "/" page-basename "." ext))))
-
 (defn get-repo-config-path
-  ([]
-   (get-repo-config-path (state/get-current-repo)))
-  ([repo]
-   (when repo
-     (get-file-path repo (str app-name "/" config-file)))))
+  []
+  (path/path-join app-name config-file))
 
 (defn get-custom-css-path
   ([]
    (get-custom-css-path (state/get-current-repo)))
   ([repo]
-   (when repo
-     (get-file-path repo
-                    (str app-name "/" custom-css-file)))))
+   (when-let [repo-dir (get-repo-dir repo)]
+     (path/path-join repo-dir app-name custom-css-file))))
 
 (defn get-export-css-path
   ([]
    (get-export-css-path (state/get-current-repo)))
   ([repo]
-   (when repo
-     (get-file-path repo
-                    (str app-name "/" export-css-file)))))
+   (when-let [repo-dir (get-repo-dir repo)]
+     (path/path-join repo-dir app-name  export-css-file))))
 
 (defn expand-relative-assets-path
+  "Resolve all relative links in custom.css to assets:// URL"
   ;; ../assets/xxx -> {assets|file}://{current-graph-root-path}/xxx
   [source]
-  (when-let [protocol (and (string? source)
-                           (not (string/blank? source))
-                           (if (util/electron?) "assets" "file"))]
-
-    (string/replace
-     source "../assets" (util/format "%s://%s/assets" protocol (get-repo-dir (state/get-current-repo))))))
+  (let [protocol (and (string? source)
+                      (not (string/blank? source))
+                      (if (util/electron?) "assets://" "file://"))
+        ;; BUG: use "assets" as fake current directory
+        assets-link-fn (fn [_]
+                         (str (path/path-join protocol
+                                              (get-repo-dir (state/get-current-repo)) "assets") "/"))]
+    (when (not-empty source)
+      (string/replace source #"\.\./assets/"
+                      assets-link-fn))))
 
 (defn get-current-repo-assets-root
   []
-  (when-let [repo-root (and (local-db? (state/get-current-repo))
+  (when-let [repo-dir (and (local-db? (state/get-current-repo))
                             (get-repo-dir (state/get-current-repo)))]
-    (util/node-path.join repo-root "assets")))
+    (path/path-join repo-dir "assets")))
 
 (defn get-custom-js-path
   ([]
    (get-custom-js-path (state/get-current-repo)))
   ([repo]
-   (when repo
-     (get-file-path repo
-                    (str app-name "/" custom-js-file)))))
+   (when-let [repo-dir (get-repo-dir repo)]
+     (path/path-join repo-dir app-name custom-js-file))))
 
 (defn get-block-hidden-properties
   []

+ 1 - 2
src/main/frontend/core.cljs

@@ -9,7 +9,6 @@
             [frontend.routes :as routes]
             [frontend.spec]
             [frontend.log]
-            [frontend.util.persist-var :as persist-var]
             [reitit.frontend :as rf]
             [reitit.frontend.easy :as rfe]
             [logseq.api]
@@ -51,7 +50,7 @@
     (set-router!)
     (rum/mount (page/current-page) node)
     (display-welcome-message)
-    (persist-var/load-vars)
+    ;; NO repo state here, better not add init logic here
     (when config/dev?
       (js/setTimeout #(sync/<sync-start) 1000))))
 

+ 15 - 12
src/main/frontend/db.cljs

@@ -69,19 +69,22 @@
 
  [logseq.db.default built-in-pages-names built-in-pages])
 
-(defn get-schema-version [db]
-  (d/q
-    '[:find ?v .
-      :where
-      [_ :schema/version ?v]]
-    db))
-
-(defn old-schema?
+(defn- old-schema?
+  "Requires migration if the schema version is older than db-schema/version"
   [db]
-  (let [v (get-schema-version db)]
-    (if (integer? v)
-      (> db-schema/version v)
-      ;; backward compatibility
+  (let [v (db-migrate/get-schema-version db)
+        ;; backward compatibility
+        v (if (integer? v) v 0)]
+    (cond
+      (= db-schema/version v)
+      false
+
+      (< db-schema/version v)
+      (do
+        (js/console.error "DB schema version is newer than the app, please update the app. " ":db-version" v)
+        false)
+
+      :else
       true)))
 
 ;; persisting DBs between page reloads

+ 18 - 12
src/main/frontend/db/conn.cljs

@@ -7,7 +7,8 @@
             [frontend.config :as config]
             [frontend.util.text :as text-util]
             [logseq.graph-parser.text :as text]
-            [logseq.db :as ldb]))
+            [logseq.db :as ldb]
+            [logseq.graph-parser.util :as gp-util]))
 
 (defonce conns (atom {}))
 
@@ -20,24 +21,29 @@
       url)))
 
 (defn get-repo-name
-  [repo]
+  [repo-url]
   (cond
     (mobile-util/native-platform?)
-    (text-util/get-graph-name-from-path repo)
+    (text-util/get-graph-name-from-path repo-url)
 
-    (config/local-db? repo)
-    (config/get-local-dir repo)
+    (config/local-db? repo-url)
+    (config/get-local-dir repo-url)
 
     :else
-    (get-repo-path repo)))
+    (get-repo-path repo-url)))
 
 (defn get-short-repo-name
-  "repo-path: output of `get-repo-name`"
-  [repo-path]
-  (if (or (util/electron?)
-          (mobile-util/native-platform?))
-    (text/get-file-basename repo-path)
-    repo-path))
+  "repo-name: from get-repo-name. Dir/Name => Name"
+  [repo-name]
+  (cond
+    (util/electron?)
+    (text/get-file-basename repo-name)
+
+    (mobile-util/native-platform?)
+    (gp-util/safe-decode-uri-component (text/get-file-basename repo-name))
+
+    :else
+    repo-name))
 
 (defn datascript-db
   [repo]

+ 75 - 10
src/main/frontend/db/migrate.cljs

@@ -1,22 +1,87 @@
-(ns ^:no-doc frontend.db.migrate
-  (:require [datascript.core :as d]))
+(ns frontend.db.migrate
+  "Do DB migration, in a version-by-version style.
 
-(defn get-collapsed-blocks
+   `:schema/version` is not touched"
+  (:require [clojure.string :as string]
+            [datascript.core :as d]
+            [frontend.config :as config]
+            [frontend.state :as state]
+            [logseq.common.path :as path]
+            [logseq.db.schema :as db-schema]))
+
+
+(defn get-schema-version
+  "Get schema version from db, the current version is defined in db-schema/version"
   [db]
   (d/q
-    '[:find [?b ...]
-      :where
-      [?b :block/properties ?properties]
-      [(get ?properties :collapsed) ?collapsed]
-      [(= true ?collapsed)]]
-    db))
+   '[:find (max ?v) .
+     :where
+     [_ :schema/version ?v]]
+   db))
 
-(defn migrate
+(defn get-collapsed-blocks
   [db]
+  (d/q
+   '[:find [?b ...]
+     :where
+     [?b :block/properties ?properties]
+     [(get ?properties :collapsed) ?collapsed]
+     [(= true ?collapsed)]]
+   db))
+
+(defn migrate-collapsed-blocks [db]
   (when db
     (let [collapsed-blocks (get-collapsed-blocks db)]
       (if (seq collapsed-blocks)
         (let [tx-data (map (fn [id] {:db/id id
                                      :block/collapsed? true}) collapsed-blocks)]
+          (prn :migrate-collapsed-blocks {:count (count collapsed-blocks)})
+          (d/db-with db tx-data))
+        db))))
+
+(defn migrate-absolute-file-path-to-relative [db]
+  (when db
+    (let [all-files (d/q
+                     '[:find [(pull ?b [:db/id :file/path]) ...]
+                       :where
+                       [?b :file/path]]
+                     db)
+          repo-dir (config/get-repo-dir (state/get-current-repo))]
+      (if (seq all-files)
+        (let [tx-data (->> all-files
+                           (filter (fn [db-file]
+                                     (and (path/absolute? (:file/path db-file))
+                                                      (string/starts-with? (:file/path db-file) repo-dir))))
+                           (mapv (fn [db-file] {:db/id (:db/id db-file)
+                                                :file/path (path/trim-dir-prefix repo-dir (:file/path db-file))})))]
+          (when tx-data
+            (state/pub-event! [:notification/show
+                               {:content [:div "Migrated from an old version of DB, please re-index the graph from the graph list dropdown."]
+                                :status :warning
+                                :clear? false}]))
+          (prn :migrate-absolute-file-path-to-relative {:count (count tx-data)})
           (d/db-with db tx-data))
         db))))
+
+
+(defmulti do-migration get-schema-version)
+
+(defmethod do-migration 0
+  [db]
+  (-> db
+      migrate-collapsed-blocks
+      migrate-absolute-file-path-to-relative))
+
+(defmethod do-migration 1
+  [db]
+  (-> db
+      migrate-absolute-file-path-to-relative))
+
+(defmethod do-migration :default
+  [db]
+  db)
+
+(defn migrate
+  [db]
+  (prn ::migrate {:from (get-schema-version db) :to db-schema/version})
+  (do-migration db))

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

@@ -6,7 +6,6 @@
             [clojure.string :as string]
             [clojure.walk :as walk]
             [datascript.core :as d]
-            [frontend.config :as config]
             [frontend.date :as date]
             [frontend.db.conn :as conn]
             [frontend.db.react :as react]
@@ -269,7 +268,7 @@
 (defn get-custom-css
   []
   (when-let [repo (state/get-current-repo)]
-    (get-file (config/get-file-path repo "logseq/custom.css"))))
+    (get-file repo "logseq/custom.css")))
 
 (defn get-block-by-uuid
   [id]

+ 0 - 9
src/main/frontend/dicts.cljc

@@ -8,7 +8,6 @@
                           :default "tutorial-en.md")
         :tutorial/dummy-notes #?(:cljs (rc/inline "dummy-notes-en.md")
                                  :default "dummy-notes-en.md")
-        :on-boarding/closed-feature "Closed {1}"
         :on-boarding/demo-graph "This is a demo graph, changes will not be saved until you open a local folder."
         :on-boarding/add-graph "Add a graph"
         :on-boarding/open-local-dir "Open a local directory"
@@ -530,7 +529,6 @@
         :notification/clear-all "Alles löschen"
 
         :on-boarding/add-graph "Graph hinzufügen"
-        :on-boarding/closed-feature "{1} geschlossen"
         :on-boarding/demo-graph "Dies ist ein Demo-Graph. Änderungen werden nicht gespeichert, solange Sie kein lokales Verzeichnis öffnen."
         :on-boarding/new-graph-desc-1 "Logseq unterstützt sowohl Markdown als auch Org-mode. Sie können ein bestehendes Verzeichnis öffnen oder auf Ihrem Rechner ein neues Verzeichnis anlegen. Ein Verzeichnis wird auch als Ordner bezeichnet. Ihre Daten werden nur auf diesem Gerät gespeichert."
         :on-boarding/new-graph-desc-2 "Nachdem Sie ein Verzeichnis geöffnet haben, werden darin drei Ordner angelegt:"
@@ -1289,7 +1287,6 @@
 
         :file/validate-existing-file-error "La page existe déjà avec un autre fichier: {1}, fichier actuel: {2}. Veuillez n'en garder qu'un et réindexer votre graphique."
         :notification/clear-all "Tout effacer"
-        :on-boarding/closed-feature "Fermé {1}"
         :on-boarding/tour-whiteboard-home "{1} Commencez pour vos tableaux blancs"
         :on-boarding/tour-whiteboard-home-description "Les tableaux blancs ont leur propre section dans l'application où vous pouvez les voir en un coup d'œil, en créer de nouveaux ou les supprimer facilement."
         :on-boarding/tour-whiteboard-new "{1} Créer un nouveau tableau blanc"
@@ -1629,7 +1626,6 @@
 
    :zh-Hant {
           :accessibility/skip-to-main-content "跳轉到主頁面"
-          :on-boarding/closed-feature "已關閉 {1}"
           :on-boarding/demo-graph "目前在 demo 用圖表,您需要打開本機目錄以保存。"
           :on-boarding/add-graph "增加圖表"
           :on-boarding/open-local-dir "打開本機目錄"
@@ -2875,7 +2871,6 @@
            :left-side-bar/create "Criar"
            :left-side-bar/new-whiteboard "Novo quadro branco"
            :notification/clear-all "Limpar tudo"
-           :on-boarding/closed-feature "Fechado {1}"
            :on-boarding/tour-whiteboard-home "{1} Início para seus quadros brancos"
            :on-boarding/tour-whiteboard-home-description "Os quadros brancos têm sua própria seção no aplicativo, onde você pode vê-los rapidamente, criar novos ou excluí-los facilmente."
            :on-boarding/tour-whiteboard-new "{1} Criar novo quadro branco"
@@ -2915,7 +2910,6 @@
                              :default "tutorial-en.md")
            :tutorial/dummy-notes #?(:cljs (rc/inline "dummy-notes-en.md")
                                     :default "dummy-notes-en.md")
-           :on-boarding/closed-feature "{1} fechado/a"
            :on-boarding/demo-graph "Isto é um grafo de demonstração, nenhuma mudança será guardada até abrir uma pasta local."
            :on-boarding/add-graph "Adicionar grafo"
            :on-boarding/open-local-dir "Abrir uma pasta local"
@@ -3997,7 +3991,6 @@
                           :default "tutorial-tr.md")
         :tutorial/dummy-notes #?(:cljs (rc/inline "dummy-notes-tr.md")
                                  :default "dummy-notes-tr.md")
-        :on-boarding/closed-feature "Kapalı {1}"
         :on-boarding/demo-graph "Bu bir demo graftır, yerel bir klasör açana kadar değişiklikler kaydedilmeyecektir."
         :on-boarding/add-graph "Bir graf ekle"
         :on-boarding/open-local-dir "Yerel bir dizin açın"
@@ -4594,7 +4587,6 @@
         :color/purple "보라색"
         :color/red "빨간색"
         :color/yellow "노란색"
-        :on-boarding/closed-feature "{1} 종료됨"
         :on-boarding/tour-whiteboard-home "{1} 홈 화이트보드"
         :on-boarding/tour-whiteboard-home-description "화이트보드는 각각 섹션이 존재합니다. 섹션에서 화이트보드를 한눈에 보고, 생성하거나 삭제할 수 있습니다."
         :on-boarding/tour-whiteboard-new "{1} 새 화이트보드 생성"
@@ -4918,7 +4910,6 @@
                                                              :default "tutorial-sk.md")
         :tutorial/dummy-notes                             #?(:cljs    (rc/inline "dummy-notes-sk.md")
                                                              :default "dummy-notes-sk.md")
-        :on-boarding/closed-feature                       "Zatvorený {1}"
         :on-boarding/demo-graph                           "Toto je ukážkový graf, zmeny nebudú uložené, kým neotvoríte lokálny adresár."
         :on-boarding/add-graph                            "Pridať graf"
         :on-boarding/open-local-dir                       "Otvoriť lokálny adresár"

+ 2 - 2
src/main/frontend/extensions/pdf/assets.cljs

@@ -213,8 +213,8 @@
   [highlight ^js viewer]
   (when-let [ref-block (ensure-ref-block! (state/get-current-pdf) highlight)]
     (util/copy-to-clipboard!
-     (block-ref/->block-ref (:block/uuid ref-block)) nil
-     (pdf-windows/resolve-own-window viewer))))
+     (block-ref/->block-ref (:block/uuid ref-block))
+     :owner-window (pdf-windows/resolve-own-window viewer))))
 
 (defn open-block-ref!
   [block]

+ 2 - 2
src/main/frontend/extensions/pdf/core.cljs

@@ -141,8 +141,8 @@
                             "copy"
                             (do
                               (util/copy-to-clipboard!
-                               (or (:text content) (pdf-utils/fix-selection-text-breakline (.toString selection))) nil
-                               (pdf-windows/resolve-own-window viewer))
+                               (or (:text content) (pdf-utils/fix-selection-text-breakline (.toString selection)))
+                               :owner-window (pdf-windows/resolve-own-window viewer))
                               (pdf-utils/clear-all-selection))
 
                             "link"

+ 3 - 1
src/main/frontend/extensions/tldraw.cljs

@@ -3,6 +3,7 @@
   (:require ["/frontend/tldraw-logseq" :as TldrawLogseq]
             [frontend.components.block :as block]
             [frontend.components.page :as page]
+            [frontend.config :as config]
             [frontend.db.model :as model]
             [frontend.handler.editor :as editor-handler]
             [frontend.handler.route :as route-handler]
@@ -93,7 +94,7 @@
    :isMobile util/mobile?
    :saveAsset save-asset-handler
    :makeAssetUrl editor-handler/make-asset-url
-   :copyToClipboard (fn [text, html] (util/copy-to-clipboard! text html))
+   :copyToClipboard (fn [text, html] (util/copy-to-clipboard! text :html html))
    :getRedirectPageName (fn [page-name-or-uuid] (model/get-redirect-page-name page-name-or-uuid))
    :insertFirstPageBlock (fn [page-name] (editor-handler/insert-first-page-block-if-not-exists! page-name {:redirect? false}))
    :addNewWhiteboard (fn [page-name]
@@ -152,6 +153,7 @@
        (tldraw {:renderers tldraw-renderers
                 :handlers (get-tldraw-handlers page-name)
                 :onMount on-mount
+                :readOnly config/publishing?
                 :onPersist (fn [app info]
                              (state/set-state! [:whiteboard/last-persisted-at (state/get-current-repo)] (util/time-ms))
                              (util/profile "tldraw persist"

+ 118 - 101
src/main/frontend/fs.cljs

@@ -6,44 +6,56 @@
             [frontend.fs.nfs :as nfs]
             [frontend.fs.node :as node]
             [frontend.fs.capacitor-fs :as capacitor-fs]
-            [frontend.fs.bfs :as bfs]
+            [frontend.fs.memory-fs :as memory-fs]
             [frontend.mobile.util :as mobile-util]
             [frontend.fs.protocol :as protocol]
             [frontend.util :as util]
             [lambdaisland.glogi :as log]
             [promesa.core :as p]
-            [frontend.db :as db]
+            [logseq.common.path :as path]
             [clojure.string :as string]
             [frontend.state :as state]
             [logseq.graph-parser.util :as gp-util]
             [electron.ipc :as ipc]))
 
-(defonce nfs-record (nfs/->Nfs))
-(defonce bfs-record (bfs/->Bfs))
-(defonce node-record (node/->Node))
-(defonce mobile-record (capacitor-fs/->Capacitorfs))
+(defonce nfs-backend (nfs/->Nfs))
+(defonce memory-backend (memory-fs/->MemoryFs))
+(defonce node-backend (node/->Node))
+(defonce mobile-backend (capacitor-fs/->Capacitorfs))
 
-(defn local-db?
-  [dir]
-  (and (string? dir)
-       (config/local-db? (subs dir 1))))
+(defn- get-native-backend
+  "Native FS backend of current platform"
+  []
+  (cond
+    (util/electron?)
+    node-backend
+
+    (mobile-util/native-platform?)
+    mobile-backend
+
+    :else
+    nfs-backend))
 
 (defn get-fs
   [dir]
-  (let [bfs-local? (or (string/starts-with? dir "/local")
-                       (string/starts-with? dir "local"))]
+  (let [bfs-local? (and dir
+                        (or (string/starts-with? dir "/local")
+                            (string/starts-with? dir "local")))]
     (cond
+      (nil? dir) ;; global file op, use native backend
+      (get-native-backend)
+
+      (string/starts-with? dir "memory://")
+      memory-backend
+
       (and (util/electron?) (not bfs-local?))
-      node-record
+      node-backend
 
       (mobile-util/native-platform?)
-      mobile-record
-
-      (local-db? dir)
-      nfs-record
+      mobile-backend
 
       :else
-      bfs-record)))
+      nfs-backend)))
 
 (defn mkdir!
   [dir]
@@ -54,33 +66,33 @@
   (protocol/mkdir-recur! (get-fs dir) dir))
 
 (defn readdir
+  "list all absolute paths in dir, absolute"
   [dir & {:keys [path-only?]}]
+  (when-not path-only?
+    (js/console.error "BUG: (deprecation) path-only? is always true"))
   (p/let [result (protocol/readdir (get-fs dir) dir)
           result (bean/->clj result)]
-    (let [result (if (and path-only? (map? (first result)))
-                   (map :uri result)
-                   result)]
-      (if (and (map? (first result)) (:uri (first result)))
-        (map #(update % :uri gp-util/path-normalize) result)
-        (map gp-util/path-normalize result)))))
+    (map gp-util/path-normalize result)))
 
 (defn unlink!
   "Should move the path to logseq/recycle instead of deleting it."
-  [repo path opts]
-  (protocol/unlink! (get-fs path) repo path opts))
+  [repo fpath opts]
+  ;; TODO(andelf): better handle backup here, instead of fs impl
+  (protocol/unlink! (get-fs fpath) repo fpath opts))
 
 (defn rmdir!
   "Remove the directory recursively.
    Warning: only run it for browser cache."
   [dir]
   (when-let [fs (get-fs dir)]
-    (when (= fs bfs-record)
+    (when (= fs memory-backend)
       (protocol/rmdir! fs dir))))
 
+;; TODO(andelf): distinguish from graph file writing and global file write
 (defn write-file!
-  [repo dir path content opts]
+  [repo dir rpath content opts]
   (when content
-    (let [path (gp-util/path-normalize path)
+    (let [path (gp-util/path-normalize rpath)
           fs-record (get-fs dir)]
       (->
        (p/let [opts (assoc opts
@@ -91,9 +103,7 @@
                                                                           :fs (type fs-record)
                                                                           :user-agent (when js/navigator js/navigator.userAgent)
                                                                           :content-length (count content)}}])))
-               _ (protocol/write-file! (get-fs dir) repo dir path content opts)]
-         (when (= bfs-record fs-record)
-           (db/set-file-last-modified-at! repo (config/get-file-path repo path) (js/Date.))))
+               _ (protocol/write-file! (get-fs dir) repo dir path content opts)])
        (p/catch (fn [error]
                   (log/error :file/write-failed {:dir dir
                                                  :path path
@@ -105,7 +115,7 @@
 (defn read-file
   ([dir path]
    (let [fs (get-fs dir)
-         options (if (= fs bfs-record)
+         options (if (= fs memory-backend)
                    {:encoding "utf8"}
                    {})]
      (read-file dir path options)))
@@ -117,18 +127,17 @@
   (let [new-path (gp-util/path-normalize new-path)]
     (cond
                                         ; See https://github.com/isomorphic-git/lightning-fs/issues/41
-     (= old-path new-path)
-     (p/resolved nil)
+      (= old-path new-path)
+      (p/resolved nil)
 
-     :else
-     (let [[old-path new-path]
-           (map #(if (or (util/electron?) (mobile-util/native-platform?))
-                   %
-                   (str (config/get-repo-dir repo) "/" %))
-             [old-path new-path])]
-       (protocol/rename! (get-fs old-path) repo old-path new-path)))))
+      :else
+      (let [repo-dir (config/get-repo-dir repo)
+            old-fpath (path/path-join repo-dir old-path)
+            new-fpath (path/path-join repo-dir new-path)]
+        (protocol/rename! (get-fs old-fpath) repo old-fpath new-fpath)))))
 
 (defn copy!
+  "Only used by Logseq Sync"
   [repo old-path new-path]
   (cond
     (= old-path new-path)
@@ -143,92 +152,100 @@
       (protocol/copy! (get-fs old-path) repo old-path new-path))))
 
 (defn stat
-  [dir path]
-  (protocol/stat (get-fs dir) dir path))
-
-(defn- get-record
-  []
-  (cond
-    (util/electron?)
-    node-record
-
-    (mobile-util/native-platform?)
-    mobile-record
-
-    :else
-    nfs-record))
+  ([fpath]
+   (protocol/stat (get-fs fpath) fpath))
+  ([dir path]
+   (let [fpath (path/path-join dir path)]
+     (protocol/stat (get-fs dir) fpath))))
 
 (defn open-dir
-  [dir ok-handler]
-  (let [record (get-record)]
-    (p/let [result (protocol/open-dir record dir ok-handler)]
-      (if (or (util/electron?)
-              (mobile-util/native-platform?))
-        (let [[dir & paths] (bean/->clj result)]
-          [(:path dir) paths])
-        result))))
+  [dir]
+  (let [record (get-native-backend)]
+    (p/let [result (protocol/open-dir record dir)]
+      (when result
+        (let [{:keys [path files]} result
+              dir path
+              files (mapv (fn [entry]
+                            (assoc entry :path (path/relative-path dir (:path entry))))
+                          files)]
+          {:path path :files files})))))
 
 (defn get-files
-  [path-or-handle ok-handler]
-  (let [record (get-record)
-        electron? (util/electron?)
-        mobile? (mobile-util/native-platform?)]
-    (p/let [result (protocol/get-files record path-or-handle ok-handler)]
-      (if (or electron? mobile?)
-        (let [result (bean/->clj result)]
-          (if electron? (rest result) result))
-        result))))
+  "List all files in the directory, recursively.
+   
+   Wrap as {:path string :files []}, using relative path"
+  [dir]
+  (let [fs-record (get-native-backend)]
+    (p/let [files (protocol/get-files fs-record dir)]
+      (println ::get-files (count files) "files")
+      (let [files (mapv (fn [entry]
+                          (assoc entry :path (path/relative-path dir (:path entry))))
+                        files)]
+        {:path dir :files files}))))
 
 (defn watch-dir!
   ([dir] (watch-dir! dir {}))
-  ([dir options] (protocol/watch-dir! (get-record) dir options)))
+  ([dir options] (protocol/watch-dir! (get-fs dir) dir options)))
 
 (defn unwatch-dir!
   [dir]
-  (protocol/unwatch-dir! (get-record) dir))
+  (protocol/unwatch-dir! (get-fs dir) dir))
 
 (defn mkdir-if-not-exists
   [dir]
   (->
    (when dir
      (util/p-handle
-      (stat dir nil)
+      (stat dir)
       (fn [_stat])
       (fn [_error]
         (mkdir! dir))))
    (p/catch (fn [error] (js/console.error error)))))
 
+;; FIXME: counterintuitive return value
 (defn create-if-not-exists
+  "Create a file if it doesn't exist. return false on written, true on already exists"
   ([repo dir path]
    (create-if-not-exists repo dir path ""))
   ([repo dir path initial-content]
-   (let [path (if (util/absolute-path? path) path
-                  (if (util/starts-with? path "/")
-                    path
-                    (str "/" path)))]
-     (->
-      (p/let [_stat (stat dir path)]
-        true)
-      (p/catch
-       (fn [_error]
-         (p/let [_ (write-file! repo dir path initial-content nil)]
-           false)))))))
+   (-> (p/let [_stat (stat dir path)]
+         true)
+       (p/catch
+        (fn [_error]
+          (p/let [_ (write-file! repo dir path initial-content nil)]
+            false))))))
 
 (defn file-exists?
-  [dir path]
-  (util/p-handle
-   (stat dir path)
-   (fn [stat] (not (nil? stat)))
-   (fn [_e] false)))
-
-(defn file-or-href-exists?
-  "It not only accept path, but also href (url encoded path)"
-  [dir href]
-  (p/let [exist? (file-exists? dir href)
-          decoded-href   (gp-util/safe-decode-uri-component href)
-          decoded-exist? (when (not= decoded-href href)
-                           (file-exists? dir decoded-href))]
-    (or exist? decoded-exist?)))
+  ([fpath]
+   (util/p-handle
+    (stat fpath)
+    (fn [stat] (not (nil? stat)))
+    (fn [_e] false)))
+  ([dir path]
+   (util/p-handle
+    (stat dir path)
+    (fn [stat] (not (nil? stat)))
+    (fn [_e] false))))
+
+(defn asset-href-exists?
+  "href is from `make-asset-url`, so it's most likely a full-path"
+  [href]
+  (p/let [repo-dir (config/get-repo-dir (state/get-current-repo))
+          rpath (path/relative-path repo-dir href)
+          exist? (file-exists? repo-dir rpath)]
+    exist?))
+
+(defn asset-path-normalize
+  [path]
+  (cond
+    (util/electron?)
+    (path/url-to-path path)
+
+    (mobile-util/native-platform?)
+    path
+
+    :else
+    path))
 
 (defn dir-exists?
   [dir]

+ 0 - 40
src/main/frontend/fs/bfs.cljs

@@ -1,40 +0,0 @@
-(ns ^:no-doc frontend.fs.bfs
-  (:require [frontend.fs.protocol :as protocol]
-            [frontend.util :as util]
-            [promesa.core :as p]))
-
-(defrecord Bfs []
-  protocol/Fs
-  (mkdir! [_this dir]
-    (when (and js/window.pfs (not (util/electron?)))
-      (->
-       (js/window.pfs.mkdir dir)
-       (p/catch (fn [error] (println "Mkdir error: " error))))))
-  (readdir [_this dir]
-    (when js/window.pfs
-      (js/window.pfs.readdir dir)))
-  (unlink! [_this _repo path opts]
-    (when js/window.pfs
-      (p/let [stat (js/window.pfs.stat path)]
-        (if (= (.-type stat) "file")
-          (js/window.pfs.unlink path opts)
-          (p/rejected "Unlinking a directory is not allowed")))))
-  (rmdir! [_this dir]
-    (js/window.workerThread.rimraf dir))
-  (read-file [_this dir path options]
-    (js/window.pfs.readFile (str dir "/" path) (clj->js options)))
-  (write-file! [_this _repo dir path content _opts]
-    (when-not (util/electron?)
-      (js/window.pfs.writeFile (str dir "/" path) content)))
-  (rename! [_this _repo old-path new-path]
-    (js/window.pfs.rename old-path new-path))
-  (stat [_this dir path]
-    (js/window.pfs.stat (str dir path)))
-  (open-dir [_this _dir _ok-handler]
-    nil)
-  (get-files [_this _path-or-handle _ok-handler]
-    nil)
-  (watch-dir! [_this _dir _options]
-    nil)
-  (unwatch-dir! [_this _dir]
-    nil))

+ 157 - 158
src/main/frontend/fs/capacitor_fs.cljs

@@ -13,7 +13,7 @@
             [lambdaisland.glogi :as log]
             [promesa.core :as p]
             [rum.core :as rum]
-            [logseq.graph-parser.util :as gp-util]))
+            [logseq.common.path :as path]))
 
 (when (mobile-util/native-ios?)
   (defn ios-ensure-documents!
@@ -30,6 +30,17 @@
         (p/do!
          (.requestPermissions Filesystem))))))
 
+(defn- <dir-exists?
+  [fpath]
+  (p/catch (p/let [fpath (path/path-normalize fpath)
+                   stat (.stat Filesystem (clj->js {:path fpath}))]
+             (-> stat
+                 bean/->clj
+                 :type
+                 (= "directory")))
+           (fn [_error]
+             false)))
+
 (defn- <write-file-with-utf8
   [path content]
   (when-not (string/blank? path)
@@ -55,21 +66,39 @@
 
 (defn- <readdir [path]
   (-> (p/chain (.readdir Filesystem (clj->js {:path path}))
-               #(js->clj % :keywordize-keys true)
-               :files)
+              #(js->clj % :keywordize-keys true)
+              :files)
       (p/catch (fn [error]
                  (js/console.error "readdir Error: " path ": " error)
                  nil))))
 
-(defn- <stat [path]
-  (-> (p/chain (.stat Filesystem (clj->js {:path path}))
-               #(js->clj % :keywordize-keys true))
-      (p/catch (fn [error]
-                 (js/console.error "stat Error: " path ": " error)
-                 nil))))
+(defn- get-file-paths
+  "get all file paths recursively"
+  [path]
+  (p/let [result (p/loop [result []
+                          dirs [path]]
+                   (if (empty? dirs)
+                     result
+                     (p/let [d (first dirs)
+                             files (<readdir d)
+                             files (->> files
+                                        (remove (fn [{:keys [name  type]}]
+                                                  (or (string/starts-with? name ".")
+                                                      (and (= type "directory")
+                                                           (or (= name "bak")
+                                                               (= name "version-files")))))))
+                             files-dir (->> files
+                                            (filterv #(= (:type %) "directory"))
+                                            (mapv :uri))
+                             paths-result (->> files
+                                               (filterv #(= (:type %) "file"))
+                                               (mapv :uri))]
+                       (p/recur (concat result paths-result)
+                                (concat (rest dirs) files-dir)))))]
+    result))
 
-(defn readdir
-  "readdir recursively"
+(defn- get-files
+  "get all files recursively"
   [path]
   (p/let [result (p/loop [result []
                           dirs [path]]
@@ -97,7 +126,9 @@
                                    (mapv
                                     (fn [{:keys [uri] :as file-info}]
                                       (p/chain (<read-file-with-utf8 uri)
-                                               #(assoc file-info :content %))))))]
+                                               #(assoc (dissoc file-info :uri)
+                                                       :content %
+                                                       :path uri))))))]
                        (p/recur (concat result files-result)
                                 (concat (rest dirs) files-dir)))))]
     (js->clj result :keywordize-keys true)))
@@ -123,11 +154,11 @@
   "reserve the latest 6 version files"
   [dir]
   (->
-   (p/let [files (readdir dir)
+   (p/let [files (get-files dir)
            files (js->clj files :keywordize-keys true)
            old-versioned-files (drop 6 (reverse (sort-by :mtime files)))]
      (mapv (fn [file]
-             (.deleteFile Filesystem (clj->js {:path (:uri file)})))
+             (.deleteFile Filesystem (clj->js {:path (:path file)})))
            old-versioned-files))
    (p/catch (fn [_]))))
 
@@ -168,50 +199,53 @@
     (truncate-old-versioned-files! file-root)))
 
 (defn- write-file-impl!
-  [_this repo _dir path content {:keys [ok-handler error-handler old-content skip-compare?]} stat]
-  (if (or (string/blank? repo) skip-compare?)
-    (p/catch
-     (p/let [result (<write-file-with-utf8 path content)]
-       (when ok-handler
-         (ok-handler repo path result)))
-     (fn [error]
-       (if error-handler
-         (error-handler error)
-         (log/error :write-file-failed error))))
+  [repo dir rpath content {:keys [ok-handler error-handler old-content skip-compare?]} stat]
+  (let [fpath (path/path-join dir rpath)]
+    (if (or (string/blank? repo) skip-compare?)
+      (p/catch
+       (p/let [result (<write-file-with-utf8 fpath content)]
+         (when ok-handler
+           (ok-handler repo fpath result)))
+       (fn [error]
+         (if error-handler
+           (error-handler error)
+           (log/error :write-file-failed error))))
 
     ;; Compare with disk content and backup if not equal
-    (p/let [disk-content (<read-file-with-utf8 path)
-            disk-content (or disk-content "")
-            repo-dir (config/get-local-dir repo)
-            ext (util/get-file-ext path)
-            db-content (or old-content (db/get-file repo path) "")
-            contents-matched? (contents-matched? disk-content db-content)]
-      (cond
-        (and
-         (not= stat :not-found)   ; file on the disk was deleted
-         (not contents-matched?)
-         (not (contains? #{"excalidraw" "edn" "css"} ext))
-         (not (string/includes? path "/.recycle/")))
-        (p/let [disk-content disk-content]
-          (state/pub-event! [:file/not-matched-from-disk path disk-content content]))
+      (p/let [disk-content (if (not= stat :not-found)
+                             (<read-file-with-utf8 fpath)
+                             "")
+              disk-content (or disk-content "")
+              repo-dir (config/get-local-dir repo)
+              ext (util/get-file-ext rpath)
+              db-content (or old-content (db/get-file repo rpath) "")
+              contents-matched? (contents-matched? disk-content db-content)]
+        (cond
+          (and
+           (not= stat :not-found)   ; file on the disk was deleted
+           (not contents-matched?)
+           (not (contains? #{"excalidraw" "edn" "css"} ext))
+           (not (string/includes? fpath "/.recycle/")))
+          (p/let [disk-content disk-content]
+            (state/pub-event! [:file/not-matched-from-disk rpath disk-content content]))
 
-        :else
-        (->
-         (p/let [result (<write-file-with-utf8 path content)
-                 mtime (-> (js->clj stat :keywordize-keys true)
-                           :mtime)]
-           (when-not contents-matched?
-             (backup-file repo-dir :backup-dir path disk-content))
-           (db/set-file-last-modified-at! repo path mtime)
-           (p/let [content content]
-             (db/set-file-content! repo path content))
-           (when ok-handler
-             (ok-handler repo path result))
-           result)
-         (p/catch (fn [error]
-                    (if error-handler
-                      (error-handler error)
-                      (log/error :write-file-failed error)))))))))
+          :else
+          (->
+           (p/let [result (<write-file-with-utf8 fpath content)
+                   mtime (-> (js->clj stat :keywordize-keys true)
+                             :mtime)]
+             (when-not contents-matched?
+               (backup-file repo-dir :backup-dir fpath disk-content))
+             (db/set-file-last-modified-at! repo rpath mtime)
+             (p/let [content content]
+               (db/set-file-content! repo rpath content))
+             (when ok-handler
+               (ok-handler repo fpath result))
+             result)
+           (p/catch (fn [error]
+                      (if error-handler
+                        (error-handler error)
+                        (log/error :write-file-failed error))))))))))
 
 (defn ios-force-include-private
   "iOS sometimes return paths without the private part."
@@ -231,44 +265,6 @@
       path)
     path))
 
-(defn normalize-file-protocol-path [dir path]
-  (let [dir             (some-> dir (string/replace #"/+$" ""))
-        dir             (if (and (not-empty dir) (string/starts-with? dir "/"))
-                          (do
-                            (js/console.trace "WARN: detect absolute path, use URL instead")
-                            (str "file://" (js/encodeURI dir)))
-                          dir)
-        path            (some-> path (string/replace #"^/+" ""))
-        normalize-f     gp-util/path-normalize
-        encodeURI-f     js/encodeURI
-        safe-encode-url #(let [encoded-chars?
-                               (and (string? %) (boolean (re-find #"(?i)%[0-9a-f]{2}" %)))]
-                           (cond
-                             (not encoded-chars?)
-                             (encodeURI-f (normalize-f %))
-
-                             :else
-                             (encodeURI-f (normalize-f (js/decodeURI %)))))
-        path' (cond
-                (and path (string/starts-with? path "file:/"))
-                (safe-encode-url path)
-
-                (string/blank? path)
-                (safe-encode-url dir)
-
-                (string/blank? dir)
-                (safe-encode-url path)
-
-                (string/starts-with? path dir)
-                (safe-encode-url path)
-
-                :else
-                (let [path' (safe-encode-url path)]
-                  (str dir "/" path')))]
-    (if (mobile-util/native-ios?)
-      (ios-force-include-private path')
-      path')))
-
 (defn- local-container-path?
   "Check whether `path' is logseq's container `localDocumentsPath' on iOS"
   [path localDocumentsPath]
@@ -305,92 +301,95 @@
                        (not (or (local-container-path? path localDocumentsPath)
                                 (mobile-util/iCloud-container-path? path))))
               (state/pub-event! [:modal/show-instruction]))
+          path (if (mobile-util/native-ios?)
+                  (ios-force-include-private path)
+                  path)
           _ (js/console.log "Opening or Creating graph at directory: " path)
-          files (readdir path)
-          files (js->clj files :keywordize-keys true)]
-    (into [] (concat [{:path path}] files))))
+          files (get-files path)]
+    {:path path
+     :files (into [] files)}))
 
 (defrecord ^:large-vars/cleanup-todo Capacitorfs []
   protocol/Fs
   (mkdir! [_this dir]
-    (let [dir' (normalize-file-protocol-path "" dir)]
-      (-> (.mkdir Filesystem
-                  (clj->js
-                   {:path dir'}))
-          (p/catch (fn [error]
-                     (log/error :mkdir! {:path  dir'
-                                         :error error}))))))
+    (-> (<dir-exists? dir)
+        (p/then (fn [exists?]
+                  (if exists?
+                    (p/resolved true)
+                    (.mkdir Filesystem
+                            (clj->js
+                             {:path dir})))))
+        (p/catch (fn [error]
+                   (log/error :mkdir! {:path dir
+                                       :error error})))))
   (mkdir-recur! [_this dir]
-    (p/let
-     [_ (-> (.mkdir Filesystem
-                    (clj->js
-                     {:path dir
-                      :recursive true}))
-            (p/catch (fn [error]
-                       (log/error :mkdir-recur! {:path dir
-                                                 :error error}))))
-      stat (<stat dir)]
-      (if (= (:type stat) "directory")
-        (p/resolved true)
-        (p/rejected (js/Error. "mkdir-recur! failed")))))
+    (-> (<dir-exists? dir)
+        (p/then (fn [exists?]
+                  (if exists?
+                    (p/resolved true)
+                    (.mkdir Filesystem
+                            (clj->js
+                             {:path dir
+                              :recursive true})))))
+        (p/catch (fn [error]
+                   (log/error :mkdir-recur! {:path dir
+                                             :error error})))))
   (readdir [_this dir]                  ; recursive
-    (let [dir (if-not (string/starts-with? dir "file://")
-                (str "file://" dir)
-                dir)]
-      (readdir dir)))
-  (unlink! [this repo path _opts]
-    (p/let [path (normalize-file-protocol-path nil path)
-            repo-url (config/get-local-dir repo)
-            recycle-dir (util/safe-path-join repo-url config/app-name ".recycle") ;; logseq/.recycle
+    (let [dir (path/path-normalize dir)]
+      (get-file-paths dir)))
+  (unlink! [this repo fpath _opts]
+    (p/let [repo-dir (config/get-local-dir repo)
+            recycle-dir (path/path-join repo-dir config/app-name ".recycle") ;; logseq/.recycle
             ;; convert url to pure path
-            file-name (-> (string/replace path repo-url "")
-                          (string/replace "/" "_")
-                          (string/replace "\\" "_"))
-            new-path (str recycle-dir "/" file-name)
+            file-name (-> (path/trim-dir-prefix repo-dir fpath)
+                          (string/replace "/" "_"))
+            new-path (path/path-join recycle-dir file-name)
             _ (protocol/mkdir-recur! this recycle-dir)]
-      (protocol/rename! this repo path new-path)))
+      (protocol/rename! this repo fpath new-path)))
   (rmdir! [_this _dir]
     ;; Too dangerous!!! We'll never implement this.
     nil)
   (read-file [_this dir path _options]
-    (let [path (normalize-file-protocol-path dir path)]
+    (let [fpath (path/path-join dir path)]
       (->
-       (<read-file-with-utf8 path)
+       (<read-file-with-utf8 fpath)
        (p/catch (fn [error]
                   (log/error :read-file-failed error))))))
-  (write-file! [this repo dir path content opts]
-    (let [path (normalize-file-protocol-path dir path)]
+  (write-file! [_this repo dir path content opts]
+    (let [fpath (path/path-join dir path)]
       (p/let [stat (p/catch
-                    (.stat Filesystem (clj->js {:path path}))
+                    (.stat Filesystem (clj->js {:path fpath}))
                     (fn [_e] :not-found))]
         ;; `path` is full-path
-        (write-file-impl! this repo dir path content opts stat))))
-  (rename! [_this _repo old-path new-path]
-    (let [[old-path new-path] (map #(normalize-file-protocol-path "" %) [old-path new-path])]
-      (p/catch
-       (p/let [_ (.rename Filesystem
-                          (clj->js
-                           {:from old-path
-                            :to new-path}))])
-       (fn [error]
-         (log/error :rename-file-failed error)))))
+        (write-file-impl! repo dir path content opts stat))))
+  (rename! [_this _repo old-fpath new-fpath]
+    (-> (.rename Filesystem
+                 (clj->js
+                  {:from old-fpath
+                   :to new-fpath}))
+        (p/catch (fn [error]
+                   (log/error :rename-file-failed error)))))
   (copy! [_this _repo old-path new-path]
-    (let [[old-path new-path] (map #(normalize-file-protocol-path "" %) [old-path new-path])]
-      (p/catch
-       (p/let [_ (.copy Filesystem
-                        (clj->js
-                         {:from old-path
-                          :to new-path}))])
-       (fn [error]
-         (log/error :copy-file-failed error)))))
-  (stat [_this dir path]
-    (let [path (normalize-file-protocol-path dir path)]
-      (p/chain (.stat Filesystem (clj->js {:path path}))
-               #(js->clj % :keywordize-keys true))))
-  (open-dir [_this dir _ok-handler]
+    (-> (.copy Filesystem
+               (clj->js
+                {:from old-path
+                 :to new-path}))
+        (p/catch (fn [error]
+                   (log/error :copy-file-failed error)))))
+  (stat [_this fpath]
+    (-> (p/chain (.stat Filesystem (clj->js {:path fpath}))
+                 #(js->clj % :keywordize-keys true))
+        (p/catch (fn [error]
+                   (let [errstr (if error (.toString error) "")]
+                     (when (string/includes? errstr "because you don’t have permission to view it")
+                       (state/pub-event! [:notification/show
+                                          {:content "No permission, please clear cache and re-open graph folder."
+                                           :status :error}]))
+                     (p/rejected error))))))
+  (open-dir [_this dir]
     (open-dir dir))
-  (get-files [_this path-or-handle _ok-handler]
-    (readdir path-or-handle))
+  (get-files [_this dir]
+    (get-files dir))
   (watch-dir! [_this dir _options]
     (p/do!
      (.unwatch mobile-util/fs-watcher)

+ 101 - 0
src/main/frontend/fs/memory_fs.cljs

@@ -0,0 +1,101 @@
+(ns frontend.fs.memory-fs
+  "Memory FS backed by lightning-fs
+
+   Paths are denoted by `memory://`. No open-dir/get-files support."
+  (:require [cljs-bean.core :as bean]
+            [frontend.db :as db]
+            [frontend.fs.protocol :as protocol]
+            [logseq.common.path :as path]
+            [promesa.core :as p]))
+
+(defn- <readdir
+  "Read dir recursively, return all paths
+
+   accept dir as path, without memory:// prefix for simplicity"
+  [dir]
+  (p/let [result (p/loop [result []
+                          dirs [dir]]
+                   (if (empty? dirs)
+                     result
+                     (p/let [dir (first dirs)
+                             stat (js/window.pfs.stat dir)
+                             is-file? (= (.-type stat) "file")
+                             result (if is-file?
+                                      (conj result dir)
+                                      result)
+                             dir-content (when-not is-file?
+                                           (-> (js/window.pfs.readdir dir)
+                                               (p/then bean/->clj)
+                                               (p/then (fn [rpaths]
+                                                         (mapv #(path/path-join dir %) rpaths)))))]
+                       (p/recur result (concat (rest dirs) dir-content)))))]
+    result))
+
+
+(defn- <ensure-dir!
+  "dir is path, without memory:// prefix for simplicity"
+  [dir]
+  (-> (p/let [stat (js/window.pfs.stat dir)]
+        (cond
+          (= (.-type stat) "file")
+          (p/rejected "Path is a file")
+
+          :else
+          (p/resolved nil)))
+      (p/catch (fn [_error]
+                 (js/window.pfs.mkdir dir)))))
+
+
+(defrecord MemoryFs []
+  protocol/Fs
+  (mkdir! [_this dir]
+    (when js/window.pfs
+      (let [fpath (path/url-to-path dir)]
+        (-> (js/window.pfs.mkdir fpath)
+            (p/catch (fn [error] (println "(memory-fs)Mkdir error: " error)))))))
+  (readdir [_this dir]
+    (when js/window.pfs
+      (let [fpath (path/url-to-path dir)]
+        (-> (<readdir fpath)
+            (p/then (fn [rpaths]
+                      (mapv #(path/path-join "memory://" %) rpaths)))
+            (p/catch (fn [error]
+                       (println "(memory-fs)Readdir error: " error)
+                       (p/rejected error)))))))
+
+  (unlink! [_this _repo path opts]
+    (when js/window.pfs
+      (p/let [fpath (path/url-to-path path)
+              stat (js/window.pfs.stat fpath)]
+        (if (= (.-type stat) "file")
+          (js/window.pfs.unlink fpath opts)
+          (p/rejected "Unlinking a directory is not allowed, use rmdir! instead")))))
+  (rmdir! [_this dir]
+    (let [fpath (path/url-to-path dir)]
+      (js/window.workerThread.rimraf fpath)))
+  (read-file [_this dir path options]
+    (let [fpath (path/url-to-path (path/path-join dir path))]
+      (js/window.pfs.readFile fpath (clj->js options))))
+  (write-file! [_this repo dir rpath content _opts]
+    (p/let [fpath (path/url-to-path (path/path-join dir rpath))
+            containing-dir (path/parent fpath)
+            _ (<ensure-dir! containing-dir)
+            _ (js/window.pfs.writeFile fpath content)]
+      (db/set-file-content! repo rpath content)
+      (db/set-file-last-modified-at! repo rpath (js/Date.))))
+  (rename! [_this _repo old-path new-path]
+    (let [old-path (path/url-to-path old-path)
+          new-path (path/url-to-path new-path)]
+      (js/window.pfs.rename old-path new-path)))
+  (stat [_this fpath]
+    (let [fpath (path/url-to-path fpath)]
+      (js/window.pfs.stat fpath)))
+
+  (open-dir [_this _dir]
+    nil)
+  (get-files [_this _path-or-handle]
+    nil)
+  (watch-dir! [_this _dir _options]
+    nil)
+  (unwatch-dir! [_this _dir]
+    nil))

+ 285 - 156
src/main/frontend/fs/nfs.cljs

@@ -1,4 +1,10 @@
-(ns ^:no-doc frontend.fs.nfs
+(ns frontend.fs.nfs
+  "Browser File System API based fs implementation.
+
+   Rationale:
+   - nfs-file-handles-cache stores all file & directory handle
+   - idb stores top-level directory handle
+   - readdir/get-files is called by re-index and initial watcher to init all handles"
   (:require [frontend.fs.protocol :as protocol]
             [frontend.util :as util]
             [clojure.string :as string]
@@ -10,25 +16,28 @@
             [frontend.config :as config]
             [frontend.state :as state]
             [frontend.handler.notification :as notification]
-            ["/frontend/utils" :as utils]))
+            ["/frontend/utils" :as utils]
+            [logseq.graph-parser.util :as gp-util]
+            [logseq.common.path :as path]))
 
-;; We need to cache the file handles in the memory so that
+;; Cache the file handles in the memory so that
 ;; the browser will not keep asking permissions.
 (defonce nfs-file-handles-cache (atom {}))
 
-(defn get-nfs-file-handle
+(defn- get-nfs-file-handle
   [handle-path]
   (get @nfs-file-handles-cache handle-path))
 
 (defn add-nfs-file-handle!
   [handle-path handle]
+  (prn ::DEBUG "add-nfs-file-handle!" handle-path)
   (swap! nfs-file-handles-cache assoc handle-path handle))
 
 (defn remove-nfs-file-handle!
   [handle-path]
   (swap! nfs-file-handles-cache dissoc handle-path))
 
-(defn nfs-saved-handler
+(defn- nfs-saved-handler
   [repo path file]
   (when-let [last-modified (gobj/get file "lastModified")]
     ;; TODO: extract
@@ -38,9 +47,16 @@
       ;; Bad code
       (db/set-file-last-modified-at! repo path last-modified))))
 
+(defn- verify-handle-permission
+  [handle read-write?]
+  (utils/verifyPermission handle read-write?))
+
 (defn verify-permission
-  [repo handle read-write?]
-  (let [repo (or repo (state/get-current-repo))]
+  [repo read-write?]
+  (let [repo (or repo (state/get-current-repo))
+        repo-dir (config/get-repo-dir repo)
+        handle-path (str "handle/" repo-dir)
+        handle (get-nfs-file-handle handle-path)]
     (p/then
      (utils/verifyPermission handle read-write?)
      (fn []
@@ -50,185 +66,298 @@
 (defn check-directory-permission!
   [repo]
   (when (config/local-db? repo)
-    (p/let [handle (idb/get-item (str "handle/" repo))]
+    (p/let [repo-dir (config/get-repo-dir repo)
+            handle-path (str "handle/" repo-dir)
+            handle (idb/get-item handle-path)]
       (when handle
-        (verify-permission repo handle true)))))
+        (add-nfs-file-handle! handle-path handle)
+        (verify-permission repo true)))))
 
 (defn- contents-matched?
   [disk-content db-content]
   (when (and (string? disk-content) (string? db-content))
-    (p/resolved (= (string/trim disk-content) (string/trim db-content)))))
+    (= (string/trim disk-content) (string/trim db-content))))
+
+(defn- await-permission-granted
+  "Guard against File System Access API permission, avoiding early access before granted"
+  [repo]
+  (if (state/nfs-user-granted? repo)
+    (p/resolved true)
+    (js/Promise. (fn [resolve reject]
+                   (let [timer (atom nil)
+                         timer' (js/setInterval (fn []
+                                                  (when (state/nfs-user-granted? repo)
+                                                    (js/clearInterval @timer)
+                                                    (resolve true)))
+                                                1000)
+                         _ (reset! timer timer')]
+                     (js/setTimeout (fn []
+                                      (js/clearInterval timer)
+                                      (reject false))
+                                    100000))))))
+
+(defn await-get-nfs-file-handle
+  "for accessing File handle outside, ensuring user granted."
+  [repo handle-path]
+  (p/do!
+   (await-permission-granted repo)
+   (get-nfs-file-handle handle-path)))
+
+(defn- readdir-and-reload-all-handles
+  "Return list of filenames"
+  [root-dir root-handle]
+  (p/let [files (utils/getFiles root-handle
+                                true
+                                (fn [path entry]
+                                  (let [handle-path (str "handle/" path)]
+                                    ;; Same for all handles here, even for directories and ignored directories(for backing up)
+                                    ;; FileSystemDirectoryHandle or FileSystemFileHandle
+                                    (when-not (string/includes? path "/.")
+                                      (add-nfs-file-handle! handle-path entry)))))]
+    (->> files
+         (remove  (fn [file]
+                    (let [rpath (string/replace-first (.-webkitRelativePath file) (str root-dir "/") "")
+                          ext (util/get-file-ext rpath)]
+                      (or  (string/blank? rpath)
+                           (string/starts-with? rpath ".")
+                           (string/starts-with? rpath "logseq/bak")
+                           ; (string/starts-with? rpath "logseq/version-files")
+                           (not (contains? #{"md" "org" "excalidraw" "edn" "css"} ext))))))
+         (map (fn [file]
+                (-> (.-webkitRelativePath file)
+                    gp-util/path-normalize))))))
+
+
+(defn- get-files-and-reload-all-handles
+  "Return list of file objects"
+  [root-dir root-handle]
+  (p/let [files (utils/getFiles root-handle
+                                true
+                                (fn [path entry]
+                                  (let [handle-path (str "handle/" path)]
+                                    ;; Same for all handles here, even for directories and ignored directories(for backing up)
+                                    ;; FileSystemDirectoryHandle or FileSystemFileHandle
+                                    (when-not (string/includes? path "/.")
+                                      (add-nfs-file-handle! handle-path entry)))))]
+    (p/all (->> files
+                (remove  (fn [file]
+                           (let [rpath (string/replace-first (.-webkitRelativePath file) (str root-dir "/") "")
+                                 ext (util/get-file-ext rpath)]
+                             (or  (string/blank? rpath)
+                                  (string/starts-with? rpath ".")
+                                  (string/starts-with? rpath "logseq/bak")
+                                  (string/starts-with? rpath "logseq/version-files")
+                                  (not (contains? #{"md" "org" "excalidraw" "edn" "css"} ext))))))
+                ;; Read out using .text, Promise<string>
+                (map (fn [file]
+                       (p/let [content (.text file)]
+                         {:name        (.-name file)
+                          :path        (-> (.-webkitRelativePath file)
+                                           gp-util/path-normalize)
+                          :mtime       (.-lastModified file)
+                          :size        (.-size file)
+                          :type        (.-kind (.-handle file))
+                          :content     content
+                          :file/file   file
+                          :file/handle (.-handle file)})))))))
 
 (defrecord ^:large-vars/cleanup-todo Nfs []
   protocol/Fs
   (mkdir! [_this dir]
-    (let [parts (->> (string/split dir "/")
-                     (remove string/blank?))
-          root (->> (butlast parts)
-                    util/string-join-path)
-          new-dir (last parts)
-          root-handle (str "handle/" root)]
-      (->
-       (p/let [handle (idb/get-item root-handle)
-               _ (when handle (verify-permission nil handle true))]
-         (when (and handle new-dir
-                    (not (string/blank? new-dir)))
-           (p/let [handle (.getDirectoryHandle ^js handle new-dir
-                                               #js {:create true})
-                   handle-path (str root-handle "/" new-dir)
-                   _ (idb/set-item! handle-path handle)]
-             (add-nfs-file-handle! handle-path handle)
-             (println "Stored handle: " (str root-handle "/" new-dir)))))
-       (p/catch (fn [error]
-                  (js/console.debug "mkdir error: " error ", dir: " dir)
-                  (throw error))))))
+    (let [dir (path/path-normalize dir)
+          parent-dir (path/parent dir)
+
+          parent-handle-path (str "handle/" parent-dir)]
+      (-> (p/let [parent-handle (or (get-nfs-file-handle parent-handle-path)
+                                    (idb/get-item parent-handle-path))
+                  _ (when parent-handle (verify-handle-permission parent-handle true))]
+            (when parent-handle
+              (p/let [new-dir-name (path/filename dir)
+                      new-handle (.getDirectoryHandle ^js parent-handle new-dir-name
+                                                      #js {:create true})
+                      handle-path (str "handle/" dir)
+                      _ (idb/set-item! handle-path new-handle)]
+                (add-nfs-file-handle! handle-path new-handle)
+                (println "dir created: " dir))))
+          (p/catch (fn [error]
+                     (js/console.debug "mkdir error: " error ", dir: " dir)
+                     (throw error))))))
 
   (readdir [_this dir]
-    (let [prefix (str "handle/" dir)
-          cached-files (keys @nfs-file-handles-cache)]
-      (p/resolved
-       (->> (filter #(string/starts-with? % (str prefix "/")) cached-files)
-            (map (fn [path]
-                   (string/replace path prefix "")))))))
-
-  (unlink! [this repo path _opts]
-    (let [[dir basename] (util/get-dir-and-basename path)
-          handle-path (str "handle" path)]
+    ;; This method is only used for repo-dir and version-files dir
+    ;; There's no Logseq Sync support for nfs. So assume dir is always a repo dir.
+    (p/let [repo-url (str "logseq_local_" dir)
+            _ (await-permission-granted repo-url)
+            handle-path (str "handle/" dir)
+            handle (or (get-nfs-file-handle handle-path)
+                       (idb/get-item handle-path))
+            _ (when handle
+                (verify-handle-permission handle true))
+            fpaths (if (string/includes? dir "/")
+                     (js/console.error "ERROR: unimpl")
+                     (readdir-and-reload-all-handles dir handle))]
+      fpaths))
+
+  (unlink! [this repo fpath _opts]
+    (let [repo-dir (config/get-repo-dir repo)
+          filename (path/filename fpath)
+          handle-path (str "handle/" fpath)
+          recycle-dir (path/path-join repo-dir config/app-name config/recycle-dir)]
       (->
-       (p/let [recycle-dir (str "/" repo (util/format "/%s/%s" config/app-name config/recycle-dir))
-               _ (protocol/mkdir! this recycle-dir)
-               handle (idb/get-item handle-path)
+       (p/let [_ (protocol/mkdir! this recycle-dir)
+               handle (get-nfs-file-handle handle-path)
                file (.getFile handle)
                content (.text file)
-               handle (idb/get-item (str "handle" dir))
-               _ (idb/remove-item! handle-path)
-               file-name (-> (string/replace path (str "/" repo "/") "")
-                             (string/replace "/" "_")
-                             (string/replace "\\" "_"))
-               new-path (str recycle-dir "/" file-name)
-               _ (protocol/write-file! this repo
-                                       "/"
-                                       new-path
-                                       content nil)]
-         (when handle
-           (.removeEntry ^js handle basename))
+
+               bak-handle (get-nfs-file-handle (str "handle/" recycle-dir))
+               bak-filename (-> (path/relative-path repo-dir fpath)
+                                (string/replace "/" "_")
+                                (string/replace "\\" "_"))
+               file-handle (.getFileHandle ^js bak-handle bak-filename #js {:create true})
+               _ (utils/writeFile file-handle content)
+
+               parent-dir (path/parent fpath)
+               parent-handle (get-nfs-file-handle (str "handle/" parent-dir))
+               _ (when parent-handle
+                   (.removeEntry ^js parent-handle filename))]
+         (idb/remove-item! handle-path)
          (remove-nfs-file-handle! handle-path))
        (p/catch (fn [error]
-                  (log/error :unlink/path {:path path
+                  (log/error :unlink/path {:path fpath
                                            :error error}))))))
 
   (rmdir! [_this _dir]
-    ;; TOO dangerious, we should never implement this
     nil)
 
   (read-file [_this dir path _options]
-    (let [handle-path (str "handle" dir "/" path)]
-      (p/let [handle (idb/get-item handle-path)
+    (p/let [fpath (path/path-join dir path)
+            handle-path (str "handle/" fpath)]
+      (p/let [handle (or (get-nfs-file-handle handle-path)
+                         (idb/get-item handle-path))
               local-file (and handle (.getFile handle))]
         (and local-file (.text local-file)))))
 
   (write-file! [_this repo dir path content opts]
-    (let [parts (string/split path "/")
-          basename (last parts)
-          sub-dir (->> (butlast parts)
-                       (remove string/blank?)
-                       util/string-join-path)
-          sub-dir-handle-path (str "handle/"
-                                   (subs dir 1)
-                                   (when sub-dir
-                                     (str "/" sub-dir)))
-          handle-path (if (= "/" (last sub-dir-handle-path))
-                        (subs sub-dir-handle-path 0 (dec (count sub-dir-handle-path)))
-                        sub-dir-handle-path)
-          handle-path (string/replace handle-path "//" "/")
-          basename-handle-path (str handle-path "/" basename)]
-      (p/let [file-handle (idb/get-item basename-handle-path)]
-        ;; check file-handle available, remove it when got 'NotFoundError'
-        (p/let [test-get-file (when file-handle
-                                (p/catch (p/let [_ (.getFile file-handle)] true)
-                                         (fn [e]
-                                           (js/console.dir e)
-                                           (when (= "NotFoundError" (.-name e))
-                                             (idb/remove-item! basename-handle-path)
-                                             (remove-nfs-file-handle! basename-handle-path))
-                                           false)))
-                file-handle (if test-get-file file-handle nil)]
-
-          (when file-handle
-            (add-nfs-file-handle! basename-handle-path file-handle))
-          (if file-handle
-            (-> (p/let [local-file (.getFile file-handle)
-                        local-content (.text local-file)
-                        ext (string/lower-case (util/get-file-ext path))
-                        db-content (db/get-file repo path)
-                        contents-matched? (contents-matched? local-content (or db-content ""))]
-                  (when local-content
-                    (if (and
-                         (not (string/blank? db-content))
-                         (not (:skip-compare? opts))
-                         (not contents-matched?)
-                         (not (contains? #{"excalidraw" "edn" "css"} ext))
-                         (not (string/includes? path "/.recycle/")))
-                      (state/pub-event! [:file/not-matched-from-disk path local-content content])
-                      (p/let [_ (verify-permission repo file-handle true)
-                              _ (utils/writeFile file-handle content)
-                              file (.getFile file-handle)]
-                        (when file
-                          (db/set-file-content! repo path content)
-                          (nfs-saved-handler repo path file))))))
-                (p/catch (fn [e]
-                           (js/console.error e))))
-            ;; create file handle
-            (->
-             (p/let [handle (idb/get-item handle-path)]
-               (if handle
-                 (p/let [_ (verify-permission repo handle true)
-                         file-handle (.getFileHandle ^js handle basename #js {:create true})
-                         ;; File exists if the file-handle has some content in it.
-                         file (.getFile file-handle)
-                         text (.text file)]
-                   (if (string/blank? text)
-                     (p/let [_ (idb/set-item! basename-handle-path file-handle)
-                             _ (utils/writeFile file-handle content)
-                             file (.getFile file-handle)]
-                       (when file
-                         (nfs-saved-handler repo path file)))
-                     (do
-                       (notification/show! (str "The file " path " already exists, please append the content if you need it.\n Unsaved content: \n" content)
-                                          :warning
-                                          false)
-                       (state/pub-event! [:file/alter repo path text]))))
-                 (println "Error: directory handle not exists: " handle-path)))
-             (p/catch (fn [error]
-                        (println "Write local file failed: " {:path path})
-                        (js/console.error error)))))))))
+    ;; TODO: file backup handling
+    (let [fpath (path/path-join dir path)
+          ext (util/get-file-ext path)
+          file-handle-path (str "handle/" fpath)]
+      (p/let [file-handle (get-nfs-file-handle file-handle-path)]
+        (if file-handle
+          ;; file exist
+          (p/let [local-file (.getFile file-handle)
+                  disk-content (.text local-file)
+                  db-content (db/get-file repo path)
+                  contents-matched? (contents-matched? disk-content db-content)]
+            (if (and
+                 (not (string/blank? db-content))
+                 (not (:skip-compare? opts))
+                 (not contents-matched?)
+                 (not (contains? #{"excalidraw" "edn" "css"} ext))
+                 (not (string/includes? path "/.recycle/")))
+              (state/pub-event! [:file/not-matched-from-disk path disk-content content])
+              (p/let [_ (verify-permission repo true)
+                      _ (utils/writeFile file-handle content)
+                      file (.getFile file-handle)]
+                (when file
+                  (db/set-file-content! repo path content)
+                  (nfs-saved-handler repo path file)))))
+          ;; file no-exist, write via parent dir handle
+          (p/let [basename (path/filename fpath)
+                  parent-dir (path/parent fpath)
+                  parent-dir-handle-path (str "handle/" parent-dir)
+                  parent-dir-handle (get-nfs-file-handle parent-dir-handle-path)]
+
+            (if parent-dir-handle
+              ;; create from directory handle
+              (p/let [file-handle (.getFileHandle ^js parent-dir-handle basename #js {:create true})
+                      _  (add-nfs-file-handle! file-handle-path file-handle)
+                      file (.getFile file-handle)
+                      text (.text file)]
+                (if (string/blank? text)
+                  (p/let [;; _ (idb/set-item! file-handle-path file-handle)
+                          _ (utils/writeFile file-handle content)
+                          file (.getFile file-handle)]
+                    (when file
+                      (nfs-saved-handler repo path file)))
+                  (do
+                    (notification/show! (str "The file " path " already exists, please append the content if you need it.\n Unsaved content: \n" content)
+                                        :warning
+                                        false)
+                    (state/pub-event! [:file/alter repo path text]))))
+
+              ;; TODO(andelf): Create parent directory and write
+              ;; Normally directory are created layer by layer. So it's safe to leave this unimplemented.
+              (js/console.error "TODO: can not create directory hierarchy")))))))
 
   (rename! [this repo old-path new-path]
-    (p/let [parts (->> (string/split new-path "/")
-                       (remove string/blank?))
-            dir (str "/" (first parts))
-            new-path (->> (rest parts)
-                          util/string-join-path)
-            handle (idb/get-item (str "handle" old-path))
-            file (.getFile handle)
-            content (.text file)
-            _ (protocol/write-file! this repo dir new-path content nil)]
-      (protocol/unlink! this repo old-path nil)))
-  (stat [_this dir path]
-    (if-let [file (get-nfs-file-handle (str "handle/"
-                                            (string/replace-first dir "/" "")
-                                            path))]
-      (p/let [file (.getFile file)]
+    (p/let [repo-dir (config/get-repo-dir repo)
+            old-rpath (path/relative-path repo-dir old-path)
+            new-rpath (path/relative-path repo-dir new-path)
+            old-content (protocol/read-file this repo-dir old-rpath nil)
+            _ (protocol/write-file! this repo repo-dir new-rpath old-content nil)
+            _ (protocol/unlink! this repo old-path nil)]))
+
+  (stat [_this fpath]
+    (if-let [handle (get-nfs-file-handle (str "handle/" fpath))]
+      (p/let [_ (verify-handle-permission handle true)
+              file (.getFile handle)]
         (let [get-attr #(gobj/get file %)]
-          {:file/last-modified-at (get-attr "lastModified")
-           :file/size (get-attr "size")
-           :file/type (get-attr "type")}))
+          {:last-modified-at (get-attr "lastModified")
+           :size (get-attr "size")
+           :path fpath
+           :type (get-attr "type")}))
       (p/rejected "File not exists")))
-  (open-dir [_this _dir ok-handler]
-    (utils/openDirectory #js {:recursive true}
-                         ok-handler))
-  (get-files [_this path-or-handle ok-handler]
-    (utils/getFiles path-or-handle true ok-handler))
+
+  (open-dir [_this _dir]
+    (p/let [files (utils/openDirectory #js {:recursive true
+                                            :mode "readwrite"}
+                                       (fn [path entry]
+                                         (let [handle-path (str "handle/" path)]
+                                           ;; Same all handles here, even for directories and ignored directories(for backing up)
+                                           ;; FileSystemDirectoryHandle or FileSystemFileHandle
+                                           (when-not (string/includes? path "/.")
+                                             (add-nfs-file-handle! handle-path entry)))))
+            dir-handle (first files) ;; FileSystemDirectoryHandle
+            dir-name (.-name dir-handle)
+            files (->> (next files)
+                       (remove  (fn [file]
+                                  (let [rpath (.-webkitRelativePath file) ;
+                                        ; (string/replace-first (.-webkitRelativePath file) (str dir-name "/") "")
+                                        ext (util/get-file-ext rpath)]
+                                    (or  (string/blank? rpath)
+                                         (string/starts-with? rpath ".")
+                                         (string/starts-with? rpath "logseq/bak")
+                                         (string/starts-with? rpath "logseq/version-files")
+                                         (not (contains? #{"md" "org" "excalidraw" "edn" "css"} ext))))))
+                       ;; Read out using .text, Promise<string>
+                       (map (fn [file]
+                              (js/console.log "handle" file)
+                              (p/let [content (.text file)]
+                                ;; path content size mtime
+                                {:name        (.-name file)
+                                 :path        (-> (.-webkitRelativePath file)
+                                                  gp-util/path-normalize)
+                                 :mtime       (.-lastModified file)
+                                 :size        (.-size file)
+                                 :type        (.-kind (.-handle file))
+                                 :content     content
+                                 ;; expose the following, they are used by the file system
+                                 :file/file   file
+                                 :file/handle (.-handle file)}))))
+            files (p/all files)]
+      (add-nfs-file-handle! (str "handle/" dir-name) dir-handle)
+      (idb/set-item! (str "handle/" dir-name) dir-handle)
+      {:path dir-name
+       :files files}))
+
+  (get-files [_this dir]
+    (when (string/includes? dir "/")
+      (js/console.error "BUG: get-files(nfs) only accepts repo-dir"))
+    (p/let [handle-path (str "handle/" dir)
+            handle (get-nfs-file-handle handle-path)
+            files (get-files-and-reload-all-handles dir handle)]
+      files))
 
   (watch-dir! [_this _dir _options]
     nil)

+ 76 - 76
src/main/frontend/fs/node.cljs

@@ -1,6 +1,7 @@
 (ns frontend.fs.node
-  "Implementation of fs protocol for desktop"
-  (:require [clojure.string :as string]
+  "Implementation of fs protocol for Electron, based on nodejs"
+  (:require [cljs-bean.core :as bean]
+            [clojure.string :as string]
             [electron.ipc :as ipc]
             [frontend.config :as config]
             [frontend.db :as db]
@@ -9,21 +10,8 @@
             [frontend.util :as util]
             [goog.object :as gobj]
             [lambdaisland.glogi :as log]
-            [promesa.core :as p]))
-
-(defn concat-path
-  [dir path]
-  (cond
-    (nil? path)
-    dir
-
-    (string/starts-with? path dir)
-    path
-
-    :else
-    (str (string/replace dir #"/$" "")
-         (when path
-           (str "/" (string/replace path #"^/" ""))))))
+            [promesa.core :as p]
+            [logseq.common.path :as path]))
 
 (defn- contents-matched?
   [disk-content db-content]
@@ -31,55 +19,62 @@
     (p/resolved (= (string/trim disk-content) (string/trim db-content)))))
 
 (defn- write-file-impl!
-  [this repo dir path content {:keys [ok-handler error-handler old-content skip-compare?]} stat]
-  (if skip-compare?
-    (p/catch
-        (p/let [result (ipc/ipc "writeFile" repo path content)]
-          (when ok-handler
-            (ok-handler repo path result)))
-        (fn [error]
-          (if error-handler
-            (error-handler error)
-            (log/error :write-file-failed error))))
+  [repo dir rpath content {:keys [ok-handler error-handler old-content skip-compare?]} stat]
+  (let [file-fpath (path/path-join dir rpath)]
+    (if skip-compare?
+      (p/catch
+       (p/let [result (ipc/ipc "writeFile" repo file-fpath content)]
+         (when ok-handler
+           (ok-handler repo rpath result)))
+       (fn [error]
+         (if error-handler
+           (error-handler error)
+           (log/error :write-file-failed error))))
 
-    (p/let [disk-content (when (not= stat :not-found)
-                           (-> (protocol/read-file this dir path nil)
-                               (p/catch (fn [error]
-                                          (js/console.error error)
-                                          nil))))
-            disk-content (or disk-content "")
-            ext (string/lower-case (util/get-file-ext path))
-            db-content (or old-content (db/get-file repo path) "")
-            contents-matched? (contents-matched? disk-content db-content)]
-      (cond
-        (and
-         (not= stat :not-found)         ; file on the disk was deleted
-         (not contents-matched?)
-         (not (contains? #{"excalidraw" "edn" "css"} ext))
-         (not (string/includes? path "/.recycle/")))
-        (state/pub-event! [:file/not-matched-from-disk path disk-content content])
+      (p/let [disk-content (when (not= stat :not-found)
+                             (-> (ipc/ipc "readFile" file-fpath)
+                                 (p/then bean/->clj)
+                                 (p/catch (fn [error]
+                                            (js/console.error error)
+                                            nil))))
+              disk-content (or disk-content "")
+              ext (string/lower-case (util/get-file-ext rpath))
+              db-content (or old-content (db/get-file repo rpath) "")
+              contents-matched? (contents-matched? disk-content db-content)]
+        (cond
+          (and
+           (not= stat :not-found)         ; file on the disk was deleted
+           (not contents-matched?)
+           (not (contains? #{"excalidraw" "edn" "css"} ext))
+           (not (string/includes? rpath "/.recycle/")))
+          (state/pub-event! [:file/not-matched-from-disk rpath disk-content content])
 
-        :else
-        (->
-         (p/let [result (ipc/ipc "writeFile" repo path content)
-                 mtime (gobj/get result "mtime")]
-           (when-not contents-matched?
-             (ipc/ipc "backupDbFile" (config/get-local-dir repo) path disk-content content))
-           (db/set-file-last-modified-at! repo path mtime)
-           (db/set-file-content! repo path content)
-           (when ok-handler
-             (ok-handler repo path result))
-           result)
-         (p/catch (fn [error]
-                    (if error-handler
-                      (error-handler error)
-                      (log/error :write-file-failed error)))))))))
+          :else
+          (->
+           (p/let [result (ipc/ipc "writeFile" repo file-fpath content)
+                   mtime (gobj/get result "mtime")]
+             (when-not contents-matched?
+               (ipc/ipc "backupDbFile" (config/get-local-dir repo) rpath disk-content content))
+             (db/set-file-last-modified-at! repo rpath mtime)
+             (db/set-file-content! repo rpath content)
+             (when ok-handler
+               (ok-handler repo rpath result))
+             result)
+           (p/catch (fn [error]
+                      (if error-handler
+                        (error-handler error)
+                        (log/error :write-file-failed error))))))))))
 
-(defn- open-dir [dir]
+(defn- open-dir
+  "Open a new directory"
+  [dir]
   (p/let [dir-path (or dir (util/mocked-open-dir-path))
           result (if dir-path
-                   (ipc/ipc "getFiles" dir-path)
-                   (ipc/ipc "openDir" {}))]
+                   (do
+                     (println "NOTE: Using mocked dir" dir-path)
+                     (ipc/ipc "getFiles" dir-path))
+                   (ipc/ipc "openDir" {}))
+          result (bean/->clj result)]
     result))
 
 (defrecord Node []
@@ -89,7 +84,8 @@
   (mkdir-recur! [_this dir]
     (ipc/ipc "mkdir-recur" dir))
   (readdir [_this dir]                   ; recursive
-    (ipc/ipc "readdir" dir))
+    (p/then (ipc/ipc "readdir" dir)
+            bean/->clj))
   (unlink! [_this repo path _opts]
     (ipc/ipc "unlink"
              (config/get-repo-dir repo)
@@ -98,25 +94,29 @@
     ;; Too dangerious!!! We'll never implement this.
     nil)
   (read-file [_this dir path _options]
-    (let [path (concat-path dir path)]
+    (let [path (if (nil? dir)
+                 path
+                 (path/path-join dir path))]
       (ipc/ipc "readFile" path)))
   (write-file! [this repo dir path content opts]
-    (let [path (concat-path dir path)]
-      (p/let [stat (p/catch
-                       (protocol/stat this dir path)
-                       (fn [_e] :not-found))
-              sub-dir (first (util/get-dir-and-basename path))
-              _ (protocol/mkdir-recur! this sub-dir)]
-        (write-file-impl! this repo dir path content opts stat))))
+    (p/let [fpath (path/path-join dir path)
+            stat (p/catch
+                  (protocol/stat this fpath)
+                  (fn [_e] :not-found))
+            parent-dir (path/parent fpath)
+            _ (protocol/mkdir-recur! this parent-dir)]
+      (write-file-impl! repo dir path content opts stat)))
   (rename! [_this _repo old-path new-path]
     (ipc/ipc "rename" old-path new-path))
-  (stat [_this dir path]
-    (let [path (concat-path dir path)]
-      (ipc/ipc "stat" path)))
-  (open-dir [_this dir _ok-handler]
+  (stat [_this fpath]
+    (-> (ipc/ipc "stat" fpath)
+        (p/then bean/->clj)))
+  (open-dir [_this dir]
     (open-dir dir))
-  (get-files [_this path-or-handle _ok-handler]
-    (ipc/ipc "getFiles" path-or-handle))
+  (get-files [_this dir]
+    (-> (ipc/ipc "getFiles" dir)
+        (p/then (fn [result]
+                  (:files (bean/->clj result))))))
   (watch-dir! [_this dir options]
     (ipc/ipc "addDirWatcher" dir options))
   (unwatch-dir! [_this dir]

+ 23 - 9
src/main/frontend/fs/protocol.cljs

@@ -3,21 +3,35 @@
   {:clj-kondo/config {:linters {:private-call {:level :off}}}})
 
 (defprotocol Fs
+  ;; TODO(andelf): merge mkdir! & mkdir-recur!
   (mkdir! [this dir])
   (mkdir-recur! [this dir])
-  (readdir [this dir])
+  ;; TODO(andelf): clarify the return value. How is this different from `get-files`?
+  (readdir [this dir]
+    "Read directory and return list of files. Won't read file out.
+     Used by initial watcher, version files of Logseq Sync.
+     
+     => [string]")
   (unlink! [this repo path opts])
+  ;; FIXME(andelf): remove this API? since the only usage is plugin API
   (rmdir! [this dir])
   (read-file [this dir path opts])
   (write-file! [this repo dir path content opts])
   (rename! [this repo old-path new-path])
   (copy! [this repo old-path new-path])
-  (stat [this dir path])
-  (open-dir [this dir ok-handler])
-  (get-files [this path-or-handle ok-handler])
+  (stat [this path]
+    "=> {:type string :size number :mtime number}")
+
+  ;; The following APIs are optional
+  (open-dir [this dir]
+    "Open a directory and return the files in it.
+     Used by open a new graph.
+     
+     => {:path string :files [{...}]}")
+  (get-files [this dir]
+    "Almost the same as `open-dir`. For returning files.
+     Used by re-index/refresh.
+     
+     => [{:path string :content string}] (absolute path)")
   (watch-dir! [this dir options])
-  (unwatch-dir! [this dir])
-  ;; Ensure the dir is watched, window agnostic.
-  ;; Implementation should handle the actual watcher's construction / destruction.
-  ;; So shouldn't consider `unwatch-dir!`.
-  )
+  (unwatch-dir! [this dir]))

+ 29 - 25
src/main/frontend/fs/sync.cljs

@@ -35,7 +35,7 @@
             [lambdaisland.glogi :as log]
             [frontend.fs.capacitor-fs :as capacitor-fs]
             ["@capawesome/capacitor-background-task" :refer [BackgroundTask]]
-            ["path" :as path]))
+            ["path" :as node-path]))
 
 ;;; ### Commentary
 ;; file-sync related local files/dirs:
@@ -662,7 +662,7 @@
   (let [favorite-pages* (set favorite-pages)]
     (fn [^FileMetadata item]
       (let [path (relative-path item)
-            journal-dir (path/join (config/get-journals-directory) path/sep)
+            journal-dir (node-path/join (config/get-journals-directory) node-path/sep)
             journal? (string/starts-with? path journal-dir)
             journal-day
             (when journal?
@@ -694,9 +694,8 @@
           (- (.-size item)))))))
 ;;; ### path-normalize
 (def path-normalize
-  (if (util/electron?)
-    gp-util/path-normalize
-    (partial capacitor-fs/normalize-file-protocol-path nil)))
+
+  gp-util/path-normalize)
 
 
 ;;; ### APIs
@@ -724,6 +723,7 @@
   (<get-remote-all-files-meta [this graph-uuid] "get all remote files' metadata")
   (<get-remote-files-meta [this graph-uuid filepaths] "get remote files' metadata")
   (<get-remote-graph [this graph-name-opt graph-uuid-opt] "get graph info by GRAPH-NAME-OPT or GRAPH-UUID-OPT")
+  (<get-remote-txid [this graph-uuid] "get remote graph's txid")
   (<get-remote-file-versions [this graph-uuid filepath] "get file's version list")
   (<list-remote-graphs [this] "list all remote graphs")
   (<get-deletion-logs [this graph-uuid from-txid] "get deletion logs from FROM-TXID")
@@ -1267,6 +1267,10 @@
                                        (seq graph-uuid-opt)
                                        (assoc :GraphUUID graph-uuid-opt))))))
 
+  (<get-remote-txid [this graph-uuid]
+    (user/<wrap-ensure-id&access-token
+     (<! (.<request this "get_txid" {:GraphUUID graph-uuid}))))
+
   (<get-remote-file-versions [this graph-uuid filepath]
     (user/<wrap-ensure-id&access-token
      (let [encrypted-path (first (<! (<encrypt-fnames rsapi graph-uuid [filepath])))]
@@ -1377,7 +1381,7 @@
      (let [partitioned-files (partition-all 20 (<! (<encrypt-fnames rsapi graph-uuid filepaths)))]
        (loop [[files & others] partitioned-files]
          (when files
-           (let [current-txid (:TXId (<! (<get-remote-graph this nil graph-uuid)))]
+           (let [current-txid (:TXId (<! (<get-remote-txid this graph-uuid)))]
              (<! (.<request this "delete_files" {:GraphUUID graph-uuid :TXId current-txid :Files files}))
              (recur others))))))))
 
@@ -1425,8 +1429,8 @@
 (defn- is-journals-or-pages?
   [filetxn]
   (let [rel-path (relative-path filetxn)]
-    (or (string/starts-with? rel-path (path/join (config/get-journals-directory) path/sep))
-        (string/starts-with? rel-path (path/join (config/get-pages-directory) path/sep)))))
+    (or (string/starts-with? rel-path (node-path/join (config/get-journals-directory) node-path/sep))
+        (string/starts-with? rel-path (node-path/join (config/get-pages-directory) node-path/sep)))))
 
 (defn- need-add-version-file?
   "when we need to create a new version file:
@@ -1442,10 +1446,10 @@
       (.-deleted? filetxn)
       false
       (.-updated? filetxn)
-      (let [path (relative-path filetxn)
+      (let [rpath (relative-path filetxn)
             repo (state/get-current-repo)
-            file-path (config/get-file-path repo path)
-            content (<! (p->c (fs/read-file "" file-path)))]
+            repo-dir (config/get-repo-dir repo)
+            content (<! (p->c (fs/read-file repo-dir rpath)))]
         (and (seq origin-db-content)
              (or (nil? content)
                  (some :removed (diff/diff origin-db-content content))))))))
@@ -1468,7 +1472,7 @@
 (defn- assert-local-txid<=remote-txid
   []
   (when-let [local-txid (last @graphs-txid)]
-    (go (let [remote-txid (:TXId (<! (<get-remote-graph remoteapi nil (second @graphs-txid))))]
+    (go (let [remote-txid (:TXId (<! (<get-remote-txid remoteapi (second @graphs-txid))))]
           (assert (<= local-txid remote-txid)
                   [@graphs-txid local-txid remote-txid])))))
 
@@ -1541,7 +1545,7 @@
             txn->db-content-vec (->> filetxns
                                      (mapv
                                       #(when (is-journals-or-pages? %)
-                                         [% (db/get-file repo (config/get-file-path repo (relative-path %)))]))
+                                         [% (db/get-file repo (relative-path %))]))
                                      (remove nil?))]
 
         (doseq [relative-p (map relative-path filetxns)]
@@ -2323,12 +2327,12 @@
                 sorted-diff-remote-files
                                         (sort-by
                                          (sort-file-metadata-fn :recent-days-range recent-10-days-range) > diff-remote-files)
-                remote-graph-info-or-ex (<! (<get-remote-graph remoteapi nil graph-uuid))
-                latest-txid             (:TXId remote-graph-info-or-ex)]
-            (if (or (instance? ExceptionInfo remote-graph-info-or-ex) (nil? latest-txid))
+                remote-txid-or-ex       (<! (<get-remote-txid remoteapi graph-uuid))
+                latest-txid             (:TXId remote-txid-or-ex)]
+            (if (or (instance? ExceptionInfo remote-txid-or-ex) (nil? latest-txid))
               (do (put-sync-event! {:event :get-remote-graph-failed
                                     :data {:graph-uuid graph-uuid
-                                           :exp remote-graph-info-or-ex
+                                           :exp remote-txid-or-ex
                                            :epoch (tc/to-epoch (t/now))}})
                   {:stop true})
               (do (println "[full-sync(remote->local)]" (count sorted-diff-remote-files) "files need to sync")
@@ -2562,12 +2566,12 @@
 
               (need-reset-local-txid? r*) ;; TODO: this cond shouldn't be true,
               ;; but some potential bugs cause local-txid > remote-txid
-              (let [remote-graph-info-or-ex (<! (<get-remote-graph remoteapi nil graph-uuid))
-                    remote-txid             (:TXId remote-graph-info-or-ex)]
-                (if (or (instance? ExceptionInfo remote-graph-info-or-ex) (nil? remote-txid))
+              (let [remote-txid-or-ex (<! (<get-remote-txid remoteapi graph-uuid))
+                    remote-txid             (:TXId remote-txid-or-ex)]
+                (if (or (instance? ExceptionInfo remote-txid-or-ex) (nil? remote-txid))
                   (do (put-sync-event! {:event :get-remote-graph-failed
                                         :data  {:graph-uuid graph-uuid
-                                                :exp        remote-graph-info-or-ex
+                                                :exp        remote-txid-or-ex
                                                 :epoch      (tc/to-epoch (t/now))}})
                       {:stop true})
                   (do (<! (<update-graphs-txid! remote-txid graph-uuid user-uuid repo))
@@ -2701,7 +2705,7 @@
   Object
   (schedule [this next-state args reason]
     {:pre [(s/valid? ::state next-state)]}
-    (println "[SyncManager" graph-uuid "]"
+    (println (str "[SyncManager " graph-uuid "]")
              (and state (name state)) "->" (and next-state (name next-state)) :reason reason :local-txid @*txid :now (tc/to-string (t/now)))
     (set! state next-state)
     (swap! *sync-state sync-state--update-state next-state)
@@ -2766,7 +2770,7 @@
           remote->local
           (let [txid
                 (if (true? remote->local)
-                  {:txid (:TXId (<! (<get-remote-graph remoteapi nil graph-uuid)))}
+                  {:txid (:TXId (<! (<get-remote-txid remoteapi graph-uuid)))}
                   remote->local)]
             (when (some? txid)
               (>! ops-chan {:remote->local txid}))
@@ -3091,7 +3095,7 @@
 (defn <sync-stop []
   (go
     (when-let [sm ^SyncManager (state/get-file-sync-manager (state/get-current-file-sync-graph-uuid))]
-      (println "[SyncManager" (:graph-uuid sm) "]" "stopping")
+      (println (str "[SyncManager " (:graph-uuid sm) "]") "stopping")
 
       (state/clear-file-sync-state! (:graph-uuid sm))
 
@@ -3099,7 +3103,7 @@
 
       (reset! *sync-entered? false)
 
-      (println "[SyncManager" (:graph-uuid sm) "]" "stopped"))
+      (println (str "[SyncManager " (:graph-uuid sm) "]") "stopped"))
 
     (reset! current-sm-graph-uuid nil)))
 

+ 76 - 49
src/main/frontend/fs/watcher_handler.cljs

@@ -1,25 +1,24 @@
 (ns frontend.fs.watcher-handler
   "Main ns that handles file watching events from electron's main process"
-  (:require [clojure.string :as string]
+  (:require [clojure.set :as set]
+            [clojure.string :as string]
             [frontend.config :as config]
             [frontend.db :as db]
             [frontend.db.model :as model]
+            [frontend.fs :as fs]
+            [logseq.common.path :as path]
             [frontend.handler.editor :as editor]
             [frontend.handler.file :as file-handler]
             [frontend.handler.page :as page-handler]
             [frontend.handler.ui :as ui-handler]
-            [logseq.graph-parser.util :as gp-util]
+            [frontend.state :as state]
+            [frontend.util :as util]
+            [frontend.util.fs :as fs-util]
+            [lambdaisland.glogi :as log]
             [logseq.graph-parser.config :as gp-config]
             [logseq.graph-parser.util.block-ref :as block-ref]
-            [frontend.mobile.util :as mobile-util]
-            [lambdaisland.glogi :as log]
             [promesa.core :as p]
-            [frontend.state :as state]
-            [frontend.fs :as fs]
-            [frontend.fs.capacitor-fs :as capacitor-fs]
-            [frontend.util.fs :as fs-util]
-            [frontend.util :as util]
-            [clojure.set :as set]))
+            [frontend.handler.global-config :as global-config-handler]))
 
 ;; all IPC paths must be normalized! (via gp-util/path-normalize)
 
@@ -51,15 +50,19 @@
 (defn handle-changed!
   [type {:keys [dir path content stat global-dir] :as payload}]
   (when dir
-    (let [path (gp-util/path-normalize path)
-          path (if (mobile-util/native-platform?)
-                 (capacitor-fs/normalize-file-protocol-path nil path)
-                 path)
-          ;; Global directory events don't know their originating repo so we rely
+    (let [;; Global directory events don't know their originating repo so we rely
           ;; on the client to correctly identify it
-          repo (if global-dir (state/get-current-repo) (config/get-local-repo dir))
+          repo (cond
+                 global-dir (state/get-current-repo)
+                 ;; FIXME(andelf): hack for demo graph, demo graph does not bind to local directory
+                 (string/starts-with? dir "memory://") "local"
+                 :else (config/get-local-repo dir))
+          repo-dir (config/get-local-dir repo)
           {:keys [mtime]} stat
-          db-content (or (db/get-file repo path) "")]
+          db-content (db/get-file repo path)
+          exists-in-db? (not (nil? db-content))
+          db-content (or db-content "")]
+
       (when (or content (contains? #{"unlink" "unlinkDir" "addDir"} type))
         (cond
           (and (= "unlinkDir" type) dir)
@@ -77,12 +80,9 @@
             (handle-add-and-change! repo path content db-content mtime backup?))
 
           (and (= "change" type)
-               (not (db/file-exists? repo path)))
-          (js/console.error "Can't get file in the db: " path)
-
-          (and (= "change" type)
+               (= dir repo-dir)
                (not= (string/trim content) (string/trim db-content))
-               (not (gp-config/local-asset? (string/replace-first path dir ""))))
+               (not (gp-config/local-asset? path)))
           (when-not (and
                      (string/includes? path (str "/" (config/get-journals-directory) "/"))
                      (or
@@ -93,13 +93,24 @@
             (handle-add-and-change! repo path content db-content mtime (not global-dir))) ;; no backup for global dir
 
           (and (= "unlink" type)
-               (db/file-exists? repo path))
+               exists-in-db?)
           (p/let [dir-exists? (fs/file-exists? dir "")]
             (when dir-exists?
               (when-let [page-name (db/get-file-page path)]
                 (println "Delete page: " page-name ", file path: " path ".")
                 (page-handler/delete! page-name #() :delete-file? false))))
 
+          ;; global config handling
+          (and (= "change" type)
+               (= dir (global-config-handler/global-config-dir)))
+          (when (= path "config.edn")
+            (file-handler/alter-global-file
+             (global-config-handler/global-config-path) content {:from-disk? true}))
+
+          (and (= "change" type)
+               (not exists-in-db?))
+          (js/console.error "Can't get file in the db: " path)
+
           (and (contains? #{"add" "change" "unlink"} type)
                (string/ends-with? path "logseq/custom.css"))
           (do
@@ -119,30 +130,46 @@
 (defn load-graph-files!
   [graph]
   (when graph
-    (let [dir (config/get-repo-dir graph)
+    (let [repo-dir (config/get-repo-dir graph)
           db-files (->> (db/get-files graph)
-                        (map first)
-                        (filter #(string/starts-with? % (config/get-repo-dir graph))))]
-      (p/let [files (fs/readdir dir :path-only? true)
-              files (remove #(fs-util/ignored-path? dir %) files)]
-        (let [deleted-files (set/difference (set db-files) (set files))]
-          (when (seq deleted-files)
-            (let [delete-tx-data (->> (db/delete-files deleted-files)
-                                      (concat (db/delete-blocks graph deleted-files nil))
-                                      (remove nil?))]
-              (db/transact! graph delete-tx-data {:delete-files? true})))
-          (doseq [file files]
-            (when-let [_ext (util/get-file-ext file)]
-              (->
-               (p/let [content (fs/read-file dir file)
-                       stat (fs/stat dir file)
-                       type (if (db/file-exists? graph file)
-                              "change"
-                              "add")]
-                 (handle-changed! type
-                                  {:dir dir
-                                   :path file
-                                   :content content
-                                   :stat stat}))
-               (p/catch (fn [error]
-                          (js/console.dir error)))))))))))
+                        (map first))]
+      ;; read all files in the repo dir, notify if readdir error
+      (p/let [[files deleted-files]
+              (-> (fs/readdir repo-dir :path-only? true)
+                  (p/chain (fn [files]
+                             (->> files
+                                  (map #(path/relative-path repo-dir %))
+                                  (remove #(fs-util/ignored-path? repo-dir %))))
+                           (fn [files]
+                             (let [deleted-files (set/difference (set db-files) (set files))]
+                               [files deleted-files])))
+                  (p/catch (fn [error]
+                             (when-not (config/demo-graph? graph)
+                               (js/console.error "reading" graph)
+                               (state/pub-event! [:notification/show
+                                                  {:content (str "The graph " graph " can not be read:" error)
+                                                   :status :error
+                                                   :clear? false}]))
+                             [nil nil])))]
+        (prn ::init-watcher repo-dir {:deleted (count deleted-files)
+                                      :total (count files)})
+        (when (seq deleted-files)
+          (let [delete-tx-data (->> (db/delete-files deleted-files)
+                                    (concat (db/delete-blocks graph deleted-files nil))
+                                    (remove nil?))]
+            (db/transact! graph delete-tx-data {:delete-files? true})))
+        (doseq [file-rpath files]
+          (when-let [_ext (util/get-file-ext file-rpath)]
+            (->
+             (p/let [content (fs/read-file repo-dir file-rpath)
+                     stat (fs/stat repo-dir file-rpath)
+                     type (if (db/file-exists? graph file-rpath)
+                            "change"
+                            "add")]
+               (handle-changed! type
+                                {:dir repo-dir
+                                 :path file-rpath
+                                 :content content
+                                 :stat stat}))
+             (p/catch (fn [error]
+                        (js/console.dir error))))))))))

+ 28 - 26
src/main/frontend/handler.cljs

@@ -21,14 +21,14 @@
             [frontend.handler.command-palette :as command-palette]
             [frontend.handler.events :as events]
             [frontend.handler.file :as file-handler]
+            [frontend.handler.global-config :as global-config-handler]
             [frontend.handler.notification :as notification]
             [frontend.handler.page :as page-handler]
+            [frontend.handler.plugin-config :as plugin-config-handler]
             [frontend.handler.repo :as repo-handler]
+            [frontend.handler.repo-config :as repo-config-handler]
             [frontend.handler.ui :as ui-handler]
             [frontend.handler.user :as user-handler]
-            [frontend.handler.repo-config :as repo-config-handler]
-            [frontend.handler.global-config :as global-config-handler]
-            [frontend.handler.plugin-config :as plugin-config-handler]
             [frontend.idb :as idb]
             [frontend.mobile.util :as mobile-util]
             [frontend.modules.instrumentation.core :as instrument]
@@ -88,7 +88,8 @@
             (p/do! (repo-config-handler/start {:repo repo})
                    (when (config/global-config-enabled?)
                      (global-config-handler/start {:repo repo}))
-                   (when (config/plugin-config-enabled?) (plugin-config-handler/start)))
+                   (when (config/plugin-config-enabled?)
+                     (plugin-config-handler/start)))
             (p/finally
               (fn []
                 ;; install after config is restored
@@ -214,28 +215,29 @@
 
   (events/run!)
 
-  (-> (p/let [repos (get-repos)
-              _ (state/set-repos! repos)
-              _ (restore-and-setup! repos)]
-        (when (mobile-util/native-platform?)
-          (p/do!
-           (mobile-util/hide-splash)
-           (state/restore-mobile-theme!))))
-      (p/catch (fn [e]
-                 (js/console.error "Error while restoring repos: " e)))
-      (p/finally (fn []
-                   (state/set-db-restoring! false))))
-
-  (db/run-batch-txs!)
-  (file/<ratelimit-file-writes!)
-  (util/<app-wake-up-from-sleep-loop (atom false))
-
-  (when config/dev?
-    (enable-datalog-console))
-  (when (util/electron?)
-    (el/listen!))
-  (persist-var/load-vars)
-  (js/setTimeout instrument! (* 60 1000)))
+  (p/do!
+   (-> (p/let [repos (get-repos)
+               _ (state/set-repos! repos)
+               _ (restore-and-setup! repos)]
+         (when (mobile-util/native-platform?)
+           (p/do!
+            (mobile-util/hide-splash)
+            (state/restore-mobile-theme!))))
+       (p/catch (fn [e]
+                  (js/console.error "Error while restoring repos: " e)))
+       (p/finally (fn []
+                    (state/set-db-restoring! false))))
+
+   (db/run-batch-txs!)
+   (file/<ratelimit-file-writes!)
+   (util/<app-wake-up-from-sleep-loop (atom false))
+
+   (when config/dev?
+     (enable-datalog-console))
+   (when (util/electron?)
+     (el/listen!))
+   (persist-var/load-vars)
+   (js/setTimeout instrument! (* 60 1000))))
 
 (defn stop! []
   (prn "stop!"))

+ 4 - 3
src/main/frontend/handler/assets.cljs

@@ -5,7 +5,8 @@
             [frontend.config :as config]
             [frontend.mobile.util :as mobile-util]
             [logseq.graph-parser.config :as gp-config]
-            [clojure.string :as string]))
+            [clojure.string :as string]
+            [logseq.common.path :as path]))
 
 (defn alias-enabled?
   []
@@ -89,7 +90,7 @@
       protocol-link?
       full-path
 
-      (util/absolute-path? full-path)
+      (path/absolute? full-path)
       (str "file://" full-path)
 
       :else
@@ -112,4 +113,4 @@
  (normalize-asset-resource-url "https://x.com/a.pdf")
  (normalize-asset-resource-url "./a/b.pdf")
  (normalize-asset-resource-url "assets/a/b.pdf")
- (normalize-asset-resource-url "@图书/a/b.pdf"))
+ (normalize-asset-resource-url "@图书/a/b.pdf"))

+ 26 - 12
src/main/frontend/handler/code.cljs

@@ -1,12 +1,14 @@
 (ns frontend.handler.code
   "Codemirror editor related."
-  (:require [frontend.state :as state]
-            [goog.object :as gobj]
+  (:require [clojure.string :as string]
+            [frontend.config :as config]
             [frontend.db :as db]
             [frontend.handler.editor :as editor-handler]
             [frontend.handler.file :as file-handler]
+            [frontend.state :as state]
+            [goog.object :as gobj]
             [logseq.graph-parser.utf8 :as utf8]
-            [clojure.string :as string]))
+            [logseq.common.path :as path]))
 
 (defn save-code-editor!
   []
@@ -20,6 +22,7 @@
             default-value (gobj/get textarea "defaultValue")]
         (when (not= value default-value)
           (cond
+            ;; save block content
             (:block/uuid config)
             (let [block (db/pull [:block/uuid (:block/uuid config)])
                   content (:block/content block)
@@ -34,16 +37,27 @@
               (state/set-edit-content! (state/get-edit-input-id) new-content)
               (editor-handler/save-block-if-changed! block new-content))
 
-            (:file-path config)
+            (not-empty (:file-path config))
             (let [path (:file-path config)
-                  content (or (db/get-file path) "")]
-              (when (and
-                     (not (string/blank? value))
-                     (not= (string/trim value) (string/trim content)))
-                (file-handler/alter-file (state/get-current-repo)
-                                         path
-                                         (str (string/trim value) "\n")
-                                         {:re-render-root? true})))
+                  repo (state/get-current-repo)
+                  repo-dir (config/get-repo-dir repo)
+                  rpath (when (string/starts-with? path repo-dir)
+                          (path/trim-dir-prefix repo-dir path))]
+              (if rpath
+                ;; in-db file
+                (let [db-content (db/get-file rpath)
+                      not-in-db? (nil? db-content)
+                      old-content (or db-content "")
+                      contents-matched? (= (string/trim value) (string/trim old-content))]
+                  (when (or
+                         (and not-in-db? (not-empty value))
+                         (not contents-matched?))
+                    (file-handler/alter-file (state/get-current-repo)
+                                             rpath
+                                             (str (string/trim value) "\n")
+                                             {:re-render-root? true})))
+                ;; global file
+                (file-handler/alter-global-file path (str (string/trim value) "\n") {})))
 
             :else
             nil))))))

+ 4 - 2
src/main/frontend/handler/common.cljs

@@ -11,8 +11,10 @@
             ["ignore" :as Ignore]))
 
 (defn copy-to-clipboard-without-id-property!
-  [format raw-text html]
-  (util/copy-to-clipboard! (property/remove-id-property format raw-text) html))
+  [format raw-text html blocks]
+  (util/copy-to-clipboard! (property/remove-id-property format raw-text)
+                           :html html
+                           :blocks blocks))
 
 (defn config-with-document-mode
   [config]

+ 7 - 32
src/main/frontend/handler/common/file.cljs

@@ -1,15 +1,11 @@
 (ns frontend.handler.common.file
   "Common file related fns for handlers"
-  (:require [frontend.util :as util]
-            [frontend.config :as config]
+  (:require [frontend.config :as config]
             [frontend.state :as state]
             [frontend.db :as db]
-            ["/frontend/utils" :as utils]
-            [frontend.mobile.util :as mobile-util]
             [logseq.graph-parser :as graph-parser]
             [logseq.graph-parser.util :as gp-util]
             [logseq.graph-parser.config :as gp-config]
-            [frontend.fs.capacitor-fs :as capacitor-fs]
             [frontend.fs :as fs]
             [frontend.context.i18n :refer [t]]
             [clojure.string :as string]
@@ -51,40 +47,19 @@
 
 (defn reset-file!
   "Main fn for updating a db with the results of a parsed file"
-  ([repo-url file content]
-   (reset-file! repo-url file content {}))
-  ([repo-url file content {:keys [verbose] :as options}]
-   (let [electron-local-repo? (and (util/electron?)
-                                   (config/local-db? repo-url))
-         repo-dir (config/get-repo-dir repo-url)
-         file (cond
-                (and electron-local-repo?
-                     util/win32?
-                     (utils/win32 file))
-                file
-
-                (and electron-local-repo? (or
-                                           util/win32?
-                                           (not= "/" (first file))))
-                (str repo-dir "/" file)
-
-                (mobile-util/native-platform?)
-                (capacitor-fs/normalize-file-protocol-path repo-dir file)
-
-                :else
-                file)
-         file (gp-util/path-normalize file)
-         new? (nil? (db/entity [:file/path file]))
+  ([repo-url file-path content]
+   (reset-file! repo-url file-path content {}))
+  ([repo-url file-path content {:keys [verbose] :as options}]
+   (let [new? (nil? (db/entity [:file/path file-path]))
          options (merge (dissoc options :verbose)
                         {:new? new?
                          :delete-blocks-fn (partial validate-and-get-blocks-to-delete repo-url)
                          :extract-options (merge
                                            {:user-config (state/get-config)
                                             :date-formatter (state/get-date-formatter)
-                                            :block-pattern (config/get-block-pattern (gp-util/get-format file))
+                                            :block-pattern (config/get-block-pattern (gp-util/get-format file-path))
                                             :supported-formats (gp-config/supported-formats)
-                                            :uri-encoded? (boolean (mobile-util/native-platform?))
                                             :filename-format (state/get-filename-format repo-url)
                                             :extracted-block-ids (:extracted-block-ids options)}
                                            (when (some? verbose) {:verbose verbose}))})]
-     (:tx (graph-parser/parse-file (db/get-db repo-url false) file content options)))))
+     (:tx (graph-parser/parse-file (db/get-db repo-url false) file-path content options)))))

+ 3 - 6
src/main/frontend/handler/config.cljs

@@ -3,7 +3,6 @@
   (:require [frontend.state :as state]
             [frontend.handler.file :as file-handler]
             [frontend.handler.repo-config :as repo-config-handler]
-            [frontend.config :as config]
             [frontend.db :as db]
             [borkdude.rewrite-edn :as rewrite]))
 
@@ -24,11 +23,9 @@
         (file-handler/set-file-content! repo path new-content) nil))))
 
 (defn set-config!
-  ([k v]
-   (set-config! (state/get-current-repo) k v))
-  ([repo k v]
-   (let [path (config/get-repo-config-path repo)]
-     (repo-config-set-key-value path k v))))
+  [k v]
+  (let [path "logseq/config.edn"]
+    (repo-config-set-key-value path k v)))
 
 (defn toggle-ui-show-brackets! []
   (let [show-brackets? (state/show-brackets?)]

Неке датотеке нису приказане због велике количине промена