diff --git a/CLAUDE.md b/CLAUDE.md index 1abe8afde7f..535924fcb2c 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -27,6 +27,7 @@ When running scripts, use `npx turbo`, not `npm`. # Code style +- Always try to add proper typing, limit the use of `any`. If needed, ask first. - Use $-suffix for variables storing Promises - Use Σ-suffix for variables storing Signals (MutableSignal, Signal, DerivedSignal, etc) diff --git a/docs/pages/get-started/zustand.mdx b/docs/pages/get-started/zustand.mdx index 534323b7f97..30465ee2de1 100644 --- a/docs/pages/get-started/zustand.mdx +++ b/docs/pages/get-started/zustand.mdx @@ -161,7 +161,7 @@ collaborative experiences for your Zustand store. - [@liveblocks/zustand API Reference](/docs/api-reference/liveblocks-zustand) - [Zustand guides](/docs/guides?technologies=zustand) -- [How to use Liveblocks Presence with Zustand](/docs/guides/how-to-create-a-collaborative-to-do-list-with-react-zustand-and-liveblocks) +- [How to use Liveblocks Presence with Zustand](/docs/guides/how-to-use-liveblocks-presence-with-zustand) - [How to use Liveblocks Storage with Zustand](/docs/guides/how-to-use-liveblocks-storage-with-zustand) --- diff --git a/guides/pages/how-to-use-liveblocks-presence-with-zustand.mdx b/guides/pages/how-to-use-liveblocks-presence-with-zustand.mdx index 0c01133dd3b..6564a5b272a 100644 --- a/guides/pages/how-to-use-liveblocks-presence-with-zustand.mdx +++ b/guides/pages/how-to-use-liveblocks-presence-with-zustand.mdx @@ -129,6 +129,7 @@ function App() { } ``` +[`@liveblocks/zustand`]: /docs/api-reference/liveblocks-zustand [`room.history.undo`]: /docs/api-reference/liveblocks-client#Room.history.undo [`room.history.redo`]: /docs/api-reference/liveblocks-client#Room.history.redo [`room.history.pause`]: /docs/api-reference/liveblocks-client#Room.history.pause diff --git a/guides/pages/how-to-use-liveblocks-storage-with-zustand.mdx b/guides/pages/how-to-use-liveblocks-storage-with-zustand.mdx index 56ca0b6638c..98ab2707912 100644 --- a/guides/pages/how-to-use-liveblocks-storage-with-zustand.mdx +++ b/guides/pages/how-to-use-liveblocks-storage-with-zustand.mdx @@ -105,6 +105,7 @@ room's storage from our server and patches your store. If this is the first time you're entering a room, the storage will be initialized with the current value in your Zustand state, typically your initial state. +[`@liveblocks/zustand`]: /docs/api-reference/liveblocks-zustand [`room.history.undo`]: /docs/api-reference/liveblocks-client#Room.history.undo [`room.history.redo`]: /docs/api-reference/liveblocks-client#Room.history.redo [`room.history.pause`]: /docs/api-reference/liveblocks-client#Room.history.pause diff --git a/package-lock.json b/package-lock.json index c26097e63bc..87768a52576 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18,6 +18,7 @@ "@types/node": "^18.19.70", "@types/react": "^18.3.17", "@types/react-dom": "^18.3.5", + "@vitest/coverage-istanbul": "^2.1.9", "dependency-cruiser": "^16.9.0", "prettier": "^3.4.2", "publint": "^0.3.6", @@ -25,7 +26,8 @@ "tsd": "^0.31.2", "tsup": "^8.3.5", "turbo": "^2.3.3", - "typescript": "^5.7.2" + "typescript": "^5.7.2", + "vitest": "^2.1.9" }, "engines": { "node": ">=22.x" @@ -1593,6 +1595,116 @@ "node": ">=14.17" } }, + "node_modules/@asamuzakjp/css-color": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@asamuzakjp/css-color/-/css-color-3.2.0.tgz", + "integrity": "sha512-K1A6z8tS3XsmCMM86xoWdn7Fkdn9m6RSVtocUrJYIwZnFVkng/PvkEoWtOWmP+Scc6saYWHWZYbndEEXxl24jw==", + "license": "MIT", + "dependencies": { + "@csstools/css-calc": "^2.1.3", + "@csstools/css-color-parser": "^3.0.9", + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3", + "lru-cache": "^10.4.3" + } + }, + "node_modules/@asamuzakjp/css-color/node_modules/@csstools/css-calc": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@csstools/css-calc/-/css-calc-2.1.4.tgz", + "integrity": "sha512-3N8oaj+0juUw/1H3YwmDDJXCgTB1gKU6Hc/bB502u9zR0q2vd786XJH9QfrKIEgFlZmhZiq6epXl4rHqhzsIgQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4" + } + }, + "node_modules/@asamuzakjp/css-color/node_modules/@csstools/css-color-parser": { + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-3.0.10.tgz", + "integrity": "sha512-TiJ5Ajr6WRd1r8HSiwJvZBiJOqtH86aHpUjq5aEKWHiII2Qfjqd/HCWKPOW8EP4vcspXbHnXrwIDlu5savQipg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "dependencies": { + "@csstools/color-helpers": "^5.0.2", + "@csstools/css-calc": "^2.1.4" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4" + } + }, + "node_modules/@asamuzakjp/css-color/node_modules/@csstools/css-parser-algorithms": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-3.0.5.tgz", + "integrity": "sha512-DaDeUkXZKjdGhgYaHNJTV9pV7Y9B3b644jCLs9Upc3VeNGg6LWARAT6O+Q+/COo+2gg/bM5rhpMAtf70WqfBdQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@csstools/css-tokenizer": "^3.0.4" + } + }, + "node_modules/@asamuzakjp/css-color/node_modules/@csstools/css-tokenizer": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-3.0.4.tgz", + "integrity": "sha512-Vd/9EVDiu6PPJt9yAh6roZP6El1xHrdvIVGjyBsHR0RYwNHgL7FJPyIIW4fANJNG6FtyZfvlRPpFI4ZM/lubvw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/@asamuzakjp/css-color/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "license": "ISC" + }, "node_modules/@babel/code-frame": { "version": "7.24.6", "license": "MIT", @@ -3562,7 +3674,7 @@ }, "node_modules/@bundled-es-modules/cookie": { "version": "2.0.1", - "devOptional": true, + "dev": true, "license": "ISC", "dependencies": { "cookie": "^0.7.2" @@ -3570,7 +3682,7 @@ }, "node_modules/@bundled-es-modules/cookie/node_modules/cookie": { "version": "0.7.2", - "devOptional": true, + "dev": true, "license": "MIT", "engines": { "node": ">= 0.6" @@ -3578,7 +3690,7 @@ }, "node_modules/@bundled-es-modules/statuses": { "version": "1.0.1", - "devOptional": true, + "dev": true, "license": "ISC", "dependencies": { "statuses": "^2.0.1" @@ -3586,7 +3698,7 @@ }, "node_modules/@bundled-es-modules/tough-cookie": { "version": "0.1.6", - "devOptional": true, + "dev": true, "license": "ISC", "dependencies": { "@types/tough-cookie": "^4.0.5", @@ -3602,6 +3714,25 @@ "node": ">=0.1.90" } }, + "node_modules/@csstools/color-helpers": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-5.0.2.tgz", + "integrity": "sha512-JqWH1vsgdGcw2RR6VliXXdA0/59LttzlU8UlRT/iUUsEeWfYq8I+K0yhihEUTTHLRm1EXvpsCx3083EU15ecsA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "engines": { + "node": ">=18" + } + }, "node_modules/@csstools/css-parser-algorithms": { "version": "2.3.1", "devOptional": true, @@ -4387,7 +4518,7 @@ }, "node_modules/@inquirer/confirm": { "version": "5.1.1", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "@inquirer/core": "^10.1.2", @@ -4402,7 +4533,7 @@ }, "node_modules/@inquirer/core": { "version": "10.1.2", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "@inquirer/figures": "^1.0.9", @@ -4421,7 +4552,7 @@ }, "node_modules/@inquirer/core/node_modules/cli-width": { "version": "4.1.0", - "devOptional": true, + "dev": true, "license": "ISC", "engines": { "node": ">= 12" @@ -4429,7 +4560,7 @@ }, "node_modules/@inquirer/core/node_modules/mute-stream": { "version": "2.0.0", - "devOptional": true, + "dev": true, "license": "ISC", "engines": { "node": "^18.17.0 || >=20.5.0" @@ -4437,7 +4568,7 @@ }, "node_modules/@inquirer/core/node_modules/signal-exit": { "version": "4.1.0", - "devOptional": true, + "dev": true, "license": "ISC", "engines": { "node": ">=14" @@ -4448,7 +4579,7 @@ }, "node_modules/@inquirer/core/node_modules/wrap-ansi": { "version": "6.2.0", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", @@ -4461,7 +4592,7 @@ }, "node_modules/@inquirer/figures": { "version": "1.0.9", - "devOptional": true, + "dev": true, "license": "MIT", "engines": { "node": ">=18" @@ -4469,7 +4600,7 @@ }, "node_modules/@inquirer/type": { "version": "3.0.2", - "devOptional": true, + "dev": true, "license": "MIT", "engines": { "node": ">=18" @@ -5522,6 +5653,8 @@ }, "node_modules/@mswjs/cookies": { "version": "0.2.2", + "resolved": "https://registry.npmjs.org/@mswjs/cookies/-/cookies-0.2.2.tgz", + "integrity": "sha512-mlN83YSrcFgk7Dm1Mys40DLssI1KdJji2CMKN8eOlBqsTADYzj2+jWzsANsUTFbxDMWPD5e9bfA1RGqBpS3O1g==", "dev": true, "license": "MIT", "dependencies": { @@ -5533,29 +5666,21 @@ } }, "node_modules/@mswjs/interceptors": { - "version": "0.17.10", + "version": "0.39.5", + "resolved": "https://registry.npmjs.org/@mswjs/interceptors/-/interceptors-0.39.5.tgz", + "integrity": "sha512-B9nHSJYtsv79uo7QdkZ/b/WoKm20IkVSmTc/WCKarmDtFwM0dRx2ouEniqwNkzCSLn3fydzKmnMzjtfdOWt3VQ==", "dev": true, "license": "MIT", "dependencies": { - "@open-draft/until": "^1.0.3", - "@types/debug": "^4.1.7", - "@xmldom/xmldom": "^0.8.3", - "debug": "^4.3.3", - "headers-polyfill": "3.2.5", - "outvariant": "^1.2.1", - "strict-event-emitter": "^0.2.4", - "web-encoding": "^1.1.5" + "@open-draft/deferred-promise": "^2.2.0", + "@open-draft/logger": "^0.3.0", + "@open-draft/until": "^2.0.0", + "is-node-process": "^1.2.0", + "outvariant": "^1.4.3", + "strict-event-emitter": "^0.5.1" }, "engines": { - "node": ">=14" - } - }, - "node_modules/@mswjs/interceptors/node_modules/@xmldom/xmldom": { - "version": "0.8.10", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10.0.0" + "node": ">=18" } }, "node_modules/@next/env": { @@ -5815,12 +5940,14 @@ }, "node_modules/@open-draft/deferred-promise": { "version": "2.2.0", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/@open-draft/logger": { "version": "0.3.0", - "devOptional": true, + "resolved": "https://registry.npmjs.org/@open-draft/logger/-/logger-0.3.0.tgz", + "integrity": "sha512-X2g45fzhxH238HKO4xbSr7+wBS8Fvw6ixhTDuvLd5mqh6bJJCFAPwU9mPDxbcrRtfxv4u5IHCEH77BmxvXmmxQ==", + "dev": true, "license": "MIT", "dependencies": { "is-node-process": "^1.2.0", @@ -5828,7 +5955,9 @@ } }, "node_modules/@open-draft/until": { - "version": "1.0.3", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@open-draft/until/-/until-2.1.0.tgz", + "integrity": "sha512-U69T3ItWHvLwGg5eJ0n3I62nWuE6ilHlmz7zM0npLBRvPRd7e6NYmg54vvRtP5mZG7kZqZCFVdsTWo7BPtBujg==", "dev": true, "license": "MIT" }, @@ -15332,222 +15461,6 @@ } } }, - "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.36.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.36.0.tgz", - "integrity": "sha512-jgrXjjcEwN6XpZXL0HUeOVGfjXhPyxAbbhD0BlXUB+abTOpbPiN5Wb3kOT7yb+uEtATNYF5x5gIfwutmuBA26w==", - "cpu": [ - "arm" - ], - "optional": true, - "os": [ - "android" - ] - }, - "node_modules/@rollup/rollup-android-arm64": { - "version": "4.36.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.36.0.tgz", - "integrity": "sha512-NyfuLvdPdNUfUNeYKUwPwKsE5SXa2J6bCt2LdB/N+AxShnkpiczi3tcLJrm5mA+eqpy0HmaIY9F6XCa32N5yzg==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "android" - ] - }, - "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.36.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.36.0.tgz", - "integrity": "sha512-6c6wMZa1lrtiRsbDziCmjE53YbTkxMYhhnWnSW8R/yqsM7a6mSJ3uAVT0t8Y/DGt7gxUWYuFM4bwWk9XCJrFKA==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.36.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.36.0.tgz", - "integrity": "sha512-KXVsijKeJXOl8QzXTsA+sHVDsFOmMCdBRgFmBb+mfEb/7geR7+C8ypAml4fquUt14ZyVXaw2o1FWhqAfOvA4sg==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "freebsd" - ] - }, - "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.36.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.36.0.tgz", - "integrity": "sha512-dVeWq1ebbvByI+ndz4IJcD4a09RJgRYmLccwlQ8bPd4olz3Y213uf1iwvc7ZaxNn2ab7bjc08PrtBgMu6nb4pQ==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "freebsd" - ] - }, - "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.36.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.36.0.tgz", - "integrity": "sha512-bvXVU42mOVcF4le6XSjscdXjqx8okv4n5vmwgzcmtvFdifQ5U4dXFYaCB87namDRKlUL9ybVtLQ9ztnawaSzvg==", - "cpu": [ - "arm" - ], - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.36.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.36.0.tgz", - "integrity": "sha512-JFIQrDJYrxOnyDQGYkqnNBtjDwTgbasdbUiQvcU8JmGDfValfH1lNpng+4FWlhaVIR4KPkeddYjsVVbmJYvDcg==", - "cpu": [ - "arm" - ], - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.36.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.36.0.tgz", - "integrity": "sha512-KqjYVh3oM1bj//5X7k79PSCZ6CvaVzb7Qs7VMWS+SlWB5M8p3FqufLP9VNp4CazJ0CsPDLwVD9r3vX7Ci4J56A==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.36.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.36.0.tgz", - "integrity": "sha512-QiGnhScND+mAAtfHqeT+cB1S9yFnNQ/EwCg5yE3MzoaZZnIV0RV9O5alJAoJKX/sBONVKeZdMfO8QSaWEygMhw==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-loongarch64-gnu": { - "version": "4.36.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.36.0.tgz", - "integrity": "sha512-1ZPyEDWF8phd4FQtTzMh8FQwqzvIjLsl6/84gzUxnMNFBtExBtpL51H67mV9xipuxl1AEAerRBgBwFNpkw8+Lg==", - "cpu": [ - "loong64" - ], - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { - "version": "4.36.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.36.0.tgz", - "integrity": "sha512-VMPMEIUpPFKpPI9GZMhJrtu8rxnp6mJR3ZzQPykq4xc2GmdHj3Q4cA+7avMyegXy4n1v+Qynr9fR88BmyO74tg==", - "cpu": [ - "ppc64" - ], - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.36.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.36.0.tgz", - "integrity": "sha512-ttE6ayb/kHwNRJGYLpuAvB7SMtOeQnVXEIpMtAvx3kepFQeowVED0n1K9nAdraHUPJ5hydEMxBpIR7o4nrm8uA==", - "cpu": [ - "riscv64" - ], - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.36.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.36.0.tgz", - "integrity": "sha512-4a5gf2jpS0AIe7uBjxDeUMNcFmaRTbNv7NxI5xOCs4lhzsVyGR/0qBXduPnoWf6dGC365saTiwag8hP1imTgag==", - "cpu": [ - "s390x" - ], - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.36.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.36.0.tgz", - "integrity": "sha512-5KtoW8UWmwFKQ96aQL3LlRXX16IMwyzMq/jSSVIIyAANiE1doaQsx/KRyhAvpHlPjPiSU/AYX/8m+lQ9VToxFQ==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.36.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.36.0.tgz", - "integrity": "sha512-sycrYZPrv2ag4OCvaN5js+f01eoZ2U+RmT5as8vhxiFz+kxwlHrsxOwKPSA8WyS+Wc6Epid9QeI/IkQ9NkgYyQ==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.36.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.36.0.tgz", - "integrity": "sha512-qbqt4N7tokFwwSVlWDsjfoHgviS3n/vZ8LK0h1uLG9TYIRuUTJC88E1xb3LM2iqZ/WTqNQjYrtmtGmrmmawB6A==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.36.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.36.0.tgz", - "integrity": "sha512-t+RY0JuRamIocMuQcfwYSOkmdX9dtkr1PbhKW42AMvaDQa+jOdpUYysroTF/nuPpAaQMWp7ye+ndlmmthieJrQ==", - "cpu": [ - "ia32" - ], - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.36.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.36.0.tgz", - "integrity": "sha512-aRXd7tRZkWLqGbChgcMMDEHjOKudo1kChb1Jt1IfR8cY/KIpgNviLeJy5FUb9IpSuQj8dU2fAYNMPW/hLKOSTw==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "win32" - ] - }, "node_modules/@rtsao/scc": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz", @@ -17269,7 +17182,9 @@ "license": "MIT" }, "node_modules/@types/cookie": { - "version": "0.4.1", + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==", "dev": true, "license": "MIT" }, @@ -17559,7 +17474,9 @@ } }, "node_modules/@types/js-levenshtein": { - "version": "1.1.1", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@types/js-levenshtein/-/js-levenshtein-1.1.3.tgz", + "integrity": "sha512-jd+Q+sD20Qfu9e2aEXogiO3vpOC1PYJOUdyN9gvs4Qrvkg4wF43L5OhqrPeokdv8TL0/mXoYfpkcoGZMNN2pkQ==", "dev": true, "license": "MIT" }, @@ -17696,7 +17613,9 @@ } }, "node_modules/@types/set-cookie-parser": { - "version": "2.4.2", + "version": "2.4.10", + "resolved": "https://registry.npmjs.org/@types/set-cookie-parser/-/set-cookie-parser-2.4.10.tgz", + "integrity": "sha512-GGmQVGpQWUe5qglJozEjZV/5dyxbOOZ0LHe/lqyWssB88Y4svNfst0uqBVscdDeIKl5Jy5+aPSvy7mI9tYRguw==", "dev": true, "license": "MIT", "dependencies": { @@ -17709,7 +17628,7 @@ }, "node_modules/@types/statuses": { "version": "2.0.5", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/@types/testing-library__jest-dom": { @@ -17975,11 +17894,14 @@ "license": "ISC" }, "node_modules/@vitest/coverage-istanbul": { - "version": "3.0.7", + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/@vitest/coverage-istanbul/-/coverage-istanbul-2.1.9.tgz", + "integrity": "sha512-vdYE4FkC/y2lxcN3Dcj54Bw+ericmDwiex0B8LV5F/YNYEYP1mgVwhPnHwWGAXu38qizkjOuyczKbFTALfzFKw==", + "dev": true, "license": "MIT", "dependencies": { "@istanbuljs/schema": "^0.1.3", - "debug": "^4.4.0", + "debug": "^4.3.7", "istanbul-lib-coverage": "^3.2.2", "istanbul-lib-instrument": "^6.0.3", "istanbul-lib-report": "^3.0.1", @@ -17987,17 +17909,20 @@ "istanbul-reports": "^3.1.7", "magicast": "^0.3.5", "test-exclude": "^7.0.1", - "tinyrainbow": "^2.0.0" + "tinyrainbow": "^1.2.0" }, "funding": { "url": "https://opencollective.com/vitest" }, "peerDependencies": { - "vitest": "3.0.7" + "vitest": "2.1.9" } }, "node_modules/@vitest/coverage-istanbul/node_modules/brace-expansion": { - "version": "2.0.1", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "dev": true, "license": "MIT", "dependencies": { "balanced-match": "^1.0.0" @@ -18005,6 +17930,9 @@ }, "node_modules/@vitest/coverage-istanbul/node_modules/glob": { "version": "10.4.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", + "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", + "dev": true, "license": "ISC", "dependencies": { "foreground-child": "^3.1.0", @@ -18023,6 +17951,9 @@ }, "node_modules/@vitest/coverage-istanbul/node_modules/istanbul-lib-instrument": { "version": "6.0.3", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz", + "integrity": "sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==", + "dev": true, "license": "BSD-3-Clause", "dependencies": { "@babel/core": "^7.23.9", @@ -18037,6 +17968,9 @@ }, "node_modules/@vitest/coverage-istanbul/node_modules/istanbul-lib-source-maps": { "version": "5.0.6", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-5.0.6.tgz", + "integrity": "sha512-yg2d+Em4KizZC5niWhQaIomgf5WlL4vOOjZ5xGCmF8SnPE/mDWWXgvRExdcpCgh9lLRRa1/fSYp2ymmbJ1pI+A==", + "dev": true, "license": "BSD-3-Clause", "dependencies": { "@jridgewell/trace-mapping": "^0.3.23", @@ -18049,6 +17983,9 @@ }, "node_modules/@vitest/coverage-istanbul/node_modules/minimatch": { "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, "license": "ISC", "dependencies": { "brace-expansion": "^2.0.1" @@ -18062,6 +17999,9 @@ }, "node_modules/@vitest/coverage-istanbul/node_modules/test-exclude": { "version": "7.0.1", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-7.0.1.tgz", + "integrity": "sha512-pFYqmTw68LXVjeWJMST4+borgQP2AyMNbg1BpZh9LbyhUeNkeaPF9gzfPGUAnSMV3qPYdWUwDIjjCLiSDOl7vg==", + "dev": true, "license": "ISC", "dependencies": { "@istanbuljs/schema": "^0.1.2", @@ -18073,59 +18013,69 @@ } }, "node_modules/@vitest/expect": { - "version": "3.0.7", + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-2.1.9.tgz", + "integrity": "sha512-UJCIkTBenHeKT1TTlKMJWy1laZewsRIzYighyYiJKZreqtdxSos/S1t+ktRMQWu2CKqaarrkeszJx1cgC5tGZw==", + "dev": true, "license": "MIT", - "peer": true, "dependencies": { - "@vitest/spy": "3.0.7", - "@vitest/utils": "3.0.7", - "chai": "^5.2.0", - "tinyrainbow": "^2.0.0" + "@vitest/spy": "2.1.9", + "@vitest/utils": "2.1.9", + "chai": "^5.1.2", + "tinyrainbow": "^1.2.0" }, "funding": { "url": "https://opencollective.com/vitest" } }, "node_modules/@vitest/pretty-format": { - "version": "3.0.7", + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-2.1.9.tgz", + "integrity": "sha512-KhRIdGV2U9HOUzxfiHmY8IFHTdqtOhIzCpd8WRdJiE7D/HUcZVD0EgQCVjm+Q9gkUXWgBvMmTtZgIG48wq7sOQ==", + "dev": true, "license": "MIT", - "peer": true, "dependencies": { - "tinyrainbow": "^2.0.0" + "tinyrainbow": "^1.2.0" }, "funding": { "url": "https://opencollective.com/vitest" } }, "node_modules/@vitest/runner": { - "version": "3.0.7", + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-2.1.9.tgz", + "integrity": "sha512-ZXSSqTFIrzduD63btIfEyOmNcBmQvgOVsPNPe0jYtESiXkhd8u2erDLnMxmGrDCwHCCHE7hxwRDCT3pt0esT4g==", + "dev": true, "license": "MIT", - "peer": true, "dependencies": { - "@vitest/utils": "3.0.7", - "pathe": "^2.0.3" + "@vitest/utils": "2.1.9", + "pathe": "^1.1.2" }, "funding": { "url": "https://opencollective.com/vitest" } }, "node_modules/@vitest/snapshot": { - "version": "3.0.7", + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-2.1.9.tgz", + "integrity": "sha512-oBO82rEjsxLNJincVhLhaxxZdEtV0EFHMK5Kmx5sJ6H9L183dHECjiefOAdnqpIgT5eZwT04PoggUnW88vOBNQ==", + "dev": true, "license": "MIT", - "peer": true, "dependencies": { - "@vitest/pretty-format": "3.0.7", - "magic-string": "^0.30.17", - "pathe": "^2.0.3" + "@vitest/pretty-format": "2.1.9", + "magic-string": "^0.30.12", + "pathe": "^1.1.2" }, "funding": { "url": "https://opencollective.com/vitest" } }, "node_modules/@vitest/spy": { - "version": "3.0.7", + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-2.1.9.tgz", + "integrity": "sha512-E1B35FwzXXTs9FHNK6bDszs7mtydNi5MIfUWpceJ8Xbfb1gBMscAnwLbEu+B44ed6W3XjL9/ehLPHR1fkf1KLQ==", + "dev": true, "license": "MIT", - "peer": true, "dependencies": { "tinyspy": "^3.0.2" }, @@ -18134,13 +18084,15 @@ } }, "node_modules/@vitest/utils": { - "version": "3.0.7", + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-2.1.9.tgz", + "integrity": "sha512-v0psaMSkNJ3A2NMrUEHFRzJtDPFn+/VWZ5WxImB21T9fjucJRmS7xCS3ppEnARb9y11OAzaD+P2Ps+b+BGX5iQ==", + "dev": true, "license": "MIT", - "peer": true, "dependencies": { - "@vitest/pretty-format": "3.0.7", - "loupe": "^3.1.3", - "tinyrainbow": "^2.0.0" + "@vitest/pretty-format": "2.1.9", + "loupe": "^3.1.2", + "tinyrainbow": "^1.2.0" }, "funding": { "url": "https://opencollective.com/vitest" @@ -18238,8 +18190,20 @@ "version": "3.3.4", "license": "MIT" }, + "node_modules/@xmldom/xmldom": { + "version": "0.8.10", + "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.10.tgz", + "integrity": "sha512-2WALfTl4xo2SkGCYRt6rDTFfk9R1czmBvUQy12gK2KuRKIpWEhcbbzy8EZXtz/jkRqHX8bFEc6FC1HjX4TUWYw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.0.0" + } + }, "node_modules/@zxing/text-encoding": { "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@zxing/text-encoding/-/text-encoding-0.9.0.tgz", + "integrity": "sha512-U/4aVJ2mxI0aDNI8Uq0wEhMgY+u4CNtEb0om3+y3+niDAsoTCOB33UF0sxpzqzdqXLqmvc+vZyAt4O8pPdfkwA==", "dev": true, "license": "(Unlicense OR Apache-2.0)", "optional": true @@ -18656,6 +18620,7 @@ }, "node_modules/assertion-error": { "version": "2.0.1", + "dev": true, "license": "MIT", "engines": { "node": ">=12" @@ -19394,6 +19359,7 @@ }, "node_modules/chai": { "version": "5.2.0", + "dev": true, "license": "MIT", "dependencies": { "assertion-error": "^2.0.1", @@ -19462,6 +19428,7 @@ }, "node_modules/check-error": { "version": "2.1.1", + "dev": true, "license": "MIT", "engines": { "node": ">= 16" @@ -20047,6 +20014,8 @@ }, "node_modules/cookie": { "version": "0.4.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", + "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==", "dev": true, "license": "MIT", "engines": { @@ -20734,6 +20703,7 @@ }, "node_modules/deep-eql": { "version": "5.0.2", + "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -20988,7 +20958,6 @@ "node_modules/dequal": { "version": "2.0.3", "license": "MIT", - "peer": true, "engines": { "node": ">=6" } @@ -22313,6 +22282,7 @@ }, "node_modules/expect-type": { "version": "1.2.0", + "dev": true, "license": "Apache-2.0", "engines": { "node": ">=12.0.0" @@ -23301,7 +23271,7 @@ }, "node_modules/graphql": { "version": "16.8.1", - "devOptional": true, + "dev": true, "license": "MIT", "engines": { "node": "^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0" @@ -23891,7 +23861,9 @@ } }, "node_modules/headers-polyfill": { - "version": "3.2.5", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/headers-polyfill/-/headers-polyfill-4.0.3.tgz", + "integrity": "sha512-IScLbePpkvO846sIwOtOTDjutRMWdXdJmXdMvk6gCBHxFO8d+QKOQedyZSxFTTFYRSmlgSTDtXqqq4pcenBXLQ==", "dev": true, "license": "MIT" }, @@ -24280,7 +24252,9 @@ } }, "node_modules/inquirer": { - "version": "8.2.4", + "version": "8.2.6", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.6.tgz", + "integrity": "sha512-M1WuAmb7pn9zdFRtQYk26ZBoY043Sse0wVDdk4Bppr+JOXyQYybdtvK+l9wUibhtjdjvtoiNy8tk+EgsYIUqKg==", "dev": true, "license": "MIT", "dependencies": { @@ -24298,7 +24272,7 @@ "string-width": "^4.1.0", "strip-ansi": "^6.0.0", "through": "^2.3.6", - "wrap-ansi": "^7.0.0" + "wrap-ansi": "^6.0.1" }, "engines": { "node": ">=12.0.0" @@ -24306,6 +24280,8 @@ }, "node_modules/inquirer/node_modules/chalk": { "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "license": "MIT", "dependencies": { @@ -24319,6 +24295,21 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "node_modules/inquirer/node_modules/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/internal-slot": { "version": "1.1.0", "license": "MIT", @@ -24748,7 +24739,7 @@ }, "node_modules/is-node-process": { "version": "1.2.0", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/is-number": { @@ -25841,7 +25832,7 @@ }, "node_modules/jiti": { "version": "1.21.3", - "devOptional": true, + "dev": true, "license": "MIT", "bin": { "jiti": "bin/jiti.js" @@ -25860,6 +25851,8 @@ }, "node_modules/js-levenshtein": { "version": "1.1.6", + "resolved": "https://registry.npmjs.org/js-levenshtein/-/js-levenshtein-1.1.6.tgz", + "integrity": "sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g==", "dev": true, "license": "MIT", "engines": { @@ -26713,6 +26706,7 @@ }, "node_modules/loupe": { "version": "3.1.3", + "dev": true, "license": "MIT" }, "node_modules/lowercase-keys": { @@ -26752,6 +26746,7 @@ }, "node_modules/magicast": { "version": "0.3.5", + "dev": true, "license": "MIT", "dependencies": { "@babel/parser": "^7.25.4", @@ -28019,43 +28014,43 @@ } }, "node_modules/msw": { - "version": "1.3.5", + "version": "2.10.4", + "resolved": "https://registry.npmjs.org/msw/-/msw-2.10.4.tgz", + "integrity": "sha512-6R1or/qyele7q3RyPwNuvc0IxO8L8/Aim6Sz5ncXEgcWUNxSKE+udriTOWHtpMwmfkLYlacA2y7TIx4cL5lgHA==", "dev": true, "hasInstallScript": true, "license": "MIT", "dependencies": { - "@mswjs/cookies": "^0.2.2", - "@mswjs/interceptors": "^0.17.10", - "@open-draft/until": "^1.0.3", - "@types/cookie": "^0.4.1", - "@types/js-levenshtein": "^1.1.1", - "chalk": "^4.1.1", - "chokidar": "^3.4.2", - "cookie": "^0.4.2", + "@bundled-es-modules/cookie": "^2.0.1", + "@bundled-es-modules/statuses": "^1.0.1", + "@bundled-es-modules/tough-cookie": "^0.1.6", + "@inquirer/confirm": "^5.0.0", + "@mswjs/interceptors": "^0.39.1", + "@open-draft/deferred-promise": "^2.2.0", + "@open-draft/until": "^2.1.0", + "@types/cookie": "^0.6.0", + "@types/statuses": "^2.0.4", "graphql": "^16.8.1", - "headers-polyfill": "3.2.5", - "inquirer": "^8.2.0", + "headers-polyfill": "^4.0.2", "is-node-process": "^1.2.0", - "js-levenshtein": "^1.1.6", - "node-fetch": "^2.6.7", - "outvariant": "^1.4.0", + "outvariant": "^1.4.3", "path-to-regexp": "^6.3.0", - "strict-event-emitter": "^0.4.3", - "type-fest": "^2.19.0", - "yargs": "^17.3.1" + "picocolors": "^1.1.1", + "strict-event-emitter": "^0.5.1", + "type-fest": "^4.26.1", + "yargs": "^17.7.2" }, "bin": { "msw": "cli/index.js" }, "engines": { - "node": ">=14" + "node": ">=18" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/mswjs" + "url": "https://github.com/sponsors/mswjs" }, "peerDependencies": { - "typescript": ">= 4.4.x" + "typescript": ">= 4.8.x" }, "peerDependenciesMeta": { "typescript": { @@ -28063,32 +28058,21 @@ } } }, - "node_modules/msw/node_modules/chalk": { - "version": "4.1.1", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/msw/node_modules/strict-event-emitter": { - "version": "0.4.6", + "node_modules/msw/node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", "dev": true, - "license": "MIT" + "license": "ISC" }, "node_modules/msw/node_modules/type-fest": { - "version": "2.19.0", + "version": "4.41.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz", + "integrity": "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==", "dev": true, "license": "(MIT OR CC0-1.0)", "engines": { - "node": ">=12.20" + "node": ">=16" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -28765,7 +28749,7 @@ }, "node_modules/outvariant": { "version": "1.4.3", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/own-keys": { @@ -28997,7 +28981,7 @@ }, "node_modules/path-to-regexp": { "version": "6.3.0", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/path-type": { @@ -29008,12 +28992,15 @@ } }, "node_modules/pathe": { - "version": "2.0.3", - "license": "MIT", - "peer": true + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.1.2.tgz", + "integrity": "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==", + "dev": true, + "license": "MIT" }, "node_modules/pathval": { "version": "2.0.0", + "dev": true, "license": "MIT", "engines": { "node": ">= 14.16" @@ -32012,6 +31999,12 @@ "node": ">=16" } }, + "node_modules/rrweb-cssom": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.7.1.tgz", + "integrity": "sha512-TrEMa7JGdVm0UThDJSx7ddw5nVm3UJS9o9CCIZ72B1vSyEZoziDqBYP3XIoi/12lKrJR8rE3jeFHMok2F/Mnsg==", + "license": "MIT" + }, "node_modules/run-async": { "version": "2.4.1", "license": "MIT", @@ -32253,7 +32246,9 @@ } }, "node_modules/set-cookie-parser": { - "version": "2.5.1", + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.1.tgz", + "integrity": "sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==", "dev": true, "license": "MIT" }, @@ -32508,6 +32503,7 @@ }, "node_modules/siginfo": { "version": "2.0.0", + "dev": true, "license": "ISC" }, "node_modules/signal-exit": { @@ -32920,6 +32916,7 @@ }, "node_modules/stackback": { "version": "0.0.2", + "dev": true, "license": "MIT" }, "node_modules/static-extend": { @@ -32956,7 +32953,7 @@ }, "node_modules/statuses": { "version": "2.0.1", - "devOptional": true, + "dev": true, "license": "MIT", "engines": { "node": ">= 0.8" @@ -32964,6 +32961,7 @@ }, "node_modules/std-env": { "version": "3.8.1", + "dev": true, "license": "MIT" }, "node_modules/stdin-discarder": { @@ -33040,12 +33038,11 @@ } }, "node_modules/strict-event-emitter": { - "version": "0.2.7", + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/strict-event-emitter/-/strict-event-emitter-0.5.1.tgz", + "integrity": "sha512-vMgjE/GGEPEFnhFub6pa4FmJBRBVOLpIII2hvCZ8Kzb7K0hlHo7mQv6xYrBvCL2LtAIBwFUK8wvuJgTVSQ5MFQ==", "dev": true, - "license": "MIT", - "dependencies": { - "events": "^3.3.0" - } + "license": "MIT" }, "node_modules/string_decoder": { "version": "1.3.0", @@ -34143,10 +34140,12 @@ }, "node_modules/tinybench": { "version": "2.9.0", + "dev": true, "license": "MIT" }, "node_modules/tinyexec": { "version": "0.3.2", + "dev": true, "license": "MIT" }, "node_modules/tinyglobby": { @@ -34187,13 +34186,17 @@ }, "node_modules/tinypool": { "version": "1.0.2", + "dev": true, "license": "MIT", "engines": { "node": "^18.0.0 || >=20.0.0" } }, "node_modules/tinyrainbow": { - "version": "2.0.0", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-1.2.0.tgz", + "integrity": "sha512-weEDEq7Z5eTHPDh4xjX789+fHfF+P8boiFB+0vbWzpbnbsEr/GRaohi/uMKxg8RZMXnl1ItAi/IUHWMsjDV7kQ==", + "dev": true, "license": "MIT", "engines": { "node": ">=14.0.0" @@ -34201,6 +34204,9 @@ }, "node_modules/tinyspy": { "version": "3.0.2", + "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-3.0.2.tgz", + "integrity": "sha512-n1cw8k1k0x4pgA2+9XrOkFydTerNcJ1zWCO5Nn9scWHTD+5tp8dghT2x1uduQePZTZgd3Tupf+x9BxJjeJi77Q==", + "dev": true, "license": "MIT", "engines": { "node": ">=14.0.0" @@ -34213,6 +34219,24 @@ "@popperjs/core": "^2.9.0" } }, + "node_modules/tldts": { + "version": "6.1.86", + "resolved": "https://registry.npmjs.org/tldts/-/tldts-6.1.86.tgz", + "integrity": "sha512-WMi/OQ2axVTf/ykqCQgXiIct+mSQDFdH2fkwhPwgEwvJ1kSzZRiinb0zF2Xb8u4+OqPChmyI6MEu4EezNJz+FQ==", + "license": "MIT", + "dependencies": { + "tldts-core": "^6.1.86" + }, + "bin": { + "tldts": "bin/cli.js" + } + }, + "node_modules/tldts-core": { + "version": "6.1.86", + "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-6.1.86.tgz", + "integrity": "sha512-Je6p7pkk+KMzMv2XXKmAE3McmolOQFdxkKw0R8EYNr7sELW46JqnNeTX8ybPiQgvg1ymCoF8LXs5fzFaZvJPTA==", + "license": "MIT" + }, "node_modules/tmp": { "version": "0.0.33", "license": "MIT", @@ -35763,6 +35787,20 @@ "react": "^16.8.0 || ^17.0.0 || ^18.0.0" } }, + "node_modules/util": { + "version": "0.12.5", + "resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz", + "integrity": "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "is-arguments": "^1.0.4", + "is-generator-function": "^1.0.7", + "is-typed-array": "^1.1.3", + "which-typed-array": "^1.1.2" + } + }, "node_modules/util-deprecate": { "version": "1.0.2", "license": "MIT" @@ -35910,6 +35948,7 @@ }, "node_modules/vite": { "version": "5.4.14", + "devOptional": true, "license": "MIT", "dependencies": { "esbuild": "^0.21.3", @@ -35966,255 +36005,28 @@ } }, "node_modules/vite-node": { - "version": "3.0.7", + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-2.1.9.tgz", + "integrity": "sha512-AM9aQ/IPrW/6ENLQg3AGY4K1N2TGZdR5e4gu/MmmR2xR3Ll1+dib+nook92g4TV3PXVyeyxdWwtaCAiUL0hMxA==", + "dev": true, "license": "MIT", - "peer": true, "dependencies": { "cac": "^6.7.14", - "debug": "^4.4.0", - "es-module-lexer": "^1.6.0", - "pathe": "^2.0.3", - "vite": "^5.0.0 || ^6.0.0" + "debug": "^4.3.7", + "es-module-lexer": "^1.5.4", + "pathe": "^1.1.2", + "vite": "^5.0.0" }, "bin": { "vite-node": "vite-node.mjs" }, "engines": { - "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + "node": "^18.0.0 || >=20.0.0" }, "funding": { "url": "https://opencollective.com/vitest" } }, - "node_modules/vite-node/node_modules/@esbuild/darwin-arm64": { - "version": "0.25.0", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "peer": true, - "engines": { - "node": ">=18" - } - }, - "node_modules/vite-node/node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.34.9", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "peer": true - }, - "node_modules/vite-node/node_modules/esbuild": { - "version": "0.25.0", - "hasInstallScript": true, - "license": "MIT", - "peer": true, - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=18" - }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.25.0", - "@esbuild/android-arm": "0.25.0", - "@esbuild/android-arm64": "0.25.0", - "@esbuild/android-x64": "0.25.0", - "@esbuild/darwin-arm64": "0.25.0", - "@esbuild/darwin-x64": "0.25.0", - "@esbuild/freebsd-arm64": "0.25.0", - "@esbuild/freebsd-x64": "0.25.0", - "@esbuild/linux-arm": "0.25.0", - "@esbuild/linux-arm64": "0.25.0", - "@esbuild/linux-ia32": "0.25.0", - "@esbuild/linux-loong64": "0.25.0", - "@esbuild/linux-mips64el": "0.25.0", - "@esbuild/linux-ppc64": "0.25.0", - "@esbuild/linux-riscv64": "0.25.0", - "@esbuild/linux-s390x": "0.25.0", - "@esbuild/linux-x64": "0.25.0", - "@esbuild/netbsd-arm64": "0.25.0", - "@esbuild/netbsd-x64": "0.25.0", - "@esbuild/openbsd-arm64": "0.25.0", - "@esbuild/openbsd-x64": "0.25.0", - "@esbuild/sunos-x64": "0.25.0", - "@esbuild/win32-arm64": "0.25.0", - "@esbuild/win32-ia32": "0.25.0", - "@esbuild/win32-x64": "0.25.0" - } - }, - "node_modules/vite-node/node_modules/fsevents": { - "version": "2.3.3", - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "peer": true, - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/vite-node/node_modules/picocolors": { - "version": "1.1.1", - "license": "ISC", - "peer": true - }, - "node_modules/vite-node/node_modules/postcss": { - "version": "8.5.3", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "peer": true, - "dependencies": { - "nanoid": "^3.3.8", - "picocolors": "^1.1.1", - "source-map-js": "^1.2.1" - }, - "engines": { - "node": "^10 || ^12 || >=14" - } - }, - "node_modules/vite-node/node_modules/rollup": { - "version": "4.34.9", - "license": "MIT", - "peer": true, - "dependencies": { - "@types/estree": "1.0.6" - }, - "bin": { - "rollup": "dist/bin/rollup" - }, - "engines": { - "node": ">=18.0.0", - "npm": ">=8.0.0" - }, - "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.34.9", - "@rollup/rollup-android-arm64": "4.34.9", - "@rollup/rollup-darwin-arm64": "4.34.9", - "@rollup/rollup-darwin-x64": "4.34.9", - "@rollup/rollup-freebsd-arm64": "4.34.9", - "@rollup/rollup-freebsd-x64": "4.34.9", - "@rollup/rollup-linux-arm-gnueabihf": "4.34.9", - "@rollup/rollup-linux-arm-musleabihf": "4.34.9", - "@rollup/rollup-linux-arm64-gnu": "4.34.9", - "@rollup/rollup-linux-arm64-musl": "4.34.9", - "@rollup/rollup-linux-loongarch64-gnu": "4.34.9", - "@rollup/rollup-linux-powerpc64le-gnu": "4.34.9", - "@rollup/rollup-linux-riscv64-gnu": "4.34.9", - "@rollup/rollup-linux-s390x-gnu": "4.34.9", - "@rollup/rollup-linux-x64-gnu": "4.34.9", - "@rollup/rollup-linux-x64-musl": "4.34.9", - "@rollup/rollup-win32-arm64-msvc": "4.34.9", - "@rollup/rollup-win32-ia32-msvc": "4.34.9", - "@rollup/rollup-win32-x64-msvc": "4.34.9", - "fsevents": "~2.3.2" - } - }, - "node_modules/vite-node/node_modules/vite": { - "version": "6.2.0", - "license": "MIT", - "peer": true, - "dependencies": { - "esbuild": "^0.25.0", - "postcss": "^8.5.3", - "rollup": "^4.30.1" - }, - "bin": { - "vite": "bin/vite.js" - }, - "engines": { - "node": "^18.0.0 || ^20.0.0 || >=22.0.0" - }, - "funding": { - "url": "https://github.com/vitejs/vite?sponsor=1" - }, - "optionalDependencies": { - "fsevents": "~2.3.3" - }, - "peerDependencies": { - "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", - "jiti": ">=1.21.0", - "less": "*", - "lightningcss": "^1.21.0", - "sass": "*", - "sass-embedded": "*", - "stylus": "*", - "sugarss": "*", - "terser": "^5.16.0", - "tsx": "^4.8.1", - "yaml": "^2.4.2" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - }, - "jiti": { - "optional": true - }, - "less": { - "optional": true - }, - "lightningcss": { - "optional": true - }, - "sass": { - "optional": true - }, - "sass-embedded": { - "optional": true - }, - "stylus": { - "optional": true - }, - "sugarss": { - "optional": true - }, - "terser": { - "optional": true - }, - "tsx": { - "optional": true - }, - "yaml": { - "optional": true - } - } - }, - "node_modules/vite-node/node_modules/yaml": { - "version": "2.7.0", - "license": "ISC", - "optional": true, - "peer": true, - "bin": { - "yaml": "bin.mjs" - }, - "engines": { - "node": ">= 14" - } - }, "node_modules/vite-tsconfig-paths": { "version": "5.1.4", "license": "MIT", @@ -36237,6 +36049,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -36246,19 +36059,273 @@ "node": ">=12" } }, + "node_modules/vite/node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.34.9", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.34.9.tgz", + "integrity": "sha512-qZdlImWXur0CFakn2BJ2znJOdqYZKiedEPEVNTBrpfPjc/YuTGcaYZcdmNFTkUj3DU0ZM/AElcM8Ybww3xVLzA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/vite/node_modules/@rollup/rollup-android-arm64": { + "version": "4.34.9", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.34.9.tgz", + "integrity": "sha512-4KW7P53h6HtJf5Y608T1ISKvNIYLWRKMvfnG0c44M6In4DQVU58HZFEVhWINDZKp7FZps98G3gxwC1sb0wXUUg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, "node_modules/vite/node_modules/@rollup/rollup-darwin-arm64": { "version": "4.34.9", "cpu": [ "arm64" ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/vite/node_modules/@rollup/rollup-darwin-x64": { + "version": "4.34.9", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.34.9.tgz", + "integrity": "sha512-eOojSEAi/acnsJVYRxnMkPFqcxSMFfrw7r2iD9Q32SGkb/Q9FpUY1UlAu1DH9T7j++gZ0lHjnm4OyH2vCI7l7Q==", + "cpu": [ + "x64" + ], + "dev": true, "license": "MIT", "optional": true, "os": [ "darwin" ] }, + "node_modules/vite/node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.34.9", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.34.9.tgz", + "integrity": "sha512-2lzjQPJbN5UnHm7bHIUKFMulGTQwdvOkouJDpPysJS+QFBGDJqcfh+CxxtG23Ik/9tEvnebQiylYoazFMAgrYw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/vite/node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.34.9", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.34.9.tgz", + "integrity": "sha512-SLl0hi2Ah2H7xQYd6Qaiu01kFPzQ+hqvdYSoOtHYg/zCIFs6t8sV95kaoqjzjFwuYQLtOI0RZre/Ke0nPaQV+g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/vite/node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.34.9", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.34.9.tgz", + "integrity": "sha512-88I+D3TeKItrw+Y/2ud4Tw0+3CxQ2kLgu3QvrogZ0OfkmX/DEppehus7L3TS2Q4lpB+hYyxhkQiYPJ6Mf5/dPg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/vite/node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.34.9", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.34.9.tgz", + "integrity": "sha512-3qyfWljSFHi9zH0KgtEPG4cBXHDFhwD8kwg6xLfHQ0IWuH9crp005GfoUUh/6w9/FWGBwEHg3lxK1iHRN1MFlA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/vite/node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.34.9", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.34.9.tgz", + "integrity": "sha512-6TZjPHjKZUQKmVKMUowF3ewHxctrRR09eYyvT5eFv8w/fXarEra83A2mHTVJLA5xU91aCNOUnM+DWFMSbQ0Nxw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/vite/node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.34.9", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.34.9.tgz", + "integrity": "sha512-LD2fytxZJZ6xzOKnMbIpgzFOuIKlxVOpiMAXawsAZ2mHBPEYOnLRK5TTEsID6z4eM23DuO88X0Tq1mErHMVq0A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/vite/node_modules/@rollup/rollup-linux-loongarch64-gnu": { + "version": "4.34.9", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.34.9.tgz", + "integrity": "sha512-dRAgTfDsn0TE0HI6cmo13hemKpVHOEyeciGtvlBTkpx/F65kTvShtY/EVyZEIfxFkV5JJTuQ9tP5HGBS0hfxIg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/vite/node_modules/@rollup/rollup-linux-powerpc64le-gnu": { + "version": "4.34.9", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.34.9.tgz", + "integrity": "sha512-PHcNOAEhkoMSQtMf+rJofwisZqaU8iQ8EaSps58f5HYll9EAY5BSErCZ8qBDMVbq88h4UxaNPlbrKqfWP8RfJA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/vite/node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.34.9", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.34.9.tgz", + "integrity": "sha512-Z2i0Uy5G96KBYKjeQFKbbsB54xFOL5/y1P5wNBsbXB8yE+At3oh0DVMjQVzCJRJSfReiB2tX8T6HUFZ2k8iaKg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/vite/node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.34.9", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.34.9.tgz", + "integrity": "sha512-U+5SwTMoeYXoDzJX5dhDTxRltSrIax8KWwfaaYcynuJw8mT33W7oOgz0a+AaXtGuvhzTr2tVKh5UO8GVANTxyQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/vite/node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.34.9", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.34.9.tgz", + "integrity": "sha512-FwBHNSOjUTQLP4MG7y6rR6qbGw4MFeQnIBrMe161QGaQoBQLqSUEKlHIiVgF3g/mb3lxlxzJOpIBhaP+C+KP2A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/vite/node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.34.9", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.34.9.tgz", + "integrity": "sha512-cYRpV4650z2I3/s6+5/LONkjIz8MBeqrk+vPXV10ORBnshpn8S32bPqQ2Utv39jCiDcO2eJTuSlPXpnvmaIgRA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/vite/node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.34.9", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.34.9.tgz", + "integrity": "sha512-z4mQK9dAN6byRA/vsSgQiPeuO63wdiDxZ9yg9iyX2QTzKuQM7T4xlBoeUP/J8uiFkqxkcWndWi+W7bXdPbt27Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/vite/node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.34.9", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.34.9.tgz", + "integrity": "sha512-KB48mPtaoHy1AwDNkAJfHXvHp24H0ryZog28spEs0V48l3H1fr4i37tiyHsgKZJnCmvxsbATdZGBpbmxTE3a9w==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/vite/node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.34.9", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.34.9.tgz", + "integrity": "sha512-AyleYRPU7+rgkMWbEh71fQlrzRfeP6SyMnRf9XX4fCdDPAJumdSBqYEcWPMzVQ4ScAl7E4oFfK0GUVn77xSwbw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, "node_modules/vite/node_modules/esbuild": { "version": "0.21.5", + "devOptional": true, "hasInstallScript": true, "license": "MIT", "bin": { @@ -36295,6 +36362,7 @@ }, "node_modules/vite/node_modules/fsevents": { "version": "2.3.3", + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -36306,10 +36374,12 @@ }, "node_modules/vite/node_modules/picocolors": { "version": "1.1.1", + "devOptional": true, "license": "ISC" }, "node_modules/vite/node_modules/postcss": { "version": "8.5.3", + "devOptional": true, "funding": [ { "type": "opencollective", @@ -36336,6 +36406,7 @@ }, "node_modules/vite/node_modules/rollup": { "version": "4.34.9", + "devOptional": true, "license": "MIT", "dependencies": { "@types/estree": "1.0.6" @@ -36371,46 +36442,47 @@ } }, "node_modules/vitest": { - "version": "3.0.7", + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-2.1.9.tgz", + "integrity": "sha512-MSmPM9REYqDGBI8439mA4mWhV5sKmDlBKWIYbA3lRb2PTHACE0mgKwA8yQ2xq9vxDTuk4iPrECBAEW2aoFXY0Q==", + "dev": true, "license": "MIT", - "peer": true, "dependencies": { - "@vitest/expect": "3.0.7", - "@vitest/mocker": "3.0.7", - "@vitest/pretty-format": "^3.0.7", - "@vitest/runner": "3.0.7", - "@vitest/snapshot": "3.0.7", - "@vitest/spy": "3.0.7", - "@vitest/utils": "3.0.7", - "chai": "^5.2.0", - "debug": "^4.4.0", + "@vitest/expect": "2.1.9", + "@vitest/mocker": "2.1.9", + "@vitest/pretty-format": "^2.1.9", + "@vitest/runner": "2.1.9", + "@vitest/snapshot": "2.1.9", + "@vitest/spy": "2.1.9", + "@vitest/utils": "2.1.9", + "chai": "^5.1.2", + "debug": "^4.3.7", "expect-type": "^1.1.0", - "magic-string": "^0.30.17", - "pathe": "^2.0.3", + "magic-string": "^0.30.12", + "pathe": "^1.1.2", "std-env": "^3.8.0", "tinybench": "^2.9.0", - "tinyexec": "^0.3.2", - "tinypool": "^1.0.2", - "tinyrainbow": "^2.0.0", - "vite": "^5.0.0 || ^6.0.0", - "vite-node": "3.0.7", + "tinyexec": "^0.3.1", + "tinypool": "^1.0.1", + "tinyrainbow": "^1.2.0", + "vite": "^5.0.0", + "vite-node": "2.1.9", "why-is-node-running": "^2.3.0" }, "bin": { "vitest": "vitest.mjs" }, "engines": { - "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + "node": "^18.0.0 || >=20.0.0" }, "funding": { "url": "https://opencollective.com/vitest" }, "peerDependencies": { "@edge-runtime/vm": "*", - "@types/debug": "^4.1.12", - "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", - "@vitest/browser": "3.0.7", - "@vitest/ui": "3.0.7", + "@types/node": "^18.0.0 || >=20.0.0", + "@vitest/browser": "2.1.9", + "@vitest/ui": "2.1.9", "happy-dom": "*", "jsdom": "*" }, @@ -36418,9 +36490,6 @@ "@edge-runtime/vm": { "optional": true }, - "@types/debug": { - "optional": true - }, "@types/node": { "optional": true }, @@ -36448,77 +36517,23 @@ "tsconfig-paths": "^3.9.0" } }, - "node_modules/vitest/node_modules/@esbuild/darwin-arm64": { - "version": "0.25.0", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "peer": true, - "engines": { - "node": ">=18" - } - }, - "node_modules/vitest/node_modules/@mswjs/interceptors": { - "version": "0.37.6", - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "@open-draft/deferred-promise": "^2.2.0", - "@open-draft/logger": "^0.3.0", - "@open-draft/until": "^2.0.0", - "is-node-process": "^1.2.0", - "outvariant": "^1.4.3", - "strict-event-emitter": "^0.5.1" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/vitest/node_modules/@open-draft/until": { - "version": "2.1.0", - "license": "MIT", - "optional": true, - "peer": true - }, - "node_modules/vitest/node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.34.9", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "peer": true - }, - "node_modules/vitest/node_modules/@types/cookie": { - "version": "0.6.0", - "license": "MIT", - "optional": true, - "peer": true - }, "node_modules/vitest/node_modules/@vitest/mocker": { - "version": "3.0.7", + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-2.1.9.tgz", + "integrity": "sha512-tVL6uJgoUdi6icpxmdrn5YNo3g3Dxv+IHJBr0GXHaEdTcw3F+cPKnsXFhli6nO+f/6SDKPHEK1UN+k+TQv0Ehg==", + "dev": true, "license": "MIT", - "peer": true, "dependencies": { - "@vitest/spy": "3.0.7", + "@vitest/spy": "2.1.9", "estree-walker": "^3.0.3", - "magic-string": "^0.30.17" + "magic-string": "^0.30.12" }, "funding": { "url": "https://opencollective.com/vitest" }, "peerDependencies": { "msw": "^2.4.9", - "vite": "^5.0.0 || ^6.0.0" + "vite": "^5.0.0" }, "peerDependenciesMeta": { "msw": { @@ -36529,284 +36544,16 @@ } } }, - "node_modules/vitest/node_modules/esbuild": { - "version": "0.25.0", - "hasInstallScript": true, - "license": "MIT", - "peer": true, - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=18" - }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.25.0", - "@esbuild/android-arm": "0.25.0", - "@esbuild/android-arm64": "0.25.0", - "@esbuild/android-x64": "0.25.0", - "@esbuild/darwin-arm64": "0.25.0", - "@esbuild/darwin-x64": "0.25.0", - "@esbuild/freebsd-arm64": "0.25.0", - "@esbuild/freebsd-x64": "0.25.0", - "@esbuild/linux-arm": "0.25.0", - "@esbuild/linux-arm64": "0.25.0", - "@esbuild/linux-ia32": "0.25.0", - "@esbuild/linux-loong64": "0.25.0", - "@esbuild/linux-mips64el": "0.25.0", - "@esbuild/linux-ppc64": "0.25.0", - "@esbuild/linux-riscv64": "0.25.0", - "@esbuild/linux-s390x": "0.25.0", - "@esbuild/linux-x64": "0.25.0", - "@esbuild/netbsd-arm64": "0.25.0", - "@esbuild/netbsd-x64": "0.25.0", - "@esbuild/openbsd-arm64": "0.25.0", - "@esbuild/openbsd-x64": "0.25.0", - "@esbuild/sunos-x64": "0.25.0", - "@esbuild/win32-arm64": "0.25.0", - "@esbuild/win32-ia32": "0.25.0", - "@esbuild/win32-x64": "0.25.0" - } - }, "node_modules/vitest/node_modules/estree-walker": { "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@types/estree": "^1.0.0" } }, - "node_modules/vitest/node_modules/fsevents": { - "version": "2.3.3", - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "peer": true, - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/vitest/node_modules/headers-polyfill": { - "version": "4.0.3", - "license": "MIT", - "optional": true, - "peer": true - }, - "node_modules/vitest/node_modules/msw": { - "version": "2.7.3", - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "@bundled-es-modules/cookie": "^2.0.1", - "@bundled-es-modules/statuses": "^1.0.1", - "@bundled-es-modules/tough-cookie": "^0.1.6", - "@inquirer/confirm": "^5.0.0", - "@mswjs/interceptors": "^0.37.0", - "@open-draft/deferred-promise": "^2.2.0", - "@open-draft/until": "^2.1.0", - "@types/cookie": "^0.6.0", - "@types/statuses": "^2.0.4", - "graphql": "^16.8.1", - "headers-polyfill": "^4.0.2", - "is-node-process": "^1.2.0", - "outvariant": "^1.4.3", - "path-to-regexp": "^6.3.0", - "picocolors": "^1.1.1", - "strict-event-emitter": "^0.5.1", - "type-fest": "^4.26.1", - "yargs": "^17.7.2" - }, - "bin": { - "msw": "cli/index.js" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/mswjs" - }, - "peerDependencies": { - "typescript": ">= 4.8.x" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/vitest/node_modules/picocolors": { - "version": "1.1.1", - "license": "ISC", - "peer": true - }, - "node_modules/vitest/node_modules/postcss": { - "version": "8.5.3", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "peer": true, - "dependencies": { - "nanoid": "^3.3.8", - "picocolors": "^1.1.1", - "source-map-js": "^1.2.1" - }, - "engines": { - "node": "^10 || ^12 || >=14" - } - }, - "node_modules/vitest/node_modules/rollup": { - "version": "4.34.9", - "license": "MIT", - "peer": true, - "dependencies": { - "@types/estree": "1.0.6" - }, - "bin": { - "rollup": "dist/bin/rollup" - }, - "engines": { - "node": ">=18.0.0", - "npm": ">=8.0.0" - }, - "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.34.9", - "@rollup/rollup-android-arm64": "4.34.9", - "@rollup/rollup-darwin-arm64": "4.34.9", - "@rollup/rollup-darwin-x64": "4.34.9", - "@rollup/rollup-freebsd-arm64": "4.34.9", - "@rollup/rollup-freebsd-x64": "4.34.9", - "@rollup/rollup-linux-arm-gnueabihf": "4.34.9", - "@rollup/rollup-linux-arm-musleabihf": "4.34.9", - "@rollup/rollup-linux-arm64-gnu": "4.34.9", - "@rollup/rollup-linux-arm64-musl": "4.34.9", - "@rollup/rollup-linux-loongarch64-gnu": "4.34.9", - "@rollup/rollup-linux-powerpc64le-gnu": "4.34.9", - "@rollup/rollup-linux-riscv64-gnu": "4.34.9", - "@rollup/rollup-linux-s390x-gnu": "4.34.9", - "@rollup/rollup-linux-x64-gnu": "4.34.9", - "@rollup/rollup-linux-x64-musl": "4.34.9", - "@rollup/rollup-win32-arm64-msvc": "4.34.9", - "@rollup/rollup-win32-ia32-msvc": "4.34.9", - "@rollup/rollup-win32-x64-msvc": "4.34.9", - "fsevents": "~2.3.2" - } - }, - "node_modules/vitest/node_modules/strict-event-emitter": { - "version": "0.5.1", - "license": "MIT", - "optional": true, - "peer": true - }, - "node_modules/vitest/node_modules/type-fest": { - "version": "4.37.0", - "license": "(MIT OR CC0-1.0)", - "optional": true, - "peer": true, - "engines": { - "node": ">=16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/vitest/node_modules/vite": { - "version": "6.2.0", - "license": "MIT", - "peer": true, - "dependencies": { - "esbuild": "^0.25.0", - "postcss": "^8.5.3", - "rollup": "^4.30.1" - }, - "bin": { - "vite": "bin/vite.js" - }, - "engines": { - "node": "^18.0.0 || ^20.0.0 || >=22.0.0" - }, - "funding": { - "url": "https://github.com/vitejs/vite?sponsor=1" - }, - "optionalDependencies": { - "fsevents": "~2.3.3" - }, - "peerDependencies": { - "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", - "jiti": ">=1.21.0", - "less": "*", - "lightningcss": "^1.21.0", - "sass": "*", - "sass-embedded": "*", - "stylus": "*", - "sugarss": "*", - "terser": "^5.16.0", - "tsx": "^4.8.1", - "yaml": "^2.4.2" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - }, - "jiti": { - "optional": true - }, - "less": { - "optional": true - }, - "lightningcss": { - "optional": true - }, - "sass": { - "optional": true - }, - "sass-embedded": { - "optional": true - }, - "stylus": { - "optional": true - }, - "sugarss": { - "optional": true - }, - "terser": { - "optional": true - }, - "tsx": { - "optional": true - }, - "yaml": { - "optional": true - } - } - }, - "node_modules/vitest/node_modules/yaml": { - "version": "2.7.0", - "license": "ISC", - "optional": true, - "peer": true, - "bin": { - "yaml": "bin.mjs" - }, - "engines": { - "node": ">= 14" - } - }, "node_modules/vue": { "version": "3.3.4", "license": "MIT", @@ -36864,6 +36611,8 @@ }, "node_modules/web-encoding": { "version": "1.1.5", + "resolved": "https://registry.npmjs.org/web-encoding/-/web-encoding-1.1.5.tgz", + "integrity": "sha512-HYLeVCdJ0+lBYV2FvNZmv3HJ2Nt0QYXqZojk3d9FJOLkwnuhzM9tmamh8d7HPM8QqjKH8DeHkFTx+CFlWpZZDA==", "dev": true, "license": "MIT", "dependencies": { @@ -36873,19 +36622,6 @@ "@zxing/text-encoding": "0.9.0" } }, - "node_modules/web-encoding/node_modules/util": { - "version": "0.12.4", - "dev": true, - "license": "MIT", - "dependencies": { - "inherits": "^2.0.3", - "is-arguments": "^1.0.4", - "is-generator-function": "^1.0.7", - "is-typed-array": "^1.1.3", - "safe-buffer": "^5.1.2", - "which-typed-array": "^1.1.2" - } - }, "node_modules/web-namespaces": { "version": "2.0.1", "license": "MIT", @@ -37044,6 +36780,7 @@ }, "node_modules/why-is-node-running": { "version": "2.3.0", + "dev": true, "license": "MIT", "dependencies": { "siginfo": "^2.0.0", @@ -37270,7 +37007,7 @@ }, "node_modules/yoctocolors-cjs": { "version": "2.1.2", - "devOptional": true, + "dev": true, "license": "MIT", "engines": { "node": ">=18" @@ -37343,7 +37080,7 @@ }, "devDependencies": { "@liveblocks/eslint-config": "*", - "@liveblocks/jest-config": "*" + "@liveblocks/vitest-config": "*" } }, "packages/liveblocks-core": { @@ -37352,12 +37089,12 @@ "license": "Apache-2.0", "devDependencies": { "@liveblocks/eslint-config": "*", - "@liveblocks/jest-config": "*", "@liveblocks/query-parser": "^0.1.1", + "@liveblocks/vitest-config": "*", "@types/ws": "^8.5.10", "dotenv": "^16.4.5", "eslint-plugin-rulesdir": "^0.2.2", - "msw": "^1.3.5", + "msw": "^2.10.4", "ws": "^8.17.1" }, "peerDependencies": { @@ -37374,114 +37111,19 @@ }, "devDependencies": { "@liveblocks/eslint-config": "*", - "@liveblocks/jest-config": "*", + "@liveblocks/vitest-config": "*", "csstype": "3.0.2", - "msw": "^2.7.0" + "msw": "^2.10.4" }, "peerDependencies": { "react": "^18 || ^19 || ^19.0.0-rc" } }, - "packages/liveblocks-emails/node_modules/@mswjs/interceptors": { - "version": "0.37.5", - "dev": true, - "license": "MIT", - "dependencies": { - "@open-draft/deferred-promise": "^2.2.0", - "@open-draft/logger": "^0.3.0", - "@open-draft/until": "^2.0.0", - "is-node-process": "^1.2.0", - "outvariant": "^1.4.3", - "strict-event-emitter": "^0.5.1" - }, - "engines": { - "node": ">=18" - } - }, - "packages/liveblocks-emails/node_modules/@open-draft/until": { - "version": "2.1.0", - "dev": true, - "license": "MIT" - }, - "packages/liveblocks-emails/node_modules/@types/cookie": { - "version": "0.6.0", - "dev": true, - "license": "MIT" - }, "packages/liveblocks-emails/node_modules/csstype": { "version": "3.0.2", "dev": true, "license": "MIT" }, - "packages/liveblocks-emails/node_modules/headers-polyfill": { - "version": "4.0.3", - "dev": true, - "license": "MIT" - }, - "packages/liveblocks-emails/node_modules/msw": { - "version": "2.7.0", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "dependencies": { - "@bundled-es-modules/cookie": "^2.0.1", - "@bundled-es-modules/statuses": "^1.0.1", - "@bundled-es-modules/tough-cookie": "^0.1.6", - "@inquirer/confirm": "^5.0.0", - "@mswjs/interceptors": "^0.37.0", - "@open-draft/deferred-promise": "^2.2.0", - "@open-draft/until": "^2.1.0", - "@types/cookie": "^0.6.0", - "@types/statuses": "^2.0.4", - "graphql": "^16.8.1", - "headers-polyfill": "^4.0.2", - "is-node-process": "^1.2.0", - "outvariant": "^1.4.3", - "path-to-regexp": "^6.3.0", - "picocolors": "^1.1.1", - "strict-event-emitter": "^0.5.1", - "type-fest": "^4.26.1", - "yargs": "^17.7.2" - }, - "bin": { - "msw": "cli/index.js" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/mswjs" - }, - "peerDependencies": { - "typescript": ">= 4.8.x" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "packages/liveblocks-emails/node_modules/picocolors": { - "version": "1.1.1", - "dev": true, - "license": "ISC" - }, - "packages/liveblocks-emails/node_modules/strict-event-emitter": { - "version": "0.5.1", - "dev": true, - "license": "MIT" - }, - "packages/liveblocks-emails/node_modules/type-fest": { - "version": "4.26.1", - "dev": true, - "license": "(MIT OR CC0-1.0)", - "engines": { - "node": ">=16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "packages/liveblocks-node": { "name": "@liveblocks/node", "version": "3.3.3", @@ -37494,9 +37136,9 @@ }, "devDependencies": { "@liveblocks/eslint-config": "*", - "@liveblocks/jest-config": "*", + "@liveblocks/vitest-config": "*", "@types/node-fetch": "^2.6.6", - "msw": "^2.7.0", + "msw": "^2.10.4", "svix": "^0.75.0" } }, @@ -37511,7 +37153,7 @@ }, "devDependencies": { "@liveblocks/eslint-config": "*", - "@liveblocks/jest-config": "*" + "@liveblocks/vitest-config": "*" }, "peerDependencies": { "@lexical/headless": "0.24.0", @@ -37532,8 +37174,8 @@ }, "devDependencies": { "@liveblocks/eslint-config": "*", - "@liveblocks/jest-config": "*", - "msw": "^2.7.0" + "@liveblocks/vitest-config": "*", + "msw": "^2.10.4" }, "peerDependencies": { "@tiptap/core": "^2.9.1", @@ -37545,196 +37187,6 @@ "yjs": "^13.6.20" } }, - "packages/liveblocks-node-prosemirror/node_modules/@mswjs/interceptors": { - "version": "0.37.5", - "dev": true, - "license": "MIT", - "dependencies": { - "@open-draft/deferred-promise": "^2.2.0", - "@open-draft/logger": "^0.3.0", - "@open-draft/until": "^2.0.0", - "is-node-process": "^1.2.0", - "outvariant": "^1.4.3", - "strict-event-emitter": "^0.5.1" - }, - "engines": { - "node": ">=18" - } - }, - "packages/liveblocks-node-prosemirror/node_modules/@open-draft/until": { - "version": "2.1.0", - "dev": true, - "license": "MIT" - }, - "packages/liveblocks-node-prosemirror/node_modules/@types/cookie": { - "version": "0.6.0", - "dev": true, - "license": "MIT" - }, - "packages/liveblocks-node-prosemirror/node_modules/headers-polyfill": { - "version": "4.0.3", - "dev": true, - "license": "MIT" - }, - "packages/liveblocks-node-prosemirror/node_modules/msw": { - "version": "2.7.0", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "dependencies": { - "@bundled-es-modules/cookie": "^2.0.1", - "@bundled-es-modules/statuses": "^1.0.1", - "@bundled-es-modules/tough-cookie": "^0.1.6", - "@inquirer/confirm": "^5.0.0", - "@mswjs/interceptors": "^0.37.0", - "@open-draft/deferred-promise": "^2.2.0", - "@open-draft/until": "^2.1.0", - "@types/cookie": "^0.6.0", - "@types/statuses": "^2.0.4", - "graphql": "^16.8.1", - "headers-polyfill": "^4.0.2", - "is-node-process": "^1.2.0", - "outvariant": "^1.4.3", - "path-to-regexp": "^6.3.0", - "picocolors": "^1.1.1", - "strict-event-emitter": "^0.5.1", - "type-fest": "^4.26.1", - "yargs": "^17.7.2" - }, - "bin": { - "msw": "cli/index.js" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/mswjs" - }, - "peerDependencies": { - "typescript": ">= 4.8.x" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "packages/liveblocks-node-prosemirror/node_modules/picocolors": { - "version": "1.1.1", - "dev": true, - "license": "ISC" - }, - "packages/liveblocks-node-prosemirror/node_modules/strict-event-emitter": { - "version": "0.5.1", - "dev": true, - "license": "MIT" - }, - "packages/liveblocks-node-prosemirror/node_modules/type-fest": { - "version": "4.26.1", - "dev": true, - "license": "(MIT OR CC0-1.0)", - "engines": { - "node": ">=16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "packages/liveblocks-node/node_modules/@mswjs/interceptors": { - "version": "0.37.5", - "dev": true, - "license": "MIT", - "dependencies": { - "@open-draft/deferred-promise": "^2.2.0", - "@open-draft/logger": "^0.3.0", - "@open-draft/until": "^2.0.0", - "is-node-process": "^1.2.0", - "outvariant": "^1.4.3", - "strict-event-emitter": "^0.5.1" - }, - "engines": { - "node": ">=18" - } - }, - "packages/liveblocks-node/node_modules/@open-draft/until": { - "version": "2.1.0", - "dev": true, - "license": "MIT" - }, - "packages/liveblocks-node/node_modules/@types/cookie": { - "version": "0.6.0", - "dev": true, - "license": "MIT" - }, - "packages/liveblocks-node/node_modules/headers-polyfill": { - "version": "4.0.2", - "dev": true, - "license": "MIT" - }, - "packages/liveblocks-node/node_modules/msw": { - "version": "2.7.0", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "dependencies": { - "@bundled-es-modules/cookie": "^2.0.1", - "@bundled-es-modules/statuses": "^1.0.1", - "@bundled-es-modules/tough-cookie": "^0.1.6", - "@inquirer/confirm": "^5.0.0", - "@mswjs/interceptors": "^0.37.0", - "@open-draft/deferred-promise": "^2.2.0", - "@open-draft/until": "^2.1.0", - "@types/cookie": "^0.6.0", - "@types/statuses": "^2.0.4", - "graphql": "^16.8.1", - "headers-polyfill": "^4.0.2", - "is-node-process": "^1.2.0", - "outvariant": "^1.4.3", - "path-to-regexp": "^6.3.0", - "picocolors": "^1.1.1", - "strict-event-emitter": "^0.5.1", - "type-fest": "^4.26.1", - "yargs": "^17.7.2" - }, - "bin": { - "msw": "cli/index.js" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/mswjs" - }, - "peerDependencies": { - "typescript": ">= 4.8.x" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "packages/liveblocks-node/node_modules/picocolors": { - "version": "1.1.1", - "dev": true, - "license": "ISC" - }, - "packages/liveblocks-node/node_modules/strict-event-emitter": { - "version": "0.5.1", - "dev": true, - "license": "MIT" - }, - "packages/liveblocks-node/node_modules/type-fest": { - "version": "4.31.0", - "dev": true, - "license": "(MIT OR CC0-1.0)", - "engines": { - "node": ">=16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "packages/liveblocks-react": { "name": "@liveblocks/react", "version": "3.3.3", @@ -37785,12 +37237,12 @@ }, "devDependencies": { "@liveblocks/eslint-config": "*", - "@liveblocks/jest-config": "*", "@liveblocks/rollup-config": "*", + "@liveblocks/vitest-config": "*", "@testing-library/jest-dom": "^5.16.5", "eslint-plugin-react": "^7.33.2", "eslint-plugin-react-hooks": "^4.6.0", - "msw": "^1.3.5", + "msw": "^2.10.4", "stylelint": "^15.10.2", "stylelint-config-standard": "^34.0.0", "stylelint-order": "^6.0.3", @@ -37831,12 +37283,12 @@ }, "devDependencies": { "@liveblocks/eslint-config": "*", - "@liveblocks/jest-config": "*", "@liveblocks/rollup-config": "*", + "@liveblocks/vitest-config": "*", "@testing-library/jest-dom": "^5.16.5", "eslint-plugin-react": "^7.33.2", "eslint-plugin-react-hooks": "^4.6.0", - "msw": "^1.3.5", + "msw": "^2.10.4", "stylelint": "^15.10.2", "stylelint-config-standard": "^34.0.0", "stylelint-order": "^6.0.3", @@ -38373,12 +37825,12 @@ }, "devDependencies": { "@liveblocks/eslint-config": "*", - "@liveblocks/jest-config": "*", "@liveblocks/rollup-config": "*", + "@liveblocks/vitest-config": "*", "@testing-library/jest-dom": "^5.16.5", "eslint-plugin-react": "^7.33.2", "eslint-plugin-react-hooks": "^4.6.0", - "msw": "^1.3.5", + "msw": "^2.10.4", "stylelint": "^15.10.2", "stylelint-config-standard": "^34.0.0", "stylelint-order": "^6.0.3", @@ -38907,13 +38359,13 @@ }, "devDependencies": { "@liveblocks/eslint-config": "*", - "@liveblocks/jest-config": "*", "@liveblocks/rollup-config": "*", - "@testing-library/jest-dom": "^5.16.5", + "@liveblocks/vitest-config": "*", + "@testing-library/jest-dom": "^6.4.6", "@testing-library/react": "^13.1.1", "eslint-plugin-react": "^7.33.2", "eslint-plugin-react-hooks": "^4.6.0", - "msw": "^1.3.5", + "msw": "^2.10.4", "stylelint": "^15.10.2", "stylelint-config-standard": "^34.0.0", "stylelint-order": "^6.0.3", @@ -39886,6 +39338,34 @@ "version": "1.1.0", "license": "MIT" }, + "packages/liveblocks-react-ui/node_modules/@testing-library/jest-dom": { + "version": "6.6.4", + "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-6.6.4.tgz", + "integrity": "sha512-xDXgLjVunjHqczScfkCJ9iyjdNOVHvvCdqHSSxwM9L0l/wHkTRum67SDc020uAlCoqktJplgO2AAQeLP1wgqDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@adobe/css-tools": "^4.4.0", + "aria-query": "^5.0.0", + "css.escape": "^1.5.1", + "dom-accessibility-api": "^0.6.3", + "lodash": "^4.17.21", + "picocolors": "^1.1.1", + "redent": "^3.0.0" + }, + "engines": { + "node": ">=14", + "npm": ">=6", + "yarn": ">=1" + } + }, + "packages/liveblocks-react-ui/node_modules/dom-accessibility-api": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.6.3.tgz", + "integrity": "sha512-7ZgogeTnjuHbo+ct10G9Ffp0mif17idi0IyWNVA/wcwcm7NPOD/WEHVP3n7n3MhXqxoIYm8d6MuZohYWIZ4T3w==", + "dev": true, + "license": "MIT" + }, "packages/liveblocks-react-ui/node_modules/marked": { "version": "15.0.11", "resolved": "https://registry.npmjs.org/marked/-/marked-15.0.11.tgz", @@ -39898,6 +39378,13 @@ "node": ">= 18" } }, + "packages/liveblocks-react-ui/node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, "packages/liveblocks-react-ui/node_modules/react-remove-scroll": { "version": "2.6.0", "license": "MIT", @@ -39925,6 +39412,43 @@ "version": "2.8.0", "license": "0BSD" }, + "packages/liveblocks-react/node_modules/@mswjs/interceptors": { + "version": "0.17.10", + "resolved": "https://registry.npmjs.org/@mswjs/interceptors/-/interceptors-0.17.10.tgz", + "integrity": "sha512-N8x7eSLGcmUFNWZRxT1vsHvypzIRgQYdG0rJey/rZCy6zT/30qDt8Joj7FxzGNLSwXbeZqJOMqDurp7ra4hgbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@open-draft/until": "^1.0.3", + "@types/debug": "^4.1.7", + "@xmldom/xmldom": "^0.8.3", + "debug": "^4.3.3", + "headers-polyfill": "3.2.5", + "outvariant": "^1.2.1", + "strict-event-emitter": "^0.2.4", + "web-encoding": "^1.1.5" + }, + "engines": { + "node": ">=14" + } + }, + "packages/liveblocks-react/node_modules/@mswjs/interceptors/node_modules/strict-event-emitter": { + "version": "0.2.8", + "resolved": "https://registry.npmjs.org/strict-event-emitter/-/strict-event-emitter-0.2.8.tgz", + "integrity": "sha512-KDf/ujU8Zud3YaLtMCcTI4xkZlZVIYxTLr+XIULexP+77EEVWixeXroLUXQXiVtH4XH2W7jr/3PT1v3zBuvc3A==", + "dev": true, + "license": "MIT", + "dependencies": { + "events": "^3.3.0" + } + }, + "packages/liveblocks-react/node_modules/@open-draft/until": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@open-draft/until/-/until-1.0.3.tgz", + "integrity": "sha512-Aq58f5HiWdyDlFffbbSjAlv596h/cOnt2DO1w3DOC7OJ5EHs0hd/nycJfiu9RJbT6Yk6F1knnRRXNSpxoIVZ9Q==", + "dev": true, + "license": "MIT" + }, "packages/liveblocks-react/node_modules/@testing-library/dom": { "version": "9.3.4", "dev": true, @@ -40016,24 +39540,85 @@ "engines": { "node": ">=14" }, - "peerDependencies": { - "react": "^18.0.0", - "react-dom": "^18.0.0" - } - }, - "packages/liveblocks-react/node_modules/chalk": { - "version": "4.1.1", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "peerDependencies": { + "react": "^18.0.0", + "react-dom": "^18.0.0" + } + }, + "packages/liveblocks-react/node_modules/@types/cookie": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz", + "integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==", + "dev": true, + "license": "MIT" + }, + "packages/liveblocks-react/node_modules/chalk": { + "version": "4.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "packages/liveblocks-react/node_modules/headers-polyfill": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/headers-polyfill/-/headers-polyfill-3.2.5.tgz", + "integrity": "sha512-tUCGvt191vNSQgttSyJoibR+VO+I6+iCHIUdhzEMJKE+EAL8BwCN7fUOZlY4ofOelNHsK+gEjxB/B+9N3EWtdA==", + "dev": true, + "license": "MIT" + }, + "packages/liveblocks-react/node_modules/msw": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/msw/-/msw-1.3.5.tgz", + "integrity": "sha512-nG3fpmBXxFbKSIdk6miPuL3KjU6WMxgoW4tG1YgnP1M+TRG3Qn7b7R0euKAHq4vpwARHb18ZyfZljSxsTnMX2w==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "@mswjs/cookies": "^0.2.2", + "@mswjs/interceptors": "^0.17.10", + "@open-draft/until": "^1.0.3", + "@types/cookie": "^0.4.1", + "@types/js-levenshtein": "^1.1.1", + "chalk": "^4.1.1", + "chokidar": "^3.4.2", + "cookie": "^0.4.2", + "graphql": "^16.8.1", + "headers-polyfill": "3.2.5", + "inquirer": "^8.2.0", + "is-node-process": "^1.2.0", + "js-levenshtein": "^1.1.6", + "node-fetch": "^2.6.7", + "outvariant": "^1.4.0", + "path-to-regexp": "^6.3.0", + "strict-event-emitter": "^0.4.3", + "type-fest": "^2.19.0", + "yargs": "^17.3.1" + }, + "bin": { + "msw": "cli/index.js" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mswjs" }, - "engines": { - "node": ">=10" + "peerDependencies": { + "typescript": ">= 4.4.x" }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, "packages/liveblocks-react/node_modules/pretty-format": { @@ -40065,6 +39650,26 @@ "dev": true, "license": "MIT" }, + "packages/liveblocks-react/node_modules/strict-event-emitter": { + "version": "0.4.6", + "resolved": "https://registry.npmjs.org/strict-event-emitter/-/strict-event-emitter-0.4.6.tgz", + "integrity": "sha512-12KWeb+wixJohmnwNFerbyiBrAlq5qJLwIt38etRtKtmmHyDSoGlIqFE9wx+4IwG0aDjI7GV8tc8ZccjWZZtTg==", + "dev": true, + "license": "MIT" + }, + "packages/liveblocks-react/node_modules/type-fest": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", + "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "packages/liveblocks-redux": { "name": "@liveblocks/redux", "version": "3.3.3", @@ -40075,10 +39680,10 @@ }, "devDependencies": { "@liveblocks/eslint-config": "*", - "@liveblocks/jest-config": "*", + "@liveblocks/vitest-config": "*", "@reduxjs/toolkit": "^2.8.2", - "@testing-library/jest-dom": "^6.4.6", - "msw": "^1.3.5", + "@testing-library/dom": "^10.4.0", + "msw": "^2.10.4", "redux": "^5.0.1" }, "peerDependencies": { @@ -40112,55 +39717,56 @@ } } }, - "packages/liveblocks-redux/node_modules/@testing-library/jest-dom": { - "version": "6.4.6", + "packages/liveblocks-redux/node_modules/@testing-library/dom": { + "version": "10.4.1", + "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.1.tgz", + "integrity": "sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==", "dev": true, "license": "MIT", "dependencies": { - "@adobe/css-tools": "^4.4.0", - "@babel/runtime": "^7.9.2", - "aria-query": "^5.0.0", - "chalk": "^3.0.0", - "css.escape": "^1.5.1", - "dom-accessibility-api": "^0.6.3", - "lodash": "^4.17.21", - "redent": "^3.0.0" + "@babel/code-frame": "^7.10.4", + "@babel/runtime": "^7.12.5", + "@types/aria-query": "^5.0.1", + "aria-query": "5.3.0", + "dom-accessibility-api": "^0.5.9", + "lz-string": "^1.5.0", + "picocolors": "1.1.1", + "pretty-format": "^27.0.2" }, "engines": { - "node": ">=14", - "npm": ">=6", - "yarn": ">=1" - }, - "peerDependencies": { - "@jest/globals": ">= 28", - "@types/bun": "latest", - "@types/jest": ">= 28", - "jest": ">= 28", - "vitest": ">= 0.32" - }, - "peerDependenciesMeta": { - "@jest/globals": { - "optional": true - }, - "@types/bun": { - "optional": true - }, - "@types/jest": { - "optional": true - }, - "jest": { - "optional": true - }, - "vitest": { - "optional": true - } + "node": ">=18" } }, - "packages/liveblocks-redux/node_modules/dom-accessibility-api": { - "version": "0.6.3", + "packages/liveblocks-redux/node_modules/@testing-library/dom/node_modules/dom-accessibility-api": { + "version": "0.5.16", + "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz", + "integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==", "dev": true, "license": "MIT" }, + "packages/liveblocks-redux/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "packages/liveblocks-redux/node_modules/aria-query": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz", + "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "dequal": "^2.0.3" + } + }, "packages/liveblocks-redux/node_modules/immer": { "version": "10.1.1", "resolved": "https://registry.npmjs.org/immer/-/immer-10.1.1.tgz", @@ -40172,6 +39778,35 @@ "url": "https://opencollective.com/immer" } }, + "packages/liveblocks-redux/node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "packages/liveblocks-redux/node_modules/pretty-format": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", + "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^17.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "packages/liveblocks-redux/node_modules/react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", + "dev": true, + "license": "MIT" + }, "packages/liveblocks-redux/node_modules/redux": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz", @@ -40208,9 +39843,9 @@ }, "devDependencies": { "@liveblocks/eslint-config": "*", - "@liveblocks/jest-config": "*", + "@liveblocks/vitest-config": "*", "@testing-library/jest-dom": "^6.4.6", - "msw": "^1.3.5" + "msw": "^2.7.3" }, "peerDependencies": { "yjs": "^13.6.1" @@ -40260,18 +39895,6 @@ } } }, - "packages/liveblocks-yjs/node_modules/@testing-library/jest-dom/node_modules/chalk": { - "version": "3.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=8" - } - }, "packages/liveblocks-yjs/node_modules/dom-accessibility-api": { "version": "0.6.3", "dev": true, @@ -40287,61 +39910,91 @@ }, "devDependencies": { "@liveblocks/eslint-config": "*", - "@liveblocks/jest-config": "*", - "@testing-library/jest-dom": "^6.4.6", - "msw": "^1.3.5", + "@liveblocks/vitest-config": "*", + "@testing-library/dom": "^10.4.0", + "msw": "^2.10.4", "zustand": "^5.0.1" }, "peerDependencies": { "zustand": "^5.0.1" } }, - "packages/liveblocks-zustand/node_modules/@testing-library/jest-dom": { - "version": "6.4.6", + "packages/liveblocks-zustand/node_modules/@testing-library/dom": { + "version": "10.4.1", + "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.1.tgz", + "integrity": "sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==", "dev": true, "license": "MIT", "dependencies": { - "@adobe/css-tools": "^4.4.0", - "@babel/runtime": "^7.9.2", - "aria-query": "^5.0.0", - "chalk": "^3.0.0", - "css.escape": "^1.5.1", - "dom-accessibility-api": "^0.6.3", - "lodash": "^4.17.21", - "redent": "^3.0.0" + "@babel/code-frame": "^7.10.4", + "@babel/runtime": "^7.12.5", + "@types/aria-query": "^5.0.1", + "aria-query": "5.3.0", + "dom-accessibility-api": "^0.5.9", + "lz-string": "^1.5.0", + "picocolors": "1.1.1", + "pretty-format": "^27.0.2" }, "engines": { - "node": ">=14", - "npm": ">=6", - "yarn": ">=1" + "node": ">=18" + } + }, + "packages/liveblocks-zustand/node_modules/@testing-library/dom/node_modules/dom-accessibility-api": { + "version": "0.5.16", + "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz", + "integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==", + "dev": true, + "license": "MIT" + }, + "packages/liveblocks-zustand/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" }, - "peerDependencies": { - "@jest/globals": ">= 28", - "@types/bun": "latest", - "@types/jest": ">= 28", - "jest": ">= 28", - "vitest": ">= 0.32" + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "packages/liveblocks-zustand/node_modules/aria-query": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz", + "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "dequal": "^2.0.3" + } + }, + "packages/liveblocks-zustand/node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "packages/liveblocks-zustand/node_modules/pretty-format": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", + "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^17.0.1" }, - "peerDependenciesMeta": { - "@jest/globals": { - "optional": true - }, - "@types/bun": { - "optional": true - }, - "@types/jest": { - "optional": true - }, - "jest": { - "optional": true - }, - "vitest": { - "optional": true - } + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "packages/liveblocks-zustand/node_modules/dom-accessibility-api": { - "version": "0.6.3", + "packages/liveblocks-zustand/node_modules/react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", "dev": true, "license": "MIT" }, @@ -40567,308 +40220,288 @@ "name": "@liveblocks/vitest-config", "version": "1.0.0", "dependencies": { - "@vitest/coverage-istanbul": "^3.0.7", "fast-check": "^3.19.0", + "jsdom": "^25.0.1", "vite-tsconfig-paths": "^5.1.4", - "vitest": "^2.1.9" + "whatwg-fetch": "^3.6.20" } }, - "shared/vitest-config/node_modules/@mswjs/interceptors": { - "version": "0.37.6", + "shared/vitest-config/node_modules/agent-base": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "@open-draft/deferred-promise": "^2.2.0", - "@open-draft/logger": "^0.3.0", - "@open-draft/until": "^2.0.0", - "is-node-process": "^1.2.0", - "outvariant": "^1.4.3", - "strict-event-emitter": "^0.5.1" - }, "engines": { - "node": ">=18" + "node": ">= 14" } }, - "shared/vitest-config/node_modules/@open-draft/until": { - "version": "2.1.0", - "license": "MIT", - "optional": true, - "peer": true - }, - "shared/vitest-config/node_modules/@types/cookie": { - "version": "0.6.0", - "license": "MIT", - "optional": true, - "peer": true - }, - "shared/vitest-config/node_modules/@vitest/expect": { - "version": "2.1.9", + "shared/vitest-config/node_modules/cssstyle": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-4.6.0.tgz", + "integrity": "sha512-2z+rWdzbbSZv6/rhtvzvqeZQHrBaqgogqt85sqFNbabZOuFbCVFb8kPeEtZjiKkbrm395irpNKiYeFeLiQnFPg==", "license": "MIT", "dependencies": { - "@vitest/spy": "2.1.9", - "@vitest/utils": "2.1.9", - "chai": "^5.1.2", - "tinyrainbow": "^1.2.0" + "@asamuzakjp/css-color": "^3.2.0", + "rrweb-cssom": "^0.8.0" }, - "funding": { - "url": "https://opencollective.com/vitest" + "engines": { + "node": ">=18" } }, - "shared/vitest-config/node_modules/@vitest/mocker": { - "version": "2.1.9", - "license": "MIT", - "dependencies": { - "@vitest/spy": "2.1.9", - "estree-walker": "^3.0.3", - "magic-string": "^0.30.12" - }, - "funding": { - "url": "https://opencollective.com/vitest" - }, - "peerDependencies": { - "msw": "^2.4.9", - "vite": "^5.0.0" - }, - "peerDependenciesMeta": { - "msw": { - "optional": true - }, - "vite": { - "optional": true - } - } + "shared/vitest-config/node_modules/cssstyle/node_modules/rrweb-cssom": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.8.0.tgz", + "integrity": "sha512-guoltQEx+9aMf2gDZ0s62EcV8lsXR+0w8915TC3ITdn2YueuNjdAYh/levpU9nFaoChh9RUS5ZdQMrKfVEN9tw==", + "license": "MIT" }, - "shared/vitest-config/node_modules/@vitest/pretty-format": { - "version": "2.1.9", + "shared/vitest-config/node_modules/data-urls": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-5.0.0.tgz", + "integrity": "sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==", "license": "MIT", "dependencies": { - "tinyrainbow": "^1.2.0" + "whatwg-mimetype": "^4.0.0", + "whatwg-url": "^14.0.0" }, - "funding": { - "url": "https://opencollective.com/vitest" + "engines": { + "node": ">=18" } }, - "shared/vitest-config/node_modules/@vitest/runner": { - "version": "2.1.9", - "license": "MIT", - "dependencies": { - "@vitest/utils": "2.1.9", - "pathe": "^1.1.2" + "shared/vitest-config/node_modules/decimal.js": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.6.0.tgz", + "integrity": "sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==", + "license": "MIT" + }, + "shared/vitest-config/node_modules/entities": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", + "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" }, "funding": { - "url": "https://opencollective.com/vitest" + "url": "https://github.com/fb55/entities?sponsor=1" } }, - "shared/vitest-config/node_modules/@vitest/snapshot": { - "version": "2.1.9", + "shared/vitest-config/node_modules/html-encoding-sniffer": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-4.0.0.tgz", + "integrity": "sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==", "license": "MIT", "dependencies": { - "@vitest/pretty-format": "2.1.9", - "magic-string": "^0.30.12", - "pathe": "^1.1.2" + "whatwg-encoding": "^3.1.1" }, - "funding": { - "url": "https://opencollective.com/vitest" + "engines": { + "node": ">=18" } }, - "shared/vitest-config/node_modules/@vitest/spy": { - "version": "2.1.9", + "shared/vitest-config/node_modules/http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", "license": "MIT", "dependencies": { - "tinyspy": "^3.0.2" + "agent-base": "^7.1.0", + "debug": "^4.3.4" }, - "funding": { - "url": "https://opencollective.com/vitest" + "engines": { + "node": ">= 14" } }, - "shared/vitest-config/node_modules/@vitest/utils": { - "version": "2.1.9", + "shared/vitest-config/node_modules/https-proxy-agent": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", "license": "MIT", "dependencies": { - "@vitest/pretty-format": "2.1.9", - "loupe": "^3.1.2", - "tinyrainbow": "^1.2.0" + "agent-base": "^7.1.2", + "debug": "4" }, - "funding": { - "url": "https://opencollective.com/vitest" + "engines": { + "node": ">= 14" } }, - "shared/vitest-config/node_modules/estree-walker": { - "version": "3.0.3", + "shared/vitest-config/node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", "license": "MIT", "dependencies": { - "@types/estree": "^1.0.0" + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "shared/vitest-config/node_modules/headers-polyfill": { - "version": "4.0.3", - "license": "MIT", - "optional": true, - "peer": true - }, - "shared/vitest-config/node_modules/msw": { - "version": "2.7.3", - "hasInstallScript": true, + "shared/vitest-config/node_modules/jsdom": { + "version": "25.0.1", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-25.0.1.tgz", + "integrity": "sha512-8i7LzZj7BF8uplX+ZyOlIz86V6TAsSs+np6m1kpW9u0JWi4z/1t+FzcK1aek+ybTnAC4KhBL4uXCNT0wcUIeCw==", "license": "MIT", - "optional": true, - "peer": true, "dependencies": { - "@bundled-es-modules/cookie": "^2.0.1", - "@bundled-es-modules/statuses": "^1.0.1", - "@bundled-es-modules/tough-cookie": "^0.1.6", - "@inquirer/confirm": "^5.0.0", - "@mswjs/interceptors": "^0.37.0", - "@open-draft/deferred-promise": "^2.2.0", - "@open-draft/until": "^2.1.0", - "@types/cookie": "^0.6.0", - "@types/statuses": "^2.0.4", - "graphql": "^16.8.1", - "headers-polyfill": "^4.0.2", - "is-node-process": "^1.2.0", - "outvariant": "^1.4.3", - "path-to-regexp": "^6.3.0", - "picocolors": "^1.1.1", - "strict-event-emitter": "^0.5.1", - "type-fest": "^4.26.1", - "yargs": "^17.7.2" - }, - "bin": { - "msw": "cli/index.js" + "cssstyle": "^4.1.0", + "data-urls": "^5.0.0", + "decimal.js": "^10.4.3", + "form-data": "^4.0.0", + "html-encoding-sniffer": "^4.0.0", + "http-proxy-agent": "^7.0.2", + "https-proxy-agent": "^7.0.5", + "is-potential-custom-element-name": "^1.0.1", + "nwsapi": "^2.2.12", + "parse5": "^7.1.2", + "rrweb-cssom": "^0.7.1", + "saxes": "^6.0.0", + "symbol-tree": "^3.2.4", + "tough-cookie": "^5.0.0", + "w3c-xmlserializer": "^5.0.0", + "webidl-conversions": "^7.0.0", + "whatwg-encoding": "^3.1.1", + "whatwg-mimetype": "^4.0.0", + "whatwg-url": "^14.0.0", + "ws": "^8.18.0", + "xml-name-validator": "^5.0.0" }, "engines": { "node": ">=18" }, - "funding": { - "url": "https://github.com/sponsors/mswjs" - }, "peerDependencies": { - "typescript": ">= 4.8.x" + "canvas": "^2.11.2" }, "peerDependenciesMeta": { - "typescript": { + "canvas": { "optional": true } } }, - "shared/vitest-config/node_modules/pathe": { - "version": "1.1.2", + "shared/vitest-config/node_modules/nwsapi": { + "version": "2.2.21", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.21.tgz", + "integrity": "sha512-o6nIY3qwiSXl7/LuOU0Dmuctd34Yay0yeuZRLFmDPrrdHpXKFndPj3hM+YEPVHYC5fx2otBx4Ilc/gyYSAUaIA==", "license": "MIT" }, - "shared/vitest-config/node_modules/picocolors": { - "version": "1.1.1", - "license": "ISC", - "optional": true, - "peer": true - }, - "shared/vitest-config/node_modules/strict-event-emitter": { - "version": "0.5.1", + "shared/vitest-config/node_modules/parse5": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz", + "integrity": "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==", "license": "MIT", - "optional": true, - "peer": true + "dependencies": { + "entities": "^6.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } }, - "shared/vitest-config/node_modules/tinyrainbow": { - "version": "1.2.0", + "shared/vitest-config/node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", "license": "MIT", "engines": { - "node": ">=14.0.0" + "node": ">=6" } }, - "shared/vitest-config/node_modules/type-fest": { - "version": "4.37.0", - "license": "(MIT OR CC0-1.0)", - "optional": true, - "peer": true, + "shared/vitest-config/node_modules/tough-cookie": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-5.1.2.tgz", + "integrity": "sha512-FVDYdxtnj0G6Qm/DhNPSb8Ju59ULcup3tuJxkFb5K8Bv2pUXILbf0xZWU8PX8Ov19OXljbUyveOFwRMwkXzO+A==", + "license": "BSD-3-Clause", + "dependencies": { + "tldts": "^6.1.32" + }, "engines": { "node": ">=16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" } }, - "shared/vitest-config/node_modules/vite-node": { - "version": "2.1.9", + "shared/vitest-config/node_modules/tr46": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-5.1.1.tgz", + "integrity": "sha512-hdF5ZgjTqgAntKkklYw0R03MG2x/bSzTtkxmIRw/sTNV8YXsCJ1tfLAX23lhxhHJlEf3CRCOCGGWw3vI3GaSPw==", "license": "MIT", "dependencies": { - "cac": "^6.7.14", - "debug": "^4.3.7", - "es-module-lexer": "^1.5.4", - "pathe": "^1.1.2", - "vite": "^5.0.0" - }, - "bin": { - "vite-node": "vite-node.mjs" + "punycode": "^2.3.1" }, "engines": { - "node": "^18.0.0 || >=20.0.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" + "node": ">=18" } }, - "shared/vitest-config/node_modules/vitest": { - "version": "2.1.9", + "shared/vitest-config/node_modules/w3c-xmlserializer": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz", + "integrity": "sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==", "license": "MIT", "dependencies": { - "@vitest/expect": "2.1.9", - "@vitest/mocker": "2.1.9", - "@vitest/pretty-format": "^2.1.9", - "@vitest/runner": "2.1.9", - "@vitest/snapshot": "2.1.9", - "@vitest/spy": "2.1.9", - "@vitest/utils": "2.1.9", - "chai": "^5.1.2", - "debug": "^4.3.7", - "expect-type": "^1.1.0", - "magic-string": "^0.30.12", - "pathe": "^1.1.2", - "std-env": "^3.8.0", - "tinybench": "^2.9.0", - "tinyexec": "^0.3.1", - "tinypool": "^1.0.1", - "tinyrainbow": "^1.2.0", - "vite": "^5.0.0", - "vite-node": "2.1.9", - "why-is-node-running": "^2.3.0" + "xml-name-validator": "^5.0.0" }, - "bin": { - "vitest": "vitest.mjs" + "engines": { + "node": ">=18" + } + }, + "shared/vitest-config/node_modules/whatwg-encoding": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz", + "integrity": "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==", + "license": "MIT", + "dependencies": { + "iconv-lite": "0.6.3" }, "engines": { - "node": "^18.0.0 || >=20.0.0" + "node": ">=18" + } + }, + "shared/vitest-config/node_modules/whatwg-mimetype": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz", + "integrity": "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "shared/vitest-config/node_modules/whatwg-url": { + "version": "14.2.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.2.0.tgz", + "integrity": "sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw==", + "license": "MIT", + "dependencies": { + "tr46": "^5.1.0", + "webidl-conversions": "^7.0.0" }, - "funding": { - "url": "https://opencollective.com/vitest" + "engines": { + "node": ">=18" + } + }, + "shared/vitest-config/node_modules/ws": { + "version": "8.18.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz", + "integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" }, "peerDependencies": { - "@edge-runtime/vm": "*", - "@types/node": "^18.0.0 || >=20.0.0", - "@vitest/browser": "2.1.9", - "@vitest/ui": "2.1.9", - "happy-dom": "*", - "jsdom": "*" + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" }, "peerDependenciesMeta": { - "@edge-runtime/vm": { - "optional": true - }, - "@types/node": { - "optional": true - }, - "@vitest/browser": { - "optional": true - }, - "@vitest/ui": { - "optional": true - }, - "happy-dom": { + "bufferutil": { "optional": true }, - "jsdom": { + "utf-8-validate": { "optional": true } } }, + "shared/vitest-config/node_modules/xml-name-validator": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-5.0.0.tgz", + "integrity": "sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==", + "license": "Apache-2.0", + "engines": { + "node": ">=18" + } + }, "tools/create-liveblocks-app": { "version": "2.20240816.0", "license": "Apache-2.0", diff --git a/package.json b/package.json index e9b3e88c1ad..85e9d678d99 100644 --- a/package.json +++ b/package.json @@ -24,6 +24,7 @@ "@types/node": "^18.19.70", "@types/react": "^18.3.17", "@types/react-dom": "^18.3.5", + "@vitest/coverage-istanbul": "^2.1.9", "dependency-cruiser": "^16.9.0", "prettier": "^3.4.2", "publint": "^0.3.6", @@ -31,7 +32,8 @@ "tsd": "^0.31.2", "tsup": "^8.3.5", "turbo": "^2.3.3", - "typescript": "^5.7.2" + "typescript": "^5.7.2", + "vitest": "^2.1.9" }, "engines": { "node": ">=22.x" diff --git a/packages/liveblocks-client/jest.config.cjs b/packages/liveblocks-client/jest.config.cjs deleted file mode 100644 index 5fa0bec03a3..00000000000 --- a/packages/liveblocks-client/jest.config.cjs +++ /dev/null @@ -1 +0,0 @@ -module.exports = require("@liveblocks/jest-config"); diff --git a/packages/liveblocks-client/package.json b/packages/liveblocks-client/package.json index ca5bc6d74bf..a0ad8ebf8b2 100644 --- a/packages/liveblocks-client/package.json +++ b/packages/liveblocks-client/package.json @@ -29,16 +29,16 @@ "format": "(eslint --fix src/ || true) && prettier --write src/", "lint": "eslint src/", "lint:package": "publint --strict && attw --pack", - "test": "jest --silent --verbose --color=always --passWithNoTests", + "test": "NODE_OPTIONS=\"--no-deprecation\" vitest run --passWithNoTests", "test:types": "ls test-d/* | xargs -n1 tsd --files", - "test:watch": "jest --silent --verbose --color=always --passWithNoTests --watch" + "test:watch": "NODE_OPTIONS=\"--no-deprecation\" vitest" }, "dependencies": { "@liveblocks/core": "3.3.3" }, "devDependencies": { "@liveblocks/eslint-config": "*", - "@liveblocks/jest-config": "*" + "@liveblocks/vitest-config": "*" }, "sideEffects": false, "bugs": { diff --git a/packages/liveblocks-client/vitest.config.ts b/packages/liveblocks-client/vitest.config.ts new file mode 100644 index 00000000000..5c364192146 --- /dev/null +++ b/packages/liveblocks-client/vitest.config.ts @@ -0,0 +1,3 @@ +import { defaultLiveblocksVitestConfig } from "@liveblocks/vitest-config"; + +export default defaultLiveblocksVitestConfig(); \ No newline at end of file diff --git a/packages/liveblocks-core/e2e/list.test.ts b/packages/liveblocks-core/e2e/list.test.ts index 3dfc64b1c50..c0da272ace5 100644 --- a/packages/liveblocks-core/e2e/list.test.ts +++ b/packages/liveblocks-core/e2e/list.test.ts @@ -1,5 +1,7 @@ -import { lsonToJson } from "../src/immutable"; +import { describe, expect, test } from "vitest"; + import { LiveList } from "../src/crdts/LiveList"; +import { lsonToJson } from "../src/immutable"; import type { Json } from "../src/lib/Json"; import { prepareSingleClientTest, prepareTestsConflicts } from "./utils"; diff --git a/packages/liveblocks-core/e2e/map.test.ts b/packages/liveblocks-core/e2e/map.test.ts index 1f41083d2f7..81563fda62d 100644 --- a/packages/liveblocks-core/e2e/map.test.ts +++ b/packages/liveblocks-core/e2e/map.test.ts @@ -1,10 +1,13 @@ -import type { Immutable } from "../src/types/Immutable"; +import { describe, expect, test } from "vitest"; + import { LiveMap } from "../src/crdts/LiveMap"; +import type { Immutable } from "../src/types/Immutable"; import { prepareSingleClientTest, prepareTestsConflicts } from "./utils"; describe("LiveMap single client", () => { test( "remote set conflicts with another set", + { timeout: 10000 }, prepareTestsConflicts( { map: new LiveMap(), @@ -58,6 +61,7 @@ describe("LiveMap single client", () => { describe("LiveMap single client", () => { test( "fast consecutive sets on same key", + { timeout: 10000 }, prepareSingleClientTest( { map: new LiveMap(), diff --git a/packages/liveblocks-core/e2e/utils.ts b/packages/liveblocks-core/e2e/utils.ts index 7ecf3fa9de7..cc6fa6ffad8 100644 --- a/packages/liveblocks-core/e2e/utils.ts +++ b/packages/liveblocks-core/e2e/utils.ts @@ -2,18 +2,19 @@ import "dotenv/config"; import fetch from "node-fetch"; import type { URL } from "url"; +import { expect } from "vitest"; import WebSocket from "ws"; -import type { Room } from "../src/room"; +import type { BaseMetadata, NoInfr } from "../src"; +import { createClient } from "../src/client"; import type { Status } from "../src/connection"; -import type { BaseUserMeta } from "../src/protocol/BaseUserMeta"; -import { wait, withTimeout } from "../src/lib/utils"; -import type { Json, JsonObject } from "../src/lib/Json"; import type { LiveObject } from "../src/crdts/LiveObject"; import type { LsonObject } from "../src/crdts/Lson"; import type { ToImmutable } from "../src/crdts/utils"; -import { createClient } from "../src/client"; -import type { BaseMetadata, NoInfr } from "../src"; +import type { Json, JsonObject } from "../src/lib/Json"; +import { wait, withTimeout } from "../src/lib/utils"; +import type { BaseUserMeta } from "../src/protocol/BaseUserMeta"; +import type { Room } from "../src/room"; async function initializeRoomForTest< P extends JsonObject = JsonObject, @@ -24,7 +25,7 @@ async function initializeRoomForTest< >(roomId: string, initialPresence: NoInfr

, initialStorage: NoInfr) { const publicApiKey = process.env.LIVEBLOCKS_PUBLIC_KEY; - if (publicApiKey == null) { + if (!publicApiKey) { throw new Error('Environment variable "LIVEBLOCKS_PUBLIC_KEY" is missing.'); } @@ -36,6 +37,7 @@ async function initializeRoomForTest< constructor(address: string | URL) { super(address); + // eslint-disable-next-line @typescript-eslint/no-this-alias ws = this; } @@ -63,7 +65,7 @@ async function initializeRoomForTest< const client = createClient({ publicApiKey, polyfills: { - // @ts-ignore-error + // @ts-expect-error fetch from Node isn't compatible? fetch, WebSocket: PausableWebSocket, }, @@ -227,8 +229,8 @@ export function prepareSingleClientTest( actor.ws.pauseSend(); - actor.ws.addEventListener("message", (message) => { - console.log(message.data); + actor.ws.addEventListener("message", (_message) => { + // console.log(message.data); }); try { diff --git a/packages/liveblocks-core/jest.config.cjs b/packages/liveblocks-core/jest.config.cjs deleted file mode 100644 index 2b4b5a4a80e..00000000000 --- a/packages/liveblocks-core/jest.config.cjs +++ /dev/null @@ -1,11 +0,0 @@ -/** @type {import('jest').Config} */ - -const commonJestConfig = require("@liveblocks/jest-config"); - -module.exports = { - // Our standard Jest configuration, used by all projects in this monorepo - ...commonJestConfig, - - // Collect code coverage for this project, when using the --coverage flag - coveragePathIgnorePatterns: ["/__tests__/"], -}; diff --git a/packages/liveblocks-core/jest.config.e2e.cjs b/packages/liveblocks-core/jest.config.e2e.cjs deleted file mode 100644 index 71239deee53..00000000000 --- a/packages/liveblocks-core/jest.config.e2e.cjs +++ /dev/null @@ -1,14 +0,0 @@ -/** @type {import('jest').Config} */ - -const commonJestConfig = require("@liveblocks/jest-config"); - -module.exports = { - // Our standard Jest configuration, used by all projects in this monorepo - ...commonJestConfig, - - // Our standard setup assumed jsdom environment. Override it for node here. - testEnvironment: "node", - testTimeout: 30000, - - roots: ["/e2e"], -}; diff --git a/packages/liveblocks-core/package.json b/packages/liveblocks-core/package.json index bc18d740f57..c01bea4ff70 100644 --- a/packages/liveblocks-core/package.json +++ b/packages/liveblocks-core/package.json @@ -34,13 +34,13 @@ "scripts": { "dev": "tsup --watch", "build": "tsup && node dist/index.js", - "format": "(eslint --fix src/ || true) && prettier --write src/", + "format": "(eslint --fix src/ e2e/ || true) && prettier --write src/ e2e/", "lint": "eslint src/", "lint:package": "publint --strict && attw --pack", - "test": "jest --silent --verbose --color=always", + "test": "NODE_OPTIONS=\"--no-deprecation\" vitest run", "test:types": "ls test-d/* | xargs -n1 tsd --files", - "test:watch": "jest --silent --verbose --color=always --watch", - "test:e2e": "jest --silent --verbose --color=always --config=./jest.config.e2e.cjs", + "test:watch": "NODE_OPTIONS=\"--no-deprecation\" vitest", + "test:e2e": "NODE_OPTIONS=\"--no-deprecation\" vitest run --config=./vitest.config.e2e.ts", "test:deps": "depcruise src --exclude __tests__", "showdeps": "depcruise src --include-only '^src' --exclude='__tests__' --output-type dot | dot -T svg > /tmp/dependency-graph.svg && open /tmp/dependency-graph.svg", "showdeps:high-level": "depcruise src --include-only '^src' --exclude='(^src/index.ts|shallow.ts|__tests__)' --collapse='^src/(refs|lib|compat|types|crdts|protocol)' --output-type dot | dot -T svg > /tmp/dependency-graph.svg && open /tmp/dependency-graph.svg" @@ -48,12 +48,12 @@ "license": "Apache-2.0", "devDependencies": { "@liveblocks/eslint-config": "*", - "@liveblocks/jest-config": "*", "@liveblocks/query-parser": "^0.1.1", + "@liveblocks/vitest-config": "*", "@types/ws": "^8.5.10", "dotenv": "^16.4.5", "eslint-plugin-rulesdir": "^0.2.2", - "msw": "^1.3.5", + "msw": "^2.10.4", "ws": "^8.17.1" }, "peerDependencies": { diff --git a/packages/liveblocks-core/src/__tests__/_behaviors.ts b/packages/liveblocks-core/src/__tests__/_behaviors.ts index dbe340a6105..4dfdb0ab2fb 100644 --- a/packages/liveblocks-core/src/__tests__/_behaviors.ts +++ b/packages/liveblocks-core/src/__tests__/_behaviors.ts @@ -8,6 +8,8 @@ * const { wss, delegates } = defineBehavior(ALWAYS_AUTH_AS(2), SOCKET_AUTO_OPEN); */ +import { vi } from "vitest"; + import type { AuthValue } from "../auth-manager"; import type { Delegates } from "../connection"; import { StopRetrying } from "../connection"; @@ -62,10 +64,10 @@ export function defineBehavior( const canZombie = () => false; const delegates: Delegates = { - authenticate: jest.fn(authenticate), - createSocket: jest.fn(createSocket), - canZombie: jest.fn(canZombie), - // ^^^^^^^ Allow observing these calls in tests + authenticate: vi.fn(authenticate), + createSocket: vi.fn(createSocket), + canZombie: vi.fn(canZombie), + // ^^^^^ Allow observing these calls in tests }; return { wss, delegates }; diff --git a/packages/liveblocks-core/src/__tests__/_updatesUtils.ts b/packages/liveblocks-core/src/__tests__/_updatesUtils.ts index 368580404c8..a95181859d3 100644 --- a/packages/liveblocks-core/src/__tests__/_updatesUtils.ts +++ b/packages/liveblocks-core/src/__tests__/_updatesUtils.ts @@ -52,10 +52,6 @@ export type JsonLiveMapUpdate = { updates: { [key: string]: UpdateDelta }; }; -it("Always passes", () => { - /* This bogus test just makes Jest less naggy about this module missing any tests */ -}); - export function liveListUpdateToJson( update: LiveListUpdates ): JsonLiveListUpdate { diff --git a/packages/liveblocks-core/src/__tests__/_utils.ts b/packages/liveblocks-core/src/__tests__/_utils.ts index cd4a6537027..1cc05ecbbcb 100644 --- a/packages/liveblocks-core/src/__tests__/_utils.ts +++ b/packages/liveblocks-core/src/__tests__/_utils.ts @@ -1,3 +1,5 @@ +import { expect } from "vitest"; + import { createApiClient } from "../api-client"; import { createAuthManager } from "../auth-manager"; import { DEFAULT_BASE_URL } from "../constants"; diff --git a/packages/liveblocks-core/src/__tests__/ai.test.ts b/packages/liveblocks-core/src/__tests__/ai.test.ts index 21deffc4b89..51734311857 100644 --- a/packages/liveblocks-core/src/__tests__/ai.test.ts +++ b/packages/liveblocks-core/src/__tests__/ai.test.ts @@ -1,16 +1,18 @@ +import { describe, expect, test } from "vitest"; + import { KnowledgeStack } from "../ai"; describe("KnowledgeStack", () => { - it("should be empty by default", () => { + test("should be empty by default", () => { expect(new KnowledgeStack().get()).toEqual([]); }); - it("should be ref equal when called multiple times", () => { + test("should be ref equal when called multiple times", () => { const stack = new KnowledgeStack(); expect(stack.get()).toBe(stack.get()); }); - it("multiple knowledge registrations", () => { + test("multiple knowledge registrations", () => { const stack = new KnowledgeStack(); const key1 = stack.registerLayer("«r1»"); stack.updateKnowledge(key1, "abc", { @@ -27,7 +29,7 @@ describe("KnowledgeStack", () => { ]); }); - it("overriding knowledge", () => { + test("overriding knowledge", () => { const stack = new KnowledgeStack(); const key1 = stack.registerLayer("«r1»"); const key2 = stack.registerLayer("«r2»"); @@ -45,7 +47,7 @@ describe("KnowledgeStack", () => { ]); }); - it("explicitly removing knowledge", () => { + test("explicitly removing knowledge", () => { const stack = new KnowledgeStack(); const key1 = stack.registerLayer("«r1»"); const key2 = stack.registerLayer("«r2»"); @@ -62,7 +64,7 @@ describe("KnowledgeStack", () => { ]); }); - it("registering exact same knowledge twice just overrides it", () => { + test("registering exact same knowledge twice just overrides it", () => { const stack = new KnowledgeStack(); const key1 = stack.registerLayer("«r1»"); stack.updateKnowledge(key1, "abc", { @@ -87,7 +89,7 @@ describe("KnowledgeStack", () => { expect(stack.get()).toEqual([]); }); - it("deregistering layer 1", () => { + test("deregistering layer 1", () => { const stack = new KnowledgeStack(); const key1 = stack.registerLayer("«r1»"); const key2 = stack.registerLayer("«r2»"); @@ -106,7 +108,7 @@ describe("KnowledgeStack", () => { ]); }); - it("deregistering layer 2", () => { + test("deregistering layer 2", () => { const stack = new KnowledgeStack(); const key1 = stack.registerLayer("«r1»"); const key2 = stack.registerLayer("«r2»"); @@ -125,7 +127,7 @@ describe("KnowledgeStack", () => { ]); }); - it("deregistering both layers", () => { + test("deregistering both layers", () => { const stack = new KnowledgeStack(); const key1 = stack.registerLayer("«r1»"); const key2 = stack.registerLayer("«r2»"); diff --git a/packages/liveblocks-core/src/__tests__/auth-manager.test.ts b/packages/liveblocks-core/src/__tests__/auth-manager.test.ts index 56f6609506c..44ad594823e 100644 --- a/packages/liveblocks-core/src/__tests__/auth-manager.test.ts +++ b/packages/liveblocks-core/src/__tests__/auth-manager.test.ts @@ -1,5 +1,15 @@ -import { rest } from "msw"; +import { http, HttpResponse } from "msw"; import { setupServer } from "msw/node"; +import { + afterAll, + afterEach, + beforeAll, + beforeEach, + describe, + expect, + test, + vi, +} from "vitest"; import { createAuthManager } from "../auth-manager"; import type { ParsedAuthToken } from "../protocol/AuthToken"; @@ -62,42 +72,42 @@ describe("auth-manager - secret auth", () => { "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE2NjQ1NjY0MTAsImV4cCI6MTY2NDU3MDAxMCwicGlkIjoiNjA1YTRmZDMxYTM2ZDVlYTdhMmUwOGYxIiwidWlkIjoidXNlcjEiLCJrIjoiaWQifQ.MhjHg2udkBivX7cW8Q1jmgc4DOZ1YnMoUnP61O32JLVJlIsc0zmHWA__DItsO3vBbRS8doG98cOzSE2qQ-5rKoX2l19k5Mr7gk6M75u1kOAzppV_3YQAGeZ8PfsUUPUBGOF5O6msLnha-HcAywvBuoUmcqP0CF_xhBBx0CLbFeuaWVJqndPKe8LJk9EYcB29HEwFaIzrOSarU1iLxRhsa8FCB910GTDcaApaUTPM9ZRadmf33ypSn3c6by0BWI54vx4O2p-hFsmJ71R38ifRRVq3ETXn78ftwbu1pp6hMTqyYn5YLlnZPPM-JAck_OsarGvE9cxg_Z3Y8bMTOlA5E"; const server = setupServer( - rest.post("/mocked-api/legacy-auth", (_req, res, ctx) => { - return res( - ctx.json({ token: legacyTokens[requestCount++ % legacyTokens.length] }) - ); + http.post("/api/legacy-auth", () => { + return HttpResponse.json({ + token: legacyTokens[requestCount++ % legacyTokens.length], + }); }), - rest.post("/mocked-api/legacy-auth-that-caches", (_req, res, ctx) => { + http.post("/api/legacy-auth-that-caches", () => { requestCount++; - return res(ctx.json({ token: legacyTokens[0] })); + return HttpResponse.json({ token: legacyTokens[0] }); }), - rest.post("/mocked-api/access-auth", (_req, res, ctx) => { + http.post("/api/access-auth", () => { requestCount++; - return res(ctx.json({ token: accessToken })); + return HttpResponse.json({ token: accessToken }); }), - rest.post("/mocked-api/access-auth-comments-read", (_req, res, ctx) => { + http.post("/api/access-auth-comments-read", () => { requestCount++; - return res(ctx.json({ token: accessTokenWildcardCommentsRead })); + return HttpResponse.json({ token: accessTokenWildcardCommentsRead }); }), - rest.post("/mocked-api/access-auth-no-permission", (_req, res, ctx) => { + http.post("/api/access-auth-no-permission", () => { requestCount++; - return res(ctx.json({ token: accessTokenWithNoPermission })); + return HttpResponse.json({ token: accessTokenWithNoPermission }); }), - rest.post("/mocked-api/id-auth", (_req, res, ctx) => { + http.post("/api/id-auth", () => { requestCount++; - return res(ctx.json({ token: idToken })); + return HttpResponse.json({ token: idToken }); }), - rest.post("/mocked-api/403", (_req, res, ctx) => { - return res(ctx.status(403)); + http.post("/api/403", () => { + return new HttpResponse(null, { status: 403 }); }), - rest.post("/mocked-api/401-with-details", (_req, res, ctx) => { - return res(ctx.status(401), ctx.text("wrong key type")); + http.post("/api/401-with-details", () => { + return new HttpResponse("wrong key type", { status: 401 }); }), - rest.post("/mocked-api/not-json", (_req, res, ctx) => { - return res(ctx.status(202), ctx.text("this is not json")); + http.post("/api/not-json", () => { + return new HttpResponse("this is not json", { status: 202 }); }), - rest.post("/mocked-api/missing-token", (_req, res, ctx) => { - return res(ctx.status(202), ctx.json({})); + http.post("/api/missing-token", () => { + return HttpResponse.json({}, { status: 202 }); }) ); @@ -108,7 +118,7 @@ describe("auth-manager - secret auth", () => { test("should return token", async () => { const authManager = createAuthManager({ - authEndpoint: "/mocked-api/legacy-auth", + authEndpoint: "/api/legacy-auth", }); const authValue = (await authManager.getAuthValue({ @@ -123,7 +133,7 @@ describe("auth-manager - secret auth", () => { test("should deduplicate concurrent requests on same room", async () => { const authManager = createAuthManager({ - authEndpoint: "/mocked-api/legacy-auth", + authEndpoint: "/api/legacy-auth", }); const results = await Promise.all([ @@ -144,7 +154,7 @@ describe("auth-manager - secret auth", () => { test("should not deduplicate concurrent requests on different room", async () => { const authManager = createAuthManager({ - authEndpoint: "/mocked-api/legacy-auth", + authEndpoint: "/api/legacy-auth", }); const results = await Promise.all([ @@ -165,7 +175,7 @@ describe("auth-manager - secret auth", () => { test("should never use cache when using legacy token", async () => { const authManager = createAuthManager({ - authEndpoint: "/mocked-api/legacy-auth", + authEndpoint: "/api/legacy-auth", }); const authValueReq1 = (await authManager.getAuthValue({ @@ -185,7 +195,7 @@ describe("auth-manager - secret auth", () => { test("should throw if legacy token is expired but the next fetch from the backend returns the same (expired) token", async () => { const authManager = createAuthManager({ - authEndpoint: "/mocked-api/legacy-auth-that-caches", + authEndpoint: "/api/legacy-auth-that-caches", }); const authValueReq1 = (await authManager.getAuthValue({ @@ -197,8 +207,8 @@ describe("auth-manager - secret auth", () => { expect(requestCount).toBe(1); // Five hours later, this token should be expired. For ID and access tokens, that mweans - jest.useFakeTimers(); - jest.setSystemTime(Date.now() + 5 * HOURS); + vi.useFakeTimers(); + vi.setSystemTime(Date.now() + 5 * HOURS); try { const $promise = expect( authManager.getAuthValue({ @@ -209,19 +219,19 @@ describe("auth-manager - secret auth", () => { "The same Liveblocks auth token was issued from the backend before. Caching Liveblocks tokens is not supported." ); - jest.useRealTimers(); + vi.useRealTimers(); await $promise; // This made a new HTTP request expect(requestCount).toBe(2); } finally { - jest.useRealTimers(); + vi.useRealTimers(); } }); test("should use cache when access token has correct permissions", async () => { const authManager = createAuthManager({ - authEndpoint: "/mocked-api/access-auth", + authEndpoint: "/api/access-auth", }); const authValueReq1 = (await authManager.getAuthValue({ @@ -241,7 +251,7 @@ describe("auth-manager - secret auth", () => { test("when no roomId, should use cache when access token has correct permissions", async () => { const authManager = createAuthManager({ - authEndpoint: "/mocked-api/access-auth-comments-read", + authEndpoint: "/api/access-auth-comments-read", }); const authValueReq1 = (await authManager.getAuthValue({ @@ -259,7 +269,7 @@ describe("auth-manager - secret auth", () => { test("when no roomId, should use cache when access token has correct permissions (higher level)", async () => { const authManager = createAuthManager({ - authEndpoint: "/mocked-api/access-auth", + authEndpoint: "/api/access-auth", }); const authValueReq1 = (await authManager.getAuthValue({ @@ -277,7 +287,7 @@ describe("auth-manager - secret auth", () => { test("when no roomId, should use cache when access token has no permission", async () => { const authManager = createAuthManager({ - authEndpoint: "/mocked-api/access-auth-no-permission", + authEndpoint: "/api/access-auth-no-permission", }); const authValueReq1 = (await authManager.getAuthValue({ @@ -295,7 +305,7 @@ describe("auth-manager - secret auth", () => { test("should throw if access token is expired but the next fetch from the backend returns the same (expired) token", async () => { const authManager = createAuthManager({ - authEndpoint: "/mocked-api/access-auth", + authEndpoint: "/api/access-auth", }); const authValueReq1 = (await authManager.getAuthValue({ @@ -314,8 +324,8 @@ describe("auth-manager - secret auth", () => { // Five hours later, this token should be expired and no longer be served // from cache... - jest.useFakeTimers(); - jest.setSystemTime(Date.now() + 5 * HOURS); + vi.useFakeTimers(); + vi.setSystemTime(Date.now() + 5 * HOURS); try { // Should throw because this mock will return the exact same (expired) token const $promise = expect( @@ -327,19 +337,19 @@ describe("auth-manager - secret auth", () => { "The same Liveblocks auth token was issued from the backend before. Caching Liveblocks tokens is not supported." ); - jest.useRealTimers(); + vi.useRealTimers(); await $promise; // This made a new HTTP request expect(requestCount).toBe(2); } finally { - jest.useRealTimers(); + vi.useRealTimers(); } }); test("should use cache when ID token", async () => { const authManager = createAuthManager({ - authEndpoint: "/mocked-api/id-auth", + authEndpoint: "/api/id-auth", }); const authValueReq1 = (await authManager.getAuthValue({ @@ -359,7 +369,7 @@ describe("auth-manager - secret auth", () => { test("should throw if ID token is expired but the next fetch from the backend returns the same (expired) token", async () => { const authManager = createAuthManager({ - authEndpoint: "/mocked-api/id-auth", + authEndpoint: "/api/id-auth", }); const authValueReq1 = (await authManager.getAuthValue({ @@ -378,8 +388,8 @@ describe("auth-manager - secret auth", () => { // Five hours later, this token should be expired and no longer be served // from cache... - jest.useFakeTimers(); - jest.setSystemTime(Date.now() + 5 * HOURS); + vi.useFakeTimers(); + vi.setSystemTime(Date.now() + 5 * HOURS); try { // Should throw because this mock will return the exact same (expired) token const $promise = expect( @@ -391,13 +401,13 @@ describe("auth-manager - secret auth", () => { "The same Liveblocks auth token was issued from the backend before. Caching Liveblocks tokens is not supported." ); - jest.useRealTimers(); + vi.useRealTimers(); await $promise; // This made a new HTTP request expect(requestCount).toBe(2); } finally { - jest.useRealTimers(); + vi.useRealTimers(); } }); @@ -452,7 +462,7 @@ describe("auth-manager - secret auth", () => { test("private authentication with 403 status should fail", async () => { const authManager = createAuthManager({ - authEndpoint: "/mocked-api/403", + authEndpoint: "/api/403", }); await expect( @@ -461,13 +471,13 @@ describe("auth-manager - secret auth", () => { roomId: "room1", }) ).rejects.toThrow( - "Unauthorized: reason not provided in auth response (403 returned by POST /mocked-api/403)" + "Unauthorized: reason not provided in auth response (403 returned by POST /api/403)" ); }); test("private authentication with 403 status should fail with details", async () => { const authManager = createAuthManager({ - authEndpoint: "/mocked-api/401-with-details", + authEndpoint: "/api/401-with-details", }); await expect( @@ -476,13 +486,13 @@ describe("auth-manager - secret auth", () => { roomId: "room1", }) ).rejects.toThrow( - "Unauthorized: wrong key type (401 returned by POST /mocked-api/401-with-details)" + "Unauthorized: wrong key type (401 returned by POST /api/401-with-details)" ); }); test("private authentication that does not return valid JSON should fail", async () => { const authManager = createAuthManager({ - authEndpoint: "/mocked-api/not-json", + authEndpoint: "/api/not-json", }); await expect( @@ -491,13 +501,13 @@ describe("auth-manager - secret auth", () => { roomId: "room1", }) ).rejects.toThrow( - 'Expected a JSON response when doing a POST request on "/mocked-api/not-json". SyntaxError: Unexpected token' + 'Expected a JSON response when doing a POST request on "/api/not-json". SyntaxError: Unexpected token' ); }); test("private authentication without an auth token response should fail", async () => { const authManager = createAuthManager({ - authEndpoint: "/mocked-api/missing-token", + authEndpoint: "/api/missing-token", }); await expect( @@ -506,7 +516,7 @@ describe("auth-manager - secret auth", () => { roomId: "room1", }) ).rejects.toThrow( - 'Expected a JSON response of the form `{ token: "..." }` when doing a POST request on "/mocked-api/missing-token", but got {}' + 'Expected a JSON response of the form `{ token: "..." }` when doing a POST request on "/api/missing-token", but got {}' ); }); }); diff --git a/packages/liveblocks-core/src/__tests__/client.node.test.ts b/packages/liveblocks-core/src/__tests__/client.node.test.ts index 1294e7cff64..402d4ce5698 100644 --- a/packages/liveblocks-core/src/__tests__/client.node.test.ts +++ b/packages/liveblocks-core/src/__tests__/client.node.test.ts @@ -1,9 +1,10 @@ /** - * @jest-environment node + * @vitest-environment node */ // We're using node-fetch 2.X because 3+ only support ESM and jest is a pain to use with ESM import { Response as NodeFetchResponse } from "node-fetch"; +import { afterAll, beforeAll, describe, expect, test, vi } from "vitest"; import type { ClientOptions } from "../client"; import { createClient } from "../client"; @@ -90,7 +91,7 @@ describe("createClient", () => { ); test("should not try to connect if autoConnect is false (new style)", () => { - const authMock = jest.fn(); + const authMock = vi.fn(); const client = createClient({ authEndpoint: authMock, @@ -111,7 +112,7 @@ describe("createClient", () => { }); test("entering twice returns the same room (new style)", () => { - const authMock = jest.fn(); + const authMock = vi.fn(); const client = createClient({ authEndpoint: authMock, @@ -187,7 +188,7 @@ describe("createClient", () => { }); test("should throw if authEndpoint is string and fetch polyfill is not defined", async () => { - const spy = jest.spyOn(console, "error"); + const spy = vi.spyOn(console, "error"); const client = createClient({ authEndpoint: "/api/auth", @@ -215,7 +216,7 @@ describe("createClient", () => { const ws = globalThis.WebSocket; delete (globalThis as any).WebSocket; - const spy = jest.spyOn(console, "error"); + const spy = vi.spyOn(console, "error"); const client = createClient({ authEndpoint: authEndpointCallback }); const { room, leave } = client.enterRoom("room"); diff --git a/packages/liveblocks-core/src/__tests__/connection.test.ts b/packages/liveblocks-core/src/__tests__/connection.test.ts index 298108d7b28..b5fb101fb7a 100644 --- a/packages/liveblocks-core/src/__tests__/connection.test.ts +++ b/packages/liveblocks-core/src/__tests__/connection.test.ts @@ -1,3 +1,5 @@ +import { describe, expect, test, vi } from "vitest"; + import { ManagedSocket } from "../connection"; import { ALWAYS_FAIL_AUTH, @@ -10,57 +12,57 @@ import { describe("ManagedSocket", () => { test("failure to authenticate", async () => { - jest.useFakeTimers(); + vi.useFakeTimers(); const { delegates } = defineBehavior(ALWAYS_FAIL_AUTH, SOCKET_NO_BEHAVIOR); - const didConnect = jest.fn(); + const didConnect = vi.fn(); const mgr = new ManagedSocket(delegates); mgr.events.didConnect.subscribe(didConnect); mgr.connect(); - await jest.advanceTimersByTimeAsync(4000); + await vi.advanceTimersByTimeAsync(4000); mgr.disconnect(); expect(didConnect).not.toHaveBeenCalled(); }); test("authenticate + websocket connection are successes but no ROOM_STATE still means not connected", async () => { - jest.useFakeTimers(); + vi.useFakeTimers(); const { delegates } = defineBehavior( AUTH_SUCCESS, SOCKET_AUTOCONNECT_BUT_NO_ROOM_STATE ); - const didConnect = jest.fn(); + const didConnect = vi.fn(); const mgr = new ManagedSocket(delegates); mgr.events.didConnect.subscribe(didConnect); mgr.connect(); - await jest.advanceTimersByTimeAsync(4000); + await vi.advanceTimersByTimeAsync(4000); mgr.disconnect(); expect(didConnect).not.toHaveBeenCalled(); }); test("authenticate + websocket connection + ROOM_STATE = connected", async () => { - jest.useFakeTimers(); + vi.useFakeTimers(); const { delegates } = defineBehavior( AUTH_SUCCESS, SOCKET_AUTOCONNECT_AND_ROOM_STATE() ); - const didConnect = jest.fn(); + const didConnect = vi.fn(); const mgr = new ManagedSocket(delegates); mgr.events.didConnect.subscribe(didConnect); mgr.connect(); - await jest.advanceTimersByTimeAsync(4000); + await vi.advanceTimersByTimeAsync(4000); mgr.disconnect(); expect(didConnect).toHaveBeenCalledTimes(1); diff --git a/packages/liveblocks-core/src/__tests__/immutable.test.ts b/packages/liveblocks-core/src/__tests__/immutable.test.ts index ff94ed67fb6..60bf098c3f3 100644 --- a/packages/liveblocks-core/src/__tests__/immutable.test.ts +++ b/packages/liveblocks-core/src/__tests__/immutable.test.ts @@ -1,3 +1,13 @@ +import { + afterEach, + beforeAll, + describe, + expect, + type MockInstance, + test, + vi, +} from "vitest"; + import { LiveList } from "../crdts/LiveList"; import { LiveMap } from "../crdts/LiveMap"; import { LiveObject } from "../crdts/LiveObject"; @@ -657,11 +667,11 @@ describe("2 ways tests with two clients", () => { describe("unsupported types", () => { let originalEnv: NodeJS.ProcessEnv; - let consoleErrorSpy: jest.SpyInstance; + let consoleErrorSpy: MockInstance; beforeAll(() => { originalEnv = process.env; - consoleErrorSpy = jest.spyOn(console, "error"); + consoleErrorSpy = vi.spyOn(console, "error"); }); afterEach(() => { @@ -729,10 +739,6 @@ describe("2 ways tests with two clients", () => { expect(consoleErrorSpy).toHaveBeenCalledTimes(0); }); }); - - describe("Map/LiveMap", () => { - // TODO - }); }); describe("legacy_patchImmutableObject", () => { diff --git a/packages/liveblocks-core/src/__tests__/resolvers.test.ts b/packages/liveblocks-core/src/__tests__/resolvers.test.ts index 1af13b3c749..bd04b98155c 100644 --- a/packages/liveblocks-core/src/__tests__/resolvers.test.ts +++ b/packages/liveblocks-core/src/__tests__/resolvers.test.ts @@ -1,3 +1,5 @@ +import { describe, expect, test, vi } from "vitest"; + import type { ClientOptions, ResolveRoomsInfoArgs, @@ -24,7 +26,7 @@ function createClientForTest( describe("resolvers", () => { describe("invalidateUsers", () => { test("should support invalidating all users", async () => { - const resolveUsers = jest.fn(({ userIds }: ResolveUsersArgs) => + const resolveUsers = vi.fn(({ userIds }: ResolveUsersArgs) => userIds.map((userId) => ({ name: userId })) ); const client = createClientForTest({ @@ -53,7 +55,7 @@ describe("resolvers", () => { }); test("should support invalidating specific users", async () => { - const resolveUsers = jest.fn(({ userIds }: ResolveUsersArgs) => + const resolveUsers = vi.fn(({ userIds }: ResolveUsersArgs) => userIds.map((userId) => ({ name: userId })) ); const client = createClientForTest({ @@ -92,7 +94,7 @@ describe("resolvers", () => { describe("invalidateRoomsInfo", () => { test("should support invalidating all rooms", async () => { - const resolveRoomsInfo = jest.fn(({ roomIds }: ResolveRoomsInfoArgs) => + const resolveRoomsInfo = vi.fn(({ roomIds }: ResolveRoomsInfoArgs) => roomIds.map((roomId) => ({ name: roomId })) ); const client = createClientForTest({ @@ -126,7 +128,7 @@ describe("resolvers", () => { }); test("should support invalidating specific rooms", async () => { - const resolveRoomsInfo = jest.fn(({ roomIds }: ResolveRoomsInfoArgs) => + const resolveRoomsInfo = vi.fn(({ roomIds }: ResolveRoomsInfoArgs) => roomIds.map((roomId) => ({ name: roomId })) ); const client = createClientForTest({ diff --git a/packages/liveblocks-core/src/__tests__/room.test.ts b/packages/liveblocks-core/src/__tests__/room.test.ts index 63b4f9dc142..730f62abc65 100644 --- a/packages/liveblocks-core/src/__tests__/room.test.ts +++ b/packages/liveblocks-core/src/__tests__/room.test.ts @@ -1,3 +1,13 @@ +import { + afterEach, + beforeEach, + describe, + expect, + type MockInstance, + test, + vi, +} from "vitest"; + import { createApiClient } from "../api-client"; import { type AuthValue, createAuthManager } from "../auth-manager"; import { StopRetrying } from "../connection"; @@ -139,10 +149,10 @@ function createTestableRoom< } describe("room / auth", () => { - let consoleErrorSpy: jest.SpyInstance; + let consoleErrorSpy: MockInstance; beforeEach(() => { - consoleErrorSpy = jest.spyOn(console, "error").mockImplementation(() => {}); + consoleErrorSpy = vi.spyOn(console, "error").mockImplementation(() => {}); }); afterEach(() => { @@ -570,29 +580,29 @@ describe("room", () => { { type: ClientMsgCode.UPDATE_PRESENCE, targetActor: -1, data: { x: 0 } }, ]); - jest.useFakeTimers(); + vi.useFakeTimers(); try { const now = Date.now(); // Forward the system clock by 30 millis - jest.setSystemTime(now + 30); + vi.setSystemTime(now + 30); room.updatePresence({ x: 1 }); - jest.setSystemTime(now + 35); + vi.setSystemTime(now + 35); room.updatePresence({ x: 2 }); // These calls should get batched and flushed later - await jest.advanceTimersByTimeAsync(0); + await vi.advanceTimersByTimeAsync(0); expect(wss.receivedMessages.length).toBe(1); // Still no new data received expect(room[kInternal].presenceBuffer).toEqual({ x: 2 }); // Forwarding time by the flush threshold will trigger the future flush - await jest.advanceTimersByTimeAsync(THROTTLE_DELAY); + await vi.advanceTimersByTimeAsync(THROTTLE_DELAY); expect(wss.receivedMessages.length).toBe(2); expect(wss.receivedMessages[1]).toEqual([ { type: ClientMsgCode.UPDATE_PRESENCE, data: { x: 2 } }, ]); } finally { - jest.useRealTimers(); + vi.useRealTimers(); } }); @@ -888,19 +898,19 @@ describe("room", () => { ]); const now = Date.now(); - jest.useFakeTimers(); + vi.useFakeTimers(); try { // Event payload can be any JSON value - jest.setSystemTime(now + 1000); + vi.setSystemTime(now + 1000); room.broadcastEvent({ type: "EVENT" }); - jest.setSystemTime(now + 2000); + vi.setSystemTime(now + 2000); room.broadcastEvent([1, 2, 3]); - jest.setSystemTime(now + 3000); + vi.setSystemTime(now + 3000); room.broadcastEvent(42); - jest.setSystemTime(now + 4000); + vi.setSystemTime(now + 4000); room.broadcastEvent("hi"); } finally { - jest.useRealTimers(); + vi.useRealTimers(); } expect(wss.receivedMessages[1]).toEqual([ @@ -1349,7 +1359,7 @@ describe("room", () => { test("batch my-presence", () => { const { room } = createTestableRoom({}); - const callback = jest.fn(); + const callback = vi.fn(); room.events.myPresence.subscribe(callback); @@ -1378,8 +1388,8 @@ describe("room", () => { const storage = await room.getStorage(); - const presenceSubscriber = jest.fn(); - const storageRootSubscriber = jest.fn(); + const presenceSubscriber = vi.fn(); + const storageRootSubscriber = vi.fn(); room.subscribe("my-presence", presenceSubscriber); room.subscribe(storage.root, storageRootSubscriber); @@ -1565,7 +1575,7 @@ describe("room", () => { test("batch history", () => { const { room } = createTestableRoom({}); - const callback = jest.fn(); + const callback = vi.fn(); room.events.history.subscribe(callback); room.batch(() => { @@ -1580,7 +1590,7 @@ describe("room", () => { test("my-presence", () => { const { room } = createTestableRoom({}); - const callback = jest.fn(); + const callback = vi.fn(); const unsubscribe = room.events.myPresence.subscribe(callback); room.updatePresence({ x: 0 }); @@ -1696,7 +1706,7 @@ describe("room", () => { ); }); - const callback = jest.fn(); + const callback = vi.fn(); room.events.customEvent.subscribe(callback); await waitUntilCustomEvent(room); @@ -1746,7 +1756,7 @@ describe("room", () => { ); }); - const callback = jest.fn(); + const callback = vi.fn(); room.events.customEvent.subscribe(callback); await waitUntilCustomEvent(room); @@ -1763,7 +1773,7 @@ describe("room", () => { test("history", () => { const { room } = createTestableRoom({}); - const callback = jest.fn(); + const callback = vi.fn(); const unsubscribe = room.events.history.subscribe(callback); room.updatePresence({ x: 0 }, { addToHistory: true }); @@ -1954,7 +1964,7 @@ describe("room", () => { expect(room.getStorageStatus()).toBe("synchronized"); - const storageStatusCallback = jest.fn(); + const storageStatusCallback = vi.fn(); room.events.storageStatus.subscribe(storageStatusCallback); @@ -1991,10 +2001,10 @@ describe("room", () => { }); describe("reconnect", () => { - let consoleWarnSpy: jest.SpyInstance; + let consoleWarnSpy: any; beforeEach(() => { - consoleWarnSpy = jest.spyOn(console, "warn").mockImplementation(() => {}); + consoleWarnSpy = vi.spyOn(console, "warn").mockImplementation(() => {}); }); afterEach(() => { @@ -2017,19 +2027,19 @@ describe("room", () => { await waitUntilStatus(room, "connecting"); - jest.useFakeTimers(); + vi.useFakeTimers(); try { - await jest.advanceTimersByTimeAsync(0); + await vi.advanceTimersByTimeAsync(0); expect(consoleWarnSpy).toHaveBeenCalledWith( "Connection to Liveblocks websocket server closed prematurely (code: 1006). Retrying in 250ms." ); expect(wss.connections.size).toBe(1); // A new connection attempt will be made after a short backoff delay - await jest.advanceTimersByTimeAsync(250); + await vi.advanceTimersByTimeAsync(250); expect(wss.connections.size).toBe(2); } finally { - jest.useRealTimers(); + vi.useRealTimers(); } }); @@ -2051,21 +2061,21 @@ describe("room", () => { await waitUntilStatus(room, "connecting"); - jest.useFakeTimers(); + vi.useFakeTimers(); try { - await jest.advanceTimersByTimeAsync(0); + await vi.advanceTimersByTimeAsync(0); await waitUntilStatus(room, "connected"); - await jest.advanceTimersByTimeAsync(1111); + await vi.advanceTimersByTimeAsync(1111); expect(consoleWarnSpy).toHaveBeenCalledWith( "Connection to Liveblocks websocket server closed (code: 1006). Retrying in 250ms." ); expect(wss.connections.size).toBe(1); // A new connection attempt will be made after a short backoff delay - await jest.advanceTimersByTimeAsync(250); + await vi.advanceTimersByTimeAsync(250); expect(wss.connections.size).toBe(2); } finally { - jest.useRealTimers(); + vi.useRealTimers(); } }); @@ -2088,15 +2098,15 @@ describe("room", () => { await waitUntilStatus(room, "connecting"); - jest.useFakeTimers(); + vi.useFakeTimers(); try { - await jest.advanceTimersByTimeAsync(0); + await vi.advanceTimersByTimeAsync(0); await waitUntilStatus(room, "disconnected"); expect(wss.connections.size).toBe(1); expect(err.message).toEqual("whatever"); expect(err.context.code).toEqual(4042); } finally { - jest.useRealTimers(); + vi.useRealTimers(); } }); @@ -2122,18 +2132,18 @@ describe("room", () => { await waitUntilStatus(room, "connecting"); - jest.useFakeTimers(); + vi.useFakeTimers(); try { - await jest.advanceTimersByTimeAsync(0); + await vi.advanceTimersByTimeAsync(0); await waitUntilStatus(room, "connected"); - await jest.advanceTimersByTimeAsync(1111); + await vi.advanceTimersByTimeAsync(1111); await waitUntilStatus(room, "disconnected"); expect(wss.connections.size).toBe(1); expect(err.message).toEqual("whatever"); expect(err.context.code).toEqual(4042); } finally { - jest.useRealTimers(); + vi.useRealTimers(); } }); @@ -2152,9 +2162,9 @@ describe("room", () => { await waitUntilStatus(room, "connecting"); - jest.useFakeTimers(); + vi.useFakeTimers(); try { - await jest.advanceTimersByTimeAsync(0); + await vi.advanceTimersByTimeAsync(0); expect(consoleWarnSpy).toHaveBeenCalledWith( "Connection to Liveblocks websocket server closed prematurely (code: 1013). Retrying in 2000ms." ); @@ -2162,12 +2172,12 @@ describe("room", () => { expect(wss.connections.size).toBe(1); // A new connection attempt will be made after a longer backoff delay - await jest.advanceTimersByTimeAsync(500); // Waiting our normal short delay isn't enough here... + await vi.advanceTimersByTimeAsync(500); // Waiting our normal short delay isn't enough here... expect(wss.connections.size).toBe(1); - await jest.advanceTimersByTimeAsync(1500); // Wait an additional 1500 seconds + await vi.advanceTimersByTimeAsync(1500); // Wait an additional 1500 seconds expect(wss.connections.size).toBe(2); } finally { - jest.useRealTimers(); + vi.useRealTimers(); } }); @@ -2189,23 +2199,23 @@ describe("room", () => { await waitUntilStatus(room, "connecting"); - jest.useFakeTimers(); + vi.useFakeTimers(); try { - await jest.advanceTimersByTimeAsync(0); + await vi.advanceTimersByTimeAsync(0); await waitUntilStatus(room, "connected"); - await jest.advanceTimersByTimeAsync(1111); + await vi.advanceTimersByTimeAsync(1111); expect(consoleWarnSpy).toHaveBeenCalledWith( "Connection to Liveblocks websocket server closed (code: 1013). Retrying in 2000ms." ); expect(wss.connections.size).toBe(1); // A new connection attempt will be made after a LONG backoff delay - await jest.advanceTimersByTimeAsync(500); // Waiting our normal short delay isn't enough here... + await vi.advanceTimersByTimeAsync(500); // Waiting our normal short delay isn't enough here... expect(wss.connections.size).toBe(1); - await jest.advanceTimersByTimeAsync(1500); // Wait an additional 1500 seconds (for a total of 2000ms) + await vi.advanceTimersByTimeAsync(1500); // Wait an additional 1500 seconds (for a total of 2000ms) expect(wss.connections.size).toBe(2); } finally { - jest.useRealTimers(); + vi.useRealTimers(); } }); @@ -2224,9 +2234,9 @@ describe("room", () => { await waitUntilStatus(room, "connecting"); - jest.useFakeTimers(); + vi.useFakeTimers(); try { - await jest.advanceTimersByTimeAsync(0); + await vi.advanceTimersByTimeAsync(0); expect(consoleWarnSpy).toHaveBeenCalledWith( "Connection to Liveblocks websocket server closed prematurely (code: 4142). Retrying in 250ms." ); @@ -2234,10 +2244,10 @@ describe("room", () => { expect(wss.connections.size).toBe(1); // A new connection attempt will be made after a normal backoff delay - await jest.advanceTimersByTimeAsync(250); + await vi.advanceTimersByTimeAsync(250); expect(wss.connections.size).toBe(2); } finally { - jest.useRealTimers(); + vi.useRealTimers(); } }); @@ -2259,21 +2269,21 @@ describe("room", () => { await waitUntilStatus(room, "connecting"); - jest.useFakeTimers(); + vi.useFakeTimers(); try { - await jest.advanceTimersByTimeAsync(0); + await vi.advanceTimersByTimeAsync(0); await waitUntilStatus(room, "connected"); - await jest.advanceTimersByTimeAsync(1111); + await vi.advanceTimersByTimeAsync(1111); expect(consoleWarnSpy).toHaveBeenCalledWith( "Connection to Liveblocks websocket server closed (code: 4142). Retrying in 250ms." ); expect(wss.connections.size).toBe(1); // A new connection attempt will be made after a normal backoff delay - await jest.advanceTimersByTimeAsync(250); + await vi.advanceTimersByTimeAsync(250); expect(wss.connections.size).toBe(2); } finally { - jest.useRealTimers(); + vi.useRealTimers(); } }); @@ -2292,12 +2302,12 @@ describe("room", () => { await waitUntilStatus(room, "connecting"); - jest.useFakeTimers(); + vi.useFakeTimers(); try { - await jest.advanceTimersByTimeAsync(0); + await vi.advanceTimersByTimeAsync(0); expect(wss.connections.size).toBe(2); // Instantly gets a new token, no backoff } finally { - jest.useRealTimers(); + vi.useRealTimers(); } }); @@ -2319,16 +2329,16 @@ describe("room", () => { await waitUntilStatus(room, "connecting"); - jest.useFakeTimers(); + vi.useFakeTimers(); try { - await jest.advanceTimersByTimeAsync(0); + await vi.advanceTimersByTimeAsync(0); await waitUntilStatus(room, "connected"); - await jest.advanceTimersByTimeAsync(1111); + await vi.advanceTimersByTimeAsync(1111); // Instantly gets a new token (no backoff) expect(wss.connections.size).toBe(2); } finally { - jest.useRealTimers(); + vi.useRealTimers(); } }); @@ -2347,9 +2357,9 @@ describe("room", () => { await waitUntilStatus(room, "connecting"); - jest.useFakeTimers(); + vi.useFakeTimers(); try { - await jest.advanceTimersByTimeAsync(0); + await vi.advanceTimersByTimeAsync(0); expect(consoleWarnSpy).toHaveBeenCalledWith( "Connection to Liveblocks websocket server closed prematurely (code: 4242). Retrying in 2000ms." ); @@ -2357,12 +2367,12 @@ describe("room", () => { expect(wss.connections.size).toBe(1); // A new connection attempt will be made after a longer backoff delay - await jest.advanceTimersByTimeAsync(500); // Waiting our normal short delay isn't enough here... + await vi.advanceTimersByTimeAsync(500); // Waiting our normal short delay isn't enough here... expect(wss.connections.size).toBe(1); - await jest.advanceTimersByTimeAsync(1500); // Wait an additional 1500 seconds + await vi.advanceTimersByTimeAsync(1500); // Wait an additional 1500 seconds expect(wss.connections.size).toBe(2); } finally { - jest.useRealTimers(); + vi.useRealTimers(); } }); @@ -2384,28 +2394,28 @@ describe("room", () => { await waitUntilStatus(room, "connecting"); - jest.useFakeTimers(); + vi.useFakeTimers(); try { - await jest.advanceTimersByTimeAsync(0); + await vi.advanceTimersByTimeAsync(0); await waitUntilStatus(room, "connected"); - await jest.advanceTimersByTimeAsync(1111); + await vi.advanceTimersByTimeAsync(1111); expect(consoleWarnSpy).toHaveBeenCalledWith( "Connection to Liveblocks websocket server closed (code: 4242). Retrying in 2000ms." ); expect(wss.connections.size).toBe(1); // A new connection attempt will be made after a LONG backoff delay - await jest.advanceTimersByTimeAsync(500); // Waiting our normal short delay isn't enough here... + await vi.advanceTimersByTimeAsync(500); // Waiting our normal short delay isn't enough here... expect(wss.connections.size).toBe(1); - await jest.advanceTimersByTimeAsync(1500); // Wait an additional 1500 seconds (for a total of 2000ms) + await vi.advanceTimersByTimeAsync(1500); // Wait an additional 1500 seconds (for a total of 2000ms) expect(wss.connections.size).toBe(2); } finally { - jest.useRealTimers(); + vi.useRealTimers(); } }); test("manual reconnection", async () => { - jest.useFakeTimers(); + vi.useFakeTimers(); try { const { room, wss } = createTestableRoom( { x: 0 }, @@ -2416,7 +2426,7 @@ describe("room", () => { room.connect(); expect(room.getStatus()).toEqual("connecting"); - await jest.advanceTimersByTimeAsync(0); // Resolve the auth promise, which will then start the socket connection + await vi.advanceTimersByTimeAsync(0); // Resolve the auth promise, which will then start the socket connection const ws1 = wss.last; ws1.accept(); @@ -2434,9 +2444,9 @@ describe("room", () => { room.reconnect(); expect(room.getStatus()).toEqual("connecting"); - await jest.advanceTimersByTimeAsync(0); // There's a backoff delay here! + await vi.advanceTimersByTimeAsync(0); // There's a backoff delay here! expect(room.getStatus()).toEqual("connecting"); - await jest.advanceTimersByTimeAsync(500); // Wait for the increased backoff delay! + await vi.advanceTimersByTimeAsync(500); // Wait for the increased backoff delay! expect(room.getStatus()).toEqual("connecting"); const ws2 = wss.last; @@ -2457,7 +2467,7 @@ describe("room", () => { await waitUntilStatus(room, "connected"); expect(room.getStatus()).toEqual("connected"); } finally { - jest.useRealTimers(); + vi.useRealTimers(); } }); }); diff --git a/packages/liveblocks-core/src/comments/__tests__/comment-body.test.ts b/packages/liveblocks-core/src/comments/__tests__/comment-body.test.ts index 2fc55fb7948..ec8a15c4b3b 100644 --- a/packages/liveblocks-core/src/comments/__tests__/comment-body.test.ts +++ b/packages/liveblocks-core/src/comments/__tests__/comment-body.test.ts @@ -1,3 +1,5 @@ +import { describe, expect, test, vi } from "vitest"; + import type { ResolveUsersArgs } from "../../client"; import type { CommentBody } from "../../protocol/Comments"; import { @@ -333,7 +335,7 @@ describe("stringifyCommentBody", () => { ); }); - it("should escape html entities - mention w/ username", async () => { + test("should escape html entities - mention w/ username", async () => { const commentBodyHtml: CommentBody = { version: 1, content: [ @@ -506,10 +508,10 @@ describe("stringifyCommentBody", () => { }); test("provides arguments to custom elements", async () => { - const paragraph = jest.fn(); - const text = jest.fn(); - const link = jest.fn(); - const mention = jest.fn(); + const paragraph = vi.fn(); + const text = vi.fn(); + const link = vi.fn(); + const mention = vi.fn(); await stringifyCommentBody(commentBodyWithMultipleParagraphs, { elements: { diff --git a/packages/liveblocks-core/src/crdts/__tests__/AuthToken.test.ts b/packages/liveblocks-core/src/crdts/__tests__/AuthToken.test.ts index ad915df98a1..c753ba8b5b9 100644 --- a/packages/liveblocks-core/src/crdts/__tests__/AuthToken.test.ts +++ b/packages/liveblocks-core/src/crdts/__tests__/AuthToken.test.ts @@ -1,3 +1,5 @@ +import { describe, expect, test } from "vitest"; + import { parseAuthToken } from "../../protocol/AuthToken"; describe("parseRoomAuthToken", () => { diff --git a/packages/liveblocks-core/src/crdts/__tests__/LiveList.test.ts b/packages/liveblocks-core/src/crdts/__tests__/LiveList.test.ts index d69d69f747f..d8e4bf980d6 100644 --- a/packages/liveblocks-core/src/crdts/__tests__/LiveList.test.ts +++ b/packages/liveblocks-core/src/crdts/__tests__/LiveList.test.ts @@ -1,3 +1,5 @@ +import { describe, expect, test, vi } from "vitest"; + import { listUpdate, listUpdateDelete, @@ -34,7 +36,7 @@ import { LiveObject } from "../LiveObject"; describe("LiveList", () => { describe("not attached", () => { - it("basic operations with native objects", () => { + test("basic operations with native objects", () => { const list = new LiveList(["first", "second", "third"]); expect(list.get(0)).toEqual("first"); expect(list.length).toBe(3); @@ -73,7 +75,7 @@ describe("LiveList", () => { }); describe("deserialization", () => { - it("create document with list in root", async () => { + test("create document with list in root", async () => { const { expectStorage } = await prepareIsolatedStorageTest<{ items: LiveList; }>([ @@ -86,7 +88,7 @@ describe("LiveList", () => { }); }); - it("init list with items", async () => { + test("init list with items", async () => { const { expectStorage } = await prepareIsolatedStorageTest<{ items: LiveList>; }>([ @@ -104,7 +106,7 @@ describe("LiveList", () => { }); describe("push", () => { - it("throws on read-only", async () => { + test("throws on read-only", async () => { const { storage } = await prepareStorageTest<{ items: LiveList; }>( @@ -125,7 +127,7 @@ describe("LiveList", () => { }); describe("updates", () => { - it("push on empty list update", async () => { + test("push on empty list update", async () => { const { root, expectUpdates, room } = await prepareStorageUpdateTest<{ items: LiveList; }>([ @@ -145,7 +147,7 @@ describe("LiveList", () => { }); }); - it("push LiveObject on empty list", async () => { + test("push LiveObject on empty list", async () => { const { storage, expectStorage, assertUndoRedo } = await prepareStorageTest<{ items: LiveList>; @@ -173,7 +175,7 @@ describe("LiveList", () => { assertUndoRedo(); }); - it("push number on empty list", async () => { + test("push number on empty list", async () => { const { storage, expectStorage, assertUndoRedo } = await prepareStorageTest<{ items: LiveList; @@ -196,7 +198,7 @@ describe("LiveList", () => { assertUndoRedo(); }); - it("push LiveMap on empty list", async () => { + test("push LiveMap on empty list", async () => { const { storage, expectStorage, assertUndoRedo } = await prepareStorageTest<{ items: LiveList>; @@ -220,7 +222,7 @@ describe("LiveList", () => { assertUndoRedo(); }); - it("push already attached LiveObject should throw", async () => { + test("push already attached LiveObject should throw", async () => { const { root } = await prepareIsolatedStorageTest<{ items: LiveList>; }>( @@ -241,7 +243,7 @@ describe("LiveList", () => { }); describe("insert", () => { - it("throws on read-only", async () => { + test("throws on read-only", async () => { const { storage } = await prepareStorageTest<{ items: LiveList; }>( @@ -262,7 +264,7 @@ describe("LiveList", () => { }); describe("updates", () => { - it("insert at the middle update", async () => { + test("insert at the middle update", async () => { const { root, expectUpdates, room } = await prepareStorageUpdateTest<{ items: LiveList; }>([ @@ -284,7 +286,7 @@ describe("LiveList", () => { }); }); - it("insert LiveObject at position 0", async () => { + test("insert LiveObject at position 0", async () => { const { storage, expectStorage, assertUndoRedo } = await prepareStorageTest<{ items: LiveList>; @@ -313,7 +315,7 @@ describe("LiveList", () => { }); describe("delete", () => { - it("throws on read-only", async () => { + test("throws on read-only", async () => { const { storage } = await prepareStorageTest<{ items: LiveList; }>( @@ -334,7 +336,7 @@ describe("LiveList", () => { }); describe("updates", () => { - it("delete first update", async () => { + test("delete first update", async () => { const { root, expectUpdates, room } = await prepareStorageUpdateTest<{ items: LiveList; }>([ @@ -355,7 +357,7 @@ describe("LiveList", () => { }); }); - it("delete first item", async () => { + test("delete first item", async () => { const { storage, expectStorage, assertUndoRedo } = await prepareStorageTest<{ items: LiveList; @@ -382,7 +384,7 @@ describe("LiveList", () => { assertUndoRedo(); }); - it("delete should remove descendants", async () => { + test("delete should remove descendants", async () => { const { room, storage, expectStorage, assertUndoRedo } = await prepareStorageTest<{ items: LiveList }>>; @@ -411,7 +413,7 @@ describe("LiveList", () => { }); describe("move", () => { - it("throws on read-only", async () => { + test("throws on read-only", async () => { const { storage } = await prepareStorageTest<{ items: LiveList; }>( @@ -432,7 +434,7 @@ describe("LiveList", () => { }); describe("updates", () => { - it("move at the end update", async () => { + test("move at the end update", async () => { const { root, expectUpdates, room } = await prepareStorageUpdateTest<{ items: LiveList; }>([ @@ -454,7 +456,7 @@ describe("LiveList", () => { }); }); - it("move after current position", async () => { + test("move after current position", async () => { const { storage, expectStorage, assertUndoRedo } = await prepareStorageTest<{ items: LiveList; @@ -479,7 +481,7 @@ describe("LiveList", () => { assertUndoRedo(); }); - it("move before current position", async () => { + test("move before current position", async () => { const { storage, expectStorage, assertUndoRedo } = await prepareStorageTest<{ items: LiveList; @@ -508,7 +510,7 @@ describe("LiveList", () => { assertUndoRedo(); }); - it("move at the end of the list", async () => { + test("move at the end of the list", async () => { const { storage, expectStorage, assertUndoRedo } = await prepareStorageTest<{ items: LiveList; @@ -537,7 +539,7 @@ describe("LiveList", () => { }); describe("clear", () => { - it("throws on read-only", async () => { + test("throws on read-only", async () => { const { storage } = await prepareStorageTest<{ items: LiveList }>( [ createSerializedObject("0:0", {}), @@ -556,7 +558,7 @@ describe("LiveList", () => { }); describe("updates", () => { - it("clear updates", async () => { + test("clear updates", async () => { const { root, expectUpdates, room } = await prepareStorageUpdateTest<{ items: LiveList; }>([ @@ -594,7 +596,7 @@ describe("LiveList", () => { }); }); - it("clear should delete all items", async () => { + test("clear should delete all items", async () => { const { storage, expectStorage, assertUndoRedo } = await prepareStorageTest<{ items: LiveList; @@ -626,7 +628,7 @@ describe("LiveList", () => { }); describe("batch", () => { - it("batch multiple inserts", async () => { + test("batch multiple inserts", async () => { const { room, storage, expectStorage, assertUndoRedo } = await prepareStorageTest<{ items: LiveList; @@ -657,7 +659,7 @@ describe("LiveList", () => { }); describe("set", () => { - it("throws on read-only", async () => { + test("throws on read-only", async () => { const { storage } = await prepareStorageTest<{ items: LiveList }>( [ createSerializedObject("0:0", {}), @@ -675,13 +677,13 @@ describe("LiveList", () => { ); }); - it("set register on detached list", () => { + test("set register on detached list", () => { const list = new LiveList(["A", "B", "C"]); list.set(0, "D"); expect(list.toArray()).toEqual(["D", "B", "C"]); }); - it("set at invalid position should throw", () => { + test("set at invalid position should throw", () => { const list = new LiveList(["A", "B", "C"]); expect(() => list.set(-1, "D")).toThrow( 'Cannot set list item at index "-1". index should be between 0 and 2' @@ -691,7 +693,7 @@ describe("LiveList", () => { ); }); - it("set register", async () => { + test("set register", async () => { const { storage, expectStorage, assertUndoRedo } = await prepareStorageTest<{ items: LiveList; @@ -720,7 +722,7 @@ describe("LiveList", () => { assertUndoRedo(); }); - it("set nested object", async () => { + test("set nested object", async () => { const { storage, expectStorage, assertUndoRedo } = await prepareStorageTest<{ items: LiveList>; @@ -746,7 +748,7 @@ describe("LiveList", () => { }); describe("conflict", () => { - it("list conflicts", async () => { + test("list conflicts", async () => { const { root, expectStorage, applyRemoteOperations } = await prepareIsolatedStorageTest<{ items: LiveList }>( [ @@ -789,7 +791,7 @@ describe("LiveList", () => { }); }); - it("list conflicts 2", async () => { + test("list conflicts 2", async () => { const { root, applyRemoteOperations, expectStorage } = await prepareIsolatedStorageTest<{ items: LiveList }>( [ @@ -859,7 +861,7 @@ describe("LiveList", () => { }); }); - it("list conflicts with offline", async () => { + test("list conflicts with offline", async () => { const { room, root, expectStorage, applyRemoteOperations, wss } = await prepareIsolatedStorageTest<{ items: LiveList }>( [ @@ -903,7 +905,7 @@ describe("LiveList", () => { }); }); - it("list conflicts with undo redo and remote change", async () => { + test("list conflicts with undo redo and remote change", async () => { const { root, expectStorage, applyRemoteOperations, room, wss } = await prepareIsolatedStorageTest<{ items: LiveList }>( [ @@ -947,7 +949,7 @@ describe("LiveList", () => { expectStorage({ items: ["1", "0"] }); }); - it("list conflicts - move", async () => { + test("list conflicts - move", async () => { const { root, expectStorage, applyRemoteOperations } = await prepareIsolatedStorageTest<{ items: LiveList }>( [ @@ -1001,7 +1003,7 @@ describe("LiveList", () => { }); }); - it("list conflicts - ack has different position that local item", async () => { + test("list conflicts - ack has different position that local item", async () => { const { root, expectStorage, applyRemoteOperations } = await prepareIsolatedStorageTest<{ items: LiveList }>( [ @@ -1078,7 +1080,7 @@ describe("LiveList", () => { }); }); - it("list conflicts - ack has different position that local and ack position is used", async () => { + test("list conflicts - ack has different position that local and ack position is used", async () => { const { root, expectStorage, applyRemoteOperations } = await prepareIsolatedStorageTest<{ items: LiveList }>( [ @@ -1148,7 +1150,7 @@ describe("LiveList", () => { 1 ); - const callback = jest.fn(); + const callback = vi.fn(); room.events.storageBatch.subscribe(callback); const root = storage.root; @@ -1186,7 +1188,7 @@ describe("LiveList", () => { 1 ); - const callback = jest.fn(); + const callback = vi.fn(); room.events.storageBatch.subscribe(callback); const root = storage.root; @@ -1217,9 +1219,9 @@ describe("LiveList", () => { 1 ); - const rootCallback = jest.fn(); - const rootDeepCallback = jest.fn(); - const listCallback = jest.fn(); + const rootCallback = vi.fn(); + const rootDeepCallback = vi.fn(); + const listCallback = vi.fn(); const listItems = root.get("items"); @@ -1300,9 +1302,9 @@ describe("LiveList", () => { 1 ); - const rootCallback = jest.fn(); - const rootDeepCallback = jest.fn(); - const listCallback = jest.fn(); + const rootCallback = vi.fn(); + const rootDeepCallback = vi.fn(); + const listCallback = vi.fn(); const listItems = root.get("items"); @@ -1371,9 +1373,9 @@ describe("LiveList", () => { 1 ); - const rootCallback = jest.fn(); - const rootDeepCallback = jest.fn(); - const listCallback = jest.fn(); + const rootCallback = vi.fn(); + const rootDeepCallback = vi.fn(); + const listCallback = vi.fn(); const listItems = root.get("items"); @@ -1459,7 +1461,7 @@ describe("LiveList", () => { }); describe("apply CreateRegister", () => { - it('with intent "set" should replace existing item', async () => { + test('with intent "set" should replace existing item', async () => { const { expectStorage, applyRemoteOperations } = await prepareIsolatedStorageTest<{ items: LiveList }>( [ @@ -1490,7 +1492,7 @@ describe("LiveList", () => { }); }); - it('with intent "set" should notify with a "set" update', async () => { + test('with intent "set" should notify with a "set" update', async () => { const { room, root, applyRemoteOperations } = await prepareIsolatedStorageTest<{ items: LiveList }>( [ @@ -1503,7 +1505,7 @@ describe("LiveList", () => { const items = root.get("items"); - const callback = jest.fn(); + const callback = vi.fn(); room.events.storageBatch.subscribe(callback); applyRemoteOperations([ @@ -1526,7 +1528,7 @@ describe("LiveList", () => { ]); }); - it('with intent "set" should insert item if conflict with a delete operation', async () => { + test('with intent "set" should insert item if conflict with a delete operation', async () => { const { root, expectStorage, applyRemoteOperations } = await prepareIsolatedStorageTest<{ items: LiveList }>( [ @@ -1565,7 +1567,7 @@ describe("LiveList", () => { }); }); - it('with intent "set" should notify with a "insert" update if no item exists at this position', async () => { + test('with intent "set" should notify with a "insert" update if no item exists at this position', async () => { const { room, root, applyRemoteOperations } = await prepareIsolatedStorageTest<{ items: LiveList }>( [ @@ -1579,7 +1581,7 @@ describe("LiveList", () => { const items = root.get("items"); items.delete(0); - const callback = jest.fn(); + const callback = vi.fn(); room.subscribe(items, callback, { isDeep: true }); applyRemoteOperations([ @@ -1602,7 +1604,7 @@ describe("LiveList", () => { ]); }); - it("on existing position should give the right update", async () => { + test("on existing position should give the right update", async () => { const { room, root, expectStorage, applyRemoteOperations } = await prepareIsolatedStorageTest<{ items: LiveList }>( [ @@ -1621,7 +1623,7 @@ describe("LiveList", () => { items: ["0"], }); - const callback = jest.fn(); + const callback = vi.fn(); room.subscribe(items, callback, { isDeep: true }); applyRemoteOperations([ diff --git a/packages/liveblocks-core/src/crdts/__tests__/LiveMap.test.ts b/packages/liveblocks-core/src/crdts/__tests__/LiveMap.test.ts index 4ce96f43dfc..7b0ff6965c7 100644 --- a/packages/liveblocks-core/src/crdts/__tests__/LiveMap.test.ts +++ b/packages/liveblocks-core/src/crdts/__tests__/LiveMap.test.ts @@ -1,3 +1,5 @@ +import { describe, expect, test, vi } from "vitest"; + import { createSerializedList, createSerializedMap, @@ -19,7 +21,7 @@ import { LiveObject } from "../LiveObject"; describe("LiveMap", () => { describe("not attached", () => { - it("basic operations with LiveObjects", () => { + test("basic operations with LiveObjects", () => { const map = new LiveMap([["first" as string, new LiveObject({ a: 0 })]]); expect(map.get("first")?.get("a")).toBe(0); @@ -58,7 +60,7 @@ describe("LiveMap", () => { expect(asArray[1][1].get("a")).toBe(2); }); - it("basic operations with native objects", () => { + test("basic operations with native objects", () => { const map = new LiveMap([["first", { a: 0 }]]); expect(map.get("first")).toEqual({ a: 0 }); @@ -94,7 +96,7 @@ describe("LiveMap", () => { }); }); - it("create document with map in root", async () => { + test("create document with map in root", async () => { const { storage, expectStorage } = await prepareStorageTest<{ map: LiveMap>; }>([ @@ -108,7 +110,7 @@ describe("LiveMap", () => { expectStorage({ map: new Map() }); }); - it("set throws on read-only", async () => { + test("set throws on read-only", async () => { const { storage } = await prepareStorageTest<{ map: LiveMap>; }>( @@ -126,7 +128,7 @@ describe("LiveMap", () => { ); }); - it("init map with items", async () => { + test("init map with items", async () => { const { storage, expectStorage } = await prepareStorageTest<{ map: LiveMap>; }>([ @@ -157,7 +159,7 @@ describe("LiveMap", () => { }); }); - it("map.set object", async () => { + test("map.set object", async () => { const { storage, expectStorage, assertUndoRedo } = await prepareStorageTest<{ map: LiveMap; @@ -200,7 +202,7 @@ describe("LiveMap", () => { }); describe("delete", () => { - it("throws on read-only", async () => { + test("throws on read-only", async () => { const { storage } = await prepareStorageTest<{ map: LiveMap; }>( @@ -218,7 +220,7 @@ describe("LiveMap", () => { ); }); - it("should delete LiveObject", async () => { + test("should delete LiveObject", async () => { const { storage, expectStorage, assertUndoRedo } = await prepareStorageTest<{ map: LiveMap; @@ -262,7 +264,7 @@ describe("LiveMap", () => { assertUndoRedo(); }); - it("should remove nested data structure from cache", async () => { + test("should remove nested data structure from cache", async () => { const { room, storage, expectStorage, assertUndoRedo } = await prepareStorageTest<{ map: LiveMap>; @@ -293,7 +295,7 @@ describe("LiveMap", () => { assertUndoRedo(); }); - it("should delete live list", async () => { + test("should delete live list", async () => { const { room, storage, expectStorage, assertUndoRedo } = await prepareStorageTest<{ map: LiveMap> }>( [ @@ -324,7 +326,7 @@ describe("LiveMap", () => { }); // https://github.com/liveblocks/liveblocks/issues/95 - it("should have deleted key when subscriber is called", async () => { + test("should have deleted key when subscriber is called", async () => { const { room, root } = await prepareIsolatedStorageTest<{ map: LiveMap; }>( @@ -348,7 +350,7 @@ describe("LiveMap", () => { expect(keys).toEqual(["second"]); }); - it("should call subscribe when key is deleted", async () => { + test("should call subscribe when key is deleted", async () => { const { room, root } = await prepareIsolatedStorageTest<{ map: LiveMap; }>( @@ -363,7 +365,7 @@ describe("LiveMap", () => { const map = root.get("map"); - const fn = jest.fn(); + const fn = vi.fn(); room.subscribe(map, fn); @@ -373,7 +375,7 @@ describe("LiveMap", () => { expect(fn.mock.calls[0][0]).toBe(map); }); - it("should not call subscribe when key is not deleted", async () => { + test("should not call subscribe when key is not deleted", async () => { const { room, root } = await prepareIsolatedStorageTest<{ map: LiveMap; }>( @@ -388,7 +390,7 @@ describe("LiveMap", () => { const map = root.get("map"); - const fn = jest.fn(); + const fn = vi.fn(); room.subscribe(map, fn); @@ -398,7 +400,7 @@ describe("LiveMap", () => { }); }); - it("map.set live object", async () => { + test("map.set live object", async () => { const { storage, expectStorage, assertUndoRedo } = await prepareStorageTest<{ map: LiveMap>; @@ -425,7 +427,7 @@ describe("LiveMap", () => { assertUndoRedo(); }); - it("map.set already attached live object should throw", async () => { + test("map.set already attached live object should throw", async () => { const { storage } = await prepareStorageTest<{ map: LiveMap>; }>([ @@ -442,7 +444,7 @@ describe("LiveMap", () => { expect(() => map.set("second", object)).toThrow(); }); - it("new Map with already attached live object should throw", async () => { + test("new Map with already attached live object should throw", async () => { const { storage } = await prepareStorageTest<{ child: LiveObject<{ a: number }> | null; map: LiveMap> | null; @@ -455,7 +457,7 @@ describe("LiveMap", () => { expect(() => new LiveMap([["first", child]])).toThrow(); }); - it("map.set live object on existing key", async () => { + test("map.set live object on existing key", async () => { const { storage, expectStorage, assertUndoRedo } = await prepareStorageTest<{ map: LiveMap>; @@ -484,7 +486,7 @@ describe("LiveMap", () => { assertUndoRedo(); }); - it("attach map with items to root", async () => { + test("attach map with items to root", async () => { const { storage, expectStorage, assertUndoRedo } = await prepareStorageTest<{ map?: LiveMap; @@ -501,7 +503,7 @@ describe("LiveMap", () => { assertUndoRedo(); }); - it("attach map with live objects to root", async () => { + test("attach map with live objects to root", async () => { const { storage, expectStorage, assertUndoRedo } = await prepareStorageTest<{ map?: LiveMap>; @@ -518,7 +520,7 @@ describe("LiveMap", () => { assertUndoRedo(); }); - it("attach map with objects to root", async () => { + test("attach map with objects to root", async () => { const { storage, expectStorage, assertUndoRedo } = await prepareStorageTest<{ map?: LiveMap; @@ -535,7 +537,7 @@ describe("LiveMap", () => { assertUndoRedo(); }); - it("add list in map", async () => { + test("add list in map", async () => { const { storage, expectStorage, assertUndoRedo } = await prepareStorageTest<{ map: LiveMap>; @@ -559,7 +561,7 @@ describe("LiveMap", () => { assertUndoRedo(); }); - it("add map in map", async () => { + test("add map in map", async () => { const { storage, expectStorage, assertUndoRedo } = await prepareStorageTest<{ map: LiveMap>; @@ -595,7 +597,7 @@ describe("LiveMap", () => { 1 ); - const callback = jest.fn(); + const callback = vi.fn(); const root = storage.root; @@ -621,7 +623,7 @@ describe("LiveMap", () => { 1 ); - const callback = jest.fn(); + const callback = vi.fn(); const root = storage.root; const mapElement = root.get("map").get("mapElement"); @@ -661,8 +663,8 @@ describe("LiveMap", () => { 1 ); - const rootDeepCallback = jest.fn(); - const mapCallback = jest.fn(); + const rootDeepCallback = vi.fn(); + const mapCallback = vi.fn(); const listItems = root.get("map"); diff --git a/packages/liveblocks-core/src/crdts/__tests__/LiveObject.test.ts b/packages/liveblocks-core/src/crdts/__tests__/LiveObject.test.ts index d5d53a92c6f..30aac75cdef 100644 --- a/packages/liveblocks-core/src/crdts/__tests__/LiveObject.test.ts +++ b/packages/liveblocks-core/src/crdts/__tests__/LiveObject.test.ts @@ -1,3 +1,5 @@ +import { afterEach, beforeAll, describe, expect, test, vi } from "vitest"; + import { objectUpdate } from "../../__tests__/_updatesUtils"; import { createSerializedList, @@ -18,11 +20,11 @@ import { LiveObject } from "../LiveObject"; describe("LiveObject", () => { describe("roomId", () => { - it("should be null for orphan", () => { + test("should be null for orphan", () => { expect(new LiveObject().roomId).toBeNull(); }); - it("should be the associated room id if attached", async () => { + test("should be the associated room id if attached", async () => { const { root } = await prepareIsolatedStorageTest( [createSerializedObject("root", {})], 1 @@ -31,7 +33,7 @@ describe("LiveObject", () => { expect(root.roomId).toBe("room-id"); }); - it("should be null after being detached", async () => { + test("should be null after being detached", async () => { const { root } = await prepareIsolatedStorageTest<{ child: LiveObject<{ a: number }>; }>( @@ -52,7 +54,7 @@ describe("LiveObject", () => { }); }); - it("update non existing property", async () => { + test("update non existing property", async () => { const { storage, expectStorage, assertUndoRedo } = await prepareStorageTest( [createSerializedObject("0:0", {})] ); @@ -67,7 +69,7 @@ describe("LiveObject", () => { assertUndoRedo(); }); - it("update non existing property with null", async () => { + test("update non existing property with null", async () => { const { storage, expectStorage, assertUndoRedo } = await prepareStorageTest( [createSerializedObject("0:0", {})] ); @@ -82,7 +84,7 @@ describe("LiveObject", () => { assertUndoRedo(); }); - it("update throws on read-only", async () => { + test("update throws on read-only", async () => { const { storage } = await prepareStorageTest( [createSerializedObject("0:0", { a: 0 })], 1, @@ -94,7 +96,7 @@ describe("LiveObject", () => { ); }); - it("update existing property", async () => { + test("update existing property", async () => { const { storage, expectStorage, assertUndoRedo } = await prepareStorageTest( [createSerializedObject("0:0", { a: 0 })] ); @@ -109,7 +111,7 @@ describe("LiveObject", () => { assertUndoRedo(); }); - it("update existing property with null", async () => { + test("update existing property with null", async () => { const { storage, expectStorage, assertUndoRedo } = await prepareStorageTest( [createSerializedObject("0:0", { a: 0 })] ); @@ -124,7 +126,7 @@ describe("LiveObject", () => { assertUndoRedo(); }); - it("update root", async () => { + test("update root", async () => { const { storage, expectStorage, assertUndoRedo } = await prepareStorageTest( [createSerializedObject("0:0", { a: 0 })] ); @@ -147,7 +149,7 @@ describe("LiveObject", () => { assertUndoRedo(); }); - it("set throws on read-only", async () => { + test("set throws on read-only", async () => { const { storage } = await prepareStorageTest( [createSerializedObject("0:0", {})], 1, @@ -159,7 +161,7 @@ describe("LiveObject", () => { ); }); - it("update with LiveObject", async () => { + test("update with LiveObject", async () => { const { room, storage, expectStorage, operations, assertUndoRedo } = await prepareStorageTest<{ child: LiveObject<{ a: number }> | null }>( [createSerializedObject("0:0", { child: null })], @@ -219,7 +221,7 @@ describe("LiveObject", () => { assertUndoRedo(); }); - it("remove nested grand child record with update", async () => { + test("remove nested grand child record with update", async () => { const { room, storage, expectStorage, assertUndoRedo } = await prepareStorageTest<{ a: number; @@ -254,7 +256,7 @@ describe("LiveObject", () => { assertUndoRedo(); }); - it("remove nested child record with update", async () => { + test("remove nested child record with update", async () => { const { room, storage, expectStorage, assertUndoRedo } = await prepareStorageTest<{ a: number; @@ -282,7 +284,7 @@ describe("LiveObject", () => { assertUndoRedo(); }); - it("add nested record with update", async () => { + test("add nested record with update", async () => { const { room, storage, expectStorage, assertUndoRedo } = await prepareStorageTest([createSerializedObject("0:0", {})], 1); @@ -303,7 +305,7 @@ describe("LiveObject", () => { assertUndoRedo(); }); - it("replace nested record with update", async () => { + test("replace nested record with update", async () => { const { room, storage, expectStorage, assertUndoRedo } = await prepareStorageTest([createSerializedObject("0:0", {})], 1); @@ -334,7 +336,7 @@ describe("LiveObject", () => { assertUndoRedo(); }); - it("update nested record", async () => { + test("update nested record", async () => { const { storage, expectStorage, assertUndoRedo } = await prepareStorageTest<{ a: number; @@ -365,7 +367,7 @@ describe("LiveObject", () => { assertUndoRedo(); }); - it("update deeply nested record", async () => { + test("update deeply nested record", async () => { const { storage, expectStorage, assertUndoRedo } = await prepareStorageTest<{ a: number; @@ -410,7 +412,7 @@ describe("LiveObject", () => { }); describe("acknowledge mechanism", () => { - it("should not ignore history updates if the current op has not been acknowledged", async () => { + test("should not ignore history updates if the current op has not been acknowledged", async () => { const { room, root, expectUpdates } = await prepareDisconnectedStorageUpdateTest<{ items: LiveObject<{ b?: string; a?: string }>; @@ -480,7 +482,7 @@ describe("LiveObject", () => { expectStorage({ a: 1 }); }); - it("when value is a LiveObject", async () => { + test("when value is a LiveObject", async () => { const { root, expectStorage, applyRemoteOperations } = await prepareIsolatedStorageTest<{ a: LiveObject<{ subA: number }>; @@ -512,7 +514,7 @@ describe("LiveObject", () => { expectStorage({ a: { subA: 1 } }); }); - it("when value is a LiveList with LiveObjects", async () => { + test("when value is a LiveList with LiveObjects", async () => { const { root, expectStorage, applyRemoteOperations } = await prepareIsolatedStorageTest<{ a: LiveList>; @@ -548,7 +550,7 @@ describe("LiveObject", () => { }); describe("delete", () => { - it("throws on read-only", async () => { + test("throws on read-only", async () => { const { storage } = await prepareStorageTest<{ child: LiveObject<{ a: number }>; }>( @@ -565,13 +567,13 @@ describe("LiveObject", () => { ); }); - it("detached", () => { + test("detached", () => { const liveObject = new LiveObject({ a: 0 }); liveObject.delete("a"); expect(liveObject.get("a")).toBe(undefined); }); - it("should delete property from the object", async () => { + test("should delete property from the object", async () => { const { storage, expectStorage, assertUndoRedo } = await prepareStorageTest<{ a?: number; @@ -584,7 +586,7 @@ describe("LiveObject", () => { assertUndoRedo(); }); - it("should delete nested crdt", async () => { + test("should delete nested crdt", async () => { const { storage, expectStorage, assertUndoRedo } = await prepareStorageTest<{ child?: LiveObject<{ a: number }>; @@ -601,12 +603,12 @@ describe("LiveObject", () => { assertUndoRedo(); }); - it("should not notify if property does not exist", async () => { + test("should not notify if property does not exist", async () => { const { room, root } = await prepareIsolatedStorageTest<{ a?: number; }>([createSerializedObject("0:0", {})]); - const callback = jest.fn(); + const callback = vi.fn(); room.subscribe(root, callback); root.delete("a"); @@ -614,12 +616,12 @@ describe("LiveObject", () => { expect(callback).toHaveBeenCalledTimes(0); }); - it("should notify if property has been deleted", async () => { + test("should notify if property has been deleted", async () => { const { room, root } = await prepareIsolatedStorageTest<{ a?: number; }>([createSerializedObject("0:0", { a: 1 })]); - const callback = jest.fn(); + const callback = vi.fn(); room.subscribe(root, callback); root.delete("a"); @@ -629,13 +631,13 @@ describe("LiveObject", () => { }); describe("applyDeleteObjectKey", () => { - it("should not notify if property does not exist", async () => { + test("should not notify if property does not exist", async () => { const { room, root, applyRemoteOperations } = await prepareIsolatedStorageTest<{ a?: number }>([ createSerializedObject("0:0", {}), ]); - const callback = jest.fn(); + const callback = vi.fn(); room.subscribe(root, callback); applyRemoteOperations([ @@ -645,13 +647,13 @@ describe("LiveObject", () => { expect(callback).toHaveBeenCalledTimes(0); }); - it("should notify if property has been deleted", async () => { + test("should notify if property has been deleted", async () => { const { room, root, applyRemoteOperations } = await prepareIsolatedStorageTest<{ a?: number }>([ createSerializedObject("0:0", { a: 1 }), ]); - const callback = jest.fn(); + const callback = vi.fn(); room.subscribe(root, callback); applyRemoteOperations([ @@ -669,7 +671,7 @@ describe("LiveObject", () => { 1 ); - const callback = jest.fn(); + const callback = vi.fn(); const root = storage.root; @@ -694,7 +696,7 @@ describe("LiveObject", () => { 1 ); - const callback = jest.fn(); + const callback = vi.fn(); const root = storage.root; @@ -724,7 +726,7 @@ describe("LiveObject", () => { 1 ); - const callback = jest.fn(); + const callback = vi.fn(); const root = storage.root; @@ -770,7 +772,7 @@ describe("LiveObject", () => { 1 ); - const callback = jest.fn(); + const callback = vi.fn(); const root = storage.root; @@ -824,7 +826,7 @@ describe("LiveObject", () => { 1 ); - const callback = jest.fn(); + const callback = vi.fn(); const root = storage.root; @@ -867,7 +869,7 @@ describe("LiveObject", () => { 1 ); - const callback = jest.fn(); + const callback = vi.fn(); const root = storage.root; @@ -917,8 +919,8 @@ describe("LiveObject", () => { 1 ); - const rootDeepCallback = jest.fn(); - const liveObjectCallback = jest.fn(); + const rootDeepCallback = vi.fn(); + const liveObjectCallback = vi.fn(); room.subscribe(root, rootDeepCallback, { isDeep: true }); room.subscribe(root.get("obj"), liveObjectCallback); @@ -970,8 +972,8 @@ describe("LiveObject", () => { 1 ); - const rootDeepCallback = jest.fn(); - const liveObjectCallback = jest.fn(); + const rootDeepCallback = vi.fn(); + const liveObjectCallback = vi.fn(); room.subscribe(root, rootDeepCallback, { isDeep: true }); room.subscribe(root.get("obj"), liveObjectCallback); @@ -1033,7 +1035,7 @@ describe("LiveObject", () => { root.set("a", 1); expectStorage({ a: 1 }); - const callback = jest.fn(); + const callback = vi.fn(); room.subscribe(root, callback, { isDeep: true }); room.history.undo(); @@ -1112,7 +1114,7 @@ describe("LiveObject", () => { LiveObject.detectLargeObjects = false; }); - it("should NOT throw when LiveObject.detectLargeObjects property is disabled (default behavior)", () => { + test("should NOT throw when LiveObject.detectLargeObjects property is disabled (default behavior)", () => { // Ensure LiveObject.detectLargeObjects property is disabled LiveObject.detectLargeObjects = false; @@ -1125,7 +1127,7 @@ describe("LiveObject", () => { }).not.toThrow(); }); - it("should throw when LiveObject.detectLargeObjects property is enabled and size exceeds 128KB", () => { + test("should throw when LiveObject.detectLargeObjects property is enabled and size exceeds 128KB", () => { // Enable LiveObject.detectLargeObjects property LiveObject.detectLargeObjects = true; @@ -1138,7 +1140,7 @@ describe("LiveObject", () => { }).toThrow(/LiveObject size exceeded limit.*bytes/); }); - it("should NOT throw when LiveObject.detectLargeObjects property is enabled but size is within limit", () => { + test("should NOT throw when LiveObject.detectLargeObjects property is enabled but size is within limit", () => { // Enable LiveObject.detectLargeObjects property LiveObject.detectLargeObjects = true; @@ -1151,7 +1153,7 @@ describe("LiveObject", () => { }).not.toThrow(); }); - it("should exclude Live structure references from size calculation", () => { + test("should exclude Live structure references from size calculation", () => { // Enable LiveObject.detectLargeObjects property LiveObject.detectLargeObjects = true; @@ -1183,7 +1185,7 @@ describe("LiveObject", () => { }).not.toThrow(); }); - it("should throw when accumulating many small properties exceeds 128KB limit", () => { + test("should throw when accumulating many small properties exceeds 128KB limit", () => { // Enable LiveObject.detectLargeObjects property LiveObject.detectLargeObjects = true; @@ -1208,7 +1210,7 @@ describe("LiveObject", () => { }).toThrow(/LiveObject size exceeded limit/); }); - it("should correctly handle mixed small properties and Live structures", () => { + test("should correctly handle mixed small properties and Live structures", () => { // Enable LiveObject.detectLargeObjects property LiveObject.detectLargeObjects = true; @@ -1240,7 +1242,7 @@ describe("LiveObject", () => { }).toThrow(/LiveObject size exceeded limit/); }); - it("should handle the exact boundary case at 128KB", () => { + test("should handle the exact boundary case at 128KB", () => { // Enable LiveObject.detectLargeObjects property LiveObject.detectLargeObjects = true; @@ -1261,7 +1263,7 @@ describe("LiveObject", () => { }).toThrow(/LiveObject size exceeded limit/); }); - it("should allow many small properties when total stays under limit", () => { + test("should allow many small properties when total stays under limit", () => { // Enable LiveObject.detectLargeObjects property LiveObject.detectLargeObjects = true; @@ -1283,7 +1285,7 @@ describe("LiveObject", () => { }).not.toThrow(); }); - it("should handle performance optimization boundary correctly", () => { + test("should handle performance optimization boundary correctly", () => { // Enable LiveObject.detectLargeObjects property LiveObject.detectLargeObjects = true; diff --git a/packages/liveblocks-core/src/crdts/__tests__/cloning.test.ts b/packages/liveblocks-core/src/crdts/__tests__/cloning.test.ts index fbee05769c1..be2ae1aba7f 100644 --- a/packages/liveblocks-core/src/crdts/__tests__/cloning.test.ts +++ b/packages/liveblocks-core/src/crdts/__tests__/cloning.test.ts @@ -1,4 +1,5 @@ import * as fc from "fast-check"; +import { describe, expect, test } from "vitest"; import { listUpdate, @@ -15,7 +16,7 @@ import type { LiveList } from "../LiveList"; import { liveStructure, lson } from "./_arbitraries"; describe("cloning LiveStructures", () => { - it("basic cloning logic", async () => { + test("basic cloning logic", async () => { const { root, expectUpdates, room } = await prepareStorageUpdateTest<{ list1: LiveList; list2: LiveList; @@ -64,7 +65,7 @@ describe("cloning LiveStructures", () => { ]); }); - it("deep cloning of LiveStructures", () => + test("deep cloning of LiveStructures", () => fc.assert( fc.asyncProperty( liveStructure, @@ -84,7 +85,7 @@ describe("cloning LiveStructures", () => { ) )); - it("deep cloning of LiveStructures (twice)", () => + test("deep cloning of LiveStructures (twice)", () => fc.assert( fc.asyncProperty( liveStructure, @@ -105,7 +106,7 @@ describe("cloning LiveStructures", () => { ) )); - it("deep cloning of LSON data (= LiveStructures or JSON)", () => + test("deep cloning of LSON data (= LiveStructures or JSON)", () => fc.assert( fc.asyncProperty( lson, diff --git a/packages/liveblocks-core/src/crdts/__tests__/doc.test.ts b/packages/liveblocks-core/src/crdts/__tests__/doc.test.ts index 2d4755585dc..df66d4ae597 100644 --- a/packages/liveblocks-core/src/crdts/__tests__/doc.test.ts +++ b/packages/liveblocks-core/src/crdts/__tests__/doc.test.ts @@ -1,3 +1,5 @@ +import { describe, expect, test, vi } from "vitest"; + import { createSerializedList, createSerializedMap, @@ -17,7 +19,7 @@ describe("Storage", () => { 1 ); - const callback = jest.fn(); + const callback = vi.fn(); const unsubscribe = room.subscribe(callback); @@ -44,7 +46,7 @@ describe("Storage", () => { 1 ); - const callback = jest.fn(); + const callback = vi.fn(); const unsubscribe = room.subscribe(callback); @@ -75,7 +77,7 @@ describe("Storage", () => { 1 ); - const callback = jest.fn(); + const callback = vi.fn(); const unsubscribe = room.subscribe(callback); @@ -106,7 +108,7 @@ describe("Storage", () => { b: number; }>([createSerializedObject("0:0", { a: 0, b: 0 })], 1); - const callback = jest.fn(); + const callback = vi.fn(); const root = storage.root; @@ -148,7 +150,7 @@ describe("Storage", () => { 1 ); - const callback = jest.fn(); + const callback = vi.fn(); const root = storage.root; @@ -190,7 +192,7 @@ describe("Storage", () => { 1 ); - const callback = jest.fn(); + const callback = vi.fn(); const root = storage.root; @@ -230,7 +232,7 @@ describe("Storage", () => { }); describe("batching", () => { - it("batching and undo", async () => { + test("batching and undo", async () => { const { room, storage, expectStorage } = await prepareStorageTest<{ items: LiveList; }>( @@ -266,7 +268,7 @@ describe("Storage", () => { }); }); - it("nesting batches makes inner batches a no-op", async () => { + test("nesting batches makes inner batches a no-op", async () => { const { room, storage, expectStorage } = await prepareStorageTest<{ items: LiveList; }>( @@ -316,7 +318,7 @@ describe("Storage", () => { }); }); - it("batch callbacks can return a value", async () => { + test("batch callbacks can return a value", async () => { const { room, storage } = await prepareStorageTest<{ items: LiveList; }>( @@ -340,7 +342,7 @@ describe("Storage", () => { expect(numInserted).toEqual(3); }); - it("calling undo during a batch should throw", async () => { + test("calling undo during a batch should throw", async () => { const { room } = await prepareStorageTest<{ a: number }>( [createSerializedObject("0:0", { a: 0 })], 1 @@ -351,7 +353,7 @@ describe("Storage", () => { }); }); - it("calling redo during a batch should throw", async () => { + test("calling redo during a batch should throw", async () => { const { room } = await prepareStorageTest<{ a: number }>( [createSerializedObject("0:0", { a: 0 })], 1 @@ -364,7 +366,7 @@ describe("Storage", () => { }); describe("undo / redo", () => { - it("list.push", async () => { + test("list.push", async () => { const { storage, expectStorage, assertUndoRedo } = await prepareStorageTest<{ items: LiveList; @@ -393,7 +395,7 @@ describe("Storage", () => { assertUndoRedo(); }); - it("max undo-redo stack", async () => { + test("max undo-redo stack", async () => { const { room, storage, expectStorage } = await prepareStorageTest<{ a: number; }>([createSerializedObject("0:0", { a: 0 })], 1); @@ -414,7 +416,7 @@ describe("Storage", () => { }); }); - it("storage operation should clear redo stack", async () => { + test("storage operation should clear redo stack", async () => { const { room, storage, expectStorage } = await prepareStorageTest<{ items: LiveList; }>( diff --git a/packages/liveblocks-core/src/crdts/__tests__/liveblocks-helpers.test.ts b/packages/liveblocks-core/src/crdts/__tests__/liveblocks-helpers.test.ts index 280b95e51f7..0629ab6f813 100644 --- a/packages/liveblocks-core/src/crdts/__tests__/liveblocks-helpers.test.ts +++ b/packages/liveblocks-core/src/crdts/__tests__/liveblocks-helpers.test.ts @@ -1,3 +1,5 @@ +import { describe, expect, test } from "vitest"; + import { FIRST_POSITION, SECOND_POSITION } from "../../__tests__/_utils"; import { OpCode } from "../../protocol/Op"; import { CrdtType } from "../../protocol/SerializedCrdt"; @@ -238,7 +240,7 @@ describe("getTreesDiffOperations", () => { }); describe("findNonSerializableValue", () => { - it("findNonSerializableValue should return path and value of non serializable value", () => { + test("findNonSerializableValue should return path and value of non serializable value", () => { for (const [value, expectedPath] of [ [null, false], [undefined, false], @@ -264,7 +266,7 @@ describe("findNonSerializableValue", () => { }); describe("toPlainLson", () => { - it("toPlainLson with a plain object should not change", () => { + test("toPlainLson with a plain object should not change", () => { const mockPlainObject = { fruits: ["strawberry", "apple", "mango"], vegetables: { broccoli: "delicious", spinach: "also tasty" }, @@ -272,7 +274,7 @@ describe("toPlainLson", () => { expect(toPlainLson(mockPlainObject)).toEqual(mockPlainObject); }); - it("toPlainLson with a liveStructure object should return plain lson object", () => { + test("toPlainLson with a liveStructure object should return plain lson object", () => { const mockLsonObject = new LiveObject({ fruits: new LiveList(["strawberry", "apple", "mango"]), vegetables: new LiveMap([ @@ -300,7 +302,7 @@ describe("toPlainLson", () => { }); // See https://github.com/liveblocks/liveblocks/issues/1304 - it("toPlainLson regression #1", () => { + test("toPlainLson regression #1", () => { const mockLsonObject = new LiveObject({ a: null, b: 0, diff --git a/packages/liveblocks-core/src/lib/__tests__/AiChatDB.test.ts b/packages/liveblocks-core/src/lib/__tests__/AiChatDB.test.ts index e3aafdae69c..a871459a069 100644 --- a/packages/liveblocks-core/src/lib/__tests__/AiChatDB.test.ts +++ b/packages/liveblocks-core/src/lib/__tests__/AiChatDB.test.ts @@ -1,3 +1,5 @@ +import { describe, expect, test } from "vitest"; + import { AiChatDB } from "../../AiChatDB"; import type { AiChat, ISODateString } from "../../types/ai"; diff --git a/packages/liveblocks-core/src/lib/__tests__/DefaultMap.test.ts b/packages/liveblocks-core/src/lib/__tests__/DefaultMap.test.ts index ec57d69a550..bbaefae5ca3 100644 --- a/packages/liveblocks-core/src/lib/__tests__/DefaultMap.test.ts +++ b/packages/liveblocks-core/src/lib/__tests__/DefaultMap.test.ts @@ -1,4 +1,5 @@ import * as fc from "fast-check"; +import { describe, expect, test } from "vitest"; import { DefaultMap } from "../DefaultMap"; diff --git a/packages/liveblocks-core/src/lib/__tests__/Deque.test.ts b/packages/liveblocks-core/src/lib/__tests__/Deque.test.ts index 340caf0b942..0f14952eb6b 100644 --- a/packages/liveblocks-core/src/lib/__tests__/Deque.test.ts +++ b/packages/liveblocks-core/src/lib/__tests__/Deque.test.ts @@ -1,4 +1,5 @@ import * as fc from "fast-check"; +import { describe, expect, test } from "vitest"; import { Deque } from "../Deque"; diff --git a/packages/liveblocks-core/src/lib/__tests__/EventSource.test.ts b/packages/liveblocks-core/src/lib/__tests__/EventSource.test.ts index 76a59410241..cc526a13a3a 100644 --- a/packages/liveblocks-core/src/lib/__tests__/EventSource.test.ts +++ b/packages/liveblocks-core/src/lib/__tests__/EventSource.test.ts @@ -1,4 +1,5 @@ import fc from "fast-check"; +import { describe, expect, test, vi } from "vitest"; import { makeBufferableEventSource, makeEventSource } from "../EventSource"; @@ -22,7 +23,7 @@ describe("EventSource", () => { anything(), (payload) => { - const callback = jest.fn(); + const callback = vi.fn(); const hub = makeEventSource(); hub.observable.subscribe(callback); @@ -45,8 +46,8 @@ describe("EventSource", () => { anything(), (payload) => { - const callback1 = jest.fn(); - const callback2 = jest.fn(); + const callback1 = vi.fn(); + const callback2 = vi.fn(); const hub = makeEventSource(); hub.observable.subscribe(callback1); @@ -71,9 +72,9 @@ describe("EventSource", () => { }); test("getting counts", () => { - const callback1 = jest.fn(); - const callback2 = jest.fn(); - const callback3 = jest.fn(); + const callback1 = vi.fn(); + const callback2 = vi.fn(); + const callback3 = vi.fn(); const hub = makeEventSource(); // No callbacks registered yet @@ -110,8 +111,8 @@ describe("EventSource", () => { }); test("detecting if notifications were sent", () => { - const callback1 = jest.fn(); - const callback2 = jest.fn(); + const callback1 = vi.fn(); + const callback2 = vi.fn(); const hub = makeEventSource(); expect(hub.notify("hi")).toBe(false); // No callbacks were invoked @@ -134,7 +135,7 @@ describe("EventSource", () => { anything(), (payload) => { - const callback = jest.fn(); + const callback = vi.fn(); const hub = makeEventSource(); const dereg1 = hub.observable.subscribeOnce(callback); @@ -162,8 +163,8 @@ describe("EventSource", () => { anything(), (payload) => { - const callback1 = jest.fn(); - const callback2 = jest.fn(); + const callback1 = vi.fn(); + const callback2 = vi.fn(); const hub = makeEventSource(); const dereg1 = hub.observable.subscribe(callback1); @@ -242,8 +243,8 @@ describe("EventSource", () => { describe("BufferableEventSource", () => { test("detecting if notifications were sent", () => { - const callback1 = jest.fn(); - const callback2 = jest.fn(); + const callback1 = vi.fn(); + const callback2 = vi.fn(); const src = makeBufferableEventSource(); expect(src.notify("hi")).toBe(false); // No callbacks were invoked @@ -273,7 +274,7 @@ describe("BufferableEventSource", () => { anything(), (payload) => { - const callback = jest.fn(); + const callback = vi.fn(); const hub = makeBufferableEventSource(); const unsub = hub.observable.subscribe(callback); diff --git a/packages/liveblocks-core/src/lib/Poller.test.ts b/packages/liveblocks-core/src/lib/__tests__/Poller.test.ts similarity index 78% rename from packages/liveblocks-core/src/lib/Poller.test.ts rename to packages/liveblocks-core/src/lib/__tests__/Poller.test.ts index e9577d05646..64b0a00d820 100644 --- a/packages/liveblocks-core/src/lib/Poller.test.ts +++ b/packages/liveblocks-core/src/lib/__tests__/Poller.test.ts @@ -1,65 +1,67 @@ -import { makePoller } from "../lib/Poller"; +import { afterEach, beforeEach, describe, expect, test, vi } from "vitest"; + +import { makePoller } from "../Poller"; describe("Poller", () => { beforeEach(() => { - jest.useFakeTimers(); + vi.useFakeTimers(); }); afterEach(() => { - jest.clearAllTimers(); - jest.useRealTimers(); + vi.clearAllTimers(); + vi.useRealTimers(); }); test("should start the poller when condition is true", async () => { - const callback = jest.fn(); + const callback = vi.fn(); const poller = makePoller(callback, 1000); // 1000ms interval poller.inc(); // Fast-forward until all timers have been executed - await jest.advanceTimersByTimeAsync(1000); + await vi.advanceTimersByTimeAsync(1000); // Expect the callback to be called after the interval expect(callback).toHaveBeenCalledTimes(1); }); test("should stop the poller when condition is false", async () => { - const callback = jest.fn(); + const callback = vi.fn(); const poller = makePoller(callback, 1000); // 1000ms interval poller.inc(); // Start the poller poller.dec(); // Stop the poller // Fast-forward time to check if polling stops - await jest.advanceTimersByTimeAsync(3000); + await vi.advanceTimersByTimeAsync(3000); // Expect the callback not to be called since the poller was stopped expect(callback).toHaveBeenCalledTimes(0); }); test("should also stop the poller when visibility state is false", async () => { - const callback = jest.fn(); + const callback = vi.fn(); const poller = makePoller(callback, 1000); // 1000ms interval poller.inc(); // Start the poller poller.setInForeground(false); // Stops the poller // Fast-forward time to check if polling stops - await jest.advanceTimersByTimeAsync(3000); + await vi.advanceTimersByTimeAsync(3000); // Expect the callback not to be called since the poller was stopped expect(callback).toHaveBeenCalledTimes(0); }); test("should trigger a poll as soon as visibility state is toggled before stale time", async () => { - const callback = jest.fn(); + const callback = vi.fn(); const poller = makePoller(callback, 1000, { maxStaleTimeMs: 500 }); // 1000ms interval poller.inc(); poller.setInForeground(false); expect(callback).toHaveBeenCalledTimes(0); - await jest.advanceTimersByTimeAsync(400); + await vi.advanceTimersByTimeAsync(400); poller.setInForeground(true); // Becoming visible should instantly trigger a poll expect(callback).toHaveBeenCalledTimes(0); @@ -68,14 +70,14 @@ describe("Poller", () => { }); test("should trigger a poll as soon as visibility state is toggled after stale time", async () => { - const callback = jest.fn(); + const callback = vi.fn(); const poller = makePoller(callback, 1000, { maxStaleTimeMs: 500 }); // 1000ms interval poller.inc(); poller.setInForeground(false); expect(callback).toHaveBeenCalledTimes(0); - await jest.advanceTimersByTimeAsync(600); + await vi.advanceTimersByTimeAsync(600); poller.setInForeground(true); // Becoming visible should instantly trigger a poll expect(callback).toHaveBeenCalledTimes(1); @@ -90,7 +92,7 @@ describe("Poller", () => { // // Mock async callback that takes 2s to resolve - const callback = jest.fn(async () => { + const callback = vi.fn(async () => { await new Promise((resolve) => setTimeout(resolve, 2000)); }); @@ -99,70 +101,70 @@ describe("Poller", () => { poller.inc(); // Fast-forward time by 2000ms - await jest.advanceTimersByTimeAsync(2000); // Move from 0s -> 2s on the timeline + await vi.advanceTimersByTimeAsync(2000); // Move from 0s -> 2s on the timeline // The async callback should have been called (even though it hasn't finished yet) expect(callback).toHaveBeenCalledTimes(1); // Fast-forward another 2000ms, the callback should be invoked again - await jest.advanceTimersByTimeAsync(1000); // Move from 2s -> 3s + await vi.advanceTimersByTimeAsync(1000); // Move from 2s -> 3s expect(callback).toHaveBeenCalledTimes(1); - await jest.advanceTimersByTimeAsync(1000); // Move from 3s -> 4s (where Poll 2 should happen) + await vi.advanceTimersByTimeAsync(1000); // Move from 3s -> 4s (where Poll 2 should happen) expect(callback).toHaveBeenCalledTimes(2); }); test("should not start polling if already running", async () => { - const callback = jest.fn(); + const callback = vi.fn(); const poller = makePoller(callback, 1000); // 1000ms interval poller.inc(); // Start the poller poller.inc(); // Fast-forward by 3000ms - await jest.advanceTimersByTimeAsync(3000); + await vi.advanceTimersByTimeAsync(3000); // Expect callback to be called only 3 times (once per interval) expect(callback).toHaveBeenCalledTimes(3); }); test("should handle enable/disable toggle", async () => { - const callback = jest.fn(); + const callback = vi.fn(); const poller = makePoller(callback, 1000); // 1000ms interval poller.inc(); // Start polling // Fast-forward 1500ms (should call callback once after 1000ms) - await jest.advanceTimersByTimeAsync(1500); + await vi.advanceTimersByTimeAsync(1500); expect(callback).toHaveBeenCalledTimes(1); poller.dec(); // Stop polling // Fast-forward another 1500ms (no more polling) - await jest.advanceTimersByTimeAsync(1500); + await vi.advanceTimersByTimeAsync(1500); expect(callback).toHaveBeenCalledTimes(1); // No more calls }); test("should keep the original polling schedule, even when disabled half-way", async () => { - const callback = jest.fn(); + const callback = vi.fn(); const poller = makePoller(callback, 10_000); // 10s interval poller.inc(); // Start the poller // Forward 3s and stop the poller - await jest.advanceTimersByTimeAsync(3000); + await vi.advanceTimersByTimeAsync(3000); poller.dec(); // Forward 3s -> 6s and start + stop the poller - await jest.advanceTimersByTimeAsync(3000); + await vi.advanceTimersByTimeAsync(3000); poller.inc(); poller.dec(); expect(callback).toHaveBeenCalledTimes(0); // Forward 6s -> 11s and start the poller - await jest.advanceTimersByTimeAsync(5000); + await vi.advanceTimersByTimeAsync(5000); poller.inc(); - await jest.advanceTimersByTimeAsync(0); + await vi.advanceTimersByTimeAsync(0); // A poll should now immediately happen (because it's been past 10 seconds // mark since the poller was originally started) @@ -170,14 +172,14 @@ describe("Poller", () => { }); test("should not allow explicit poll when disabled", async () => { - const callback = jest.fn(); + const callback = vi.fn(); const poller = makePoller(callback, 1000); poller.dec(); poller.setInForeground(true); // Fast-forward well beyond when the first poll is triggered - await jest.advanceTimersByTimeAsync(100_000); + await vi.advanceTimersByTimeAsync(100_000); expect(callback).toHaveBeenCalledTimes(0); // Should not poll, since polling is disabled }); @@ -188,14 +190,14 @@ describe("Poller", () => { // | // Force poll here - const callback = jest.fn(); + const callback = vi.fn(); const poller = makePoller(callback, 5000, { maxStaleTimeMs: 1000 }); poller.inc(); // Start polling expect(callback).toHaveBeenCalledTimes(0); // We're still before the first poll here - await jest.advanceTimersByTimeAsync(2000); + await vi.advanceTimersByTimeAsync(2000); expect(callback).toHaveBeenCalledTimes(0); // Bring to foreground to trigger a poll right now @@ -210,16 +212,16 @@ describe("Poller", () => { // Forced poll // Advance to what originally was the time the 1st poll - await jest.advanceTimersByTimeAsync(3000); // Move from 2s -> 5s + await vi.advanceTimersByTimeAsync(3000); // Move from 2s -> 5s expect(callback).toHaveBeenCalledTimes(1); - await jest.advanceTimersByTimeAsync(2000); // Move from 5s -> 7s + await vi.advanceTimersByTimeAsync(2000); // Move from 5s -> 7s expect(callback).toHaveBeenCalledTimes(2); - await jest.advanceTimersByTimeAsync(3000); // Move from 7s -> 10s + await vi.advanceTimersByTimeAsync(3000); // Move from 7s -> 10s expect(callback).toHaveBeenCalledTimes(2); - await jest.advanceTimersByTimeAsync(2000); // Move from 10s -> 12s + await vi.advanceTimersByTimeAsync(2000); // Move from 10s -> 12s expect(callback).toHaveBeenCalledTimes(3); }); @@ -230,14 +232,14 @@ describe("Poller", () => { // | // Turned stale - const callback = jest.fn(); + const callback = vi.fn(); const poller = makePoller(callback, 5000, { maxStaleTimeMs: 3000 }); poller.inc(); // Start polling expect(callback).toHaveBeenCalledTimes(0); // We're still before the first poll here - await jest.advanceTimersByTimeAsync(4000); + await vi.advanceTimersByTimeAsync(4000); expect(callback).toHaveBeenCalledTimes(0); // Bring to foreground to trigger a poll right now @@ -253,16 +255,16 @@ describe("Poller", () => { // Forced poll // Advance to what originally was the time the 1st poll - await jest.advanceTimersByTimeAsync(1000); // Move from 4s -> 5s + await vi.advanceTimersByTimeAsync(1000); // Move from 4s -> 5s expect(callback).toHaveBeenCalledTimes(1); - await jest.advanceTimersByTimeAsync(2000); // Move from 5s -> 7s + await vi.advanceTimersByTimeAsync(2000); // Move from 5s -> 7s expect(callback).toHaveBeenCalledTimes(1); - await jest.advanceTimersByTimeAsync(3000); // Move from 7s -> 10s (crosses the 9s mark, so polls) + await vi.advanceTimersByTimeAsync(3000); // Move from 7s -> 10s (crosses the 9s mark, so polls) expect(callback).toHaveBeenCalledTimes(2); - await jest.advanceTimersByTimeAsync(2000); // Move from 10s -> 12s + await vi.advanceTimersByTimeAsync(2000); // Move from 10s -> 12s expect(callback).toHaveBeenCalledTimes(2); }); @@ -273,14 +275,14 @@ describe("Poller", () => { // | // Force poll here - const callback = jest.fn(); + const callback = vi.fn(); const poller = makePoller(callback, 5000, { maxStaleTimeMs: 1000 }); poller.inc(); // Start polling expect(callback).toHaveBeenCalledTimes(0); // Advance to beyond the 1st and 2nd poll - await jest.advanceTimersByTimeAsync(7000); + await vi.advanceTimersByTimeAsync(7000); expect(callback).toHaveBeenCalledTimes(1); // Poll 1 has happened // Bring to foreground to trigger a poll right now @@ -295,10 +297,10 @@ describe("Poller", () => { // Force poll 2 here // Advance to what originally was the time the second poll should happen - await jest.advanceTimersByTimeAsync(3000); // Move from 7s -> 10s + await vi.advanceTimersByTimeAsync(3000); // Move from 7s -> 10s expect(callback).toHaveBeenCalledTimes(2); - await jest.advanceTimersByTimeAsync(3000); // Move from 10s -> 12s + await vi.advanceTimersByTimeAsync(3000); // Move from 10s -> 12s expect(callback).toHaveBeenCalledTimes(3); }); @@ -311,7 +313,7 @@ describe("Poller", () => { // Force poll here // Mock async callback that takes 1000ms to resolve - const callback = jest.fn(async () => { + const callback = vi.fn(async () => { await new Promise((resolve) => setTimeout(resolve, 1000)); }); const poller = makePoller(callback, 5000, { maxStaleTimeMs: 0 }); @@ -320,7 +322,7 @@ describe("Poller", () => { poller.inc(); // Fast-forward to 5s on the timeline (to trigger Poll 1) - await jest.advanceTimersByTimeAsync(5000); + await vi.advanceTimersByTimeAsync(5000); expect(callback).toHaveBeenCalledTimes(1); // Only one call since the poll is still in progress // Bring to foreground to trigger a poll right now @@ -330,10 +332,10 @@ describe("Poller", () => { // Since no forced poll happened, the original natural polling schedule is intact // Forward to 11s to verify - await jest.advanceTimersByTimeAsync(5000); // Forward from 5s -> 10s + await vi.advanceTimersByTimeAsync(5000); // Forward from 5s -> 10s expect(callback).toHaveBeenCalledTimes(1); // Still only one call - await jest.advanceTimersByTimeAsync(1000); // Forward from 10s -> 11s (when Poll 2 should happen) + await vi.advanceTimersByTimeAsync(1000); // Forward from 10s -> 11s (when Poll 2 should happen) expect(callback).toHaveBeenCalledTimes(2); // Still only one call }); @@ -346,24 +348,24 @@ describe("Poller", () => { // Force poll here // (but it's not stale enough) - const callback = jest.fn(); + const callback = vi.fn(); const poller = makePoller(callback, 5000, { maxStaleTimeMs: 30000 }); // Start the poller poller.inc(); // Fast-forward to 5s - await jest.advanceTimersByTimeAsync(5000); + await vi.advanceTimersByTimeAsync(5000); expect(callback).toHaveBeenCalledTimes(1); // Poll 1 // Fast-forward from 5s -> 6s - await jest.advanceTimersByTimeAsync(1000); + await vi.advanceTimersByTimeAsync(1000); // Bring to foreground poller.setInForeground(true); // Data is allowed to be 30 seconds old, so not stale // Fast-forward from 6s -> 10s - await jest.advanceTimersByTimeAsync(4000); + await vi.advanceTimersByTimeAsync(4000); expect(callback).toHaveBeenCalledTimes(2); // Poll 2 }); @@ -377,18 +379,18 @@ describe("Poller", () => { // + pollNowIfStale // (forces immediate poll 2) - const callback = jest.fn(); + const callback = vi.fn(); const poller = makePoller(callback, 5000, { maxStaleTimeMs: 30000 }); // Start the poller poller.inc(); // Fast-forward to 5s - await jest.advanceTimersByTimeAsync(5000); + await vi.advanceTimersByTimeAsync(5000); expect(callback).toHaveBeenCalledTimes(1); // Poll 1 // Fast-forward from 5s -> 6s - await jest.advanceTimersByTimeAsync(1000); + await vi.advanceTimersByTimeAsync(1000); // Mark as stale and poll poller.markAsStale(); @@ -396,13 +398,13 @@ describe("Poller", () => { expect(callback).toHaveBeenCalledTimes(2); // Forced poll 2 // Fast-forward from 6s -> 11s - await jest.advanceTimersByTimeAsync(5000); + await vi.advanceTimersByTimeAsync(5000); expect(callback).toHaveBeenCalledTimes(3); // Poll 3 }); test("should allow new polls when re-enabled, but not schedule extra polls after completion of an in-progress poll", async () => { // Mock async callback that takes 4s to resolve - const callback = jest.fn(async () => { + const callback = vi.fn(async () => { await new Promise((resolve) => setTimeout(resolve, 2000)); }); const poller = makePoller(callback, 1000); @@ -411,30 +413,30 @@ describe("Poller", () => { poller.inc(); // Fast-forward to 1s when the first poll is triggered - await jest.advanceTimersByTimeAsync(1000); + await vi.advanceTimersByTimeAsync(1000); expect(callback).toHaveBeenCalledTimes(1); // Poll 1 starts - await jest.advanceTimersByTimeAsync(1000); // Poll 1 still in progress + await vi.advanceTimersByTimeAsync(1000); // Poll 1 still in progress // Disable and enable while Poll 1 is still in progress poller.dec(); poller.inc(); - await jest.advanceTimersByTimeAsync(1000); // Poll 1 finished + await vi.advanceTimersByTimeAsync(1000); // Poll 1 finished expect(callback).toHaveBeenCalledTimes(1); - await jest.advanceTimersByTimeAsync(1000); // Poll 2 starts + await vi.advanceTimersByTimeAsync(1000); // Poll 2 starts poller.dec(); - await jest.advanceTimersByTimeAsync(2000); // Poll 2 finishes + await vi.advanceTimersByTimeAsync(2000); // Poll 2 finishes expect(callback).toHaveBeenCalledTimes(2); - await jest.advanceTimersByTimeAsync(10000); + await vi.advanceTimersByTimeAsync(10000); expect(callback).toHaveBeenCalledTimes(2); // No new polls are getting scheduled }); test("should abort long running ongoing poll", async () => { // Mock async callback that takes 2s to resolve - const callback = jest.fn(async (signal: AbortSignal) => { + const callback = vi.fn(async (signal: AbortSignal) => { await new Promise((resolve) => setTimeout(resolve, 40_000)); signal.throwIfAborted(); }); @@ -444,17 +446,17 @@ describe("Poller", () => { poller.inc(); // Fast-forward to 5s (polling interval) - await jest.advanceTimersByTimeAsync(5000); + await vi.advanceTimersByTimeAsync(5000); expect(callback).toHaveBeenCalledTimes(1); // Advance by 30s (which is longer than the time the poller callback takes to complete) and verify the signal was aborted - await jest.advanceTimersByTimeAsync(30_000); + await vi.advanceTimersByTimeAsync(30_000); const [signal] = callback.mock.calls[0]; expect(signal.aborted).toBe(true); }); test("should poll with exponential backoff on error", async () => { - const callback = jest.fn(() => { + const callback = vi.fn(() => { throw new Error(); }); const poller = makePoller(callback, 2000); @@ -463,40 +465,40 @@ describe("Poller", () => { poller.inc(); // Fast-forward to 2s - await jest.advanceTimersByTimeAsync(2000); + await vi.advanceTimersByTimeAsync(2000); expect(callback).toHaveBeenCalledTimes(1); // Poll 1 // Advance by 1s and verify that a new poll takes place - await jest.advanceTimersByTimeAsync(1000); + await vi.advanceTimersByTimeAsync(1000); expect(callback).toHaveBeenCalledTimes(2); // Advance by 2s and verify that a new poll takes place - await jest.advanceTimersByTimeAsync(2000); + await vi.advanceTimersByTimeAsync(2000); expect(callback).toHaveBeenCalledTimes(3); // Advance by 4s and verify that a new poll takes place - await jest.advanceTimersByTimeAsync(4000); + await vi.advanceTimersByTimeAsync(4000); expect(callback).toHaveBeenCalledTimes(4); // Advance by 8s and verify that a new poll takes place - await jest.advanceTimersByTimeAsync(8000); + await vi.advanceTimersByTimeAsync(8000); expect(callback).toHaveBeenCalledTimes(5); // Advance by 10s and verify that a new poll takes place - await jest.advanceTimersByTimeAsync(10000); + await vi.advanceTimersByTimeAsync(10000); expect(callback).toHaveBeenCalledTimes(6); // Advance by 10s and verify that a new poll takes place - await jest.advanceTimersByTimeAsync(10000); + await vi.advanceTimersByTimeAsync(10000); expect(callback).toHaveBeenCalledTimes(7); // Advance by 10s and verify that a new poll takes place - await jest.advanceTimersByTimeAsync(10000); + await vi.advanceTimersByTimeAsync(10000); expect(callback).toHaveBeenCalledTimes(8); }); test("should poll with exponential backoff on error and use normal interval once successful", async () => { - const callback = jest + const callback = vi .fn() // First call - throw .mockImplementationOnce(() => { @@ -519,31 +521,31 @@ describe("Poller", () => { poller.inc(); // Fast-forward to 2s - await jest.advanceTimersByTimeAsync(2000); + await vi.advanceTimersByTimeAsync(2000); expect(callback).toHaveBeenCalledTimes(1); // Poll 1 // Advance by 1s and verify that a new poll takes place - await jest.advanceTimersByTimeAsync(1000); + await vi.advanceTimersByTimeAsync(1000); expect(callback).toHaveBeenCalledTimes(2); // Advance by 2s and verify that a new poll takes place - await jest.advanceTimersByTimeAsync(2000); + await vi.advanceTimersByTimeAsync(2000); expect(callback).toHaveBeenCalledTimes(3); // Advance by 4s and verify that a new poll takes place - await jest.advanceTimersByTimeAsync(4000); + await vi.advanceTimersByTimeAsync(4000); expect(callback).toHaveBeenCalledTimes(4); // At this point, callback succeeds, so normal interval resumes - await jest.advanceTimersByTimeAsync(2000); // Normal interval after success + await vi.advanceTimersByTimeAsync(2000); // Normal interval after success expect(callback).toHaveBeenCalledTimes(5); // Advance again by the normal interval and verify callback is called - await jest.advanceTimersByTimeAsync(2000); + await vi.advanceTimersByTimeAsync(2000); expect(callback).toHaveBeenCalledTimes(6); // Confirm normal interval persists on further calls - await jest.advanceTimersByTimeAsync(2000); + await vi.advanceTimersByTimeAsync(2000); expect(callback).toHaveBeenCalledTimes(7); // and so on diff --git a/packages/liveblocks-core/src/lib/__tests__/SortedList.test.ts b/packages/liveblocks-core/src/lib/__tests__/SortedList.test.ts index 4588126010f..0ccacc22ae8 100644 --- a/packages/liveblocks-core/src/lib/__tests__/SortedList.test.ts +++ b/packages/liveblocks-core/src/lib/__tests__/SortedList.test.ts @@ -1,4 +1,5 @@ import * as fc from "fast-check"; +import { describe, expect, test } from "vitest"; import { SortedList } from "../SortedList"; diff --git a/packages/liveblocks-core/src/lib/__tests__/autoRetry.test.ts b/packages/liveblocks-core/src/lib/__tests__/autoRetry.test.ts index 263c3ea3923..4a3e7fac567 100644 --- a/packages/liveblocks-core/src/lib/__tests__/autoRetry.test.ts +++ b/packages/liveblocks-core/src/lib/__tests__/autoRetry.test.ts @@ -1,3 +1,5 @@ +import { describe, expect, test } from "vitest"; + import { autoRetry } from "../autoRetry"; function makeFailThreeTimes() { diff --git a/packages/liveblocks-core/src/lib/__tests__/batch.test.ts b/packages/liveblocks-core/src/lib/__tests__/batch.test.ts index 6114587523c..388567172b9 100644 --- a/packages/liveblocks-core/src/lib/__tests__/batch.test.ts +++ b/packages/liveblocks-core/src/lib/__tests__/batch.test.ts @@ -1,3 +1,5 @@ +import { describe, expect, test, vi } from "vitest"; + import { Batch } from "../batch"; import { wait } from "../utils"; @@ -16,7 +18,7 @@ const asynchronousCallback = async (inputs: string[]) => { describe("Batch", () => { test("should batch synchronous calls", async () => { - const callback = jest.fn(synchronousCallback); + const callback = vi.fn(synchronousCallback); const batch = new Batch(callback, { delay: SOME_TIME }); const a = batch.get("a"); @@ -30,7 +32,7 @@ describe("Batch", () => { }); test("should batch asynchronous calls", async () => { - const callback = jest.fn(asynchronousCallback); + const callback = vi.fn(asynchronousCallback); const batch = new Batch(callback, { delay: SOME_TIME }); const a = batch.get("a"); @@ -44,7 +46,7 @@ describe("Batch", () => { }); test("should batch based on delay", async () => { - const callback = jest.fn(synchronousCallback); + const callback = vi.fn(synchronousCallback); const batch = new Batch(callback, { delay: SOME_TIME }); const a = batch.get("a"); @@ -61,7 +63,7 @@ describe("Batch", () => { }); test("should batch based on size", async () => { - const callback = jest.fn(synchronousCallback); + const callback = vi.fn(synchronousCallback); const batch = new Batch(callback, { delay: SOME_TIME, size: 1, @@ -80,7 +82,7 @@ describe("Batch", () => { }); test("should reject batch errors", async () => { - const callback = jest.fn(() => { + const callback = vi.fn(() => { throw ERROR; }); const batch = new Batch(callback, { delay: SOME_TIME }); @@ -94,7 +96,7 @@ describe("Batch", () => { }); test("should reject batch rejections", async () => { - const callback = jest.fn(() => { + const callback = vi.fn(() => { return Promise.reject(ERROR_MESSAGE); }); const batch = new Batch(callback, { delay: SOME_TIME }); @@ -108,7 +110,7 @@ describe("Batch", () => { }); test("should reject individual errors", async () => { - const callback = jest.fn(() => { + const callback = vi.fn(() => { return ["a", ERROR]; }); const batch = new Batch(callback, { delay: SOME_TIME }); @@ -122,7 +124,7 @@ describe("Batch", () => { }); test("should reject if callback doesn't return an array", async () => { - const callback = jest.fn(); + const callback = vi.fn(); const batch = new Batch(callback, { delay: SOME_TIME }); await expect(batch.get("a")).rejects.toEqual( @@ -131,7 +133,7 @@ describe("Batch", () => { }); test("should reject if callback doesn't return an array of the same length as batch", async () => { - const callback = jest.fn(() => []); + const callback = vi.fn(() => []); const batch = new Batch(callback, { delay: SOME_TIME }); await expect(batch.get("a")).rejects.toEqual( @@ -142,7 +144,7 @@ describe("Batch", () => { }); test("should deduplicate identical calls", async () => { - const callback = jest.fn(synchronousCallback); + const callback = vi.fn(synchronousCallback); const batch = new Batch(callback, { delay: SOME_TIME }); const a = batch.get("a"); @@ -159,7 +161,7 @@ describe("Batch", () => { }); test("should not deduplicate identical calls if they're not in the same batch", async () => { - const callback = jest.fn(synchronousCallback); + const callback = vi.fn(synchronousCallback); const batch = new Batch(callback, { delay: SOME_TIME }); const a = batch.get("a"); diff --git a/packages/liveblocks-core/src/lib/__tests__/create-store.test.ts b/packages/liveblocks-core/src/lib/__tests__/create-store.test.ts index 7b094e3842a..47f4bb4ab0f 100644 --- a/packages/liveblocks-core/src/lib/__tests__/create-store.test.ts +++ b/packages/liveblocks-core/src/lib/__tests__/create-store.test.ts @@ -1,8 +1,10 @@ +import { describe, expect, test, vi } from "vitest"; + import { batch, Signal } from "../signals"; describe("Signals (previously createStore)", () => { test("should not notify subscriber right after subscribing", () => { - const fn = jest.fn(); + const fn = vi.fn(); const store = new Signal({ x: 0 }); store.subscribe(fn); @@ -11,7 +13,7 @@ describe("Signals (previously createStore)", () => { }); test("should notify subscriber when state is updated via callback", () => { - const fn = jest.fn(); + const fn = vi.fn(); const store = new Signal({ x: 0 }); store.subscribe(fn); @@ -24,7 +26,7 @@ describe("Signals (previously createStore)", () => { }); test("should only notify subscriber if state reference changes", () => { - const fn = jest.fn(); + const fn = vi.fn(); const store = new Signal({ x: 0 }); store.subscribe(fn); @@ -47,7 +49,7 @@ describe("Signals (previously createStore)", () => { }); test("batching will only notify once", () => { - const fn = jest.fn(); + const fn = vi.fn(); const store = new Signal({ x: 0 }); store.subscribe(fn); @@ -72,7 +74,7 @@ describe("Signals (previously createStore)", () => { }); test("nesting batches has no effect (only the outer batch counts)", () => { - const fn = jest.fn(); + const fn = vi.fn(); const store = new Signal({ x: 0 }); store.subscribe(fn); diff --git a/packages/liveblocks-core/src/lib/__tests__/freeze.test.ts b/packages/liveblocks-core/src/lib/__tests__/freeze.test.ts index 988fc8b877d..be2bbb87a92 100644 --- a/packages/liveblocks-core/src/lib/__tests__/freeze.test.ts +++ b/packages/liveblocks-core/src/lib/__tests__/freeze.test.ts @@ -1,7 +1,9 @@ +import { describe, expect, test } from "vitest"; + import { freeze } from "../freeze"; describe("freeze", () => { - it("freezes objects", () => { + test("freezes objects", () => { const x = freeze({ a: 1 }) as Record; expect(() => { x.b = 2; diff --git a/packages/liveblocks-core/src/lib/__tests__/fsm.test.ts b/packages/liveblocks-core/src/lib/__tests__/fsm.test.ts index 06898ad3054..209f6e59c3d 100644 --- a/packages/liveblocks-core/src/lib/__tests__/fsm.test.ts +++ b/packages/liveblocks-core/src/lib/__tests__/fsm.test.ts @@ -1,3 +1,5 @@ +import { describe, expect, test, vi } from "vitest"; + import { distance, FSM, patterns } from "../fsm"; import { wait } from "../utils"; @@ -183,9 +185,9 @@ describe("finite state machine", () => { describe("enter/leave functions", () => { test("executes onEnter when starting", () => { - const onEnterRed = jest.fn(); - const onEnterGreen = jest.fn(); - const onEnterYellow = jest.fn(); + const onEnterRed = vi.fn(); + const onEnterGreen = vi.fn(); + const onEnterYellow = vi.fn(); const fsm = new FSM({}) .addState("red") @@ -285,20 +287,20 @@ describe("finite state machine", () => { test("executes group-based enter/exit handlers correctly", () => { const calls: string[] = []; - const exitMachine = jest.fn(() => void calls.push("exited machine")); - const enterMachine = jest.fn(() => { + const exitMachine = vi.fn(() => void calls.push("exited machine")); + const enterMachine = vi.fn(() => { calls.push("entered machine"); return exitMachine; }); - const exitGroup = jest.fn(() => void calls.push("exited group")); - const enterGroup = jest.fn(() => { + const exitGroup = vi.fn(() => void calls.push("exited group")); + const enterGroup = vi.fn(() => { calls.push("entered group"); return exitGroup; }); - const exitRed = jest.fn(() => void calls.push("exited red")); - const enterRed = jest.fn(() => { + const exitRed = vi.fn(() => void calls.push("exited red")); + const enterRed = vi.fn(() => { calls.push("entered red"); return exitRed; }); @@ -491,8 +493,8 @@ describe("finite state machine", () => { }); test("side effects", () => { - const reset = jest.fn(); - const inced = jest.fn(); + const reset = vi.fn(); + const inced = vi.fn(); const fsm = new FSM({ x: 13, y: 13 }) .addState("one") @@ -572,7 +574,7 @@ describe("finite state machine", () => { describe("time-based transitions", () => { test("time-based transitions", () => { - jest.useFakeTimers(); + vi.useFakeTimers(); const fsm = new FSM({}) .addState("start.one") @@ -595,12 +597,12 @@ describe("finite state machine", () => { fsm.send({ type: "GO" }); expect(fsm.currentState).toEqual("start.two"); - jest.runAllTimers(); // Make the timer go off... + vi.runAllTimers(); // Make the timer go off... expect(fsm.currentState).toEqual("timed-out"); // ...the timer causes the machine to move to "timed-out" state }); test("time-based transitions get cancelled", () => { - jest.useFakeTimers(); + vi.useFakeTimers(); const fsm = new FSM({}) .addState("start.one") @@ -616,7 +618,7 @@ describe("finite state machine", () => { .start(); - jest.advanceTimersByTime(5000); // Not far enough yet + vi.advanceTimersByTime(5000); // Not far enough yet // Staying within the "start" group won't cancel expect(fsm.currentState).toEqual("start.one"); @@ -628,7 +630,7 @@ describe("finite state machine", () => { fsm.send({ type: "END" }); expect(fsm.currentState).toEqual("end"); - jest.runAllTimers(); // Make the timer go off... + vi.runAllTimers(); // Make the timer go off... expect(fsm.currentState).toEqual("end"); // ...it should _NOT_ move to timed-out state anymore }); }); @@ -655,79 +657,79 @@ describe("finite state machine", () => { } test("promise-based transitions (on success, within timeout)", async () => { - jest.useFakeTimers(); + vi.useFakeTimers(); const fsm = makeFSM(() => wait(2000)); fsm.start(); expect(fsm.currentState).toEqual("waiting.one"); - await jest.advanceTimersByTimeAsync(1000); + await vi.advanceTimersByTimeAsync(1000); expect(fsm.currentState).toEqual("waiting.one"); - await jest.runAllTimersAsync(); + await vi.runAllTimersAsync(); expect(fsm.currentState).toEqual("good"); fsm.stop(); }); test("promise-based transitions (on failure, within timeout)", async () => { - jest.useFakeTimers(); + vi.useFakeTimers(); const fsm = makeFSM(() => failAfter(2000)); fsm.start(); expect(fsm.currentState).toEqual("waiting.one"); - await jest.runAllTimersAsync(); + await vi.runAllTimersAsync(); expect(fsm.currentState).toEqual("bad"); fsm.stop(); }); test("promise-based transitions (on timeout)", async () => { - jest.useFakeTimers(); + vi.useFakeTimers(); // One millisecond longer than the allowed timeout (30_000) const fsm = makeFSM(() => wait(30_001)); fsm.start(); expect(fsm.currentState).toEqual("waiting.one"); - await jest.runAllTimersAsync(); + await vi.runAllTimersAsync(); expect(fsm.currentState).toEqual("bad"); fsm.stop(); }); test("promise-based transitions abort successfully (on success)", async () => { - jest.useFakeTimers(); + vi.useFakeTimers(); const fsm = makeFSM(() => wait(2000)); fsm.start(); expect(fsm.currentState).toEqual("waiting.one"); - await jest.advanceTimersByTimeAsync(1000); + await vi.advanceTimersByTimeAsync(1000); expect(fsm.currentState).toEqual("waiting.one"); fsm.send({ type: "FAIL" }); // Manually failing first... expect(fsm.currentState).toEqual("bad"); - await jest.runAllTimersAsync(); + await vi.runAllTimersAsync(); expect(fsm.currentState).toEqual("bad"); // ...will ignore the returned promise transition }); test("promise-based transitions abort successfully (on failure)", async () => { - jest.useFakeTimers(); + vi.useFakeTimers(); const fsm = makeFSM(() => failAfter(2000)); fsm.start(); expect(fsm.currentState).toEqual("waiting.one"); - await jest.advanceTimersByTimeAsync(1000); + await vi.advanceTimersByTimeAsync(1000); expect(fsm.currentState).toEqual("waiting.one"); fsm.send({ type: "OK" }); // Manually failing first... expect(fsm.currentState).toEqual("good"); - await jest.runAllTimersAsync(); + await vi.runAllTimersAsync(); expect(fsm.currentState).toEqual("good"); // ...will ignore the returned promise transition }); test("promise-based transitions won't abort within group", async () => { - jest.useFakeTimers(); + vi.useFakeTimers(); const fsm = makeFSM(() => failAfter(2000)); fsm.start(); @@ -737,7 +739,7 @@ describe("finite state machine", () => { expect(fsm.currentState).toEqual("waiting.two"); fsm.send({ type: "JUMP" }); expect(fsm.currentState).toEqual("waiting.one"); - await jest.advanceTimersByTimeAsync(1000); + await vi.advanceTimersByTimeAsync(1000); // We can keep jumping between waiting.* states without the promise // getting cancelled (unlike jumping to "good" or "bad") @@ -745,12 +747,12 @@ describe("finite state machine", () => { fsm.send({ type: "JUMP" }); expect(fsm.currentState).toEqual("waiting.two"); - await jest.runAllTimersAsync(); + await vi.runAllTimersAsync(); expect(fsm.currentState).toEqual("bad"); // ...will ignore the returned promise transition }); test("promise-based transitions abort with signal handler (when aborted)", async () => { - jest.useFakeTimers(); + vi.useFakeTimers(); let gotAborted = false; @@ -769,19 +771,19 @@ describe("finite state machine", () => { fsm.start(); expect(fsm.currentState).toEqual("waiting.one"); - await jest.advanceTimersByTimeAsync(1000); + await vi.advanceTimersByTimeAsync(1000); expect(fsm.currentState).toEqual("waiting.one"); expect(gotAborted).toEqual(false); fsm.send({ type: "FAIL" }); // Manually failing first... expect(gotAborted).toEqual(true); expect(fsm.currentState).toEqual("bad"); - await jest.runAllTimersAsync(); + await vi.runAllTimersAsync(); expect(fsm.currentState).toEqual("bad"); // ...will ignore the returned promise transition expect(gotAborted).toEqual(true); }); test("promise-based transitions abort with signal handler (when timed out)", async () => { - jest.useFakeTimers(); + vi.useFakeTimers(); let gotAborted = false; @@ -801,14 +803,14 @@ describe("finite state machine", () => { expect(fsm.currentState).toEqual("waiting.one"); expect(gotAborted).toEqual(false); - await jest.runAllTimersAsync(); + await vi.runAllTimersAsync(); expect(gotAborted).toEqual(true); // Got aborted by timeout expect(fsm.currentState).toEqual("bad"); fsm.stop(); }); test("promise-based transitions abort with signal handler (when not aborted)", async () => { - jest.useFakeTimers(); + vi.useFakeTimers(); let hijackedSignal: AbortSignal | undefined; @@ -820,13 +822,13 @@ describe("finite state machine", () => { fsm.start(); expect(fsm.currentState).toEqual("waiting.one"); - await jest.runAllTimersAsync(); + await vi.runAllTimersAsync(); expect(fsm.currentState).toEqual("good"); expect(hijackedSignal?.aborted).toEqual(false); }); test("promise-based transitions abort with signal inspection (when aborted)", async () => { - jest.useFakeTimers(); + vi.useFakeTimers(); let gotAborted = false; @@ -838,19 +840,19 @@ describe("finite state machine", () => { fsm.start(); expect(fsm.currentState).toEqual("waiting.one"); - await jest.advanceTimersByTimeAsync(1000); + await vi.advanceTimersByTimeAsync(1000); expect(fsm.currentState).toEqual("waiting.one"); expect(gotAborted).toEqual(false); fsm.send({ type: "FAIL" }); // Manually failing first... expect(gotAborted).toEqual(false); // not yet visible before promise has run expect(fsm.currentState).toEqual("bad"); - await jest.runAllTimersAsync(); + await vi.runAllTimersAsync(); expect(gotAborted).toEqual(true); expect(fsm.currentState).toEqual("bad"); // ...will ignore the returned promise transition }); test("promise-based transitions abort with signal inspection (when not aborted)", async () => { - jest.useFakeTimers(); + vi.useFakeTimers(); let hijackedSignal: AbortSignal | undefined; @@ -862,13 +864,13 @@ describe("finite state machine", () => { fsm.start(); expect(fsm.currentState).toEqual("waiting.one"); - await jest.runAllTimersAsync(); + await vi.runAllTimersAsync(); expect(fsm.currentState).toEqual("good"); expect(hijackedSignal?.aborted).toEqual(false); }); test("promise-based transitions abort failing promise with signal handler (when aborted)", async () => { - jest.useFakeTimers(); + vi.useFakeTimers(); let gotAborted = false; @@ -887,19 +889,19 @@ describe("finite state machine", () => { fsm.start(); expect(fsm.currentState).toEqual("waiting.one"); - await jest.advanceTimersByTimeAsync(1000); + await vi.advanceTimersByTimeAsync(1000); expect(fsm.currentState).toEqual("waiting.one"); expect(gotAborted).toEqual(false); fsm.send({ type: "OK" }); // Manually move to good... expect(gotAborted).toEqual(true); expect(fsm.currentState).toEqual("good"); - await jest.runAllTimersAsync(); + await vi.runAllTimersAsync(); expect(fsm.currentState).toEqual("good"); // ...will ignore the returned promise transition expect(gotAborted).toEqual(true); }); test("promise-based transitions abort failing promise with signal handler (when not aborted)", async () => { - jest.useFakeTimers(); + vi.useFakeTimers(); let gotAborted = false; @@ -918,13 +920,13 @@ describe("finite state machine", () => { fsm.start(); expect(fsm.currentState).toEqual("waiting.one"); - await jest.runAllTimersAsync(); + await vi.runAllTimersAsync(); expect(fsm.currentState).toEqual("bad"); expect(gotAborted).toEqual(false); }); test("promise-based transitions abort failing promise with signal inspection (when aborted)", async () => { - jest.useFakeTimers(); + vi.useFakeTimers(); let hijackedSignal: AbortSignal | undefined; @@ -936,7 +938,7 @@ describe("finite state machine", () => { fsm.start(); expect(fsm.currentState).toEqual("waiting.one"); - await jest.advanceTimersByTimeAsync(1000); + await vi.advanceTimersByTimeAsync(1000); expect(fsm.currentState).toEqual("waiting.one"); expect(hijackedSignal?.aborted).toEqual(false); fsm.send({ type: "OK" }); // Manually move to good... @@ -946,7 +948,7 @@ describe("finite state machine", () => { }); test("promise-based transitions abort failing promise with signal inspection (when not aborted)", async () => { - jest.useFakeTimers(); + vi.useFakeTimers(); let hijackedSignal: AbortSignal | undefined; @@ -958,7 +960,7 @@ describe("finite state machine", () => { fsm.start(); expect(fsm.currentState).toEqual("waiting.one"); - await jest.runAllTimersAsync(); + await vi.runAllTimersAsync(); expect(fsm.currentState).toEqual("bad"); expect(hijackedSignal?.aborted).toEqual(false); }); diff --git a/packages/liveblocks-core/src/lib/__tests__/nanoid.test.ts b/packages/liveblocks-core/src/lib/__tests__/nanoid.test.ts index b0276af3761..4db8911ddcd 100644 --- a/packages/liveblocks-core/src/lib/__tests__/nanoid.test.ts +++ b/packages/liveblocks-core/src/lib/__tests__/nanoid.test.ts @@ -1,9 +1,10 @@ import fc from "fast-check"; +import { describe, expect, test } from "vitest"; import { nanoid } from "../nanoid"; describe("nanoid", () => { - it("generated random strings with given length", () => { + test("generated random strings with given length", () => { fc.assert( fc.property(fc.integer({ min: 0, max: 256 }), (n) => { expect(nanoid(n).length).toBe(n); @@ -11,7 +12,7 @@ describe("nanoid", () => { ); }); - it("generates unique values every time", () => { + test("generates unique values every time", () => { // When called a 1000 times, expect at least 9999 of them to be unique expect( new Set(Array.from({ length: 1000 }, () => nanoid())).size diff --git a/packages/liveblocks-core/src/lib/__tests__/objectToQuery.test.ts b/packages/liveblocks-core/src/lib/__tests__/objectToQuery.test.ts index e7446c70035..5df662bc200 100644 --- a/packages/liveblocks-core/src/lib/__tests__/objectToQuery.test.ts +++ b/packages/liveblocks-core/src/lib/__tests__/objectToQuery.test.ts @@ -1,11 +1,12 @@ /* eslint-disable quotes */ import { QueryParser } from "@liveblocks/query-parser"; import * as fc from "fast-check"; +import { describe, expect, test } from "vitest"; import { objectToQuery, quote } from "../objectToQuery"; describe("objectToQuery", () => { - it("should convert a simple key/value pair to a query", () => { + test("should convert a simple key/value pair to a query", () => { const query = objectToQuery({ org: "liveblocks:engineering", }); @@ -13,7 +14,7 @@ describe("objectToQuery", () => { expect(query).toEqual("org:'liveblocks:engineering'"); }); - it("should convert a nested object with operator to a query", () => { + test("should convert a nested object with operator to a query", () => { const query = objectToQuery({ org: { startsWith: "liveblocks:", @@ -23,7 +24,7 @@ describe("objectToQuery", () => { expect(query).toEqual("org^'liveblocks:'"); }); - it("should convert an indexed field object to a query", () => { + test("should convert an indexed field object to a query", () => { const query = objectToQuery({ metadata: { status: "open", @@ -40,7 +41,7 @@ describe("objectToQuery", () => { ); }); - it("should convert regular and indexed field objects to a query", () => { + test("should convert regular and indexed field objects to a query", () => { const query = objectToQuery({ metadata: { status: "open", @@ -61,7 +62,7 @@ describe("objectToQuery", () => { ); }); - it.each([ + test.each([ "string", "string with spaces", "string with special characters: !@#$%^&*()", @@ -83,7 +84,7 @@ describe("objectToQuery", () => { ); }); - it("will only generate syntactically valid queries", () => + test("will only generate syntactically valid queries", () => fc.assert( fc.property( fc.dictionary( @@ -128,7 +129,7 @@ describe("objectToQuery", () => { ) )); - it("previous regressions", () => { + test("previous regressions", () => { const BS = "\\"; const SQ = "'"; const DQ = '"'; @@ -195,7 +196,7 @@ describe("objectToQuery", () => { } }); - it.each([ + test.each([ "'string with single quotes'", '"string with double quotes"', '"string with both \'single\' and "double" quotes"', @@ -210,7 +211,7 @@ describe("objectToQuery", () => { expect(query).toEqual(`metadata[${quote(key)}]:'value'`); }); - it("should avoid injections", () => { + test("should avoid injections", () => { const query1 = objectToQuery({ foo: '" OR evil:"' }); // ^^^^^^^^^^^^^ Injection attack with double-quoted strings diff --git a/packages/liveblocks-core/src/lib/__tests__/position.test.ts b/packages/liveblocks-core/src/lib/__tests__/position.test.ts index 5d83a9f4092..b33c22b5477 100644 --- a/packages/liveblocks-core/src/lib/__tests__/position.test.ts +++ b/packages/liveblocks-core/src/lib/__tests__/position.test.ts @@ -1,4 +1,5 @@ import * as fc from "fast-check"; +import { describe, expect, test } from "vitest"; import type { Pos } from "../position"; import { @@ -136,7 +137,7 @@ describe("digits", () => { }); describe("position datastructure", () => { - it("zero is an illegal Pos value", () => { + test("zero is an illegal Pos value", () => { fc.assert( fc.property( genZeroes(), @@ -148,7 +149,7 @@ describe("position datastructure", () => { ); }); - it("for valid strings, asPos is a noop", () => { + test("for valid strings, asPos is a noop", () => { fc.assert( fc.property( genPos(), @@ -160,7 +161,7 @@ describe("position datastructure", () => { ); }); - it("asPos is idempotent", () => { + test("asPos is idempotent", () => { fc.assert( fc.property( fc.string(), @@ -280,7 +281,7 @@ describe("after / before", () => { expect(after(asPos(NINE + THREE))).toBe(NINE + FOUR); // e.g. after(.93) => .99 }); - it("always outputs valid Pos values", () => { + test("always outputs valid Pos values", () => { fc.assert( fc.property( genPos(), @@ -293,7 +294,7 @@ describe("after / before", () => { ); }); - it('after generates alphabetically "higher" values', () => { + test('after generates alphabetically "higher" values', () => { fc.assert( fc.property( genUnverifiedPos(), @@ -306,7 +307,7 @@ describe("after / before", () => { ); }); - it('before generates alphabetically "lower" values', () => { + test('before generates alphabetically "lower" values', () => { fc.assert( fc.property( genPos(), @@ -321,7 +322,7 @@ describe("after / before", () => { }); describe("between", () => { - it("throws for equal values", () => { + test("throws for equal values", () => { expect(() => between(asPos("x"), asPos("x"))).toThrow(); expect(() => between(asPos("x"), asPos("x "))).toThrow(); @@ -336,7 +337,7 @@ describe("between", () => { ); }); - it("always output valid positions", () => { + test("always output valid positions", () => { fc.assert( fc.property( genPosRange(), @@ -348,7 +349,7 @@ describe("between", () => { ); }); - it("arguments are commutative", () => { + test("arguments are commutative", () => { fc.assert( fc.property( genPos(), @@ -363,7 +364,7 @@ describe("between", () => { ); }); - it("generates values that are alphabetically between inputs", () => { + test("generates values that are alphabetically between inputs", () => { fc.assert( fc.property( genPosRange(), @@ -474,13 +475,13 @@ describe("makePosition", () => { }); describe("comparePosition", () => { - it("basics", () => { + test("basics", () => { expect(asPos("1") < asPos("2")).toBe(true); expect(asPos("!") < asPos("~~")).toBe(true); expect(asPos("11111") > asPos("11")).toBe(true); }); - it("correct compares output of before/after", () => { + test("correct compares output of before/after", () => { fc.assert( fc.property( genPos(), @@ -495,7 +496,7 @@ describe("comparePosition", () => { ); }); - it("correct compares output of between", () => { + test("correct compares output of between", () => { fc.assert( fc.property( genPosRange(), diff --git a/packages/liveblocks-core/src/lib/__tests__/shallow.test.ts b/packages/liveblocks-core/src/lib/__tests__/shallow.test.ts index fbda3a7ad54..45fe886b579 100644 --- a/packages/liveblocks-core/src/lib/__tests__/shallow.test.ts +++ b/packages/liveblocks-core/src/lib/__tests__/shallow.test.ts @@ -1,4 +1,5 @@ import fc from "fast-check"; +import { describe, expect, test } from "vitest"; import { shallow } from "../shallow"; @@ -36,7 +37,7 @@ const nonpojo = () => ); describe("shallow", () => { - it("scalar values", () => { + test("scalar values", () => { expect(shallow(0, 0)).toBe(true); expect(shallow("", "")).toBe(true); expect(shallow("hi", "hi")).toBe(true); @@ -52,7 +53,7 @@ describe("shallow", () => { expect(shallow(-0, +0)).toBe(false); }); - it("scalar values wrapped in list", () => { + test("scalar values wrapped in list", () => { expect(shallow([0], [0])).toBe(true); expect(shallow([""], [""])).toBe(true); expect(shallow(["hi"], ["hi"])).toBe(true); @@ -68,7 +69,7 @@ describe("shallow", () => { expect(shallow([-0], [+0])).toBe(false); }); - it("scalar values wrapped in objs", () => { + test("scalar values wrapped in objs", () => { expect(shallow({ k: 0 }, { k: 0 })).toBe(true); expect(shallow({ k: "" }, { k: "" })).toBe(true); expect(shallow({ k: "hi" }, { k: "hi" })).toBe(true); @@ -84,7 +85,7 @@ describe("shallow", () => { expect(shallow({ k: -0 }, { k: +0 })).toBe(false); }); - it("different outer types are never equal", () => { + test("different outer types are never equal", () => { expect(shallow({}, [])).toBe(false); expect(shallow([], {})).toBe(false); expect(shallow(new Date(), new Date())).toBe(false); @@ -93,15 +94,15 @@ describe("shallow", () => { expect(shallow({}, new Date())).toBe(false); }); - it("key order does not matter", () => { + test("key order does not matter", () => { expect(shallow({ a: 1, b: 2 }, { b: 2, a: 1 })).toBe(true); }); - it("different key counts are never equal", () => { + test("different key counts are never equal", () => { expect(shallow({ a: undefined, b: 1 }, { b: 1 })).toBe(false); }); - it("sparse arrays", () => { + test("sparse arrays", () => { // Sparse arrays should not break /* eslint-disable no-sparse-arrays */ expect(shallow([,], ["oops", 1])).toBe(false); @@ -113,7 +114,7 @@ describe("shallow", () => { }); describe("shallow (properties)", () => { - it("all equal scalars are shallowly equal", () => { + test("all equal scalars are shallowly equal", () => { fc.assert( fc.property( // Inputs @@ -146,7 +147,7 @@ describe("shallow (properties)", () => { ); }); - it("different scalars are not shallowly equal", () => { + test("different scalars are not shallowly equal", () => { fc.assert( fc.property( // Inputs @@ -167,7 +168,7 @@ describe("shallow (properties)", () => { ); }); - it("equal composite values", () => { + test("equal composite values", () => { fc.assert( fc.property( // Inputs @@ -191,7 +192,7 @@ describe("shallow (properties)", () => { ); }); - it("consistency", () => { + test("consistency", () => { fc.assert( fc.property( // Inputs @@ -218,7 +219,7 @@ describe("shallow (properties)", () => { ); }); - it("argument ordering does not matter", () => { + test("argument ordering does not matter", () => { fc.assert( fc.property( // Inputs @@ -238,7 +239,7 @@ describe("shallow (properties)", () => { ); }); - it("date (and other non-pojos) are never considered equal", () => { + test("date (and other non-pojos) are never considered equal", () => { fc.assert( fc.property( // Inputs diff --git a/packages/liveblocks-core/src/lib/__tests__/shallow2.test.ts b/packages/liveblocks-core/src/lib/__tests__/shallow2.test.ts index 631727f62f7..230427e4b16 100644 --- a/packages/liveblocks-core/src/lib/__tests__/shallow2.test.ts +++ b/packages/liveblocks-core/src/lib/__tests__/shallow2.test.ts @@ -1,3 +1,5 @@ +import { describe, expect, test } from "vitest"; + import { shallow, shallow2 } from "../shallow"; const THING1 = { a: 1 }; diff --git a/packages/liveblocks-core/src/lib/__tests__/signals/DerivedSignal.test.ts b/packages/liveblocks-core/src/lib/__tests__/signals/DerivedSignal.test.ts index cb8ada7e904..ce7afe909bf 100644 --- a/packages/liveblocks-core/src/lib/__tests__/signals/DerivedSignal.test.ts +++ b/packages/liveblocks-core/src/lib/__tests__/signals/DerivedSignal.test.ts @@ -1,8 +1,10 @@ +import { expect, test, vi } from "vitest"; + import { shallow } from "../../../lib/shallow"; import { batch, DerivedSignal, Signal } from "../../../lib/signals"; import { DefaultMap } from "../../DefaultMap"; -it("compute signal from other signals", () => { +test("compute signal from other signals", () => { const greeting = new Signal("hi"); const count = new Signal(3); const derived = DerivedSignal.from( @@ -25,7 +27,7 @@ it("compute signal from other signals", () => { expect(derived.get()).toEqual("!"); }); -it("compute signal from many other signals", () => { +test("compute signal from many other signals", () => { const jokesSignal = new Signal(["joke1", "joke2"]); const allGreatSignal = new Signal(false); const multiplierSignal = new Signal(1); // Number of laughs per joke @@ -51,7 +53,7 @@ it("compute signal from many other signals", () => { expect(greatLaughsSignal.get()).toEqual(["HA", "HA", "HA", "HA", "HA", "HA"]); }); -it("derived signal chaining", () => { +test("derived signal chaining", () => { const counter = new Signal(0); const isEven = DerivedSignal.from(counter, (n) => (n & 1) === 0); const parity = DerivedSignal.from(isEven, (even) => (even ? "even" : "odd")); @@ -74,7 +76,7 @@ it("derived signal chaining", () => { expect(parity.isDirty).toEqual(false); }); -it("derived signals re-evaluate when sources change (without listeners)", () => { +test("derived signals re-evaluate when sources change (without listeners)", () => { const counter = new Signal(0); const isEven = DerivedSignal.from(counter, (n) => (n & 1) === 0); const parity = DerivedSignal.from(isEven, (even) => (even ? "even" : "odd")); @@ -94,7 +96,7 @@ it("derived signals re-evaluate when sources change (without listeners)", () => expect(parity.get()).toEqual("odd"); }); -it("derived signals re-evaluate when sources change (with listeners)", () => { +test("derived signals re-evaluate when sources change (with listeners)", () => { const counter = new Signal(0); const isEven = DerivedSignal.from(counter, (n) => (n & 1) === 0); const parity = DerivedSignal.from(isEven, (even) => (even ? "even" : "odd")); @@ -118,7 +120,7 @@ it("derived signals re-evaluate when sources change (with listeners)", () => { unsub(); }); -it("derived signals re-evaluate when sources change (with listeners in parent)", () => { +test("derived signals re-evaluate when sources change (with listeners in parent)", () => { const counter = new Signal(0); const isEven = DerivedSignal.from(counter, (n) => (n & 1) === 0); const parity = DerivedSignal.from(isEven, (even) => (even ? "even" : "odd")); @@ -142,7 +144,7 @@ it("derived signals re-evaluate when sources change (with listeners in parent)", unsub(); }); -it("derived signals re-evaluate when sources change (with listeners in grandparent)", () => { +test("derived signals re-evaluate when sources change (with listeners in grandparent)", () => { const counter = new Signal(0); const isEven = DerivedSignal.from(counter, (n) => (n & 1) === 0); const parity = DerivedSignal.from(isEven, (even) => (even ? "even" : "odd")); @@ -166,8 +168,8 @@ it("derived signals re-evaluate when sources change (with listeners in grandpare unsub(); }); -it("signals only notify watchers when their value changes", () => { - const fn = jest.fn(); +test("signals only notify watchers when their value changes", () => { + const fn = vi.fn(); const counter = new Signal(0); const isEven = DerivedSignal.from(counter, (n) => (n & 1) === 0); @@ -197,10 +199,10 @@ it("signals only notify watchers when their value changes", () => { unsub(); }); -it("signals only notify watchers when their value changes (with shallow)", () => { +test("signals only notify watchers when their value changes (with shallow)", () => { let numEvals = 0; - const fn = jest.fn(); + const fn = vi.fn(); const fruits = new Signal([]); const uppercase = new Signal(false); @@ -246,9 +248,9 @@ it("signals only notify watchers when their value changes (with shallow)", () => unsub(); }); -it("batch signal updates so derived signals will only be notified once", () => { - const fn1 = jest.fn(); // Callback when z changes - const fn2 = jest.fn(); // Callback when zz changes +test("batch signal updates so derived signals will only be notified once", () => { + const fn1 = vi.fn(); // Callback when z changes + const fn2 = vi.fn(); // Callback when zz changes const x = new Signal(1); const y = new Signal(2); @@ -277,7 +279,7 @@ it("batch signal updates so derived signals will only be notified once", () => { unsub2(); }); -it("batch signal notifications and re-evaluations are as efficient as possible", () => { +test("batch signal notifications and re-evaluations are as efficient as possible", () => { const x = new Signal(1); const y = new Signal(2); const z = new Signal(3); @@ -320,7 +322,7 @@ it("batch signal notifications and re-evaluations are as efficient as possible", const after2 = sorted.get(); expect(after2).toBe(before); - const fn = jest.fn(); // Callback when sorted changes + const fn = vi.fn(); // Callback when sorted changes const unsub = sorted.subscribe(fn); expect(fn).not.toHaveBeenCalled(); @@ -348,7 +350,7 @@ it("batch signal notifications and re-evaluations are as efficient as possible", unsub(); }); -it("conditionally read from other signal", () => { +test("conditionally read from other signal", () => { const index = new Signal(0); // Signal to read const signals = [ new Signal("hi"), @@ -384,8 +386,8 @@ it("conditionally read from other signal", () => { expect(derived.isDirty).toEqual(false); }); -it("conditionally read nested signals", () => { - const fn = jest.fn(); +test("conditionally read nested signals", () => { + const fn = vi.fn(); const map = new DefaultMap>(() => new Signal(0)); map.getOrCreate(0).set(7); @@ -439,9 +441,9 @@ it("conditionally read nested signals", () => { expect(derived.get()).toEqual(1234); }); -it("conditionally reading signals won't unregister old sinks (when using static syntax)", () => { - const notificationFn = jest.fn(); - const evalFn = jest.fn(); +test("conditionally reading signals won't unregister old sinks (when using static syntax)", () => { + const notificationFn = vi.fn(); + const evalFn = vi.fn(); const cond = new Signal(false); const x = new Signal(7); const y = new Signal(42); @@ -476,9 +478,9 @@ it("conditionally reading signals won't unregister old sinks (when using static unsub(); }); -it("conditionally reading signals will unregister old sinks (when using dynamic syntax)", () => { - const notificationFn = jest.fn(); - const evalFn = jest.fn(); +test("conditionally reading signals will unregister old sinks (when using dynamic syntax)", () => { + const notificationFn = vi.fn(); + const evalFn = vi.fn(); const cond = new Signal(false); const x = new Signal(7); const y = new Signal(42); @@ -514,10 +516,10 @@ it("conditionally reading signals will unregister old sinks (when using dynamic unsub(); }); -it("conditionally read from nested signals", () => { +test("conditionally read from nested signals", () => { const map = new DefaultMap>(() => new Signal(0)); const prefix = new Signal("pre"); - const fn = jest.fn(); + const fn = vi.fn(); const derived = DerivedSignal.from( prefix, diff --git a/packages/liveblocks-core/src/lib/__tests__/signals/MutableSignal.test.ts b/packages/liveblocks-core/src/lib/__tests__/signals/MutableSignal.test.ts index fe88d30100e..28dd20af39d 100644 --- a/packages/liveblocks-core/src/lib/__tests__/signals/MutableSignal.test.ts +++ b/packages/liveblocks-core/src/lib/__tests__/signals/MutableSignal.test.ts @@ -1,4 +1,5 @@ import fc from "fast-check"; +import { expect, test, vi } from "vitest"; import { batch, DerivedSignal, MutableSignal, Signal } from "../../signals"; @@ -11,8 +12,8 @@ test("empty", () => { expect(new MutableSignal([1, 2, 3]).get()).toStrictEqual([1, 2, 3]); }); -it("signals always notify watchers whenever mutated (because we cannot tell if their value has changed)", () => { - const fn = jest.fn(); +test("signals always notify watchers whenever mutated (because we cannot tell if their value has changed)", () => { + const fn = vi.fn(); type S = { counter: 0 }; @@ -58,7 +59,7 @@ it("signals always notify watchers whenever mutated (because we cannot tell if t unsub(); }); -it("signals throw when used with an async mutation function", () => { +test("signals throw when used with an async mutation function", () => { type S = { counter: 0 }; const counter = new MutableSignal({ counter: 0 }); const asyncInc = (state: S) => Promise.resolve(state.counter++); @@ -68,7 +69,7 @@ it("signals throw when used with an async mutation function", () => { ); }); -it("when chained, derived signals will think the value changed", () => { +test("when chained, derived signals will think the value changed", () => { const fruits = new MutableSignal([]); const count = DerivedSignal.from(fruits, (fruits) => fruits.length); const str = DerivedSignal.from(fruits, (fruits) => fruits.join(",")); @@ -97,9 +98,9 @@ it("when chained, derived signals will think the value changed", () => { expect(str.get()).toEqual("apple,banana,cherry"); }); -it("when batched, derived signals will only update the value changed", () => { - const evaled = jest.fn(); - const watcher = jest.fn(); +test("when batched, derived signals will only update the value changed", () => { + const evaled = vi.fn(); + const watcher = vi.fn(); const fruits = new MutableSignal([]); const count = new Signal(0); @@ -139,9 +140,9 @@ it("when batched, derived signals will only update the value changed", () => { unsub(); }); -it("nesting of mutations", () => { - const evaled = jest.fn(); - const watcher = jest.fn(); +test("nesting of mutations", () => { + const evaled = vi.fn(); + const watcher = vi.fn(); const fruits = new MutableSignal([]); const count = new Signal(1); diff --git a/packages/liveblocks-core/src/lib/__tests__/signals/PatchableSignal.test.ts b/packages/liveblocks-core/src/lib/__tests__/signals/PatchableSignal.test.ts index 99cf15a3a64..fea30508779 100644 --- a/packages/liveblocks-core/src/lib/__tests__/signals/PatchableSignal.test.ts +++ b/packages/liveblocks-core/src/lib/__tests__/signals/PatchableSignal.test.ts @@ -1,3 +1,5 @@ +import { describe, expect, test } from "vitest"; + import { PatchableSignal } from "../../signals"; type P = { @@ -7,20 +9,20 @@ type P = { }; describe('Read-only "patchable" ref cache', () => { - it("empty", () => { + test("empty", () => { const ref = new PatchableSignal({ x: 0, y: 0, z: undefined }); expect(ref.get()).toStrictEqual({ x: 0, y: 0 }); }); describe("tracking", () => { - it("patching", () => { + test("patching", () => { const ref = new PatchableSignal

({ x: 0, y: 0 }); ref.patch({ y: 1, z: 2 }); expect(ref.get()).toStrictEqual({ x: 0, y: 1, z: 2 }); }); - it("patching me with undefineds deletes keys", () => { + test("patching me with undefineds deletes keys", () => { const ref = new PatchableSignal

({ x: 1, y: 2 }); ref.patch({ x: undefined }); @@ -35,7 +37,7 @@ describe('Read-only "patchable" ref cache', () => { }); describe("caching", () => { - it("caches immutable results", () => { + test("caches immutable results", () => { const ref = new PatchableSignal

({ x: 0, y: 0 }); const me1 = ref.get(); diff --git a/packages/liveblocks-core/src/lib/__tests__/signals/Signal.test.ts b/packages/liveblocks-core/src/lib/__tests__/signals/Signal.test.ts index 9141997c47d..62ffb66e429 100644 --- a/packages/liveblocks-core/src/lib/__tests__/signals/Signal.test.ts +++ b/packages/liveblocks-core/src/lib/__tests__/signals/Signal.test.ts @@ -1,4 +1,5 @@ import fc from "fast-check"; +import { expect, test, vi } from "vitest"; import { shallow } from "../../../lib/shallow"; import { batch, Signal } from "../../signals"; @@ -32,8 +33,8 @@ test("with custom equals function", () => { } }); -it("signals only notify watchers when their value changes", () => { - const fn = jest.fn(); +test("signals only notify watchers when their value changes", () => { + const fn = vi.fn(); const counter = new Signal(0); @@ -52,8 +53,8 @@ it("signals only notify watchers when their value changes", () => { unsub(); }); -it("without batching three signal updates will lead to three notifications", () => { - const fn = jest.fn(); +test("without batching three signal updates will lead to three notifications", () => { + const fn = vi.fn(); const x = new Signal(1); const unsub = x.subscribe(fn); @@ -71,8 +72,8 @@ it("without batching three signal updates will lead to three notifications", () unsub(); }); -it("batched signal updates notify only once", () => { - const fn = jest.fn(); +test("batched signal updates notify only once", () => { + const fn = vi.fn(); const x = new Signal(1); const unsub = x.subscribe(fn); diff --git a/packages/liveblocks-core/src/lib/__tests__/stringify.test.ts b/packages/liveblocks-core/src/lib/__tests__/stringify.test.ts index 03ac2e7e33f..40b0e2bd0ed 100644 --- a/packages/liveblocks-core/src/lib/__tests__/stringify.test.ts +++ b/packages/liveblocks-core/src/lib/__tests__/stringify.test.ts @@ -1,7 +1,9 @@ +import { describe, expect, test } from "vitest"; + import { stableStringify } from "../stringify"; describe("stable stringify", () => { - it("returns the same result as JSON.stringify", () => { + test("returns the same result as JSON.stringify", () => { expect( stableStringify({ a: 2, @@ -18,7 +20,7 @@ describe("stable stringify", () => { expect(stableStringify(null)).toEqual(JSON.stringify(null)); }); - it("supports objects in a stable way", () => { + test("supports objects in a stable way", () => { expect( stableStringify({ a: 2, @@ -32,7 +34,7 @@ describe("stable stringify", () => { ); }); - it("supports nested objects", () => { + test("supports nested objects", () => { expect(stableStringify([{ a: 2, b: true }])).toEqual( stableStringify([{ b: true, a: 2 }]) ); @@ -41,7 +43,7 @@ describe("stable stringify", () => { ).toEqual(stableStringify([{ b: true, a: 2, c: [[{ d: 0, e: 0 }]] }])); }); - it("explicitly-undefined keys become implicit-undefined", () => { + test("explicitly-undefined keys become implicit-undefined", () => { expect(stableStringify([{ b: true, c: undefined, a: 2 }])).toEqual( '[{"a":2,"b":true}]' ); diff --git a/packages/liveblocks-core/src/lib/__tests__/url.test.ts b/packages/liveblocks-core/src/lib/__tests__/url.test.ts index c4c33d9bb0d..76e0253b5ac 100644 --- a/packages/liveblocks-core/src/lib/__tests__/url.test.ts +++ b/packages/liveblocks-core/src/lib/__tests__/url.test.ts @@ -1,7 +1,9 @@ +import { describe, expect, test } from "vitest"; + import { generateUrl, sanitizeUrl } from "../url"; describe("sanitizeUrl", () => { - it("should return valid URLs as-is", () => { + test("should return valid URLs as-is", () => { expect(sanitizeUrl("https://liveblocks.io")).toBe("https://liveblocks.io"); expect(sanitizeUrl("https://liveblocks.io/docs")).toBe( "https://liveblocks.io/docs" @@ -13,19 +15,19 @@ describe("sanitizeUrl", () => { expect(sanitizeUrl("#anchor")).toBe("#anchor"); }); - it("should normalize relative URLs", () => { + test("should normalize relative URLs", () => { expect(sanitizeUrl("./docs")).toBe("/docs"); expect(sanitizeUrl("../docs")).toBe("/docs"); }); - it("should normalize www URLs to HTTPS", () => { + test("should normalize www URLs to HTTPS", () => { expect(sanitizeUrl("www.liveblocks.io")).toBe("https://www.liveblocks.io"); expect(sanitizeUrl("www.liveblocks.io/docs/get-started")).toBe( "https://www.liveblocks.io/docs/get-started" ); }); - it("should support ports, query params, and a hash", () => { + test("should support ports, query params, and a hash", () => { expect(sanitizeUrl("https://localhost:3000/docs?query=value#hash")).toBe( "https://localhost:3000/docs?query=value#hash" ); @@ -34,7 +36,7 @@ describe("sanitizeUrl", () => { ); }); - it("should preserve the presence/absence of trailing slashes", () => { + test("should preserve the presence/absence of trailing slashes", () => { expect(sanitizeUrl("https://liveblocks.io/")).toBe( "https://liveblocks.io/" ); @@ -60,7 +62,7 @@ describe("sanitizeUrl", () => { ); }); - it("should reject non-HTTP(S) protocols and other invalid URLs", () => { + test("should reject non-HTTP(S) protocols and other invalid URLs", () => { expect(sanitizeUrl("javascript:alert('xss')")).toBe(null); expect(sanitizeUrl("data:text/html,")).toBe( null @@ -74,7 +76,7 @@ describe("sanitizeUrl", () => { }); describe("generateUrl", () => { - it("should generate absolute URLs", () => { + test("should generate absolute URLs", () => { expect(generateUrl("https://liveblocks.io/examples")).toBe( "https://liveblocks.io/examples" ); @@ -94,7 +96,7 @@ describe("generateUrl", () => { ).toBe("https://liveblocks.io/examples?query=2#hash"); }); - it("should preserve any existing query params and hash", () => { + test("should preserve any existing query params and hash", () => { expect( generateUrl("https://liveblocks.io/examples?existing=1#existinghash", { query: "value", diff --git a/packages/liveblocks-core/src/lib/__tests__/utils.test.ts b/packages/liveblocks-core/src/lib/__tests__/utils.test.ts index 2f37b8d814d..8a33f9df896 100644 --- a/packages/liveblocks-core/src/lib/__tests__/utils.test.ts +++ b/packages/liveblocks-core/src/lib/__tests__/utils.test.ts @@ -1,4 +1,5 @@ import * as fc from "fast-check"; +import { describe, expect, test } from "vitest"; import { isPlainObject } from "../guards"; import { @@ -25,19 +26,19 @@ const objectWithoutProto = () => }); describe("TypeScript wrapper utils", () => { - it("keys (alias of Object.keys)", () => { + test("keys (alias of Object.keys)", () => { expect(keys({})).toEqual([]); expect(keys({ a: 1 })).toEqual(["a"]); expect(keys({ [1]: 1, [2]: 2 })).toEqual(["1", "2"]); }); - it("values (alias of Object.values)", () => { + test("values (alias of Object.values)", () => { expect(values({})).toEqual([]); expect(values({ a: 1 })).toEqual([1]); expect(values({ [1]: 1, [2]: 2 })).toEqual([1, 2]); }); - it("entries (alias of Object.entries)", () => { + test("entries (alias of Object.entries)", () => { expect(entries({})).toEqual([]); expect(entries({ a: 1 })).toEqual([["a", 1]]); expect(entries({ [1]: 1, [2]: 2 })).toEqual([ @@ -48,11 +49,11 @@ describe("TypeScript wrapper utils", () => { }); describe("compact", () => { - it("compact w/ empty list", () => { + test("compact w/ empty list", () => { expect(compact([])).toEqual([]); }); - it("compact removes nulls and undefined values", () => { + test("compact removes nulls and undefined values", () => { expect(compact(["a", "b", "c"])).toEqual(["a", "b", "c"]); expect(compact(["x", undefined])).toEqual(["x"]); expect(compact([0, null, undefined, NaN, Infinity])).toEqual([ @@ -64,7 +65,7 @@ describe("compact", () => { }); describe("compactObject", () => { - it("compactObject w/ empty object", () => { + test("compactObject w/ empty object", () => { expect(compactObject({})).toStrictEqual({}); expect( compactObject({ @@ -92,11 +93,11 @@ describe("compactObject", () => { }); describe("mapValues", () => { - it("empty object", () => { + test("empty object", () => { expect(mapValues({}, (x) => x)).toStrictEqual({}); }); - it("maps values, not keys", () => { + test("maps values, not keys", () => { expect(mapValues({ a: 13, b: 0, c: -7 }, (n) => n * 2)).toStrictEqual({ a: 26, b: 0, @@ -104,7 +105,7 @@ describe("mapValues", () => { }); }); - it("keys don't change", () => { + test("keys don't change", () => { fc.assert( fc.property( objectWithoutProto(), @@ -117,7 +118,7 @@ describe("mapValues", () => { ); }); - it("will skip copying dangerous keys", () => { + test("will skip copying dangerous keys", () => { expect(mapValues({ __proto__: null }, (x) => x)).toStrictEqual({}); expect(mapValues({ ["__proto__"]: null }, (x) => x)).toStrictEqual({}); expect(mapValues({ __proto__: {} }, (x) => x)).toStrictEqual({}); @@ -130,7 +131,7 @@ describe("mapValues", () => { }); }); - it("using keys in mapper", () => { + test("using keys in mapper", () => { expect( mapValues({ a: 5, b: 0, c: 3 }, (n, k) => k.repeat(n)) ).toStrictEqual({ a: "aaaaa", b: "", c: "ccc" }); @@ -153,7 +154,7 @@ describe("mapValues", () => { }); describe("isPlainObject", () => { - it("isPlainObject", () => { + test("isPlainObject", () => { expect(isPlainObject(undefined)).toBe(false); expect(isPlainObject(null)).toBe(false); expect(isPlainObject(false)).toBe(false); @@ -176,7 +177,7 @@ describe("isPlainObject", () => { }); describe("tryParseJson", () => { - it("works like JSON.parse() on legal JSON inputs", () => { + test("works like JSON.parse() on legal JSON inputs", () => { expect(tryParseJson("true")).toEqual(true); expect(tryParseJson("false")).toEqual(false); expect(tryParseJson("null")).toEqual(null); @@ -184,7 +185,7 @@ describe("tryParseJson", () => { expect(tryParseJson('["hi", {"a": 1}]')).toEqual(["hi", { a: 1 }]); }); - it("returns undefined for invalid JSON inputs", () => { + test("returns undefined for invalid JSON inputs", () => { expect(tryParseJson("i am not a JSON value")).toBeUndefined(); expect(tryParseJson("'single quotes'")).toBeUndefined(); expect(tryParseJson("[[]")).toBeUndefined(); diff --git a/packages/liveblocks-core/src/protocol/__tests__/NotificationSettings.test.ts b/packages/liveblocks-core/src/protocol/__tests__/NotificationSettings.test.ts index a15957b1754..15c2ca324a5 100644 --- a/packages/liveblocks-core/src/protocol/__tests__/NotificationSettings.test.ts +++ b/packages/liveblocks-core/src/protocol/__tests__/NotificationSettings.test.ts @@ -1,3 +1,6 @@ +import type { MockInstance } from "vitest"; +import { afterEach, beforeEach, describe, expect, test, vi } from "vitest"; + import * as console from "../../lib/fancy-console"; import { createNotificationSettings, @@ -5,17 +8,17 @@ import { } from "../NotificationSettings"; describe("NotificationSettings protocol", () => { - let consoleErrorMock: jest.Mock; + let consoleErrorMock: MockInstance; beforeEach(() => { - consoleErrorMock = jest.fn(); - jest.spyOn(console, "error").mockImplementation(consoleErrorMock); + consoleErrorMock = vi.fn(); + vi.spyOn(console, "error").mockImplementation(consoleErrorMock as any); }); afterEach(() => { consoleErrorMock.mockRestore(); }); - it("should create an object with getters for each known notification channel", () => { + test("should create an object with getters for each known notification channel", () => { const plain: NotificationSettingsPlain = { email: { thread: true, @@ -38,7 +41,7 @@ describe("NotificationSettings protocol", () => { expect(consoleErrorMock).not.toHaveBeenCalled(); }); - it("should return null and log an error if a channel is not defined in plain and is accessed later", () => { + test("should return null and log an error if a channel is not defined in plain and is accessed later", () => { const plain: NotificationSettingsPlain = { email: { thread: true, @@ -76,7 +79,7 @@ describe("NotificationSettings protocol", () => { ); }); - it("should return an object where properties are enumerable except `[kPlain]`", () => { + test("should return an object where properties are enumerable except `[kPlain]`", () => { const plain: NotificationSettingsPlain = { email: { thread: true, textMention: true }, slack: { thread: true, textMention: true }, diff --git a/packages/liveblocks-core/src/refs/__tests__/ManagedOthers.test.ts b/packages/liveblocks-core/src/refs/__tests__/ManagedOthers.test.ts index 7f059685523..cc155a8f1fa 100644 --- a/packages/liveblocks-core/src/refs/__tests__/ManagedOthers.test.ts +++ b/packages/liveblocks-core/src/refs/__tests__/ManagedOthers.test.ts @@ -1,3 +1,5 @@ +import { describe, expect, test } from "vitest"; + import { ManagedOthers } from "../ManagedOthers"; type P = { @@ -16,7 +18,7 @@ type M = { describe('Read-only "others" ref cache', () => { describe('Tracking "others"', () => { - it("setting alone is not enough other", () => { + test("setting alone is not enough other", () => { const others = new ManagedOthers(); others.setOther(2, { x: 1, y: 1 }); @@ -41,7 +43,7 @@ describe('Read-only "others" ref cache', () => { ]); }); - it("setting other", () => { + test("setting other", () => { const others = new ManagedOthers(); others.setConnection(2, "user-123", undefined, ["room:write"]); others.setConnection(3, "user-567", undefined, ["room:write"]); @@ -70,7 +72,7 @@ describe('Read-only "others" ref cache', () => { ]); }); - it("setting other as read-only", () => { + test("setting other as read-only", () => { const others = new ManagedOthers(); others.setConnection(2, "user-123", undefined, ["room:read"]); others.setConnection(3, "user-567", undefined, ["room:write"]); @@ -98,7 +100,7 @@ describe('Read-only "others" ref cache', () => { ]); }); - it("setting others removes explicitly-undefined keys", () => { + test("setting others removes explicitly-undefined keys", () => { const others = new ManagedOthers(); others.setConnection(2, "user-123", undefined, ["room:write"]); others.setOther(2, { x: 2, y: 2, z: undefined }); @@ -117,7 +119,7 @@ describe('Read-only "others" ref cache', () => { ]); }); - it("patching others ignores patches for unknown users", () => { + test("patching others ignores patches for unknown users", () => { const others = new ManagedOthers(); others.setConnection(2, "user-123", undefined, ["room:write"]); others.patchOther(2, { y: 1, z: 2 }); // .setOther() not called yet for actor 2 @@ -125,7 +127,7 @@ describe('Read-only "others" ref cache', () => { expect(others.get()).toStrictEqual([]); }); - it("patching others", () => { + test("patching others", () => { const others = new ManagedOthers(); others.setConnection(2, "user-123", undefined, ["room:write"]); others.setOther(2, { x: 2, y: 2 }); @@ -165,7 +167,7 @@ describe('Read-only "others" ref cache', () => { ]); }); - it("removing connections", () => { + test("removing connections", () => { const others = new ManagedOthers(); others.setConnection(2, "user-123", undefined, ["room:write"]); others.setOther(2, { x: 2, y: 2 }); @@ -191,7 +193,7 @@ describe('Read-only "others" ref cache', () => { }); describe("caching", () => { - it("caches immutable results (others)", () => { + test("caches immutable results (others)", () => { const others = new ManagedOthers(); others.setConnection(2, "user-123", undefined, ["room:write"]); others.setOther(2, { x: 2, y: 2 }); @@ -220,7 +222,7 @@ describe('Read-only "others" ref cache', () => { expect(others6).toBe(others7); }); - it("getUser() returns stable cache results", () => { + test("getUser() returns stable cache results", () => { const others = new ManagedOthers(); others.setConnection(2, "user-123", undefined, ["room:write"]); others.setOther(2, { x: 2, y: 2 }); diff --git a/packages/liveblocks-core/turbo.json b/packages/liveblocks-core/turbo.json index c4977a7f303..de515f8a7e5 100644 --- a/packages/liveblocks-core/turbo.json +++ b/packages/liveblocks-core/turbo.json @@ -1,8 +1,11 @@ { - // Extend the global Turbo file "extends": ["//"], "tasks": { + "test": { + "cache": false + }, "test:e2e": { + "cache": false, "dependsOn": ["build"], "inputs": [ "jest.*", diff --git a/packages/liveblocks-core/vitest.config.e2e.ts b/packages/liveblocks-core/vitest.config.e2e.ts new file mode 100644 index 00000000000..e025ce7d947 --- /dev/null +++ b/packages/liveblocks-core/vitest.config.e2e.ts @@ -0,0 +1,13 @@ +import { defaultLiveblocksVitestConfig } from "@liveblocks/vitest-config"; + +export default defaultLiveblocksVitestConfig({ + test: { + // Only run e2e/* tests, not the "normal" tests in src/* + include: ["e2e/**/*.test.*"], + + // Enable test globals like describe, it, test, expect + // Use node environment for e2e tests instead of jsdom + environment: "node", + timeout: 30000, + }, +}); diff --git a/packages/liveblocks-core/vitest.config.ts b/packages/liveblocks-core/vitest.config.ts new file mode 100644 index 00000000000..4f7fc4ef2df --- /dev/null +++ b/packages/liveblocks-core/vitest.config.ts @@ -0,0 +1,21 @@ +import { defaultLiveblocksVitestConfig } from "@liveblocks/vitest-config"; + +export default defaultLiveblocksVitestConfig({ + test: { + // Don't run the e2e/* tests, only the "normal" tests in src/* + // e2e/* tests will be run by `npm run test:e2e` + exclude: ["e2e/**"], + + environment: "jsdom", + environmentOptions: { + jsdom: { + url: "http://dummy/", + }, + }, + // Collect code coverage for this project, when using the --coverage flag + coverage: { + provider: "istanbul", + exclude: ["**/__tests__/**"], + }, + }, +}); diff --git a/packages/liveblocks-emails/jest.config.cjs b/packages/liveblocks-emails/jest.config.cjs deleted file mode 100644 index 4de12d705d9..00000000000 --- a/packages/liveblocks-emails/jest.config.cjs +++ /dev/null @@ -1,11 +0,0 @@ -/** @type {import('jest').Config} */ - -const commonJestConfig = require("@liveblocks/jest-config"); - -module.exports = { - // Our standard Jest configuration, used by all projects in this monorepo - ...commonJestConfig, - - // Our standard setup assumed jsdom environment. Override it for node here. - testEnvironment: "node", -}; diff --git a/packages/liveblocks-emails/package.json b/packages/liveblocks-emails/package.json index 7866c5cfdd1..30471db7c93 100644 --- a/packages/liveblocks-emails/package.json +++ b/packages/liveblocks-emails/package.json @@ -30,9 +30,9 @@ "format": "(eslint --fix src/ || true) && prettier --write src/", "lint": "eslint src/", "lint:package": "publint --strict && attw --pack", - "test": "jest --silent --verbose --color=always", + "test": "NODE_OPTIONS=\"--no-deprecation\" vitest run", "test:types": "ls test-d/* | xargs -n1 tsd --files", - "test:watch": "jest --silent --verbose --color=always --watch" + "test:watch": "NODE_OPTIONS=\"--no-deprecation\" vitest" }, "dependencies": { "@liveblocks/core": "3.3.3", @@ -43,9 +43,9 @@ }, "devDependencies": { "@liveblocks/eslint-config": "*", - "@liveblocks/jest-config": "*", + "@liveblocks/vitest-config": "*", "csstype": "3.0.2", - "msw": "^2.7.0" + "msw": "^2.10.4" }, "sideEffects": false, "bugs": { diff --git a/packages/liveblocks-emails/src/__tests__/comment-body.test.tsx b/packages/liveblocks-emails/src/__tests__/comment-body.test.tsx index 261823fb7e9..317887351a7 100644 --- a/packages/liveblocks-emails/src/__tests__/comment-body.test.tsx +++ b/packages/liveblocks-emails/src/__tests__/comment-body.test.tsx @@ -1,4 +1,5 @@ import { html, htmlSafe } from "@liveblocks/core"; +import { describe, expect, test } from "vitest"; import type { ConvertCommentBodyElements } from "../comment-body"; import { convertCommentBody } from "../comment-body"; @@ -67,14 +68,14 @@ describe("convert comment body", () => { }, }; - it("should convert simple text elements", async () => { + test("should convert simple text elements", async () => { const body = await convertCommentBody(commentBody1, { elements }); const expected = "

What do you think of this team? 🤔

"; expect(body).toEqual(expected); }); - it("should convert with italic and bold", async () => { + test("should convert with italic and bold", async () => { const body = await convertCommentBody(commentBody5, { elements }); const expected = "

Bold text and italic text

"; @@ -82,7 +83,7 @@ describe("convert comment body", () => { expect(body).toEqual(expected); }); - it("should convert with code and strikethrough", async () => { + test("should convert with code and strikethrough", async () => { const body = await convertCommentBody(commentBody6, { elements }); const expected = "

Strikethrough text and code text

"; @@ -90,7 +91,7 @@ describe("convert comment body", () => { expect(body).toEqual(expected); }); - it("should convert with link", async () => { + test("should convert with link", async () => { const [body1, body2] = await Promise.all([ convertCommentBody(commentBody4, { elements }), convertCommentBody(commentBody7, { elements }), @@ -105,7 +106,7 @@ describe("convert comment body", () => { expect(body2).toEqual(expected2); }); - it("should preserve valid URLs", async () => { + test("should preserve valid URLs", async () => { const body = await convertCommentBody(commentBodyWithValidUrls, { elements, }); @@ -115,7 +116,7 @@ describe("convert comment body", () => { expect(body).toEqual(expected); }); - it("should replace invalid URLs with plain text", async () => { + test("should replace invalid URLs with plain text", async () => { const body = await convertCommentBody(commentBodyWithInvalidUrls, { elements, }); @@ -125,7 +126,7 @@ describe("convert comment body", () => { expect(body).toEqual(expected); }); - it("should convert with user mention", async () => { + test("should convert with user mention", async () => { const body = await convertCommentBody( buildCommentBodyWithMention({ mentionedUserId: "user-dracula" }), { elements } @@ -135,7 +136,7 @@ describe("convert comment body", () => { expect(body).toEqual(expected); }); - it("should convert with a resolved user mention", async () => { + test("should convert with a resolved user mention", async () => { const body = await convertCommentBody( buildCommentBodyWithMention({ mentionedUserId: "user-2" }), { @@ -149,14 +150,14 @@ describe("convert comment body", () => { }); describe("use-case/escaping html entities", () => { - it("should escape html entities in text", async () => { + test("should escape html entities in text", async () => { const body = await convertCommentBody(commentBodyWithHtml, { elements }); const expected = "

Trying with <b>inject html</b> !

"; expect(body).toEqual(expected); }); - it("should escape html entities in link w/ text", async () => { + test("should escape html entities in link w/ text", async () => { const body = await convertCommentBody(commentBodyWithHtml2, { elements }); const expected = '

Trying with <script>injected script</script> !

'; @@ -164,7 +165,7 @@ describe("convert comment body", () => { expect(body).toEqual(expected); }); - it("should escape html entities in mention w/ username", async () => { + test("should escape html entities in mention w/ username", async () => { const body = await convertCommentBody( buildCommentBodyWithMention({ mentionedUserId: "user-0" }), { diff --git a/packages/liveblocks-emails/src/__tests__/comment-with-body.test.ts b/packages/liveblocks-emails/src/__tests__/comment-with-body.test.ts index c73ff846ea9..a3faa3597b0 100644 --- a/packages/liveblocks-emails/src/__tests__/comment-with-body.test.ts +++ b/packages/liveblocks-emails/src/__tests__/comment-with-body.test.ts @@ -1,8 +1,10 @@ +import { describe, expect, test } from "vitest"; + import { filterCommentsWithBody } from "../comment-with-body"; import { commentBody1, generateThreadId, makeComment } from "./_helpers"; describe("Comment with body", () => { - it("should filter comments with defined bodies", () => { + test("should filter comments with defined bodies", () => { const threadId = generateThreadId(); const comment1 = makeComment({ userId: "user-0", threadId }); const comment2 = makeComment({ diff --git a/packages/liveblocks-emails/src/__tests__/lexical-editor.test.ts b/packages/liveblocks-emails/src/__tests__/lexical-editor.test.ts index f5dc07e9bde..26c6eef3ee5 100644 --- a/packages/liveblocks-emails/src/__tests__/lexical-editor.test.ts +++ b/packages/liveblocks-emails/src/__tests__/lexical-editor.test.ts @@ -1,3 +1,5 @@ +import { describe, expect, test } from "vitest"; + import type { SerializedLexicalRootNode } from "../lexical-editor"; import { findLexicalMentionNodeWithContext, @@ -16,7 +18,7 @@ import { describe("Lexical editor", () => { describe("get serialized state", () => { - it("should parse correctly a real document", () => { + test("should parse correctly a real document", () => { const state = getSerializedLexicalState({ buffer: docUpdateBuffer, key: "root", @@ -27,7 +29,7 @@ describe("Lexical editor", () => { }); describe("find mention node with context", () => { - it("should flatten Lexical tree", () => { + test("should flatten Lexical tree", () => { const flattenNodes = flattenLexicalTree(docStateRoot2.children); expect(flattenNodes).toEqual([ { @@ -96,7 +98,7 @@ describe("Lexical editor", () => { ]); }); - it("should find no mention with context", () => { + test("should find no mention with context", () => { const root: SerializedLexicalRootNode = { type: "root", children: [ @@ -152,7 +154,7 @@ describe("Lexical editor", () => { expect(context).toBeNull(); }); - it("should find a mention with context", () => { + test("should find a mention with context", () => { const context = findLexicalMentionNodeWithContext({ root: docStateRoot2, mentionedUserId: MENTIONED_USER_ID, diff --git a/packages/liveblocks-emails/src/__tests__/liveblocks-text-editor.test.tsx b/packages/liveblocks-emails/src/__tests__/liveblocks-text-editor.test.tsx index ec9d9eac637..20b0387e978 100644 --- a/packages/liveblocks-emails/src/__tests__/liveblocks-text-editor.test.tsx +++ b/packages/liveblocks-emails/src/__tests__/liveblocks-text-editor.test.tsx @@ -1,3 +1,5 @@ +import { describe, expect, test } from "vitest"; + import type { LiveblocksTextEditorNode } from "../liveblocks-text-editor"; import { transformAsLiveblocksTextEditorNodes } from "../liveblocks-text-editor"; import { generateInboxNotificationId } from "./_helpers"; @@ -6,7 +8,7 @@ import { createTipTapMentionNodeWithContext } from "./_tiptap-helpers"; describe("liveblocks text editor", () => { describe("transform serialized nodes into Liveblocks Text Editor nodes", () => { - it("should transform lexical nodes", () => { + test("should transform lexical nodes", () => { const mentionId = generateInboxNotificationId(); const userId = "user-mina"; @@ -47,7 +49,7 @@ describe("liveblocks text editor", () => { expect(nodes).toEqual(expected); }); - it("should transform tiptap nodes", () => { + test("should transform tiptap nodes", () => { const mentionId = generateInboxNotificationId(); const userId = "user-dracula"; diff --git a/packages/liveblocks-emails/src/__tests__/mention-content.test.tsx b/packages/liveblocks-emails/src/__tests__/mention-content.test.tsx index 76b256e8e08..385eff73317 100644 --- a/packages/liveblocks-emails/src/__tests__/mention-content.test.tsx +++ b/packages/liveblocks-emails/src/__tests__/mention-content.test.tsx @@ -1,4 +1,5 @@ import { html, htmlSafe } from "@liveblocks/core"; +import { describe, expect, test } from "vitest"; import { MENTION_CHARACTER } from "../lib/constants"; import type { LiveblocksTextEditorNode } from "../liveblocks-text-editor"; @@ -82,7 +83,7 @@ describe("convert mention content", () => { }, }; - it("should convert mention content", async () => { + test("should convert mention content", async () => { const mention = buildMentionTextEditorNodes({ mentionedUserId: "user-dracula", }); @@ -93,7 +94,7 @@ describe("convert mention content", () => { expect(content).toEqual(expected); }); - it("should convert with bold and italic", async () => { + test("should convert with bold and italic", async () => { const mention: LiveblocksTextEditorNode[] = [ { type: "text", @@ -126,7 +127,7 @@ describe("convert mention content", () => { expect(content).toEqual(expected); }); - it("should convert with strikethrough and code", async () => { + test("should convert with strikethrough and code", async () => { const mention: LiveblocksTextEditorNode[] = [ { type: "text", @@ -159,7 +160,7 @@ describe("convert mention content", () => { expect(content).toEqual(expected); }); - it("should resolve user info", async () => { + test("should resolve user info", async () => { const mention = buildMentionTextEditorNodes({ mentionedUserId: "user-0" }); const content = await convertMentionContent(mention, { elements, @@ -172,7 +173,7 @@ describe("convert mention content", () => { }); describe("use-case/escaping html entities", () => { - it("should escape html entities in text", async () => { + test("should escape html entities in text", async () => { const mention: LiveblocksTextEditorNode[] = [ { type: "text", @@ -197,7 +198,7 @@ describe("convert mention content", () => { expect(content).toEqual(expected); }); - it("should escape html entities in mention w/ username", async () => { + test("should escape html entities in mention w/ username", async () => { const mention = buildMentionTextEditorNodes({ mentionedUserId: "user-mina", }); diff --git a/packages/liveblocks-emails/src/__tests__/text-mention-notification.test.tsx b/packages/liveblocks-emails/src/__tests__/text-mention-notification.test.tsx index 92878b35082..795252d99fe 100644 --- a/packages/liveblocks-emails/src/__tests__/text-mention-notification.test.tsx +++ b/packages/liveblocks-emails/src/__tests__/text-mention-notification.test.tsx @@ -4,6 +4,15 @@ import type { } from "@liveblocks/core"; import { Liveblocks, type RoomData } from "@liveblocks/node"; import { http, HttpResponse } from "msw"; +import { + afterAll, + afterEach, + beforeAll, + describe, + expect, + test, + vi, +} from "vitest"; import { MENTION_CHARACTER } from "../lib/constants"; import type { ConvertMentionContentElements } from "../mention-content"; @@ -80,9 +89,9 @@ describe("text mention notification", () => { }; describe("internals utils", () => { - it("should extract `null` - bad bad notification kind", async () => { - const warnMock1 = jest.fn(); - jest.spyOn(console, "warn").mockImplementation(warnMock1); + test("should extract `null` - bad bad notification kind", async () => { + const warnMock1 = vi.fn(); + vi.spyOn(console, "warn").mockImplementation(warnMock1); const mentionId = generateInboxNotificationId(); const badInboxNotification = makeThreadInboxNotification({ @@ -126,7 +135,7 @@ describe("text mention notification", () => { warnMock1.mockRestore(); }); - it("should extract `null` - notification is already read", async () => { + test("should extract `null` - notification is already read", async () => { const mentionId = generateInboxNotificationId(); const inboxNotification = makeTextMentionInboxNotification({ mentionId, @@ -153,9 +162,9 @@ describe("text mention notification", () => { expect(extracted).toBeNull(); }); - it("should extract `null` - no text editor associated", async () => { - const warnMock2 = jest.fn(); - jest.spyOn(console, "warn").mockImplementation(warnMock2); + test("should extract `null` - no text editor associated", async () => { + const warnMock2 = vi.fn(); + vi.spyOn(console, "warn").mockImplementation(warnMock2); const mentionId = generateInboxNotificationId(); const inboxNotification = makeTextMentionInboxNotification({ @@ -186,7 +195,7 @@ describe("text mention notification", () => { warnMock2.mockRestore(); }); - it("should extract a text mention notification data", async () => { + test("should extract a text mention notification data", async () => { const inboxNotification = makeTextMentionInboxNotification({ mentionId: MENTION_ID_TIPTAP, createdBy: "user-nimesh", @@ -238,7 +247,7 @@ describe("text mention notification", () => { text: ({ node }) => node.text, }; - it("should extract mention and nodes and prepare base email data", async () => { + test("should extract mention and nodes and prepare base email data", async () => { const inboxNotification = makeTextMentionInboxNotification({ mentionId: MENTION_ID_TIPTAP, createdBy: "user-nimesh", @@ -360,7 +369,7 @@ describe("text mention notification", () => { roomInfo: RESOLVED_ROOM_INFO_TEST, }; - it.each<{ + test.each<{ withResolvers: boolean; promise: () => Promise; expected: TextMentionNotificationEmailDataAsHtml; @@ -443,7 +452,7 @@ describe("text mention notification", () => { }, }; - it.each<{ + test.each<{ withResolvers: boolean; promise: () => Promise; expected: TextMentionNotificationEmailDataAsReact; diff --git a/packages/liveblocks-emails/src/__tests__/thread-notification.test.tsx b/packages/liveblocks-emails/src/__tests__/thread-notification.test.tsx index 2b16e924dc1..8b369d8a5e3 100644 --- a/packages/liveblocks-emails/src/__tests__/thread-notification.test.tsx +++ b/packages/liveblocks-emails/src/__tests__/thread-notification.test.tsx @@ -5,6 +5,7 @@ import type { import type { ThreadData } from "@liveblocks/node"; import { Liveblocks } from "@liveblocks/node"; import { http, HttpResponse } from "msw"; +import { afterAll, afterEach, beforeAll, describe, expect, test } from "vitest"; import type { ConvertCommentBodyElements } from "../comment-body"; import { MENTION_CHARACTER } from "../lib/constants"; @@ -74,7 +75,7 @@ describe("thread notification", () => { }; describe("internals utils", () => { - it("should get unread comments - all comments", () => { + test("should get unread comments - all comments", () => { const threadId = generateThreadId(); const comment1 = makeComment({ userId: "user-dracula", @@ -109,7 +110,7 @@ describe("thread notification", () => { expect(unreadComments).toEqual(expected); }); - it("should get unread comments - only two comments", () => { + test("should get unread comments - only two comments", () => { const threadId = generateThreadId(); const comment1 = makeComment({ userId: "user-dracula", @@ -144,7 +145,7 @@ describe("thread notification", () => { expect(unreadComments).toEqual(expected); }); - it("should get last unread comment with mention - first comment is a mention", () => { + test("should get last unread comment with mention - first comment is a mention", () => { const threadId = generateThreadId(); const comment1 = makeComment({ userId: "user-dracula", @@ -179,7 +180,7 @@ describe("thread notification", () => { expect(lastCommentWithMention1).toEqual(comment1); }); - it("should get last unread comment with mention - last comment is a mention", () => { + test("should get last unread comment with mention - last comment is a mention", () => { const threadId = generateThreadId(); const comment1 = makeComment({ userId: "user-dracula", @@ -220,7 +221,7 @@ describe("thread notification", () => { expect(lastUnreadCommentWithMention).toEqual(comment3); }); - it("should extract null (no last unread comment with a mention nor unread replies) from a thread notification", async () => { + test("should extract null (no last unread comment with a mention nor unread replies) from a thread notification", async () => { const threadId = generateThreadId(); const comment = makeComment({ userId: "user-0", @@ -248,7 +249,7 @@ describe("thread notification", () => { expect(extracted).toBeNull(); }); - it("should extract last unread comment with a mention from a thread notification", async () => { + test("should extract last unread comment with a mention from a thread notification", async () => { const threadId = generateThreadId(); const comment1 = makeComment({ userId: "user-0", @@ -285,7 +286,7 @@ describe("thread notification", () => { expect(extracted).toEqual(expected); }); - it("should extract unread replies comments from a thread notification", async () => { + test("should extract unread replies comments from a thread notification", async () => { const threadId = generateThreadId(); const comment1 = makeComment({ userId: "user-dracula", @@ -333,7 +334,7 @@ describe("thread notification", () => { expect(extracted).toEqual(expected); }); - it("should extract only unread replies from a thread notification - no mentions", async () => { + test("should extract only unread replies from a thread notification - no mentions", async () => { const threadId = generateThreadId(); const comment1 = makeComment({ userId: "user-0", @@ -395,7 +396,7 @@ describe("thread notification", () => { `${MENTION_CHARACTER}${user?.name ?? element.id}`, }; - it("should prepare for last unread comment with mention", async () => { + test("should prepare for last unread comment with mention", async () => { const threadId = generateThreadId(); const comment = makeComment({ userId: "user-0", @@ -467,7 +468,7 @@ describe("thread notification", () => { expect(preparedWithResolvedRoomInfo).toEqual(expected2); }); - it("should prepare for unread replies comments", async () => { + test("should prepare for unread replies comments", async () => { const threadId = generateThreadId(); const comment1 = makeComment({ userId: "user-dracula", @@ -616,7 +617,7 @@ describe("thread notification", () => { roomInfo: RESOLVED_ROOM_INFO_TEST, }; - it.each<{ + test.each<{ withResolvers: boolean; promise: () => Promise; expected: ThreadNotificationEmailDataAsHtml; @@ -703,7 +704,7 @@ describe("thread notification", () => { roomInfo: RESOLVED_ROOM_INFO_TEST, }; - it.each<{ + test.each<{ withResolvers: boolean; promise: () => Promise; expected: ThreadNotificationEmailDataAsHtml; @@ -788,7 +789,7 @@ describe("thread notification", () => { roomInfo: RESOLVED_ROOM_INFO_TEST, }; - it.each<{ + test.each<{ withResolvers: boolean; promise: () => Promise; expected: ThreadNotificationEmailDataAsHtml; @@ -878,7 +879,7 @@ describe("thread notification", () => { roomInfo: RESOLVED_ROOM_INFO_TEST, }; - it.each<{ + test.each<{ withResolvers: boolean; promise: () => Promise; expected: ThreadNotificationEmailDataAsHtml; @@ -981,7 +982,7 @@ describe("thread notification", () => { roomInfo: RESOLVED_ROOM_INFO_TEST, }; - it.each<{ + test.each<{ withResolvers: boolean; promise: () => Promise; expected: ThreadNotificationEmailDataAsReact; @@ -1094,7 +1095,7 @@ describe("thread notification", () => { roomInfo: RESOLVED_ROOM_INFO_TEST, }; - it.each<{ + test.each<{ withResolvers: boolean; promise: () => Promise; expected: ThreadNotificationEmailDataAsReact; @@ -1210,7 +1211,7 @@ describe("thread notification", () => { roomInfo: RESOLVED_ROOM_INFO_TEST, }; - it.each<{ + test.each<{ withResolvers: boolean; promise: () => Promise; expected: ThreadNotificationEmailDataAsReact; @@ -1323,7 +1324,7 @@ describe("thread notification", () => { roomInfo: RESOLVED_ROOM_INFO_TEST, }; - it.each<{ + test.each<{ withResolvers: boolean; promise: () => Promise; expected: ThreadNotificationEmailDataAsReact; diff --git a/packages/liveblocks-emails/src/__tests__/tiptap-editor.test.ts b/packages/liveblocks-emails/src/__tests__/tiptap-editor.test.ts index 9415bfb69ae..b3c5133125a 100644 --- a/packages/liveblocks-emails/src/__tests__/tiptap-editor.test.ts +++ b/packages/liveblocks-emails/src/__tests__/tiptap-editor.test.ts @@ -1,3 +1,5 @@ +import { describe, expect, test } from "vitest"; + import type { SerializedTiptapRootNode } from "../tiptap-editor"; import { findTiptapMentionNodeWithContext, @@ -16,7 +18,7 @@ import { describe("tiptap editor", () => { describe("get serialized state", () => { - it("should parse correctly a real document", () => { + test("should parse correctly a real document", () => { const state = getSerializedTiptapState({ buffer: docUpdateBuffer, key: "default", @@ -27,7 +29,7 @@ describe("tiptap editor", () => { }); describe("find mention node with context", () => { - it("should flatten tiptap tree", () => { + test("should flatten tiptap tree", () => { const flattenNodes = flattenTiptapTree(docStateRoot2.content); expect(flattenNodes).toEqual([ { type: "paragraph" }, @@ -76,7 +78,7 @@ describe("tiptap editor", () => { ]); }); - it("should find no mention with context", () => { + test("should find no mention with context", () => { const root: SerializedTiptapRootNode = { type: "doc", content: [ @@ -114,7 +116,7 @@ describe("tiptap editor", () => { expect(context).toBeNull(); }); - it("should find a mention with context", () => { + test("should find a mention with context", () => { const context = findTiptapMentionNodeWithContext({ root: docStateRoot2, mentionedUserId: MENTIONED_USER_ID, diff --git a/packages/liveblocks-emails/src/lib/__tests__/batch-users-resolver.test.ts b/packages/liveblocks-emails/src/lib/__tests__/batch-users-resolver.test.ts index d2a41f60d63..20a52afe1c5 100644 --- a/packages/liveblocks-emails/src/lib/__tests__/batch-users-resolver.test.ts +++ b/packages/liveblocks-emails/src/lib/__tests__/batch-users-resolver.test.ts @@ -5,6 +5,7 @@ import type { IUserInfo, ResolveUsersArgs, } from "@liveblocks/core"; +import { afterEach, beforeEach, describe, expect, test, vi } from "vitest"; import { createBatchUsersResolver } from "../batch-users-resolver"; @@ -28,9 +29,14 @@ const USERS_DB: IUserInfo[] = [ ]; describe("batch users resolve", () => { - let resolveUsersMock: jest.Mock; + let resolveUsersMock: ReturnType; + + afterEach(() => { + vi.restoreAllMocks(); + }); + beforeEach(() => { - resolveUsersMock = jest.fn( + resolveUsersMock = vi.fn( ({ userIds, }: ResolveUsersArgs): Awaitable< @@ -50,9 +56,9 @@ describe("batch users resolve", () => { ); }); - it("should handle no `resolveUsers` callback", async () => { - const warnMock1 = jest.fn(); - jest.spyOn(console, "warn").mockImplementation(warnMock1); + test("should handle no `resolveUsers` callback", async () => { + const warnMock1 = vi.fn(); + vi.spyOn(console, "warn").mockImplementation(warnMock1); const batchUsersResolver = createBatchUsersResolver({ callerName: "test-suite-0", @@ -76,7 +82,7 @@ describe("batch users resolve", () => { warnMock1.mockRestore(); }); - it("should resolve users info all at once", async () => { + test("should resolve users info all at once", async () => { const batchUsersResolver = createBatchUsersResolver({ resolveUsers: resolveUsersMock, callerName: "test-suite-1", @@ -100,7 +106,7 @@ describe("batch users resolve", () => { expect(resolveUsersMock).toHaveBeenCalledWith({ userIds }); }); - it("should resolve the same user in one call with multiple resolveUsers promises", async () => { + test("should resolve the same user in one call with multiple resolveUsers promises", async () => { const batchUsersResolver = createBatchUsersResolver({ resolveUsers: resolveUsersMock, callerName: "test-suite-2", @@ -121,8 +127,8 @@ describe("batch users resolve", () => { expect(resolvedUser2).toEqual(expected); }); - it("should warn if batch promise is already resolved", async () => { - const warnMock2 = jest.spyOn(console, "warn").mockImplementation(() => {}); + test("should warn if batch promise is already resolved", async () => { + const warnMock2 = vi.spyOn(console, "warn").mockImplementation(() => {}); const batchUsersResolver = createBatchUsersResolver({ resolveUsers: resolveUsersMock, @@ -139,7 +145,7 @@ describe("batch users resolve", () => { await batchUsersResolver.resolve(); const resolvedUser2 = await promise2; - expect(warnMock2).toHaveBeenCalledTimes(2); + expect(warnMock2).toHaveBeenCalledTimes(1); expect(warnMock2).toHaveBeenCalledWith( "Batch users resolver promise already resolved. It can only resolve once." ); diff --git a/packages/liveblocks-emails/src/lib/__tests__/css-properties.test.ts b/packages/liveblocks-emails/src/lib/__tests__/css-properties.test.ts index 683fae596fa..1a7b7e37d75 100644 --- a/packages/liveblocks-emails/src/lib/__tests__/css-properties.test.ts +++ b/packages/liveblocks-emails/src/lib/__tests__/css-properties.test.ts @@ -1,8 +1,10 @@ +import { describe, expect, test } from "vitest"; + import type { CSSProperties } from "../css-properties"; import { toInlineCSSString } from "../css-properties"; describe("to inline css string", () => { - it("should convert simple properties correctly", () => { + test("should convert simple properties correctly", () => { const styles: CSSProperties = { color: "red", backgroundColor: "blue", @@ -13,7 +15,7 @@ describe("to inline css string", () => { expect(inlineCSS).toBe(expected); }); - it("should add px to numeric properties that are not unitless", () => { + test("should add px to numeric properties that are not unitless", () => { const styles: CSSProperties = { margin: 0, padding: 0, @@ -24,7 +26,7 @@ describe("to inline css string", () => { expect(inlineCSS).toBe(expected); }); - it("should not add px to unitless properties", () => { + test("should not add px to unitless properties", () => { const styles: CSSProperties = { opacity: 0.5, zIndex: 10, @@ -36,7 +38,7 @@ describe("to inline css string", () => { expect(inlineCSS).toBe(expected); }); - it("should handle vendor-prefixed properties correctly", () => { + test("should handle vendor-prefixed properties correctly", () => { const styles: CSSProperties = { WebkitTransform: "rotate(45deg)", msFlex: 1, @@ -47,7 +49,7 @@ describe("to inline css string", () => { expect(inlineCSS).toBe(expected); }); - it("should handle mixed properties", () => { + test("should handle mixed properties", () => { const styles: CSSProperties = { color: "red", WebkitTransform: "scale(1.5)", @@ -61,7 +63,7 @@ describe("to inline css string", () => { expect(inlineCSS).toBe(expected); }); - it("should ignore null, undefined, and boolean values", () => { + test("should ignore null, undefined, and boolean values", () => { const styles: CSSProperties = { color: "red", // eslint-disable-next-line @typescript-eslint/ban-ts-comment @@ -79,7 +81,7 @@ describe("to inline css string", () => { expect(inlineCSS).toBe(expected); }); - it("should ignore empty strings", () => { + test("should ignore empty strings", () => { const styles: CSSProperties = { color: "", backgroundColor: "blue", @@ -90,7 +92,7 @@ describe("to inline css string", () => { expect(inlineCSS).toBe(expected); }); - it("should handle complex vendor-prefixed properties", () => { + test("should handle complex vendor-prefixed properties", () => { const styles: CSSProperties = { WebkitBoxFlex: 1, MozBoxFlex: 2, diff --git a/packages/liveblocks-emails/vitest.config.ts b/packages/liveblocks-emails/vitest.config.ts new file mode 100644 index 00000000000..e29ad5d9647 --- /dev/null +++ b/packages/liveblocks-emails/vitest.config.ts @@ -0,0 +1,7 @@ +import { defaultLiveblocksVitestConfig } from "@liveblocks/vitest-config"; + +export default defaultLiveblocksVitestConfig({ + test: { + environment: "node", + }, +}); \ No newline at end of file diff --git a/packages/liveblocks-node-lexical/jest.config.cjs b/packages/liveblocks-node-lexical/jest.config.cjs deleted file mode 100644 index 4de12d705d9..00000000000 --- a/packages/liveblocks-node-lexical/jest.config.cjs +++ /dev/null @@ -1,11 +0,0 @@ -/** @type {import('jest').Config} */ - -const commonJestConfig = require("@liveblocks/jest-config"); - -module.exports = { - // Our standard Jest configuration, used by all projects in this monorepo - ...commonJestConfig, - - // Our standard setup assumed jsdom environment. Override it for node here. - testEnvironment: "node", -}; diff --git a/packages/liveblocks-node-lexical/package.json b/packages/liveblocks-node-lexical/package.json index 43d572211b4..cf839c57bb2 100644 --- a/packages/liveblocks-node-lexical/package.json +++ b/packages/liveblocks-node-lexical/package.json @@ -29,9 +29,9 @@ "format": "(eslint --fix src/ || true) && prettier --write src/", "lint": "eslint src/", "lint:package": "publint --strict && attw --pack", - "test": "jest --silent --verbose --color=always", + "test": "NODE_OPTIONS=\"--no-deprecation\" vitest run", "test:types": "tsd", - "test:watch": "jest --silent --verbose --color=always --watch" + "test:watch": "NODE_OPTIONS=\"--no-deprecation\" vitest" }, "dependencies": { "@liveblocks/core": "3.3.3", @@ -47,7 +47,7 @@ }, "devDependencies": { "@liveblocks/eslint-config": "*", - "@liveblocks/jest-config": "*" + "@liveblocks/vitest-config": "*" }, "bugs": { "url": "https://github.com/liveblocks/liveblocks/issues" diff --git a/packages/liveblocks-node-lexical/src/__tests__/index.test.ts b/packages/liveblocks-node-lexical/src/__tests__/index.test.ts index 06df3fe343d..46f18b08447 100644 --- a/packages/liveblocks-node-lexical/src/__tests__/index.test.ts +++ b/packages/liveblocks-node-lexical/src/__tests__/index.test.ts @@ -1,3 +1,5 @@ +import { test } from "vitest"; + import * as _ from ".."; test.todo("Write test for createLiveblocksDocument"); diff --git a/packages/liveblocks-node-lexical/vitest.config.ts b/packages/liveblocks-node-lexical/vitest.config.ts new file mode 100644 index 00000000000..e29ad5d9647 --- /dev/null +++ b/packages/liveblocks-node-lexical/vitest.config.ts @@ -0,0 +1,7 @@ +import { defaultLiveblocksVitestConfig } from "@liveblocks/vitest-config"; + +export default defaultLiveblocksVitestConfig({ + test: { + environment: "node", + }, +}); \ No newline at end of file diff --git a/packages/liveblocks-node-prosemirror/jest.config.cjs b/packages/liveblocks-node-prosemirror/jest.config.cjs deleted file mode 100644 index 4de12d705d9..00000000000 --- a/packages/liveblocks-node-prosemirror/jest.config.cjs +++ /dev/null @@ -1,11 +0,0 @@ -/** @type {import('jest').Config} */ - -const commonJestConfig = require("@liveblocks/jest-config"); - -module.exports = { - // Our standard Jest configuration, used by all projects in this monorepo - ...commonJestConfig, - - // Our standard setup assumed jsdom environment. Override it for node here. - testEnvironment: "node", -}; diff --git a/packages/liveblocks-node-prosemirror/package.json b/packages/liveblocks-node-prosemirror/package.json index 24182a4e280..6f742a747e6 100644 --- a/packages/liveblocks-node-prosemirror/package.json +++ b/packages/liveblocks-node-prosemirror/package.json @@ -29,9 +29,9 @@ "format": "(eslint --fix src/ || true) && prettier --write src/", "lint": "eslint src/", "lint:package": "publint --strict && attw --pack", - "test": "jest --silent --verbose --color=always", + "test": "NODE_OPTIONS=\"--no-deprecation\" vitest run", "test:types": "tsd -f test-d/index.test-d.ts", - "test:watch": "jest --silent --verbose --color=always --watch" + "test:watch": "NODE_OPTIONS=\"--no-deprecation\" vitest" }, "dependencies": { "@liveblocks/core": "3.3.3", @@ -49,8 +49,8 @@ }, "devDependencies": { "@liveblocks/eslint-config": "*", - "@liveblocks/jest-config": "*", - "msw": "^2.7.0" + "@liveblocks/vitest-config": "*", + "msw": "^2.10.4" }, "bugs": { "url": "https://github.com/liveblocks/liveblocks/issues" diff --git a/packages/liveblocks-node-prosemirror/src/__tests__/index.test.ts b/packages/liveblocks-node-prosemirror/src/__tests__/index.test.ts index a8543e3165b..7bdccabc38f 100644 --- a/packages/liveblocks-node-prosemirror/src/__tests__/index.test.ts +++ b/packages/liveblocks-node-prosemirror/src/__tests__/index.test.ts @@ -1,6 +1,7 @@ import { Liveblocks } from "@liveblocks/node"; import { http, HttpResponse } from "msw"; import { setupServer } from "msw/node"; +import { afterAll, beforeAll, describe, expect, test } from "vitest"; import { applyUpdate, Doc, encodeStateAsUpdate } from "yjs"; import { withProsemirrorDocument } from "../document"; diff --git a/packages/liveblocks-node-prosemirror/vitest.config.ts b/packages/liveblocks-node-prosemirror/vitest.config.ts new file mode 100644 index 00000000000..e29ad5d9647 --- /dev/null +++ b/packages/liveblocks-node-prosemirror/vitest.config.ts @@ -0,0 +1,7 @@ +import { defaultLiveblocksVitestConfig } from "@liveblocks/vitest-config"; + +export default defaultLiveblocksVitestConfig({ + test: { + environment: "node", + }, +}); \ No newline at end of file diff --git a/packages/liveblocks-node/jest.config.cjs b/packages/liveblocks-node/jest.config.cjs deleted file mode 100644 index 4de12d705d9..00000000000 --- a/packages/liveblocks-node/jest.config.cjs +++ /dev/null @@ -1,11 +0,0 @@ -/** @type {import('jest').Config} */ - -const commonJestConfig = require("@liveblocks/jest-config"); - -module.exports = { - // Our standard Jest configuration, used by all projects in this monorepo - ...commonJestConfig, - - // Our standard setup assumed jsdom environment. Override it for node here. - testEnvironment: "node", -}; diff --git a/packages/liveblocks-node/package.json b/packages/liveblocks-node/package.json index 8409d779af8..fcaf239ded6 100644 --- a/packages/liveblocks-node/package.json +++ b/packages/liveblocks-node/package.json @@ -29,9 +29,9 @@ "format": "(eslint --fix src/ || true) && prettier --write src/", "lint": "eslint src/", "lint:package": "publint --strict && attw --pack", - "test": "jest --silent --verbose --color=always", + "test": "NODE_OPTIONS=\"--no-deprecation\" vitest run", "test:types": "ls test-d/* | xargs -n1 tsd --files", - "test:watch": "jest --silent --verbose --color=always --watch" + "test:watch": "NODE_OPTIONS=\"--no-deprecation\" vitest" }, "dependencies": { "@liveblocks/core": "3.3.3", @@ -41,9 +41,9 @@ }, "devDependencies": { "@liveblocks/eslint-config": "*", - "@liveblocks/jest-config": "*", + "@liveblocks/vitest-config": "*", "@types/node-fetch": "^2.6.6", - "msw": "^2.7.0", + "msw": "^2.10.4", "svix": "^0.75.0" }, "bugs": { diff --git a/packages/liveblocks-node/src/__tests__/Session.test.ts b/packages/liveblocks-node/src/__tests__/Session.test.ts index b7782a21a75..c7096d9986b 100644 --- a/packages/liveblocks-node/src/__tests__/Session.test.ts +++ b/packages/liveblocks-node/src/__tests__/Session.test.ts @@ -1,3 +1,5 @@ +import { describe, expect, test } from "vitest"; + import { Liveblocks } from "../client"; const P1 = "room:read"; diff --git a/packages/liveblocks-node/src/__tests__/client.test.ts b/packages/liveblocks-node/src/__tests__/client.test.ts index bcc61def10c..318aaa87092 100644 --- a/packages/liveblocks-node/src/__tests__/client.test.ts +++ b/packages/liveblocks-node/src/__tests__/client.test.ts @@ -10,6 +10,7 @@ import type { import { createNotificationSettings, LiveList } from "@liveblocks/core"; import { http, HttpResponse } from "msw"; import { setupServer } from "msw/node"; +import { afterAll, afterEach, beforeAll, describe, expect, test } from "vitest"; import { Liveblocks, LiveblocksError } from "../client"; import { getBaseUrl } from "../utils"; diff --git a/packages/liveblocks-node/src/__tests__/webhooks.test.ts b/packages/liveblocks-node/src/__tests__/webhooks.test.ts index d91ebc6e605..c7e7312b3a5 100644 --- a/packages/liveblocks-node/src/__tests__/webhooks.test.ts +++ b/packages/liveblocks-node/src/__tests__/webhooks.test.ts @@ -1,4 +1,5 @@ import { Webhook } from "svix"; +import { afterEach, describe, expect, test, vi } from "vitest"; import { isCustomNotificationEvent, @@ -45,7 +46,7 @@ describe("WebhookHandler", () => { ); }; - it.each([undefined, null, "", "not_a_valid_secret"])( + test.each([undefined, null, "", "not_a_valid_secret"])( "initialization should throw an error if the secret is not valid", (invalidSecret) => { // @ts-expect-error: We want to test invalid secret @@ -55,10 +56,10 @@ describe("WebhookHandler", () => { describe("verifyRequest", () => { afterEach(() => { - jest.useRealTimers(); + vi.useRealTimers(); }); - it.each([ + test.each([ ["userEntered", userEnteredBody], [ "storageUpdated", @@ -239,7 +240,7 @@ describe("WebhookHandler", () => { ], ])('should verify a "%s" event', (type, data) => { const now = 1674851609000; - jest.useFakeTimers({ + vi.useFakeTimers({ now, }); @@ -272,7 +273,7 @@ describe("WebhookHandler", () => { expect(event).toEqual(body); }); - it('should verify a "ydocUpdated" event', () => { + test('should verify a "ydocUpdated" event', () => { const ydocUpdated = { data: { appId: "605a50b01a36d5ea7a2e9104", @@ -294,7 +295,7 @@ describe("WebhookHandler", () => { ), }; - jest.useFakeTimers({ + vi.useFakeTimers({ now: 1674851522000, }); @@ -308,8 +309,8 @@ describe("WebhookHandler", () => { expect(event).toEqual(ydocUpdated); }); - it("should verify an event with multiple signatures", () => { - jest.useFakeTimers({ + test("should verify an event with multiple signatures", () => { + vi.useFakeTimers({ now: 1674850126000, }); @@ -345,8 +346,8 @@ describe("WebhookHandler", () => { expect(event).toEqual(userEnteredBody); }); - it("should allow a native Headers object", () => { - jest.useFakeTimers({ + test("should allow a native Headers object", () => { + vi.useFakeTimers({ now: 1674850126000, }); const webhookHandler = new WebhookHandler(secret); @@ -369,8 +370,8 @@ describe("WebhookHandler", () => { expect(event).toEqual(userEnteredBody); }); - it("should throw if the rawBody is not a string", () => { - jest.useFakeTimers({ + test("should throw if the rawBody is not a string", () => { + vi.useFakeTimers({ now: 1674850126000, }); @@ -394,8 +395,8 @@ describe("WebhookHandler", () => { ); }); - it("should throw if the signature is invalid", () => { - jest.useFakeTimers({ + test("should throw if the signature is invalid", () => { + vi.useFakeTimers({ now: 1674850126000, }); @@ -411,8 +412,8 @@ describe("WebhookHandler", () => { ).toThrowError("Invalid signature"); }); - it("should throw if the timestamp is invalid", () => { - jest.useFakeTimers({ + test("should throw if the timestamp is invalid", () => { + vi.useFakeTimers({ now: 1674850126000, }); @@ -434,9 +435,9 @@ describe("WebhookHandler", () => { ).toThrowError("Invalid timestamp"); }); - it("should throw if timestamp is above future threshold", () => { + test("should throw if timestamp is above future threshold", () => { const tenMinutesAgo = 1674850126000 - 10 * 60 * 1000; - jest.useFakeTimers({ + vi.useFakeTimers({ now: tenMinutesAgo, }); @@ -457,9 +458,9 @@ describe("WebhookHandler", () => { ).toThrowError("Timestamp in the future"); }); - it("should throw if timestamp is below past threshold", () => { + test("should throw if timestamp is below past threshold", () => { const tenMinutesFromNow = 1674850126000 + 10 * 60 * 1000; - jest.useFakeTimers({ + vi.useFakeTimers({ now: tenMinutesFromNow, }); @@ -480,8 +481,8 @@ describe("WebhookHandler", () => { ).toThrowError("Timestamp too old"); }); - it("should throw if the event type is not supported", () => { - jest.useFakeTimers({ + test("should throw if the event type is not supported", () => { + vi.useFakeTimers({ now: 1674851522000, }); @@ -523,7 +524,7 @@ describe("WebhookHandler", () => { describe("Type guards", () => { describe("isThreadNotificationEvent", () => { - it.each<{ name: string; event: WebhookEvent; expected: boolean }>([ + test.each<{ name: string; event: WebhookEvent; expected: boolean }>([ { name: "notification/thread", event: { @@ -584,7 +585,7 @@ describe("Type guards", () => { }); describe("isTextMentionNotificationEvent", () => { - it.each<{ name: string; event: WebhookEvent; expected: boolean }>([ + test.each<{ name: string; event: WebhookEvent; expected: boolean }>([ { name: "notification/textMention", event: { @@ -645,7 +646,7 @@ describe("Type guards", () => { }); describe("isCustomNotificationEvent", () => { - it.each<{ name: string; event: WebhookEvent; expected: boolean }>([ + test.each<{ name: string; event: WebhookEvent; expected: boolean }>([ { name: "notification/textMention", event: { diff --git a/packages/liveblocks-node/vitest.config.ts b/packages/liveblocks-node/vitest.config.ts new file mode 100644 index 00000000000..e29ad5d9647 --- /dev/null +++ b/packages/liveblocks-node/vitest.config.ts @@ -0,0 +1,7 @@ +import { defaultLiveblocksVitestConfig } from "@liveblocks/vitest-config"; + +export default defaultLiveblocksVitestConfig({ + test: { + environment: "node", + }, +}); \ No newline at end of file diff --git a/packages/liveblocks-react-blocknote/package.json b/packages/liveblocks-react-blocknote/package.json index 96daa54b462..6a91b65031c 100644 --- a/packages/liveblocks-react-blocknote/package.json +++ b/packages/liveblocks-react-blocknote/package.json @@ -38,8 +38,8 @@ "lint": "eslint src/; stylelint src/styles/", "lint:package": "publint --strict && attw --pack", "start": "npm run dev", - "test": "vitest run", - "test:watch": "vitest" + "test": "NODE_OPTIONS=\"--no-deprecation\" vitest run", + "test:watch": "NODE_OPTIONS=\"--no-deprecation\" vitest" }, "dependencies": { "@liveblocks/client": "3.3.3", @@ -70,12 +70,12 @@ }, "devDependencies": { "@liveblocks/eslint-config": "*", - "@liveblocks/jest-config": "*", + "@liveblocks/vitest-config": "*", "@liveblocks/rollup-config": "*", "@testing-library/jest-dom": "^5.16.5", "eslint-plugin-react": "^7.33.2", "eslint-plugin-react-hooks": "^4.6.0", - "msw": "^1.3.5", + "msw": "^2.10.4", "stylelint": "^15.10.2", "stylelint-config-standard": "^34.0.0", "stylelint-order": "^6.0.3", diff --git a/packages/liveblocks-react-lexical/jest.config.cjs b/packages/liveblocks-react-lexical/jest.config.cjs deleted file mode 100644 index 5fa0bec03a3..00000000000 --- a/packages/liveblocks-react-lexical/jest.config.cjs +++ /dev/null @@ -1 +0,0 @@ -module.exports = require("@liveblocks/jest-config"); diff --git a/packages/liveblocks-react-lexical/package.json b/packages/liveblocks-react-lexical/package.json index 177aed4048e..2ef7a461b01 100644 --- a/packages/liveblocks-react-lexical/package.json +++ b/packages/liveblocks-react-lexical/package.json @@ -38,8 +38,8 @@ "lint": "eslint src/; stylelint src/styles/", "lint:package": "publint --strict && attw --pack", "start": "npm run dev", - "test": "jest --silent --verbose --color=always", - "test:watch": "jest --silent --verbose --color=always --watch" + "test": "NODE_OPTIONS=\"--no-deprecation\" vitest run", + "test:watch": "NODE_OPTIONS=\"--no-deprecation\" vitest" }, "dependencies": { "@floating-ui/react-dom": "^2.1.1", @@ -74,12 +74,12 @@ }, "devDependencies": { "@liveblocks/eslint-config": "*", - "@liveblocks/jest-config": "*", "@liveblocks/rollup-config": "*", + "@liveblocks/vitest-config": "*", "@testing-library/jest-dom": "^5.16.5", "eslint-plugin-react": "^7.33.2", "eslint-plugin-react-hooks": "^4.6.0", - "msw": "^1.3.5", + "msw": "^2.10.4", "stylelint": "^15.10.2", "stylelint-config-standard": "^34.0.0", "stylelint-order": "^6.0.3", diff --git a/packages/liveblocks-react-lexical/src/__tests__/index.test.ts b/packages/liveblocks-react-lexical/src/__tests__/index.test.ts index e7210492ec3..e2ed6d93276 100644 --- a/packages/liveblocks-react-lexical/src/__tests__/index.test.ts +++ b/packages/liveblocks-react-lexical/src/__tests__/index.test.ts @@ -1,3 +1,5 @@ +import { test } from "vitest"; + import * as _ from ".."; test.todo("Write test for _.FloatingComposer"); diff --git a/packages/liveblocks-react-lexical/vitest.config.ts b/packages/liveblocks-react-lexical/vitest.config.ts new file mode 100644 index 00000000000..40d487e4690 --- /dev/null +++ b/packages/liveblocks-react-lexical/vitest.config.ts @@ -0,0 +1,7 @@ +import { defaultLiveblocksVitestConfig } from "@liveblocks/vitest-config"; + +export default defaultLiveblocksVitestConfig({ + test: { + environment: "jsdom", + }, +}); \ No newline at end of file diff --git a/packages/liveblocks-react-tiptap/jest.config.cjs b/packages/liveblocks-react-tiptap/jest.config.cjs deleted file mode 100644 index 5fa0bec03a3..00000000000 --- a/packages/liveblocks-react-tiptap/jest.config.cjs +++ /dev/null @@ -1 +0,0 @@ -module.exports = require("@liveblocks/jest-config"); diff --git a/packages/liveblocks-react-tiptap/package.json b/packages/liveblocks-react-tiptap/package.json index aa6927da65a..370627075ae 100644 --- a/packages/liveblocks-react-tiptap/package.json +++ b/packages/liveblocks-react-tiptap/package.json @@ -38,8 +38,8 @@ "lint": "eslint src/; stylelint src/styles/", "lint:package": "publint --strict && attw --pack", "start": "npm run dev", - "test": "jest --silent --verbose --color=always", - "test:watch": "jest --silent --verbose --color=always --watch" + "test": "NODE_OPTIONS=\"--no-deprecation\" vitest run", + "test:watch": "NODE_OPTIONS=\"--no-deprecation\" vitest" }, "dependencies": { "@floating-ui/react-dom": "^2.1.2", @@ -78,12 +78,12 @@ }, "devDependencies": { "@liveblocks/eslint-config": "*", - "@liveblocks/jest-config": "*", "@liveblocks/rollup-config": "*", + "@liveblocks/vitest-config": "*", "@testing-library/jest-dom": "^5.16.5", "eslint-plugin-react": "^7.33.2", "eslint-plugin-react-hooks": "^4.6.0", - "msw": "^1.3.5", + "msw": "^2.10.4", "stylelint": "^15.10.2", "stylelint-config-standard": "^34.0.0", "stylelint-order": "^6.0.3", diff --git a/packages/liveblocks-react-tiptap/src/__tests__/__snapshots__/utils.test.ts.snap b/packages/liveblocks-react-tiptap/src/__tests__/__snapshots__/utils.test.ts.snap index a285c1bd128..79f8d936f52 100644 --- a/packages/liveblocks-react-tiptap/src/__tests__/__snapshots__/utils.test.ts.snap +++ b/packages/liveblocks-react-tiptap/src/__tests__/__snapshots__/utils.test.ts.snap @@ -1,6 +1,6 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html -exports[`utils getContextualPromptContext should balance the available length equally on both sides of the selection 1`] = ` +exports[`utils > getContextualPromptContext > should balance the available length equally on both sides of the selection 1`] = ` { "afterSelection": "congue eleifend hendrerit. Curabitur maximus sit amet lectus ac dapibus. Suspendisse potenti. Pellentesque vel est molestie, posuere orci nec, finibus ligula. Aliquam erat volutpat. Proin justo diam, lobortis a imperdiet non, mollis quis massa. Mauris rhoncus scelerisque leo, vulputate tempor sem commodo id. Donec volutpat ante at massa mattis ultricies. Mauris quis egestas felis, non vulputate do[…]", "beforeSelection": "[…]ius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Pellentesque viverra consectetur lectus vitae rhoncus. Maecenas hendrerit nulla id tristique ullamcorper. Suspendisse gravida dapibus ante volutpat convallis. Quisque enim lectus, lobortis vitae turpis ut, tempor semper lectus. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam in quam rhoncus, euismod leo nec", @@ -8,7 +8,7 @@ exports[`utils getContextualPromptContext should balance the available length eq } `; -exports[`utils getContextualPromptContext should compensate after the selection if before is not enough 1`] = ` +exports[`utils > getContextualPromptContext > should compensate after the selection if before is not enough 1`] = ` { "afterSelection": "landit lorem. Aliquam neque risus, tempor sed volutpat eget, cursus at magna. Nullam eu metus orci. Aliquam bibendum pellentesque elit at feugiat. Sed elementum nisl eget ante commodo, pellentesque consectetur mi semper. Vivamus pharetra justo sed velit venenatis, sed lobortis lacus mollis. Mauris finibus dolor non turpis rutrum rhoncus a in lacus. Nunc tempor enim arcu, sit amet egestas urna imperdiet non. Fusce et eros tempus, eleifend leo nec, dictum augue. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Duis sit amet laoreet leo, ornare imperdiet massa. Cras iaculis ligula sed commodo suscipit. Donec sit amet sem ut diam ullamcorper pulvinar vel quis mauris. Sed accumsan finibus egestas. Orci varius natoque penatibus et magnis dis parturient […]", "beforeSelection": "", @@ -16,7 +16,7 @@ exports[`utils getContextualPromptContext should compensate after the selection } `; -exports[`utils getContextualPromptContext should compensate before the selection if after is not enough 1`] = ` +exports[`utils > getContextualPromptContext > should compensate before the selection if after is not enough 1`] = ` { "afterSelection": "nisl, posuere et elementum luctus, commodo volutpat diam. Praesent luctus id lacus eu cursus. Sed nec dolor quis neque convallis cursus et quis diam.", "beforeSelection": "[…]s. Mauris quis egestas felis, non vulputate dolor. Maecenas egestas diam at arcu auctor sagittis. Nulla dignissim feugiat erat. Sed justo enim, tincidunt quis nunc vel, vestibulum euismod libero. Suspendisse dictum at lorem sit amet porta. Vestibulum vehicula mattis leo sit amet pulvinar. Maecenas in hendrerit magna. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras dignissim porttitor quam nec interdum. Sed posuere leo eget sodales dignissim. Mauris malesuada vel diam eget faucibus. Proin et hendrerit dui, ac porttitor nibh. Praesent efficitur mollis condimentum. Aliquam sit amet turpis in felis vulputate eleifend ut facilisis ar", @@ -24,7 +24,7 @@ exports[`utils getContextualPromptContext should compensate before the selection } `; -exports[`utils getContextualPromptContext should handle an empty selection 1`] = ` +exports[`utils > getContextualPromptContext > should handle an empty selection 1`] = ` { "afterSelection": "us laoreet eu et nulla. Nulla tempor lobortis turpis, sed placerat nulla elementum eget. Vestibulum congue eleifend hendrerit. Curabitur maximus sit amet lectus ac dapibus. Suspendisse potenti. Pellentesque vel est molestie, posuere orci nec, finibus ligula. Aliquam erat volutpat. Proin justo diam, lobortis a imperdiet non, mollis quis massa. Mauris rhoncus scelerisque leo, vulputate tempor sem commodo id. Donec volutpat ante at massa mattis ultricies. Mauris quis egestas felis, non vulputate do[…]", "beforeSelection": "[…]ius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Pellentesque viverra consectetur lectus vitae rhoncus. Maecenas hendrerit nulla id tristique ullamcorper. Suspendisse gravida dapibus ante volutpat convallis. Quisque enim lectus, lobortis vitae turpis ut, tempor semper lectus. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam in quam rhoncus, euismod leo nec, molestie risus. Phasellus eu urna sit amet massa ultrices semper. Integer id felis in lorem faucib", @@ -32,7 +32,7 @@ exports[`utils getContextualPromptContext should handle an empty selection 1`] = } `; -exports[`utils getContextualPromptContext should support elements 1`] = ` +exports[`utils > getContextualPromptContext > should support elements 1`] = ` { "afterSelection": "rem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem ipsum @@ -44,7 +44,7 @@ ipsum ipsum ipsum ipsum ipsum ipsum ipsum ipsum ipsum ipsum ipsum ipsum ipsum ip } `; -exports[`utils getContextualPromptContext should take into account the document size 1`] = ` +exports[`utils > getContextualPromptContext > should take into account the document size 1`] = ` { "afterSelection": "c dolor quis neque convallis cursus et quis diam.", "beforeSelection": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque viverra aliquet magna, id fau", @@ -52,7 +52,7 @@ exports[`utils getContextualPromptContext should take into account the document } `; -exports[`utils getContextualPromptContext should truncate the selection if it is too large 1`] = ` +exports[`utils > getContextualPromptContext > should truncate the selection if it is too large 1`] = ` { "afterSelection": "", "beforeSelection": "", diff --git a/packages/liveblocks-react-tiptap/src/__tests__/index.test.ts b/packages/liveblocks-react-tiptap/src/__tests__/index.test.ts index 790735f38d5..00d07fbb570 100644 --- a/packages/liveblocks-react-tiptap/src/__tests__/index.test.ts +++ b/packages/liveblocks-react-tiptap/src/__tests__/index.test.ts @@ -1,3 +1,5 @@ +import { test } from "vitest"; + import * as _ from ".."; test.todo("Write test for _.FloatingComposer"); diff --git a/packages/liveblocks-react-tiptap/src/__tests__/utils.test.ts b/packages/liveblocks-react-tiptap/src/__tests__/utils.test.ts index 73ab3c2d772..93993b6ca13 100644 --- a/packages/liveblocks-react-tiptap/src/__tests__/utils.test.ts +++ b/packages/liveblocks-react-tiptap/src/__tests__/utils.test.ts @@ -3,6 +3,7 @@ import { Editor } from "@tiptap/core"; import Document from "@tiptap/extension-document"; import Paragraph from "@tiptap/extension-paragraph"; import Text from "@tiptap/extension-text"; +import { afterEach, beforeEach, describe, expect, test } from "vitest"; import { getContextualPromptContext } from "../utils"; diff --git a/packages/liveblocks-react-tiptap/vitest.config.ts b/packages/liveblocks-react-tiptap/vitest.config.ts new file mode 100644 index 00000000000..40d487e4690 --- /dev/null +++ b/packages/liveblocks-react-tiptap/vitest.config.ts @@ -0,0 +1,7 @@ +import { defaultLiveblocksVitestConfig } from "@liveblocks/vitest-config"; + +export default defaultLiveblocksVitestConfig({ + test: { + environment: "jsdom", + }, +}); \ No newline at end of file diff --git a/packages/liveblocks-react-ui/jest.config.cjs b/packages/liveblocks-react-ui/jest.config.cjs deleted file mode 100644 index 5fa0bec03a3..00000000000 --- a/packages/liveblocks-react-ui/jest.config.cjs +++ /dev/null @@ -1 +0,0 @@ -module.exports = require("@liveblocks/jest-config"); diff --git a/packages/liveblocks-react-ui/package.json b/packages/liveblocks-react-ui/package.json index ce5c64a0506..4f7dd8c6874 100644 --- a/packages/liveblocks-react-ui/package.json +++ b/packages/liveblocks-react-ui/package.json @@ -70,9 +70,9 @@ "format": "eslint --fix src/; stylelint --fix src/styles/; prettier --write src/", "lint": "eslint src/; stylelint src/styles/", "lint:package": "publint --strict && attw --pack", - "test": "jest --silent --verbose --color=always", + "test": "NODE_OPTIONS=\"--no-deprecation\" vitest run", "test:types": "ls test-d/* | xargs -n1 tsd --files", - "test:watch": "jest --silent --verbose --color=always --watch" + "test:watch": "NODE_OPTIONS=\"--no-deprecation\" vitest" }, "dependencies": { "@floating-ui/react-dom": "^2.1.2", @@ -107,13 +107,13 @@ }, "devDependencies": { "@liveblocks/eslint-config": "*", - "@liveblocks/jest-config": "*", "@liveblocks/rollup-config": "*", - "@testing-library/jest-dom": "^5.16.5", + "@liveblocks/vitest-config": "*", + "@testing-library/jest-dom": "^6.4.6", "@testing-library/react": "^13.1.1", "eslint-plugin-react": "^7.33.2", "eslint-plugin-react-hooks": "^4.6.0", - "msw": "^1.3.5", + "msw": "^2.10.4", "stylelint": "^15.10.2", "stylelint-config-standard": "^34.0.0", "stylelint-order": "^6.0.3", diff --git a/packages/liveblocks-react-ui/src/__tests__/format-file-size.test.ts b/packages/liveblocks-react-ui/src/__tests__/format-file-size.test.ts index d4cf65eb672..9f27a88b7e6 100644 --- a/packages/liveblocks-react-ui/src/__tests__/format-file-size.test.ts +++ b/packages/liveblocks-react-ui/src/__tests__/format-file-size.test.ts @@ -1,3 +1,5 @@ +import { describe, expect, test } from "vitest"; + import { formatFileSize } from "../utils/format-file-size"; const BASE = 1000; diff --git a/packages/liveblocks-react-ui/src/__tests__/index.test.tsx b/packages/liveblocks-react-ui/src/__tests__/index.test.tsx index f13023b6a8d..71e6a9636df 100644 --- a/packages/liveblocks-react-ui/src/__tests__/index.test.tsx +++ b/packages/liveblocks-react-ui/src/__tests__/index.test.tsx @@ -1,13 +1,12 @@ -import "@testing-library/jest-dom"; - import type { CommentData, RoomStateServerMsg, ThreadData, } from "@liveblocks/core"; import { ServerMsgCode } from "@liveblocks/core"; -import { rest } from "msw"; +import { http, HttpResponse } from "msw"; import { setupServer } from "msw/node"; +import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, test } from "vitest"; import { Comment } from "../components/Comment"; import { Composer } from "../components/Composer"; @@ -110,13 +109,11 @@ class MockWebSocket { window.WebSocket = MockWebSocket as any; const server = setupServer( - rest.post("/api/auth", (_, res, ctx) => { - return res( - ctx.json({ - token: - "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE2OTAwMzMzMjgsImV4cCI6MTY5MDAzMzMzMywiayI6InNlYy1sZWdhY3kiLCJyb29tSWQiOiJlTFB3dU9tTXVUWEN6Q0dSaTVucm4iLCJhcHBJZCI6IjYyNDFjYjk1ZWQ2ODdkNWRlNWFhYTEzMiIsImFjdG9yIjoxLCJzY29wZXMiOlsicm9vbTp3cml0ZSJdLCJpZCI6InVzZXItMyIsIm1heENvbm5lY3Rpb25zUGVyUm9vbSI6MjB9.QoRc9dJJp-C1LzmQ-S_scHfFsAZ7dBcqep0bUZNyWxEWz_VeBHBBNdJpNs7b7RYRFDBi7RxkywKJlO-gNE8h3wkhebgLQVeSgI3YfTJo7J8Jzj38TzH85ZIbybaiGcxda_sYn3VohDtUHA1k67ns08Q2orJBNr30Gc88jJmc1He_7bLStsDP4M2F1NRMuFuqLULWHnPeEM7jMvLZYkbu3SBeCH4TQGyweu7qAXvP-HHtmvzOi8LdEnpxgxGjxefdu6m4a-fJj6LwoYCGi1rlLDHH9aOHFwYVrBBBVwoeIDSHoAonkPaae9AWM6igJhNt9-ihgEH6sF-qgFiPxHNXdg", - }) - ); + http.post("/api/auth", () => { + return HttpResponse.json({ + token: + "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE2OTAwMzMzMjgsImV4cCI6MTY5MDAzMzMzMywiayI6InNlYy1sZWdhY3kiLCJyb29tSWQiOiJlTFB3dU9tTXVUWEN6Q0dSaTVucm4iLCJhcHBJZCI6IjYyNDFjYjk1ZWQ2ODdkNWRlNWFhYTEzMiIsImFjdG9yIjoxLCJzY29wZXMiOlsicm9vbTp3cml0ZSJdLCJpZCI6InVzZXItMyIsIm1heENvbm5lY3Rpb25zUGVyUm9vbSI6MjB9.QoRc9dJJp-C1LzmQ-S_scHfFsAZ7dBcqep0bUZNyWxEWz_VeBHBBNdJpNs7b7RYRFDBi7RxkywKJlO-gNE8h3wkhebgLQVeSgI3YfTJo7J8Jzj38TzH85ZIbybaiGcxda_sYn3VohDtUHA1k67ns08Q2orJBNr30Gc88jJmc1He_7bLStsDP4M2F1NRMuFuqLULWHnPeEM7jMvLZYkbu3SBeCH4TQGyweu7qAXvP-HHtmvzOi8LdEnpxgxGjxefdu6m4a-fJj6LwoYCGi1rlLDHH9aOHFwYVrBBBVwoeIDSHoAonkPaae9AWM6igJhNt9-ihgEH6sF-qgFiPxHNXdg", + }); }) ); diff --git a/packages/liveblocks-react-ui/src/primitives/Composer/__tests__/utils.test.ts b/packages/liveblocks-react-ui/src/primitives/Composer/__tests__/utils.test.ts index 664fcc1bb53..0d5eb128aea 100644 --- a/packages/liveblocks-react-ui/src/primitives/Composer/__tests__/utils.test.ts +++ b/packages/liveblocks-react-ui/src/primitives/Composer/__tests__/utils.test.ts @@ -1,4 +1,5 @@ import type { CommentBody } from "@liveblocks/client"; +import { describe, expect, test } from "vitest"; import type { ComposerBody } from "../../../types"; import { commentBodyToComposerBody, composerBodyToCommentBody } from "../utils"; diff --git a/packages/liveblocks-react-ui/src/primitives/__tests__/Markdown.test.tsx b/packages/liveblocks-react-ui/src/primitives/__tests__/Markdown.test.tsx index 64cc6c8ef8e..8cac26aef80 100644 --- a/packages/liveblocks-react-ui/src/primitives/__tests__/Markdown.test.tsx +++ b/packages/liveblocks-react-ui/src/primitives/__tests__/Markdown.test.tsx @@ -1,11 +1,13 @@ -import "@testing-library/jest-dom"; - -import { render } from "@testing-library/react"; +import { cleanup, render } from "@testing-library/react"; +import { afterEach, describe, expect, test } from "vitest"; import { Markdown, type MarkdownComponents } from "../Markdown"; import { dedent } from "./_utils"; describe("Markdown", () => { + afterEach(() => { + cleanup(); + }); test.each([ { description: "paragraphs", diff --git a/packages/liveblocks-react-ui/src/primitives/__tests__/Timestamp.test.tsx b/packages/liveblocks-react-ui/src/primitives/__tests__/Timestamp.test.tsx index cd99ee94e03..fb290cd48f7 100644 --- a/packages/liveblocks-react-ui/src/primitives/__tests__/Timestamp.test.tsx +++ b/packages/liveblocks-react-ui/src/primitives/__tests__/Timestamp.test.tsx @@ -1,10 +1,12 @@ -import "@testing-library/jest-dom"; - -import { render } from "@testing-library/react"; +import { cleanup, render } from "@testing-library/react"; +import { afterEach, describe, expect, test } from "vitest"; import { Timestamp } from "../Timestamp"; describe("Timestamp", () => { + afterEach(() => { + cleanup(); + }); const now = Date.now(); test("should render", () => { diff --git a/packages/liveblocks-react-ui/vitest.config.ts b/packages/liveblocks-react-ui/vitest.config.ts new file mode 100644 index 00000000000..7dac5cb27e3 --- /dev/null +++ b/packages/liveblocks-react-ui/vitest.config.ts @@ -0,0 +1,8 @@ +import { defaultLiveblocksVitestConfig } from "@liveblocks/vitest-config"; + +export default defaultLiveblocksVitestConfig({ + test: { + environment: "jsdom", + setupFiles: ["vitest.setup.ts"], + }, +}); diff --git a/packages/liveblocks-react-ui/vitest.setup.ts b/packages/liveblocks-react-ui/vitest.setup.ts new file mode 100644 index 00000000000..f149f27ae4b --- /dev/null +++ b/packages/liveblocks-react-ui/vitest.setup.ts @@ -0,0 +1 @@ +import "@testing-library/jest-dom/vitest"; diff --git a/packages/liveblocks-react/package.json b/packages/liveblocks-react/package.json index 20112f2c9fd..d9651dd9ff7 100644 --- a/packages/liveblocks-react/package.json +++ b/packages/liveblocks-react/package.json @@ -54,9 +54,9 @@ "format": "(eslint --fix src/ || true) && prettier --write src/", "lint": "eslint src/", "lint:package": "publint --strict && attw --pack && bun scripts/check-exports.ts", - "test": "jest --silent --verbose --color=always", + "test": "NODE_OPTIONS=\"--no-deprecation\" jest --silent --verbose --color=always", "test:types": "ls test-d/* | xargs -n1 tsd --files", - "test:watch": "jest --silent --verbose --color=always --watch", + "test:watch": "NODE_OPTIONS=\"--no-deprecation\" jest --silent --verbose --color=always --watch", "test:deps": "depcruise src --exclude __tests__", "showdeps": "depcruise src --include-only '^src' --exclude='__tests__' --output-type dot | dot -T svg > /tmp/dependency-graph.svg && open /tmp/dependency-graph.svg" }, diff --git a/packages/liveblocks-react/src/liveblocks.tsx b/packages/liveblocks-react/src/liveblocks.tsx index 440b8b55667..7eb086fb0ef 100644 --- a/packages/liveblocks-react/src/liveblocks.tsx +++ b/packages/liveblocks-react/src/liveblocks.tsx @@ -990,7 +990,11 @@ function useAiChats(options?: UseAiChatsOptions): AiChatsAsyncResult { // *next* render after that, a *new* fetch/promise will get created. ); - return useSignal(store.outputs.aiChats.getOrCreate(queryKey).signal, identity, shallow); + return useSignal( + store.outputs.aiChats.getOrCreate(queryKey).signal, + identity, + shallow + ); } function useAiChatsSuspense(options?: UseAiChatsOptions): AiChatsAsyncSuccess { diff --git a/packages/liveblocks-redux/jest.config.cjs b/packages/liveblocks-redux/jest.config.cjs deleted file mode 100644 index 5fa0bec03a3..00000000000 --- a/packages/liveblocks-redux/jest.config.cjs +++ /dev/null @@ -1 +0,0 @@ -module.exports = require("@liveblocks/jest-config"); diff --git a/packages/liveblocks-redux/package.json b/packages/liveblocks-redux/package.json index 9d3ccaca24d..eed10741dcc 100644 --- a/packages/liveblocks-redux/package.json +++ b/packages/liveblocks-redux/package.json @@ -29,8 +29,8 @@ "format": "(eslint --fix src/ || true) && prettier --write src/", "lint": "eslint src/", "lint:package": "publint --strict && attw --pack", - "test": "jest --silent --verbose --color=always", - "test:watch": "jest --silent --verbose --color=always --watch" + "test": "NODE_OPTIONS=\"--no-deprecation\" vitest run", + "test:watch": "NODE_OPTIONS=\"--no-deprecation\" vitest" }, "dependencies": { "@liveblocks/client": "3.3.3", @@ -41,10 +41,10 @@ }, "devDependencies": { "@liveblocks/eslint-config": "*", - "@liveblocks/jest-config": "*", + "@liveblocks/vitest-config": "*", "@reduxjs/toolkit": "^2.8.2", - "@testing-library/jest-dom": "^6.4.6", - "msw": "^1.3.5", + "@testing-library/dom": "^10.4.0", + "msw": "^2.10.4", "redux": "^5.0.1" }, "sideEffects": false, diff --git a/packages/liveblocks-redux/src/__tests__/index.test.ts b/packages/liveblocks-redux/src/__tests__/index.test.ts index d01dc64ca42..53229a99308 100644 --- a/packages/liveblocks-redux/src/__tests__/index.test.ts +++ b/packages/liveblocks-redux/src/__tests__/index.test.ts @@ -10,8 +10,17 @@ import type { import { ClientMsgCode, OpCode, ServerMsgCode } from "@liveblocks/core"; import type { Reducer } from "@reduxjs/toolkit"; import { configureStore } from "@reduxjs/toolkit"; -import { rest } from "msw"; +import { http, HttpResponse } from "msw"; import { setupServer } from "msw/node"; +import { + afterAll, + afterEach, + beforeAll, + beforeEach, + describe, + expect, + test, +} from "vitest"; import type { Mapping, WithLiveblocks } from ".."; import { actions, liveblocksEnhancer } from ".."; @@ -27,16 +36,14 @@ window.WebSocket = MockWebSocket as any; const { enterRoom, leaveRoom } = actions; const server = setupServer( - rest.post("/api/auth", (_req, res, ctx) => { - return res( - ctx.json({ - token: - "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE2OTAwMzMzMjgsImV4cCI6MTY5MDAzMzMzMywiayI6InNlYy1sZWdhY3kiLCJyb29tSWQiOiJlTFB3dU9tTXVUWEN6Q0dSaTVucm4iLCJhcHBJZCI6IjYyNDFjYjk1ZWQ2ODdkNWRlNWFhYTEzMiIsImFjdG9yIjoxLCJzY29wZXMiOlsicm9vbTp3cml0ZSJdLCJpZCI6InVzZXItMyIsIm1heENvbm5lY3Rpb25zUGVyUm9vbSI6MjB9.QoRc9dJJp-C1LzmQ-S_scHfFsAZ7dBcqep0bUZNyWxEWz_VeBHBBNdJpNs7b7RYRFDBi7RxkywKJlO-gNE8h3wkhebgLQVeSgI3YfTJo7J8Jzj38TzH85ZIbybaiGcxda_sYn3VohDtUHA1k67ns08Q2orJBNr30Gc88jJmc1He_7bLStsDP4M2F1NRMuFuqLULWHnPeEM7jMvLZYkbu3SBeCH4TQGyweu7qAXvP-HHtmvzOi8LdEnpxgxGjxefdu6m4a-fJj6LwoYCGi1rlLDHH9aOHFwYVrBBBVwoeIDSHoAonkPaae9AWM6igJhNt9-ihgEH6sF-qgFiPxHNXdg", - }) - ); + http.post("/api/auth", () => { + return HttpResponse.json({ + token: + "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE2OTAwMzMzMjgsImV4cCI6MTY5MDAzMzMzMywiayI6InNlYy1sZWdhY3kiLCJyb29tSWQiOiJlTFB3dU9tTXVUWEN6Q0dSaTVucm4iLCJhcHBJZCI6IjYyNDFjYjk1ZWQ2ODdkNWRlNWFhYTEzMiIsImFjdG9yIjoxLCJzY29wZXMiOlsicm9vbTp3cml0ZSJdLCJpZCI6InVzZXItMyIsIm1heENvbm5lY3Rpb25zUGVyUm9vbSI6MjB9.QoRc9dJJp-C1LzmQ-S_scHfFsAZ7dBcqep0bUZNyWxEWz_VeBHBBNdJpNs7b7RYRFDBi7RxkywKJlO-gNE8h3wkhebgLQVeSgI3YfTJo7J8Jzj38TzH85ZIbybaiGcxda_sYn3VohDtUHA1k67ns08Q2orJBNr30Gc88jJmc1He_7bLStsDP4M2F1NRMuFuqLULWHnPeEM7jMvLZYkbu3SBeCH4TQGyweu7qAXvP-HHtmvzOi8LdEnpxgxGjxefdu6m4a-fJj6LwoYCGi1rlLDHH9aOHFwYVrBBBVwoeIDSHoAonkPaae9AWM6igJhNt9-ihgEH6sF-qgFiPxHNXdg", + }); }), - rest.post("/api/auth-fail", (_req, res, ctx) => { - return res(ctx.status(400)); + http.post("/api/auth-fail", () => { + return new HttpResponse(null, { status: 400 }); }) ); diff --git a/packages/liveblocks-redux/vitest.config.ts b/packages/liveblocks-redux/vitest.config.ts new file mode 100644 index 00000000000..40d487e4690 --- /dev/null +++ b/packages/liveblocks-redux/vitest.config.ts @@ -0,0 +1,7 @@ +import { defaultLiveblocksVitestConfig } from "@liveblocks/vitest-config"; + +export default defaultLiveblocksVitestConfig({ + test: { + environment: "jsdom", + }, +}); \ No newline at end of file diff --git a/packages/liveblocks-yjs/jest.config.cjs b/packages/liveblocks-yjs/jest.config.cjs deleted file mode 100644 index 5fa0bec03a3..00000000000 --- a/packages/liveblocks-yjs/jest.config.cjs +++ /dev/null @@ -1 +0,0 @@ -module.exports = require("@liveblocks/jest-config"); diff --git a/packages/liveblocks-yjs/package.json b/packages/liveblocks-yjs/package.json index 24887070daa..844abadefec 100644 --- a/packages/liveblocks-yjs/package.json +++ b/packages/liveblocks-yjs/package.json @@ -29,8 +29,8 @@ "format": "eslint --fix src/; prettier --write src/", "lint": "eslint src/", "lint:package": "publint --strict && attw --pack", - "test": "jest --silent --verbose --color=always", - "test:watch": "jest --silent --verbose --color=always --watch" + "test": "NODE_OPTIONS=\"--no-deprecation\" vitest run", + "test:watch": "NODE_OPTIONS=\"--no-deprecation\" vitest" }, "dependencies": { "@liveblocks/client": "3.3.3", @@ -44,9 +44,9 @@ }, "devDependencies": { "@liveblocks/eslint-config": "*", - "@liveblocks/jest-config": "*", + "@liveblocks/vitest-config": "*", "@testing-library/jest-dom": "^6.4.6", - "msw": "^1.3.5" + "msw": "^2.7.3" }, "sideEffects": false, "bugs": { diff --git a/packages/liveblocks-yjs/src/__tests__/awareness.test.ts b/packages/liveblocks-yjs/src/__tests__/awareness.test.ts index 31e4ec6b4f7..ba10b8a0be5 100644 --- a/packages/liveblocks-yjs/src/__tests__/awareness.test.ts +++ b/packages/liveblocks-yjs/src/__tests__/awareness.test.ts @@ -5,8 +5,17 @@ import type { UpdatePresenceServerMsg, } from "@liveblocks/core"; import { ServerMsgCode } from "@liveblocks/core"; -import { rest } from "msw"; +import { http, HttpResponse } from "msw"; import { setupServer } from "msw/node"; +import { + afterAll, + afterEach, + beforeAll, + beforeEach, + describe, + expect, + test, +} from "vitest"; import * as Y from "yjs"; import { LiveblocksYjsProvider } from ".."; @@ -17,16 +26,14 @@ type UpdateType = { added: string[]; removed: string[]; updated: string[] }; window.WebSocket = MockWebSocket as any; const server = setupServer( - rest.post("/api/auth", (_req, res, ctx) => { - return res( - ctx.json({ - token: - "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE2OTAwMzMzMjgsImV4cCI6MTY5MDAzMzMzMywiayI6InNlYy1sZWdhY3kiLCJyb29tSWQiOiJlTFB3dU9tTXVUWEN6Q0dSaTVucm4iLCJhcHBJZCI6IjYyNDFjYjk1ZWQ2ODdkNWRlNWFhYTEzMiIsImFjdG9yIjoxLCJzY29wZXMiOlsicm9vbTp3cml0ZSJdLCJpZCI6InVzZXItMyIsIm1heENvbm5lY3Rpb25zUGVyUm9vbSI6MjB9.QoRc9dJJp-C1LzmQ-S_scHfFsAZ7dBcqep0bUZNyWxEWz_VeBHBBNdJpNs7b7RYRFDBi7RxkywKJlO-gNE8h3wkhebgLQVeSgI3YfTJo7J8Jzj38TzH85ZIbybaiGcxda_sYn3VohDtUHA1k67ns08Q2orJBNr30Gc88jJmc1He_7bLStsDP4M2F1NRMuFuqLULWHnPeEM7jMvLZYkbu3SBeCH4TQGyweu7qAXvP-HHtmvzOi8LdEnpxgxGjxefdu6m4a-fJj6LwoYCGi1rlLDHH9aOHFwYVrBBBVwoeIDSHoAonkPaae9AWM6igJhNt9-ihgEH6sF-qgFiPxHNXdg", - }) - ); + http.post("/api/auth", () => { + return HttpResponse.json({ + token: + "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE2OTAwMzMzMjgsImV4cCI6MTY5MDAzMzMzMywiayI6InNlYy1sZWdhY3kiLCJyb29tSWQiOiJlTFB3dU9tTXVUWEN6Q0dSaTVucm4iLCJhcHBJZCI6IjYyNDFjYjk1ZWQ2ODdkNWRlNWFhYTEzMiIsImFjdG9yIjoxLCJzY29wZXMiOlsicm9vbTp3cml0ZSJdLCJpZCI6InVzZXItMyIsIm1heENvbm5lY3Rpb25zUGVyUm9vbSI6MjB9.QoRc9dJJp-C1LzmQ-S_scHfFsAZ7dBcqep0bUZNyWxEWz_VeBHBBNdJpNs7b7RYRFDBi7RxkywKJlO-gNE8h3wkhebgLQVeSgI3YfTJo7J8Jzj38TzH85ZIbybaiGcxda_sYn3VohDtUHA1k67ns08Q2orJBNr30Gc88jJmc1He_7bLStsDP4M2F1NRMuFuqLULWHnPeEM7jMvLZYkbu3SBeCH4TQGyweu7qAXvP-HHtmvzOi8LdEnpxgxGjxefdu6m4a-fJj6LwoYCGi1rlLDHH9aOHFwYVrBBBVwoeIDSHoAonkPaae9AWM6igJhNt9-ihgEH6sF-qgFiPxHNXdg", + }); }), - rest.post("/api/auth-fail", (_req, res, ctx) => { - return res(ctx.status(400)); + http.post("/api/auth-fail", () => { + return new HttpResponse(null, { status: 400 }); }) ); diff --git a/packages/liveblocks-yjs/src/__tests__/index.test.ts b/packages/liveblocks-yjs/src/__tests__/index.test.ts index 4aaddbef3e8..7657f8abf8e 100644 --- a/packages/liveblocks-yjs/src/__tests__/index.test.ts +++ b/packages/liveblocks-yjs/src/__tests__/index.test.ts @@ -1,3 +1,5 @@ +import { describe, expect, test } from "vitest"; + // eslint-disable-next-line @typescript-eslint/no-unused-vars import { LiveblocksYjsProvider } from ".."; diff --git a/packages/liveblocks-yjs/vitest.config.ts b/packages/liveblocks-yjs/vitest.config.ts new file mode 100644 index 00000000000..40d487e4690 --- /dev/null +++ b/packages/liveblocks-yjs/vitest.config.ts @@ -0,0 +1,7 @@ +import { defaultLiveblocksVitestConfig } from "@liveblocks/vitest-config"; + +export default defaultLiveblocksVitestConfig({ + test: { + environment: "jsdom", + }, +}); \ No newline at end of file diff --git a/packages/liveblocks-zustand/jest.config.cjs b/packages/liveblocks-zustand/jest.config.cjs deleted file mode 100644 index 5fa0bec03a3..00000000000 --- a/packages/liveblocks-zustand/jest.config.cjs +++ /dev/null @@ -1 +0,0 @@ -module.exports = require("@liveblocks/jest-config"); diff --git a/packages/liveblocks-zustand/package.json b/packages/liveblocks-zustand/package.json index bcb4c9d3333..cda5da7a59d 100644 --- a/packages/liveblocks-zustand/package.json +++ b/packages/liveblocks-zustand/package.json @@ -29,9 +29,9 @@ "format": "(eslint --fix src/ || true) && prettier --write src/", "lint": "eslint src/", "lint:package": "publint --strict && attw --pack", - "test": "jest --silent --verbose --color=always", + "test": "NODE_OPTIONS=\"--no-deprecation\" vitest run", "test:types": "tsd", - "test:watch": "jest --silent --verbose --color=always --watch" + "test:watch": "NODE_OPTIONS=\"--no-deprecation\" vitest" }, "dependencies": { "@liveblocks/client": "3.3.3", @@ -42,9 +42,9 @@ }, "devDependencies": { "@liveblocks/eslint-config": "*", - "@liveblocks/jest-config": "*", - "@testing-library/jest-dom": "^6.4.6", - "msw": "^1.3.5", + "@liveblocks/vitest-config": "*", + "@testing-library/dom": "^10.4.0", + "msw": "^2.10.4", "zustand": "^5.0.1" }, "sideEffects": false, diff --git a/packages/liveblocks-zustand/src/__tests__/index.test.ts b/packages/liveblocks-zustand/src/__tests__/index.test.ts index deeaec36f61..9bcda937795 100644 --- a/packages/liveblocks-zustand/src/__tests__/index.test.ts +++ b/packages/liveblocks-zustand/src/__tests__/index.test.ts @@ -13,8 +13,17 @@ import type { UpdatePresenceServerMsg, } from "@liveblocks/core"; import { ClientMsgCode, OpCode, ServerMsgCode } from "@liveblocks/core"; -import { rest } from "msw"; +import { http, HttpResponse } from "msw"; import { setupServer } from "msw/node"; +import { + afterAll, + afterEach, + beforeAll, + beforeEach, + describe, + expect, + test, +} from "vitest"; import type { StateCreator } from "zustand"; import { create } from "zustand"; @@ -27,16 +36,14 @@ window.WebSocket = MockWebSocket as any; const INVALID_CONFIG_ERROR = /Invalid @liveblocks\/zustand middleware config/; const server = setupServer( - rest.post("/api/auth", (_req, res, ctx) => { - return res( - ctx.json({ - token: - "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE2OTAwMzMzMjgsImV4cCI6MTY5MDAzMzMzMywiayI6InNlYy1sZWdhY3kiLCJyb29tSWQiOiJlTFB3dU9tTXVUWEN6Q0dSaTVucm4iLCJhcHBJZCI6IjYyNDFjYjk1ZWQ2ODdkNWRlNWFhYTEzMiIsImFjdG9yIjoxLCJzY29wZXMiOlsicm9vbTp3cml0ZSJdLCJpZCI6InVzZXItMyIsIm1heENvbm5lY3Rpb25zUGVyUm9vbSI6MjB9.QoRc9dJJp-C1LzmQ-S_scHfFsAZ7dBcqep0bUZNyWxEWz_VeBHBBNdJpNs7b7RYRFDBi7RxkywKJlO-gNE8h3wkhebgLQVeSgI3YfTJo7J8Jzj38TzH85ZIbybaiGcxda_sYn3VohDtUHA1k67ns08Q2orJBNr30Gc88jJmc1He_7bLStsDP4M2F1NRMuFuqLULWHnPeEM7jMvLZYkbu3SBeCH4TQGyweu7qAXvP-HHtmvzOi8LdEnpxgxGjxefdu6m4a-fJj6LwoYCGi1rlLDHH9aOHFwYVrBBBVwoeIDSHoAonkPaae9AWM6igJhNt9-ihgEH6sF-qgFiPxHNXdg", - }) - ); + http.post("/api/auth", () => { + return HttpResponse.json({ + token: + "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE2OTAwMzMzMjgsImV4cCI6MTY5MDAzMzMzMywiayI6InNlYy1sZWdhY3kiLCJyb29tSWQiOiJlTFB3dU9tTXVUWEN6Q0dSaTVucm4iLCJhcHBJZCI6IjYyNDFjYjk1ZWQ2ODdkNWRlNWFhYTEzMiIsImFjdG9yIjoxLCJzY29wZXMiOlsicm9vbTp3cml0ZSJdLCJpZCI6InVzZXItMyIsIm1heENvbm5lY3Rpb25zUGVyUm9vbSI6MjB9.QoRc9dJJp-C1LzmQ-S_scHfFsAZ7dBcqep0bUZNyWxEWz_VeBHBBNdJpNs7b7RYRFDBi7RxkywKJlO-gNE8h3wkhebgLQVeSgI3YfTJo7J8Jzj38TzH85ZIbybaiGcxda_sYn3VohDtUHA1k67ns08Q2orJBNr30Gc88jJmc1He_7bLStsDP4M2F1NRMuFuqLULWHnPeEM7jMvLZYkbu3SBeCH4TQGyweu7qAXvP-HHtmvzOi8LdEnpxgxGjxefdu6m4a-fJj6LwoYCGi1rlLDHH9aOHFwYVrBBBVwoeIDSHoAonkPaae9AWM6igJhNt9-ihgEH6sF-qgFiPxHNXdg", + }); }), - rest.post("/api/auth-fail", (_req, res, ctx) => { - return res(ctx.status(400)); + http.post("/api/auth-fail", () => { + return new HttpResponse(null, { status: 400 }); }) ); diff --git a/packages/liveblocks-zustand/vitest.config.ts b/packages/liveblocks-zustand/vitest.config.ts new file mode 100644 index 00000000000..40d487e4690 --- /dev/null +++ b/packages/liveblocks-zustand/vitest.config.ts @@ -0,0 +1,7 @@ +import { defaultLiveblocksVitestConfig } from "@liveblocks/vitest-config"; + +export default defaultLiveblocksVitestConfig({ + test: { + environment: "jsdom", + }, +}); \ No newline at end of file diff --git a/shared/eslint-config/restricted-syntax.js b/shared/eslint-config/restricted-syntax.js index ee547fecff6..d9ea7a2580f 100644 --- a/shared/eslint-config/restricted-syntax.js +++ b/shared/eslint-config/restricted-syntax.js @@ -15,4 +15,10 @@ module.exports = [ message: "useLayoutEffect triggers a warning when executed on the server on React <=18.2.0. Import it from '@liveblocks/react/_private' instead.", }, + { + selector: + "ImportDeclaration[source.value='vitest'] ImportSpecifier[imported.name='it']", + message: + "Import 'test' instead of 'it' from vitest.", + }, ]; diff --git a/shared/vitest-config/index.js b/shared/vitest-config/index.js index a7b0730d010..c1dbbc91a16 100644 --- a/shared/vitest-config/index.js +++ b/shared/vitest-config/index.js @@ -1,11 +1,25 @@ -import { defineConfig } from "vitest/config"; +import { configDefaults, defineConfig } from "vitest/config"; +import path from "path"; +import { fileURLToPath } from "url"; import tsconfigPaths from "vite-tsconfig-paths"; -export function defaultLiveblocksVitestConfig(_options) { +const __dirname = path.dirname(fileURLToPath(import.meta.url)); + +export function defaultLiveblocksVitestConfig(options = {}) { return defineConfig({ plugins: [tsconfigPaths()], test: { + setupFiles: [path.join(__dirname, "setup.js")], + + // Gotcha! One key difference between Jest (our old test runner) and Vitest + // is that Vitest does not automatically mock the `performance.now()` method. + // Some of our tests rely on this behavior though. + // See https://github.com/vitest-dev/vitest/issues/4004 + fakeTimers: { + toFake: [...configDefaults.fakeTimers.toFake, "performance"], + }, + coverage: { provider: "istanbul", reporter: ["text", "html"], @@ -19,6 +33,7 @@ export function defaultLiveblocksVitestConfig(_options) { // branches: 100, }, }, + ...options.test, }, }); } diff --git a/shared/vitest-config/package-lock.json b/shared/vitest-config/package-lock.json new file mode 100644 index 00000000000..03bf9d0c6dc --- /dev/null +++ b/shared/vitest-config/package-lock.json @@ -0,0 +1,3847 @@ +{ + "name": "@liveblocks/vitest-config", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "@liveblocks/vitest-config", + "version": "1.0.0", + "dependencies": { + "@vitest/coverage-istanbul": "^2.1.9", + "fast-check": "^3.19.0", + "jsdom": "^25.0.1", + "vite-tsconfig-paths": "^5.1.4", + "vitest": "^2.1.9", + "whatwg-fetch": "^3.6.20" + } + }, + "node_modules/@ampproject/remapping": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", + "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", + "license": "Apache-2.0", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@asamuzakjp/css-color": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@asamuzakjp/css-color/-/css-color-3.2.0.tgz", + "integrity": "sha512-K1A6z8tS3XsmCMM86xoWdn7Fkdn9m6RSVtocUrJYIwZnFVkng/PvkEoWtOWmP+Scc6saYWHWZYbndEEXxl24jw==", + "license": "MIT", + "dependencies": { + "@csstools/css-calc": "^2.1.3", + "@csstools/css-color-parser": "^3.0.9", + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3", + "lru-cache": "^10.4.3" + } + }, + "node_modules/@asamuzakjp/css-color/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "license": "ISC" + }, + "node_modules/@babel/code-frame": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", + "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.27.1", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.0.tgz", + "integrity": "sha512-60X7qkglvrap8mn1lh2ebxXdZYtUcpd7gsmy9kLaBJ4i/WdY8PqTSdxyA8qraikqKQK5C1KRBKXqznrVapyNaw==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.0.tgz", + "integrity": "sha512-UlLAnTPrFdNGoFtbSXwcGFQBtQZJCNjaN6hQNP3UPvuNXT1i82N26KL3dZeIpNalWywr9IuQuncaAfUaS1g6sQ==", + "license": "MIT", + "dependencies": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.28.0", + "@babel/helper-compilation-targets": "^7.27.2", + "@babel/helper-module-transforms": "^7.27.3", + "@babel/helpers": "^7.27.6", + "@babel/parser": "^7.28.0", + "@babel/template": "^7.27.2", + "@babel/traverse": "^7.28.0", + "@babel/types": "^7.28.0", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/core/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/generator": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.0.tgz", + "integrity": "sha512-lJjzvrbEeWrhB4P3QBsH7tey117PjLZnDbLiQEKjQ/fNJTjuq4HSqgFA+UNSwZT8D7dxxbnuSBMsa1lrWzKlQg==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.28.0", + "@babel/types": "^7.28.0", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz", + "integrity": "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==", + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.27.2", + "@babel/helper-validator-option": "^7.27.1", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-globals": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", + "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz", + "integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==", + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.27.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.27.3.tgz", + "integrity": "sha512-dSOvYwvyLsWBeIRyOeHXp5vPj5l1I011r52FM1+r1jCERv+aFXYk4whgQccYEGYxK2H3ZAIA8nuPkQ0HaUo3qg==", + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1", + "@babel/traverse": "^7.27.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz", + "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", + "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.28.2", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.2.tgz", + "integrity": "sha512-/V9771t+EgXz62aCcyofnQhGM8DQACbRhvzKFsXKC9QM+5MadF8ZmIm0crDMaz3+o0h0zXfJnd4EhbYbxsrcFw==", + "license": "MIT", + "dependencies": { + "@babel/template": "^7.27.2", + "@babel/types": "^7.28.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.0.tgz", + "integrity": "sha512-jVZGvOxOuNSsuQuLRTh13nU0AogFlw32w/MT+LV6D3sP5WdbW61E77RnkbaO2dUvmPAYrBDJXGn5gGS6tH4j8g==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.0" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/template": { + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", + "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/parser": "^7.27.2", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.0.tgz", + "integrity": "sha512-mGe7UK5wWyh0bKRfupsUchrQGqvDbZDbKJw+kcRGSmdHVYrv+ltd0pnpDTVpiTqnaBru9iEvA8pz8W46v0Amwg==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.28.0", + "@babel/helper-globals": "^7.28.0", + "@babel/parser": "^7.28.0", + "@babel/template": "^7.27.2", + "@babel/types": "^7.28.0", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.28.2", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.2.tgz", + "integrity": "sha512-ruv7Ae4J5dUYULmeXw1gmb7rYRz57OWCPM57pHojnLq/3Z1CK2lNSLTCVjxVk1F/TZHwOZZrOWi0ur95BbLxNQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@bundled-es-modules/cookie": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@bundled-es-modules/cookie/-/cookie-2.0.1.tgz", + "integrity": "sha512-8o+5fRPLNbjbdGRRmJj3h6Hh1AQJf2dk3qQ/5ZFb+PXkRNiSoMGGUKlsgLfrxneb72axVJyIYji64E2+nNfYyw==", + "license": "ISC", + "optional": true, + "peer": true, + "dependencies": { + "cookie": "^0.7.2" + } + }, + "node_modules/@bundled-es-modules/statuses": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@bundled-es-modules/statuses/-/statuses-1.0.1.tgz", + "integrity": "sha512-yn7BklA5acgcBr+7w064fGV+SGIFySjCKpqjcWgBAIfrAkY+4GQTJJHQMeT3V/sgz23VTEVV8TtOmkvJAhFVfg==", + "license": "ISC", + "optional": true, + "peer": true, + "dependencies": { + "statuses": "^2.0.1" + } + }, + "node_modules/@bundled-es-modules/tough-cookie": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/@bundled-es-modules/tough-cookie/-/tough-cookie-0.1.6.tgz", + "integrity": "sha512-dvMHbL464C0zI+Yqxbz6kZ5TOEp7GLW+pry/RWndAR8MJQAXZ2rPmIs8tziTZjeIyhSNZgZbCePtfSbdWqStJw==", + "license": "ISC", + "optional": true, + "peer": true, + "dependencies": { + "@types/tough-cookie": "^4.0.5", + "tough-cookie": "^4.1.4" + } + }, + "node_modules/@bundled-es-modules/tough-cookie/node_modules/tough-cookie": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.4.tgz", + "integrity": "sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==", + "license": "BSD-3-Clause", + "optional": true, + "peer": true, + "dependencies": { + "psl": "^1.1.33", + "punycode": "^2.1.1", + "universalify": "^0.2.0", + "url-parse": "^1.5.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@csstools/color-helpers": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-5.0.2.tgz", + "integrity": "sha512-JqWH1vsgdGcw2RR6VliXXdA0/59LttzlU8UlRT/iUUsEeWfYq8I+K0yhihEUTTHLRm1EXvpsCx3083EU15ecsA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "engines": { + "node": ">=18" + } + }, + "node_modules/@csstools/css-calc": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@csstools/css-calc/-/css-calc-2.1.4.tgz", + "integrity": "sha512-3N8oaj+0juUw/1H3YwmDDJXCgTB1gKU6Hc/bB502u9zR0q2vd786XJH9QfrKIEgFlZmhZiq6epXl4rHqhzsIgQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4" + } + }, + "node_modules/@csstools/css-color-parser": { + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-3.0.10.tgz", + "integrity": "sha512-TiJ5Ajr6WRd1r8HSiwJvZBiJOqtH86aHpUjq5aEKWHiII2Qfjqd/HCWKPOW8EP4vcspXbHnXrwIDlu5savQipg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "dependencies": { + "@csstools/color-helpers": "^5.0.2", + "@csstools/css-calc": "^2.1.4" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4" + } + }, + "node_modules/@csstools/css-parser-algorithms": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-3.0.5.tgz", + "integrity": "sha512-DaDeUkXZKjdGhgYaHNJTV9pV7Y9B3b644jCLs9Upc3VeNGg6LWARAT6O+Q+/COo+2gg/bM5rhpMAtf70WqfBdQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@csstools/css-tokenizer": "^3.0.4" + } + }, + "node_modules/@csstools/css-tokenizer": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-3.0.4.tgz", + "integrity": "sha512-Vd/9EVDiu6PPJt9yAh6roZP6El1xHrdvIVGjyBsHR0RYwNHgL7FJPyIIW4fANJNG6FtyZfvlRPpFI4ZM/lubvw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", + "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", + "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", + "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", + "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", + "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", + "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", + "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", + "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", + "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", + "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", + "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", + "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", + "cpu": [ + "loong64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", + "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", + "cpu": [ + "mips64el" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", + "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", + "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", + "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", + "cpu": [ + "s390x" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", + "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", + "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", + "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", + "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", + "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", + "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", + "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@inquirer/confirm": { + "version": "5.1.14", + "resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-5.1.14.tgz", + "integrity": "sha512-5yR4IBfe0kXe59r1YCTG8WXkUbl7Z35HK87Sw+WUyGD8wNUx7JvY7laahzeytyE1oLn74bQnL7hstctQxisQ8Q==", + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "@inquirer/core": "^10.1.15", + "@inquirer/type": "^3.0.8" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/core": { + "version": "10.1.15", + "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-10.1.15.tgz", + "integrity": "sha512-8xrp836RZvKkpNbVvgWUlxjT4CraKk2q+I3Ksy+seI2zkcE+y6wNs1BVhgcv8VyImFecUhdQrYLdW32pAjwBdA==", + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "@inquirer/figures": "^1.0.13", + "@inquirer/type": "^3.0.8", + "ansi-escapes": "^4.3.2", + "cli-width": "^4.1.0", + "mute-stream": "^2.0.0", + "signal-exit": "^4.1.0", + "wrap-ansi": "^6.2.0", + "yoctocolors-cjs": "^2.1.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/figures": { + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-1.0.13.tgz", + "integrity": "sha512-lGPVU3yO9ZNqA7vTYz26jny41lE7yoQansmqdMLBEfqaGsmdg7V3W9mK9Pvb5IL4EVZ9GnSDGMO/cJXud5dMaw==", + "license": "MIT", + "optional": true, + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/@inquirer/type": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-3.0.8.tgz", + "integrity": "sha512-lg9Whz8onIHRthWaN1Q9EGLa/0LFJjyM8mEUbL1eTi6yMGvBf8gvyDLtxSXztQsxMvhxxNpJYrwa1YHdq+w4Jw==", + "license": "MIT", + "optional": true, + "peer": true, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "license": "ISC", + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/@istanbuljs/schema": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.12", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.12.tgz", + "integrity": "sha512-OuLGC46TjB5BbN1dH8JULVVZY4WTdkF7tV9Ys6wLL1rubZnCMstOhNHueU5bLCrnRuDhKPDM4g6sw4Bel5Gzqg==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.4.tgz", + "integrity": "sha512-VT2+G1VQs/9oz078bLrYbecdZKs912zQlkelYpuf+SXF+QvZDYJlbx/LSx+meSAwdDFnF8FVXW92AVjjkVmgFw==", + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.29", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.29.tgz", + "integrity": "sha512-uw6guiW/gcAGPDhLmd77/6lW8QLeiV5RUTsAX46Db6oLhGaVj4lhnPwb184s1bkc8kdVg/+h988dro8GRDpmYQ==", + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@mswjs/interceptors": { + "version": "0.37.6", + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "@open-draft/deferred-promise": "^2.2.0", + "@open-draft/logger": "^0.3.0", + "@open-draft/until": "^2.0.0", + "is-node-process": "^1.2.0", + "outvariant": "^1.4.3", + "strict-event-emitter": "^0.5.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@open-draft/deferred-promise": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@open-draft/deferred-promise/-/deferred-promise-2.2.0.tgz", + "integrity": "sha512-CecwLWx3rhxVQF6V4bAgPS5t+So2sTbPgAzafKkVizyi7tlwpcFpdFqq+wqF2OwNBmqFuu6tOyouTuxgpMfzmA==", + "license": "MIT", + "optional": true, + "peer": true + }, + "node_modules/@open-draft/logger": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@open-draft/logger/-/logger-0.3.0.tgz", + "integrity": "sha512-X2g45fzhxH238HKO4xbSr7+wBS8Fvw6ixhTDuvLd5mqh6bJJCFAPwU9mPDxbcrRtfxv4u5IHCEH77BmxvXmmxQ==", + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "is-node-process": "^1.2.0", + "outvariant": "^1.4.0" + } + }, + "node_modules/@open-draft/until": { + "version": "2.1.0", + "license": "MIT", + "optional": true, + "peer": true + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.46.2.tgz", + "integrity": "sha512-Zj3Hl6sN34xJtMv7Anwb5Gu01yujyE/cLBDB2gnHTAHaWS1Z38L7kuSG+oAh0giZMqG060f/YBStXtMH6FvPMA==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.46.2.tgz", + "integrity": "sha512-nTeCWY83kN64oQ5MGz3CgtPx8NSOhC5lWtsjTs+8JAJNLcP3QbLCtDDgUKQc/Ro/frpMq4SHUaHN6AMltcEoLQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.46.2.tgz", + "integrity": "sha512-HV7bW2Fb/F5KPdM/9bApunQh68YVDU8sO8BvcW9OngQVN3HHHkw99wFupuUJfGR9pYLLAjcAOA6iO+evsbBaPQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.46.2.tgz", + "integrity": "sha512-SSj8TlYV5nJixSsm/y3QXfhspSiLYP11zpfwp6G/YDXctf3Xkdnk4woJIF5VQe0of2OjzTt8EsxnJDCdHd2xMA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.46.2.tgz", + "integrity": "sha512-ZyrsG4TIT9xnOlLsSSi9w/X29tCbK1yegE49RYm3tu3wF1L/B6LVMqnEWyDB26d9Ecx9zrmXCiPmIabVuLmNSg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.46.2.tgz", + "integrity": "sha512-pCgHFoOECwVCJ5GFq8+gR8SBKnMO+xe5UEqbemxBpCKYQddRQMgomv1104RnLSg7nNvgKy05sLsY51+OVRyiVw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.46.2.tgz", + "integrity": "sha512-EtP8aquZ0xQg0ETFcxUbU71MZlHaw9MChwrQzatiE8U/bvi5uv/oChExXC4mWhjiqK7azGJBqU0tt5H123SzVA==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.46.2.tgz", + "integrity": "sha512-qO7F7U3u1nfxYRPM8HqFtLd+raev2K137dsV08q/LRKRLEc7RsiDWihUnrINdsWQxPR9jqZ8DIIZ1zJJAm5PjQ==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.46.2.tgz", + "integrity": "sha512-3dRaqLfcOXYsfvw5xMrxAk9Lb1f395gkoBYzSFcc/scgRFptRXL9DOaDpMiehf9CO8ZDRJW2z45b6fpU5nwjng==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.46.2.tgz", + "integrity": "sha512-fhHFTutA7SM+IrR6lIfiHskxmpmPTJUXpWIsBXpeEwNgZzZZSg/q4i6FU4J8qOGyJ0TR+wXBwx/L7Ho9z0+uDg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loongarch64-gnu": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.46.2.tgz", + "integrity": "sha512-i7wfGFXu8x4+FRqPymzjD+Hyav8l95UIZ773j7J7zRYc3Xsxy2wIn4x+llpunexXe6laaO72iEjeeGyUFmjKeA==", + "cpu": [ + "loong64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.46.2.tgz", + "integrity": "sha512-B/l0dFcHVUnqcGZWKcWBSV2PF01YUt0Rvlurci5P+neqY/yMKchGU8ullZvIv5e8Y1C6wOn+U03mrDylP5q9Yw==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.46.2.tgz", + "integrity": "sha512-32k4ENb5ygtkMwPMucAb8MtV8olkPT03oiTxJbgkJa7lJ7dZMr0GCFJlyvy+K8iq7F/iuOr41ZdUHaOiqyR3iQ==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.46.2.tgz", + "integrity": "sha512-t5B2loThlFEauloaQkZg9gxV05BYeITLvLkWOkRXogP4qHXLkWSbSHKM9S6H1schf/0YGP/qNKtiISlxvfmmZw==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.46.2.tgz", + "integrity": "sha512-YKjekwTEKgbB7n17gmODSmJVUIvj8CX7q5442/CK80L8nqOUbMtf8b01QkG3jOqyr1rotrAnW6B/qiHwfcuWQA==", + "cpu": [ + "s390x" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.46.2.tgz", + "integrity": "sha512-Jj5a9RUoe5ra+MEyERkDKLwTXVu6s3aACP51nkfnK9wJTraCC8IMe3snOfALkrjTYd2G1ViE1hICj0fZ7ALBPA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.46.2.tgz", + "integrity": "sha512-7kX69DIrBeD7yNp4A5b81izs8BqoZkCIaxQaOpumcJ1S/kmqNFjPhDu1LHeVXv0SexfHQv5cqHsxLOjETuqDuA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.46.2.tgz", + "integrity": "sha512-wiJWMIpeaak/jsbaq2HMh/rzZxHVW1rU6coyeNNpMwk5isiPjSTx0a4YLSlYDwBH/WBvLz+EtsNqQScZTLJy3g==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.46.2.tgz", + "integrity": "sha512-gBgaUDESVzMgWZhcyjfs9QFK16D8K6QZpwAaVNJxYDLHWayOta4ZMjGm/vsAEy3hvlS2GosVFlBlP9/Wb85DqQ==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.46.2.tgz", + "integrity": "sha512-CvUo2ixeIQGtF6WvuB87XWqPQkoFAFqW+HUo/WzHwuHDvIwZCtjdWXoYCcr06iKGydiqTclC4jU/TNObC/xKZg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@types/cookie": { + "version": "0.6.0", + "license": "MIT", + "optional": true, + "peer": true + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "license": "MIT" + }, + "node_modules/@types/statuses": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@types/statuses/-/statuses-2.0.6.tgz", + "integrity": "sha512-xMAgYwceFhRA2zY+XbEA7mxYbA093wdiW8Vu6gZPGWy9cmOyU9XesH1tNcEWsKFd5Vzrqx5T3D38PWx1FIIXkA==", + "license": "MIT", + "optional": true, + "peer": true + }, + "node_modules/@types/tough-cookie": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.5.tgz", + "integrity": "sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==", + "license": "MIT", + "optional": true, + "peer": true + }, + "node_modules/@vitest/coverage-istanbul": { + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/@vitest/coverage-istanbul/-/coverage-istanbul-2.1.9.tgz", + "integrity": "sha512-vdYE4FkC/y2lxcN3Dcj54Bw+ericmDwiex0B8LV5F/YNYEYP1mgVwhPnHwWGAXu38qizkjOuyczKbFTALfzFKw==", + "license": "MIT", + "dependencies": { + "@istanbuljs/schema": "^0.1.3", + "debug": "^4.3.7", + "istanbul-lib-coverage": "^3.2.2", + "istanbul-lib-instrument": "^6.0.3", + "istanbul-lib-report": "^3.0.1", + "istanbul-lib-source-maps": "^5.0.6", + "istanbul-reports": "^3.1.7", + "magicast": "^0.3.5", + "test-exclude": "^7.0.1", + "tinyrainbow": "^1.2.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "vitest": "2.1.9" + } + }, + "node_modules/@vitest/expect": { + "version": "2.1.9", + "license": "MIT", + "dependencies": { + "@vitest/spy": "2.1.9", + "@vitest/utils": "2.1.9", + "chai": "^5.1.2", + "tinyrainbow": "^1.2.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/mocker": { + "version": "2.1.9", + "license": "MIT", + "dependencies": { + "@vitest/spy": "2.1.9", + "estree-walker": "^3.0.3", + "magic-string": "^0.30.12" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "msw": "^2.4.9", + "vite": "^5.0.0" + }, + "peerDependenciesMeta": { + "msw": { + "optional": true + }, + "vite": { + "optional": true + } + } + }, + "node_modules/@vitest/pretty-format": { + "version": "2.1.9", + "license": "MIT", + "dependencies": { + "tinyrainbow": "^1.2.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/runner": { + "version": "2.1.9", + "license": "MIT", + "dependencies": { + "@vitest/utils": "2.1.9", + "pathe": "^1.1.2" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/snapshot": { + "version": "2.1.9", + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "2.1.9", + "magic-string": "^0.30.12", + "pathe": "^1.1.2" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/spy": { + "version": "2.1.9", + "license": "MIT", + "dependencies": { + "tinyspy": "^3.0.2" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/utils": { + "version": "2.1.9", + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "2.1.9", + "loupe": "^3.1.2", + "tinyrainbow": "^1.2.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/agent-base": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, + "node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-escapes/node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "license": "(MIT OR CC0-1.0)", + "optional": true, + "peer": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-regex": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/assertion-error": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", + "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "license": "MIT" + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "license": "MIT" + }, + "node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/browserslist": { + "version": "4.25.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.25.1.tgz", + "integrity": "sha512-KGj0KoOMXLpSNkkEI6Z6mShmQy0bc1I+T7K9N81k4WWMrfz+6fQ6es80B/YLAeRoKvjYE1YSHHOW1qe9xIVzHw==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "caniuse-lite": "^1.0.30001726", + "electron-to-chromium": "^1.5.173", + "node-releases": "^2.0.19", + "update-browserslist-db": "^1.1.3" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/cac": { + "version": "6.7.14", + "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", + "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001731", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001731.tgz", + "integrity": "sha512-lDdp2/wrOmTRWuoB5DpfNkC0rJDU8DqRa6nYL6HK6sytw70QMopt/NIc/9SM7ylItlBWfACXk0tEn37UWM/+mg==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/chai": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/chai/-/chai-5.2.1.tgz", + "integrity": "sha512-5nFxhUrX0PqtyogoYOA8IPswy5sZFTOsBFl/9bNsmDLgsxYTzSZQJDPppDnZPTQbzSEm0hqGjWPzRemQCYbD6A==", + "license": "MIT", + "dependencies": { + "assertion-error": "^2.0.1", + "check-error": "^2.1.1", + "deep-eql": "^5.0.1", + "loupe": "^3.1.0", + "pathval": "^2.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/check-error": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-2.1.1.tgz", + "integrity": "sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==", + "license": "MIT", + "engines": { + "node": ">= 16" + } + }, + "node_modules/cli-width": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-4.1.0.tgz", + "integrity": "sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==", + "license": "ISC", + "optional": true, + "peer": true, + "engines": { + "node": ">= 12" + } + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "license": "ISC", + "optional": true, + "peer": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/cliui/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "optional": true, + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT", + "optional": true, + "peer": true + }, + "node_modules/cliui/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "license": "MIT" + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "license": "MIT" + }, + "node_modules/cookie": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", + "license": "MIT", + "optional": true, + "peer": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/cssstyle": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-4.6.0.tgz", + "integrity": "sha512-2z+rWdzbbSZv6/rhtvzvqeZQHrBaqgogqt85sqFNbabZOuFbCVFb8kPeEtZjiKkbrm395irpNKiYeFeLiQnFPg==", + "license": "MIT", + "dependencies": { + "@asamuzakjp/css-color": "^3.2.0", + "rrweb-cssom": "^0.8.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/cssstyle/node_modules/rrweb-cssom": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.8.0.tgz", + "integrity": "sha512-guoltQEx+9aMf2gDZ0s62EcV8lsXR+0w8915TC3ITdn2YueuNjdAYh/levpU9nFaoChh9RUS5ZdQMrKfVEN9tw==", + "license": "MIT" + }, + "node_modules/data-urls": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-5.0.0.tgz", + "integrity": "sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==", + "license": "MIT", + "dependencies": { + "whatwg-mimetype": "^4.0.0", + "whatwg-url": "^14.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/debug": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", + "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decimal.js": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.6.0.tgz", + "integrity": "sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==", + "license": "MIT" + }, + "node_modules/deep-eql": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-5.0.2.tgz", + "integrity": "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "license": "MIT" + }, + "node_modules/electron-to-chromium": { + "version": "1.5.198", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.198.tgz", + "integrity": "sha512-G5COfnp3w+ydVu80yprgWSfmfQaYRh9DOxfhAxstLyetKaLyl55QrNjx8C38Pc/C+RaDmb1M0Lk8wPEMQ+bGgQ==", + "license": "ISC" + }, + "node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "license": "MIT" + }, + "node_modules/entities": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", + "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-module-lexer": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz", + "integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==", + "license": "MIT" + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/esbuild": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", + "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.21.5", + "@esbuild/android-arm": "0.21.5", + "@esbuild/android-arm64": "0.21.5", + "@esbuild/android-x64": "0.21.5", + "@esbuild/darwin-arm64": "0.21.5", + "@esbuild/darwin-x64": "0.21.5", + "@esbuild/freebsd-arm64": "0.21.5", + "@esbuild/freebsd-x64": "0.21.5", + "@esbuild/linux-arm": "0.21.5", + "@esbuild/linux-arm64": "0.21.5", + "@esbuild/linux-ia32": "0.21.5", + "@esbuild/linux-loong64": "0.21.5", + "@esbuild/linux-mips64el": "0.21.5", + "@esbuild/linux-ppc64": "0.21.5", + "@esbuild/linux-riscv64": "0.21.5", + "@esbuild/linux-s390x": "0.21.5", + "@esbuild/linux-x64": "0.21.5", + "@esbuild/netbsd-x64": "0.21.5", + "@esbuild/openbsd-x64": "0.21.5", + "@esbuild/sunos-x64": "0.21.5", + "@esbuild/win32-arm64": "0.21.5", + "@esbuild/win32-ia32": "0.21.5", + "@esbuild/win32-x64": "0.21.5" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/estree-walker": { + "version": "3.0.3", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + } + }, + "node_modules/expect-type": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.2.2.tgz", + "integrity": "sha512-JhFGDVJ7tmDJItKhYgJCGLOWjuK9vPxiXoUFLwLDc99NlmklilbiQJwoctZtt13+xMw91MCk/REan6MWHqDjyA==", + "license": "Apache-2.0", + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/fast-check": { + "version": "3.23.2", + "resolved": "https://registry.npmjs.org/fast-check/-/fast-check-3.23.2.tgz", + "integrity": "sha512-h5+1OzzfCC3Ef7VbtKdcv7zsstUQwUDlYpUTvjeUsJAssPgLn7QzbboPtL5ro04Mq0rPOsMzl7q5hIbRs2wD1A==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + ], + "license": "MIT", + "dependencies": { + "pure-rand": "^6.1.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/foreground-child": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", + "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", + "license": "ISC", + "dependencies": { + "cross-spawn": "^7.0.6", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/form-data": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.4.tgz", + "integrity": "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==", + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.2", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "license": "ISC", + "optional": true, + "peer": true, + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/glob": { + "version": "10.4.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", + "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/globrex": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/globrex/-/globrex-0.1.2.tgz", + "integrity": "sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==", + "license": "MIT" + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graphql": { + "version": "16.11.0", + "resolved": "https://registry.npmjs.org/graphql/-/graphql-16.11.0.tgz", + "integrity": "sha512-mS1lbMsxgQj6hge1XZ6p7GPhbrtFwUFYi3wRzXAC/FmYnyXMTvvI3td3rjmQ2u8ewXueaSvRPWaEcgVVOT9Jnw==", + "license": "MIT", + "optional": true, + "peer": true, + "engines": { + "node": "^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/headers-polyfill": { + "version": "4.0.3", + "license": "MIT", + "optional": true, + "peer": true + }, + "node_modules/html-encoding-sniffer": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-4.0.0.tgz", + "integrity": "sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==", + "license": "MIT", + "dependencies": { + "whatwg-encoding": "^3.1.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "license": "MIT" + }, + "node_modules/http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/https-proxy-agent": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-node-process": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/is-node-process/-/is-node-process-1.2.0.tgz", + "integrity": "sha512-Vg4o6/fqPxIjtxgUH5QLJhwZ7gW5diGCVlXpuUfELC62CuxM1iHcRe51f2W1FDy04Ai4KJkagKjx3XaqyfRKXw==", + "license": "MIT", + "optional": true, + "peer": true + }, + "node_modules/is-potential-custom-element-name": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", + "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", + "license": "MIT" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "license": "ISC" + }, + "node_modules/istanbul-lib-coverage": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", + "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-instrument": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz", + "integrity": "sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==", + "license": "BSD-3-Clause", + "dependencies": { + "@babel/core": "^7.23.9", + "@babel/parser": "^7.23.9", + "@istanbuljs/schema": "^0.1.3", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^7.5.4" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-report": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", + "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", + "license": "BSD-3-Clause", + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^4.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-source-maps": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-5.0.6.tgz", + "integrity": "sha512-yg2d+Em4KizZC5niWhQaIomgf5WlL4vOOjZ5xGCmF8SnPE/mDWWXgvRExdcpCgh9lLRRa1/fSYp2ymmbJ1pI+A==", + "license": "BSD-3-Clause", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.23", + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-reports": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.7.tgz", + "integrity": "sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==", + "license": "BSD-3-Clause", + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "license": "MIT" + }, + "node_modules/jsdom": { + "version": "25.0.1", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-25.0.1.tgz", + "integrity": "sha512-8i7LzZj7BF8uplX+ZyOlIz86V6TAsSs+np6m1kpW9u0JWi4z/1t+FzcK1aek+ybTnAC4KhBL4uXCNT0wcUIeCw==", + "license": "MIT", + "dependencies": { + "cssstyle": "^4.1.0", + "data-urls": "^5.0.0", + "decimal.js": "^10.4.3", + "form-data": "^4.0.0", + "html-encoding-sniffer": "^4.0.0", + "http-proxy-agent": "^7.0.2", + "https-proxy-agent": "^7.0.5", + "is-potential-custom-element-name": "^1.0.1", + "nwsapi": "^2.2.12", + "parse5": "^7.1.2", + "rrweb-cssom": "^0.7.1", + "saxes": "^6.0.0", + "symbol-tree": "^3.2.4", + "tough-cookie": "^5.0.0", + "w3c-xmlserializer": "^5.0.0", + "webidl-conversions": "^7.0.0", + "whatwg-encoding": "^3.1.1", + "whatwg-mimetype": "^4.0.0", + "whatwg-url": "^14.0.0", + "ws": "^8.18.0", + "xml-name-validator": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "canvas": "^2.11.2" + }, + "peerDependenciesMeta": { + "canvas": { + "optional": true + } + } + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/loupe": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.2.0.tgz", + "integrity": "sha512-2NCfZcT5VGVNX9mSZIxLRkEAegDGBpuQZBy13desuHeVORmBDyAET4TkJr4SjqQy3A8JDofMN6LpkK8Xcm/dlw==", + "license": "MIT" + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/magic-string": { + "version": "0.30.17", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz", + "integrity": "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0" + } + }, + "node_modules/magicast": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/magicast/-/magicast-0.3.5.tgz", + "integrity": "sha512-L0WhttDl+2BOsybvEOLK7fW3UA0OQ0IQ2d6Zl2x/a6vVRs3bAY0ECOSHHeL5jD+SbOpOCUEi0y1DgHEn9Qn1AQ==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.25.4", + "@babel/types": "^7.25.4", + "source-map-js": "^1.2.0" + } + }, + "node_modules/make-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", + "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", + "license": "MIT", + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "license": "ISC", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/msw": { + "version": "2.7.3", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "@bundled-es-modules/cookie": "^2.0.1", + "@bundled-es-modules/statuses": "^1.0.1", + "@bundled-es-modules/tough-cookie": "^0.1.6", + "@inquirer/confirm": "^5.0.0", + "@mswjs/interceptors": "^0.37.0", + "@open-draft/deferred-promise": "^2.2.0", + "@open-draft/until": "^2.1.0", + "@types/cookie": "^0.6.0", + "@types/statuses": "^2.0.4", + "graphql": "^16.8.1", + "headers-polyfill": "^4.0.2", + "is-node-process": "^1.2.0", + "outvariant": "^1.4.3", + "path-to-regexp": "^6.3.0", + "picocolors": "^1.1.1", + "strict-event-emitter": "^0.5.1", + "type-fest": "^4.26.1", + "yargs": "^17.7.2" + }, + "bin": { + "msw": "cli/index.js" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/mswjs" + }, + "peerDependencies": { + "typescript": ">= 4.8.x" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/mute-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-2.0.0.tgz", + "integrity": "sha512-WWdIxpyjEn+FhQJQQv9aQAYlHoNVdzIzUySNV1gHUPDSdZJ3yZn7pAAbQcV7B56Mvu881q9FZV+0Vx2xC44VWA==", + "license": "ISC", + "optional": true, + "peer": true, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/node-releases": { + "version": "2.0.19", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz", + "integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==", + "license": "MIT" + }, + "node_modules/nwsapi": { + "version": "2.2.21", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.21.tgz", + "integrity": "sha512-o6nIY3qwiSXl7/LuOU0Dmuctd34Yay0yeuZRLFmDPrrdHpXKFndPj3hM+YEPVHYC5fx2otBx4Ilc/gyYSAUaIA==", + "license": "MIT" + }, + "node_modules/outvariant": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/outvariant/-/outvariant-1.4.3.tgz", + "integrity": "sha512-+Sl2UErvtsoajRDKCE5/dBz4DIvHXQQnAxtQTF04OJxY0+DyZXSo5P5Bb7XYWOh81syohlYL24hbDwxedPUJCA==", + "license": "MIT", + "optional": true, + "peer": true + }, + "node_modules/package-json-from-dist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "license": "BlueOak-1.0.0" + }, + "node_modules/parse5": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz", + "integrity": "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==", + "license": "MIT", + "dependencies": { + "entities": "^6.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-scurry/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "license": "ISC" + }, + "node_modules/path-to-regexp": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.3.0.tgz", + "integrity": "sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==", + "license": "MIT", + "optional": true, + "peer": true + }, + "node_modules/pathe": { + "version": "1.1.2", + "license": "MIT" + }, + "node_modules/pathval": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-2.0.1.tgz", + "integrity": "sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==", + "license": "MIT", + "engines": { + "node": ">= 14.16" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "license": "ISC" + }, + "node_modules/postcss": { + "version": "8.5.6", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", + "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/psl": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.15.0.tgz", + "integrity": "sha512-JZd3gMVBAVQkSs6HdNZo9Sdo0LNcQeMNP3CozBJb3JYC/QUYZTnKxP+f8oWRX4rHP5EurWxqAHTSwUCjlNKa1w==", + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "punycode": "^2.3.1" + }, + "funding": { + "url": "https://github.com/sponsors/lupomontero" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/pure-rand": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.1.0.tgz", + "integrity": "sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + ], + "license": "MIT" + }, + "node_modules/querystringify": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", + "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", + "license": "MIT", + "optional": true, + "peer": true + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "license": "MIT", + "optional": true, + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", + "license": "MIT", + "optional": true, + "peer": true + }, + "node_modules/rollup": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.46.2.tgz", + "integrity": "sha512-WMmLFI+Boh6xbop+OAGo9cQ3OgX9MIg7xOQjn+pTCwOkk+FNDAeAemXkJ3HzDJrVXleLOFVa1ipuc1AmEx1Dwg==", + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.8" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.46.2", + "@rollup/rollup-android-arm64": "4.46.2", + "@rollup/rollup-darwin-arm64": "4.46.2", + "@rollup/rollup-darwin-x64": "4.46.2", + "@rollup/rollup-freebsd-arm64": "4.46.2", + "@rollup/rollup-freebsd-x64": "4.46.2", + "@rollup/rollup-linux-arm-gnueabihf": "4.46.2", + "@rollup/rollup-linux-arm-musleabihf": "4.46.2", + "@rollup/rollup-linux-arm64-gnu": "4.46.2", + "@rollup/rollup-linux-arm64-musl": "4.46.2", + "@rollup/rollup-linux-loongarch64-gnu": "4.46.2", + "@rollup/rollup-linux-ppc64-gnu": "4.46.2", + "@rollup/rollup-linux-riscv64-gnu": "4.46.2", + "@rollup/rollup-linux-riscv64-musl": "4.46.2", + "@rollup/rollup-linux-s390x-gnu": "4.46.2", + "@rollup/rollup-linux-x64-gnu": "4.46.2", + "@rollup/rollup-linux-x64-musl": "4.46.2", + "@rollup/rollup-win32-arm64-msvc": "4.46.2", + "@rollup/rollup-win32-ia32-msvc": "4.46.2", + "@rollup/rollup-win32-x64-msvc": "4.46.2", + "fsevents": "~2.3.2" + } + }, + "node_modules/rrweb-cssom": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.7.1.tgz", + "integrity": "sha512-TrEMa7JGdVm0UThDJSx7ddw5nVm3UJS9o9CCIZ72B1vSyEZoziDqBYP3XIoi/12lKrJR8rE3jeFHMok2F/Mnsg==", + "license": "MIT" + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT" + }, + "node_modules/saxes": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", + "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==", + "license": "ISC", + "dependencies": { + "xmlchars": "^2.2.0" + }, + "engines": { + "node": ">=v12.22.7" + } + }, + "node_modules/semver": { + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/siginfo": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", + "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", + "license": "ISC" + }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/stackback": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", + "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", + "license": "MIT" + }, + "node_modules/statuses": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", + "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", + "license": "MIT", + "optional": true, + "peer": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/std-env": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.9.0.tgz", + "integrity": "sha512-UGvjygr6F6tpH7o2qyqR6QYpwraIjKSdtzyBdyytFOHmPZY917kwdwLG0RbOjWOnKmnm3PeHjaoLLMie7kPLQw==", + "license": "MIT" + }, + "node_modules/strict-event-emitter": { + "version": "0.5.1", + "license": "MIT", + "optional": true, + "peer": true + }, + "node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, + "node_modules/string-width-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/symbol-tree": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", + "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", + "license": "MIT" + }, + "node_modules/test-exclude": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-7.0.1.tgz", + "integrity": "sha512-pFYqmTw68LXVjeWJMST4+borgQP2AyMNbg1BpZh9LbyhUeNkeaPF9gzfPGUAnSMV3qPYdWUwDIjjCLiSDOl7vg==", + "license": "ISC", + "dependencies": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^10.4.1", + "minimatch": "^9.0.4" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/tinybench": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", + "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", + "license": "MIT" + }, + "node_modules/tinyexec": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.2.tgz", + "integrity": "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==", + "license": "MIT" + }, + "node_modules/tinypool": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-1.1.1.tgz", + "integrity": "sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg==", + "license": "MIT", + "engines": { + "node": "^18.0.0 || >=20.0.0" + } + }, + "node_modules/tinyrainbow": { + "version": "1.2.0", + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tinyspy": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-3.0.2.tgz", + "integrity": "sha512-n1cw8k1k0x4pgA2+9XrOkFydTerNcJ1zWCO5Nn9scWHTD+5tp8dghT2x1uduQePZTZgd3Tupf+x9BxJjeJi77Q==", + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tldts": { + "version": "6.1.86", + "resolved": "https://registry.npmjs.org/tldts/-/tldts-6.1.86.tgz", + "integrity": "sha512-WMi/OQ2axVTf/ykqCQgXiIct+mSQDFdH2fkwhPwgEwvJ1kSzZRiinb0zF2Xb8u4+OqPChmyI6MEu4EezNJz+FQ==", + "license": "MIT", + "dependencies": { + "tldts-core": "^6.1.86" + }, + "bin": { + "tldts": "bin/cli.js" + } + }, + "node_modules/tldts-core": { + "version": "6.1.86", + "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-6.1.86.tgz", + "integrity": "sha512-Je6p7pkk+KMzMv2XXKmAE3McmolOQFdxkKw0R8EYNr7sELW46JqnNeTX8ybPiQgvg1ymCoF8LXs5fzFaZvJPTA==", + "license": "MIT" + }, + "node_modules/tough-cookie": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-5.1.2.tgz", + "integrity": "sha512-FVDYdxtnj0G6Qm/DhNPSb8Ju59ULcup3tuJxkFb5K8Bv2pUXILbf0xZWU8PX8Ov19OXljbUyveOFwRMwkXzO+A==", + "license": "BSD-3-Clause", + "dependencies": { + "tldts": "^6.1.32" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/tr46": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-5.1.1.tgz", + "integrity": "sha512-hdF5ZgjTqgAntKkklYw0R03MG2x/bSzTtkxmIRw/sTNV8YXsCJ1tfLAX23lhxhHJlEf3CRCOCGGWw3vI3GaSPw==", + "license": "MIT", + "dependencies": { + "punycode": "^2.3.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/tsconfck": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/tsconfck/-/tsconfck-3.1.6.tgz", + "integrity": "sha512-ks6Vjr/jEw0P1gmOVwutM3B7fWxoWBL2KRDb1JfqGVawBmO5UsvmWOQFGHBPl5yxYz4eERr19E6L7NMv+Fej4w==", + "license": "MIT", + "bin": { + "tsconfck": "bin/tsconfck.js" + }, + "engines": { + "node": "^18 || >=20" + }, + "peerDependencies": { + "typescript": "^5.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/type-fest": { + "version": "4.37.0", + "license": "(MIT OR CC0-1.0)", + "optional": true, + "peer": true, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/universalify": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", + "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", + "license": "MIT", + "optional": true, + "peer": true, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz", + "integrity": "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/url-parse": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", + "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "querystringify": "^2.1.1", + "requires-port": "^1.0.0" + } + }, + "node_modules/vite": { + "version": "5.4.19", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.19.tgz", + "integrity": "sha512-qO3aKv3HoQC8QKiNSTuUM1l9o/XX3+c+VTgLHbJWHZGeTPVAg2XwazI9UWzoxjIJCGCV2zU60uqMzjeLZuULqA==", + "license": "MIT", + "dependencies": { + "esbuild": "^0.21.3", + "postcss": "^8.4.43", + "rollup": "^4.20.0" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || >=20.0.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "sass-embedded": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + } + } + }, + "node_modules/vite-node": { + "version": "2.1.9", + "license": "MIT", + "dependencies": { + "cac": "^6.7.14", + "debug": "^4.3.7", + "es-module-lexer": "^1.5.4", + "pathe": "^1.1.2", + "vite": "^5.0.0" + }, + "bin": { + "vite-node": "vite-node.mjs" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/vite-tsconfig-paths": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/vite-tsconfig-paths/-/vite-tsconfig-paths-5.1.4.tgz", + "integrity": "sha512-cYj0LRuLV2c2sMqhqhGpaO3LretdtMn/BVX4cPLanIZuwwrkVl+lK84E/miEXkCHWXuq65rhNN4rXsBcOB3S4w==", + "license": "MIT", + "dependencies": { + "debug": "^4.1.1", + "globrex": "^0.1.2", + "tsconfck": "^3.0.3" + }, + "peerDependencies": { + "vite": "*" + }, + "peerDependenciesMeta": { + "vite": { + "optional": true + } + } + }, + "node_modules/vitest": { + "version": "2.1.9", + "license": "MIT", + "dependencies": { + "@vitest/expect": "2.1.9", + "@vitest/mocker": "2.1.9", + "@vitest/pretty-format": "^2.1.9", + "@vitest/runner": "2.1.9", + "@vitest/snapshot": "2.1.9", + "@vitest/spy": "2.1.9", + "@vitest/utils": "2.1.9", + "chai": "^5.1.2", + "debug": "^4.3.7", + "expect-type": "^1.1.0", + "magic-string": "^0.30.12", + "pathe": "^1.1.2", + "std-env": "^3.8.0", + "tinybench": "^2.9.0", + "tinyexec": "^0.3.1", + "tinypool": "^1.0.1", + "tinyrainbow": "^1.2.0", + "vite": "^5.0.0", + "vite-node": "2.1.9", + "why-is-node-running": "^2.3.0" + }, + "bin": { + "vitest": "vitest.mjs" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@edge-runtime/vm": "*", + "@types/node": "^18.0.0 || >=20.0.0", + "@vitest/browser": "2.1.9", + "@vitest/ui": "2.1.9", + "happy-dom": "*", + "jsdom": "*" + }, + "peerDependenciesMeta": { + "@edge-runtime/vm": { + "optional": true + }, + "@types/node": { + "optional": true + }, + "@vitest/browser": { + "optional": true + }, + "@vitest/ui": { + "optional": true + }, + "happy-dom": { + "optional": true + }, + "jsdom": { + "optional": true + } + } + }, + "node_modules/w3c-xmlserializer": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz", + "integrity": "sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==", + "license": "MIT", + "dependencies": { + "xml-name-validator": "^5.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + } + }, + "node_modules/whatwg-encoding": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz", + "integrity": "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==", + "license": "MIT", + "dependencies": { + "iconv-lite": "0.6.3" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/whatwg-fetch": { + "version": "3.6.20", + "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.6.20.tgz", + "integrity": "sha512-EqhiFU6daOA8kpjOWTL0olhVOF3i7OrFzSYiGsEMB8GcXS+RrzauAERX65xMeNWVqxA6HXH2m69Z9LaKKdisfg==", + "license": "MIT" + }, + "node_modules/whatwg-mimetype": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz", + "integrity": "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/whatwg-url": { + "version": "14.2.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.2.0.tgz", + "integrity": "sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw==", + "license": "MIT", + "dependencies": { + "tr46": "^5.1.0", + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/why-is-node-running": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", + "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", + "license": "MIT", + "dependencies": { + "siginfo": "^2.0.0", + "stackback": "0.0.2" + }, + "bin": { + "why-is-node-running": "cli.js" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, + "node_modules/wrap-ansi-cjs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "optional": true, + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT", + "optional": true, + "peer": true + }, + "node_modules/wrap-ansi/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ws": { + "version": "8.18.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz", + "integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/xml-name-validator": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-5.0.0.tgz", + "integrity": "sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==", + "license": "Apache-2.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/xmlchars": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", + "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", + "license": "MIT" + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "license": "ISC", + "optional": true, + "peer": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "license": "ISC" + }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "license": "ISC", + "optional": true, + "peer": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "optional": true, + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT", + "optional": true, + "peer": true + }, + "node_modules/yargs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yoctocolors-cjs": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yoctocolors-cjs/-/yoctocolors-cjs-2.1.2.tgz", + "integrity": "sha512-cYVsTjKl8b+FrnidjibDWskAv7UKOfcwaVZdp/it9n1s9fU3IkgDbhdIRKCW4JDsAlECJY0ytoVPT3sK6kideA==", + "license": "MIT", + "optional": true, + "peer": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/shared/vitest-config/package.json b/shared/vitest-config/package.json index 3875066672a..ec7bab726d3 100644 --- a/shared/vitest-config/package.json +++ b/shared/vitest-config/package.json @@ -7,9 +7,9 @@ ".": "./index.js" }, "dependencies": { - "@vitest/coverage-istanbul": "^3.0.7", "fast-check": "^3.19.0", + "jsdom": "^25.0.1", "vite-tsconfig-paths": "^5.1.4", - "vitest": "^2.1.9" + "whatwg-fetch": "^3.6.20" } } diff --git a/shared/vitest-config/setup.js b/shared/vitest-config/setup.js new file mode 100644 index 00000000000..ac30624c093 --- /dev/null +++ b/shared/vitest-config/setup.js @@ -0,0 +1,32 @@ +import "whatwg-fetch"; + +// Set up a base URL for tests since MSW tests use relative URLs +if (typeof global !== "undefined") { + global.location = { + origin: "http://dummy", + href: "http://dummy/", + hostname: "dummy", + protocol: "http:", + port: "", + pathname: "/", + search: "", + hash: "" + }; +} + +// Also set it up for window if in browser-like environment +if (typeof window !== "undefined") { + Object.defineProperty(window, "location", { + value: { + origin: "http://dummy", + href: "http://dummy/", + hostname: "dummy", + protocol: "http:", + port: "", + pathname: "/", + search: "", + hash: "" + }, + writable: true, + }); +} \ No newline at end of file