@nmtjs/ws-transport 0.2.2 → 0.7.0

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/README.md CHANGED
@@ -1 +1,9 @@
1
- ## WebSockets transport for [Neemata](https://github.com/neematajs/neemata)
1
+ # NeemataJS - RPC application server for real-time applications (proof of concept)
2
+
3
+ ### Built with following in mind:
4
+ - transport-agnostic (like WebSockets, WebTransport, .etc)
5
+ - format-agnostic (like JSON, MessagePack, BSON, .etc)
6
+ - binary data streaming and event subscriptions
7
+ - contract-based API
8
+ - end-to-end type safety
9
+ - CPU-intensive task execution on separate workers
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
- export * from "./lib/injectables.js";
2
- export * from "./lib/server.js";
3
- export * from "./lib/transport.js";
4
- export * from "./lib/types.js";
5
- export * from "./lib/utils.js";
1
+ export * from "./injectables.js";
2
+ export * from "./server.js";
3
+ export * from "./transport.js";
4
+ export * from "./types.js";
5
+ export * from "./utils.js";
package/dist/index.js.map CHANGED
@@ -1 +1 @@
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
+ {"mappings":"AAAA,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc","names":[],"sources":["src/index.ts"],"sourcesContent":["export * from './injectables.ts'\nexport * from './server.ts'\nexport * from './transport.ts'\nexport * from './types.ts'\nexport * from './utils.ts'\n"],"version":3}
@@ -0,0 +1,3 @@
1
+ import { ProtocolInjectables } from "@nmtjs/protocol/server";
2
+ const connectionData = ProtocolInjectables.connectionData;
3
+ export const WsTransportInjectables = { connectionData };
@@ -0,0 +1 @@
1
+ {"mappings":"AACA,SAAS,2BAA2B,wBAAwB;AAG5D,MAAM,iBAAiB,oBAAoB;AAK3C,OAAO,MAAM,yBAAyB,EACpC,eACD","names":[],"sources":["src/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"],"version":3}
package/dist/server.js ADDED
@@ -0,0 +1,167 @@
1
+ import { App, SSLApp } from "uWebSockets.js";
2
+ import { randomUUID } from "node:crypto";
3
+ import { createPromise } from "@nmtjs/common";
4
+ import { ClientMessageType, decodeNumber } from "@nmtjs/protocol/common";
5
+ import { ProtocolInjectables } from "@nmtjs/protocol/server";
6
+ import { WsTransportInjectables } from "./injectables.js";
7
+ import { getRequestData, send } from "./utils.js";
8
+ export class WsTransportServer {
9
+ server;
10
+ clients = new Map();
11
+ constructor(context, options) {
12
+ this.context = context;
13
+ this.options = options;
14
+ this.server = this.options.tls ? SSLApp(options.tls) : App();
15
+ this.server.options("/*", (res, req) => {
16
+ this.applyCors(res, req);
17
+ res.writeStatus("200 OK");
18
+ res.endWithoutBody();
19
+ }).get("/healthy", (res, req) => {
20
+ this.applyCors(res, req);
21
+ res.writeHeader("Content-Type", "text/plain");
22
+ res.end("OK");
23
+ }).ws("/api", {
24
+ sendPingsAutomatically: true,
25
+ maxPayloadLength: this.options.maxPayloadLength,
26
+ upgrade: (res, req, context) => {
27
+ const requestData = getRequestData(req);
28
+ const contentType = requestData.headers.get("content-type") || requestData.query.get("content-type");
29
+ const acceptType = requestData.headers.get("accept") || requestData.query.get("accept");
30
+ const data = {
31
+ id: randomUUID(),
32
+ request: {
33
+ query: requestData.query,
34
+ headers: requestData.headers,
35
+ proxiedRemoteAddress: Buffer.from(res.getProxiedRemoteAddressAsText()).toString(),
36
+ remoteAddress: Buffer.from(res.getRemoteAddressAsText()).toString(),
37
+ contentType,
38
+ acceptType
39
+ },
40
+ opening: createPromise(),
41
+ backpressure: null,
42
+ context: {}
43
+ };
44
+ res.upgrade(data, req.getHeader("sec-websocket-key"), req.getHeader("sec-websocket-protocol"), req.getHeader("sec-websocket-extensions"), context);
45
+ },
46
+ open: async (ws) => {
47
+ const { id, context, request, opening } = ws.getUserData();
48
+ this.clients.set(id, ws);
49
+ this.logger.debug("Connection %s opened", id);
50
+ try {
51
+ const { context: _context, connection } = await this.context.protocol.connections.add(this, {
52
+ id,
53
+ data: {}
54
+ }, {
55
+ acceptType: request.acceptType,
56
+ contentType: request.contentType
57
+ });
58
+ Object.assign(context, _context);
59
+ context.container.provide(ProtocolInjectables.connection, connection);
60
+ context.container.provide(WsTransportInjectables.connectionData, request);
61
+ opening.resolve();
62
+ } catch (error) {
63
+ opening.reject(error);
64
+ }
65
+ },
66
+ message: async (ws, buffer) => {
67
+ const { opening } = ws.getUserData();
68
+ const messageType = decodeNumber(buffer, "Uint8");
69
+ if (messageType in this === false) {
70
+ ws.end(1011, "Unknown message type");
71
+ } else {
72
+ try {
73
+ await opening.promise;
74
+ await this[messageType](ws, buffer.slice(Uint8Array.BYTES_PER_ELEMENT));
75
+ } catch (error) {
76
+ this.logError(error, "Error while processing message");
77
+ }
78
+ }
79
+ },
80
+ drain: (ws) => {
81
+ const data = ws.getUserData();
82
+ data.backpressure?.resolve();
83
+ data.backpressure = null;
84
+ },
85
+ close: async (ws, code, message) => {
86
+ const { id } = ws.getUserData();
87
+ this.logger.debug("Connection %s closed with code %s: %s", id, code, Buffer.from(message).toString());
88
+ this.clients.delete(id);
89
+ await this.protocol.connections.remove(id);
90
+ }
91
+ });
92
+ }
93
+ send(connection, messageType, buffer) {
94
+ const ws = this.clients.get(connection.id);
95
+ if (ws) send(ws, messageType, buffer);
96
+ }
97
+ async start() {
98
+ return new Promise((resolve, reject) => {
99
+ const hostname = this.options.hostname ?? "127.0.0.1";
100
+ this.server.listen(hostname, this.options.port, (socket) => {
101
+ if (socket) {
102
+ this.logger.info("Server started on %s:%s", hostname, this.options.port);
103
+ resolve();
104
+ } else {
105
+ reject(new Error("Failed to start server"));
106
+ }
107
+ });
108
+ });
109
+ }
110
+ async stop() {
111
+ this.server.close();
112
+ }
113
+ get protocol() {
114
+ return this.context.protocol;
115
+ }
116
+ get logger() {
117
+ return this.context.logger;
118
+ }
119
+ async logError(cause, message = "Unknown error while processing request") {
120
+ this.logger.error(new Error(message, { cause }));
121
+ }
122
+ applyCors(res, req) {
123
+ const origin = req.getHeader("origin");
124
+ if (!origin) return;
125
+ res.writeHeader("Access-Control-Allow-Origin", origin);
126
+ res.writeHeader("Access-Control-Allow-Headers", "Content-Type");
127
+ res.writeHeader("Access-Control-Allow-Methods", "GET, POST");
128
+ res.writeHeader("Access-Control-Allow-Credentials", "true");
129
+ }
130
+ [ClientMessageType.Rpc](ws, buffer) {
131
+ const { id } = ws.getUserData();
132
+ this.protocol.rpcRaw(id, buffer);
133
+ }
134
+ [ClientMessageType.RpcAbort](ws, buffer) {
135
+ const { id } = ws.getUserData();
136
+ this.protocol.rpcAbortRaw(id, buffer);
137
+ }
138
+ [ClientMessageType.RpcStreamAbort](ws, buffer) {
139
+ const { id } = ws.getUserData();
140
+ this.protocol.rpcStreamAbortRaw(id, buffer);
141
+ }
142
+ [ClientMessageType.ClientStreamPush](ws, buffer) {
143
+ const { id } = ws.getUserData();
144
+ const streamId = decodeNumber(buffer, "Uint32");
145
+ this.protocol.clientStreams.push(id, streamId, buffer.slice(Uint32Array.BYTES_PER_ELEMENT));
146
+ }
147
+ [ClientMessageType.ClientStreamEnd](ws, buffer) {
148
+ const { id } = ws.getUserData();
149
+ const streamId = decodeNumber(buffer, "Uint32");
150
+ this.protocol.clientStreams.end(id, streamId);
151
+ }
152
+ [ClientMessageType.ClientStreamAbort](ws, buffer) {
153
+ const { id } = ws.getUserData();
154
+ const streamId = decodeNumber(buffer, "Uint32");
155
+ this.protocol.clientStreams.abort(id, streamId);
156
+ }
157
+ [ClientMessageType.ServerStreamPull](ws, buffer) {
158
+ const { id } = ws.getUserData();
159
+ const streamId = decodeNumber(buffer, "Uint32");
160
+ this.protocol.serverStreams.pull(id, streamId);
161
+ }
162
+ [ClientMessageType.ServerStreamAbort](ws, buffer) {
163
+ const { id } = ws.getUserData();
164
+ const streamId = decodeNumber(buffer, "Uint32");
165
+ this.protocol.serverStreams.abort(id, streamId);
166
+ }
167
+ }
@@ -0,0 +1 @@
1
+ {"mappings":"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","names":["context: TransportPluginContext","options: WsTransportOptions","data: WsUserData","ws: WsTransportSocket","error: any","connection: Connection<WsConnectionData>","messageType: ServerMessageType","buffer: ArrayBuffer","cause: Error","res: HttpResponse","req: HttpRequest"],"sources":["src/server.ts"],"sourcesContent":["import {\n App,\n type HttpRequest,\n type HttpResponse,\n SSLApp,\n type TemplatedApp,\n} from 'uWebSockets.js'\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 if (ws) 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"],"version":3}
@@ -0,0 +1,5 @@
1
+ import { createTransport } from "@nmtjs/protocol/server";
2
+ import { WsTransportServer } from "./server.js";
3
+ export const WsTransport = createTransport("WsTransport", (context, options) => {
4
+ return new WsTransportServer(context, options);
5
+ });
@@ -0,0 +1 @@
1
+ {"mappings":"AAAA,SAAS,uBAAuB,wBAAwB;AACxD,SAAgC,yBAAyB,aAAa;AAGtE,OAAO,MAAM,cAAc,gBAGzB,eAAe,CAAC,SAAS,YAAY;AACrC,QAAO,IAAI,kBAAkB,SAAS;AACvC,EAAC","names":[],"sources":["src/transport.ts"],"sourcesContent":["import { createTransport } from '@nmtjs/protocol/server'\nimport { type WsConnectionData, WsTransportServer } from './server.ts'\nimport type { WsTransportOptions } from './types.ts'\n\nexport const WsTransport = createTransport<\n WsConnectionData,\n WsTransportOptions\n>('WsTransport', (context, options) => {\n return new WsTransportServer(context, options)\n})\n"],"version":3}
package/dist/types.js ADDED
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ {"mappings":"","names":[],"sources":["src/types.ts"],"sourcesContent":["import type { AppOptions, WebSocket } from 'uWebSockets.js'\nimport type { Connection, ConnectionContext } from '@nmtjs/protocol/server'\nimport type { InteractivePromise } from '../../common/src/index.ts'\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"],"version":3}
package/dist/utils.js ADDED
@@ -0,0 +1,46 @@
1
+ import { createPromise } from "@nmtjs/common";
2
+ import { concat, ErrorCode, encodeNumber } from "@nmtjs/protocol/common";
3
+ import { ProtocolError } from "@nmtjs/protocol/server";
4
+ export const send = (ws, type, ...buffers) => {
5
+ const data = ws.getUserData();
6
+ try {
7
+ const buffer = concat(encodeNumber(type, "Uint8"), ...buffers);
8
+ const result = ws.send(buffer, true);
9
+ if (result === 0) {
10
+ data.backpressure = createPromise();
11
+ return false;
12
+ }
13
+ if (result === 2) {
14
+ return null;
15
+ }
16
+ return true;
17
+ } catch (error) {
18
+ return null;
19
+ }
20
+ };
21
+ export const toRecord = (input) => {
22
+ const obj = {};
23
+ input.forEach((value, key) => {
24
+ obj[key] = value;
25
+ });
26
+ return obj;
27
+ };
28
+ export const getRequestData = (req) => {
29
+ const url = req.getUrl();
30
+ const method = req.getMethod();
31
+ const headers = new Map();
32
+ req.forEach((key, value) => headers.set(key, value));
33
+ const query = new URLSearchParams(req.getQuery());
34
+ const origin = headers.has("origin") ? new URL(url, headers.get("origin")) : null;
35
+ return {
36
+ url,
37
+ origin,
38
+ method,
39
+ headers,
40
+ query
41
+ };
42
+ };
43
+ export const InternalError = (message = "Internal Server Error") => new ProtocolError(ErrorCode.InternalServerError, message);
44
+ export const NotFoundError = (message = "Not Found") => new ProtocolError(ErrorCode.NotFound, message);
45
+ export const ForbiddenError = (message = "Forbidden") => new ProtocolError(ErrorCode.Forbidden, message);
46
+ export const RequestTimeoutError = (message = "Request Timeout") => new ProtocolError(ErrorCode.RequestTimeout, message);
@@ -0,0 +1 @@
1
+ {"mappings":"AACA,SAAS,qBAAqB,eAAe;AAC7C,SAAS,QAAQ,WAAW,oBAAoB,wBAAwB;AACxE,SAAS,qBAAqB,wBAAwB;AAGtD,OAAO,MAAM,OAAO,CAClBA,IACAC,MACA,GAAG,YACgB;CACnB,MAAM,OAAO,GAAG,aAAa;AAC7B,KAAI;EACF,MAAM,SAAS,OAAO,aAAa,MAAM,QAAQ,EAAE,GAAG,QAAQ;EAC9D,MAAM,SAAS,GAAG,KAAK,QAAQ,KAAK;AACpC,MAAI,WAAW,GAAG;AAChB,QAAK,eAAe,eAAe;AACnC,UAAO;EACR;AACD,MAAI,WAAW,GAAG;AAChB,UAAO;EACR;AACD,SAAO;CACR,SAAQ,OAAO;AACd,SAAO;CACR;AACF;AAED,OAAO,MAAM,WAAW,CAACC,UAEnB;CACJ,MAAMC,MAA8B,CAAE;AACtC,OAAM,QAAQ,CAAC,OAAO,QAAQ;AAC5B,MAAI,OAAO;CACZ,EAAC;AACF,QAAO;AACR;AAUD,OAAO,MAAM,iBAAiB,CAACC,QAAkC;CAC/D,MAAM,MAAM,IAAI,QAAQ;CACxB,MAAM,SAAS,IAAI,WAAW;CAC9B,MAAM,UAAU,IAAI;AACpB,KAAI,QAAQ,CAAC,KAAK,UAAU,QAAQ,IAAI,KAAK,MAAM,CAAC;CACpD,MAAM,QAAQ,IAAI,gBAAgB,IAAI,UAAU;CAChD,MAAM,SAAS,QAAQ,IAAI,SAAS,GAChC,IAAI,IAAI,KAAK,QAAQ,IAAI,SAAS,IAClC;AAEJ,QAAO;EACL;EACA;EACA;EACA;EACA;CACD;AACF;AAED,OAAO,MAAM,gBAAgB,CAAC,UAAU,4BACtC,IAAI,cAAc,UAAU,qBAAqB;AAEnD,OAAO,MAAM,gBAAgB,CAAC,UAAU,gBACtC,IAAI,cAAc,UAAU,UAAU;AAExC,OAAO,MAAM,iBAAiB,CAAC,UAAU,gBACvC,IAAI,cAAc,UAAU,WAAW;AAEzC,OAAO,MAAM,sBAAsB,CAAC,UAAU,sBAC5C,IAAI,cAAc,UAAU,gBAAgB","names":["ws: WsTransportSocket","type: number","input: {\n forEach: (cb: (value, key) => void) => void\n}","obj: Record<string, string>","req: HttpRequest"],"sources":["src/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"],"version":3}
package/package.json CHANGED
@@ -3,37 +3,31 @@
3
3
  "type": "module",
