@nmtjs/ws-transport 0.12.9 → 0.13.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -1,5 +1,4 @@
1
1
  export * from './injectables.ts';
2
2
  export * from './server.ts';
3
- export * from './transport.ts';
4
3
  export * from './types.ts';
5
4
  export * from './utils.ts';
package/dist/index.js CHANGED
@@ -1,5 +1,4 @@
1
1
  export * from "./injectables.js";
2
2
  export * from "./server.js";
3
- export * from "./transport.js";
4
3
  export * from "./types.js";
5
4
  export * from "./utils.js";
@@ -1,14 +1,6 @@
1
1
  import { type LazyInjectable, Scope } from '@nmtjs/core';
2
+ import type { WsTransportServerRequest } from './types.ts';
2
3
  export declare const WsTransportInjectables: {
3
- readonly connectionData: LazyInjectable<Readonly<{
4
- url: string;
5
- origin: URL | null;
6
- method: string;
7
- headers: Headers;
8
- querystring: string;
9
- query: URLSearchParams;
10
- remoteAddress: string;
11
- proxiedRemoteAddress: string;
12
- }>, Scope.Connection>;
4
+ readonly connectionData: LazyInjectable<WsTransportServerRequest, Scope.Connection>;
13
5
  readonly httpResponseHeaders: LazyInjectable<Headers, Scope.Call>;
14
6
  };
@@ -0,0 +1,2 @@
1
+ import type { WsConnectionData, WsTransportOptions } from '../types.ts';
2
+ export declare const WsTransport: import("@nmtjs/protocol/server").TransportPlugin<WsConnectionData, WsTransportOptions<"bun">>;
@@ -0,0 +1,68 @@
1
+ import { createTransport } from '@nmtjs/protocol/server';
2
+ import createAdapter from 'crossws/adapters/bun';
3
+ import { WsTransportServer } from "../server.js";
4
+ import { InternalServerErrorHttpResponse, NotFoundHttpResponse, StatusResponse, } from "../utils.js";
5
+ function adapterFactory(params) {
6
+ const adapter = createAdapter({ hooks: params.wsHooks });
7
+ let server = null;
8
+ function createServer() {
9
+ return globalThis.Bun.serve({
10
+ ...params.runtime?.server,
11
+ unix: params.listen.unix,
12
+ port: params.listen.port,
13
+ hostname: params.listen.hostname,
14
+ reusePort: params.listen.reusePort,
15
+ tls: params.tls
16
+ ? {
17
+ cert: params.tls.cert,
18
+ key: params.tls.key,
19
+ passphrase: params.tls.passphrase,
20
+ }
21
+ : undefined,
22
+ websocket: {
23
+ ...params.runtime?.ws,
24
+ ...adapter.websocket,
25
+ },
26
+ routes: {
27
+ ...params.runtime?.server?.routes,
28
+ '/healthy': StatusResponse(),
29
+ },
30
+ async fetch(request, server) {
31
+ const url = new URL(request.url);
32
+ if (url.pathname.startsWith(params.apiPath)) {
33
+ try {
34
+ if (request.headers.get('upgrade') === 'websocket') {
35
+ return await adapter.handleUpgrade(request, server);
36
+ }
37
+ const { body, headers, method } = request;
38
+ return await params.fetchHandler({
39
+ url,
40
+ method,
41
+ headers,
42
+ }, body, request.signal);
43
+ }
44
+ catch (err) {
45
+ params.logger.error({ err }, 'Error in fetch handler');
46
+ return InternalServerErrorHttpResponse();
47
+ }
48
+ }
49
+ return NotFoundHttpResponse();
50
+ },
51
+ });
52
+ }
53
+ return {
54
+ start: async () => {
55
+ server = createServer();
56
+ return server.url.href;
57
+ },
58
+ stop: async () => {
59
+ if (server) {
60
+ await server.stop();
61
+ server = null;
62
+ }
63
+ },
64
+ };
65
+ }
66
+ export const WsTransport = createTransport('WsTransport', (context, options) => {
67
+ return new WsTransportServer(adapterFactory, context, options);
68
+ });
@@ -0,0 +1,2 @@
1
+ import type { WsConnectionData, WsTransportOptions } from '../types.ts';
2
+ export declare const WsTransport: import("@nmtjs/protocol/server").TransportPlugin<WsConnectionData, WsTransportOptions<"deno">>;
@@ -0,0 +1,91 @@
1
+ import { createTransport } from '@nmtjs/protocol/server';
2
+ import createAdapter from 'crossws/adapters/deno';
3
+ import { WsTransportServer } from "../server.js";
4
+ import { InternalServerErrorHttpResponse, NotFoundHttpResponse, StatusResponse, } from "../utils.js";
5
+ function adapterFactory(params) {
6
+ const adapter = createAdapter({ hooks: params.wsHooks });
7
+ let server = null;
8
+ function createServer() {
9
+ const listenOptions = params.listen.unix
10
+ ? { path: params.listen.unix }
11
+ : {
12
+ port: params.listen.port,
13
+ hostname: params.listen.hostname,
14
+ reusePort: params.listen.reusePort,
15
+ };
16
+ const options = {
17
+ ...listenOptions,
18
+ tls: params.tls
19
+ ? {
20
+ cert: params.tls.cert,
21
+ key: params.tls.key,
22
+ passphrase: params.tls.passphrase,
23
+ }
24
+ : undefined,
25
+ };
26
+ return new Promise((resolve) => {
27
+ const server = globalThis.Deno.serve({
28
+ ...params.runtime?.server,
29
+ ...options,
30
+ handler: async (request, info) => {
31
+ const url = new URL(request.url);
32
+ if (url.pathname.startsWith(params.apiPath)) {
33
+ try {
34
+ if (request.headers.get('upgrade') === 'websocket') {
35
+ return await adapter.handleUpgrade(request, info);
36
+ }
37
+ const { headers, method, body } = request;
38
+ return await params.fetchHandler({
39
+ url,
40
+ method,
41
+ headers,
42
+ }, body, request.signal);
43
+ }
44
+ catch (err) {
45
+ params.logger.error({ err }, 'Error in fetch handler');
46
+ return InternalServerErrorHttpResponse();
47
+ }
48
+ }
49
+ else if (url.pathname === '/healthy') {
50
+ return StatusResponse();
51
+ }
52
+ return NotFoundHttpResponse();
53
+ },
54
+ onListen(addr) {
55
+ setTimeout(() => {
56
+ resolve({ server, addr });
57
+ }, 1);
58
+ },
59
+ });
60
+ });
61
+ }
62
+ return {
63
+ start: async () => {
64
+ const { server: _server, addr } = await createServer();
65
+ server = _server;
66
+ switch (addr.transport) {
67
+ case 'unix':
68
+ case 'unixpacket':
69
+ return `unix://${addr.path}`;
70
+ case 'tcp':
71
+ case 'udp': {
72
+ const proto = params.tls ? 'https' : 'http';
73
+ return `${proto}://${addr.hostname}:${addr.port}`;
74
+ }
75
+ case 'vsock':
76
+ return `vsock://${addr.cid}:${addr.port}`;
77
+ default:
78
+ throw new Error(`Unsupported address transport`);
79
+ }
80
+ },
81
+ stop: async () => {
82
+ if (server) {
83
+ await server.shutdown();
84
+ server = null;
85
+ }
86
+ },
87
+ };
88
+ }
89
+ export const WsTransport = createTransport('WsTransport', (context, options) => {
90
+ return new WsTransportServer(adapterFactory, context, options);
91
+ });
@@ -0,0 +1,2 @@
1
+ import type { WsConnectionData, WsTransportOptions } from '../types.ts';
2
+ export declare const WsTransport: import("@nmtjs/protocol/server").TransportPlugin<WsConnectionData, WsTransportOptions<"node">>;
@@ -0,0 +1,127 @@
1
+ import { App, SSLApp } from 'uWebSockets.js';
2
+ import { createTransport } from '@nmtjs/protocol/server';
3
+ import createAdapter from 'crossws/adapters/uws';
4
+ import { WsTransportServer } from "../server.js";
5
+ import { InternalServerErrorHttpResponse, NotFoundHttpResponse, StatusResponse, } from "../utils.js";
6
+ function adapterFactory(params) {
7
+ const adapter = createAdapter({ hooks: params.wsHooks });
8
+ const server = params.tls
9
+ ? SSLApp({
10
+ passphrase: params.tls.passphrase,
11
+ key_file_name: params.tls.key,
12
+ cert_file_name: params.tls.cert,
13
+ })
14
+ : App();
15
+ server
16
+ .ws(params.apiPath, {
17
+ ...params.runtime?.ws,
18
+ ...adapter.websocket,
19
+ })
20
+ .get('/healthy', async (res) => {
21
+ res.onAborted(() => { });
22
+ const response = StatusResponse();
23
+ res.cork(async () => {
24
+ res
25
+ .writeStatus(`${response.status} ${response.statusText}`)
26
+ .end(await response.arrayBuffer());
27
+ });
28
+ })
29
+ .any('/*', async (res, req) => {
30
+ const controller = new AbortController();
31
+ res.onAborted(() => controller.abort());
32
+ let response = NotFoundHttpResponse();
33
+ const headers = new Headers();
34
+ const method = req.getMethod();
35
+ req.forEach((k, v) => headers.append(k, v));
36
+ const host = headers.get('host') || 'localhost';
37
+ const proto = headers.get('x-forwarded-proto') || params.tls ? 'https' : 'http';
38
+ const url = new URL(req.getUrl(), `${proto}://${host}`);
39
+ if (url.pathname.startsWith(params.apiPath)) {
40
+ try {
41
+ const body = new ReadableStream({
42
+ start(controller) {
43
+ res.onData((chunk, isLast) => {
44
+ if (chunk)
45
+ controller.enqueue(Buffer.from(chunk.slice(0)));
46
+ if (isLast)
47
+ controller.close();
48
+ });
49
+ res.onAborted(() => controller.error());
50
+ },
51
+ });
52
+ response = await params.fetchHandler({
53
+ url,
54
+ method,
55
+ headers,
56
+ }, body, controller.signal);
57
+ }
58
+ catch (err) {
59
+ params.logger.error({ err }, 'Error in fetch handler');
60
+ response = InternalServerErrorHttpResponse();
61
+ }
62
+ }
63
+ if (controller.signal.aborted)
64
+ return undefined;
65
+ else {
66
+ res.cork(() => {
67
+ res.writeStatus(`${response.status.toString()} ${response.statusText}`);
68
+ response.headers.forEach((v, k) => res.writeHeader(k, v));
69
+ });
70
+ if (response.body) {
71
+ try {
72
+ const reader = response.body.getReader();
73
+ let chunk = await reader.read();
74
+ do {
75
+ if (controller.signal.aborted)
76
+ break;
77
+ if (chunk.value)
78
+ res.write(chunk.value);
79
+ chunk = await reader.read();
80
+ } while (!chunk.done);
81
+ res.end();
82
+ }
83
+ catch {
84
+ res.close();
85
+ }
86
+ }
87
+ else {
88
+ res.end();
89
+ }
90
+ }
91
+ });
92
+ return {
93
+ start: () => new Promise((resolve, reject) => {
94
+ if (params.listen.unix) {
95
+ server.listen_unix((socket) => {
96
+ if (socket) {
97
+ resolve('unix://' + params.listen.unix);
98
+ }
99
+ else {
100
+ reject(new Error('Failed to start WebSockets server'));
101
+ }
102
+ }, params.listen.unix);
103
+ }
104
+ else if (typeof params.listen.port === 'number') {
105
+ const proto = params.tls ? 'https' : 'http';
106
+ const hostname = params.listen.hostname || '127.0.0.1';
107
+ server.listen(hostname, params.listen.port, (socket) => {
108
+ if (socket) {
109
+ resolve(`${proto}://${hostname}:${params.listen.port}`);
110
+ }
111
+ else {
112
+ reject(new Error('Failed to start WebSockets server'));
113
+ }
114
+ });
115
+ }
116
+ else {
117
+ reject(new Error('Invalid listen parameters'));
118
+ }
119
+ }),
120
+ stop: () => {
121
+ server.close();
122
+ },
123
+ };
124
+ }
125
+ export const WsTransport = createTransport('WsTransport', (context, options) => {
126
+ return new WsTransportServer(adapterFactory, context, options);
127
+ });
package/dist/server.d.ts CHANGED
@@ -1,27 +1,30 @@
1
- import { type HttpRequest, type HttpResponse, type TemplatedApp } from 'uWebSockets.js';
2
1
  import { ClientMessageType, type ServerMessageType } from '@nmtjs/protocol';
3
2
  import { Connection, type Transport, type TransportPluginContext } from '@nmtjs/protocol/server';
4
- import type { WsConnectionData, WsTransportOptions, WsTransportSocket } from './types.ts';
3
+ import { type Peer } from 'crossws';
4
+ import type { WsAdapterServerFactory, WsConnectionData, WsTransportOptions, WsTransportServerRequest } from './types.ts';
5
5
  export declare class WsTransportServer implements Transport<WsConnectionData> {
6
+ #private;
7
+ protected readonly adapterFactory: WsAdapterServerFactory<any>;
6
8
  protected readonly context: TransportPluginContext;
7
9
  protected readonly options: WsTransportOptions;
8
- protected server: TemplatedApp;
9
- protected clients: Map<string, WsTransportSocket>;
10
- constructor(context: TransportPluginContext, options: WsTransportOptions);
11
- send(connection: Connection<WsConnectionData>, messageType: ServerMessageType, buffer: ArrayBuffer): void;
10
+ clients: Map<string, Peer<import("crossws").AdapterInternal>>;
11
+ constructor(adapterFactory: WsAdapterServerFactory<any>, context: TransportPluginContext, options: WsTransportOptions);
12
12
  start(): Promise<void>;
13
13
  stop(): Promise<void>;
14
- protected httpHandler(res: HttpResponse, req: HttpRequest): Promise<undefined>;
14
+ send(connection: Connection<WsConnectionData>, messageType: ServerMessageType, buffer: ArrayBuffer): void;
15
+ httpHandler(request: WsTransportServerRequest, body: ReadableStream | null, requestSignal: AbortSignal): Promise<Response>;
16
+ private applyCors;
15
17
  protected get protocol(): import("@nmtjs/protocol/server").Protocol;
16
18
  protected get logger(): import("@nmtjs/core").Logger;
17
19
  protected logError(cause: any, message?: string): Promise<void>;
18
- protected applyCors(res: HttpResponse, req: HttpRequest): void;
19
- protected [ClientMessageType.Rpc](ws: WsTransportSocket, buffer: ArrayBuffer): void;
20
- protected [ClientMessageType.RpcAbort](ws: WsTransportSocket, buffer: ArrayBuffer): void;
21
- protected [ClientMessageType.RpcStreamAbort](ws: WsTransportSocket, buffer: ArrayBuffer): void;
22
- protected [ClientMessageType.ClientStreamPush](ws: WsTransportSocket, buffer: ArrayBuffer): void;
23
- protected [ClientMessageType.ClientStreamEnd](ws: WsTransportSocket, buffer: ArrayBuffer): void;
24
- protected [ClientMessageType.ClientStreamAbort](ws: WsTransportSocket, buffer: ArrayBuffer): void;
25
- protected [ClientMessageType.ServerStreamPull](ws: WsTransportSocket, buffer: ArrayBuffer): void;
26
- protected [ClientMessageType.ServerStreamAbort](ws: WsTransportSocket, buffer: ArrayBuffer): void;
20
+ protected [ClientMessageType.Rpc](peer: Peer, buffer: ArrayBuffer, connectionId: string): void;
21
+ protected [ClientMessageType.RpcAbort](peer: Peer, buffer: ArrayBuffer, connectionId: string): void;
22
+ protected [ClientMessageType.RpcStreamAbort](peer: Peer, buffer: ArrayBuffer, connectionId: string): void;
23
+ protected [ClientMessageType.ClientStreamPush](peer: Peer, buffer: ArrayBuffer, connectionId: string): void;
24
+ protected [ClientMessageType.ClientStreamEnd](peer: Peer, buffer: ArrayBuffer, connectionId: string): void;
25
+ protected [ClientMessageType.ClientStreamAbort](peer: Peer, buffer: ArrayBuffer, connectionId: string): void;
26
+ protected [ClientMessageType.ServerStreamPull](peer: Peer, buffer: ArrayBuffer, connectionId: string): void;
27
+ protected [ClientMessageType.ServerStreamAbort](peer: Peer, buffer: ArrayBuffer, connectionId: string): void;
28
+ private createWsHooks;
29
+ private createServer;
27
30
  }