]> git.ipfire.org Git - thirdparty/vuejs/pinia.git/commitdiff
feat(subscribe): make the watcher 'pre' by default like regular watchers
authorEduardo San Martin Morote <posva13@gmail.com>
Thu, 12 Aug 2021 16:31:33 +0000 (18:31 +0200)
committerEduardo San Martin Morote <posva@users.noreply.github.com>
Fri, 13 Aug 2021 08:14:53 +0000 (10:14 +0200)
`store.$subscribe()` now takes an extra argument like `watch` and
provides a more flexible API. You can now set `deep`, `flush`, and other
`watch` options.

Close #610

BREAKING CHANGE: `$store.subscribe()` now runs a `flush: 'pre'` instead
of a `flush: 'sync'` by default. This is due to the performance
implications of using `deep: true` + `flush: 'sync'`. **Most of the
times, this change should not affect you**. If you were relying on the
`flush` being `sync`, you can still provide it as a second argument
which is now an object instead of a boolean (`detached` is now a
property of that object). Migrating this should be fairly easy as the
boolean version will show a warning in dev mode and TypeScript will show
the function as deprecated.

```diff
-store.$subscribe(callback, true)
+store.$subscribe(callback, { detached: true })

 // to keep the flush: 'sync' behavior
-store.$subscribe(callback)
+store.$subscribe(callback, { flush: 'sync' })
```

__tests__/store.spec.ts
__tests__/subscriptions.spec.ts
src/devtools/plugin.ts
src/store.ts
src/types.ts
yarn.lock

