fix(node-ws): adapter shouldn't send buffer as a event (#1094)
* fix(node-ws): adapter shouldn't send buffer as a event * chore: changesetpull/1095/head
parent
b18f24379b
commit
519404ad2c
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
'@hono/node-ws': patch
|
||||
---
|
||||
|
||||
Adapter won't send Buffer as a MessageEvent.
|
|
@ -1,5 +1,5 @@
|
|||
import type { Context } from 'hono'
|
||||
import { getCookie } from 'hono/cookie';
|
||||
import { getCookie } from 'hono/cookie'
|
||||
import { createMiddleware } from 'hono/factory'
|
||||
import { HTTPException } from 'hono/http-exception'
|
||||
|
||||
|
|
|
@ -52,9 +52,7 @@ describe('WebSocket helper', () => {
|
|||
})
|
||||
|
||||
it('Should be rejected if upgradeWebSocket is not used', async () => {
|
||||
app.get(
|
||||
'/', (c)=>c.body('')
|
||||
)
|
||||
app.get('/', (c) => c.body(''))
|
||||
|
||||
{
|
||||
const ws = new WebSocket('ws://localhost:3030/')
|
||||
|
@ -70,7 +68,8 @@ describe('WebSocket helper', () => {
|
|||
expect(await mainPromise).toBe(true)
|
||||
}
|
||||
|
||||
{ //also should rejected on fallback
|
||||
{
|
||||
//also should rejected on fallback
|
||||
const ws = new WebSocket('ws://localhost:3030/notFound')
|
||||
const mainPromise = new Promise<boolean>((resolve) => {
|
||||
ws.onerror = () => {
|
||||
|
@ -202,11 +201,11 @@ describe('WebSocket helper', () => {
|
|||
ws.send(binaryData)
|
||||
|
||||
const receivedMessage = await mainPromise
|
||||
expect(receivedMessage).toBeInstanceOf(Buffer)
|
||||
expect((receivedMessage as Buffer).byteLength).toBe(binaryData.length)
|
||||
expect(receivedMessage).toBeInstanceOf(ArrayBuffer)
|
||||
expect((receivedMessage as ArrayBuffer).byteLength).toBe(binaryData.length)
|
||||
|
||||
binaryData.forEach((val, idx) => {
|
||||
expect((receivedMessage as Buffer).at(idx)).toBe(val)
|
||||
expect(new Uint8Array(receivedMessage as ArrayBuffer)[idx]).toBe(val)
|
||||
})
|
||||
})
|
||||
|
||||
|
|
|
@ -25,7 +25,10 @@ export interface NodeWebSocketInit {
|
|||
*/
|
||||
export const createNodeWebSocket = (init: NodeWebSocketInit): NodeWebSocket => {
|
||||
const wss = new WebSocketServer({ noServer: true })
|
||||
const waiterMap = new Map<IncomingMessage, { resolve: (ws: WebSocket) => void, response: Response }>()
|
||||
const waiterMap = new Map<
|
||||
IncomingMessage,
|
||||
{ resolve: (ws: WebSocket) => void; response: Response }
|
||||
>()
|
||||
|
||||
wss.on('connection', (ws, request) => {
|
||||
const waiter = waiterMap.get(request)
|
||||
|
@ -64,9 +67,9 @@ export const createNodeWebSocket = (init: NodeWebSocketInit): NodeWebSocket => {
|
|||
if (!waiter || waiter.response !== response) {
|
||||
socket.end(
|
||||
'HTTP/1.1 400 Bad Request\r\n' +
|
||||
'Connection: close\r\n' +
|
||||
'Content-Length: 0\r\n' +
|
||||
'\r\n'
|
||||
'Connection: close\r\n' +
|
||||
'Content-Length: 0\r\n' +
|
||||
'\r\n'
|
||||
)
|
||||
waiterMap.delete(request)
|
||||
return
|
||||
|
@ -113,7 +116,11 @@ export const createNodeWebSocket = (init: NodeWebSocketInit): NodeWebSocket => {
|
|||
for (const data of datas) {
|
||||
events.onMessage?.(
|
||||
new MessageEvent('message', {
|
||||
data: isBinary ? data : data.toString('utf-8'),
|
||||
data: isBinary
|
||||
? data instanceof ArrayBuffer
|
||||
? data
|
||||
: data.buffer.slice(data.byteOffset, data.byteOffset + data.byteLength)
|
||||
: data.toString('utf-8'),
|
||||
}),
|
||||
ctx
|
||||
)
|
||||
|
|
|
@ -77,13 +77,13 @@ export class AuthFlow {
|
|||
|
||||
const url = 'https://id.twitch.tv/oauth2/token'
|
||||
|
||||
const response = (await fetch(url, {
|
||||
const response = await fetch(url, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/x-www-form-urlencoded',
|
||||
},
|
||||
body: parsedOptions,
|
||||
}).then((res) => res.json() as Promise<TwitchTokenResponse>))
|
||||
}).then((res) => res.json() as Promise<TwitchTokenResponse>)
|
||||
|
||||
if ('error' in response) {
|
||||
throw new HTTPException(400, { message: response.error })
|
||||
|
|
|
@ -14,18 +14,18 @@ export async function refreshToken(
|
|||
client_secret,
|
||||
})
|
||||
|
||||
const response = (await fetch('https://id.twitch.tv/oauth2/token', {
|
||||
const response = await fetch('https://id.twitch.tv/oauth2/token', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/x-www-form-urlencoded',
|
||||
},
|
||||
body: params,
|
||||
}).then((res) => res.json() as Promise<TwitchRefreshResponse>))
|
||||
}).then((res) => res.json() as Promise<TwitchRefreshResponse>)
|
||||
|
||||
if ('error' in response) {
|
||||
throw new HTTPException(400, { message: response.error })
|
||||
}
|
||||
|
||||
|
||||
if ('message' in response) {
|
||||
throw new HTTPException(400, { message: response.message as string })
|
||||
}
|
||||
|
|
|
@ -2,10 +2,7 @@ import { HTTPException } from 'hono/http-exception'
|
|||
import { toQueryParams } from '../../utils/objectToQuery'
|
||||
import type { TwitchRevokingResponse } from './types'
|
||||
|
||||
export async function revokeToken(
|
||||
client_id: string,
|
||||
token: string
|
||||
): Promise<boolean> {
|
||||
export async function revokeToken(client_id: string, token: string): Promise<boolean> {
|
||||
const params = toQueryParams({
|
||||
client_id: client_id,
|
||||
token,
|
||||
|
@ -23,14 +20,16 @@ export async function revokeToken(
|
|||
if (!res.ok) {
|
||||
// Try to parse error response
|
||||
try {
|
||||
const errorResponse = await res.json() as TwitchRevokingResponse
|
||||
const errorResponse = (await res.json()) as TwitchRevokingResponse
|
||||
if (errorResponse && typeof errorResponse === 'object' && 'message' in errorResponse) {
|
||||
throw new HTTPException(400, { message: errorResponse.message })
|
||||
}
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
} catch (e) {
|
||||
// If parsing fails, throw a generic error with the status
|
||||
throw new HTTPException(400, { message: `Token revocation failed with status: ${res.status}` })
|
||||
throw new HTTPException(400, {
|
||||
message: `Token revocation failed with status: ${res.status}`,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2,10 +2,10 @@ export type Scopes =
|
|||
// Analytics
|
||||
| 'analytics:read:extensions'
|
||||
| 'analytics:read:games'
|
||||
|
||||
|
||||
// Bits
|
||||
| 'bits:read'
|
||||
|
||||
|
||||
// Channel
|
||||
| 'channel:bot'
|
||||
| 'channel:manage:ads'
|
||||
|
@ -85,11 +85,11 @@ export type Scopes =
|
|||
| 'moderator:read:vips'
|
||||
| 'moderator:read:warnings'
|
||||
| 'moderator:manage:warnings'
|
||||
|
||||
|
||||
// IRC Chat Scopes
|
||||
| 'chat:edit'
|
||||
| 'chat:read'
|
||||
|
||||
|
||||
// PubSub-specific Chat Scopes
|
||||
| 'whispers:read'
|
||||
|
||||
|
@ -110,7 +110,6 @@ export type TwitchRefreshError = Required<Pick<TwitchErrorResponse, 'status' | '
|
|||
|
||||
export type TwitchTokenError = Required<Pick<TwitchErrorResponse, 'status' | 'message' | 'error'>>
|
||||
|
||||
|
||||
// Success responses types from Twitch API
|
||||
export interface TwitchValidateSuccess {
|
||||
client_id: string
|
||||
|
@ -150,19 +149,21 @@ export type TwitchTokenResponse = TwitchTokenSuccess | TwitchTokenError
|
|||
export type TwitchValidateResponse = TwitchValidateSuccess | TwitchValidateError
|
||||
|
||||
export interface TwitchUserResponse {
|
||||
data: [{
|
||||
id: string
|
||||
login: string
|
||||
display_name: string
|
||||
type: string
|
||||
broadcaster_type: string
|
||||
description: string
|
||||
profile_image_url: string
|
||||
offline_image_url: string
|
||||
view_count: number
|
||||
email: string
|
||||
created_at: string
|
||||
}]
|
||||
data: [
|
||||
{
|
||||
id: string
|
||||
login: string
|
||||
display_name: string
|
||||
type: string
|
||||
broadcaster_type: string
|
||||
description: string
|
||||
profile_image_url: string
|
||||
offline_image_url: string
|
||||
view_count: number
|
||||
email: string
|
||||
created_at: string
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
export type TwitchUser = TwitchUserResponse['data'][0]
|
||||
|
|
|
@ -1,14 +1,11 @@
|
|||
import { HTTPException } from 'hono/http-exception'
|
||||
import type { TwitchValidateResponse } from './types'
|
||||
|
||||
export async function validateToken(
|
||||
token: string
|
||||
): Promise<TwitchValidateResponse> {
|
||||
|
||||
export async function validateToken(token: string): Promise<TwitchValidateResponse> {
|
||||
const response = await fetch('https://id.twitch.tv/oauth2/validate', {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
authorization: `Bearer ${token}`,
|
||||
authorization: `Bearer ${token}`,
|
||||
},
|
||||
}).then((res) => res.json() as Promise<TwitchValidateResponse>)
|
||||
|
||||
|
|
Loading…
Reference in New Issue