4
4
  "exports": {
5
5
  ".": {
6
- "default": "./dist/index.js",
7
- "types": "./index.ts"
6
+ "types": "./src/index.ts",
7
+ "import": "./dist/index.js"
8
8
  }
9
9
  },
10
10
  "dependencies": {
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"
11
+ "uWebSockets.js": "github:uNetworking/uWebSockets.js#v20.51.0",
12
+ "@nmtjs/common": "0.7.0",
13
+ "@nmtjs/core": "0.7.0",
14
+ "@nmtjs/protocol": "0.7.0"
17
15
  },
18
16
  "devDependencies": {
19
- "@types/node": "^18.0.0",
20
- "@nmtjs/core": "^0.6.4",
21
- "@nmtjs/protocol": "^0.6.4",
22
- "@nmtjs/common": "^0.6.4"
17
+ "@types/node": "^18.19.86"
23
18
  },
24
19
  "engines": {
25
20
  "node": ">=18.9.0"
26
21
  },
27
22
  "files": [
28
- "index.ts",
29
- "lib",
23
+ "src",
30
24
  "dist",
31
25
  "LICENSE.md",
32
26
  "README.md"
33
27
  ],
34
- "version": "0.2.2",
28
+ "version": "0.7.0",
35
29
  "scripts": {
36
- "build": "neemata-build ./index.ts './lib/**/*.ts'",
30
+ "build": "neemata-build --root ./src './**/*.ts'",
37
31
  "type-check": "tsc --noEmit"
38
32
  }
