From 64cf3d7b427338aa03224d61a8a238b2e038c836 Mon Sep 17 00:00:00 2001 From: Davide <43080019+edivados@users.noreply.github.com> Date: Thu, 11 Jan 2024 22:05:53 +0100 Subject: [PATCH 1/7] restore h3's toWebRequest --- packages/vinxi/runtime/server.js | 22 ++-------------------- 1 file changed, 2 insertions(+), 20 deletions(-) diff --git a/packages/vinxi/runtime/server.js b/packages/vinxi/runtime/server.js index adf4c515..bea2f153 100644 --- a/packages/vinxi/runtime/server.js +++ b/packages/vinxi/runtime/server.js @@ -97,6 +97,7 @@ import { toNodeListener, toPlainHandler, toWebHandler, + toWebRequest, unsealSession, updateSession, use, @@ -133,26 +134,6 @@ export function defineMiddleware(options) { return options; } -export function toWebRequest(/** @type {H3Event} */ event) { - /** - * @type {ReadableStream | undefined} - */ - let readableStream; - return new Request(getRequestURL(event), { - // @ts-ignore Undici option - duplex: "half", - method: event.method, - headers: event.headers, - get body() { - if (readableStream) { - return readableStream; - } - readableStream = getRequestWebStream(event); - return readableStream; - }, - }); -} - export { H3Error, H3Event, @@ -252,6 +233,7 @@ export { toNodeListener, toPlainHandler, toWebHandler, + toWebRequest, unsealSession, updateSession, use, From 4a59a05cb7889a618145411a69079285335076dd Mon Sep 17 00:00:00 2001 From: Davide <43080019+edivados@users.noreply.github.com> Date: Sat, 13 Jan 2024 00:52:01 +0100 Subject: [PATCH 2/7] Revert "restore h3's toWebRequest" This reverts commit 64cf3d7b427338aa03224d61a8a238b2e038c836. --- packages/vinxi/runtime/server.js | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/packages/vinxi/runtime/server.js b/packages/vinxi/runtime/server.js index bea2f153..adf4c515 100644 --- a/packages/vinxi/runtime/server.js +++ b/packages/vinxi/runtime/server.js @@ -97,7 +97,6 @@ import { toNodeListener, toPlainHandler, toWebHandler, - toWebRequest, unsealSession, updateSession, use, @@ -134,6 +133,26 @@ export function defineMiddleware(options) { return options; } +export function toWebRequest(/** @type {H3Event} */ event) { + /** + * @type {ReadableStream | undefined} + */ + let readableStream; + return new Request(getRequestURL(event), { + // @ts-ignore Undici option + duplex: "half", + method: event.method, + headers: event.headers, + get body() { + if (readableStream) { + return readableStream; + } + readableStream = getRequestWebStream(event); + return readableStream; + }, + }); +} + export { H3Error, H3Event, @@ -233,7 +252,6 @@ export { toNodeListener, toPlainHandler, toWebHandler, - toWebRequest, unsealSession, updateSession, use, From 4f596185bec97d14705e19cef18854fbc5463636 Mon Sep 17 00:00:00 2001 From: Davide <43080019+edivados@users.noreply.github.com> Date: Sat, 13 Jan 2024 01:57:20 +0100 Subject: [PATCH 3/7] add test showing pending request issue with toWebRequest --- pnpm-lock.yaml | 34 +- .../react-to-web-request/CHANGELOG.md | 435 ++++++++++++++++++ test/templates/react-to-web-request/README.md | 0 .../react-to-web-request/app.config.js | 24 + .../react-to-web-request/app/App.tsx | 14 + .../react-to-web-request/app/client.tsx | 5 + .../react-to-web-request/app/middleware.ts | 7 + .../templates/react-to-web-request/index.html | 13 + .../react-to-web-request/package.json | 24 + .../react-to-web-request/public/favicon.ico | Bin 0 -> 664 bytes .../react-to-web-request/tsconfig.json | 14 + test/to-web-request.test.ts | 43 ++ 12 files changed, 611 insertions(+), 2 deletions(-) create mode 100644 test/templates/react-to-web-request/CHANGELOG.md create mode 100644 test/templates/react-to-web-request/README.md create mode 100644 test/templates/react-to-web-request/app.config.js create mode 100644 test/templates/react-to-web-request/app/App.tsx create mode 100644 test/templates/react-to-web-request/app/client.tsx create mode 100644 test/templates/react-to-web-request/app/middleware.ts create mode 100644 test/templates/react-to-web-request/index.html create mode 100644 test/templates/react-to-web-request/package.json create mode 100644 test/templates/react-to-web-request/public/favicon.ico create mode 100644 test/templates/react-to-web-request/tsconfig.json create mode 100644 test/to-web-request.test.ts diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index bea4e4fd..d2990171 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1514,6 +1514,37 @@ importers: specifier: ^5.2.2 version: 5.2.2 + test/templates/react-to-web-request: + dependencies: + '@vinxi/react': + specifier: workspace:* + version: link:../../../packages/vinxi-react + '@vinxi/server-functions': + specifier: workspace:* + version: link:../../../packages/vinxi-server-functions + '@vitejs/plugin-react': + specifier: ^4.0.4 + version: 4.1.1(vite@4.5.0) + path-to-regexp: + specifier: ^6.2.1 + version: 6.2.1 + react: + specifier: 0.0.0-experimental-035a41c4e-20230704 + version: 0.0.0-experimental-035a41c4e-20230704 + react-dom: + specifier: 0.0.0-experimental-035a41c4e-20230704 + version: 0.0.0-experimental-035a41c4e-20230704(react@0.0.0-experimental-035a41c4e-20230704) + vinxi: + specifier: workspace:* + version: link:../../../packages/vinxi + devDependencies: + '@types/react': + specifier: ^18.2.21 + version: 18.2.37 + '@types/react-dom': + specifier: ^18.2.7 + version: 18.2.14 + packages: /@adobe/css-tools@4.3.1: @@ -1685,7 +1716,7 @@ packages: '@babel/helper-compilation-targets': 7.22.15 '@babel/helper-module-transforms': 7.23.0(@babel/core@7.23.2) '@babel/helpers': 7.23.2 - '@babel/parser': 7.23.0 + '@babel/parser': 7.23.5 '@babel/template': 7.22.15 '@babel/traverse': 7.23.2 '@babel/types': 7.23.0 @@ -1885,7 +1916,6 @@ packages: hasBin: true dependencies: '@babel/types': 7.23.0 - dev: false /@babel/plugin-syntax-jsx@7.22.5(@babel/core@7.23.2): resolution: {integrity: sha512-gvyP4hZrgrs/wWMaocvxZ44Hw0b3W8Pe+cMxc8V1ULQ07oh8VNbIRaoD1LRZVTvD+0nieDKjfgKg89sD7rrKrg==} diff --git a/test/templates/react-to-web-request/CHANGELOG.md b/test/templates/react-to-web-request/CHANGELOG.md new file mode 100644 index 00000000..e032d339 --- /dev/null +++ b/test/templates/react-to-web-request/CHANGELOG.md @@ -0,0 +1,435 @@ +# app + +## null + +### Patch Changes + +- Updated dependencies [769a055] +- Updated dependencies [08cd450] +- Updated dependencies [2e85423] +- Updated dependencies [bb16563] +- Updated dependencies [a011795] + - vinxi@0.1.2 + - @vinxi/react@0.1.1 + - @vinxi/server-functions@0.1.1 + +## null + +### Patch Changes + +- Updated dependencies [9c60b73] + - vinxi@0.1.1 + - @vinxi/react@0.1.0 + +## null + +### Patch Changes + +- Updated dependencies [e31abb2] +- Updated dependencies [b2ef06f] + - vinxi@0.1.0 + - @vinxi/react@0.1.0 + - @vinxi/server-functions@1.0.0 + +## null + +### Patch Changes + +- Updated dependencies [2c65c91] +- Updated dependencies [8c87b24] + - vinxi@0.0.64 + - @vinxi/react@0.0.12 + - @vinxi/server-functions@0.0.61 + +## null + +### Patch Changes + +- Updated dependencies [6f695e2] + - vinxi@0.0.63 + - @vinxi/react@0.0.12 + - @vinxi/server-functions@0.0.60 + +## null + +### Patch Changes + +- Updated dependencies [b236b2a] + - vinxi@0.0.62 + - @vinxi/react@0.0.12 + - @vinxi/server-functions@0.0.59 + +## null + +### Patch Changes + +- Updated dependencies [86982a4] +- Updated dependencies [b7332a6] + - @vinxi/server-functions@0.0.58 + - vinxi@0.0.61 + - @vinxi/react@0.0.12 + +## null + +### Patch Changes + +- Updated dependencies [1261c16] + - vinxi@0.0.60 + - @vinxi/react@0.0.12 + - @vinxi/server-functions@0.0.57 + +## null + +### Patch Changes + +- Updated dependencies [44f46ae] + - vinxi@0.0.59 + - @vinxi/react@0.0.12 + - @vinxi/server-functions@0.0.56 + +## null + +### Patch Changes + +- Updated dependencies [b654e60] + - vinxi@0.0.58 + - @vinxi/react@0.0.12 + - @vinxi/server-functions@0.0.55 + +## null + +### Patch Changes + +- Updated dependencies [ff03255] +- Updated dependencies [783d22b] +- Updated dependencies [0160b5c] + - vinxi@0.0.57 + - @vinxi/server-functions@0.0.54 + - @vinxi/react@0.0.12 + +## null + +### Patch Changes + +- Updated dependencies [d5262b3] +- Updated dependencies [5694f29] + - vinxi@0.0.56 + - @vinxi/react@0.0.12 + - @vinxi/server-functions@0.0.53 + +## null + +### Patch Changes + +- Updated dependencies [88201f3] +- Updated dependencies [cbba2d7] +- Updated dependencies [c5a94cf] +- Updated dependencies [e53f24a] +- Updated dependencies [9325a54] +- Updated dependencies [a0974f0] +- Updated dependencies [c4b76ed] +- Updated dependencies [7af0a15] + - vinxi@0.0.55 + - @vinxi/server-functions@0.0.52 + - @vinxi/react@0.0.12 + +## null + +### Patch Changes + +- Updated dependencies [7ec78e2] + - vinxi@0.0.54 + - @vinxi/react@0.0.12 + - @vinxi/server-functions@0.0.51 + +## null + +### Patch Changes + +- Updated dependencies [b601463] +- Updated dependencies [68cab94] + - vinxi@0.0.53 + - @vinxi/server-functions@0.0.50 + - @vinxi/react@0.0.12 + +## null + +### Patch Changes + +- Updated dependencies [366b29b] + - vinxi@0.0.52 + - @vinxi/react@0.0.12 + - @vinxi/server-functions@0.0.49 + +## null + +### Patch Changes + +- Updated dependencies [7276f73] + - vinxi@0.0.51 + - @vinxi/react@0.0.12 + - @vinxi/server-functions@0.0.48 + +## null + +### Patch Changes + +- Updated dependencies [e4a6251] + - vinxi@0.0.50 + - @vinxi/react@0.0.12 + - @vinxi/server-functions@0.0.47 + +## null + +### Patch Changes + +- Updated dependencies [0f9a5df] +- Updated dependencies [e6205a4] +- Updated dependencies [d8ef7c9] +- Updated dependencies [e7313f4] + - @vinxi/server-functions@0.0.46 + - vinxi@0.0.49 + - @vinxi/react@0.0.12 + +## null + +### Patch Changes + +- Updated dependencies [800f557] + - @vinxi/server-functions@0.0.45 + +## null + +### Patch Changes + +- @vinxi/server-functions@0.0.44 + +## null + +### Patch Changes + +- @vinxi/server-functions@0.0.43 + +## null + +### Patch Changes + +- @vinxi/server-functions@0.0.42 + +## null + +### Patch Changes + +- @vinxi/server-functions@0.0.41 + +## null + +### Patch Changes + +- Updated dependencies [fc7494d] +- Updated dependencies [4e4c047] +- Updated dependencies [8ef044b] + - vinxi@0.0.48 + - @vinxi/server-functions@0.0.40 + - @vinxi/react@0.0.12 + +## null + +### Patch Changes + +- Updated dependencies [8d24beb] + - vinxi@0.0.47 + - @vinxi/server-functions@0.0.39 + - @vinxi/react@0.0.12 + +## null + +### Patch Changes + +- Updated dependencies [978b04a] + - vinxi@0.0.43 + +## null + +### Patch Changes + +- Updated dependencies [e8fdad4] +- Updated dependencies [291a5cf] + - vinxi@0.0.42 + +## null + +### Patch Changes + +- Updated dependencies [2e52d87] + - vinxi@0.0.41 + +## null + +### Patch Changes + +- Updated dependencies [0335776] + - vinxi@0.0.40 + +## null + +### Patch Changes + +- Updated dependencies [f237894] +- Updated dependencies [d620072] + - vinxi@0.0.39 + +## null + +### Patch Changes + +- Updated dependencies [1284791] + - vinxi@0.0.38 + +## null + +### Patch Changes + +- Updated dependencies [6ff575e] +- Updated dependencies [f2cbc3c] +- Updated dependencies [b437331] +- Updated dependencies [e87800e] + - vinxi@0.0.37 + +## null + +### Patch Changes + +- Updated dependencies [49e4e03] +- Updated dependencies [a009733] + - vinxi@0.0.36 + +## null + +### Patch Changes + +- vinxi@0.0.35 + +## null + +### Patch Changes + +- Updated dependencies [355daea] + - vinxi@0.0.34 + +## null + +### Patch Changes + +- Updated dependencies [1dec590] + - vinxi@0.0.33 + +## null + +### Patch Changes + +- Updated dependencies [982147a] + - vinxi@0.0.32 + +## null + +### Patch Changes + +- Updated dependencies [94f59aa] +- Updated dependencies [bc82d8e] +- Updated dependencies [1d8b542] +- Updated dependencies [5bf5e03] +- Updated dependencies [4c7fd35] +- Updated dependencies [0f4b3ee] +- Updated dependencies [ad62318] +- Updated dependencies [c223ab6] +- Updated dependencies [94f59aa] + - vinxi@0.0.31 + - @vinxi/react@0.0.11 + +## null + +### Patch Changes + +- Updated dependencies [fd06048] +- Updated dependencies [0f14555] +- Updated dependencies [82267c5] + - vinxi@0.0.30 + - @vinxi/react@0.0.10 + +## null + +### Patch Changes + +- Updated dependencies [8058084] + - vinxi@0.0.29 + +## null + +### Patch Changes + +- Updated dependencies [b934e84] +- Updated dependencies [17693dc] +- Updated dependencies [d6305b8] +- Updated dependencies [cb91c48] +- Updated dependencies [085116d] +- Updated dependencies [f1ee5b8] + - vinxi@0.0.28 + +## null + +### Patch Changes + +- Updated dependencies [7803042] + - vinxi@0.0.27 + +## null + +### Patch Changes + +- Updated dependencies [2b17e0d] + - vinxi@0.0.26 + +## null + +### Patch Changes + +- Updated dependencies [552d8ca] + - vinxi@0.0.25 + +## null + +### Patch Changes + +- Updated dependencies [47abc3c] + - vinxi@0.0.24 + +## null + +### Patch Changes + +- Updated dependencies [ec37a2e] + - @vinxi/react@0.0.9 + +## null + +### Patch Changes + +- Updated dependencies [76da329] + - @vinxi/react@0.0.8 + +## null + +### Patch Changes + +- Updated dependencies [46f3426] + - @vinxi/react@0.0.7 + - vinxi@0.0.23 + +## null + +### Patch Changes + +- Updated dependencies [5834c1a] + - @vinxi/react@0.0.6 + - vinxi@0.0.22 diff --git a/test/templates/react-to-web-request/README.md b/test/templates/react-to-web-request/README.md new file mode 100644 index 00000000..e69de29b diff --git a/test/templates/react-to-web-request/app.config.js b/test/templates/react-to-web-request/app.config.js new file mode 100644 index 00000000..af778a85 --- /dev/null +++ b/test/templates/react-to-web-request/app.config.js @@ -0,0 +1,24 @@ +import reactRefresh from "@vitejs/plugin-react"; +import { serverFunctions } from "@vinxi/server-functions/plugin"; +import { createApp } from "vinxi"; + +export default createApp({ + routers: [ + { + name: "public", + mode: "static", + dir: "./public", + base: "/", + }, + { + name: "client", + mode: "spa", + handler: "./index.html", + target: "browser", + plugins: () => [serverFunctions.client(), reactRefresh()], + }, + serverFunctions.router({ + middleware: "./app/middleware.ts" + }) + ], +}); diff --git a/test/templates/react-to-web-request/app/App.tsx b/test/templates/react-to-web-request/app/App.tsx new file mode 100644 index 00000000..96a41359 --- /dev/null +++ b/test/templates/react-to-web-request/app/App.tsx @@ -0,0 +1,14 @@ +async function getData() { + "use server"; + console.log(`I have not been blocked.`); +} + +export function App() { + return ( +
+ +
+ ); +} diff --git a/test/templates/react-to-web-request/app/client.tsx b/test/templates/react-to-web-request/app/client.tsx new file mode 100644 index 00000000..1f24dbd9 --- /dev/null +++ b/test/templates/react-to-web-request/app/client.tsx @@ -0,0 +1,5 @@ +/// +import ReactDOM from "react-dom/client"; +import { App } from "./App"; + +ReactDOM.createRoot(document.getElementById("root")).render(); diff --git a/test/templates/react-to-web-request/app/middleware.ts b/test/templates/react-to-web-request/app/middleware.ts new file mode 100644 index 00000000..24fe6ee7 --- /dev/null +++ b/test/templates/react-to-web-request/app/middleware.ts @@ -0,0 +1,7 @@ +import { defineMiddleware, getRequestURL, toWebRequest } from "vinxi/server"; + +export default defineMiddleware({ + onRequest: event => { + toWebRequest(event); + } +}); \ No newline at end of file diff --git a/test/templates/react-to-web-request/index.html b/test/templates/react-to-web-request/index.html new file mode 100644 index 00000000..7a6d0b58 --- /dev/null +++ b/test/templates/react-to-web-request/index.html @@ -0,0 +1,13 @@ + + + + + + Document + + + +
+ + + \ No newline at end of file diff --git a/test/templates/react-to-web-request/package.json b/test/templates/react-to-web-request/package.json new file mode 100644 index 00000000..afd50997 --- /dev/null +++ b/test/templates/react-to-web-request/package.json @@ -0,0 +1,24 @@ +{ + "name": "test-react-to-web-request", + "type": "module", + "private": true, + "version": null, + "scripts": { + "dev": "vinxi dev", + "build": "vinxi build", + "start": "node .output/server/index.mjs" + }, + "dependencies": { + "@vinxi/react": "workspace:*", + "@vitejs/plugin-react": "^4.0.4", + "@vinxi/server-functions": "workspace:*", + "path-to-regexp": "^6.2.1", + "react": "0.0.0-experimental-035a41c4e-20230704", + "react-dom": "0.0.0-experimental-035a41c4e-20230704", + "vinxi": "workspace:*" + }, + "devDependencies": { + "@types/react": "^18.2.21", + "@types/react-dom": "^18.2.7" + } +} diff --git a/test/templates/react-to-web-request/public/favicon.ico b/test/templates/react-to-web-request/public/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..fb282da0719ef6ab4c1732df93be6216b0d85520 GIT binary patch literal 664 zcmV;J0%!e+P)m9ebk1R zejT~~6f_`?;`cEd!+`7(hw@%%2;?RN8gX-L?z6cM( zKoG@&w+0}f@Pfvwc+deid)qgE!L$ENKYjViZC_Zcr>L(`2oXUT8f0mRQ(6-=HN_Ai zeBBEz3WP+1Cw`m!49Wf!MnZzp5bH8VkR~BcJ1s-j90TAS2Yo4j!J|KodxYR%3Numw zA?gq6e`5@!W~F$_De3yt&uspo&2yLb$(NwcPPI-4LGc!}HdY%jfq@AFs8LiZ4k(p} zZ!c9o+qbWYs-Mg zgdyTALzJX&7QXHdI_DPTFL33;w}88{e6Zk)MX0kN{3DX9uz#O_L58&XRH$Nvvu;fO zf&)7@?C~$z1K<>j0ga$$MIg+5xN;eQ?1-CA=`^Y169@Ab6!vcaNP=hxfKN%@Ly^R* zK1iv*s1Yl6_dVyz8>ZqYhz6J4|3fQ@2LQeX@^%W(B~8>=MoEmBEGGD1;gHXlpX>!W ym)!leA2L@`cpb^hy)P75=I!`pBYxP7<2VfQ3j76qLgzIA0000 { + let fixture: Fixture; + let appFixture: AppFixture; + + test.beforeAll(async () => { + fixture = await createDevFixture({ + files: {}, + template: "react-to-web-request", + }); + + appFixture = await fixture.createServer(); + }); + + test.afterAll(async () => { + await appFixture.close(); + }); + + let logs: string[] = []; + + test.beforeEach(({ page }) => { + page.on("console", (msg) => { + logs.push(msg.text()); + }); + }); + + test("readBody call after toWebRequest does not block", async ({ page }) => { + let app = new PlaywrightFixture(appFixture, page); + await app.goto("/", true); + + const el = await page.$("[data-test-id=button]"); + await el.click(); + + const responses = app.collectResponses(); + await (new Promise(resolve => setTimeout(resolve, 200))); + test.expect(responses.length).toBe(1); + }); +}); + From 02142f593b401557af9c2135ec52eadd687cc118 Mon Sep 17 00:00:00 2001 From: Davide <43080019+edivados@users.noreply.github.com> Date: Sat, 13 Jan 2024 02:23:08 +0100 Subject: [PATCH 4/7] patch toWebRequest --- packages/vinxi/runtime/server.js | 30 ++++++++----------- .../react-to-web-request/app/middleware.ts | 2 +- 2 files changed, 13 insertions(+), 19 deletions(-) diff --git a/packages/vinxi/runtime/server.js b/packages/vinxi/runtime/server.js index adf4c515..02a432a4 100644 --- a/packages/vinxi/runtime/server.js +++ b/packages/vinxi/runtime/server.js @@ -97,6 +97,7 @@ import { toNodeListener, toPlainHandler, toWebHandler, + toWebRequest as toWebRequestH3, unsealSession, updateSession, use, @@ -133,24 +134,17 @@ export function defineMiddleware(options) { return options; } -export function toWebRequest(/** @type {H3Event} */ event) { - /** - * @type {ReadableStream | undefined} - */ - let readableStream; - return new Request(getRequestURL(event), { - // @ts-ignore Undici option - duplex: "half", - method: event.method, - headers: event.headers, - get body() { - if (readableStream) { - return readableStream; - } - readableStream = getRequestWebStream(event); - return readableStream; - }, - }); +/** + * @param {H3Event} event + * @returns {Request} + */ +export function toWebRequest(event) { + event.web ??= { + request: toWebRequestH3(event), + url: getRequestURL(event) + }; + // @ts-ignore + return event.web.request; } export { diff --git a/test/templates/react-to-web-request/app/middleware.ts b/test/templates/react-to-web-request/app/middleware.ts index 24fe6ee7..52e93471 100644 --- a/test/templates/react-to-web-request/app/middleware.ts +++ b/test/templates/react-to-web-request/app/middleware.ts @@ -1,4 +1,4 @@ -import { defineMiddleware, getRequestURL, toWebRequest } from "vinxi/server"; +import { defineMiddleware, toWebRequest } from "vinxi/server"; export default defineMiddleware({ onRequest: event => { From a725c692342b70a48e9bf30305ab1b772e666741 Mon Sep 17 00:00:00 2001 From: Davide <43080019+edivados@users.noreply.github.com> Date: Sat, 13 Jan 2024 03:08:55 +0100 Subject: [PATCH 5/7] remove jsdoc from toWebRequest --- packages/vinxi/runtime/server.js | 5 ----- 1 file changed, 5 deletions(-) diff --git a/packages/vinxi/runtime/server.js b/packages/vinxi/runtime/server.js index 02a432a4..14e55097 100644 --- a/packages/vinxi/runtime/server.js +++ b/packages/vinxi/runtime/server.js @@ -134,16 +134,11 @@ export function defineMiddleware(options) { return options; } -/** - * @param {H3Event} event - * @returns {Request} - */ export function toWebRequest(event) { event.web ??= { request: toWebRequestH3(event), url: getRequestURL(event) }; - // @ts-ignore return event.web.request; } From fd5740c1d68aede3440d9bbfe3ad2a3706a1b6ef Mon Sep 17 00:00:00 2001 From: Nikhil Saraf Date: Sun, 14 Jan 2024 15:22:00 +0530 Subject: [PATCH 6/7] Create twelve-falcons-hang.md --- .changeset/twelve-falcons-hang.md | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 .changeset/twelve-falcons-hang.md diff --git a/.changeset/twelve-falcons-hang.md b/.changeset/twelve-falcons-hang.md new file mode 100644 index 00000000..04e04d13 --- /dev/null +++ b/.changeset/twelve-falcons-hang.md @@ -0,0 +1,7 @@ +--- +"vinxi": patch +"test-react-to-web-request": patch +"test-react": patch +--- + +fix: non-blocking `readBody` with web requests From 432013cd223b8c96d25c29e21fb8c15d81c70bd1 Mon Sep 17 00:00:00 2001 From: Nikhil Saraf Date: Sun, 14 Jan 2024 16:34:57 +0530 Subject: [PATCH 7/7] fix server.js --- packages/vinxi/runtime/server.js | 482 ++++++++++++++++--------------- 1 file changed, 247 insertions(+), 235 deletions(-) diff --git a/packages/vinxi/runtime/server.js b/packages/vinxi/runtime/server.js index 5e199eaf..e34c9556 100644 --- a/packages/vinxi/runtime/server.js +++ b/packages/vinxi/runtime/server.js @@ -51,8 +51,7 @@ import { getResponseStatus, getResponseStatusText, getRouterParam, - getRouterParams, - getSession, + getRouterParams, // getSession, getValidatedQuery, getValidatedRouterParams, handleCacheHeaders, @@ -76,8 +75,7 @@ import { readValidatedBody, removeResponseHeader, sanitizeStatusCode, - sanitizeStatusMessage, - sealSession, + sanitizeStatusMessage, // sealSession, send, sendError, sendNoContent, @@ -98,11 +96,9 @@ import { toPlainHandler, toWebHandler, toWebRequest as toWebRequestH3, - unsealSession, - updateSession, + unsealSession, // updateSession, use, - useBase, - useSession, + useBase, // useSession, writeEarlyHints, } from "h3"; import { seal, defaults as sealDefaults } from "iron-webcrypto"; @@ -115,7 +111,7 @@ import crypto from "uncrypto"; * @param {any} value */ export function setContext(event, key, value) { - event.context[key] = value; + event.context[key] = value; } /** @@ -124,7 +120,7 @@ export function setContext(event, key, value) { * @param {string} key */ export function getContext(event, key) { - return event.context[key]; + return event.context[key]; } /** @@ -133,251 +129,267 @@ export function getContext(event, key) { * @returns */ export function defineMiddleware(options) { - return options; + return options; } -export function toWebRequest(event) { +export function toWebRequest(/** @type {import('h3').H3Event} */ event) { event.web ??= { request: toWebRequestH3(event), - url: getRequestURL(event) + url: getRequestURL(event), }; return event.web.request; } const DEFAULT_NAME = "h3"; const DEFAULT_COOKIE = { - path: "/", - secure: true, - httpOnly: true, + path: "/", + secure: true, + httpOnly: true, }; -export async function useSession(event, config) { - // Create a synced wrapper around the session - const sessionName = config.name || DEFAULT_NAME; - await getSession(event, config); // Force init - const sessionManager = { - get id() { - return event.context.sessions?.[sessionName]?.id; - }, - get data() { - return (event.context.sessions?.[sessionName]?.data || {}); - }, - update: async (update) => { - await updateSession(event, config, update); - return sessionManager; - }, - clear: async () => { - await clearSession(event, config); - return sessionManager; - }, - }; - return sessionManager; +export async function useSession( + /** @type {import('h3').H3Event} */ event, + /** @type {import('h3').SessionConfig} */ config, +) { + // Create a synced wrapper around the session + const sessionName = config.name || DEFAULT_NAME; + await getSession(event, config); // Force init + + /** @type {Awaited>} */ + const sessionManager = { + get id() { + return event.context.sessions?.[sessionName]?.id; + }, + get data() { + return event.context.sessions?.[sessionName]?.data || {}; + }, + update: async (update) => { + await updateSession(event, config, update); + return sessionManager; + }, + clear: async () => { + await clearSession(event, config); + return sessionManager; + }, + }; + return sessionManager; } -export async function getSession(event, config) { - const sessionName = config.name || DEFAULT_NAME; - // Return existing session if available - if (!event.context.sessions) { - event.context.sessions = Object.create(null); - } - if (!event.context.sessionLocks) { - event.context.sessionLocks = Object.create(null); - } - // Wait for existing session to load - if (event.context.sessionLocks[sessionName]) { - await event.context.sessionLocks[sessionName]; - } - if (event.context.sessions[sessionName]) { - return event.context.sessions[sessionName]; - } - // Prepare an empty session object and store in context - const session = { - id: "", - createdAt: 0, - data: Object.create(null), - }; - event.context.sessions[sessionName] = session; - // Try to load session - let sealedSession; - // Try header first - if (config.sessionHeader !== false) { - const headerName = typeof config.sessionHeader === "string" - ? config.sessionHeader.toLowerCase() - : `x-${sessionName.toLowerCase()}-session`; - const headerValue = event.node.req.headers[headerName]; - if (typeof headerValue === "string") { - sealedSession = headerValue; - } - } - // Fallback to cookies - if (!sealedSession) { - sealedSession = getCookie(event, sessionName); - } - if (sealedSession) { - // Unseal session data from cookie - const lock = unsealSession(event, config, sealedSession) - .catch(() => {}) - .then((unsealed) => { - Object.assign(session, unsealed); - // make sure deletion occurs before promise resolves - delete event.context.sessionLocks[sessionName]; - }); +export async function getSession( + /** @type {import('h3').H3Event} */ event, + /** @type {import('h3').SessionConfig} */ config, +) { + const sessionName = config.name || DEFAULT_NAME; + // Return existing session if available + if (!event.context.sessions) { + event.context.sessions = Object.create(null); + } + if (!event.context.sessionLocks) { + event.context.sessionLocks = Object.create(null); + } + // Wait for existing session to load + if (event.context.sessionLocks[sessionName]) { + await event.context.sessionLocks[sessionName]; + } + if (event.context.sessions[sessionName]) { + return event.context.sessions[sessionName]; + } + // Prepare an empty session object and store in context + const session = { + id: "", + createdAt: 0, + data: Object.create(null), + }; + event.context.sessions[sessionName] = session; + // Try to load session + let sealedSession; + // Try header first + if (config.sessionHeader !== false) { + const headerName = + typeof config.sessionHeader === "string" + ? config.sessionHeader.toLowerCase() + : `x-${sessionName.toLowerCase()}-session`; + const headerValue = event.node.req.headers[headerName]; + if (typeof headerValue === "string") { + sealedSession = headerValue; + } + } + // Fallback to cookies + if (!sealedSession) { + sealedSession = getCookie(event, sessionName); + } + if (sealedSession) { + // Unseal session data from cookie + const lock = unsealSession(event, config, sealedSession) + .catch(() => {}) + .then((unsealed) => { + Object.assign(session, unsealed); + // make sure deletion occurs before promise resolves + delete event.context.sessionLocks[sessionName]; + }); - event.context.sessionLocks[sessionName] = lock; - await lock; - } - // New session store in response cookies - if (!session.id) { - session.id = - config.generateId?.() ?? (config.crypto || crypto).randomUUID(); - session.createdAt = Date.now(); - await updateSession(event, config); - } - return session; + event.context.sessionLocks[sessionName] = lock; + await lock; + } + // New session store in response cookies + if (!session.id) { + session.id = + config.generateId?.() ?? (config.crypto || crypto).randomUUID(); + session.createdAt = Date.now(); + await updateSession(event, config); + } + return session; } -export async function updateSession(event, config, update) { - const sessionName = config.name || DEFAULT_NAME; - // Access current session - const session = event.context.sessions?.[sessionName] || - (await getSession(event, config)); - // Update session data if provided - if (typeof update === "function") { - update = update(session.data); - } - if (update) { - Object.assign(session.data, update); - } - // Seal and store in cookie - if (config.cookie !== false) { - const sealed = await sealSession(event, config); - setCookie(event, sessionName, sealed, { - ...DEFAULT_COOKIE, - expires: config.maxAge - ? new Date(session.createdAt + config.maxAge * 1000) - : undefined, - ...config.cookie, - }); - } - return session; +export async function updateSession( + /** @type {import('h3').H3Event} */ event, + /** @type {import('h3').SessionConfig} */ config, + update, +) { + const sessionName = config.name || DEFAULT_NAME; + // Access current session + const session = + event.context.sessions?.[sessionName] || (await getSession(event, config)); + // Update session data if provided + if (typeof update === "function") { + update = update(session.data); + } + if (update) { + Object.assign(session.data, update); + } + // Seal and store in cookie + if (config.cookie !== false) { + const sealed = await sealSession(event, config); + setCookie(event, sessionName, sealed, { + ...DEFAULT_COOKIE, + expires: config.maxAge + ? new Date(session.createdAt + config.maxAge * 1000) + : undefined, + ...config.cookie, + }); + } + return session; } -export async function sealSession(event, config) { - const sessionName = config.name || DEFAULT_NAME; - // Access current session - const session = event.context.sessions?.[sessionName] || - (await getSession(event, config)); - const sealed = await seal(config.crypto || crypto, session, config.password, { - ...sealDefaults, - ttl: config.maxAge ? config.maxAge * 1000 : 0, - ...config.seal, - }); - return sealed; +export async function sealSession( + /** @type {import('h3').H3Event} */ event, + /** @type {import('h3').SessionConfig} */ config, +) { + const sessionName = config.name || DEFAULT_NAME; + // Access current session + const session = + event.context.sessions?.[sessionName] || (await getSession(event, config)); + const sealed = await seal(config.crypto || crypto, session, config.password, { + ...sealDefaults, + ttl: config.maxAge ? config.maxAge * 1000 : 0, + ...config.seal, + }); + return sealed; } export { - H3Error, - H3Event, - MIMES, - appendCorsHeaders, - appendCorsPreflightHeaders, - appendHeader, - appendHeaders, - appendResponseHeader, - appendResponseHeaders, - assertMethod, - callNodeListener, - clearResponseHeaders, - clearSession, - createApp, - createAppEventHandler, - createError, - createEvent, - createRouter, - defaultContentType, - defineEventHandler, - defineLazyEventHandler, - defineNodeListener, - defineNodeMiddleware, - defineRequestMiddleware, - defineResponseMiddleware, - deleteCookie, - dynamicEventHandler, - eventHandler, - fetchWithEvent, - fromNodeMiddleware, - fromPlainHandler, - fromWebHandler, - getCookie, - getHeader, - getHeaders, - getMethod, - getProxyRequestHeaders, - getQuery, - getRequestFingerprint, - getRequestHeader, - getRequestHeaders, - getRequestHost, - getRequestIP, - getRequestPath, - getRequestProtocol, - getRequestURL, - getRequestWebStream, - getResponseHeader, - getResponseHeaders, - getResponseStatus, - getResponseStatusText, - getRouterParam, - getRouterParams, - // getSession, - getValidatedQuery, - getValidatedRouterParams, - handleCacheHeaders, - handleCors, - isCorsOriginAllowed, - isError, - isEvent, - isEventHandler, - isMethod, - isPreflightRequest, - isStream, - isWebResponse, - lazyEventHandler, - parseCookies, - promisifyNodeListener, - proxyRequest, - readBody, - readFormData, - readMultipartFormData, - readRawBody, - readValidatedBody, - removeResponseHeader, - sanitizeStatusCode, - sanitizeStatusMessage, - // sealSession, - send, - sendError, - sendNoContent, - sendProxy, - sendRedirect, - sendStream, - sendWebResponse, - serveStatic, - setCookie, - setHeader, - setHeaders, - setResponseHeader, - setResponseHeaders, - setResponseStatus, - splitCookiesString, - toEventHandler, - toNodeListener, - toPlainHandler, - toWebHandler, - unsealSession, - // updateSession, - use, - useBase, - // useSession, - writeEarlyHints, + H3Error, + H3Event, + MIMES, + appendCorsHeaders, + appendCorsPreflightHeaders, + appendHeader, + appendHeaders, + appendResponseHeader, + appendResponseHeaders, + assertMethod, + callNodeListener, + clearResponseHeaders, + clearSession, + createApp, + createAppEventHandler, + createError, + createEvent, + createRouter, + defaultContentType, + defineEventHandler, + defineLazyEventHandler, + defineNodeListener, + defineNodeMiddleware, + defineRequestMiddleware, + defineResponseMiddleware, + deleteCookie, + dynamicEventHandler, + eventHandler, + fetchWithEvent, + fromNodeMiddleware, + fromPlainHandler, + fromWebHandler, + getCookie, + getHeader, + getHeaders, + getMethod, + getProxyRequestHeaders, + getQuery, + getRequestFingerprint, + getRequestHeader, + getRequestHeaders, + getRequestHost, + getRequestIP, + getRequestPath, + getRequestProtocol, + getRequestURL, + getRequestWebStream, + getResponseHeader, + getResponseHeaders, + getResponseStatus, + getResponseStatusText, + getRouterParam, + getRouterParams, + // getSession, + getValidatedQuery, + getValidatedRouterParams, + handleCacheHeaders, + handleCors, + isCorsOriginAllowed, + isError, + isEvent, + isEventHandler, + isMethod, + isPreflightRequest, + isStream, + isWebResponse, + lazyEventHandler, + parseCookies, + promisifyNodeListener, + proxyRequest, + readBody, + readFormData, + readMultipartFormData, + readRawBody, + readValidatedBody, + removeResponseHeader, + sanitizeStatusCode, + sanitizeStatusMessage, + // sealSession, + send, + sendError, + sendNoContent, + sendProxy, + sendRedirect, + sendStream, + sendWebResponse, + serveStatic, + setCookie, + setHeader, + setHeaders, + setResponseHeader, + setResponseHeaders, + setResponseStatus, + splitCookiesString, + toEventHandler, + toNodeListener, + toPlainHandler, + toWebHandler, + unsealSession, + // updateSession, + use, + useBase, + // useSession, + writeEarlyHints, };