Compare commits
4 Commits
2ece8b7587
...
3d519ce9a7
Author | SHA1 | Date |
---|---|---|
|
3d519ce9a7 | |
|
bed23c62f5 | |
|
b8453438b6 | |
|
f46705474f |
|
@ -117,6 +117,81 @@ const useSession = () => {
|
|||
|
||||
For more details on how to Popup Oauth Login see [example](https://github.com/divyam234/next-auth-hono-react)
|
||||
|
||||
## Middleware
|
||||
|
||||
You can separate this code into another file, say `auth.config.ts`:
|
||||
|
||||
```ts
|
||||
function getAuthConfig(c: Context): AuthConfig {
|
||||
return {
|
||||
secret: c.env.AUTH_SECRET,
|
||||
providers: [
|
||||
GitHub({
|
||||
clientId: c.env.GITHUB_ID,
|
||||
clientSecret: c.env.GITHUB_SECRET,
|
||||
}),
|
||||
],
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Use the same config in `middleware.ts`
|
||||
|
||||
```ts
|
||||
import { getAuthConfig } from '@/auth.config'
|
||||
import { getAuthUser, initAuthConfig } from '@hono/auth-js'
|
||||
import { Hono } from 'hono'
|
||||
import { handle } from 'hono/vercel'
|
||||
import { NextResponse } from 'next/server'
|
||||
|
||||
const app = new Hono()
|
||||
|
||||
// shared config
|
||||
app.use('*', initAuthConfig(getAuthConfig))
|
||||
|
||||
app.all('*', async (c) => {
|
||||
// Retrieve the user & session
|
||||
const authUser = await getAuthUser(c)
|
||||
|
||||
const pathname = new URL(c.req.url).pathname
|
||||
const isAuthenticated = !!authUser?.session
|
||||
|
||||
// Specific to Auth.js (may vary if customized)
|
||||
const isApiAuthRoute = pathname.startsWith('/api/auth')
|
||||
|
||||
const isPublicRoute = ['/'].includes(pathname)
|
||||
const isAuthRoute = ['/sign-in'].includes(pathname)
|
||||
|
||||
if (isApiAuthRoute) return NextResponse.next()
|
||||
|
||||
if (isAuthRoute) {
|
||||
if (isAuthenticated) {
|
||||
return Response.redirect(new URL('/protected', c.req.url))
|
||||
}
|
||||
return NextResponse.next()
|
||||
}
|
||||
|
||||
if (!isAuthenticated && !isPublicRoute) {
|
||||
return Response.redirect(new URL('/sign-in', c.req.url))
|
||||
}
|
||||
|
||||
return NextResponse.next()
|
||||
})
|
||||
|
||||
export default handle(app)
|
||||
|
||||
export const config = {
|
||||
matcher: ['/((?!.+\\.[\\w]+$|_next).*)', '/', '/(api|trpc)(.*)'],
|
||||
}
|
||||
```
|
||||
|
||||
Middleware setup repo: https://github.com/mohit4bug/nextjs-hono-authjs
|
||||
|
||||
## Author
|
||||
|
||||
Divyam <https://github.com/divyam234>
|
||||
|
||||
## Contributors
|
||||
|
||||
- Mohit <https://github.com/mohit4bug>
|
||||
- Updated the README.md to include additional details about using middleware.
|
|
@ -1,5 +1,11 @@
|
|||
# @hono/node-ws
|
||||
|
||||
## 1.1.4
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1146](https://github.com/honojs/middleware/pull/1146) [`b8453438b66fc9a6af58e33593e9fa21a96c02a7`](https://github.com/honojs/middleware/commit/b8453438b66fc9a6af58e33593e9fa21a96c02a7) Thanks [@nakasyou](https://github.com/nakasyou)! - enhance WebSocket connection handling with CORS support and connection symbols
|
||||
|
||||
## 1.1.3
|
||||
|
||||
### Patch Changes
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@hono/node-ws",
|
||||
"version": "1.1.3",
|
||||
"version": "1.1.4",
|
||||
"description": "WebSocket helper for Node.js",
|
||||
"type": "module",
|
||||
"main": "dist/index.js",
|
||||
|
|
|
@ -3,6 +3,7 @@ import { serve } from '@hono/node-server'
|
|||
// @ts-ignore
|
||||
import type { ServerType } from '@hono/node-server/dist/types'
|
||||
import { Hono } from 'hono'
|
||||
import { cors } from 'hono/cors'
|
||||
import type { WSMessageReceive } from 'hono/ws'
|
||||
import { WebSocket } from 'ws'
|
||||
import { createNodeWebSocket } from '.'
|
||||
|
@ -244,4 +245,42 @@ describe('WebSocket helper', () => {
|
|||
createNodeWebSocket({ app })
|
||||
})
|
||||
})
|
||||
|
||||
it('Should client can connect when use cors()', async () => {
|
||||
app.use(cors())
|
||||
const mainPromise = new Promise<boolean>((resolve) =>
|
||||
app.get(
|
||||
'/',
|
||||
upgradeWebSocket(() => ({
|
||||
onOpen() {
|
||||
resolve(true)
|
||||
},
|
||||
}))
|
||||
)
|
||||
)
|
||||
|
||||
new WebSocket('ws://localhost:3030/')
|
||||
|
||||
expect(await mainPromise).toBe(true)
|
||||
})
|
||||
it('Should client can connect even if a response has difference', async () => {
|
||||
app.use(async (c, next) => {
|
||||
c.res = new Response(null, c.res)
|
||||
await next()
|
||||
})
|
||||
const mainPromise = new Promise<boolean>((resolve) =>
|
||||
app.get(
|
||||
'/',
|
||||
upgradeWebSocket(() => ({
|
||||
onOpen() {
|
||||
resolve(true)
|
||||
},
|
||||
}))
|
||||
)
|
||||
)
|
||||
|
||||
new WebSocket('ws://localhost:3030/')
|
||||
|
||||
expect(await mainPromise).toBe(true)
|
||||
})
|
||||
})
|
||||
|
|
|
@ -23,6 +23,11 @@ export interface NodeWebSocketInit {
|
|||
baseUrl?: string | URL
|
||||
}
|
||||
|
||||
const generateConnectionSymbol = () => Symbol('connection')
|
||||
|
||||
/** @example `c.env[CONNECTION_SYMBOL_KEY]` */
|
||||
const CONNECTION_SYMBOL_KEY: unique symbol = Symbol('CONNECTION_SYMBOL_KEY')
|
||||
|
||||
/**
|
||||
* Create WebSockets for Node.js
|
||||
* @param init Options
|
||||
|
@ -32,7 +37,7 @@ export const createNodeWebSocket = (init: NodeWebSocketInit): NodeWebSocket => {
|
|||
const wss = new WebSocketServer({ noServer: true })
|
||||
const waiterMap = new Map<
|
||||
IncomingMessage,
|
||||
{ resolve: (ws: WebSocket) => void; response: Response }
|
||||
{ resolve: (ws: WebSocket) => void; connectionSymbol: symbol }
|
||||
>()
|
||||
|
||||
wss.on('connection', (ws, request) => {
|
||||
|
@ -43,9 +48,9 @@ export const createNodeWebSocket = (init: NodeWebSocketInit): NodeWebSocket => {
|
|||
}
|
||||
})
|
||||
|
||||
const nodeUpgradeWebSocket = (request: IncomingMessage, response: Response) => {
|
||||
const nodeUpgradeWebSocket = (request: IncomingMessage, connectionSymbol: symbol) => {
|
||||
return new Promise<WebSocket>((resolve) => {
|
||||
waiterMap.set(request, { resolve, response })
|
||||
waiterMap.set(request, { resolve, connectionSymbol })
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -62,14 +67,18 @@ export const createNodeWebSocket = (init: NodeWebSocketInit): NodeWebSocket => {
|
|||
headers.append(key, Array.isArray(value) ? value[0] : value)
|
||||
}
|
||||
|
||||
const response = await init.app.request(
|
||||
url,
|
||||
{ headers: headers },
|
||||
{ incoming: request, outgoing: undefined }
|
||||
)
|
||||
|
||||
const env: {
|
||||
incoming: IncomingMessage
|
||||
outgoing: undefined
|
||||
[CONNECTION_SYMBOL_KEY]?: symbol
|
||||
} = {
|
||||
incoming: request,
|
||||
outgoing: undefined,
|
||||
}
|
||||
await init.app.request(url, { headers: headers }, env)
|
||||
const waiter = waiterMap.get(request)
|
||||
if (!waiter || waiter.response !== response) {
|
||||
|
||||
if (!waiter || waiter.connectionSymbol !== env[CONNECTION_SYMBOL_KEY]) {
|
||||
socket.end(
|
||||
'HTTP/1.1 400 Bad Request\r\n' +
|
||||
'Connection: close\r\n' +
|
||||
|
@ -93,9 +102,10 @@ export const createNodeWebSocket = (init: NodeWebSocketInit): NodeWebSocket => {
|
|||
return
|
||||
}
|
||||
|
||||
const response = new Response()
|
||||
const connectionSymbol = generateConnectionSymbol()
|
||||
c.env[CONNECTION_SYMBOL_KEY] = connectionSymbol
|
||||
;(async () => {
|
||||
const ws = await nodeUpgradeWebSocket(c.env.incoming, response)
|
||||
const ws = await nodeUpgradeWebSocket(c.env.incoming, connectionSymbol)
|
||||
let events: WSEvents<WebSocket>
|
||||
try {
|
||||
events = await createEvents(c)
|
||||
|
@ -167,7 +177,7 @@ export const createNodeWebSocket = (init: NodeWebSocketInit): NodeWebSocket => {
|
|||
})
|
||||
})()
|
||||
|
||||
return response
|
||||
return new Response()
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue