@elysiajs/websocket
Advanced tools
Comparing version 0.2.4 to 0.2.6-rc.0
/// <reference types="bun-types" /> | ||
import type { ServerWebSocket, WebSocketHandler } from 'bun'; | ||
import { Elysia, type TypedSchema, UnwrapSchema } from 'elysia'; | ||
import type { ElysiaWSContext } from './types'; | ||
export declare class ElysiaWS<WS extends ElysiaWSContext<any> = ElysiaWSContext, Schema extends TypedSchema = TypedSchema> { | ||
import { Elysia, DEFS, type UnwrapSchema, ElysiaInstance } from 'elysia'; | ||
import type { ElysiaWSContext, WSTypedSchema } from './types'; | ||
export declare class ElysiaWS<WS extends ElysiaWSContext<any> = ElysiaWSContext, Schema extends WSTypedSchema = WSTypedSchema, Instance extends ElysiaInstance = ElysiaInstance> { | ||
raw: WS; | ||
@@ -10,4 +10,4 @@ data: WS['data']; | ||
constructor(ws: WS); | ||
publish(topic: string, data: UnwrapSchema<Schema['response']>, compress?: boolean): this; | ||
send(data: UnwrapSchema<Schema['response']>): this; | ||
publish(topic: string, data: UnwrapSchema<Schema['response'], Instance>, compress?: boolean): this; | ||
send(data: UnwrapSchema<Schema['response'], Instance>): this; | ||
subscribe(room: string): this; | ||
@@ -18,7 +18,9 @@ unsubscribe(room: string): this; | ||
} | ||
export declare const websocket: (config?: Omit<WebSocketHandler, 'open' | 'message' | 'close' | 'drain'>) => (app: Elysia) => Elysia<import("elysia").ElysiaInstance<{ | ||
store: Record<typeof import("elysia").SCHEMA, {}>; | ||
request: {}; | ||
export declare const websocket: (config?: Omit<WebSocketHandler, 'open' | 'message' | 'close' | 'drain'>) => (app: Elysia) => Elysia<{ | ||
store: Record<any, any> & Record<typeof import("elysia").SCHEMA, {}> & Record<typeof DEFS, {}>; | ||
request: { | ||
publish: (topic: string, data: string | import("bun").ArrayBufferView | ArrayBuffer, compress?: boolean | undefined) => number; | ||
}; | ||
schema: {}; | ||
}>>; | ||
}>; | ||
export default websocket; |
@@ -1,2 +0,2 @@ | ||
import { Elysia, getPath, Router, createValidationError, getSchemaValidator } from 'elysia'; | ||
import { Elysia, getPath, Router, createValidationError, getSchemaValidator, DEFS } from 'elysia'; | ||
import { nanoid } from 'nanoid'; | ||
@@ -109,3 +109,8 @@ export class ElysiaWS { | ||
}; | ||
return app; | ||
return app | ||
.decorate('publish', app.server?.publish) | ||
.onRequest((context) => { | ||
if (app.server) | ||
context.publish = app.server.publish; | ||
}); | ||
}; | ||
@@ -124,3 +129,3 @@ Elysia.prototype.ws = function (path, options) { | ||
id: nanoid(), | ||
message: getSchemaValidator(options.schema?.body), | ||
message: getSchemaValidator(options.schema?.body, this.store[DEFS]), | ||
transformMessage: !options.transform | ||
@@ -127,0 +132,0 @@ ? [] |
/// <reference types="bun-types" /> | ||
import type { ServerWebSocket, WebSocketHandler } from 'bun'; | ||
import type { Context, TypedSchema, HookHandler, UnwrapSchema, Router } from 'elysia'; | ||
import type { ExtractPath, TypedRoute, TypedSchemaToRoute, WithArray, ElysiaRoute, NoReturnHandler } from 'elysia/dist/types'; | ||
import type { Static, TSchema } from '@sinclair/typebox'; | ||
import type { Context, TypedSchema, HookHandler, UnwrapSchema, Router, SCHEMA, Elysia } from 'elysia'; | ||
import type { ExtractPath, TypedRoute, TypedSchemaToRoute, WithArray, ElysiaInstance, NoReturnHandler, AnyTypedSchema } from 'elysia/dist/types'; | ||
import type { ElysiaWS } from '.'; | ||
import type { TSchema } from '@sinclair/typebox'; | ||
import type { TypeCheck } from '@sinclair/typebox/compiler'; | ||
import { ElysiaWS } from '.'; | ||
export declare type WebSocketSchemaToRoute<Schema extends TypedSchema> = { | ||
export type WSTypedSchema<ModelName extends string = string> = Omit<TypedSchema<ModelName>, 'response'> & { | ||
response?: TSchema | ModelName | undefined; | ||
}; | ||
export type ElysiaWSRoute<Method extends string = string, Schema extends TypedSchema = TypedSchema, Instance extends ElysiaInstance = ElysiaInstance, Path extends string = string, CatchResponse = unknown> = Elysia<{ | ||
request: Instance['request']; | ||
store: Instance['store'] & { | ||
[SCHEMA]: { | ||
[path in Path]: { | ||
[method in Method]: TypedSchemaToRoute<Schema, Instance> extends infer FinalSchema extends AnyTypedSchema ? Omit<FinalSchema, 'response'> & { | ||
response: undefined extends FinalSchema['response'] ? CatchResponse : FinalSchema['response']; | ||
} : never; | ||
}; | ||
}; | ||
}; | ||
schema: Instance['schema']; | ||
}>; | ||
export type TypedWSSchemaToRoute<Schema extends WSTypedSchema = WSTypedSchema, Instance extends ElysiaInstance = ElysiaInstance> = { | ||
body: UnwrapSchema<Schema['body'], Instance>; | ||
headers: UnwrapSchema<Schema['headers'], Instance> extends infer Result extends Record<string, any> ? Result : undefined; | ||
query: UnwrapSchema<Schema['query'], Instance> extends infer Result extends Record<string, any> ? Result : undefined; | ||
params: UnwrapSchema<Schema['params'], Instance> extends infer Result extends Record<string, any> ? Result : undefined; | ||
response: UnwrapSchema<Schema['params'], Instance> extends infer Result extends Record<string, any> ? Result : undefined; | ||
}; | ||
export type WSTypedSchemaToTypedSchema<Schema extends WSTypedSchema> = Omit<Schema, 'response'> & { | ||
response: Schema['response']; | ||
}; | ||
export type WebSocketSchemaToRoute<Schema extends WSTypedSchema> = { | ||
body: UnwrapSchema<Schema['body']> extends Record<string, any> ? UnwrapSchema<Schema['body']> : undefined; | ||
@@ -15,15 +41,15 @@ headers: UnwrapSchema<Schema['headers']> extends Record<string, any> ? UnwrapSchema<Schema['headers']> : undefined; | ||
}; | ||
export declare type TransformMessageHandler<Message extends TSchema | undefined> = (message: UnwrapSchema<Message>) => void | UnwrapSchema<Message>; | ||
export declare type ElysiaWSContext<Schema extends TypedSchema = TypedSchema, Path extends string = string> = ServerWebSocket<Context<ExtractPath<Path> extends never ? WebSocketSchemaToRoute<Schema> : Omit<WebSocketSchemaToRoute<Schema>, 'params'> & { | ||
export type TransformMessageHandler<Message extends TSchema | string | undefined> = (message: UnwrapSchema<Message>) => void | UnwrapSchema<Message>; | ||
export type ElysiaWSContext<Schema extends WSTypedSchema = WSTypedSchema, Path extends string = string> = ServerWebSocket<Context<ExtractPath<Path> extends never ? WebSocketSchemaToRoute<Schema> : Omit<WebSocketSchemaToRoute<Schema>, 'params'> & { | ||
params: Record<ExtractPath<Path>, string>; | ||
}> & { | ||
id: string; | ||
message: Schema['body'] extends undefined ? undefined : TypeCheck<NonNullable<Schema['body']>>; | ||
message: Schema['body'] extends undefined ? undefined : TypeCheck<NonNullable<Schema['body']> extends TSchema ? NonNullable<Schema['body']> : TSchema>; | ||
transformMessage: TransformMessageHandler<Schema['body']>[]; | ||
}>; | ||
export declare type HeaderHandler<Route extends TypedRoute = TypedRoute> = (context: Context<Route>) => HeadersInit; | ||
export declare type WebSocketHeaderHandler<Schema extends TypedSchema = TypedSchema, Path extends string = string> = HeaderHandler<TypedSchemaToRoute<Schema>['params'] extends {} ? Omit<TypedSchemaToRoute<Schema>, 'response'> & { | ||
response: void | TypedSchemaToRoute<Schema>['response']; | ||
} : Omit<Omit<TypedSchemaToRoute<Schema>, 'response'> & { | ||
response: void | TypedSchemaToRoute<Schema>['response']; | ||
export type HeaderHandler<Route extends TypedRoute = TypedRoute> = (context: Context<Route>) => HeadersInit; | ||
export type WebSocketHeaderHandler<Schema extends WSTypedSchema = WSTypedSchema, Path extends string = string> = HeaderHandler<TypedWSSchemaToRoute<Schema>['params'] extends {} ? Omit<TypedWSSchemaToRoute<Schema>, 'response'> & { | ||
response: void | TypedWSSchemaToRoute<Schema>['response']; | ||
} : Omit<Omit<TypedWSSchemaToRoute<Schema>, 'response'> & { | ||
response: void | TypedWSSchemaToRoute<Schema>['response']; | ||
}, 'params'> & { | ||
@@ -35,14 +61,14 @@ params: Record<ExtractPath<Path>, string>; | ||
websocketRouter: Router; | ||
ws<Schema extends TypedSchema = TypedSchema, Path extends string = string, Instance extends Elysia<any> = this>(path: Path, options: Omit<Partial<WebSocketHandler<Context>>, 'open' | 'message' | 'close' | 'drain'> & { | ||
ws<Schema extends WSTypedSchema = WSTypedSchema, Path extends string = string, Instance extends Elysia<any> = this>(path: Path, options: Omit<Partial<WebSocketHandler<Context>>, 'open' | 'message' | 'close' | 'drain'> & { | ||
schema?: Schema; | ||
beforeHandle?: WithArray<HookHandler<Schema>>; | ||
transform?: WithArray<NoReturnHandler<Schema>>; | ||
transform?: WithArray<NoReturnHandler<TypedWSSchemaToRoute<Schema>>>; | ||
transformMessage?: WithArray<TransformMessageHandler<Schema['body']>>; | ||
headers?: HeadersInit | WebSocketHeaderHandler<Schema>; | ||
open?: (ws: ElysiaWS<ElysiaWSContext<Schema, Path>, Schema>) => void | Promise<void>; | ||
message?: (ws: ElysiaWS<ElysiaWSContext<Schema, Path>, Schema>, message: Schema['body'] extends NonNullable<Schema['body']> ? Static<NonNullable<Schema['body']>> : string) => any; | ||
message?: (ws: ElysiaWS<ElysiaWSContext<Schema, Path>, Schema>, message: Schema['body'] extends NonNullable<Schema['body']> ? UnwrapSchema<Schema['body']> : string) => any; | ||
close?: (ws: ElysiaWS<ElysiaWSContext<Schema, Path>, Schema>) => any; | ||
drain?: (ws: ElysiaWS<ElysiaWSContext<Schema, Path>, Schema>, code: number, reason: string) => any; | ||
}): Instance extends Elysia<infer Instance> ? ElysiaRoute<'subscribe', Schema, Instance, Path, Schema['response']> : this; | ||
}): Instance extends Elysia<infer Instance> ? ElysiaWSRoute<'subscribe', Schema, Instance, Path, Schema['response']> : this; | ||
} | ||
} |
{ | ||
"name": "@elysiajs/websocket", | ||
"version": "0.2.4", | ||
"version": "0.2.6-rc.0", | ||
"description": "Plugin for Elysia that add support for websocket", | ||
@@ -36,11 +36,11 @@ "author": { | ||
"peerDependencies": { | ||
"elysia": ">= 0.1.0" | ||
"elysia": ">= 0.2.0-rc.1" | ||
}, | ||
"devDependencies": { | ||
"@sinclair/typebox": "0.25.10", | ||
"@sinclair/typebox": "0.25.21", | ||
"@types/node": "^18.11.7", | ||
"bun-types": "^0.3.0", | ||
"elysia": "^0.1.2", | ||
"bun-types": "^0.5.0", | ||
"elysia": "^0.2.0-rc.1", | ||
"eslint": "^8.26.0", | ||
"typescript": "^4.8.4" | ||
"typescript": "^4.9.3" | ||
}, | ||
@@ -47,0 +47,0 @@ "dependencies": { |
@@ -1,2 +0,2 @@ | ||
import type { ServerWebSocket, WebSocketHandler } from 'bun' | ||
import type { Server, ServerWebSocket, WebSocketHandler } from 'bun' | ||
@@ -9,5 +9,7 @@ import { | ||
getSchemaValidator, | ||
DEFS, | ||
type Context, | ||
type TypedSchema, | ||
UnwrapSchema | ||
type UnwrapSchema, | ||
ElysiaInstance | ||
} from 'elysia' | ||
@@ -17,7 +19,8 @@ import { nanoid } from 'nanoid' | ||
import type { TSchema } from '@sinclair/typebox' | ||
import type { ElysiaWSContext } from './types' | ||
import type { ElysiaWSContext, WSTypedSchema } from './types' | ||
export class ElysiaWS< | ||
WS extends ElysiaWSContext<any> = ElysiaWSContext, | ||
Schema extends TypedSchema = TypedSchema | ||
Schema extends WSTypedSchema = WSTypedSchema, | ||
Instance extends ElysiaInstance = ElysiaInstance | ||
> { | ||
@@ -36,3 +39,3 @@ raw: WS | ||
topic: string, | ||
data: UnwrapSchema<Schema['response']>, | ||
data: UnwrapSchema<Schema['response'], Instance>, | ||
compress?: boolean | ||
@@ -48,3 +51,3 @@ ) { | ||
send(data: UnwrapSchema<Schema['response']>) { | ||
send(data: UnwrapSchema<Schema['response'], Instance>) { | ||
// @ts-ignore | ||
@@ -210,2 +213,6 @@ if (typeof data === 'object') data = JSON.stringify(data) | ||
return app | ||
.decorate('publish', app.server?.publish as Server['publish']) | ||
.onRequest((context) => { | ||
if (app.server) context.publish = app.server!.publish | ||
}) | ||
} | ||
@@ -234,3 +241,6 @@ | ||
id: nanoid(), | ||
message: getSchemaValidator(options.schema?.body), | ||
message: getSchemaValidator( | ||
options.schema?.body, | ||
this.store[DEFS] | ||
), | ||
transformMessage: !options.transform | ||
@@ -237,0 +247,0 @@ ? [] |
120
src/types.ts
@@ -8,3 +8,5 @@ import type { ServerWebSocket, WebSocketHandler } from 'bun' | ||
UnwrapSchema, | ||
Router | ||
Router, | ||
SCHEMA, | ||
Elysia | ||
} from 'elysia' | ||
@@ -18,10 +20,84 @@ import type { | ||
ElysiaInstance, | ||
NoReturnHandler | ||
NoReturnHandler, | ||
TypedRouteToEden, | ||
AnyTypedSchema | ||
} from 'elysia/dist/types' | ||
import type { ElysiaWS } from '.' | ||
import type { Static, TSchema } from '@sinclair/typebox' | ||
import type { TypeCheck } from '@sinclair/typebox/compiler' | ||
import { ElysiaWS } from '.' | ||
export type WebSocketSchemaToRoute<Schema extends TypedSchema> = { | ||
export type WSTypedSchema<ModelName extends string = string> = Omit< | ||
TypedSchema<ModelName>, | ||
'response' | ||
> & { | ||
response?: TSchema | ModelName | undefined | ||
} | ||
export type ElysiaWSRoute< | ||
Method extends string = string, | ||
Schema extends TypedSchema = TypedSchema, | ||
Instance extends ElysiaInstance = ElysiaInstance, | ||
Path extends string = string, | ||
CatchResponse = unknown | ||
> = Elysia<{ | ||
request: Instance['request'] | ||
store: Instance['store'] & { | ||
[SCHEMA]: { | ||
[path in Path]: { | ||
[method in Method]: TypedSchemaToRoute< | ||
Schema, | ||
Instance | ||
> extends infer FinalSchema extends AnyTypedSchema | ||
? Omit<FinalSchema, 'response'> & { | ||
response: undefined extends FinalSchema['response'] | ||
? CatchResponse | ||
: FinalSchema['response'] | ||
} | ||
: never | ||
} | ||
} | ||
} | ||
schema: Instance['schema'] | ||
}> | ||
export type TypedWSSchemaToRoute< | ||
Schema extends WSTypedSchema = WSTypedSchema, | ||
Instance extends ElysiaInstance = ElysiaInstance | ||
> = { | ||
body: UnwrapSchema<Schema['body'], Instance> | ||
headers: UnwrapSchema< | ||
Schema['headers'], | ||
Instance | ||
> extends infer Result extends Record<string, any> | ||
? Result | ||
: undefined | ||
query: UnwrapSchema< | ||
Schema['query'], | ||
Instance | ||
> extends infer Result extends Record<string, any> | ||
? Result | ||
: undefined | ||
params: UnwrapSchema< | ||
Schema['params'], | ||
Instance | ||
> extends infer Result extends Record<string, any> | ||
? Result | ||
: undefined | ||
response: UnwrapSchema< | ||
Schema['params'], | ||
Instance | ||
> extends infer Result extends Record<string, any> | ||
? Result | ||
: undefined | ||
} | ||
export type WSTypedSchemaToTypedSchema<Schema extends WSTypedSchema> = Omit< | ||
Schema, | ||
'response' | ||
> & { | ||
response: Schema['response'] | ||
} | ||
export type WebSocketSchemaToRoute<Schema extends WSTypedSchema> = { | ||
body: UnwrapSchema<Schema['body']> extends Record<string, any> | ||
@@ -44,8 +120,8 @@ ? UnwrapSchema<Schema['body']> | ||
export type TransformMessageHandler<Message extends TSchema | undefined> = ( | ||
message: UnwrapSchema<Message> | ||
) => void | UnwrapSchema<Message> | ||
export type TransformMessageHandler< | ||
Message extends TSchema | string | undefined | ||
> = (message: UnwrapSchema<Message>) => void | UnwrapSchema<Message> | ||
export type ElysiaWSContext< | ||
Schema extends TypedSchema = TypedSchema, | ||
Schema extends WSTypedSchema = WSTypedSchema, | ||
Path extends string = string | ||
@@ -63,3 +139,7 @@ > = ServerWebSocket< | ||
? undefined | ||
: TypeCheck<NonNullable<Schema['body']>> | ||
: TypeCheck< | ||
NonNullable<Schema['body']> extends TSchema | ||
? NonNullable<Schema['body']> | ||
: TSchema | ||
> | ||
transformMessage: TransformMessageHandler<Schema['body']>[] | ||
@@ -74,12 +154,12 @@ } | ||
export type WebSocketHeaderHandler< | ||
Schema extends TypedSchema = TypedSchema, | ||
Schema extends WSTypedSchema = WSTypedSchema, | ||
Path extends string = string | ||
> = HeaderHandler< | ||
TypedSchemaToRoute<Schema>['params'] extends {} | ||
? Omit<TypedSchemaToRoute<Schema>, 'response'> & { | ||
response: void | TypedSchemaToRoute<Schema>['response'] | ||
TypedWSSchemaToRoute<Schema>['params'] extends {} | ||
? Omit<TypedWSSchemaToRoute<Schema>, 'response'> & { | ||
response: void | TypedWSSchemaToRoute<Schema>['response'] | ||
} | ||
: Omit< | ||
Omit<TypedSchemaToRoute<Schema>, 'response'> & { | ||
response: void | TypedSchemaToRoute<Schema>['response'] | ||
Omit<TypedWSSchemaToRoute<Schema>, 'response'> & { | ||
response: void | TypedWSSchemaToRoute<Schema>['response'] | ||
}, | ||
@@ -97,3 +177,3 @@ 'params' | ||
ws< | ||
Schema extends TypedSchema = TypedSchema, | ||
Schema extends WSTypedSchema = WSTypedSchema, | ||
Path extends string = string, | ||
@@ -113,3 +193,5 @@ Instance extends Elysia<any> = this | ||
beforeHandle?: WithArray<HookHandler<Schema>> | ||
transform?: WithArray<NoReturnHandler<Schema>> | ||
transform?: WithArray< | ||
NoReturnHandler<TypedWSSchemaToRoute<Schema>> | ||
> | ||
transformMessage?: WithArray< | ||
@@ -144,3 +226,3 @@ TransformMessageHandler<Schema['body']> | ||
message: Schema['body'] extends NonNullable<Schema['body']> | ||
? Static<NonNullable<Schema['body']>> | ||
? UnwrapSchema<Schema['body']> | ||
: string | ||
@@ -171,3 +253,3 @@ ) => any | ||
): Instance extends Elysia<infer Instance> | ||
? ElysiaRoute< | ||
? ElysiaWSRoute< | ||
'subscribe', | ||
@@ -174,0 +256,0 @@ Schema, |
31644
699