From 0136df7ad930456820eeba872455c69c6f7fc716 Mon Sep 17 00:00:00 2001 From: Kirill Konshin Date: Tue, 5 Nov 2024 09:51:43 -0800 Subject: [PATCH] Fixed potential race condition, Iron Session usage in demo Mention #2 --- demo/package.json | 1 + demo/src/app/client.tsx | 16 +++++++++------- demo/src/app/test/route.ts | 14 +++++++++++++- lib/package.json | 5 +++-- lib/src/index.ts | 38 +++++++++++++++++++++++--------------- yarn.lock | 26 ++++++++++++++++++++++++++ 6 files changed, 75 insertions(+), 25 deletions(-) diff --git a/demo/package.json b/demo/package.json index 271fca1..0e1bb70 100644 --- a/demo/package.json +++ b/demo/package.json @@ -20,6 +20,7 @@ "license": "ISC", "dependencies": { "electron-default-menu": "^1.0.2", + "iron-session": "^8.0.3", "next-electron-rsc": "*", "react": "^18.3.1", "react-dom": "^18.3.1" diff --git a/demo/src/app/client.tsx b/demo/src/app/client.tsx index 4f92d36..be2879f 100644 --- a/demo/src/app/client.tsx +++ b/demo/src/app/client.tsx @@ -4,13 +4,13 @@ import { useEffect, useState } from 'react'; import Image from 'next/image'; export default function Client({ foo }) { - const [text, setText] = useState(); + const [json, setJson] = useState(); const [cookie, setCookie] = useState(); useEffect(() => { fetch('/test', { method: 'POST', body: 'Hello from frontend!' }) - .then((res) => res.text()) - .then((text) => setText(text)); + .then((res) => res.json()) + .then((text) => setJson(text)); }, []); useEffect(() => { @@ -18,14 +18,16 @@ export default function Client({ foo }) { }, []); return ( -
- Server: {foo}, API: {text} +
+            Server action: {foo}
             