39
33
  }
package/src/index.ts ADDED
@@ -0,0 +1,5 @@
1
+ export * from './injectables.ts'
2
+ export * from './server.ts'
3
+ export * from './transport.ts'
4
+ export * from './types.ts'
5
+ export * from './utils.ts'
@@ -5,7 +5,6 @@ import {
5
5
  SSLApp,
6
6
  type TemplatedApp,
7
7
  } from 'uWebSockets.js'
8
- import assert from 'node:assert'
9
8
  import { randomUUID } from 'node:crypto'
10
9
  import { createPromise } from '@nmtjs/common'
11
10
  import {
@@ -161,8 +160,7 @@ export class WsTransportServer implements Transport<WsConnectionData> {
161
160
  buffer: ArrayBuffer,
162
161
  ) {
163
162
  const ws = this.clients.get(connection.id)
164
- assert(ws, 'Websocket not found')
165
- send(ws, messageType, buffer)
163
+ if (ws) send(ws, messageType, buffer)
166
164
  }
167
165
 
168
166
  async start() {
@@ -1,6 +1,6 @@
1
1
  import type { AppOptions, WebSocket } from 'uWebSockets.js'
2
- import type { InteractivePromise } from '@nmtjs/common'
3
2
  import type { Connection, ConnectionContext } from '@nmtjs/protocol/server'
3
+ import type { InteractivePromise } from '../../common/src/index.ts'
4
4
 
5
5
  export type WsUserData = {
6
6
  id: Connection['id']
@@ -1,5 +0,0 @@
1
- import { ProtocolInjectables } from '@nmtjs/protocol/server';
2
- const connectionData = ProtocolInjectables.connectionData;
3
- export const WsTransportInjectables = {
4
- connectionData
5
- };
@@ -1 +0,0 @@
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,174 +0,0 @@
1
- import { App, SSLApp } from 'uWebSockets.js';
2
- import assert from 'node:assert';
3
- import { randomUUID } from 'node:crypto';
4
- import { createPromise } from '@nmtjs/common';
5
- import { ClientMessageType, decodeNumber } from '@nmtjs/protocol/common';
6
- import { ProtocolInjectables } from '@nmtjs/protocol/server';
7
- import { WsTransportInjectables } from "./injectables.js";
8
- import { getRequestData, send } from "./utils.js";
9
- export class WsTransportServer {
10
- context;
11
- options;
12
- server;
13
- clients;
14
- constructor(context, options){
15
- this.context = context;
16
- this.options = options;
17
- this.clients = new Map();
18
- this.server = this.options.tls ? SSLApp(options.tls) : App();
19
- this.server.options('/*', (res, req)=>{
20
- this.applyCors(res, req);
21
- res.writeStatus('200 OK');
22
- res.endWithoutBody();
23
- }).get('/healthy', (res, req)=>{
24
- this.applyCors(res, req);
25
- res.writeHeader('Content-Type', 'text/plain');
26
- res.end('OK');
27
- }).ws('/api', {
28
- sendPingsAutomatically: true,
29
- maxPayloadLength: this.options.maxPayloadLength,
30
- upgrade: (res, req, context)=>{
31
- const requestData = getRequestData(req);
32
- const contentType = requestData.headers.get('content-type') || requestData.query.get('content-type');
33
- const acceptType = requestData.headers.get('accept') || requestData.query.get('accept');
34
- const data = {
35
- id: randomUUID(),
36
- request: {
37
- query: requestData.query,
38
- headers: requestData.headers,
39
- proxiedRemoteAddress: Buffer.from(res.getProxiedRemoteAddressAsText()).toString(),
40
- remoteAddress: Buffer.from(res.getRemoteAddressAsText()).toString(),
41
- contentType,
42
- acceptType
43
- },
44
- opening: createPromise(),
45
- backpressure: null,
46
- context: {}
47
- };
48
- res.upgrade(data, req.getHeader('sec-websocket-key'), req.getHeader('sec-websocket-protocol'), req.getHeader('sec-websocket-extensions'), context);
49
- },
50
- open: async (ws)=>{
51
- const { id, context, request, opening } = ws.getUserData();
52
- this.clients.set(id, ws);
53
- this.logger.debug('Connection %s opened', id);
54
- try {
55
- const { context: _context, connection } = await this.context.protocol.connections.add(this, {
56
- id,
57
- data: {}
58
- }, {
59
- acceptType: request.acceptType,
60
- contentType: request.contentType
61
- });
62
- Object.assign(context, _context);
63
- context.container.provide(ProtocolInjectables.connection, connection);
64
- context.container.provide(WsTransportInjectables.connectionData, request);
65
- opening.resolve();
66
- } catch (error) {
67
- opening.reject(error);
68
- }
69
- },
70
- message: async (ws, buffer)=>{
71
- const { opening } = ws.getUserData();
72
- const messageType = decodeNumber(buffer, 'Uint8');
73
- if (messageType in this === false) {
74
- ws.end(1011, 'Unknown message type');
75
- } else {
76
- try {
77
- await opening.promise;
78
- await this[messageType](ws, buffer.slice(Uint8Array.BYTES_PER_ELEMENT));
79
- } catch (error) {
80
- this.logError(error, 'Error while processing message');
81
- }
82
- }
83
- },
84
- drain: (ws)=>{
85
- const data = ws.getUserData();
86
- data.backpressure?.resolve();
87
- data.backpressure = null;
88
- },
89
- close: async (ws, code, message)=>{
90
- const { id } = ws.getUserData();
91
- this.logger.debug('Connection %s closed with code %s: %s', id, code, Buffer.from(message).toString());
92
- this.clients.delete(id);
93
- await this.protocol.connections.remove(id);
94
- }
95
- });
96
- }
97
- send(connection, messageType, buffer) {
98
- const ws = this.clients.get(connection.id);
99
- assert(ws, 'Websocket not found');
100
- send(ws, messageType, buffer);
101
- }
102
- async start() {
103
- return new Promise((resolve, reject)=>{
104
- const hostname = this.options.hostname ?? '127.0.0.1';
105
- this.server.listen(hostname, this.options.port, (socket)=>{
106
- if (socket) {
107
- this.logger.info('Server started on %s:%s', hostname, this.options.port);
108
- resolve();
109
- } else {
110
- reject(new Error('Failed to start server'));
111
- }
112
- });
113
- });
114
- }
115
- async stop() {
116
- this.server.close();
117
- }
118
- get protocol() {
119
- return this.context.protocol;
120
- }
121
- get logger() {
122
- return this.context.logger;
123
- }
124
- async logError(cause, message = 'Unknown error while processing request') {
125
- this.logger.error(new Error(message, {
126
- cause
127
- }));
128
- }
129
- applyCors(res, req) {
130
- const origin = req.getHeader('origin');
131
- if (!origin) return;
132
- res.writeHeader('Access-Control-Allow-Origin', origin);
133
- res.writeHeader('Access-Control-Allow-Headers', 'Content-Type');
134
- res.writeHeader('Access-Control-Allow-Methods', 'GET, POST');
135
- res.writeHeader('Access-Control-Allow-Credentials', 'true');
136
- }
137
- [ClientMessageType.Rpc](ws, buffer) {
138
- const { id } = ws.getUserData();
139
- this.protocol.rpcRaw(id, buffer);
140
- }
141
- [ClientMessageType.RpcAbort](ws, buffer) {
142
- const { id } = ws.getUserData();
143
- this.protocol.rpcAbortRaw(id, buffer);
144
- }
145
- [ClientMessageType.RpcStreamAbort](ws, buffer) {
146
- const { id } = ws.getUserData();
147
- this.protocol.rpcStreamAbortRaw(id, buffer);
148
- }
149
- [ClientMessageType.ClientStreamPush](ws, buffer) {
150
- const { id } = ws.getUserData();
151
- const streamId = decodeNumber(buffer, 'Uint32');
152
- this.protocol.clientStreams.push(id, streamId, buffer.slice(Uint32Array.BYTES_PER_ELEMENT));
153
- }
154
- [ClientMessageType.ClientStreamEnd](ws, buffer) {
155
- const { id } = ws.getUserData();
156
- const streamId = decodeNumber(buffer, 'Uint32');
157
- this.protocol.clientStreams.end(id, streamId);
158
- }
159
- [ClientMessageType.ClientStreamAbort](ws, buffer) {
160
- const { id } = ws.getUserData();
161
- const streamId = decodeNumber(buffer, 'Uint32');
162
- this.protocol.clientStreams.abort(id, streamId);
163
- }
164
- [ClientMessageType.ServerStreamPull](ws, buffer) {
165
- const { id } = ws.getUserData();
166
- const streamId = decodeNumber(buffer, 'Uint32');
167
- this.protocol.serverStreams.pull(id, streamId);
168
- }
169
- [ClientMessageType.ServerStreamAbort](ws, buffer) {
170
- const { id } = ws.getUserData();
171
- const streamId = decodeNumber(buffer, 'Uint32');
172
- this.protocol.serverStreams.abort(id, streamId);
173
- }
174
- }
@@ -1 +0,0 @@
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,5 +0,0 @@
1
- import { createTransport } from '@nmtjs/protocol/server';
2
- import { WsTransportServer } from "./server.js";
3
- export const WsTransport = createTransport('WsTransport', (context, options)=>{
4
- return new WsTransportServer(context, options);
5
- });
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../../lib/transport.ts"],"sourcesContent":["import { createTransport } from '@nmtjs/protocol/server'\nimport { type WsConnectionData, WsTransportServer } from './server.ts'\nimport type { WsTransportOptions } from './types.ts'\n\nexport const WsTransport = createTransport<\n WsConnectionData,\n WsTransportOptions\n>('WsTransport', (context, options) => {\n return new WsTransportServer(context, options)\n})\n"],"names":["createTransport","WsTransportServer","WsTransport","context","options"],"mappings":"AAAA,SAASA,eAAe,QAAQ,yBAAwB;AACxD,SAAgCC,iBAAiB,QAAQ,cAAa;AAGtE,OAAO,MAAMC,cAAcF,gBAGzB,eAAe,CAACG,SAASC;IACzB,OAAO,IAAIH,kBAAkBE,SAASC;AACxC,GAAE"}
package/dist/lib/types.js DELETED
@@ -1 +0,0 @@
1
- export { };
@@ -1 +0,0 @@
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 DELETED
@@ -1,46 +0,0 @@
1
- import { createPromise } from '@nmtjs/common';
2
- import { concat, ErrorCode, encodeNumber } from '@nmtjs/protocol/common';
3
- import { ProtocolError } from '@nmtjs/protocol/server';
4
- export const send = (ws, type, ...buffers)=>{
5
- const data = ws.getUserData();
6
- try {
7
- const buffer = concat(encodeNumber(type, 'Uint8'), ...buffers);
8
- const result = ws.send(buffer, true);
9
- if (result === 0) {
10
- data.backpressure = createPromise();
11
- return false;
12
- }
13
- if (result === 2) {
14
- return null;
15
- }
16
- return true;
17
- } catch (error) {
18
- return null;
19
- }
20
- };
21
- export const toRecord = (input)=>{
22
- const obj = {};
23
- input.forEach((value, key)=>{
24
- obj[key] = value;
25
- });
26
- return obj;
27
- };
28
- export const getRequestData = (req)=>{
29
- const url = req.getUrl();
30
- const method = req.getMethod();
31
- const headers = new Map();
32
- req.forEach((key, value)=>headers.set(key, value));
33
- const query = new URLSearchParams(req.getQuery());
34
- const origin = headers.has('origin') ? new URL(url, headers.get('origin')) : null;
35
- return {
36
- url,
37
- origin,
38
- method,
39
- headers,
40
- query
41
- };
42
- };
43
- export const InternalError = (message = 'Internal Server Error')=>new ProtocolError(ErrorCode.InternalServerError, message);
44
- export const NotFoundError = (message = 'Not Found')=>new ProtocolError(ErrorCode.NotFound, message);
45
- export const ForbiddenError = (message = 'Forbidden')=>new ProtocolError(ErrorCode.Forbidden, message);
46
- export const RequestTimeoutError = (message = 'Request Timeout')=>new ProtocolError(ErrorCode.RequestTimeout, message);
@@ -1 +0,0 @@
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 DELETED
@@ -1,5 +0,0 @@
1
- export * from './lib/injectables.ts'
2
- export * from './lib/server.ts'
3
- export * from './lib/transport.ts'
4
- export * from './lib/types.ts'
5
- export * from './lib/utils.ts'
File without changes
File without changes
File without changes