@nmtjs/ws-transport 0.2.0 → 0.2.2

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.js CHANGED
@@ -1,5 +1,5 @@
1
+ export * from "./lib/injectables.js";
1
2
  export * from "./lib/server.js";
2
3
  export * from "./lib/transport.js";
3
4
  export * from "./lib/types.js";
4
5
  export * from "./lib/utils.js";
5
- export * from "./lib/injectables.js";
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../../index.ts"],"sourcesContent":["export * from './lib/server.ts'\nexport * from './lib/transport.ts'\nexport * from './lib/types.ts'\nexport * from './lib/utils.ts'\nexport * from './lib/injectables.ts'\n"],"names":[],"mappings":"AAAA,cAAc,kBAAiB;AAC/B,cAAc,qBAAoB;AAClC,cAAc,iBAAgB;AAC9B,cAAc,iBAAgB;AAC9B,cAAc,uBAAsB"}
1
+ {"version":3,"sources":["../../index.ts"],"sourcesContent":["export * from './lib/injectables.ts'\nexport * from './lib/server.ts'\nexport * from './lib/transport.ts'\nexport * from './lib/types.ts'\nexport * from './lib/utils.ts'\n"],"names":[],"mappings":"AAAA,cAAc,uBAAsB;AACpC,cAAc,kBAAiB;AAC/B,cAAc,qBAAoB;AAClC,cAAc,iBAAgB;AAC9B,cAAc,iBAAgB"}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../lib/injectables.ts"],"sourcesContent":["import type { LazyInjectable, Scope } from '@nmtjs/core'\nimport { ProtocolInjectables } from '@nmtjs/protocol/server'\nimport type { WsUserData } from './types.ts'\n\nconst connectionData =\n ProtocolInjectables.connectionData as unknown as LazyInjectable<\n WsUserData['request'],\n Scope.Connection\n >\n\nexport const WsTransportInjectables = {\n connectionData,\n} as const\n"],"names":["ProtocolInjectables","connectionData","WsTransportInjectables"],"mappings":"AACA,SAASA,mBAAmB,QAAQ,yBAAwB;AAG5D,MAAMC,iBACJD,oBAAoBC,cAAc;AAKpC,OAAO,MAAMC,yBAAyB;IACpCD;AACF,EAAU"}
1
+ {"version":3,"sources":["../../../lib/injectables.ts"],"sourcesContent":["import type { LazyInjectable, Scope } from '@nmtjs/core'\nimport { ProtocolInjectables } from '@nmtjs/protocol/server'\nimport type { WsUserData } from './types.ts'\n\nconst connectionData = ProtocolInjectables.connectionData as LazyInjectable<\n WsUserData['request'],\n Scope.Connection\n>\n\nexport const WsTransportInjectables = {\n connectionData,\n} as const\n"],"names":["ProtocolInjectables","connectionData","WsTransportInjectables"],"mappings":"AACA,SAASA,mBAAmB,QAAQ,yBAAwB;AAG5D,MAAMC,iBAAiBD,oBAAoBC,cAAc;AAKzD,OAAO,MAAMC,yBAAyB;IACpCD;AACF,EAAU"}
@@ -1,8 +1,10 @@
1
- import { randomUUID } from 'node:crypto';
2
1
  import { App, SSLApp } from 'uWebSockets.js';
2
+ import assert from 'node:assert';
3
+ import { randomUUID } from 'node:crypto';
3
4
  import { createPromise } from '@nmtjs/common';
4
5
  import { ClientMessageType, decodeNumber } from '@nmtjs/protocol/common';
5
6
  import { ProtocolInjectables } from '@nmtjs/protocol/server';
7
+ import { WsTransportInjectables } from "./injectables.js";
6
8
  import { getRequestData, send } from "./utils.js";
