diff --git a/package-lock.json b/package-lock.json index bdfccbb6da..a9d921ca87 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2674,6 +2674,47 @@ "devOptional": true, "license": "MIT" }, + "node_modules/@bundled-es-modules/cookie": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@bundled-es-modules/cookie/-/cookie-2.0.0.tgz", + "integrity": "sha512-Or6YHg/kamKHpxULAdSqhGqnWFneIXu1NKvvfBBzKGwpVsYuFIQ5aBPHDnnoR3ghW1nvSkALd+EF9iMtY7Vjxw==", + "dev": true, + "license": "ISC", + "dependencies": { + "cookie": "^0.5.0" + } + }, + "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==", + "dev": true, + "license": "ISC", + "dependencies": { + "statuses": "^2.0.1" + } + }, + "node_modules/@bundled-es-modules/statuses/node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "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==", + "dev": true, + "license": "ISC", + "dependencies": { + "@types/tough-cookie": "^4.0.5", + "tough-cookie": "^4.1.4" + } + }, "node_modules/@changesets/apply-release-plan": { "version": "6.1.4", "dev": true, @@ -6923,6 +6964,161 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/@inquirer/confirm": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-3.2.0.tgz", + "integrity": "sha512-oOIwPs0Dvq5220Z8lGL/6LHRTEr9TgLHmiI99Rj1PJ1p1czTys+olrgBqZk4E2qC0YTzeHprxSQmoHioVdJ7Lw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/core": "^9.1.0", + "@inquirer/type": "^1.5.3" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@inquirer/core": { + "version": "9.2.1", + "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-9.2.1.tgz", + "integrity": "sha512-F2VBt7W/mwqEU4bL0RnHNZmC/OxzNx9cOYxHqnXX3MP6ruYvZUZAW9imgN9+h/uBT/oP8Gh888J2OZSbjSeWcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/figures": "^1.0.6", + "@inquirer/type": "^2.0.0", + "@types/mute-stream": "^0.0.4", + "@types/node": "^22.5.5", + "@types/wrap-ansi": "^3.0.0", + "ansi-escapes": "^4.3.2", + "cli-width": "^4.1.0", + "mute-stream": "^1.0.0", + "signal-exit": "^4.1.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^6.2.0", + "yoctocolors-cjs": "^2.1.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@inquirer/core/node_modules/@inquirer/type": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-2.0.0.tgz", + "integrity": "sha512-XvJRx+2KR3YXyYtPUUy+qd9i7p+GO9Ko6VIIpWlBrpWwXDv8WLFeHTxz35CfQFUiBMLXlGHhGzys7lqit9gWag==", + "dev": true, + "license": "MIT", + "dependencies": { + "mute-stream": "^1.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@inquirer/core/node_modules/@types/node": { + "version": "22.7.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.7.5.tgz", + "integrity": "sha512-jML7s2NAzMWc//QSJ1a3prpk78cOPchGvXJsC3C6R6PSMoooztvRVQEz89gmBTBY1SPMaqo5teB4uNHPdetShQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.19.2" + } + }, + "node_modules/@inquirer/core/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==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@inquirer/core/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==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@inquirer/core/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==", + "dev": true, + "license": "MIT" + }, + "node_modules/@inquirer/core/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==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@inquirer/core/node_modules/undici-types": { + "version": "6.19.8", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", + "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@inquirer/core/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/@inquirer/figures": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-1.0.7.tgz", + "integrity": "sha512-m+Trk77mp54Zma6xLkLuY+mvanPxlE4A7yNKs2HBiyZ4UkVs28Mv5c/pgWrHeInx+USHeX/WEPzjrWrcJiQgjw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/@inquirer/type": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-1.5.5.tgz", + "integrity": "sha512-MzICLu4yS7V8AA61sANROZ9vT1H3ooca5dSmI1FjZkzq7o/koMsRfQSzRtFo+F3Ao4Sf1C0bpLKejpKB/+j6MA==", + "dev": true, + "license": "MIT", + "dependencies": { + "mute-stream": "^1.0.0" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/@internationalized/date": { "version": "3.5.4", "license": "Apache-2.0", @@ -8654,6 +8850,24 @@ "node": ">=14.0" } }, + "node_modules/@mswjs/interceptors": { + "version": "0.35.9", + "resolved": "https://registry.npmjs.org/@mswjs/interceptors/-/interceptors-0.35.9.tgz", + "integrity": "sha512-SSnyl/4ni/2ViHKkiZb8eajA/eN1DNFaHjhGiLUdZvDz6PKF4COSf/17xqSz64nOo2Ia29SA6B2KNCsyCbVmaQ==", + "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" + } + }, "node_modules/@netlify/functions": { "version": "2.8.1", "dev": true, @@ -8943,6 +9157,31 @@ "@octokit/openapi-types": "^19.0.2" } }, + "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==", + "dev": true, + "license": "MIT" + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-node-process": "^1.2.0", + "outvariant": "^1.4.0" + } + }, + "node_modules/@open-draft/until": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@open-draft/until/-/until-2.1.0.tgz", + "integrity": "sha512-U69T3ItWHvLwGg5eJ0n3I62nWuE6ilHlmz7zM0npLBRvPRd7e6NYmg54vvRtP5mZG7kZqZCFVdsTWo7BPtBujg==", + "dev": true, + "license": "MIT" + }, "node_modules/@oslojs/encoding": { "version": "1.1.0", "license": "MIT", @@ -13956,6 +14195,16 @@ "license": "MIT", "peer": true }, + "node_modules/@types/mute-stream": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/@types/mute-stream/-/mute-stream-0.0.4.tgz", + "integrity": "sha512-CPM9nzrCPPJHQNA9keH9CVkVI+WR5kMa+7XEs5jcGQ0VoAGnLv242w8lIVgwAEfmE4oufJRaTc9PNLQl0ioAow==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/nlcst": { "version": "2.0.3", "license": "MIT", @@ -14105,6 +14354,13 @@ "devOptional": true, "license": "MIT" }, + "node_modules/@types/statuses": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@types/statuses/-/statuses-2.0.5.tgz", + "integrity": "sha512-jmIUGWrAiwu3dZpxntxieC+1n/5c3mjrImkmOSQ2NC5uP6cYO4aAZDdSmRcI5C1oiTmqlZGHC+/NmJrKogbP5A==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/superagent": { "version": "8.1.6", "dev": true, @@ -14137,7 +14393,9 @@ "license": "MIT" }, "node_modules/@types/tough-cookie": { - "version": "4.0.2", + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.5.tgz", + "integrity": "sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==", "dev": true, "license": "MIT" }, @@ -14169,6 +14427,13 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/wrap-ansi": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/wrap-ansi/-/wrap-ansi-3.0.0.tgz", + "integrity": "sha512-ltIpx+kM7g/MLRZfkbL7EsCEjfzCcScLpkg37eXEtx5kmrAKBkTJwd1GIAjDSL8wTpM6Hzn5YO4pSb91BEwu1g==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/ws": { "version": "8.5.4", "dev": true, @@ -19302,6 +19567,16 @@ "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, + "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==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">= 12" + } + }, "node_modules/client-only": { "version": "0.0.1", "license": "MIT" @@ -20094,6 +20369,16 @@ "node": "^12.20.0 || ^14.13.1 || >=16.0.0" } }, + "node_modules/cookie": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", + "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/cookie-es": { "version": "1.1.0", "dev": true, @@ -26680,6 +26965,13 @@ "he": "bin/he" } }, + "node_modules/headers-polyfill": { + "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" + }, "node_modules/hermes-estree": { "version": "0.15.0", "dev": true, @@ -28065,6 +28357,13 @@ "url": "https://github.com/sponsors/ljharb" } }, + "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==", + "dev": true, + "license": "MIT" + }, "node_modules/is-number": { "version": "7.0.0", "license": "MIT", @@ -33516,6 +33815,133 @@ "version": "2.1.2", "license": "MIT" }, + "node_modules/msw": { + "version": "2.4.9", + "resolved": "https://registry.npmjs.org/msw/-/msw-2.4.9.tgz", + "integrity": "sha512-1m8xccT6ipN4PTqLinPwmzhxQREuxaEJYdx4nIbggxP8aM7r1e71vE7RtOUSQoAm1LydjGfZKy7370XD/tsuYg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "@bundled-es-modules/cookie": "^2.0.0", + "@bundled-es-modules/statuses": "^1.0.1", + "@bundled-es-modules/tough-cookie": "^0.1.6", + "@inquirer/confirm": "^3.0.0", + "@mswjs/interceptors": "^0.35.8", + "@open-draft/until": "^2.1.0", + "@types/cookie": "^0.6.0", + "@types/statuses": "^2.0.4", + "chalk": "^4.1.2", + "graphql": "^16.8.1", + "headers-polyfill": "^4.0.2", + "is-node-process": "^1.2.0", + "outvariant": "^1.4.2", + "path-to-regexp": "^6.3.0", + "strict-event-emitter": "^0.5.1", + "type-fest": "^4.9.0", + "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/msw/node_modules/@types/cookie": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/msw/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==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/msw/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": { + "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/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==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/msw/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==", + "dev": true, + "license": "MIT" + }, + "node_modules/msw/node_modules/graphql": { + "version": "16.9.0", + "resolved": "https://registry.npmjs.org/graphql/-/graphql-16.9.0.tgz", + "integrity": "sha512-GGTKBX4SD7Wdb8mqeDLni2oaRGYQWjWHGKPQ24ZMnUtKfcsVoiv4uX8+LJr1K6U5VW2Lu1BwJnj7uiori0YtRw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0" + } + }, + "node_modules/msw/node_modules/type-fest": { + "version": "4.26.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.26.1.tgz", + "integrity": "sha512-yOGpmOAL7CkKe/91I5O3gPICmJNLJ1G4zFYVAsRHg7M64biSnPtRj0WNQt++bRkjYOqjWXrhnUw1utzmVErAdg==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/multicast-dns": { "version": "7.2.5", "dev": true, @@ -33536,6 +33962,16 @@ "mustache": "bin/mustache" } }, + "node_modules/mute-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-1.0.0.tgz", + "integrity": "sha512-avsJQhyd+680gKXyG/sQc0nXaC6rBkPOfyHYcFb9+hdkqQkR9bdnkJ0AMZhke0oesPqIO+mFFJ+IdBc7mst4IA==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, "node_modules/mv": { "version": "2.1.1", "dev": true, @@ -35028,6 +35464,13 @@ "dev": true, "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==", + "dev": true, + "license": "MIT" + }, "node_modules/p-event": { "version": "5.0.1", "dev": true, @@ -35377,7 +35820,9 @@ } }, "node_modules/path-to-regexp": { - "version": "6.2.2", + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.3.0.tgz", + "integrity": "sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==", "dev": true, "license": "MIT" }, @@ -38997,6 +39442,13 @@ "bare-events": "^2.2.0" } }, + "node_modules/strict-event-emitter": { + "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" + }, "node_modules/string_decoder": { "version": "1.1.1", "license": "MIT", @@ -44442,6 +44894,19 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "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==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/yoga-wasm-web": { "version": "0.3.3", "license": "MIT" @@ -44705,6 +45170,7 @@ "esbuild": "^0.24.0", "esbuild-register": "^3.6.0", "miniflare": "^2.14.3", + "msw": "2.4.9", "npm-run-all": "^4.1.5", "sinon": "^14.0.1", "tsup": "*", diff --git a/packages/backend/package.json b/packages/backend/package.json index 2dceacb18b..a198332fcf 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -111,6 +111,7 @@ "esbuild": "^0.24.0", "esbuild-register": "^3.6.0", "miniflare": "^2.14.3", + "msw": "2.4.9", "npm-run-all": "^4.1.5", "sinon": "^14.0.1", "tsup": "*", diff --git a/packages/backend/src/api/__tests__/factory.test.ts b/packages/backend/src/api/__tests__/factory.test.ts index 1e6f6bbf6d..126da371d1 100644 --- a/packages/backend/src/api/__tests__/factory.test.ts +++ b/packages/backend/src/api/__tests__/factory.test.ts @@ -1,10 +1,8 @@ -import sinon from 'sinon'; -import { afterEach, describe, expect, it } from 'vitest'; +import { http, HttpResponse } from 'msw'; +import { describe, expect, it } from 'vitest'; -// @ts-ignore import userJson from '../../fixtures/user.json'; -import runtime from '../../runtime'; -import { jsonError, jsonNotOk, jsonOk, jsonPaginatedOk } from '../../util/testUtils'; +import { server } from '../../mock-server'; import { createBackendApiClient } from '../factory'; describe('api.client', () => { @@ -13,15 +11,12 @@ describe('api.client', () => { secretKey: 'deadbeef', }); - let fakeFetch; - - afterEach(() => { - fakeFetch?.restore(); - }); - it('executes a successful backend API request for a single resource and parses the response', async () => { - fakeFetch = sinon.stub(runtime, 'fetch'); - fakeFetch.onCall(0).returns(jsonOk(userJson)); + server.use( + http.get(`https://api.clerk.test/v1/users/user_deadbeef`, () => { + return HttpResponse.json(userJson); + }), + ); const response = await apiClient.users.getUser('user_deadbeef'); @@ -31,23 +26,22 @@ describe('api.client', () => { expect(response.phoneNumbers[0].phoneNumber).toBe('+311-555-2368'); expect(response.externalAccounts[0].emailAddress).toBe('john.doe@clerk.test'); expect(response.publicMetadata.zodiac_sign).toBe('leo'); - - expect( - fakeFetch.calledOnceWith('https://api.clerk.test/v1/users/user_deadbeef', { - method: 'GET', - headers: { - Authorization: 'Bearer deadbeef', - 'Content-Type': 'application/json', - 'User-Agent': '@clerk/backend@0.0.0-test', - }, - }), - ).toBe(true); }); it('executes 2 backend API request for users.getUserList()', async () => { - fakeFetch = sinon.stub(runtime, 'fetch'); - fakeFetch.onCall(0).returns(jsonOk([userJson])); - fakeFetch.onCall(1).returns(jsonOk({ object: 'total_count', total_count: 2 })); + // fakeFetch.onCall(0).returns(jsonOk([userJson])); + // fakeFetch.onCall(1).returns(jsonOk({ object: 'total_count', total_count: 2 })); + server.use( + http.get(`https://api.clerk.test/v1/users`, () => { + return HttpResponse.json([userJson]); + }), + ); + server.use( + http.get(`https://api.clerk.test/v1/users/count`, () => { + return HttpResponse.json({ object: 'total_count', total_count: 2 }); + }), + ); + // const { data, totalCount } = await apiClient.users.getUserList({ const { data, totalCount } = await apiClient.users.getUserList({ offset: 2, @@ -60,31 +54,38 @@ describe('api.client', () => { expect(data.length).toBe(1); expect(totalCount).toBe(2); - expect( - fakeFetch.calledWith('https://api.clerk.test/v1/users?offset=2&limit=5&user_id=user_cafebabe', { - method: 'GET', - headers: { - Authorization: 'Bearer deadbeef', - 'Content-Type': 'application/json', - 'User-Agent': '@clerk/backend@0.0.0-test', - }, - }), - ).toBe(true); - expect( - fakeFetch.calledWith('https://api.clerk.test/v1/users/count?user_id=user_cafebabe', { - method: 'GET', - headers: { - Authorization: 'Bearer deadbeef', - 'Content-Type': 'application/json', - 'User-Agent': '@clerk/backend@0.0.0-test', - }, - }), - ).toBe(true); + // expect( + // fakeFetch.calledWith('https://api.clerk.test/v1/users?offset=2&limit=5&user_id=user_cafebabe', { + // method: 'GET', + // headers: { + // Authorization: 'Bearer deadbeef', + // 'Content-Type': 'application/json', + // 'User-Agent': '@clerk/backend@0.0.0-test', + // }, + // }), + // ).toBe(true); + // expect( + // fakeFetch.calledWith('https://api.clerk.test/v1/users/count?user_id=user_cafebabe', { + // method: 'GET', + // headers: { + // Authorization: 'Bearer deadbeef', + // 'Content-Type': 'application/json', + // 'User-Agent': '@clerk/backend@0.0.0-test', + // }, + // }), + // ).toBe(true); }); it('executes a successful backend API request for a paginated response', async () => { - fakeFetch = sinon.stub(runtime, 'fetch'); - fakeFetch.onCall(0).returns(jsonPaginatedOk([{ id: '1' }], 3)); + // fakeFetch.onCall(0).returns(); + server.use( + http.get(`https://api.clerk.test/v1/users/user_123/organization_memberships`, () => { + return HttpResponse.json({ + data: [{ id: '1' }], + total_count: 3, + }); + }), + ); const { data: response, totalCount } = await apiClient.users.getOrganizationMembershipList({ offset: 2, @@ -98,8 +99,11 @@ describe('api.client', () => { }); it('executes a successful backend API request to create a new resource', async () => { - fakeFetch = sinon.stub(runtime, 'fetch'); - fakeFetch.onCall(0).returns(jsonOk(userJson)); + server.use( + http.post(`https://api.clerk.test/v1/users`, () => { + return HttpResponse.json(userJson); + }), + ); const response = await apiClient.users.createUser({ firstName: 'John', @@ -110,24 +114,8 @@ describe('api.client', () => { }); expect(response.firstName).toBe('John'); - - expect( - fakeFetch.calledOnceWith('https://api.clerk.test/v1/users', { - method: 'POST', - headers: { - Authorization: 'Bearer deadbeef', - 'Content-Type': 'application/json', - 'User-Agent': '@clerk/backend@0.0.0-test', - }, - body: JSON.stringify({ - first_name: 'John', - last_name: 'Doe', - public_metadata: { - star_sign: 'Leon', - }, - }), - }), - ).toBe(true); + expect(response.lastName).toBe('Doe'); + expect(response.publicMetadata.zodiac_sign).toBe('leo'); }); it('executes a failed backend API request and parses the error response', async () => { @@ -138,8 +126,15 @@ describe('api.client', () => { meta: { param_name: 'some param' }, }; const traceId = 'trace_id_123'; - fakeFetch = sinon.stub(runtime, 'fetch'); - fakeFetch.onCall(0).returns(jsonNotOk({ errors: [mockErrorPayload], clerk_trace_id: traceId })); + + server.use( + http.get(`https://api.clerk.test/v1/users/user_deadbeef`, () => { + return HttpResponse.json( + { errors: [mockErrorPayload], clerk_trace_id: traceId }, + { status: 422, headers: { 'cf-ray': traceId } }, + ); + }), + ); const errResponse = await apiClient.users.getUser('user_deadbeef').catch(err => err); @@ -149,103 +144,67 @@ describe('api.client', () => { expect(errResponse.errors[0].message).toBe('whatever error'); expect(errResponse.errors[0].longMessage).toBe('some long message'); expect(errResponse.errors[0].meta.paramName).toBe('some param'); - - expect( - fakeFetch.calledOnceWith('https://api.clerk.test/v1/users/user_deadbeef', { - method: 'GET', - headers: { - Authorization: 'Bearer deadbeef', - 'Content-Type': 'application/json', - 'User-Agent': '@clerk/backend@0.0.0-test', - }, - }), - ).toBe(true); }); it('executes a failed backend API request and include cf ray id when trace not present', async () => { - fakeFetch = sinon.stub(runtime, 'fetch'); - fakeFetch.onCall(0).returns(jsonError({ errors: [] })); + server.use( + http.get(`https://api.clerk.test/v1/users/user_deadbeef`, () => { + return HttpResponse.json({ errors: [] }, { status: 500, headers: { 'cf-ray': 'mock_cf_ray' } }); + }), + ); const errResponse = await apiClient.users.getUser('user_deadbeef').catch(err => err); expect(errResponse.status).toBe(500); expect(errResponse.clerkTraceId).toBe('mock_cf_ray'); - - expect( - fakeFetch.calledOnceWith('https://api.clerk.test/v1/users/user_deadbeef', { - method: 'GET', - headers: { - Authorization: 'Bearer deadbeef', - 'Content-Type': 'application/json', - 'User-Agent': '@clerk/backend@0.0.0-test', - }, - }), - ).toBe(true); }); it('executes a successful backend API request to delete a domain', async () => { - const domainId = 'dmn_123'; - const fakeResponse = { - object: 'domain', - id: domainId, - deleted: true, - }; - - fakeFetch = sinon.stub(runtime, 'fetch'); - fakeFetch.onCall(0).returns(jsonOk(fakeResponse, 204)); - - await apiClient.domains.deleteDomain(domainId); - - expect( - fakeFetch.calledOnceWith(`https://api.clerk.test/v1/domains/${domainId}`, { - method: 'DELETE', - headers: { - Authorization: 'Bearer deadbeef', - 'Content-Type': 'application/json', - 'User-Agent': '@clerk/backend@0.0.0-test', - }, + const DOMAIN_ID = 'dmn_123'; + server.use( + http.delete(`https://api.clerk.test/v1/domains/${DOMAIN_ID}`, () => { + return HttpResponse.json({ + object: 'domain', + id: DOMAIN_ID, + deleted: true, + }); }), - ).toBe(true); + ); + + await apiClient.domains.deleteDomain(DOMAIN_ID); }); it('successfully retrieves user access tokens from backend API for a specific provider', async () => { - const fakeResponse = { - data: [ - { - external_account_id: 'eac_2dYS7stz9bgxQsSRvNqEAHhuxvW', - object: 'oauth_access_token', - token: '', - provider: 'oauth_google', - public_metadata: {}, - label: null, - scopes: ['email', 'profile'], - }, - ], - total_count: 1, - }; + server.use( + http.get('https://api.clerk.test/v1/users/user_deadbeef/oauth_access_tokens/oauth_google', ({ request }) => { + const paginated = new URL(request.url).searchParams.get('paginated'); + + if (!paginated) { + return new HttpResponse(null, { status: 404 }); + } + + return HttpResponse.json({ + data: [ + { + external_account_id: 'eac_2dYS7stz9bgxQsSRvNqEAHhuxvW', + object: 'oauth_access_token', + token: '', + provider: 'oauth_google', + public_metadata: {}, + label: null, + scopes: ['email', 'profile'], + }, + ], + total_count: 1, + }); + }), + ); + + const { data } = await apiClient.users.getUserOauthAccessToken('user_deadbeef', 'oauth_google'); - fakeFetch = sinon.stub(runtime, 'fetch'); - fakeFetch.onCall(0).returns(jsonOk(fakeResponse)); - - const response = await apiClient.users.getUserOauthAccessToken('user_deadbeef', 'oauth_google'); - - expect(response.data[0].externalAccountId).toBe('eac_2dYS7stz9bgxQsSRvNqEAHhuxvW'); - expect(response.data[0].provider).toBe('oauth_google'); - expect(response.data[0].token).toBe(''); - expect(response.data[0].scopes).toEqual(['email', 'profile']); - - expect( - fakeFetch.calledOnceWith( - 'https://api.clerk.test/v1/users/user_deadbeef/oauth_access_tokens/oauth_google?paginated=true', - { - method: 'GET', - headers: { - Authorization: 'Bearer deadbeef', - 'Content-Type': 'application/json', - 'User-Agent': '@clerk/backend@0.0.0-test', - }, - }, - ), - ).toBe(true); + expect(data[0].externalAccountId).toBe('eac_2dYS7stz9bgxQsSRvNqEAHhuxvW'); + expect(data[0].provider).toBe('oauth_google'); + expect(data[0].token).toBe(''); + expect(data[0].scopes).toEqual(['email', 'profile']); }); }); diff --git a/packages/backend/src/api/request.ts b/packages/backend/src/api/request.ts index ecf019ab5c..c4ec70f43e 100644 --- a/packages/backend/src/api/request.ts +++ b/packages/backend/src/api/request.ts @@ -88,7 +88,7 @@ export function buildRequest(options: BuildRequestOptions) { let res: Response | undefined; try { if (formData) { - res = await runtime.fetch(finalUrl.href, { + res = await (process.env.NODE_ENV === 'test' ? fetch : runtime.fetch)(finalUrl.href, { method, headers, body: formData, @@ -100,7 +100,7 @@ export function buildRequest(options: BuildRequestOptions) { const hasBody = method !== 'GET' && bodyParams && Object.keys(bodyParams).length > 0; const body = hasBody ? { body: JSON.stringify(snakecaseKeys(bodyParams, { deep: false })) } : null; - res = await runtime.fetch(finalUrl.href, { + res = await (process.env.NODE_ENV === 'test' ? fetch : runtime.fetch)(finalUrl.href, { method, headers, ...body, diff --git a/packages/backend/src/mock-server.ts b/packages/backend/src/mock-server.ts new file mode 100644 index 0000000000..07f8657412 --- /dev/null +++ b/packages/backend/src/mock-server.ts @@ -0,0 +1,5 @@ +import { setupServer } from 'msw/node'; + +const globalHandlers = []; + +export const server = setupServer(...globalHandlers); diff --git a/packages/backend/src/tokens/__tests__/authenticateContext.test.ts b/packages/backend/src/tokens/__tests__/authenticateContext.test.ts index b9e2ddebe9..13c28b52a2 100644 --- a/packages/backend/src/tokens/__tests__/authenticateContext.test.ts +++ b/packages/backend/src/tokens/__tests__/authenticateContext.test.ts @@ -1,5 +1,4 @@ -import sinon from 'sinon'; -import { afterEach, beforeEach, describe, expect, it } from 'vitest'; +import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; import { createCookieHeader, createJwt, mockJwtPayload, pkLive, pkTest } from '../../fixtures'; import runtime from '../../runtime'; @@ -8,8 +7,6 @@ import { createAuthenticateContext } from '../authenticateContext'; import { createClerkRequest } from '../clerkRequest'; describe('AuthenticateContext', () => { - let fakeClock; - const nowTimestampInSec = mockJwtPayload.iat; const suffixedSession = createJwt({ header: {} }); @@ -20,12 +17,12 @@ describe('AuthenticateContext', () => { const suffixedClientUat = '1717490193'; beforeEach(() => { - fakeClock = sinon.useFakeTimers(nowTimestampInSec * 1000); + vi.useFakeTimers(); + vi.setSystemTime(nowTimestampInSec * 1000); }); afterEach(() => { - fakeClock.restore(); - sinon.restore(); + vi.useRealTimers(); }); describe('suffixedCookies', () => { diff --git a/packages/backend/vitest.setup.mts b/packages/backend/vitest.setup.mts index e3f711f506..2324324c06 100644 --- a/packages/backend/vitest.setup.mts +++ b/packages/backend/vitest.setup.mts @@ -1,6 +1,13 @@ -import { beforeAll } from 'vitest'; +import { beforeAll, afterEach, afterAll } from 'vitest'; +import { server } from './src/mock-server'; + +beforeAll(() => server.listen()); +afterEach(() => server.resetHandlers()); +afterAll(() => server.close()); + +server.events.on('request:start', ({ request }) => { + console.log('MSW intercepted:', request.method, request.url); +}); globalThis.PACKAGE_NAME = '@clerk/backend'; globalThis.PACKAGE_VERSION = '1'; - -beforeAll(() => {});