diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 3771b69..6251eec 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -19,13 +19,13 @@ jobs: - name: Setup Node.js uses: actions/setup-node@v4 with: - node-version: 18 + node-version: 20 always-auth: true registry-url: https://registry.npmjs.org - uses: pnpm/action-setup@v4 with: - version: 8.15.6 + version: 9.14.0 - name: Setup Git run: | diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 66dede6..33bc5fc 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -18,13 +18,13 @@ jobs: - name: Setup Node.js uses: actions/setup-node@v4 with: - node-version: 18 + node-version: 20 always-auth: true registry-url: https://registry.npmjs.org - uses: pnpm/action-setup@v4 with: - version: 8.15.6 + version: 9.14.0 - name: Install dependencies run: pnpm install diff --git a/package.json b/package.json index 0d3cea8..f1ceb52 100644 --- a/package.json +++ b/package.json @@ -68,5 +68,5 @@ "engines": { "node": ">=18" }, - "packageManager": "pnpm@8.15.6" -} \ No newline at end of file + "packageManager": "pnpm@9.14.2" +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 3157bf4..4ec4e7d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -29,10 +29,10 @@ importers: version: 20.8.10 '@typescript-eslint/eslint-plugin': specifier: ^8.11.0 - version: 8.11.0(@typescript-eslint/parser@8.11.0(eslint@8.53.0)(typescript@5.8.3))(eslint@8.53.0)(typescript@5.8.3) + version: 8.11.0(@typescript-eslint/parser@8.11.0(eslint@8.53.0)(typescript@5.9.2))(eslint@8.53.0)(typescript@5.9.2) '@typescript-eslint/parser': specifier: ^8.11.0 - version: 8.11.0(eslint@8.53.0)(typescript@5.8.3) + version: 8.11.0(eslint@8.53.0)(typescript@5.9.2) eslint: specifier: ^8.53.0 version: 8.53.0 @@ -41,7 +41,7 @@ importers: version: 9.1.0(eslint@8.53.0) eslint-plugin-prettier: specifier: ^5.2.1 - version: 5.2.1(eslint-config-prettier@9.1.0(eslint@8.53.0))(eslint@8.53.0)(prettier@3.5.3) + version: 5.2.1(eslint-config-prettier@9.1.0(eslint@8.53.0))(eslint@8.53.0)(prettier@3.6.2) husky: specifier: ^7.0.4 version: 7.0.4 @@ -50,19 +50,19 @@ importers: version: 11.2.6 msw: specifier: ^2.10.2 - version: 2.10.2(@types/node@20.8.10)(typescript@5.8.3) + version: 2.10.5(@types/node@20.8.10)(typescript@5.9.2) prettier: specifier: ^3.5.3 - version: 3.5.3 + version: 3.6.2 rimraf: specifier: ^6.0.1 version: 6.0.1 typescript: specifier: ^5.8.3 - version: 5.8.3 + version: 5.9.2 vitest: specifier: ^3.2.3 - version: 3.2.3(@types/node@20.8.10)(msw@2.10.2(@types/node@20.8.10)(typescript@5.8.3)) + version: 3.2.4(@types/node@20.8.10)(msw@2.10.5(@types/node@20.8.10)(typescript@5.9.2)) packages: @@ -276,15 +276,23 @@ packages: peerDependencies: '@types/node': '>=18' + '@isaacs/balanced-match@4.0.1': + resolution: {integrity: sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==} + engines: {node: 20 || >=22} + + '@isaacs/brace-expansion@5.0.0': + resolution: {integrity: sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA==} + engines: {node: 20 || >=22} + '@isaacs/cliui@8.0.2': resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} engines: {node: '>=12'} - '@jridgewell/sourcemap-codec@1.5.0': - resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==} + '@jridgewell/sourcemap-codec@1.5.5': + resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} - '@mswjs/interceptors@0.39.2': - resolution: {integrity: sha512-RuzCup9Ct91Y7V79xwCb146RaBRHZ7NBbrIUySumd1rpKqHL5OonaqrGIbug5hNwP/fRyxFMA6ISgw4FTtYFYg==} + '@mswjs/interceptors@0.39.6': + resolution: {integrity: sha512-bndDP83naYYkfayr/qhBHMhk0YGwS1iv6vaEGcr0SQbO0IZtbOPqjKjds/WcG+bJA+1T5vCx6kprKOzn5Bg+Vw==} engines: {node: '>=18'} '@nodelib/fs.scandir@2.1.5': @@ -555,11 +563,11 @@ packages: '@ungap/structured-clone@1.2.0': resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==} - '@vitest/expect@3.2.3': - resolution: {integrity: sha512-W2RH2TPWVHA1o7UmaFKISPvdicFJH+mjykctJFoAkUw+SPTJTGjUNdKscFBrqM7IPnCVu6zihtKYa7TkZS1dkQ==} + '@vitest/expect@3.2.4': + resolution: {integrity: sha512-Io0yyORnB6sikFlt8QW5K7slY4OjqNX9jmJQ02QDda8lyM6B5oNgVWoSoKPac8/kgnCUzuHQKrSLtu/uOqqrig==} - '@vitest/mocker@3.2.3': - resolution: {integrity: sha512-cP6fIun+Zx8he4rbWvi+Oya6goKQDZK+Yq4hhlggwQBbrlOQ4qtZ+G4nxB6ZnzI9lyIb+JnvyiJnPC2AGbKSPA==} + '@vitest/mocker@3.2.4': + resolution: {integrity: sha512-46ryTE9RZO/rfDd7pEqFl7etuyzekzEhUbTW3BvmeO/BcCMEgq59BKhek3dXDWgAj4oMK6OZi+vRr1wPW6qjEQ==} peerDependencies: msw: ^2.4.9 vite: ^5.0.0 || ^6.0.0 || ^7.0.0-0 @@ -569,20 +577,20 @@ packages: vite: optional: true - '@vitest/pretty-format@3.2.3': - resolution: {integrity: sha512-yFglXGkr9hW/yEXngO+IKMhP0jxyFw2/qys/CK4fFUZnSltD+MU7dVYGrH8rvPcK/O6feXQA+EU33gjaBBbAng==} + '@vitest/pretty-format@3.2.4': + resolution: {integrity: sha512-IVNZik8IVRJRTr9fxlitMKeJeXFFFN0JaB9PHPGQ8NKQbGpfjlTx9zO4RefN8gp7eqjNy8nyK3NZmBzOPeIxtA==} - '@vitest/runner@3.2.3': - resolution: {integrity: sha512-83HWYisT3IpMaU9LN+VN+/nLHVBCSIUKJzGxC5RWUOsK1h3USg7ojL+UXQR3b4o4UBIWCYdD2fxuzM7PQQ1u8w==} + '@vitest/runner@3.2.4': + resolution: {integrity: sha512-oukfKT9Mk41LreEW09vt45f8wx7DordoWUZMYdY/cyAk7w5TWkTRCNZYF7sX7n2wB7jyGAl74OxgwhPgKaqDMQ==} - '@vitest/snapshot@3.2.3': - resolution: {integrity: sha512-9gIVWx2+tysDqUmmM1L0hwadyumqssOL1r8KJipwLx5JVYyxvVRfxvMq7DaWbZZsCqZnu/dZedaZQh4iYTtneA==} + '@vitest/snapshot@3.2.4': + resolution: {integrity: sha512-dEYtS7qQP2CjU27QBC5oUOxLE/v5eLkGqPE0ZKEIDGMs4vKWe7IjgLOeauHsR0D5YuuycGRO5oSRXnwnmA78fQ==} - '@vitest/spy@3.2.3': - resolution: {integrity: sha512-JHu9Wl+7bf6FEejTCREy+DmgWe+rQKbK+y32C/k5f4TBIAlijhJbRBIRIOCEpVevgRsCQR2iHRUH2/qKVM/plw==} + '@vitest/spy@3.2.4': + resolution: {integrity: sha512-vAfasCOe6AIK70iP5UD11Ac4siNUNJ9i/9PZ3NKx07sG6sUxeag1LWdNrMWeKKYBLlzuK+Gn65Yd5nyL6ds+nw==} - '@vitest/utils@3.2.3': - resolution: {integrity: sha512-4zFBCU5Pf+4Z6v+rwnZ1HU1yzOKKvDkMXZrymE2PBlbjKJRlrOxbvpfPSvJTGRIwGoahaOGvp+kbCoxifhzJ1Q==} + '@vitest/utils@3.2.4': + resolution: {integrity: sha512-fB2V0JFrQSMsCo9HiSq3Ezpdv4iYaXRG1Sx8edX3MwxfyNn83mKiGzOcH+Fkxt4MHxr3y42fQi1oeAInqgX2QA==} JSONStream@1.3.5: resolution: {integrity: sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==} @@ -621,8 +629,8 @@ packages: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} engines: {node: '>=8'} - ansi-regex@6.1.0: - resolution: {integrity: sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==} + ansi-regex@6.2.0: + resolution: {integrity: sha512-TKY5pyBkHyADOPYlRT9Lx6F544mPl0vS5Ew7BJ45hA08Q+t3GjbueLliBWN3sMICk6+y7HdyxSzC4bWS8baBdg==} engines: {node: '>=12'} ansi-styles@3.2.1: @@ -705,9 +713,9 @@ packages: resolution: {integrity: sha512-faqwZqnWxbxn+F1d399ygeamQNy3lPp/H9H6rNrqYh4FSVCtcY+3cub1MxA8o9mDd55mM8Aghuu/kuyYA6VTsA==} engines: {node: '>=6'} - chai@5.2.0: - resolution: {integrity: sha512-mCuXncKXk5iCLhfhwTc0izo0gtEmpz5CtG2y8GiOINBlMVS6v8TMRc5TaLWKS6692m9+dVVfzgeVxR5UxWHTYw==} - engines: {node: '>=12'} + chai@5.3.3: + resolution: {integrity: sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==} + engines: {node: '>=18'} chalk@2.4.2: resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} @@ -1014,8 +1022,8 @@ packages: resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==} engines: {node: '>=10'} - expect-type@1.2.1: - resolution: {integrity: sha512-/kP8CAwxzLVEeFrMm4kMmy4CCDlpipyA7MYLVrdJIkV0fYF0UaigQHRsxHiuY/GEea+bh4KSv3TIlgr+2UL6bw==} + expect-type@1.2.2: + resolution: {integrity: sha512-JhFGDVJ7tmDJItKhYgJCGLOWjuK9vPxiXoUFLwLDc99NlmklilbiQJwoctZtt13+xMw91MCk/REan6MWHqDjyA==} engines: {node: '>=12.0.0'} express@4.18.2: @@ -1048,8 +1056,9 @@ packages: fastq@1.15.0: resolution: {integrity: sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==} - fdir@6.4.6: - resolution: {integrity: sha512-hiFoqpyZcfNm1yc4u8oWCf9A2c4D3QjCrks3zmoVKVxpQRzmPNar1hUJcBG2RQHvEVGDN+Jm81ZheVLAQMK6+w==} + fdir@6.5.0: + resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} + engines: {node: '>=12.0.0'} peerDependencies: picomatch: ^3 || ^4 peerDependenciesMeta: @@ -1131,13 +1140,14 @@ packages: resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} engines: {node: '>=10.13.0'} - glob@11.0.2: - resolution: {integrity: sha512-YT7U7Vye+t5fZ/QMkBFrTJ7ZQxInIUjwyAjVj84CYXqgBdv30MFUPGnBR6sQaVq6Is15wYJUsnzTuWaGRBhBAQ==} + glob@11.0.3: + resolution: {integrity: sha512-2Nim7dha1KVkaiF4q6Dj+ngPPMdfvLJEOpZk/jKiUAkqKebpGAWQXAq9z1xu9HKu5lWfqw/FASuccEjyznjPaA==} engines: {node: 20 || >=22} hasBin: true glob@7.2.3: resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} + deprecated: Glob versions prior to v9 are no longer supported globals@13.23.0: resolution: {integrity: sha512-XAmF0RjlrjY23MA51q3HltdlGxUpXPvg0GioKiD9X6HD28iMjo2dKC8Vqwm7lne4GNr78+RHTfliktR6ZH09wA==} @@ -1371,15 +1381,15 @@ packages: loupe@3.1.2: resolution: {integrity: sha512-23I4pFZHmAemUnz8WZXbYRSKYj801VDaNv9ETuMh7IrMc7VuVVSo+Z9iLE3ni30+U48iDWfi30d3twAXBYmnCg==} - loupe@3.1.3: - resolution: {integrity: sha512-kkIp7XSkP78ZxJEsSxW3712C6teJVoeHHwgo9zJ380de7IYyJ2ISlxojcH2pC5OFLewESmnRi/+XCDIEEVyoug==} + loupe@3.2.1: + resolution: {integrity: sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==} lru-cache@11.1.0: resolution: {integrity: sha512-QIXZUBJUx+2zHUdQujWejBkcD9+cs94tLn0+YL8UrCh+D5sCXZ4c7LaEH48pNwRY3MLDgqUFyhlCyjJPf1WP0A==} engines: {node: 20 || >=22} - magic-string@0.30.17: - resolution: {integrity: sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==} + magic-string@0.30.18: + resolution: {integrity: sha512-yi8swmWbO17qHhwIBNeeZxTceJMeBvWJaId6dyvTSOwTipqeHhMhOrz6513r1sOKnpvQ7zkhlG8tPrpilwTxHQ==} media-typer@0.3.0: resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==} @@ -1424,8 +1434,8 @@ packages: resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} engines: {node: '>=6'} - minimatch@10.0.1: - resolution: {integrity: sha512-ethXTt3SGGR+95gudmqJ1eNhRO7eGEGIgYA9vnPatK4/etz2MEVDno5GMCibdMTuBMyElzIlgxMna3K94XDIDQ==} + minimatch@10.0.3: + resolution: {integrity: sha512-IPZ167aShDZZUMdRk66cyQAW3qr0WzbHkPdMYa8bzZhlHhO3jALbKdxcaak7W9FfT2rZNpQuUu4Od7ILEpXSaw==} engines: {node: 20 || >=22} minimatch@3.1.2: @@ -1455,8 +1465,8 @@ packages: ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} - msw@2.10.2: - resolution: {integrity: sha512-RCKM6IZseZQCWcSWlutdf590M8nVfRHG1ImwzOtwz8IYxgT4zhUO0rfTcTvDGiaFE0Rhcc+h43lcF3Jc9gFtwQ==} + msw@2.10.5: + resolution: {integrity: sha512-0EsQCrCI1HbhpBWd89DvmxY6plmvrM96b0sCIztnvcNHQbXn5vqwm1KlXslo6u4wN9LFGLC1WFjjgljcQhe40A==} engines: {node: '>=18'} hasBin: true peerDependencies: @@ -1596,8 +1606,8 @@ packages: resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} engines: {node: '>=8.6'} - picomatch@4.0.2: - resolution: {integrity: sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==} + picomatch@4.0.3: + resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} engines: {node: '>=12'} pino-abstract-transport@0.5.0: @@ -1629,8 +1639,8 @@ packages: resolution: {integrity: sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==} engines: {node: '>=6.0.0'} - prettier@3.5.3: - resolution: {integrity: sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==} + prettier@3.6.2: + resolution: {integrity: sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==} engines: {node: '>=14'} hasBin: true @@ -1939,8 +1949,8 @@ packages: resolution: {integrity: sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==} engines: {node: '>=12.0.0'} - tinypool@1.1.0: - resolution: {integrity: sha512-7CotroY9a8DKsKprEy/a14aCCm8jYVmR7aFy4fpkZM8sdpNJbKkixuNjgM50yCmip2ezc8z4N7k3oe2+rfRJCQ==} + tinypool@1.1.1: + resolution: {integrity: sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg==} engines: {node: ^18.0.0 || >=20.0.0} tinyrainbow@2.0.0: @@ -1998,8 +2008,8 @@ packages: resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==} engines: {node: '>= 0.6'} - typescript@5.8.3: - resolution: {integrity: sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==} + typescript@5.9.2: + resolution: {integrity: sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==} engines: {node: '>=14.17'} hasBin: true @@ -2031,8 +2041,8 @@ packages: resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} engines: {node: '>= 0.8'} - vite-node@3.2.3: - resolution: {integrity: sha512-gc8aAifGuDIpZHrPjuHyP4dpQmYXqWw7D1GmDnWeNWP654UEXzVfQ5IHPSK5HaHkwB/+p1atpYpSdw/2kOv8iQ==} + vite-node@3.2.4: + resolution: {integrity: sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg==} engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} hasBin: true @@ -2067,16 +2077,16 @@ packages: terser: optional: true - vitest@3.2.3: - resolution: {integrity: sha512-E6U2ZFXe3N/t4f5BwUaVCKRLHqUpk1CBWeMh78UT4VaTPH/2dyvH6ALl29JTovEPu9dVKr/K/J4PkXgrMbw4Ww==} + vitest@3.2.4: + resolution: {integrity: sha512-LUCP5ev3GURDysTWiP47wRRUpLKMOfPh+yKTx3kVIEiu5KOMeqzpnYNsKyOoVrULivR8tLcks4+lga33Whn90A==} engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} hasBin: true peerDependencies: '@edge-runtime/vm': '*' '@types/debug': ^4.1.12 '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0 - '@vitest/browser': 3.2.3 - '@vitest/ui': 3.2.3 + '@vitest/browser': 3.2.4 + '@vitest/ui': 3.2.4 happy-dom: '*' jsdom: '*' peerDependenciesMeta: @@ -2327,6 +2337,12 @@ snapshots: dependencies: '@types/node': 20.8.10 + '@isaacs/balanced-match@4.0.1': {} + + '@isaacs/brace-expansion@5.0.0': + dependencies: + '@isaacs/balanced-match': 4.0.1 + '@isaacs/cliui@8.0.2': dependencies: string-width: 5.1.2 @@ -2336,9 +2352,9 @@ snapshots: wrap-ansi: 8.1.0 wrap-ansi-cjs: wrap-ansi@7.0.0 - '@jridgewell/sourcemap-codec@1.5.0': {} + '@jridgewell/sourcemap-codec@1.5.5': {} - '@mswjs/interceptors@0.39.2': + '@mswjs/interceptors@0.39.6': dependencies: '@open-draft/deferred-promise': 2.2.0 '@open-draft/logger': 0.3.0 @@ -2560,34 +2576,34 @@ snapshots: dependencies: '@types/yargs-parser': 21.0.2 - '@typescript-eslint/eslint-plugin@8.11.0(@typescript-eslint/parser@8.11.0(eslint@8.53.0)(typescript@5.8.3))(eslint@8.53.0)(typescript@5.8.3)': + '@typescript-eslint/eslint-plugin@8.11.0(@typescript-eslint/parser@8.11.0(eslint@8.53.0)(typescript@5.9.2))(eslint@8.53.0)(typescript@5.9.2)': dependencies: '@eslint-community/regexpp': 4.10.0 - '@typescript-eslint/parser': 8.11.0(eslint@8.53.0)(typescript@5.8.3) + '@typescript-eslint/parser': 8.11.0(eslint@8.53.0)(typescript@5.9.2) '@typescript-eslint/scope-manager': 8.11.0 - '@typescript-eslint/type-utils': 8.11.0(eslint@8.53.0)(typescript@5.8.3) - '@typescript-eslint/utils': 8.11.0(eslint@8.53.0)(typescript@5.8.3) + '@typescript-eslint/type-utils': 8.11.0(eslint@8.53.0)(typescript@5.9.2) + '@typescript-eslint/utils': 8.11.0(eslint@8.53.0)(typescript@5.9.2) '@typescript-eslint/visitor-keys': 8.11.0 eslint: 8.53.0 graphemer: 1.4.0 ignore: 5.3.2 natural-compare: 1.4.0 - ts-api-utils: 1.3.0(typescript@5.8.3) + ts-api-utils: 1.3.0(typescript@5.9.2) optionalDependencies: - typescript: 5.8.3 + typescript: 5.9.2 transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.11.0(eslint@8.53.0)(typescript@5.8.3)': + '@typescript-eslint/parser@8.11.0(eslint@8.53.0)(typescript@5.9.2)': dependencies: '@typescript-eslint/scope-manager': 8.11.0 '@typescript-eslint/types': 8.11.0 - '@typescript-eslint/typescript-estree': 8.11.0(typescript@5.8.3) + '@typescript-eslint/typescript-estree': 8.11.0(typescript@5.9.2) '@typescript-eslint/visitor-keys': 8.11.0 debug: 4.3.7 eslint: 8.53.0 optionalDependencies: - typescript: 5.8.3 + typescript: 5.9.2 transitivePeerDependencies: - supports-color @@ -2596,21 +2612,21 @@ snapshots: '@typescript-eslint/types': 8.11.0 '@typescript-eslint/visitor-keys': 8.11.0 - '@typescript-eslint/type-utils@8.11.0(eslint@8.53.0)(typescript@5.8.3)': + '@typescript-eslint/type-utils@8.11.0(eslint@8.53.0)(typescript@5.9.2)': dependencies: - '@typescript-eslint/typescript-estree': 8.11.0(typescript@5.8.3) - '@typescript-eslint/utils': 8.11.0(eslint@8.53.0)(typescript@5.8.3) + '@typescript-eslint/typescript-estree': 8.11.0(typescript@5.9.2) + '@typescript-eslint/utils': 8.11.0(eslint@8.53.0)(typescript@5.9.2) debug: 4.3.7 - ts-api-utils: 1.3.0(typescript@5.8.3) + ts-api-utils: 1.3.0(typescript@5.9.2) optionalDependencies: - typescript: 5.8.3 + typescript: 5.9.2 transitivePeerDependencies: - eslint - supports-color '@typescript-eslint/types@8.11.0': {} - '@typescript-eslint/typescript-estree@8.11.0(typescript@5.8.3)': + '@typescript-eslint/typescript-estree@8.11.0(typescript@5.9.2)': dependencies: '@typescript-eslint/types': 8.11.0 '@typescript-eslint/visitor-keys': 8.11.0 @@ -2619,18 +2635,18 @@ snapshots: is-glob: 4.0.3 minimatch: 9.0.5 semver: 7.6.3 - ts-api-utils: 1.3.0(typescript@5.8.3) + ts-api-utils: 1.3.0(typescript@5.9.2) optionalDependencies: - typescript: 5.8.3 + typescript: 5.9.2 transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.11.0(eslint@8.53.0)(typescript@5.8.3)': + '@typescript-eslint/utils@8.11.0(eslint@8.53.0)(typescript@5.9.2)': dependencies: '@eslint-community/eslint-utils': 4.4.0(eslint@8.53.0) '@typescript-eslint/scope-manager': 8.11.0 '@typescript-eslint/types': 8.11.0 - '@typescript-eslint/typescript-estree': 8.11.0(typescript@5.8.3) + '@typescript-eslint/typescript-estree': 8.11.0(typescript@5.9.2) eslint: 8.53.0 transitivePeerDependencies: - supports-color @@ -2643,47 +2659,47 @@ snapshots: '@ungap/structured-clone@1.2.0': {} - '@vitest/expect@3.2.3': + '@vitest/expect@3.2.4': dependencies: '@types/chai': 5.2.2 - '@vitest/spy': 3.2.3 - '@vitest/utils': 3.2.3 - chai: 5.2.0 + '@vitest/spy': 3.2.4 + '@vitest/utils': 3.2.4 + chai: 5.3.3 tinyrainbow: 2.0.0 - '@vitest/mocker@3.2.3(msw@2.10.2(@types/node@20.8.10)(typescript@5.8.3))(vite@5.4.10(@types/node@20.8.10))': + '@vitest/mocker@3.2.4(msw@2.10.5(@types/node@20.8.10)(typescript@5.9.2))(vite@5.4.10(@types/node@20.8.10))': dependencies: - '@vitest/spy': 3.2.3 + '@vitest/spy': 3.2.4 estree-walker: 3.0.3 - magic-string: 0.30.17 + magic-string: 0.30.18 optionalDependencies: - msw: 2.10.2(@types/node@20.8.10)(typescript@5.8.3) + msw: 2.10.5(@types/node@20.8.10)(typescript@5.9.2) vite: 5.4.10(@types/node@20.8.10) - '@vitest/pretty-format@3.2.3': + '@vitest/pretty-format@3.2.4': dependencies: tinyrainbow: 2.0.0 - '@vitest/runner@3.2.3': + '@vitest/runner@3.2.4': dependencies: - '@vitest/utils': 3.2.3 + '@vitest/utils': 3.2.4 pathe: 2.0.3 strip-literal: 3.0.0 - '@vitest/snapshot@3.2.3': + '@vitest/snapshot@3.2.4': dependencies: - '@vitest/pretty-format': 3.2.3 - magic-string: 0.30.17 + '@vitest/pretty-format': 3.2.4 + magic-string: 0.30.18 pathe: 2.0.3 - '@vitest/spy@3.2.3': + '@vitest/spy@3.2.4': dependencies: tinyspy: 4.0.3 - '@vitest/utils@3.2.3': + '@vitest/utils@3.2.4': dependencies: - '@vitest/pretty-format': 3.2.3 - loupe: 3.1.3 + '@vitest/pretty-format': 3.2.4 + loupe: 3.2.1 tinyrainbow: 2.0.0 JSONStream@1.3.5: @@ -2722,7 +2738,7 @@ snapshots: ansi-regex@5.0.1: {} - ansi-regex@6.1.0: {} + ansi-regex@6.2.0: {} ansi-styles@3.2.1: dependencies: @@ -2803,7 +2819,7 @@ snapshots: camelcase@5.0.0: {} - chai@5.2.0: + chai@5.3.3: dependencies: assertion-error: 2.0.1 check-error: 2.1.1 @@ -3050,10 +3066,10 @@ snapshots: dependencies: eslint: 8.53.0 - eslint-plugin-prettier@5.2.1(eslint-config-prettier@9.1.0(eslint@8.53.0))(eslint@8.53.0)(prettier@3.5.3): + eslint-plugin-prettier@5.2.1(eslint-config-prettier@9.1.0(eslint@8.53.0))(eslint@8.53.0)(prettier@3.6.2): dependencies: eslint: 8.53.0 - prettier: 3.5.3 + prettier: 3.6.2 prettier-linter-helpers: 1.0.0 synckit: 0.9.2 optionalDependencies: @@ -3145,7 +3161,7 @@ snapshots: signal-exit: 3.0.7 strip-final-newline: 2.0.0 - expect-type@1.2.1: {} + expect-type@1.2.2: {} express@4.18.2: dependencies: @@ -3207,9 +3223,9 @@ snapshots: dependencies: reusify: 1.0.4 - fdir@6.4.6(picomatch@4.0.2): + fdir@6.5.0(picomatch@4.0.3): optionalDependencies: - picomatch: 4.0.2 + picomatch: 4.0.3 file-entry-cache@6.0.1: dependencies: @@ -3296,11 +3312,11 @@ snapshots: dependencies: is-glob: 4.0.3 - glob@11.0.2: + glob@11.0.3: dependencies: foreground-child: 3.3.1 jackspeak: 4.1.1 - minimatch: 10.0.1 + minimatch: 10.0.3 minipass: 7.1.2 package-json-from-dist: 1.0.1 path-scurry: 2.0.0 @@ -3514,13 +3530,13 @@ snapshots: loupe@3.1.2: {} - loupe@3.1.3: {} + loupe@3.2.1: {} lru-cache@11.1.0: {} - magic-string@0.30.17: + magic-string@0.30.18: dependencies: - '@jridgewell/sourcemap-codec': 1.5.0 + '@jridgewell/sourcemap-codec': 1.5.5 media-typer@0.3.0: {} @@ -3549,9 +3565,9 @@ snapshots: mimic-fn@2.1.0: {} - minimatch@10.0.1: + minimatch@10.0.3: dependencies: - brace-expansion: 2.0.1 + '@isaacs/brace-expansion': 5.0.0 minimatch@3.1.2: dependencies: @@ -3573,13 +3589,13 @@ snapshots: ms@2.1.3: {} - msw@2.10.2(@types/node@20.8.10)(typescript@5.8.3): + msw@2.10.5(@types/node@20.8.10)(typescript@5.9.2): 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(@types/node@20.8.10) - '@mswjs/interceptors': 0.39.2 + '@mswjs/interceptors': 0.39.6 '@open-draft/deferred-promise': 2.2.0 '@open-draft/until': 2.1.0 '@types/cookie': 0.6.0 @@ -3594,7 +3610,7 @@ snapshots: type-fest: 4.26.1 yargs: 17.7.2 optionalDependencies: - typescript: 5.8.3 + typescript: 5.9.2 transitivePeerDependencies: - '@types/node' @@ -3699,7 +3715,7 @@ snapshots: picomatch@2.3.1: {} - picomatch@4.0.2: {} + picomatch@4.0.3: {} pino-abstract-transport@0.5.0: dependencies: @@ -3754,7 +3770,7 @@ snapshots: dependencies: fast-diff: 1.3.0 - prettier@3.5.3: {} + prettier@3.6.2: {} process-nextick-args@2.0.1: {} @@ -3843,7 +3859,7 @@ snapshots: rimraf@6.0.1: dependencies: - glob: 11.0.2 + glob: 11.0.3 package-json-from-dist: 1.0.1 rollup@4.24.0: @@ -4047,7 +4063,7 @@ snapshots: strip-ansi@7.1.0: dependencies: - ansi-regex: 6.1.0 + ansi-regex: 6.2.0 strip-final-newline@2.0.0: {} @@ -4097,10 +4113,10 @@ snapshots: tinyglobby@0.2.14: dependencies: - fdir: 6.4.6(picomatch@4.0.2) - picomatch: 4.0.2 + fdir: 6.5.0(picomatch@4.0.3) + picomatch: 4.0.3 - tinypool@1.1.0: {} + tinypool@1.1.1: {} tinyrainbow@2.0.0: {} @@ -4123,9 +4139,9 @@ snapshots: traverse@0.6.7: {} - ts-api-utils@1.3.0(typescript@5.8.3): + ts-api-utils@1.3.0(typescript@5.9.2): dependencies: - typescript: 5.8.3 + typescript: 5.9.2 tslib@2.6.2: {} @@ -4144,7 +4160,7 @@ snapshots: media-typer: 0.3.0 mime-types: 2.1.35 - typescript@5.8.3: {} + typescript@5.9.2: {} undici-types@5.26.5: {} @@ -4167,7 +4183,7 @@ snapshots: vary@1.1.2: {} - vite-node@3.2.3(@types/node@20.8.10): + vite-node@3.2.4(@types/node@20.8.10): dependencies: cac: 6.7.14 debug: 4.4.1 @@ -4194,30 +4210,30 @@ snapshots: '@types/node': 20.8.10 fsevents: 2.3.3 - vitest@3.2.3(@types/node@20.8.10)(msw@2.10.2(@types/node@20.8.10)(typescript@5.8.3)): + vitest@3.2.4(@types/node@20.8.10)(msw@2.10.5(@types/node@20.8.10)(typescript@5.9.2)): dependencies: '@types/chai': 5.2.2 - '@vitest/expect': 3.2.3 - '@vitest/mocker': 3.2.3(msw@2.10.2(@types/node@20.8.10)(typescript@5.8.3))(vite@5.4.10(@types/node@20.8.10)) - '@vitest/pretty-format': 3.2.3 - '@vitest/runner': 3.2.3 - '@vitest/snapshot': 3.2.3 - '@vitest/spy': 3.2.3 - '@vitest/utils': 3.2.3 - chai: 5.2.0 + '@vitest/expect': 3.2.4 + '@vitest/mocker': 3.2.4(msw@2.10.5(@types/node@20.8.10)(typescript@5.9.2))(vite@5.4.10(@types/node@20.8.10)) + '@vitest/pretty-format': 3.2.4 + '@vitest/runner': 3.2.4 + '@vitest/snapshot': 3.2.4 + '@vitest/spy': 3.2.4 + '@vitest/utils': 3.2.4 + chai: 5.3.3 debug: 4.4.1 - expect-type: 1.2.1 - magic-string: 0.30.17 + expect-type: 1.2.2 + magic-string: 0.30.18 pathe: 2.0.3 - picomatch: 4.0.2 + picomatch: 4.0.3 std-env: 3.9.0 tinybench: 2.9.0 tinyexec: 0.3.2 tinyglobby: 0.2.14 - tinypool: 1.1.0 + tinypool: 1.1.1 tinyrainbow: 2.0.0 vite: 5.4.10(@types/node@20.8.10) - vite-node: 3.2.3(@types/node@20.8.10) + vite-node: 3.2.4(@types/node@20.8.10) why-is-node-running: 2.3.0 optionalDependencies: '@types/node': 20.8.10 diff --git a/src/middleware.ts b/src/middleware.ts index 4f03349..e011de3 100644 --- a/src/middleware.ts +++ b/src/middleware.ts @@ -1,37 +1,39 @@ import crypto from 'node:crypto' import { Readable } from 'node:stream' -import { handleRequest } from 'msw' -import { Emitter } from 'strict-event-emitter' - import type { ReadableStream as NodeReadableStream } from 'node:stream/web' import type { RequestHandler as ExpressMiddleware } from 'express' -import type { LifeCycleEventsMap, RequestHandler } from 'msw' +import { + handleRequest, + type LifeCycleEventsMap, + type RequestHandler, +} from 'msw' +import { Emitter } from 'strict-event-emitter' const emitter = new Emitter() export function createMiddleware( ...handlers: Array ): ExpressMiddleware { - return async (req, res, next) => { - const method = req.method || 'GET' - const serverOrigin = `${req.protocol}://${req.get('host')}` + return async (request, response, next) => { + const method = request.method || 'GET' + const origin = `${request.protocol}://${request.get('host')}` const canRequestHaveBody = method !== 'HEAD' && method !== 'GET' const fetchRequest = new Request( // Treat all relative URLs as the ones coming from the server. - new URL(req.url, serverOrigin), + new URL(request.url, origin), { method, - headers: new Headers(req.headers as HeadersInit), + headers: new Headers(request.headers as HeadersInit), credentials: 'omit', // @ts-ignore Internal Undici property. duplex: canRequestHaveBody ? 'half' : undefined, body: canRequestHaveBody - ? req.readable - ? (Readable.toWeb(req) as ReadableStream) - : req.header('content-type')?.includes('json') - ? JSON.stringify(req.body) - : req.body + ? request.readable + ? (Readable.toWeb(request) as ReadableStream) + : request.header('content-type')?.includes('json') + ? JSON.stringify(request.body) + : request.body : undefined, }, ) @@ -50,29 +52,29 @@ export function createMiddleware( * @note Resolve relative request handler URLs against * the server's origin (no relative URLs in Node.js). */ - baseUrl: serverOrigin, + baseUrl: origin, }, async onMockedResponse(mockedResponse) { const { status, statusText, headers } = mockedResponse - res.statusCode = status - res.statusMessage = statusText + response.statusCode = status + response.statusMessage = statusText headers.forEach((value, name) => { /** * @note Use `.appendHeader()` to support multi-value * response headers, like "Set-Cookie". */ - res.appendHeader(name, value) + response.appendHeader(name, value) }) if (mockedResponse.body) { const stream = Readable.fromWeb( mockedResponse.body as NodeReadableStream, ) - stream.pipe(res) + stream.pipe(response) } else { - res.end() + response.end() } }, onPassthroughResponse() { diff --git a/test/middleware.test.ts b/test/middleware.test.ts index 83e8f42..ae6316d 100644 --- a/test/middleware.test.ts +++ b/test/middleware.test.ts @@ -10,11 +10,12 @@ const httpServer = new HttpServer((app) => { http.post('/users', () => { return new HttpResponse(null, { status: 204 }) }), - + http.post('/proxy', async ({ request }) => { + return HttpResponse.json(await request.json()) + }), http.get('/error', () => { throw new Error('Something went wrong.') }), - http.get('/user', () => { return HttpResponse.json( { firstName: 'John' }, @@ -31,6 +32,14 @@ const httpServer = new HttpServer((app) => { app.get('/book', (req, res) => { return res.status(200).send('book') }) + + app.use((req, res) => { + res.status(404).json({ + readable: req.readable, + readableDidRead: req.readableDidRead, + readableEnded: req.readableEnded, + }) + }) }) beforeAll(async () => { @@ -48,8 +57,8 @@ afterEach(() => { it('returns the mocked response when requesting the middleware', async () => { const response = await fetch(httpServer.http.url('/user')) - expect(response.headers.get('x-my-header')).toEqual('value') - await expect(response.json()).resolves.toEqual({ firstName: 'John' }) + expect.soft(response.headers.get('x-my-header')).toEqual('value') + await expect.soft(response.json()).resolves.toEqual({ firstName: 'John' }) }) it('returns the mocked 204 with empty body', async () => { @@ -57,9 +66,20 @@ it('returns the mocked 204 with empty body', async () => { method: 'POST', }) - expect(response.status).toEqual(204) - expect(response.ok).toBeTruthy() - expect(response.bodyUsed).toBeFalsy() + expect.soft(response.status).toEqual(204) + expect.soft(response.ok).toBeTruthy() + expect.soft(response.bodyUsed).toBeFalsy() +}) + +it('allows reading request body in the resolver', async () => { + const response = await fetch(httpServer.http.url('/proxy'), { + method: 'POST', + headers: { 'content-type': 'application/json' }, + body: JSON.stringify({ hello: 'world' }), + }) + + expect.soft(response.status).toEqual(200) + await expect.soft(response.json()).resolves.toEqual({ hello: 'world' }) }) it('returns the original response given no matching request handler', async () => { @@ -70,6 +90,22 @@ it('returns the original response given no matching request handler', async () = it('forwards promise rejections to error middleware', async () => { const response = await fetch(httpServer.http.url('/error')) - expect(response.status).toEqual(500) - expect(response.ok).toBeFalsy() + expect.soft(response.status).toEqual(500) + expect.soft(response.ok).toBeFalsy() +}) + +it('does not lock the request stream for other middleware', async () => { + const response = await fetch(httpServer.http.url('/intentionally-unknown'), { + method: 'POST', + headers: { 'content-type': 'text/plain' }, + body: 'hello world', + }) + + console.log(await response.text()) + + await expect(response.json()).resolves.toEqual({ + readable: true, + readableDidRead: false, + readableEnded: false, + }) }) diff --git a/test/with-express-multipart-form.test.ts b/test/with-express-multipart-form.test.ts index 9393748..4f52f1d 100644 --- a/test/with-express-multipart-form.test.ts +++ b/test/with-express-multipart-form.test.ts @@ -42,9 +42,12 @@ it('supports "multipart/form-data" requests (no body parser)', async () => { body: form, }) - expect(res.status).toBe(200) - expect(res.headers.get('x-my-header')).toBe('value') - expect(await res.json()).toEqual({ field1: 'value1', field2: 'value2' }) + expect.soft(res.status).toBe(200) + expect.soft(res.headers.get('x-my-header')).toBe('value') + await expect.soft(res.json()).resolves.toEqual({ + field1: 'value1', + field2: 'value2', + }) }) it('supports "multipart/form-data" requests (raw body parser)', async () => { @@ -87,7 +90,10 @@ it('supports "multipart/form-data" requests (raw body parser)', async () => { body: form, }) - expect(res.status).toBe(200) - expect(res.headers.get('x-my-header')).toBe('value') - expect(await res.json()).toEqual({ field1: 'value1', field2: 'value2' }) + expect.soft(res.status).toBe(200) + expect.soft(res.headers.get('x-my-header')).toBe('value') + await expect.soft(res.json()).resolves.toEqual({ + field1: 'value1', + field2: 'value2', + }) }) diff --git a/tsconfig.base.json b/tsconfig.base.json index 42dd762..ce2672d 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -1,6 +1,7 @@ { "compilerOptions": { "strict": true, + "skipLibCheck": true, "noUncheckedIndexedAccess": true, "esModuleInterop": true, "allowSyntheticDefaultImports": true,