7
9
  export class WsTransportServer {
8
10
  context;
@@ -52,13 +54,14 @@ export class WsTransportServer {
52
54
  try {
53
55
  const { context: _context, connection } = await this.context.protocol.connections.add(this, {
54
56
  id,
55
- data: request
57
+ data: {}
56
58
  }, {
57
59
  acceptType: request.acceptType,
58
60
  contentType: request.contentType
59
61
  });
60
62
  Object.assign(context, _context);
61
63
  context.container.provide(ProtocolInjectables.connection, connection);
64
+ context.container.provide(WsTransportInjectables.connectionData, request);
62
65
  opening.resolve();
63
66
  } catch (error) {
64
67
  opening.reject(error);
@@ -92,7 +95,9 @@ export class WsTransportServer {
92
95
  });
93
96
  }
94
97
  send(connection, messageType, buffer) {
95
- send(connection.data.ws, messageType, buffer);
98
+ const ws = this.clients.get(connection.id);
99
+ assert(ws, 'Websocket not found');
100
+ send(ws, messageType, buffer);
96
101
  }
97
102
  async start() {
98
103
  return new Promise((resolve, reject)=>{
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../lib/server.ts"],"sourcesContent":["import { randomUUID } from 'node:crypto'\nimport {\n App,\n type HttpRequest,\n type HttpResponse,\n SSLApp,\n type TemplatedApp,\n} from 'uWebSockets.js'\n\nimport { createPromise } from '@nmtjs/common'\nimport {\n ClientMessageType,\n type ServerMessageType,\n decodeNumber,\n decodeText,\n} from '@nmtjs/protocol/common'\nimport {\n type Connection,\n ProtocolInjectables,\n type Transport,\n type TransportPluginContext,\n} from '@nmtjs/protocol/server'\nimport type {\n WsTransportOptions,\n WsTransportSocket,\n WsUserData,\n} from './types.ts'\nimport { getRequestData, send } from './utils.ts'\n\nexport type WsConnectionData = {\n ws: WsTransportSocket\n}\n\nexport class WsTransportServer implements Transport<WsConnectionData> {\n protected server!: TemplatedApp\n protected clients: Map<string, WsTransportSocket> = new Map()\n\n constructor(\n protected readonly context: TransportPluginContext,\n protected readonly options: WsTransportOptions,\n ) {\n this.server = this.options.tls ? SSLApp(options.tls!) : App()\n\n this.server\n .options('/*', (res, req) => {\n this.applyCors(res, req)\n res.writeStatus('200 OK')\n res.endWithoutBody()\n })\n .get('/healthy', (res, req) => {\n this.applyCors(res, req)\n res.writeHeader('Content-Type', 'text/plain')\n res.end('OK')\n })\n .ws<WsUserData>('/api', {\n sendPingsAutomatically: true,\n maxPayloadLength: this.options.maxPayloadLength,\n upgrade: (res, req, context) => {\n const requestData = getRequestData(req)\n\n const contentType =\n requestData.headers.get('content-type') ||\n requestData.query.get('content-type')\n\n const acceptType =\n requestData.headers.get('accept') || requestData.query.get('accept')\n\n const data: WsUserData = {\n id: randomUUID(),\n request: {\n query: requestData.query,\n headers: requestData.headers,\n proxiedRemoteAddress: Buffer.from(\n res.getProxiedRemoteAddressAsText(),\n ).toString(),\n remoteAddress: Buffer.from(\n res.getRemoteAddressAsText(),\n ).toString(),\n contentType,\n acceptType,\n },\n opening: createPromise(),\n backpressure: null,\n context: {} as any,\n }\n\n res.upgrade(\n data,\n req.getHeader('sec-websocket-key'),\n req.getHeader('sec-websocket-protocol'),\n req.getHeader('sec-websocket-extensions'),\n context,\n )\n },\n open: async (ws: WsTransportSocket) => {\n const { id, context, request, opening } = ws.getUserData()\n this.clients.set(id, ws)\n this.logger.debug('Connection %s opened', id)\n try {\n const { context: _context, connection } =\n await this.context.protocol.connections.add(\n this,\n { id, data: request },\n {\n acceptType: request.acceptType,\n contentType: request.contentType,\n },\n )\n Object.assign(context, _context)\n context.container.provide(\n ProtocolInjectables.connection,\n connection,\n )\n opening.resolve()\n } catch (error) {\n opening.reject(error)\n }\n },\n message: async (ws: WsTransportSocket, buffer) => {\n const { opening } = ws.getUserData()\n const messageType = decodeNumber(buffer, 'Uint8')\n if (messageType in this === false) {\n ws.end(1011, 'Unknown message type')\n } else {\n try {\n await opening.promise\n await this[messageType](\n ws,\n buffer.slice(Uint8Array.BYTES_PER_ELEMENT),\n )\n } catch (error: any) {\n this.logError(error, 'Error while processing message')\n }\n }\n },\n drain: (ws: WsTransportSocket) => {\n const data = ws.getUserData()\n data.backpressure?.resolve()\n data.backpressure = null\n },\n close: async (ws: WsTransportSocket, code, message) => {\n const { id } = ws.getUserData()\n\n this.logger.debug(\n 'Connection %s closed with code %s: %s',\n id,\n code,\n Buffer.from(message).toString(),\n )\n this.clients.delete(id)\n await this.protocol.connections.remove(id)\n },\n })\n }\n\n send(\n connection: Connection<WsConnectionData>,\n messageType: ServerMessageType,\n buffer: ArrayBuffer,\n ) {\n send(connection.data.ws, messageType, buffer)\n }\n\n async start() {\n return new Promise<void>((resolve, reject) => {\n const hostname = this.options.hostname ?? '127.0.0.1'\n this.server.listen(hostname, this.options.port!, (socket) => {\n if (socket) {\n this.logger.info(\n 'Server started on %s:%s',\n hostname,\n this.options.port!,\n )\n resolve()\n } else {\n reject(new Error('Failed to start server'))\n }\n })\n })\n }\n\n async stop() {\n this.server.close()\n }\n\n protected get protocol() {\n return this.context.protocol\n }\n\n protected get logger() {\n return this.context.logger\n }\n\n protected async logError(\n cause: Error,\n message = 'Unknown error while processing request',\n ) {\n this.logger.error(new Error(message, { cause }))\n }\n\n protected applyCors(res: HttpResponse, req: HttpRequest) {\n // TODO: this should be configurable\n const origin = req.getHeader('origin')\n if (!origin) return\n res.writeHeader('Access-Control-Allow-Origin', origin)\n res.writeHeader('Access-Control-Allow-Headers', 'Content-Type')\n res.writeHeader('Access-Control-Allow-Methods', 'GET, POST')\n res.writeHeader('Access-Control-Allow-Credentials', 'true')\n }\n\n protected [ClientMessageType.Rpc](\n ws: WsTransportSocket,\n buffer: ArrayBuffer,\n ) {\n const { id } = ws.getUserData()\n this.protocol.rpcRaw(id, buffer)\n }\n\n protected [ClientMessageType.RpcAbort](\n ws: WsTransportSocket,\n buffer: ArrayBuffer,\n ) {\n const { id } = ws.getUserData()\n this.protocol.rpcAbortRaw(id, buffer)\n }\n\n protected [ClientMessageType.RpcStreamAbort](\n ws: WsTransportSocket,\n buffer: ArrayBuffer,\n ) {\n const { id } = ws.getUserData()\n this.protocol.rpcStreamAbortRaw(id, buffer)\n }\n\n protected [ClientMessageType.ClientStreamPush](\n ws: WsTransportSocket,\n buffer: ArrayBuffer,\n ) {\n const { id } = ws.getUserData()\n const streamId = decodeNumber(buffer, 'Uint32')\n this.protocol.clientStreams.push(\n id,\n streamId,\n buffer.slice(Uint32Array.BYTES_PER_ELEMENT),\n )\n }\n\n protected [ClientMessageType.ClientStreamEnd](\n ws: WsTransportSocket,\n buffer: ArrayBuffer,\n ) {\n const { id } = ws.getUserData()\n const streamId = decodeNumber(buffer, 'Uint32')\n this.protocol.clientStreams.end(id, streamId)\n }\n\n protected [ClientMessageType.ClientStreamAbort](\n ws: WsTransportSocket,\n buffer: ArrayBuffer,\n ) {\n const { id } = ws.getUserData()\n const streamId = decodeNumber(buffer, 'Uint32')\n this.protocol.clientStreams.abort(id, streamId)\n }\n\n protected [ClientMessageType.ServerStreamPull](\n ws: WsTransportSocket,\n buffer: ArrayBuffer,\n ) {\n const { id } = ws.getUserData()\n const streamId = decodeNumber(buffer, 'Uint32')\n this.protocol.serverStreams.pull(id, streamId)\n }\n\n protected [ClientMessageType.ServerStreamAbort](\n ws: WsTransportSocket,\n buffer: ArrayBuffer,\n ) {\n const { id } = ws.getUserData()\n const streamId = decodeNumber(buffer, 'Uint32')\n this.protocol.serverStreams.abort(id, streamId)\n }\n}\n"],"names":["randomUUID","App","SSLApp","createPromise","ClientMessageType","decodeNumber","ProtocolInjectables","getRequestData","send","WsTransportServer","server","clients","constructor","context","options","Map","tls","res","req","applyCors","writeStatus","endWithoutBody","get","writeHeader","end","ws","sendPingsAutomatically","maxPayloadLength","upgrade","requestData","contentType","headers","query","acceptType","data","id","request","proxiedRemoteAddress","Buffer","from","getProxiedRemoteAddressAsText","toString","remoteAddress","getRemoteAddressAsText","opening","backpressure","getHeader","open","getUserData","set","logger","debug","_context","connection","protocol","connections","add","Object","assign","container","provide","resolve","error","reject","message","buffer","messageType","promise","slice","Uint8Array","BYTES_PER_ELEMENT","logError","drain","close","code","delete","remove","start","Promise","hostname","listen","port","socket","info","Error","stop","cause","origin","Rpc","rpcRaw","RpcAbort","rpcAbortRaw","RpcStreamAbort","rpcStreamAbortRaw","ClientStreamPush","streamId","clientStreams","push","Uint32Array","ClientStreamEnd","ClientStreamAbort","abort","ServerStreamPull","serverStreams","pull","ServerStreamAbort"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../lib/server.ts"],"sourcesContent":["import {\n App,\n type HttpRequest,\n type HttpResponse,\n SSLApp,\n type TemplatedApp,\n} from 'uWebSockets.js'\nimport assert from 'node:assert'\nimport { randomUUID } from 'node:crypto'\nimport { createPromise } from '@nmtjs/common'\nimport {\n ClientMessageType,\n decodeNumber,\n type ServerMessageType,\n} from '@nmtjs/protocol/common'\nimport {\n type Connection,\n ProtocolInjectables,\n type Transport,\n type TransportPluginContext,\n} from '@nmtjs/protocol/server'\nimport { WsTransportInjectables } from './injectables.ts'\nimport type {\n WsTransportOptions,\n WsTransportSocket,\n WsUserData,\n} from './types.ts'\nimport { getRequestData, send } from './utils.ts'\n\nexport type WsConnectionData = {}\n\nexport class WsTransportServer implements Transport<WsConnectionData> {\n protected server!: TemplatedApp\n protected clients: Map<string, WsTransportSocket> = new Map()\n\n constructor(\n protected readonly context: TransportPluginContext,\n protected readonly options: WsTransportOptions,\n ) {\n this.server = this.options.tls ? SSLApp(options.tls!) : App()\n\n this.server\n .options('/*', (res, req) => {\n this.applyCors(res, req)\n res.writeStatus('200 OK')\n res.endWithoutBody()\n })\n .get('/healthy', (res, req) => {\n this.applyCors(res, req)\n res.writeHeader('Content-Type', 'text/plain')\n res.end('OK')\n })\n .ws<WsUserData>('/api', {\n sendPingsAutomatically: true,\n maxPayloadLength: this.options.maxPayloadLength,\n upgrade: (res, req, context) => {\n const requestData = getRequestData(req)\n\n const contentType =\n requestData.headers.get('content-type') ||\n requestData.query.get('content-type')\n\n const acceptType =\n requestData.headers.get('accept') || requestData.query.get('accept')\n\n const data: WsUserData = {\n id: randomUUID(),\n request: {\n query: requestData.query,\n headers: requestData.headers,\n proxiedRemoteAddress: Buffer.from(\n res.getProxiedRemoteAddressAsText(),\n ).toString(),\n remoteAddress: Buffer.from(\n res.getRemoteAddressAsText(),\n ).toString(),\n contentType,\n acceptType,\n },\n opening: createPromise(),\n backpressure: null,\n context: {} as any,\n }\n\n res.upgrade(\n data,\n req.getHeader('sec-websocket-key'),\n req.getHeader('sec-websocket-protocol'),\n req.getHeader('sec-websocket-extensions'),\n context,\n )\n },\n open: async (ws: WsTransportSocket) => {\n const { id, context, request, opening } = ws.getUserData()\n this.clients.set(id, ws)\n this.logger.debug('Connection %s opened', id)\n try {\n const { context: _context, connection } =\n await this.context.protocol.connections.add(\n this,\n { id, data: {} },\n {\n acceptType: request.acceptType,\n contentType: request.contentType,\n },\n )\n Object.assign(context, _context)\n context.container.provide(\n ProtocolInjectables.connection,\n connection,\n )\n context.container.provide(\n WsTransportInjectables.connectionData,\n request,\n )\n opening.resolve()\n } catch (error) {\n opening.reject(error)\n }\n },\n message: async (ws: WsTransportSocket, buffer) => {\n const { opening } = ws.getUserData()\n const messageType = decodeNumber(buffer, 'Uint8')\n if (messageType in this === false) {\n ws.end(1011, 'Unknown message type')\n } else {\n try {\n await opening.promise\n await this[messageType](\n ws,\n buffer.slice(Uint8Array.BYTES_PER_ELEMENT),\n )\n } catch (error: any) {\n this.logError(error, 'Error while processing message')\n }\n }\n },\n drain: (ws: WsTransportSocket) => {\n const data = ws.getUserData()\n data.backpressure?.resolve()\n data.backpressure = null\n },\n close: async (ws: WsTransportSocket, code, message) => {\n const { id } = ws.getUserData()\n\n this.logger.debug(\n 'Connection %s closed with code %s: %s',\n id,\n code,\n Buffer.from(message).toString(),\n )\n this.clients.delete(id)\n await this.protocol.connections.remove(id)\n },\n })\n }\n\n send(\n connection: Connection<WsConnectionData>,\n messageType: ServerMessageType,\n buffer: ArrayBuffer,\n ) {\n const ws = this.clients.get(connection.id)\n assert(ws, 'Websocket not found')\n send(ws, messageType, buffer)\n }\n\n async start() {\n return new Promise<void>((resolve, reject) => {\n const hostname = this.options.hostname ?? '127.0.0.1'\n this.server.listen(hostname, this.options.port!, (socket) => {\n if (socket) {\n this.logger.info(\n 'Server started on %s:%s',\n hostname,\n this.options.port!,\n )\n resolve()\n } else {\n reject(new Error('Failed to start server'))\n }\n })\n })\n }\n\n async stop() {\n this.server.close()\n }\n\n protected get protocol() {\n return this.context.protocol\n }\n\n protected get logger() {\n return this.context.logger\n }\n\n protected async logError(\n cause: Error,\n message = 'Unknown error while processing request',\n ) {\n this.logger.error(new Error(message, { cause }))\n }\n\n protected applyCors(res: HttpResponse, req: HttpRequest) {\n // TODO: this should be configurable\n const origin = req.getHeader('origin')\n if (!origin) return\n res.writeHeader('Access-Control-Allow-Origin', origin)\n res.writeHeader('Access-Control-Allow-Headers', 'Content-Type')\n res.writeHeader('Access-Control-Allow-Methods', 'GET, POST')\n res.writeHeader('Access-Control-Allow-Credentials', 'true')\n }\n\n protected [ClientMessageType.Rpc](\n ws: WsTransportSocket,\n buffer: ArrayBuffer,\n ) {\n const { id } = ws.getUserData()\n this.protocol.rpcRaw(id, buffer)\n }\n\n protected [ClientMessageType.RpcAbort](\n ws: WsTransportSocket,\n buffer: ArrayBuffer,\n ) {\n const { id } = ws.getUserData()\n this.protocol.rpcAbortRaw(id, buffer)\n }\n\n protected [ClientMessageType.RpcStreamAbort](\n ws: WsTransportSocket,\n buffer: ArrayBuffer,\n ) {\n const { id } = ws.getUserData()\n this.protocol.rpcStreamAbortRaw(id, buffer)\n }\n\n protected [ClientMessageType.ClientStreamPush](\n ws: WsTransportSocket,\n buffer: ArrayBuffer,\n ) {\n const { id } = ws.getUserData()\n const streamId = decodeNumber(buffer, 'Uint32')\n this.protocol.clientStreams.push(\n id,\n streamId,\n buffer.slice(Uint32Array.BYTES_PER_ELEMENT),\n )\n }\n\n protected [ClientMessageType.ClientStreamEnd](\n ws: WsTransportSocket,\n buffer: ArrayBuffer,\n ) {\n const { id } = ws.getUserData()\n const streamId = decodeNumber(buffer, 'Uint32')\n this.protocol.clientStreams.end(id, streamId)\n }\n\n protected [ClientMessageType.ClientStreamAbort](\n ws: WsTransportSocket,\n buffer: ArrayBuffer,\n ) {\n const { id } = ws.getUserData()\n const streamId = decodeNumber(buffer, 'Uint32')\n this.protocol.clientStreams.abort(id, streamId)\n }\n\n protected [ClientMessageType.ServerStreamPull](\n ws: WsTransportSocket,\n buffer: ArrayBuffer,\n ) {\n const { id } = ws.getUserData()\n const streamId = decodeNumber(buffer, 'Uint32')\n this.protocol.serverStreams.pull(id, streamId)\n }\n\n protected [ClientMessageType.ServerStreamAbort](\n ws: WsTransportSocket,\n buffer: ArrayBuffer,\n ) {\n const { id } = ws.getUserData()\n const streamId = decodeNumber(buffer, 'Uint32')\n this.protocol.serverStreams.abort(id, streamId)\n }\n}\n"],"names":["App","SSLApp","assert","randomUUID","createPromise","ClientMessageType","decodeNumber","ProtocolInjectables","WsTransportInjectables","getRequestData","send","WsTransportServer","server","clients","constructor","context","options","Map","tls","res","req","applyCors","writeStatus","endWithoutBody","get","writeHeader","end","ws","sendPingsAutomatically","maxPayloadLength","upgrade","requestData","contentType","headers","query","acceptType","data","id","request","proxiedRemoteAddress","Buffer","from","getProxiedRemoteAddressAsText","toString","remoteAddress","getRemoteAddressAsText","opening","backpressure","getHeader","open","getUserData","set","logger","debug","_context","connection","protocol","connections","add","Object","assign","container","provide","connectionData","resolve","error","reject","message","buffer","messageType","promise","slice","Uint8Array","BYTES_PER_ELEMENT","logError","drain","close","code","delete","remove","start","Promise","hostname","listen","port","socket","info","Error","stop","cause","origin","Rpc","rpcRaw","RpcAbort","rpcAbortRaw","RpcStreamAbort","rpcStreamAbortRaw","ClientStreamPush","streamId","clientStreams","push","Uint32Array","ClientStreamEnd","ClientStreamAbort","abort","ServerStreamPull","serverStreams","pull","ServerStreamAbort"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../lib/types.ts"],"sourcesContent":["import type { InteractivePromise } from '@nmtjs/common'\nimport type { Connection, ConnectionContext } from '@nmtjs/protocol/server'\nimport type { AppOptions, WebSocket } from 'uWebSockets.js'\n\nexport type WsUserData = {\n id: Connection['id']\n opening: InteractivePromise<void>\n backpressure: InteractivePromise<void> | null\n request: {\n headers: Map<string, string>\n query: URLSearchParams\n remoteAddress: string\n proxiedRemoteAddress: string\n acceptType: string | null\n contentType: string | null\n }\n context: ConnectionContext\n}\n\nexport type WsTransportSocket = WebSocket<WsUserData>\n\nexport type WsTransportOptions = {\n port?: number\n hostname?: string\n unix?: string\n tls?: AppOptions\n maxPayloadLength?: number\n maxStreamChunkLength?: number\n}\n"],"names":[],"mappings":"AAqBA,WAOC"}
1
+ {"version":3,"sources":["../../../lib/types.ts"],"sourcesContent":["import type { AppOptions, WebSocket } from 'uWebSockets.js'\nimport type { InteractivePromise } from '@nmtjs/common'\nimport type { Connection, ConnectionContext } from '@nmtjs/protocol/server'\n\nexport type WsUserData = {\n id: Connection['id']\n opening: InteractivePromise<void>\n backpressure: InteractivePromise<void> | null\n request: {\n headers: Map<string, string>\n query: URLSearchParams\n remoteAddress: string\n proxiedRemoteAddress: string\n acceptType: string | null\n contentType: string | null\n }\n context: ConnectionContext\n}\n\nexport type WsTransportSocket = WebSocket<WsUserData>\n\nexport type WsTransportOptions = {\n port?: number\n hostname?: string\n unix?: string\n tls?: AppOptions\n maxPayloadLength?: number\n maxStreamChunkLength?: number\n}\n"],"names":[],"mappings":"AAqBA,WAOC"}
package/dist/lib/utils.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { createPromise } from '@nmtjs/common';
2
- import { ErrorCode, concat, encodeNumber } from '@nmtjs/protocol/common';
2
+ import { concat, ErrorCode, encodeNumber } from '@nmtjs/protocol/common';
3
3
  import { ProtocolError } from '@nmtjs/protocol/server';
4
4
  export const send = (ws, type, ...buffers)=>{
5
5
  const data = ws.getUserData();
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../lib/utils.ts"],"sourcesContent":["import { createPromise } from '@nmtjs/common'\nimport { ErrorCode, concat, encodeNumber } from '@nmtjs/protocol/common'\nimport { ProtocolError } from '@nmtjs/protocol/server'\nimport type { HttpRequest } from 'uWebSockets.js'\nimport type { WsTransportSocket } from './types.ts'\n\nexport const send = (\n ws: WsTransportSocket,\n type: number,\n ...buffers: ArrayBuffer[]\n): boolean | null => {\n const data = ws.getUserData()\n try {\n const buffer = concat(encodeNumber(type, 'Uint8'), ...buffers)\n const result = ws.send(buffer, true)\n if (result === 0) {\n data.backpressure = createPromise()\n return false\n }\n if (result === 2) {\n return null\n }\n return true\n } catch (error) {\n return null\n }\n}\n\nexport const toRecord = (input: {\n forEach: (cb: (value, key) => void) => void\n}) => {\n const obj: Record<string, string> = {}\n input.forEach((value, key) => {\n obj[key] = value\n })\n return obj\n}\n\ntype RequestData = {\n url: string\n origin: URL | null\n method: string\n headers: Map<string, string>\n query: URLSearchParams\n}\n\nexport const getRequestData = (req: HttpRequest): RequestData => {\n const url = req.getUrl()\n const method = req.getMethod()\n const headers = new Map()\n req.forEach((key, value) => headers.set(key, value))\n const query = new URLSearchParams(req.getQuery())\n const origin = headers.has('origin')\n ? new URL(url, headers.get('origin'))\n : null\n\n return {\n url,\n origin,\n method,\n headers,\n query,\n }\n}\n\nexport const InternalError = (message = 'Internal Server Error') =>\n new ProtocolError(ErrorCode.InternalServerError, message)\n\nexport const NotFoundError = (message = 'Not Found') =>\n new ProtocolError(ErrorCode.NotFound, message)\n\nexport const ForbiddenError = (message = 'Forbidden') =>\n new ProtocolError(ErrorCode.Forbidden, message)\n\nexport const RequestTimeoutError = (message = 'Request Timeout') =>\n new ProtocolError(ErrorCode.RequestTimeout, message)\n"],"names":["createPromise","ErrorCode","concat","encodeNumber","ProtocolError","send","ws","type","buffers","data","getUserData","buffer","result","backpressure","error","toRecord","input","obj","forEach","value","key","getRequestData","req","url","getUrl","method","getMethod","headers","Map","set","query","URLSearchParams","getQuery","origin","has","URL","get","InternalError","message","InternalServerError","NotFoundError","NotFound","ForbiddenError","Forbidden","RequestTimeoutError","RequestTimeout"],"mappings":"AAAA,SAASA,aAAa,QAAQ,gBAAe;AAC7C,SAASC,SAAS,EAAEC,MAAM,EAAEC,YAAY,QAAQ,yBAAwB;AACxE,SAASC,aAAa,QAAQ,yBAAwB;AAItD,OAAO,MAAMC,OAAO,CAClBC,IACAC,MACA,GAAGC;IAEH,MAAMC,OAAOH,GAAGI,WAAW;IAC3B,IAAI;QACF,MAAMC,SAAST,OAAOC,aAAaI,MAAM,aAAaC;QACtD,MAAMI,SAASN,GAAGD,IAAI,CAACM,QAAQ;QAC/B,IAAIC,WAAW,GAAG;YAChBH,KAAKI,YAAY,GAAGb;YACpB,OAAO;QACT;QACA,IAAIY,WAAW,GAAG;YAChB,OAAO;QACT;QACA,OAAO;IACT,EAAE,OAAOE,OAAO;QACd,OAAO;IACT;AACF,EAAC;AAED,OAAO,MAAMC,WAAW,CAACC;IAGvB,MAAMC,MAA8B,CAAC;IACrCD,MAAME,OAAO,CAAC,CAACC,OAAOC;QACpBH,GAAG,CAACG,IAAI,GAAGD;IACb;IACA,OAAOF;AACT,EAAC;AAUD,OAAO,MAAMI,iBAAiB,CAACC;IAC7B,MAAMC,MAAMD,IAAIE,MAAM;IACtB,MAAMC,SAASH,IAAII,SAAS;IAC5B,MAAMC,UAAU,IAAIC;IACpBN,IAAIJ,OAAO,CAAC,CAACE,KAAKD,QAAUQ,QAAQE,GAAG,CAACT,KAAKD;IAC7C,MAAMW,QAAQ,IAAIC,gBAAgBT,IAAIU,QAAQ;IAC9C,MAAMC,SAASN,QAAQO,GAAG,CAAC,YACvB,IAAIC,IAAIZ,KAAKI,QAAQS,GAAG,CAAC,aACzB;IAEJ,OAAO;QACLb;QACAU;QACAR;QACAE;QACAG;IACF;AACF,EAAC;AAED,OAAO,MAAMO,gBAAgB,CAACC,UAAU,uBAAuB,GAC7D,IAAIlC,cAAcH,UAAUsC,mBAAmB,EAAED,SAAQ;AAE3D,OAAO,MAAME,gBAAgB,CAACF,UAAU,WAAW,GACjD,IAAIlC,cAAcH,UAAUwC,QAAQ,EAAEH,SAAQ;AAEhD,OAAO,MAAMI,iBAAiB,CAACJ,UAAU,WAAW,GAClD,IAAIlC,cAAcH,UAAU0C,SAAS,EAAEL,SAAQ;AAEjD,OAAO,MAAMM,sBAAsB,CAACN,UAAU,iBAAiB,GAC7D,IAAIlC,cAAcH,UAAU4C,cAAc,EAAEP,SAAQ"}
1
+ {"version":3,"sources":["../../../lib/utils.ts"],"sourcesContent":["import type { HttpRequest } from 'uWebSockets.js'\nimport { createPromise } from '@nmtjs/common'\nimport { concat, ErrorCode, encodeNumber } from '@nmtjs/protocol/common'\nimport { ProtocolError } from '@nmtjs/protocol/server'\nimport type { WsTransportSocket } from './types.ts'\n\nexport const send = (\n ws: WsTransportSocket,\n type: number,\n ...buffers: ArrayBuffer[]\n): boolean | null => {\n const data = ws.getUserData()\n try {\n const buffer = concat(encodeNumber(type, 'Uint8'), ...buffers)\n const result = ws.send(buffer, true)\n if (result === 0) {\n data.backpressure = createPromise()\n return false\n }\n if (result === 2) {\n return null\n }\n return true\n } catch (error) {\n return null\n }\n}\n\nexport const toRecord = (input: {\n forEach: (cb: (value, key) => void) => void\n}) => {\n const obj: Record<string, string> = {}\n input.forEach((value, key) => {\n obj[key] = value\n })\n return obj\n}\n\ntype RequestData = {\n url: string\n origin: URL | null\n method: string\n headers: Map<string, string>\n query: URLSearchParams\n}\n\nexport const getRequestData = (req: HttpRequest): RequestData => {\n const url = req.getUrl()\n const method = req.getMethod()\n const headers = new Map()\n req.forEach((key, value) => headers.set(key, value))\n const query = new URLSearchParams(req.getQuery())\n const origin = headers.has('origin')\n ? new URL(url, headers.get('origin'))\n : null\n\n return {\n url,\n origin,\n method,\n headers,\n query,\n }\n}\n\nexport const InternalError = (message = 'Internal Server Error') =>\n new ProtocolError(ErrorCode.InternalServerError, message)\n\nexport const NotFoundError = (message = 'Not Found') =>\n new ProtocolError(ErrorCode.NotFound, message)\n\nexport const ForbiddenError = (message = 'Forbidden') =>\n new ProtocolError(ErrorCode.Forbidden, message)\n\nexport const RequestTimeoutError = (message = 'Request Timeout') =>\n new ProtocolError(ErrorCode.RequestTimeout, message)\n"],"names":["createPromise","concat","ErrorCode","encodeNumber","ProtocolError","send","ws","type","buffers","data","getUserData","buffer","result","backpressure","error","toRecord","input","obj","forEach","value","key","getRequestData","req","url","getUrl","method","getMethod","headers","Map","set","query","URLSearchParams","getQuery","origin","has","URL","get","InternalError","message","InternalServerError","NotFoundError","NotFound","ForbiddenError","Forbidden","RequestTimeoutError","RequestTimeout"],"mappings":"AACA,SAASA,aAAa,QAAQ,gBAAe;AAC7C,SAASC,MAAM,EAAEC,SAAS,EAAEC,YAAY,QAAQ,yBAAwB;AACxE,SAASC,aAAa,QAAQ,yBAAwB;AAGtD,OAAO,MAAMC,OAAO,CAClBC,IACAC,MACA,GAAGC;IAEH,MAAMC,OAAOH,GAAGI,WAAW;IAC3B,IAAI;QACF,MAAMC,SAASV,OAAOE,aAAaI,MAAM,aAAaC;QACtD,MAAMI,SAASN,GAAGD,IAAI,CAACM,QAAQ;QAC/B,IAAIC,WAAW,GAAG;YAChBH,KAAKI,YAAY,GAAGb;YACpB,OAAO;QACT;QACA,IAAIY,WAAW,GAAG;YAChB,OAAO;QACT;QACA,OAAO;IACT,EAAE,OAAOE,OAAO;QACd,OAAO;IACT;AACF,EAAC;AAED,OAAO,MAAMC,WAAW,CAACC;IAGvB,MAAMC,MAA8B,CAAC;IACrCD,MAAME,OAAO,CAAC,CAACC,OAAOC;QACpBH,GAAG,CAACG,IAAI,GAAGD;IACb;IACA,OAAOF;AACT,EAAC;AAUD,OAAO,MAAMI,iBAAiB,CAACC;IAC7B,MAAMC,MAAMD,IAAIE,MAAM;IACtB,MAAMC,SAASH,IAAII,SAAS;IAC5B,MAAMC,UAAU,IAAIC;IACpBN,IAAIJ,OAAO,CAAC,CAACE,KAAKD,QAAUQ,QAAQE,GAAG,CAACT,KAAKD;IAC7C,MAAMW,QAAQ,IAAIC,gBAAgBT,IAAIU,QAAQ;IAC9C,MAAMC,SAASN,QAAQO,GAAG,CAAC,YACvB,IAAIC,IAAIZ,KAAKI,QAAQS,GAAG,CAAC,aACzB;IAEJ,OAAO;QACLb;QACAU;QACAR;QACAE;QACAG;IACF;AACF,EAAC;AAED,OAAO,MAAMO,gBAAgB,CAACC,UAAU,uBAAuB,GAC7D,IAAIlC,cAAcF,UAAUqC,mBAAmB,EAAED,SAAQ;AAE3D,OAAO,MAAME,gBAAgB,CAACF,UAAU,WAAW,GACjD,IAAIlC,cAAcF,UAAUuC,QAAQ,EAAEH,SAAQ;AAEhD,OAAO,MAAMI,iBAAiB,CAACJ,UAAU,WAAW,GAClD,IAAIlC,cAAcF,UAAUyC,SAAS,EAAEL,SAAQ;AAEjD,OAAO,MAAMM,sBAAsB,CAACN,UAAU,iBAAiB,GAC7D,IAAIlC,cAAcF,UAAU2C,cAAc,EAAEP,SAAQ"}
package/index.ts CHANGED
@@ -1,5 +1,5 @@
1
+ export * from './lib/injectables.ts'
1
2
  export * from './lib/server.ts'
2
3
  export * from './lib/transport.ts'
3
4
  export * from './lib/types.ts'
4
5
  export * from './lib/utils.ts'
5
- export * from './lib/injectables.ts'
@@ -2,11 +2,10 @@ import type { LazyInjectable, Scope } from '@nmtjs/core'
2
2
  import { ProtocolInjectables } from '@nmtjs/protocol/server'
3
3
  import type { WsUserData } from './types.ts'
4
4
 
5
- const connectionData =
6
- ProtocolInjectables.connectionData as unknown as LazyInjectable<
7
- WsUserData['request'],
8
- Scope.Connection
9
- >
5
+ const connectionData = ProtocolInjectables.connectionData as LazyInjectable<
6
+ WsUserData['request'],
7
+ Scope.Connection
8
+ >
10
9
 
11
10
  export const WsTransportInjectables = {
12
11
  connectionData,
package/lib/server.ts CHANGED
@@ -1,4 +1,3 @@
1
- import { randomUUID } from 'node:crypto'
2
1
  import {
3
2
  App,
4
3
  type HttpRequest,
@@ -6,13 +5,13 @@ import {
6
5
  SSLApp,
7
6
  type TemplatedApp,
8
7
  } from 'uWebSockets.js'
9
-
8
+ import assert from 'node:assert'
9
+ import { randomUUID } from 'node:crypto'
10
10
  import { createPromise } from '@nmtjs/common'
11
11
  import {
12
12
  ClientMessageType,
13
- type ServerMessageType,
14
13
  decodeNumber,
15
- decodeText,
14
+ type ServerMessageType,
16
15
  } from '@nmtjs/protocol/common'
17
16
  import {
18
17
  type Connection,
@@ -20,6 +19,7 @@ import {
20
19
  type Transport,
21
20
  type TransportPluginContext,
22
21
  } from '@nmtjs/protocol/server'
22
+ import { WsTransportInjectables } from './injectables.ts'
23
23
  import type {
24
24
  WsTransportOptions,
25
25
  WsTransportSocket,
@@ -27,9 +27,7 @@ import type {
27
27
  } from './types.ts'
28
28
  import { getRequestData, send } from './utils.ts'
29
29
 
30
- export type WsConnectionData = {
31
- ws: WsTransportSocket
32
- }
30
+ export type WsConnectionData = {}
33
31
 
34
32
  export class WsTransportServer implements Transport<WsConnectionData> {
35
33
  protected server!: TemplatedApp
@@ -100,7 +98,7 @@ export class WsTransportServer implements Transport<WsConnectionData> {
100
98
  const { context: _context, connection } =
101
99
  await this.context.protocol.connections.add(
102
100
  this,
103
- { id, data: request },
101
+ { id, data: {} },
104
102
  {
105
103
  acceptType: request.acceptType,
106
104
  contentType: request.contentType,
@@ -111,6 +109,10 @@ export class WsTransportServer implements Transport<WsConnectionData> {
111
109
  ProtocolInjectables.connection,
112
110
  connection,
113
111
  )
112
+ context.container.provide(
113
+ WsTransportInjectables.connectionData,
114
+ request,
115
+ )
114
116
  opening.resolve()
115
117
  } catch (error) {
116
118
  opening.reject(error)
@@ -158,7 +160,9 @@ export class WsTransportServer implements Transport<WsConnectionData> {
158
160
  messageType: ServerMessageType,
159
161
  buffer: ArrayBuffer,
160
162
  ) {
161
- send(connection.data.ws, messageType, buffer)
163
+ const ws = this.clients.get(connection.id)
164
+ assert(ws, 'Websocket not found')
165
+ send(ws, messageType, buffer)
162
166
  }
163
167
 
164
168
  async start() {
package/lib/types.ts CHANGED
@@ -1,6 +1,6 @@
1
+ import type { AppOptions, WebSocket } from 'uWebSockets.js'
1
2
  import type { InteractivePromise } from '@nmtjs/common'
2
3
  import type { Connection, ConnectionContext } from '@nmtjs/protocol/server'
3
- import type { AppOptions, WebSocket } from 'uWebSockets.js'
4
4
 
5
5
  export type WsUserData = {
6
6
  id: Connection['id']
package/lib/utils.ts CHANGED
@@ -1,7 +1,7 @@
1
+ import type { HttpRequest } from 'uWebSockets.js'
1
2
  import { createPromise } from '@nmtjs/common'
2
- import { ErrorCode, concat, encodeNumber } from '@nmtjs/protocol/common'
3
+ import { concat, ErrorCode, encodeNumber } from '@nmtjs/protocol/common'
3
4
  import { ProtocolError } from '@nmtjs/protocol/server'
4
- import type { HttpRequest } from 'uWebSockets.js'
5
5
  import type { WsTransportSocket } from './types.ts'
6
6
 
7
7
  export const send = (
package/package.json CHANGED
@@ -8,13 +8,18 @@
8
8
  }
9
9
  },
10
10
  "dependencies": {
11
- "uWebSockets.js": "github:uNetworking/uWebSockets.js#v20.51.0",
12
- "@nmtjs/core": "^0.6.1",
13
- "@nmtjs/protocol": "^0.6.1",
14
- "@nmtjs/common": "^0.6.1"
11
+ "uWebSockets.js": "github:uNetworking/uWebSockets.js#v20.51.0"
12
+ },
13
+ "peerDependencies": {
14
+ "@nmtjs/core": "^0.6.4",
15
+ "@nmtjs/protocol": "^0.6.4",
16
+ "@nmtjs/common": "^0.6.4"
15
17
  },
16
18
  "devDependencies": {
17
- "@types/node": "^18.0.0"
19
+ "@types/node": "^18.0.0",
20
+ "@nmtjs/core": "^0.6.4",
21
+ "@nmtjs/protocol": "^0.6.4",
22
+ "@nmtjs/common": "^0.6.4"
18
23
  },
19
24
  "engines": {
20
25
  "node": ">=18.9.0"
@@ -23,11 +28,10 @@
23
28
  "index.ts",
24
29
  "lib",
25
30
  "dist",
26
- "tsconfig.json",
27
31
  "LICENSE.md",
28
32
  "README.md"
29
33
  ],
30
- "version": "0.2.0",
34
+ "version": "0.2.2",
31
35
  "scripts": {
32
36
  "build": "neemata-build ./index.ts './lib/**/*.ts'",
33
37
  "type-check": "tsc --noEmit"
package/tsconfig.json DELETED
@@ -1,3 +0,0 @@
1
- {
2
- "extends": "../../tsconfig.json"
3
- }