- Cookie: {cookie} + API response: {JSON.stringify(json, null, 2)} +
+ Frontend cookie: {cookie}
Next Electron RSC
Next Electron RSC -
+ ); } diff --git a/demo/src/app/test/route.ts b/demo/src/app/test/route.ts index 04b1731..de9300d 100644 --- a/demo/src/app/test/route.ts +++ b/demo/src/app/test/route.ts @@ -1,11 +1,18 @@ import { NextRequest, NextResponse } from 'next/server'; +import { cookies } from 'next/headers'; +import { getIronSession } from 'iron-session'; export const dynamic = 'force-dynamic'; +const password = '3YiABv0hXEjwD1Pof36HJUpW4HW7dQAG'; + export async function POST(req: NextRequest) { const iteration = parseInt(req.cookies.get('iteration')?.value, 10) || 0; - const res = NextResponse.json({ message: 'Hello from Next.js! in response to ' + (await req.text()) }); + const res = NextResponse.json({ + message: 'Hello from Next.js! in response to ' + (await req.text()), + cookies: (await cookies()).getAll(), + }); res.cookies.set('iteration', (iteration + 1).toString(), { path: '/', @@ -22,5 +29,10 @@ export async function POST(req: NextRequest) { maxAge: 60 * 60, // 1 hour }); + // const session = await getIronSession(req, res, { password, cookieName: 'iron' }); + const session = await getIronSession(await cookies(), { password, cookieName: 'iron' }); + session['username'] = 'Alison'; + await session.save(); + return res; } diff --git a/lib/package.json b/lib/package.json index cc6a89b..3d2cd4d 100644 --- a/lib/package.json +++ b/lib/package.json @@ -1,6 +1,6 @@ { "name": "next-electron-rsc", - "version": "0.2.1", + "version": "0.2.2", "description": "Next.js + Electron + React Server Components", "main": "build/index.js", "main:src": "build/index.tsx", @@ -11,7 +11,8 @@ "scripts": { "clean": "rm -rf build .tscache", "build": "tsc --build .", - "start": "yarn build --watch --preserveWatchOutput" + "start": "yarn build --watch --preserveWatchOutput", + "prepublishOnly": "yarn build" }, "license": "MIT", "dependencies": { diff --git a/lib/src/index.ts b/lib/src/index.ts index 4ba7760..d081743 100644 --- a/lib/src/index.ts +++ b/lib/src/index.ts @@ -71,23 +71,12 @@ async function createRequest({ } class ReadableServerResponse extends ServerResponse { - write(chunk: any, ...args): boolean { - this.emit('data', chunk); - return super.write(chunk, ...args); - } - - end(chunk: any, ...args): this { - this.emit('end', chunk); - return super.end(chunk, ...args); - } + private responsePromise: Promise; - writeHead(statusCode: number, ...args: any): this { - this.emit('writeHead', statusCode); - return super.writeHead(statusCode, ...args); - } + constructor(req: IncomingMessage) { + super(req); - getResponse() { - return new Promise((resolve, reject) => { + this.responsePromise = new Promise((resolve, reject) => { const readableStream = new ReadableStream({ start: (controller) => { let onData; @@ -122,6 +111,25 @@ class ReadableServerResponse extends ServerResponse { }); }); } + + write(chunk: any, ...args): boolean { + this.emit('data', chunk); + return super.write(chunk, ...args); + } + + end(chunk: any, ...args): this { + this.emit('end', chunk); + return super.end(chunk, ...args); + } + + writeHead(statusCode: number, ...args: any): this { + this.emit('writeHead', statusCode); + return super.writeHead(statusCode, ...args); + } + + getResponse() { + return this.responsePromise; + } } /** diff --git a/yarn.lock b/yarn.lock index 4e18d78..329a9d2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2175,6 +2175,7 @@ __metadata: electron: "npm:33.0.2" electron-builder: "npm:^25.1.8" electron-default-menu: "npm:^1.0.2" + iron-session: "npm:^8.0.3" next: "npm:^15.0.2" next-electron-rsc: "npm:*" react: "npm:^18.3.1" @@ -3890,6 +3891,24 @@ __metadata: languageName: node linkType: hard +"iron-session@npm:^8.0.3": + version: 8.0.3 + resolution: "iron-session@npm:8.0.3" + dependencies: + cookie: "npm:0.6.0" + iron-webcrypto: "npm:1.2.1" + uncrypto: "npm:0.1.3" + checksum: 10/73befd8333e8090cdab3756c8de4ed374ac3c9b20fa0ca44ad28f6031649052edacd0f0d6cfe87147cb8fb2b7b9d4d88a41f667ad703e84ac20c05a938ac6bc9 + languageName: node + linkType: hard + +"iron-webcrypto@npm:1.2.1": + version: 1.2.1 + resolution: "iron-webcrypto@npm:1.2.1" + checksum: 10/c1f52ccfe2780efa5438c134538ee4b26c96a87d22f351d896781219efbce25b4fe716d1cb7f248e02da96881760541135acbcc7c0622ffedf71cb0e227bebf9 + languageName: node + linkType: hard + "is-array-buffer@npm:^3.0.4": version: 3.0.4 resolution: "is-array-buffer@npm:3.0.4" @@ -7056,6 +7075,13 @@ __metadata: languageName: node linkType: hard +"uncrypto@npm:0.1.3": + version: 0.1.3 + resolution: "uncrypto@npm:0.1.3" + checksum: 10/0020f74b0ce34723196d8982a73bb7f40cff455a41b8f88ae146b86885f4e66e41a1241fe80a887505c3bd2c7f07ed362b6ed041968370073c40a98496e6a737 + languageName: node + linkType: hard + "undici-types@npm:~6.19.2, undici-types@npm:~6.19.8": version: 6.19.8 resolution: "undici-types@npm:6.19.8"