diff --git a/examples/optimistic-ui/libs/fetch.js b/examples/optimistic-ui/libs/fetch.js
index 7675f2c2f..073253a9b 100644
--- a/examples/optimistic-ui/libs/fetch.js
+++ b/examples/optimistic-ui/libs/fetch.js
@@ -1,4 +1,5 @@
export default async function fetcher(...args) {
const res = await fetch(...args)
+ if (!res.ok) throw new Error('Failed to fetch')
return res.json()
}
diff --git a/examples/optimistic-ui/pages/_app.js b/examples/optimistic-ui/pages/_app.js
new file mode 100644
index 000000000..2f8cc070e
--- /dev/null
+++ b/examples/optimistic-ui/pages/_app.js
@@ -0,0 +1,5 @@
+import '../styles.css'
+
+export default function App({ Component, pageProps }) {
+ return
+}
diff --git a/examples/optimistic-ui/pages/api/data.js b/examples/optimistic-ui/pages/api/data.js
deleted file mode 100644
index cfb4ef9c6..000000000
--- a/examples/optimistic-ui/pages/api/data.js
+++ /dev/null
@@ -1,22 +0,0 @@
-const data = []
-
-function shouldFail() {
- return Math.random() > 0.8
-}
-
-export default function api(req, res) {
- if (req.method === 'POST') {
- const body = JSON.parse(req.body)
- // sometimes it will fail, this will cause a regression on the UI
- if (!shouldFail()) {
- data.push(body.text);
- }
- res.json(data)
- return
- }
-
- setTimeout(() => {
- res.json(data)
- }, 2000)
-}
-
diff --git a/examples/optimistic-ui/pages/api/todos.js b/examples/optimistic-ui/pages/api/todos.js
new file mode 100644
index 000000000..ccca949b9
--- /dev/null
+++ b/examples/optimistic-ui/pages/api/todos.js
@@ -0,0 +1,30 @@
+let todos = []
+const delay = () => new Promise(res => setTimeout(() => res(), 1000))
+
+async function getTodos() {
+ await delay()
+ return todos.sort((a, b) => (a.text < b.text ? -1 : 1))
+}
+
+async function addTodo(todo) {
+ await delay()
+ // Sometimes it will fail, this will cause a regression on the UI
+ if (Math.random() < 0.2 || !todo.text)
+ throw new Error('Failed to add new item!')
+ todo.text = todo.text.charAt(0).toUpperCase() + todo.text.slice(1)
+ todos = [...todos, todo]
+ return todo
+}
+
+export default async function api(req, res) {
+ try {
+ if (req.method === 'POST') {
+ const body = JSON.parse(req.body)
+ return res.json(await addTodo(body))
+ }
+
+ return res.json(await getTodos())
+ } catch (err) {
+ return res.status(500).json({ error: err.message })
+ }
+}
diff --git a/examples/optimistic-ui/pages/index.js b/examples/optimistic-ui/pages/index.js
index 89b00c5b8..d45d27ab5 100644
--- a/examples/optimistic-ui/pages/index.js
+++ b/examples/optimistic-ui/pages/index.js
@@ -1,41 +1,110 @@
-import React from 'react'
+import useSWR from 'swr'
+import React, { useState } from 'react'
+
import fetch from '../libs/fetch'
-import useSWR, { mutate } from 'swr'
-
-export default function Index() {
- const [text, setText] = React.useState('');
- const { data } = useSWR('/api/data', fetch)
-
- async function handleSubmit(event) {
- event.preventDefault()
- // Call mutate to optimistically update the UI.
- mutate('/api/data', [...data, text], false)
- // Then we send the request to the API and let mutate
- // update the data with the API response.
- // Our action may fail in the API function, and the response differ
- // from what was optimistically updated, in that case the UI will be
- // changed to match the API response.
- // The fetch could also fail, in that case the UI will
- // be in an incorrect state until the next successful fetch.
- mutate('/api/data', await fetch('/api/data', {
- method: 'POST',
- body: JSON.stringify({ text })
- }))
- setText('')
- }
-
- return
-
-
- {data ? data.map(datum => {datum} ) : 'loading...'}
-
-
+export default function App() {
+ const [text, setText] = useState('')
+ const { data, mutate } = useSWR('/api/todos', fetch)
+
+ const [state, setState] = useState( )
+
+ return (
+
+ {/*
*/}
+
Optimistic UI with SWR
+
+
+
+
+
+ This application optimistically updates the data, while revalidating in
+ the background. The POST
API auto capitializes the data,
+ and only returns the new added one instead of the full list. And the{' '}
+ GET
API returns the full list in order.
+
+
+
+
+ {state}
+
+
+ {data ? (
+ data.length ? (
+ data.map(todo => {
+ return {todo.text}
+ })
+ ) : (
+
+ No todos yet. Try adding lowercased "banana" and "apple" to the
+ list.
+
+ )
+ ) : (
+ Loading...
+ )}
+
+
+ )
}
diff --git a/examples/optimistic-ui/styles.css b/examples/optimistic-ui/styles.css
new file mode 100644
index 000000000..7883519cc
--- /dev/null
+++ b/examples/optimistic-ui/styles.css
@@ -0,0 +1,91 @@
+html {
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen,
+ Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
+ text-align: center;
+}
+
+body {
+ max-width: 600px;
+ margin: auto;
+}
+
+h1 {
+ margin-top: 1em;
+}
+
+.note {
+ text-align: left;
+ font-size: 0.9em;
+ line-height: 1.5;
+ color: #666;
+}
+
+.note svg {
+ margin-right: 0.5em;
+ vertical-align: -2px;
+ width: 14px;
+ height: 14px;
+ margin-right: 5px;
+}
+
+form {
+ display: flex;
+ margin: 8px 0;
+ gap: 8px;
+}
+
+input {
+ flex: 1;
+}
+
+input,
+button {
+ font-size: 16px;
+ padding: 6px 5px;
+}
+
+code {
+ font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas,
+ Liberation Mono, Courier New, monospace;
+ font-feature-settings: 'rlig' 1, 'calt' 1, 'ss01' 1;
+ background-color: #eee;
+ padding: 1px 3px;
+ border-radius: 2px;
+}
+
+ul {
+ text-align: left;
+ list-style: none;
+ padding: 0;
+}
+
+li {
+ margin: 8px 0;
+ padding: 10px;
+ border-radius: 4px;
+ box-shadow: 0 2px 6px rgba(0, 0, 0, 0.12), 0 0 0 1px #ededed;
+}
+
+i {
+ color: #999;
+}
+
+.info,
+.success,
+.error {
+ display: block;
+ text-align: left;
+ padding: 6px 0;
+ font-size: 0.9em;
+ opacity: 0.9;
+}
+
+.info {
+ color: #666;
+}
+.success {
+ color: #4caf50;
+}
+.error {
+ color: #f44336;
+}
diff --git a/package.json b/package.json
index 05e382250..26e79ba01 100644
--- a/package.json
+++ b/package.json
@@ -97,7 +97,7 @@
"husky": "2.4.1",
"jest": "27.0.6",
"lint-staged": "8.2.1",
- "next": "12.0.9",
+ "next": "^12.1.0",
"npm-run-all": "4.1.5",
"prettier": "2.5.0",
"react": "17.0.1",
@@ -112,11 +112,11 @@
"react": "^16.11.0 || ^17.0.0 || ^18.0.0"
},
"prettier": {
+ "tabWidth": 2,
"semi": false,
- "singleQuote": true,
"useTabs": false,
- "trailingComma": "none",
- "tabWidth": 2,
- "arrowParens": "avoid"
+ "singleQuote": true,
+ "arrowParens": "avoid",
+ "trailingComma": "none"
}
}
diff --git a/src/types.ts b/src/types.ts
index 058fdf35d..7029e622c 100644
--- a/src/types.ts
+++ b/src/types.ts
@@ -139,12 +139,12 @@ export type Arguments =
export type Key = Arguments | (() => Arguments)
export type MutatorCallback = (
- currentValue?: Data
+ currentData?: Data
) => Promise | undefined | Data
export type MutatorOptions = {
revalidate?: boolean
- populateCache?: boolean
+ populateCache?: boolean | ((result: any, currentData: Data) => Data)
optimisticData?: Data
rollbackOnError?: boolean
}
diff --git a/src/use-swr.ts b/src/use-swr.ts
index e8aa6f08e..113e52f5c 100644
--- a/src/use-swr.ts
+++ b/src/use-swr.ts
@@ -360,7 +360,9 @@ export const useSWRHandler = (
// eslint-disable-next-line react-hooks/exhaustive-deps
const boundMutate: SWRResponse['mutate'] = useCallback(
// By using `bind` we don't need to modify the size of the rest arguments.
- internalMutate.bind(UNDEFINED, cache, () => keyRef.current),
+ // Due to https://github.com/microsoft/TypeScript/issues/37181, we have to
+ // cast it to any for now.
+ internalMutate.bind(UNDEFINED, cache, () => keyRef.current) as any,
// eslint-disable-next-line react-hooks/exhaustive-deps
[]
)
diff --git a/src/utils/helper.ts b/src/utils/helper.ts
index fad835625..68eb108f1 100644
--- a/src/utils/helper.ts
+++ b/src/utils/helper.ts
@@ -4,7 +4,7 @@ export const noop = () => {}
// by something else. Prettier ignore and extra parentheses are necessary here
// to ensure that tsc doesn't remove the __NOINLINE__ comment.
// prettier-ignore
-export const UNDEFINED: undefined = (/*#__NOINLINE__*/ noop()) as undefined
+export const UNDEFINED = (/*#__NOINLINE__*/ noop()) as undefined
export const OBJECT = Object
diff --git a/src/utils/mutate.ts b/src/utils/mutate.ts
index e6e8a4cdb..630f8e853 100644
--- a/src/utils/mutate.ts
+++ b/src/utils/mutate.ts
@@ -22,7 +22,9 @@ export const internalMutate = async (
typeof _opts === 'boolean' ? { revalidate: _opts } : _opts || {}
// Fallback to `true` if it's not explicitly set to `false`
- let populateCache = options.populateCache !== false
+ let populateCache = isUndefined(options.populateCache)
+ ? true
+ : options.populateCache
const revalidate = options.revalidate !== false
const rollbackOnError = options.rollbackOnError !== false
const optimisticData = options.optimisticData
@@ -43,7 +45,7 @@ export const internalMutate = async (
UNDEFINED,
UNDEFINED,
revalidate,
- populateCache
+ true
)
}
@@ -87,18 +89,26 @@ export const internalMutate = async (
if (error) throw error
return data
} else if (error && hasOptimisticData && rollbackOnError) {
- // Rollback. Always populate the cache in this case.
+ // Rollback. Always populate the cache in this case but without
+ // transforming the data.
populateCache = true
data = rollbackData
cache.set(key, rollbackData)
}
}
+ // If we should write back the cache after request.
if (populateCache) {
if (!error) {
+ // Transform the result into data.
+ if (isFunction(populateCache)) {
+ data = populateCache(data, rollbackData)
+ }
+
// Only update cached data if there's no error. Data can be `undefined` here.
cache.set(key, data)
}
+
// Always update or reset the error.
cache.set(keyInfo, mergeObjects(cache.get(keyInfo), { error }))
}
@@ -114,7 +124,7 @@ export const internalMutate = async (
error,
UNDEFINED,
revalidate,
- populateCache
+ !!populateCache
)
// Throw error or return data
diff --git a/test/use-swr-local-mutation.test.tsx b/test/use-swr-local-mutation.test.tsx
index f00c49a10..3efbdab3c 100644
--- a/test/use-swr-local-mutation.test.tsx
+++ b/test/use-swr-local-mutation.test.tsx
@@ -1112,4 +1112,112 @@ describe('useSWR - local mutation', () => {
await sleep(30)
expect(renderedData).toEqual([undefined, 0, 'bar', 1])
})
+
+ it('should support transforming the result with `populateCache` before writing back', async () => {
+ const key = createKey()
+ function Page() {
+ const { data, mutate } = useSWR(key, () => 'foo')
+ return (
+ <>
+ data: {String(data)}
+
+ mutate('bar', {
+ revalidate: false,
+ populateCache: v => '!' + v
+ })
+ }
+ >
+ mutate
+
+ >
+ )
+ }
+
+ renderWithConfig( )
+ await screen.findByText('data: foo')
+
+ fireEvent.click(screen.getByText('mutate'))
+ await sleep(30)
+ await screen.findByText('data: !bar')
+ })
+
+ it('should support transforming the result with `populateCache` for async data with optimistic data', async () => {
+ const key = createKey()
+ const renderedData = []
+
+ let mutatePage
+
+ function Page() {
+ const { data, mutate } = useSWR(key, () => 'foo')
+ mutatePage = () =>
+ mutate(new Promise(res => setTimeout(() => res('baz'), 20)), {
+ optimisticData: 'bar',
+ revalidate: false,
+ populateCache: v => '!' + v
+ })
+
+ renderedData.push(data)
+ return null
+ }
+
+ renderWithConfig( )
+ await act(() => sleep(10))
+ await act(() => mutatePage())
+ await sleep(30)
+ expect(renderedData).toEqual([undefined, 'foo', 'bar', '!baz'])
+ })
+
+ it('should pass the original data snapshot to `populateCache` as the second parameter', async () => {
+ const key = createKey()
+ const renderedData = []
+
+ let serverData = ['Apple', 'Banana']
+
+ let appendData
+
+ const sendRequest = newItem => {
+ // @TODO: We use `any` here due to limitation of type inference.
+ return new Promise(res =>
+ setTimeout(() => {
+ // Server capitializes the new item.
+ const modifiedData =
+ newItem.charAt(0).toUpperCase() + newItem.slice(1)
+ serverData = [...serverData, modifiedData]
+ res(modifiedData)
+ }, 20)
+ )
+ }
+
+ function Page() {
+ const { data, mutate } = useSWR(key, () => serverData)
+
+ appendData = () => {
+ return mutate(sendRequest('cherry'), {
+ optimisticData: [...data, 'cherry (optimistic)'],
+ populateCache: (result, currentData) => [
+ ...currentData,
+ result + ' (res)'
+ ],
+ revalidate: true
+ })
+ }
+
+ renderedData.push(data)
+ return null
+ }
+
+ renderWithConfig( )
+ await act(() => sleep(10))
+ await act(() => appendData())
+ await sleep(30)
+
+ expect(renderedData).toEqual([
+ undefined, // fetching
+ ['Apple', 'Banana'], // initial data
+ ['Apple', 'Banana', 'cherry (optimistic)'], // optimistic data
+ ['Apple', 'Banana', 'Cherry (res)'], // appended server response
+ ['Apple', 'Banana', 'Cherry'] // revalidated data
+ ])
+ })
})
diff --git a/yarn.lock b/yarn.lock
index f4461cd66..c70b5e6cc 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1253,65 +1253,65 @@
resolved "https://registry.yarnpkg.com/@napi-rs/triples/-/triples-1.0.3.tgz#76d6d0c3f4d16013c61e45dfca5ff1e6c31ae53c"
integrity sha512-jDJTpta+P4p1NZTFVLHJ/TLFVYVcOqv6l8xwOeBKNPMgY/zDYH/YH7SJbvrr/h1RcS9GzbPcLKGzpuK9cV56UA==
-"@next/env@12.0.9":
- version "12.0.9"
- resolved "https://registry.yarnpkg.com/@next/env/-/env-12.0.9.tgz#4c9e9eef00226145d9629a846b8cc31878e1328c"
- integrity sha512-oBlkyDop0Stf7MPIzETGv5r0YT/G/weBrknoPOUTaa5qwOeGjuy6gsOVc/SBtrBkOoBmRpD+fFhQJPvmo1mS+g==
-
-"@next/swc-android-arm64@12.0.9":
- version "12.0.9"
- resolved "https://registry.yarnpkg.com/@next/swc-android-arm64/-/swc-android-arm64-12.0.9.tgz#2cdbcc1814471044ea0e057b475090d25654833c"
- integrity sha512-aVqgsEn5plmUH2X58sjzhHsH/6majucWTMaaBEs7hHO2+GCwCZc7zaLH4XCBMKPES9Yaja8/pYUbvZQE9DqgFw==
-
-"@next/swc-darwin-arm64@12.0.9":
- version "12.0.9"
- resolved "https://registry.yarnpkg.com/@next/swc-darwin-arm64/-/swc-darwin-arm64-12.0.9.tgz#ea200929d7116de12c6f3b13ff75f9522c2153e3"
- integrity sha512-uAgRKm4a2nVdyBiPPJokvmDD1saugOvxljz9ld2ih0CCg5S9vBhqaj3kPGCQBj9hSu3q+Lng2CHnQqG3ga1jzA==
-
-"@next/swc-darwin-x64@12.0.9":
- version "12.0.9"
- resolved "https://registry.yarnpkg.com/@next/swc-darwin-x64/-/swc-darwin-x64-12.0.9.tgz#32800a7a9aff4bfd2038b0bce3657ece8708a87b"
- integrity sha512-fDOs2lZIyrAdU18IxMA5orBPn9qLbOdu55gXSTNZOhyRJ8ugtbUAejsK7OL0boJy0CCHPAdVRXm01Mwk8tZ9RQ==
-
-"@next/swc-linux-arm-gnueabihf@12.0.9":
- version "12.0.9"
- resolved "https://registry.yarnpkg.com/@next/swc-linux-arm-gnueabihf/-/swc-linux-arm-gnueabihf-12.0.9.tgz#da012dfb69ad2abc3d4045395581b650048bdd7c"
- integrity sha512-/ni0p9DBvATUML9RQ1ycQuf05uOYKdzA6iI8+eRsARjpGbFVUFbge7XPzlj9g2Q9YWgoN8CSjFGnKRlyky5uHA==
-
-"@next/swc-linux-arm64-gnu@12.0.9":
- version "12.0.9"
- resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-12.0.9.tgz#fe704c0a1cb048ef19d4a24b2c990574c96c933b"
- integrity sha512-AphxilJDf95rUxJDHgM9Ww1DaYXZWqTvoKwXeej/0SgSvICcRZrLaFDrkojdXz0Rxr4igX2OdYR1S4/Hj1jWOQ==
-
-"@next/swc-linux-arm64-musl@12.0.9":
- version "12.0.9"
- resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-12.0.9.tgz#b2bb68940903cd64f7875979ed9907e946dc4f3e"
- integrity sha512-K5jbvNNzF3mRjWmPdxP5Bg87i7FHivfBj/L0KJlxpkLSC8sffBJDmB6jtMnI7wiPj9J6vmLkbGtSosln78xAlQ==
-
-"@next/swc-linux-x64-gnu@12.0.9":
- version "12.0.9"
- resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-12.0.9.tgz#b700ba095551d4f6e830b92d4593a3b6e73bba82"
- integrity sha512-bJZ9bkMkQzsY+UyWezEZ77GWQ4TzwKeXdayX3U3+aEkL8k5C6eKBXlidWdrhu0teLmaUXIyWerWrLnJzwGXdfw==
-
-"@next/swc-linux-x64-musl@12.0.9":
- version "12.0.9"
- resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-12.0.9.tgz#678460266f544b52f1190ef0c3494e436608591e"
- integrity sha512-SR9p0R+v1T32DTXPVAXZw31pmJAkSDotC6Afy+mfC0xrEL3pp95R8sGXYAAUCEPkQp0MEeUOVy2LrToe92X7hQ==
-
-"@next/swc-win32-arm64-msvc@12.0.9":
- version "12.0.9"
- resolved "https://registry.yarnpkg.com/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-12.0.9.tgz#f70e5bd0821ca168aeef117e51ab870265ceeeb1"
- integrity sha512-mzQ1A8vfHhJrvEy5KJZGZWEByXthyKfWofvFaf+oo/5nJl/0Bz1ODP2ajSmbLG++77Eo2AROgbm9pkW1ucvG2A==
-
-"@next/swc-win32-ia32-msvc@12.0.9":
- version "12.0.9"
- resolved "https://registry.yarnpkg.com/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-12.0.9.tgz#0b853793754642cde9f9099087d4a86b6a99a24d"
- integrity sha512-MpD2vj1zjo1u3J3wiz3pEKse19Etz+P0GL6XfQkB/9a84vJQ1JWMaWBjmIdivzZv718Il2pRSSx8hymwPfguYQ==
-
-"@next/swc-win32-x64-msvc@12.0.9":
- version "12.0.9"
- resolved "https://registry.yarnpkg.com/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-12.0.9.tgz#f7d3b59000082cf65c84fdc61930b708aa5446e5"
- integrity sha512-1c/sxp/4Qz4F6rCxiYqAnrmghCOFt5hHZ9Kd+rXFW5Mqev4C4XDOUMHdBH55HgnJZqngYhOE0r/XNkCtsIojig==
+"@next/env@12.1.0":
+ version "12.1.0"
+ resolved "https://registry.yarnpkg.com/@next/env/-/env-12.1.0.tgz#73713399399b34aa5a01771fb73272b55b22c314"
+ integrity sha512-nrIgY6t17FQ9xxwH3jj0a6EOiQ/WDHUos35Hghtr+SWN/ntHIQ7UpuvSi0vaLzZVHQWaDupKI+liO5vANcDeTQ==
+
+"@next/swc-android-arm64@12.1.0":
+ version "12.1.0"
+ resolved "https://registry.yarnpkg.com/@next/swc-android-arm64/-/swc-android-arm64-12.1.0.tgz#865ba3a9afc204ff2bdeea49dd64d58705007a39"
+ integrity sha512-/280MLdZe0W03stA69iL+v6I+J1ascrQ6FrXBlXGCsGzrfMaGr7fskMa0T5AhQIVQD4nA/46QQWxG//DYuFBcA==
+
+"@next/swc-darwin-arm64@12.1.0":
+ version "12.1.0"
+ resolved "https://registry.yarnpkg.com/@next/swc-darwin-arm64/-/swc-darwin-arm64-12.1.0.tgz#08e8b411b8accd095009ed12efbc2f1d4d547135"
+ integrity sha512-R8vcXE2/iONJ1Unf5Ptqjk6LRW3bggH+8drNkkzH4FLEQkHtELhvcmJwkXcuipyQCsIakldAXhRbZmm3YN1vXg==
+
+"@next/swc-darwin-x64@12.1.0":
+ version "12.1.0"
+ resolved "https://registry.yarnpkg.com/@next/swc-darwin-x64/-/swc-darwin-x64-12.1.0.tgz#fcd684497a76e8feaca88db3c394480ff0b007cd"
+ integrity sha512-ieAz0/J0PhmbZBB8+EA/JGdhRHBogF8BWaeqR7hwveb6SYEIJaDNQy0I+ZN8gF8hLj63bEDxJAs/cEhdnTq+ug==
+
+"@next/swc-linux-arm-gnueabihf@12.1.0":
+ version "12.1.0"
+ resolved "https://registry.yarnpkg.com/@next/swc-linux-arm-gnueabihf/-/swc-linux-arm-gnueabihf-12.1.0.tgz#9ec6380a27938a5799aaa6035c205b3c478468a7"
+ integrity sha512-njUd9hpl6o6A5d08dC0cKAgXKCzm5fFtgGe6i0eko8IAdtAPbtHxtpre3VeSxdZvuGFh+hb0REySQP9T1ttkog==
+
+"@next/swc-linux-arm64-gnu@12.1.0":
+ version "12.1.0"
+ resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-12.1.0.tgz#7f4196dff1049cea479607c75b81033ae2dbd093"
+ integrity sha512-OqangJLkRxVxMhDtcb7Qn1xjzFA3s50EIxY7mljbSCLybU+sByPaWAHY4px97ieOlr2y4S0xdPKkQ3BCAwyo6Q==
+
+"@next/swc-linux-arm64-musl@12.1.0":
+ version "12.1.0"
+ resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-12.1.0.tgz#b445f767569cdc2dddee785ca495e1a88c025566"
+ integrity sha512-hB8cLSt4GdmOpcwRe2UzI5UWn6HHO/vLkr5OTuNvCJ5xGDwpPXelVkYW/0+C3g5axbDW2Tym4S+MQCkkH9QfWA==
+
+"@next/swc-linux-x64-gnu@12.1.0":
+ version "12.1.0"
+ resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-12.1.0.tgz#67610e9be4fbc987de7535f1bcb17e45fe12f90e"
+ integrity sha512-OKO4R/digvrVuweSw/uBM4nSdyzsBV5EwkUeeG4KVpkIZEe64ZwRpnFB65bC6hGwxIBnTv5NMSnJ+0K/WmG78A==
+
+"@next/swc-linux-x64-musl@12.1.0":
+ version "12.1.0"
+ resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-12.1.0.tgz#ea19a23db08a9f2e34ac30401f774cf7d1669d31"
+ integrity sha512-JohhgAHZvOD3rQY7tlp7NlmvtvYHBYgY0x5ZCecUT6eCCcl9lv6iV3nfu82ErkxNk1H893fqH0FUpznZ/H3pSw==
+
+"@next/swc-win32-arm64-msvc@12.1.0":
+ version "12.1.0"
+ resolved "https://registry.yarnpkg.com/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-12.1.0.tgz#eadf054fc412085659b98e145435bbba200b5283"
+ integrity sha512-T/3gIE6QEfKIJ4dmJk75v9hhNiYZhQYAoYm4iVo1TgcsuaKLFa+zMPh4056AHiG6n9tn2UQ1CFE8EoybEsqsSw==
+
+"@next/swc-win32-ia32-msvc@12.1.0":
+ version "12.1.0"
+ resolved "https://registry.yarnpkg.com/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-12.1.0.tgz#68faeae10c89f698bf9d28759172b74c9c21bda1"
+ integrity sha512-iwnKgHJdqhIW19H9PRPM9j55V6RdcOo6rX+5imx832BCWzkDbyomWnlzBfr6ByUYfhohb8QuH4hSGEikpPqI0Q==
+
+"@next/swc-win32-x64-msvc@12.1.0":
+ version "12.1.0"
+ resolved "https://registry.yarnpkg.com/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-12.1.0.tgz#d27e7e76c87a460a4da99c5bfdb1618dcd6cd064"
+ integrity sha512-aBvcbMwuanDH4EMrL2TthNJy+4nP59Bimn8egqv6GHMVj0a44cU6Au4PjOhLNqEh9l+IpRGBqMTzec94UdC5xg==
"@node-rs/helper@^1.0.0":
version "1.2.1"
@@ -4962,28 +4962,28 @@ natural-compare@^1.4.0:
resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7"
integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=
-next@12.0.9:
- version "12.0.9"
- resolved "https://registry.yarnpkg.com/next/-/next-12.0.9.tgz#4eb3006b63bb866f5c2918ca0003e98f4259e063"
- integrity sha512-omfYqoR/DvbdOIJ6SS1unKJ4mGIxUPs0RPa7wr/Mft22OCKgJhuG+aI9KFYi5ZJBwoFQk1vqaMKpWz5qr+dN0Q==
+next@^12.1.0:
+ version "12.1.0"
+ resolved "https://registry.yarnpkg.com/next/-/next-12.1.0.tgz#c33d753b644be92fc58e06e5a214f143da61dd5d"
+ integrity sha512-s885kWvnIlxsUFHq9UGyIyLiuD0G3BUC/xrH0CEnH5lHEWkwQcHOORgbDF0hbrW9vr/7am4ETfX4A7M6DjrE7Q==
dependencies:
- "@next/env" "12.0.9"
+ "@next/env" "12.1.0"
caniuse-lite "^1.0.30001283"
postcss "8.4.5"
styled-jsx "5.0.0"
use-subscription "1.5.1"
optionalDependencies:
- "@next/swc-android-arm64" "12.0.9"
- "@next/swc-darwin-arm64" "12.0.9"
- "@next/swc-darwin-x64" "12.0.9"
- "@next/swc-linux-arm-gnueabihf" "12.0.9"
- "@next/swc-linux-arm64-gnu" "12.0.9"
- "@next/swc-linux-arm64-musl" "12.0.9"
- "@next/swc-linux-x64-gnu" "12.0.9"
- "@next/swc-linux-x64-musl" "12.0.9"
- "@next/swc-win32-arm64-msvc" "12.0.9"
- "@next/swc-win32-ia32-msvc" "12.0.9"
- "@next/swc-win32-x64-msvc" "12.0.9"
+ "@next/swc-android-arm64" "12.1.0"
+ "@next/swc-darwin-arm64" "12.1.0"
+ "@next/swc-darwin-x64" "12.1.0"
+ "@next/swc-linux-arm-gnueabihf" "12.1.0"
+ "@next/swc-linux-arm64-gnu" "12.1.0"
+ "@next/swc-linux-arm64-musl" "12.1.0"
+ "@next/swc-linux-x64-gnu" "12.1.0"
+ "@next/swc-linux-x64-musl" "12.1.0"
+ "@next/swc-win32-arm64-msvc" "12.1.0"
+ "@next/swc-win32-ia32-msvc" "12.1.0"
+ "@next/swc-win32-x64-msvc" "12.1.0"
nice-try@^1.0.4:
version "1.0.5"
@@ -6265,6 +6265,7 @@ supports-hyperlinks@^2.0.0:
"swr@link:.":
version "0.0.0"
+ uid ""
symbol-observable@^1.1.0:
version "1.2.0"