index 07d1e4da60a7fbbb6cb17798c4d03ee58cd34136..7e8d1731074615553cb6539d9e48b6371e8f5571 100644 (file)
@@ -81,9 +81,10 @@ describe('Store', () => {
     const store = useStore()
     store.$state.a = false
     const spy = jest.fn()
-    store.$subscribe(spy)
+    store.$subscribe(spy, { flush: 'sync' })
     expect(spy).not.toHaveBeenCalled()
     store.$reset()
+    expect(spy).toHaveBeenCalledTimes(1)
     store.$state.nested.foo = 'bar'
     expect(spy).toHaveBeenCalledTimes(2)
     expect(store.$state).toEqual({
index 61a91402381ebb3d4ed4c8ff673929b5244a7f27..1352d84f0a3d6622c844189bcb5204c888be7b87 100644 (file)
@@ -20,7 +20,7 @@ describe('Subscriptions', () => {
 
   it('fires callback when patch is applied', () => {
     const spy = jest.fn()
-    store.$subscribe(spy)
+    store.$subscribe(spy, { flush: 'sync' })
     store.$state.name = 'Cleiton'
     expect(spy).toHaveBeenCalledTimes(1)
     expect(spy).toHaveBeenCalledWith(
@@ -35,7 +35,7 @@ describe('Subscriptions', () => {
   it('subscribe to changes done via patch', () => {
     const store = useStore()
     const spy = jest.fn()
-    store.$subscribe(spy)
+    store.$subscribe(spy, { flush: 'sync' })
 
     const patch = { name: 'Cleiton' }
     store.$patch(patch)
@@ -52,7 +52,7 @@ describe('Subscriptions', () => {
 
   it('unsubscribes callback when unsubscribe is called', () => {
     const spy = jest.fn()
-    const unsubscribe = store.$subscribe(spy)
+    const unsubscribe = store.$subscribe(spy, { flush: 'sync' })
     unsubscribe()
     store.$state.name = 'Cleiton'
     expect(spy).not.toHaveBeenCalled()
@@ -61,8 +61,8 @@ describe('Subscriptions', () => {
   it('listeners are not affected when unsubscribe is called multiple times', () => {
     const func1 = jest.fn()
     const func2 = jest.fn()
-    const unsubscribe1 = store.$subscribe(func1)
-    store.$subscribe(func2)
+    const unsubscribe1 = store.$subscribe(func1, { flush: 'sync' })
+    store.$subscribe(func2, { flush: 'sync' })
     unsubscribe1()
     unsubscribe1()
     store.$state.name = 'Cleiton'
@@ -86,8 +86,8 @@ describe('Subscriptions', () => {
       const spy1 = jest.fn()
       const spy2 = jest.fn()
 
-      s1.$subscribe(spy1)
-      s2.$subscribe(spy2)
+      s1.$subscribe(spy1, { flush: 'sync' })
+      s2.$subscribe(spy2, { flush: 'sync' })
 
       expect(spy1).toHaveBeenCalledTimes(0)
       expect(spy2).toHaveBeenCalledTimes(0)
@@ -107,7 +107,7 @@ describe('Subscriptions', () => {
         {
           setup() {
             const s1 = useStore()
-            s1.$subscribe(spy1)
+            s1.$subscribe(spy1, { flush: 'sync' })
           },
           template: `<p/>`,
         },
@@ -117,15 +117,15 @@ describe('Subscriptions', () => {
       const s1 = useStore()
       const s2 = useStore()
 
-      s2.$subscribe(spy2)
+      s2.$subscribe(spy2, { flush: 'sync' })
 
       expect(spy1).toHaveBeenCalledTimes(0)
       expect(spy2).toHaveBeenCalledTimes(0)
 
       s1.name = 'Edu'
 
-      expect(spy2).toHaveBeenCalledTimes(1)
       expect(spy1).toHaveBeenCalledTimes(1)
+      expect(spy2).toHaveBeenCalledTimes(1)
 
       s1.$patch({ name: 'a' })
       expect(spy1).toHaveBeenCalledTimes(2)
index 5592a2da124c741ef720c1734e0b684323ee5d2d..0ca6bf81466d18d1f08d05d4e4d4dfd7659f4442 100644 (file)
@@ -345,50 +345,53 @@ function addStoreToDevtools(app: App, store: StoreGeneric) {
         )
       })
 
-      store.$subscribe(({ events, type }, state) => {
-        api.notifyComponentUpdate()
-        api.sendInspectorState(INSPECTOR_ID)
+      store.$subscribe(
+        ({ events, type }, state) => {
+          api.notifyComponentUpdate()
+          api.sendInspectorState(INSPECTOR_ID)
 
-        if (!isTimelineActive) return
-        // rootStore.state[store.id] = state
+          if (!isTimelineActive) return
+          // rootStore.state[store.id] = state
 
-        const eventData: TimelineEvent = {
-          time: Date.now(),
-          title: formatMutationType(type),
-          data: {
-            store: formatDisplay(store.$id),
-            ...formatEventData(events),
-          },
-          groupId: activeAction,
-        }
+          const eventData: TimelineEvent = {
+            time: Date.now(),
+            title: formatMutationType(type),
+            data: {
+              store: formatDisplay(store.$id),
+              ...formatEventData(events),
+            },
+            groupId: activeAction,
+          }
 
-        // reset for the next mutation
-        activeAction = undefined
+          // reset for the next mutation
+          activeAction = undefined
 
-        if (type === MutationType.patchFunction) {
-          eventData.subtitle = '⤵️'
-        } else if (type === MutationType.patchObject) {
-          eventData.subtitle = '🧩'
-        } else if (events && !Array.isArray(events)) {
-          eventData.subtitle = events.type
-        }
+          if (type === MutationType.patchFunction) {
+            eventData.subtitle = '⤵️'
+          } else if (type === MutationType.patchObject) {
+            eventData.subtitle = '🧩'
+          } else if (events && !Array.isArray(events)) {
+            eventData.subtitle = events.type
+          }
 
-        if (events) {
-          eventData.data['rawEvent(s)'] = {
-            _custom: {
-              display: 'DebuggerEvent',
-              type: 'object',
-              tooltip: 'raw DebuggerEvent[]',
-              value: events,
-            },
+          if (events) {
+            eventData.data['rawEvent(s)'] = {
+              _custom: {
+                display: 'DebuggerEvent',
+                type: 'object',
+                tooltip: 'raw DebuggerEvent[]',
+                value: events,
+              },
+            }
           }
-        }
 
-        api.addTimelineEvent({
-          layerId: MUTATIONS_LAYER_ID,
-          event: eventData,
-        })
-      }, true)
+          api.addTimelineEvent({
+            layerId: MUTATIONS_LAYER_ID,
+            event: eventData,
+          })
+        },
+        { detached: true, flush: 'sync' }
+      )
 
       const hotUpdate = store._hotUpdate
       store._hotUpdate = markRaw((newStore) => {
index 2f0b6391061238aa42aae794f0f90fced8daddcf..691ca1e813ed13626f90aa9786343b5d3ead14c0 100644 (file)
@@ -43,6 +43,7 @@ import {
   _ExtractActionsFromSetupStore,
   _ExtractGettersFromSetupStore,
   _ExtractStateFromSetupStore,
+  StoreWithState,
 } from './types'
 import {
   getActivePinia,
@@ -176,7 +177,10 @@ function createSetupStore<
   }
 
   // watcher options for $subscribe
-  const $subscribeOptions: WatchOptions = { deep: true, flush: 'sync' }
+  const $subscribeOptions: WatchOptions = {
+    deep: true,
+    // flush: 'post',
+  }
   /* istanbul ignore else */
   if (__DEV__ && !isVue2) {
     $subscribeOptions.onTrigger = (event) => {
@@ -221,30 +225,7 @@ function createSetupStore<
   // TODO: idea create skipSerialize that marks properties as non serializable and they are skipped
   const setupStore = pinia._e.run(() => {
     scope = effectScope()
-    return scope.run(() => {
-      // skip setting up the watcher on HMR
-      if (!__DEV__ || !hot) {
-        watch(
-          () => pinia.state.value[$id] as UnwrapRef<S>,
-          (state, oldState) => {
-            if (isListening) {
-              triggerSubscriptions(
-                subscriptions,
-                {
-                  storeId: $id,
-                  type: MutationType.direct,
-                  events: debuggerEvents as DebuggerEvent,
-                },
-                state
-              )
-            }
-          },
-          $subscribeOptions
-        )!
-      }
-
-      return setup()
-    })
+    return scope.run(() => setup())
   })!
 
   function $patch(stateMutation: (state: UnwrapRef<S>) => void): void
@@ -427,8 +408,51 @@ function createSetupStore<
     $onAction: addSubscription.bind(null, actionSubscriptions),
     $patch,
     $reset,
-    $subscribe: addSubscription.bind(null, subscriptions),
-  }
+    $subscribe(callback, options = {}) {
+      if (__DEV__ && typeof options === 'boolean') {
+        console.warn(
+          `[🍍]: store.$subscribe() no longer accepts a boolean as the 2nd parameter:\n` +
+            `Replace "store.$subscribe(fn, ${String(
+              options
+            )})" with "$store.$subscribe(fn, { detached: ${String(
+              options
+            )} })".`
+        )
+      }
+
+      const _removeSubscription = addSubscription(
+        subscriptions,
+        callback,
+        // @ts-expect-error: until the deprecation is removed
+        options.detached
+      )
+      const stopWatcher = scope.run(() =>
+        watch(
+          () => pinia.state.value[$id] as UnwrapRef<S>,
+          (state, oldState) => {
+            if (isListening) {
+              callback(
+                {
+                  storeId: $id,
+                  type: MutationType.direct,
+                  events: debuggerEvents as DebuggerEvent,
+                },
+                state
+              )
+            }
+          },
+          assign({}, $subscribeOptions, options)
+        )
+      )!
+
+      const removeSubscription = () => {
+        stopWatcher()
+        _removeSubscription()
+      }
+
+      return removeSubscription
+    },
+  } as StoreWithState<Id, S, G, A>
 
   const store: Store<Id, S, G, A> = reactive(
     assign(
index 25d0400627d471f022258d7e4e5532ce65bcd9fa..388ae93830be67f03bcdf8cf6475983ccd63eb4d 100644 (file)
@@ -1,4 +1,10 @@
-import { ComputedRef, DebuggerEvent, Ref, UnwrapRef } from 'vue-demi'
+import {
+  ComputedRef,
+  DebuggerEvent,
+  Ref,
+  UnwrapRef,
+  WatchOptions,
+} from 'vue-demi'
 import { Pinia } from './rootStore'
 
 /**
@@ -342,7 +348,27 @@ export interface StoreWithState<
    * true.
    *
    * @param callback - callback passed to the watcher
-   * @param detached - detach the subscription from the context this is called from
+   * @param options - `watch` options + `detached` to detach the subscription
+   * from the context (usually a component) this is called from
+   * @returns function that removes the watcher
+   */
+  $subscribe(
+    callback: SubscriptionCallback<S>,
+    options?: { detached?: boolean } & WatchOptions
+  ): () => void
+
+  /**
+   * Setups a callback to be called whenever the state changes. It also returns
+   * a function to remove the callback. Note than when calling
+   * `store.$subscribe()` inside of a component, it will be automatically
+   * cleanup up when the component gets unmounted unless `detached` is set to
+   * true.
+   *
+   * @deprecated use `store.$subscribe(fn, { detached: true })` instead.
+   *
+   * @param callback - callback passed to the watcher
+   * @param detached - detach the subscription from the context this is called
+   * from
    * @returns function that removes the watcher
    */
   $subscribe(callback: SubscriptionCallback<S>, detached?: boolean): () => void
index ee9ad4cf65cced7d09650948565c2eb85ae7842e..cd14ba94c9f14d2fe3a0cc3ab138b294a7808beb 100644 (file)
--- a/yarn.lock
+++ b/yarn.lock
   integrity sha512-X67Z5y+VBJuHB/RjwECp8kSl5uYi0BvRbNeWqkaJCVh+LiTPl19WBUfG627psSgp9rSf6ojuXghQM3ha6qHHdA==
 
 "@babel/parser@^7.12.0", "@babel/parser@^7.13.9":
-  version "7.15.2"
-  resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.15.2.tgz#08d4ffcf90d211bf77e7cc7154c6f02d468d2b1d"
-  integrity sha512-bMJXql1Ss8lFnvr11TZDH4ArtwlAS5NG9qBmdiFW2UHHm6MVoR+GDc5XE2b9K938cyjc9O6/+vjjcffLDtfuDg==
+  version "7.15.3"
+  resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.15.3.tgz#3416d9bea748052cfcb63dbcc27368105b1ed862"
+  integrity sha512-O0L6v/HvqbdJawj0iBEfVQMc3/6WP+AeOsovsIgBFyJaG+W2w7eqvZB7puddATmWuARlm1SX7DwxJ/JJUnDpEA==
 
 "@babel/plugin-syntax-async-generators@^7.8.4":
   version "7.8.4"
   integrity sha512-pMCcqU2zT4TjqYFrWtYHKal7Sl30Ims6ulZ4UFXxI4xbtQqK/qqKwkDoBFCfooRqqmRu9vY3xaJRwxSh673aYg==
 
 "@types/node@^16.4.3":
-  version "16.4.13"
-  resolved "https://registry.yarnpkg.com/@types/node/-/node-16.4.13.tgz#7dfd9c14661edc65cccd43a29eb454174642370d"
-  integrity sha512-bLL69sKtd25w7p1nvg9pigE4gtKVpGTPojBFLMkGHXuUgap2sLqQt2qUnqmVCDfzGUL0DRNZP+1prIZJbMeAXg==
+  version "16.6.0"
+  resolved "https://registry.yarnpkg.com/@types/node/-/node-16.6.0.tgz#0d5685f85066f94e97f19e8a67fe003c5fadacc4"
+  integrity sha512-OyiZPohMMjZEYqcVo/UJ04GyAxXOJEZO/FpzyXxcH4r/ArrVoXHf4MbUrkLp0Tz7/p1mMKpo5zJ6ZHl8XBNthQ==
 
 "@types/normalize-package-data@^2.4.0":
   version "2.4.1"
     estree-walker "^2.0.1"
     source-map "^0.6.1"
 
-"@vue/compiler-core@3.2.1":
-  version "3.2.1"
-  resolved "https://registry.yarnpkg.com/@vue/compiler-core/-/compiler-core-3.2.1.tgz#8e13232f7aef8e308fb2d4a10571a5640257064b"
-  integrity sha512-UEJf2ZGww5wGVdrWIXIZo04KdJFGPmI2bHRUsBZ3AdyCAqJ5ykRXKOBn1OR1hvA2YzimudOEyHM+DpbBv91Kww==
+"@vue/compiler-core@3.2.2":
+  version "3.2.2"
+  resolved "https://registry.yarnpkg.com/@vue/compiler-core/-/compiler-core-3.2.2.tgz#8d3e29f129579ed9b14f48af735fd8d95f248504"
+  integrity sha512-QhCI0ZU5nAR0LMcLgzW3v75374tIrHGp8XG5CzJS7Nsy+iuignbE4MZ2XJfh5TGIrtpuzfWA4eTIfukZf/cRdg==
   dependencies:
     "@babel/parser" "^7.12.0"
     "@babel/types" "^7.12.0"
-    "@vue/shared" "3.2.1"
+    "@vue/shared" "3.2.2"
     estree-walker "^2.0.1"
     source-map "^0.6.1"
 
     "@vue/compiler-core" "3.1.5"
     "@vue/shared" "3.1.5"
 
-"@vue/compiler-dom@3.2.1":
-  version "3.2.1"
-  resolved "https://registry.yarnpkg.com/@vue/compiler-dom/-/compiler-dom-3.2.1.tgz#5cc68873f1928c7b9aee8c8a2846f7f362cb1ab9"
-  integrity sha512-tXg8tkPb3j54zNfWqoao9T1JI41yWPz8TROzmif/QNNA46eq8/SRuRsBd36i47GWaz7mh+yg3vOJ87/YBjcMyQ==
+"@vue/compiler-dom@3.2.2":
+  version "3.2.2"
+  resolved "https://registry.yarnpkg.com/@vue/compiler-dom/-/compiler-dom-3.2.2.tgz#26e198498746c53047c3744d26fc95e670692ab7"
+  integrity sha512-ggcc+NV/ENIE0Uc3TxVE/sKrhYVpLepMAAmEiQ047332mbKOvUkowz4TTFZ+YkgOIuBOPP0XpCxmCMg7p874mA==
   dependencies:
-    "@vue/compiler-core" "3.2.1"
-    "@vue/shared" "3.2.1"
+    "@vue/compiler-core" "3.2.2"
+    "@vue/shared" "3.2.2"
 
 "@vue/compiler-sfc@^3.1.1":
   version "3.1.5"
     source-map "^0.6.1"
 
 "@vue/compiler-sfc@^3.2.1":
-  version "3.2.1"
-  resolved "https://registry.yarnpkg.com/@vue/compiler-sfc/-/compiler-sfc-3.2.1.tgz#7809b298cf0fbce62a2c628b7dfc1e82dd9a3a9b"
-  integrity sha512-fVLdme5RZVkBt+jxv2LCSRM72o4FX7BR2eu2FpjjEi1kEtUMKBDnjKwGWy7TyhTju0t0CocctyoM+G56vH7NpQ==
+  version "3.2.2"
+  resolved "https://registry.yarnpkg.com/@vue/compiler-sfc/-/compiler-sfc-3.2.2.tgz#5b7b13b07689be8e4880d856f72d1be500785be9"
+  integrity sha512-hrtqpQ5L6IPn5v7yVRo7uvLcQxv0z1+KBjZBWMBOcrXz4t+PKUxU/SWd6Tl9T8FDmYlunzKUh6lcx+2CLo6f5A==
   dependencies:
     "@babel/parser" "^7.13.9"
     "@babel/types" "^7.13.0"
     "@types/estree" "^0.0.48"
-    "@vue/compiler-core" "3.2.1"
-    "@vue/compiler-dom" "3.2.1"
-    "@vue/compiler-ssr" "3.2.1"
-    "@vue/shared" "3.2.1"
+    "@vue/compiler-core" "3.2.2"
+    "@vue/compiler-dom" "3.2.2"
+    "@vue/compiler-ssr" "3.2.2"
+    "@vue/shared" "3.2.2"
     consolidate "^0.16.0"
     estree-walker "^2.0.1"
     hash-sum "^2.0.0"
     "@vue/compiler-dom" "3.1.5"
     "@vue/shared" "3.1.5"
 
-"@vue/compiler-ssr@3.2.1":
-  version "3.2.1"
-  resolved "https://registry.yarnpkg.com/@vue/compiler-ssr/-/compiler-ssr-3.2.1.tgz#f900762f83482e44e9260c2322e3d332c711826c"
-  integrity sha512-6YAOtQunuEyYlVSjK1F7a7BXi7rxVfiTiJ0Ro7eq0q0MNCFV9Z+sN68lfa/E4ABVb0ledEY/Rt8kL23nwCoTCQ==
+"@vue/compiler-ssr@3.2.2":
+  version "3.2.2"
+  resolved "https://registry.yarnpkg.com/@vue/compiler-ssr/-/compiler-ssr-3.2.2.tgz#633bb8e01f00a969c35ca12db32be7fe4c7185a9"
+  integrity sha512-rVl1agMFhdEN3Go0bCriXo+3cysxKIuRP0yh1Wd8ysRrKfAmokyDhUA8PrGSq2Ymj/LdZTh+4OKfj3p2+C+hlA==
   dependencies:
-    "@vue/compiler-dom" "3.2.1"
-    "@vue/shared" "3.2.1"
+    "@vue/compiler-dom" "3.2.2"
+    "@vue/shared" "3.2.2"
 
 "@vue/devtools-api@^6.0.0-beta.14", "@vue/devtools-api@^6.0.0-beta.15":
   version "6.0.0-beta.15"
   dependencies:
     "@vue/shared" "3.1.5"
 
-"@vue/reactivity@3.2.1":
-  version "3.2.1"
-  resolved "https://registry.yarnpkg.com/@vue/reactivity/-/reactivity-3.2.1.tgz#0e71d4ee00b0d0ca6a6141966c30b68b3f685002"
-  integrity sha512-4Lja2KmyiKvuraDed6dXK2A6+r/7x7xGDA7vVR2Aqc8hQVu0+FWeVX+IBfiVOSpbZXFlHLNmCBFkbuWLQSlgxg==
+"@vue/reactivity@3.2.2":
+  version "3.2.2"
+  resolved "https://registry.yarnpkg.com/@vue/reactivity/-/reactivity-3.2.2.tgz#d37011a68395e038a3cf5256af52d48c591b06b6"
+  integrity sha512-IHjhtmrhK6dzacj/EnLQDWOaA3HuzzVk6w84qgV8EpS4uWGIJXiRalMRg6XvGW2ykJvIl3pLsF0aBFlTMRiLOA==
   dependencies:
-    "@vue/shared" "3.2.1"
+    "@vue/shared" "3.2.2"
 
 "@vue/runtime-core@3.1.5":
   version "3.1.5"
     "@vue/reactivity" "3.1.5"
     "@vue/shared" "3.1.5"
 
-"@vue/runtime-core@3.2.1":
-  version "3.2.1"
-  resolved "https://registry.yarnpkg.com/@vue/runtime-core/-/runtime-core-3.2.1.tgz#39641110b2f84fdda3b80b86830827b7b5ef041a"
-  integrity sha512-IsgelRM/5hYeRhz5+ECi66XvYDdjG2t4lARjHvCXw5s9Q4N6uIbjLMwtLzAWRxYf3/y258BrD+ehxAi943ScJg==
+"@vue/runtime-core@3.2.2":
+  version "3.2.2"
+  resolved "https://registry.yarnpkg.com/@vue/runtime-core/-/runtime-core-3.2.2.tgz#b9a7250783de19dd8dd6febf008084b0f9144586"
+  integrity sha512-/aUk1+GO/VPX0oVxhbzSWE1zrf3/wGCsO1ALNisVokYftKqfqLDjbJHE6mrI2hx3MiuwbHrWjJClkGUVTIOPEQ==
   dependencies:
-    "@vue/reactivity" "3.2.1"
-    "@vue/shared" "3.2.1"
+    "@vue/reactivity" "3.2.2"
+    "@vue/shared" "3.2.2"
 
 "@vue/runtime-dom@3.1.5":
   version "3.1.5"
     "@vue/shared" "3.1.5"
     csstype "^2.6.8"
 
-"@vue/runtime-dom@3.2.1":
-  version "3.2.1"
-  resolved "https://registry.yarnpkg.com/@vue/runtime-dom/-/runtime-dom-3.2.1.tgz#087cf36f40ad0869712c4154693c620e478061a8"
-  integrity sha512-bUAHUSe49A5wYdHQ8wsLU1CMPXaG2fRuv2661mx/6Q9+20QxglT3ss8ZeL6AVRu16JNJMcdvTTsNpbnMbVc/lQ==
+"@vue/runtime-dom@3.2.2":
+  version "3.2.2"
+  resolved "https://registry.yarnpkg.com/@vue/runtime-dom/-/runtime-dom-3.2.2.tgz#6d0da23ed1cfc702477f4b8c5dc4f9335c94e119"
+  integrity sha512-1Le/NpCfawCOfePfJezvWUF+oCVLU8N+IHN4oFDOxRe6/PgHNJ+yT+YdxFifBfI+TIAoXI/9PsnqzmJZV+xsmw==
   dependencies:
-    "@vue/runtime-core" "3.2.1"
-    "@vue/shared" "3.2.1"
+    "@vue/runtime-core" "3.2.2"
+    "@vue/shared" "3.2.2"
     csstype "^2.6.8"
 
 "@vue/server-renderer@^3.1.1":
     "@vue/shared" "3.1.5"
 
 "@vue/server-renderer@^3.2.1":
-  version "3.2.1"
-  resolved "https://registry.yarnpkg.com/@vue/server-renderer/-/server-renderer-3.2.1.tgz#249c8b5091ccc4c939ff1a2b5786d1da81c5dfd9"
-  integrity sha512-Zphh7jjysefw4c4mqy2gDlg5W1MYpYuXPlbv2qnjr4IQHjR/FXQfrqo7U858SOCGXL7sXvx025/BstefP4WBTg==
+  version "3.2.2"
+  resolved "https://registry.yarnpkg.com/@vue/server-renderer/-/server-renderer-3.2.2.tgz#686a77891d2d2ced8737d18e0d1564efe94205e5"
+  integrity sha512-o2EcPOeDfXvSK85OhdUWVUYumFW57+MwGFCszOqka2EFpOQVrzvUtYeF6KN2kCuAxexnuVQYtIDQwPZRchXSnQ==
   dependencies:
-    "@vue/compiler-ssr" "3.2.1"
-    "@vue/shared" "3.2.1"
+    "@vue/compiler-ssr" "3.2.2"
+    "@vue/shared" "3.2.2"
 
 "@vue/shared@3.1.5":
   version "3.1.5"
   resolved "https://registry.yarnpkg.com/@vue/shared/-/shared-3.1.5.tgz#74ee3aad995d0a3996a6bb9533d4d280514ede03"
   integrity sha512-oJ4F3TnvpXaQwZJNF3ZK+kLPHKarDmJjJ6jyzVNDKH9md1dptjC7lWR//jrGuLdek/U6iltWxqAnYOu8gCiOvA==
 
-"@vue/shared@3.2.1":
-  version "3.2.1"
-  resolved "https://registry.yarnpkg.com/@vue/shared/-/shared-3.2.1.tgz#1f1fe26fe0334404cce10740b5ffb2654f1281aa"
-  integrity sha512-INN92dVBNgd0TW9BqfQQKx/HWGCHhUUbAV5EZ5FgSCiEdwuZsJbGt1mdnaD9IxGhpiyOjP2ClxGG8SFp7ELcWg==
+"@vue/shared@3.2.2":
+  version "3.2.2"
+  resolved "https://registry.yarnpkg.com/@vue/shared/-/shared-3.2.2.tgz#6104185ebd57af5a14ac51c1f491b2205fc24054"
+  integrity sha512-dvYb318tk9uOzHtSaT3WII/HscQSIRzoCZ5GyxEb3JlkEXASpAUAQwKnvSe2CudnF8XHFRTB7VITWSnWNLZUtA==
 
 "@vue/test-utils@^2.0.0-rc.12":
   version "2.0.0-rc.12"
@@ -1879,9 +1879,9 @@ color-name@~1.1.4:
   integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
 
 colorette@^1.2.2:
-  version "1.2.2"
-  resolved "https://registry.yarnpkg.com/colorette/-/colorette-1.2.2.tgz#cbcc79d5e99caea2dbf10eb3a26fd8b3e6acfa94"
-  integrity sha512-MKGMzyfeuutC/ZJ1cba9NqcNpfeqMUcYmyF1ZFY6/Cn7CNSAKx6a+s48sqLqyAiZuaP2TcqMhoo+dlwFnVxT9w==
+  version "1.3.0"
+  resolved "https://registry.yarnpkg.com/colorette/-/colorette-1.3.0.tgz#ff45d2f0edb244069d3b772adeb04fed38d0a0af"
+  integrity sha512-ecORCqbSFP7Wm8Y6lyqMJjexBQqXSF7SSeaTyGGphogUjBlFP9m9o08wy86HL2uB7fMTxtOUzLMk7ogKcxMg1w==
 
 colors@~1.2.1:
   version "1.2.5"
@@ -4353,9 +4353,9 @@ mz@^2.7.0:
     thenify-all "^1.0.0"
 
 nanoid@^3.1.23:
-  version "3.1.23"
-  resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.1.23.tgz#f744086ce7c2bc47ee0a8472574d5c78e4183a81"
-  integrity sha512-FiB0kzdP0FFVGDKlRLEQ1BgDzU87dy5NnzjeW9YZNt+/c3+q82EQDUwniSAUxp/F0gFNI1ZhKU1FqYsMuqZVnw==
+  version "3.1.24"
+  resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.1.24.tgz#d7ac20215f595c26d314ee5671169a27b609025f"
+  integrity sha512-WNhqqgD4qH7TQdU9ujXfFa/hQI5rOGGnZq+JRmz4JwMZFCgSZVquTq3ORUSv6IC+Y41ACBYV8a8J1kPkqGIiQg==
 
 nanomatch@^1.2.9:
   version "1.2.13"
@@ -5120,9 +5120,9 @@ rollup@^2.38.5:
     fsevents "~2.3.2"
 
 rollup@^2.56.1:
-  version "2.56.1"
-  resolved "https://registry.yarnpkg.com/rollup/-/rollup-2.56.1.tgz#f29dbc04a5d532dfa904f76b62395f359506211e"
-  integrity sha512-KkrsNjeiTfGJMUFBi/PNfj3fnt70akqdoNXOjlzwo98uA1qrlkmgt6SGaK5OwhyDYCVnJb6jb2Xa2wbI47P4Nw==
+  version "2.56.2"
+  resolved "https://registry.yarnpkg.com/rollup/-/rollup-2.56.2.tgz#a045ff3f6af53ee009b5f5016ca3da0329e5470f"
+  integrity sha512-s8H00ZsRi29M2/lGdm1u8DJpJ9ML8SUOpVVBd33XNeEeL3NVaTiUcSBHzBdF3eAyR0l7VSpsuoVUGrRHq7aPwQ==
   optionalDependencies:
     fsevents "~2.3.2"
 
@@ -6100,13 +6100,13 @@ vue@^3.1.1:
     "@vue/shared" "3.1.5"
 
 vue@^3.2.1:
-  version "3.2.1"
-  resolved "https://registry.yarnpkg.com/vue/-/vue-3.2.1.tgz#30dde152f2fdad0669ea9854d5a90a00ef96974b"
-  integrity sha512-0jhXluF5mzTAK5bXw/8yq4McvsI8HwEWI4cnQwJeN8NYGRbwh9wwuE4FNv1Kej9pxBB5ajTNsWr0M6DPs5EJZg==
+  version "3.2.2"
+  resolved "https://registry.yarnpkg.com/vue/-/vue-3.2.2.tgz#11715cb71a02baefd0f6e6552dc623680eb1bf32"
+  integrity sha512-D/LuzAV30CgNJYGyNheE/VUs5N4toL2IgmS6c9qeOxvyh0xyn4exyRqizpXIrsvfx34zG9x5gCI2tdRHCGvF9w==
   dependencies:
-    "@vue/compiler-dom" "3.2.1"
-    "@vue/runtime-dom" "3.2.1"
-    "@vue/shared" "3.2.1"
+    "@vue/compiler-dom" "3.2.2"
+    "@vue/runtime-dom" "3.2.2"
+    "@vue/shared" "3.2.2"
 
 vuex5@^0.5.0-testing.3:
   version "0.5.0-testing.3"