@nmtjs/ws-transport 0.8.0 → 0.9.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/dist/http.js ADDED
@@ -0,0 +1,148 @@
1
+ import { createMetadataKey } from "@nmtjs/core";
2
+ import { ErrorCode } from "@nmtjs/protocol/common";
3
+ export let HttpCode = /* @__PURE__ */ function(HttpCode) {
4
+ HttpCode[HttpCode["Continue"] = 100] = "Continue";
5
+ HttpCode[HttpCode["SwitchingProtocols"] = 101] = "SwitchingProtocols";
6
+ HttpCode[HttpCode["Processing"] = 102] = "Processing";
7
+ HttpCode[HttpCode["EarlyHints"] = 103] = "EarlyHints";
8
+ HttpCode[HttpCode["OK"] = 200] = "OK";
9
+ HttpCode[HttpCode["Created"] = 201] = "Created";
10
+ HttpCode[HttpCode["Accepted"] = 202] = "Accepted";
11
+ HttpCode[HttpCode["NonAuthoritativeInformation"] = 203] = "NonAuthoritativeInformation";
12
+ HttpCode[HttpCode["NoContent"] = 204] = "NoContent";
13
+ HttpCode[HttpCode["ResetContent"] = 205] = "ResetContent";
14
+ HttpCode[HttpCode["PartialContent"] = 206] = "PartialContent";
15
+ HttpCode[HttpCode["MultiStatus"] = 207] = "MultiStatus";
16
+ HttpCode[HttpCode["AlreadyReported"] = 208] = "AlreadyReported";
17
+ HttpCode[HttpCode["IMUsed"] = 226] = "IMUsed";
18
+ HttpCode[HttpCode["MultipleChoices"] = 300] = "MultipleChoices";
19
+ HttpCode[HttpCode["MovedPermanently"] = 301] = "MovedPermanently";
20
+ HttpCode[HttpCode["Found"] = 302] = "Found";
21
+ HttpCode[HttpCode["SeeOther"] = 303] = "SeeOther";
22
+ HttpCode[HttpCode["NotModified"] = 304] = "NotModified";
23
+ HttpCode[HttpCode["UseProxy"] = 305] = "UseProxy";
24
+ HttpCode[HttpCode["TemporaryRedirect"] = 307] = "TemporaryRedirect";
25
+ HttpCode[HttpCode["PermanentRedirect"] = 308] = "PermanentRedirect";
26
+ HttpCode[HttpCode["BadRequest"] = 400] = "BadRequest";
27
+ HttpCode[HttpCode["Unauthorized"] = 401] = "Unauthorized";
28
+ HttpCode[HttpCode["PaymentRequired"] = 402] = "PaymentRequired";
29
+ HttpCode[HttpCode["Forbidden"] = 403] = "Forbidden";
30
+ HttpCode[HttpCode["NotFound"] = 404] = "NotFound";
31
+ HttpCode[HttpCode["MethodNotAllowed"] = 405] = "MethodNotAllowed";
32
+ HttpCode[HttpCode["NotAcceptable"] = 406] = "NotAcceptable";
33
+ HttpCode[HttpCode["ProxyAuthenticationRequired"] = 407] = "ProxyAuthenticationRequired";
34
+ HttpCode[HttpCode["RequestTimeout"] = 408] = "RequestTimeout";
35
+ HttpCode[HttpCode["Conflict"] = 409] = "Conflict";
36
+ HttpCode[HttpCode["Gone"] = 410] = "Gone";
37
+ HttpCode[HttpCode["LengthRequired"] = 411] = "LengthRequired";
38
+ HttpCode[HttpCode["PreconditionFailed"] = 412] = "PreconditionFailed";
39
+ HttpCode[HttpCode["PayloadTooLarge"] = 413] = "PayloadTooLarge";
40
+ HttpCode[HttpCode["URITooLong"] = 414] = "URITooLong";
41
+ HttpCode[HttpCode["UnsupportedMediaType"] = 415] = "UnsupportedMediaType";
42
+ HttpCode[HttpCode["RangeNotSatisfiable"] = 416] = "RangeNotSatisfiable";
43
+ HttpCode[HttpCode["ExpectationFailed"] = 417] = "ExpectationFailed";
44
+ HttpCode[HttpCode["ImATeapot"] = 418] = "ImATeapot";
45
+ HttpCode[HttpCode["MisdirectedRequest"] = 421] = "MisdirectedRequest";
46
+ HttpCode[HttpCode["UnprocessableEntity"] = 422] = "UnprocessableEntity";
47
+ HttpCode[HttpCode["Locked"] = 423] = "Locked";
48
+ HttpCode[HttpCode["FailedDependency"] = 424] = "FailedDependency";
49
+ HttpCode[HttpCode["TooEarly"] = 425] = "TooEarly";
50
+ HttpCode[HttpCode["UpgradeRequired"] = 426] = "UpgradeRequired";
51
+ HttpCode[HttpCode["PreconditionRequired"] = 428] = "PreconditionRequired";
52
+ HttpCode[HttpCode["TooManyRequests"] = 429] = "TooManyRequests";
53
+ HttpCode[HttpCode["RequestHeaderFieldsTooLarge"] = 431] = "RequestHeaderFieldsTooLarge";
54
+ HttpCode[HttpCode["UnavailableForLegalReasons"] = 451] = "UnavailableForLegalReasons";
55
+ HttpCode[HttpCode["InternalServerError"] = 500] = "InternalServerError";
56
+ HttpCode[HttpCode["NotImplemented"] = 501] = "NotImplemented";
57
+ HttpCode[HttpCode["BadGateway"] = 502] = "BadGateway";
58
+ HttpCode[HttpCode["ServiceUnavailable"] = 503] = "ServiceUnavailable";
59
+ HttpCode[HttpCode["GatewayTimeout"] = 504] = "GatewayTimeout";
60
+ HttpCode[HttpCode["HTTPVersionNotSupported"] = 505] = "HTTPVersionNotSupported";
61
+ HttpCode[HttpCode["VariantAlsoNegotiates"] = 506] = "VariantAlsoNegotiates";
62
+ HttpCode[HttpCode["InsufficientStorage"] = 507] = "InsufficientStorage";
63
+ HttpCode[HttpCode["LoopDetected"] = 508] = "LoopDetected";
64
+ HttpCode[HttpCode["NotExtended"] = 510] = "NotExtended";
65
+ HttpCode[HttpCode["NetworkAuthenticationRequired"] = 511] = "NetworkAuthenticationRequired";
66
+ return HttpCode;
67
+ }({});
68
+ export const HttpStatusText = {
69
+ [HttpCode.Continue]: "Continue",
70
+ [HttpCode.SwitchingProtocols]: "Switching Protocols",
71
+ [HttpCode.Processing]: "Processing",
72
+ [HttpCode.EarlyHints]: "Early Hints",
73
+ [HttpCode.OK]: "OK",
74
+ [HttpCode.Created]: "Created",
75
+ [HttpCode.Accepted]: "Accepted",
76
+ [HttpCode.NonAuthoritativeInformation]: "Non-Authoritative Information",
77
+ [HttpCode.NoContent]: "No Content",
78
+ [HttpCode.ResetContent]: "Reset Content",
79
+ [HttpCode.PartialContent]: "Partial Content",
80
+ [HttpCode.MultiStatus]: "Multi-Status",
81
+ [HttpCode.AlreadyReported]: "Already Reported",
82
+ [HttpCode.IMUsed]: "IM Used",
83
+ [HttpCode.MultipleChoices]: "Multiple Choices",
84
+ [HttpCode.MovedPermanently]: "Moved Permanently",
85
+ [HttpCode.Found]: "Found",
86
+ [HttpCode.SeeOther]: "See Other",
87
+ [HttpCode.NotModified]: "Not Modified",
88
+ [HttpCode.UseProxy]: "Use Proxy",
89
+ [HttpCode.TemporaryRedirect]: "Temporary Redirect",
90
+ [HttpCode.PermanentRedirect]: "Permanent Redirect",
91
+ [HttpCode.BadRequest]: "Bad Request",
92
+ [HttpCode.Unauthorized]: "Unauthorized",
93
+ [HttpCode.PaymentRequired]: "Payment Required",
94
+ [HttpCode.Forbidden]: "Forbidden",
95
+ [HttpCode.NotFound]: "Not Found",
96
+ [HttpCode.MethodNotAllowed]: "Method Not Allowed",
97
+ [HttpCode.NotAcceptable]: "Not Acceptable",
98
+ [HttpCode.ProxyAuthenticationRequired]: "Proxy Authentication Required",
99
+ [HttpCode.RequestTimeout]: "Request Timeout",
100
+ [HttpCode.Conflict]: "Conflict",
101
+ [HttpCode.Gone]: "Gone",
102
+ [HttpCode.LengthRequired]: "Length Required",
103
+ [HttpCode.PreconditionFailed]: "Precondition Failed",
104
+ [HttpCode.PayloadTooLarge]: "Payload Too Large",
105
+ [HttpCode.URITooLong]: "URI Too Long",
106
+ [HttpCode.UnsupportedMediaType]: "Unsupported Media Type",
107
+ [HttpCode.RangeNotSatisfiable]: "Range Not Satisfiable",
108
+ [HttpCode.ExpectationFailed]: "Expectation Failed",
109
+ [HttpCode.ImATeapot]: "I'm a Teapot",
110
+ [HttpCode.MisdirectedRequest]: "Misdirected Request",
111
+ [HttpCode.UnprocessableEntity]: "Unprocessable Entity",
112
+ [HttpCode.Locked]: "Locked",
113
+ [HttpCode.FailedDependency]: "Failed Dependency",
114
+ [HttpCode.TooEarly]: "Too Early",
115
+ [HttpCode.UpgradeRequired]: "Upgrade Required",
116
+ [HttpCode.PreconditionRequired]: "Precondition Required",
117
+ [HttpCode.TooManyRequests]: "Too Many Requests",
118
+ [HttpCode.RequestHeaderFieldsTooLarge]: "Request Header Fields Too Large",
119
+ [HttpCode.UnavailableForLegalReasons]: "Unavailable For Legal Reasons",
120
+ [HttpCode.InternalServerError]: "Internal Server Error",
121
+ [HttpCode.NotImplemented]: "Not Implemented",
122
+ [HttpCode.BadGateway]: "Bad Gateway",
123
+ [HttpCode.ServiceUnavailable]: "Service Unavailable",
124
+ [HttpCode.GatewayTimeout]: "Gateway Timeout",
125
+ [HttpCode.HTTPVersionNotSupported]: "HTTP Version Not Supported",
126
+ [HttpCode.VariantAlsoNegotiates]: "Variant Also Negotiates",
127
+ [HttpCode.InsufficientStorage]: "Insufficient Storage",
128
+ [HttpCode.LoopDetected]: "Loop Detected",
129
+ [HttpCode.NotExtended]: "Not Extended",
130
+ [HttpCode.NetworkAuthenticationRequired]: "Network Authentication Required"
131
+ };
132
+ export const HttpCodeMap = {
133
+ [ErrorCode.ValidationError]: HttpCode.BadRequest,
134
+ [ErrorCode.BadRequest]: HttpCode.BadRequest,
135
+ [ErrorCode.NotFound]: HttpCode.NotFound,
136
+ [ErrorCode.Forbidden]: HttpCode.Forbidden,
137
+ [ErrorCode.Unauthorized]: HttpCode.Unauthorized,
138
+ [ErrorCode.InternalServerError]: HttpCode.InternalServerError,
139
+ [ErrorCode.NotAcceptable]: HttpCode.NotAcceptable,
140
+ [ErrorCode.RequestTimeout]: HttpCode.RequestTimeout,
141
+ [ErrorCode.GatewayTimeout]: HttpCode.GatewayTimeout,
142
+ [ErrorCode.ServiceUnavailable]: HttpCode.ServiceUnavailable,
143
+ [ErrorCode.ClientRequestError]: HttpCode.BadRequest,
144
+ [ErrorCode.ConnectionError]: HttpCode.NotAcceptable
145
+ };
146
+ export const AllowedHttpMethod = createMetadataKey("http:method");
147
+
148
+ //# sourceMappingURL=http.js.map
@@ -0,0 +1 @@
1
+ {"mappings":"AAAA,SAAS,yBAAyB,aAAa;AAC/C,SAAS,iBAAiB,wBAAwB;AAElD,OAAO,IAAK,8CAAL;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AACD;AAED,OAAO,MAAMA,iBAA2C;EACrD,SAAS,WAAW;EACpB,SAAS,qBAAqB;EAC9B,SAAS,aAAa;EACtB,SAAS,aAAa;EACtB,SAAS,KAAK;EACd,SAAS,UAAU;EACnB,SAAS,WAAW;EACpB,SAAS,8BAA8B;EACvC,SAAS,YAAY;EACrB,SAAS,eAAe;EACxB,SAAS,iBAAiB;EAC1B,SAAS,cAAc;EACvB,SAAS,kBAAkB;EAC3B,SAAS,SAAS;EAClB,SAAS,kBAAkB;EAC3B,SAAS,mBAAmB;EAC5B,SAAS,QAAQ;EACjB,SAAS,WAAW;EACpB,SAAS,cAAc;EACvB,SAAS,WAAW;EACpB,SAAS,oBAAoB;EAC7B,SAAS,oBAAoB;EAC7B,SAAS,aAAa;EACtB,SAAS,eAAe;EACxB,SAAS,kBAAkB;EAC3B,SAAS,YAAY;EACrB,SAAS,WAAW;EACpB,SAAS,mBAAmB;EAC5B,SAAS,gBAAgB;EACzB,SAAS,8BAA8B;EACvC,SAAS,iBAAiB;EAC1B,SAAS,WAAW;EACpB,SAAS,OAAO;EAChB,SAAS,iBAAiB;EAC1B,SAAS,qBAAqB;EAC9B,SAAS,kBAAkB;EAC3B,SAAS,aAAa;EACtB,SAAS,uBAAuB;EAChC,SAAS,sBAAsB;EAC/B,SAAS,oBAAoB;EAC7B,SAAS,YAAY;EACrB,SAAS,qBAAqB;EAC9B,SAAS,sBAAsB;EAC/B,SAAS,SAAS;EAClB,SAAS,mBAAmB;EAC5B,SAAS,WAAW;EACpB,SAAS,kBAAkB;EAC3B,SAAS,uBAAuB;EAChC,SAAS,kBAAkB;EAC3B,SAAS,8BAA8B;EACvC,SAAS,6BAA6B;EACtC,SAAS,sBAAsB;EAC/B,SAAS,iBAAiB;EAC1B,SAAS,aAAa;EACtB,SAAS,qBAAqB;EAC9B,SAAS,iBAAiB;EAC1B,SAAS,0BAA0B;EACnC,SAAS,wBAAwB;EACjC,SAAS,sBAAsB;EAC/B,SAAS,eAAe;EACxB,SAAS,cAAc;EACvB,SAAS,gCAAgC;AAC3C;AAED,OAAO,MAAM,cAAc;EACxB,UAAU,kBAAkB,SAAS;EACrC,UAAU,aAAa,SAAS;EAChC,UAAU,WAAW,SAAS;EAC9B,UAAU,YAAY,SAAS;EAC/B,UAAU,eAAe,SAAS;EAClC,UAAU,sBAAsB,SAAS;EACzC,UAAU,gBAAgB,SAAS;EACnC,UAAU,iBAAiB,SAAS;EACpC,UAAU,iBAAiB,SAAS;EACpC,UAAU,qBAAqB,SAAS;EACxC,UAAU,qBAAqB,SAAS;EACxC,UAAU,kBAAkB,SAAS;AACvC;AAED,OAAO,MAAM,oBACX,kBAAyC,cAAc","names":["HttpStatusText: Record<HttpCode, string>"],"sources":["../src/http.ts"],"sourcesContent":["import { createMetadataKey } from '@nmtjs/core'\nimport { ErrorCode } from '@nmtjs/protocol/common'\n\nexport enum HttpCode {\n Continue = 100,\n SwitchingProtocols = 101,\n Processing = 102,\n EarlyHints = 103,\n OK = 200,\n Created = 201,\n Accepted = 202,\n NonAuthoritativeInformation = 203,\n NoContent = 204,\n ResetContent = 205,\n PartialContent = 206,\n MultiStatus = 207,\n AlreadyReported = 208,\n IMUsed = 226,\n MultipleChoices = 300,\n MovedPermanently = 301,\n Found = 302,\n SeeOther = 303,\n NotModified = 304,\n UseProxy = 305,\n TemporaryRedirect = 307,\n PermanentRedirect = 308,\n BadRequest = 400,\n Unauthorized = 401,\n PaymentRequired = 402,\n Forbidden = 403,\n NotFound = 404,\n MethodNotAllowed = 405,\n NotAcceptable = 406,\n ProxyAuthenticationRequired = 407,\n RequestTimeout = 408,\n Conflict = 409,\n Gone = 410,\n LengthRequired = 411,\n PreconditionFailed = 412,\n PayloadTooLarge = 413,\n URITooLong = 414,\n UnsupportedMediaType = 415,\n RangeNotSatisfiable = 416,\n ExpectationFailed = 417,\n ImATeapot = 418,\n MisdirectedRequest = 421,\n UnprocessableEntity = 422,\n Locked = 423,\n FailedDependency = 424,\n TooEarly = 425,\n UpgradeRequired = 426,\n PreconditionRequired = 428,\n TooManyRequests = 429,\n RequestHeaderFieldsTooLarge = 431,\n UnavailableForLegalReasons = 451,\n InternalServerError = 500,\n NotImplemented = 501,\n BadGateway = 502,\n ServiceUnavailable = 503,\n GatewayTimeout = 504,\n HTTPVersionNotSupported = 505,\n VariantAlsoNegotiates = 506,\n InsufficientStorage = 507,\n LoopDetected = 508,\n NotExtended = 510,\n NetworkAuthenticationRequired = 511,\n}\n\nexport const HttpStatusText: Record<HttpCode, string> = {\n [HttpCode.Continue]: 'Continue',\n [HttpCode.SwitchingProtocols]: 'Switching Protocols',\n [HttpCode.Processing]: 'Processing',\n [HttpCode.EarlyHints]: 'Early Hints',\n [HttpCode.OK]: 'OK',\n [HttpCode.Created]: 'Created',\n [HttpCode.Accepted]: 'Accepted',\n [HttpCode.NonAuthoritativeInformation]: 'Non-Authoritative Information',\n [HttpCode.NoContent]: 'No Content',\n [HttpCode.ResetContent]: 'Reset Content',\n [HttpCode.PartialContent]: 'Partial Content',\n [HttpCode.MultiStatus]: 'Multi-Status',\n [HttpCode.AlreadyReported]: 'Already Reported',\n [HttpCode.IMUsed]: 'IM Used',\n [HttpCode.MultipleChoices]: 'Multiple Choices',\n [HttpCode.MovedPermanently]: 'Moved Permanently',\n [HttpCode.Found]: 'Found',\n [HttpCode.SeeOther]: 'See Other',\n [HttpCode.NotModified]: 'Not Modified',\n [HttpCode.UseProxy]: 'Use Proxy',\n [HttpCode.TemporaryRedirect]: 'Temporary Redirect',\n [HttpCode.PermanentRedirect]: 'Permanent Redirect',\n [HttpCode.BadRequest]: 'Bad Request',\n [HttpCode.Unauthorized]: 'Unauthorized',\n [HttpCode.PaymentRequired]: 'Payment Required',\n [HttpCode.Forbidden]: 'Forbidden',\n [HttpCode.NotFound]: 'Not Found',\n [HttpCode.MethodNotAllowed]: 'Method Not Allowed',\n [HttpCode.NotAcceptable]: 'Not Acceptable',\n [HttpCode.ProxyAuthenticationRequired]: 'Proxy Authentication Required',\n [HttpCode.RequestTimeout]: 'Request Timeout',\n [HttpCode.Conflict]: 'Conflict',\n [HttpCode.Gone]: 'Gone',\n [HttpCode.LengthRequired]: 'Length Required',\n [HttpCode.PreconditionFailed]: 'Precondition Failed',\n [HttpCode.PayloadTooLarge]: 'Payload Too Large',\n [HttpCode.URITooLong]: 'URI Too Long',\n [HttpCode.UnsupportedMediaType]: 'Unsupported Media Type',\n [HttpCode.RangeNotSatisfiable]: 'Range Not Satisfiable',\n [HttpCode.ExpectationFailed]: 'Expectation Failed',\n [HttpCode.ImATeapot]: \"I'm a Teapot\",\n [HttpCode.MisdirectedRequest]: 'Misdirected Request',\n [HttpCode.UnprocessableEntity]: 'Unprocessable Entity',\n [HttpCode.Locked]: 'Locked',\n [HttpCode.FailedDependency]: 'Failed Dependency',\n [HttpCode.TooEarly]: 'Too Early',\n [HttpCode.UpgradeRequired]: 'Upgrade Required',\n [HttpCode.PreconditionRequired]: 'Precondition Required',\n [HttpCode.TooManyRequests]: 'Too Many Requests',\n [HttpCode.RequestHeaderFieldsTooLarge]: 'Request Header Fields Too Large',\n [HttpCode.UnavailableForLegalReasons]: 'Unavailable For Legal Reasons',\n [HttpCode.InternalServerError]: 'Internal Server Error',\n [HttpCode.NotImplemented]: 'Not Implemented',\n [HttpCode.BadGateway]: 'Bad Gateway',\n [HttpCode.ServiceUnavailable]: 'Service Unavailable',\n [HttpCode.GatewayTimeout]: 'Gateway Timeout',\n [HttpCode.HTTPVersionNotSupported]: 'HTTP Version Not Supported',\n [HttpCode.VariantAlsoNegotiates]: 'Variant Also Negotiates',\n [HttpCode.InsufficientStorage]: 'Insufficient Storage',\n [HttpCode.LoopDetected]: 'Loop Detected',\n [HttpCode.NotExtended]: 'Not Extended',\n [HttpCode.NetworkAuthenticationRequired]: 'Network Authentication Required',\n}\n\nexport const HttpCodeMap = {\n [ErrorCode.ValidationError]: HttpCode.BadRequest,\n [ErrorCode.BadRequest]: HttpCode.BadRequest,\n [ErrorCode.NotFound]: HttpCode.NotFound,\n [ErrorCode.Forbidden]: HttpCode.Forbidden,\n [ErrorCode.Unauthorized]: HttpCode.Unauthorized,\n [ErrorCode.InternalServerError]: HttpCode.InternalServerError,\n [ErrorCode.NotAcceptable]: HttpCode.NotAcceptable,\n [ErrorCode.RequestTimeout]: HttpCode.RequestTimeout,\n [ErrorCode.GatewayTimeout]: HttpCode.GatewayTimeout,\n [ErrorCode.ServiceUnavailable]: HttpCode.ServiceUnavailable,\n [ErrorCode.ClientRequestError]: HttpCode.BadRequest,\n [ErrorCode.ConnectionError]: HttpCode.NotAcceptable,\n}\n\nexport const AllowedHttpMethod =\n createMetadataKey<Array<'get' | 'post'>>('http:method')\n"],"version":3,"file":"http.js"}
package/dist/index.js CHANGED
@@ -3,3 +3,5 @@ export * from "./server.js";
3
3
  export * from "./transport.js";
4
4
  export * from "./types.js";
5
5
  export * from "./utils.js";
6
+
7
+ //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
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}
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,"file":"index.js"}
@@ -1,3 +1,10 @@
1
+ import { createLazyInjectable, Scope } from "@nmtjs/core";
1
2
  import { ProtocolInjectables } from "@nmtjs/protocol/server";
2
3
  const connectionData = ProtocolInjectables.connectionData;
3
- export const WsTransportInjectables = { connectionData };
4
+ const httpResponseHeaders = createLazyInjectable(Scope.Call);
5
+ export const WsTransportInjectables = {
6
+ connectionData,
7
+ httpResponseHeaders
8
+ };
9
+
10
+ //# sourceMappingURL=injectables.js.map
@@ -1 +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}
1
+ {"mappings":"AAAA,SAAS,sBAA2C,aAAa,aAAa;AAC9E,SAAS,2BAA2B,wBAAwB;AAG5D,MAAM,iBAAiB,oBAAoB;AAK3C,MAAM,sBAAsB,qBAC1B,MAAM,KACP;AAED,OAAO,MAAM,yBAAyB;CACpC;CACA;AACD","names":[],"sources":["../src/injectables.ts"],"sourcesContent":["import { createLazyInjectable, 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\nconst httpResponseHeaders = createLazyInjectable<Headers, Scope.Call>(\n Scope.Call,\n)\n\nexport const WsTransportInjectables = {\n connectionData,\n httpResponseHeaders,\n} as const\n"],"version":3,"file":"injectables.js"}
package/dist/server.js CHANGED
@@ -1,10 +1,14 @@
1
1
  import { App, SSLApp, us_socket_local_port } from "uWebSockets.js";
2
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";
3
+ import { once } from "node:events";
4
+ import { Duplex, Readable } from "node:stream";
5
+ import { Scope } from "@nmtjs/core";
6
+ import { ClientMessageType, decodeNumber, ErrorCode, ProtocolBlob } from "@nmtjs/protocol/common";
7
+ import { Connection, getFormat, isIterableResult, isSubscriptionResult, ProtocolClientStream, ProtocolError, ProtocolInjectables, UnsupportedContentTypeError, UnsupportedFormatError } from "@nmtjs/protocol/server";
8
+ import { AllowedHttpMethod, HttpCode, HttpCodeMap, HttpStatusText } from "./http.js";
6
9
  import { WsTransportInjectables } from "./injectables.js";
7
- import { getRequestData, send } from "./utils.js";
10
+ import { getRequestBody, getRequestData, readableToArrayBuffer, send, setHeaders } from "./utils.js";
11
+ const DEFAULT_ALLOWED_METHODS = ["post"];
8
12
  export class WsTransportServer {
9
13
  server;
10
14
  clients = new Map();
@@ -23,54 +27,55 @@ export class WsTransportServer {
23
27
  }).ws("/api", {
24
28
  sendPingsAutomatically: true,
25
29
  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);
30
+ upgrade: async (res, req, socketContext) => {
31
+ const ac = new AbortController();
32
+ res.onAborted(ac.abort.bind(ac));
33
+ const requestData = getRequestData(req, res);
34
+ const contentType = requestData.query.get("content-type") || requestData.headers.get("content-type");
35
+ const acceptType = requestData.query.get("accept") || requestData.headers.get("accept");
36
+ const connectionId = randomUUID();
50
37
  try {
51
- const { context: _context, connection } = await this.context.protocol.connections.add(this, {
52
- id,
53
- data: {}
38
+ const { context } = await this.protocol.addConnection(this, {
39
+ id: connectionId,
40
+ data: { type: "ws" }
54
41
  }, {
55
- acceptType: request.acceptType,
56
- contentType: request.contentType
42
+ acceptType,
43
+ contentType
57
44
  });
58
- Object.assign(context, _context);
59
- context.container.provide(ProtocolInjectables.connection, connection);
60
- context.container.provide(WsTransportInjectables.connectionData, request);
61
- opening.resolve();
45
+ context.container.provide(WsTransportInjectables.connectionData, requestData);
46
+ if (!ac.signal.aborted) {
47
+ res.cork(() => {
48
+ res.upgrade({
49
+ id: connectionId,
50
+ request: requestData,
51
+ contentType,
52
+ acceptType,
53
+ backpressure: null,
54
+ context
55
+ }, req.getHeader("sec-websocket-key"), req.getHeader("sec-websocket-protocol"), req.getHeader("sec-websocket-extensions"), socketContext);
56
+ });
57
+ }
62
58
  } catch (error) {
63
- opening.reject(error);
59
+ this.logger.debug(new Error("Failed to upgrade connection", { cause: error }));
60
+ if (!ac.signal.aborted) {
61
+ res.cork(() => {
62
+ res.writeStatus("500 Internal Server Error");
63
+ res.endWithoutBody();
64
+ });
65
+ }
64
66
  }
65
67
  },
68
+ open: (ws) => {
69
+ const { id } = ws.getUserData();
70
+ this.logger.debug("Connection %s opened", id);
71
+ this.clients.set(id, ws);
72
+ },
66
73
  message: async (ws, buffer) => {
67
- const { opening } = ws.getUserData();
68
74
  const messageType = decodeNumber(buffer, "Uint8");
69
75
  if (messageType in this === false) {
70
76
  ws.end(1011, "Unknown message type");
71
77
  } else {
72
78
  try {
73
- await opening.promise;
74
79
  await this[messageType](ws, buffer.slice(Uint8Array.BYTES_PER_ELEMENT));
75
80
  } catch (error) {
76
81
  this.logError(error, "Error while processing message");
@@ -86,9 +91,9 @@ export class WsTransportServer {
86
91
  const { id } = ws.getUserData();
87
92
  this.logger.debug("Connection %s closed with code %s: %s", id, code, Buffer.from(message).toString());
88
93
  this.clients.delete(id);
89
- await this.protocol.connections.remove(id);
94
+ await this.protocol.removeConnection(id);
90
95
  }
91
- });
96
+ }).get("/api/:namespace/:procedure", this.httpHandler.bind(this)).post("/api/:namespace/:procedure", this.httpHandler.bind(this));
92
97
  }
93
98
  send(connection, messageType, buffer) {
94
99
  const ws = this.clients.get(connection.id);
@@ -121,6 +126,174 @@ export class WsTransportServer {
121
126
  async stop() {
122
127
  this.server.close();
123
128
  }
129
+ async httpHandler(res, req) {
130
+ this.applyCors(res, req);
131
+ const ac = new AbortController();
132
+ res.onAborted(ac.abort.bind(ac));
133
+ const method = req.getMethod();
134
+ const namespace = req.getParameter("namespace");
135
+ const procedure = req.getParameter("procedure");
136
+ const requestData = getRequestData(req, res);
137
+ if (!namespace || !procedure) {
138
+ const status = HttpCode.NotFound;
139
+ const text = HttpStatusText[status];
140
+ return void res.cork(() => {
141
+ if (ac.signal.aborted) return;
142
+ res.writeStatus(`${status} ${text}`);
143
+ res.endWithoutBody();
144
+ });
145
+ }
146
+ const isBlob = requestData.headers.get("x-neemata-blob") === "true";
147
+ const contentType = requestData.headers.get("content-type");
148
+ const acceptType = requestData.headers.get("accept");
149
+ const connectionId = randomUUID();
150
+ const connection = new Connection({
151
+ id: connectionId,
152
+ data: { type: "http" }
153
+ });
154
+ const responseHeaders = new Headers();
155
+ const container = this.context.container.fork(Scope.Call);
156
+ container.provide(ProtocolInjectables.connection, connection);
157
+ container.provide(WsTransportInjectables.connectionData, requestData);
158
+ container.provide(WsTransportInjectables.httpResponseHeaders, responseHeaders);
159
+ const body = method === "post" ? getRequestBody(res) : undefined;
160
+ const metadata = (metadata) => {
161
+ const allowHttpMethod = metadata.get(AllowedHttpMethod) ?? DEFAULT_ALLOWED_METHODS;
162
+ if (!allowHttpMethod.includes(method)) {
163
+ throw new ProtocolError(ErrorCode.NotFound);
164
+ }
165
+ };
166
+ let format;
167
+ try {
168
+ format = getFormat(this.context.format, {
169
+ acceptType,
170
+ contentType: isBlob ? "*/*" : contentType
171
+ });
172
+ let payload = undefined;
173
+ if (body) {
174
+ if (isBlob) {
175
+ const type = contentType || "application/octet-stream";
176
+ const contentLength = requestData.headers.get("content-length");
177
+ const size = contentLength ? Number.parseInt(contentLength) : undefined;
178
+ const stream = new ProtocolClientStream(-1, {
179
+ size,
180
+ type
181
+ });
182
+ body.pipe(stream);
183
+ payload = stream;
184
+ } else {
185
+ const buffer = await readableToArrayBuffer(body);
186
+ if (buffer.byteLength > 0) {
187
+ payload = format.decoder.decode(buffer);
188
+ }
189
+ }
190
+ }
191
+ const result = await this.protocol.call({
192
+ connection,
193
+ namespace,
194
+ procedure,
195
+ payload,
196
+ metadata,
197
+ container,
198
+ signal: ac.signal
199
+ });
200
+ if (isIterableResult(result) || isSubscriptionResult(result)) {
201
+ res.cork(() => {
202
+ if (ac.signal.aborted) return;
203
+ const status = HttpCode.NotImplemented;
204
+ const text = HttpStatusText[status];
205
+ res.writeStatus(`${status} ${text}`);
206
+ res.end();
207
+ });
208
+ } else {
209
+ const { output } = result;
210
+ if (output instanceof ProtocolBlob) {
211
+ const { source, metadata } = output;
212
+ const { type } = metadata;
213
+ let stream;
214
+ if (source instanceof ReadableStream) {
215
+ stream = Readable.fromWeb(source);
216
+ } else if (source instanceof Readable || source instanceof Duplex) {
217
+ stream = Readable.from(source);
218
+ } else {
219
+ throw new Error("Invalid stream source");
220
+ }
221
+ res.cork(() => {
222
+ if (ac.signal.aborted) return;
223
+ responseHeaders.set("X-Neemata-Blob", "true");
224
+ responseHeaders.set("Content-Type", type);
225
+ if (metadata.size) res.writeHeader("Content-Length", metadata.size.toString());
226
+ setHeaders(res, responseHeaders);
227
+ });
228
+ ac.signal.addEventListener("abort", () => stream.destroy(), { once: true });
229
+ stream.on("data", (chunk) => {
230
+ console.log({ chunk });
231
+ if (ac.signal.aborted) return;
232
+ const buf = Buffer.from(chunk);
233
+ const ab = buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength);
234
+ const ok = res.write(ab);
235
+ if (!ok) {
236
+ stream.pause();
237
+ res.onWritable(() => {
238
+ stream.resume();
239
+ return true;
240
+ });
241
+ }
242
+ });
243
+ await once(stream, "end");
244
+ if (stream.readableAborted) {
245
+ res.end(undefined, true);
246
+ } else {
247
+ res.end();
248
+ }
249
+ } else {
250
+ res.cork(() => {
251
+ if (ac.signal.aborted) return;
252
+ const status = HttpCode.OK;
253
+ const text = HttpStatusText[status];
254
+ const buffer = format.encoder.encode(output);
255
+ res.writeStatus(`${status} ${text}`);
256
+ responseHeaders.set("Content-Type", format.encoder.contentType);
257
+ setHeaders(res, responseHeaders);
258
+ res.end(buffer);
259
+ });
260
+ }
261
+ }
262
+ } catch (error) {
263
+ if (ac.signal.aborted) return;
264
+ if (error instanceof UnsupportedFormatError) {
265
+ res.cork(() => {
266
+ if (ac.signal.aborted) return;
267
+ const status = error instanceof UnsupportedContentTypeError ? HttpCode.UnsupportedMediaType : HttpCode.NotAcceptable;
268
+ const text = HttpStatusText[status];
269
+ res.writeStatus(`${status} ${text}`);
270
+ res.end();
271
+ });
272
+ } else if (error instanceof ProtocolError) {
273
+ res.cork(() => {
274
+ if (ac.signal.aborted) return;
275
+ const status = error.code in HttpCodeMap ? HttpCodeMap[error.code] : HttpCode.InternalServerError;
276
+ const text = HttpStatusText[status];
277
+ res.writeStatus(`${status} ${text}`);
278
+ res.end(format.encoder.encode(error));
279
+ });
280
+ } else {
281
+ this.logError(error, "Unknown error while processing request");
282
+ res.cork(() => {
283
+ if (ac.signal.aborted) return;
284
+ const status = HttpCode.InternalServerError;
285
+ const text = HttpStatusText[status];
286
+ const payload = format.encoder.encode(new ProtocolError(ErrorCode.InternalServerError, "Internal Server Error"));
287
+ res.writeStatus(`${status} ${text}`);
288
+ res.end(payload);
289
+ });
290
+ }
291
+ } finally {
292
+ container.dispose().catch((error) => {
293
+ this.logError(error, "Error while disposing call container");
294
+ });
295
+ }
296
+ }
124
297
  get protocol() {
125
298
  return this.context.protocol;
126
299
  }
@@ -131,8 +304,18 @@ export class WsTransportServer {
131
304
  this.logger.error(new Error(message, { cause }));
132
305
  }
133
306
  applyCors(res, req) {
307
+ if (this.options.cors === false) return;
134
308
  const origin = req.getHeader("origin");
135
309
  if (!origin) return;
310
+ let allowed = false;
311
+ if (this.options.cors === undefined || this.options.cors === true) {
312
+ allowed = true;
313
+ } else if (Array.isArray(this.options.cors)) {
314
+ allowed = this.options.cors.includes(origin);
315
+ } else {
316
+ allowed = this.options.cors(origin);
317
+ }
318
+ if (!allowed) return;
136
319
  res.writeHeader("Access-Control-Allow-Origin", origin);
137
320
  res.writeHeader("Access-Control-Allow-Headers", "Content-Type");
138
321
  res.writeHeader("Access-Control-Allow-Methods", "GET, POST");
@@ -153,26 +336,28 @@ export class WsTransportServer {
153
336
  [ClientMessageType.ClientStreamPush](ws, buffer) {
154
337
  const { id } = ws.getUserData();
155
338
  const streamId = decodeNumber(buffer, "Uint32");
156
- this.protocol.clientStreams.push(id, streamId, buffer.slice(Uint32Array.BYTES_PER_ELEMENT));
339
+ this.protocol.pushClientStream(id, streamId, buffer.slice(Uint32Array.BYTES_PER_ELEMENT));
157
340
  }
158
341
  [ClientMessageType.ClientStreamEnd](ws, buffer) {
159
342
  const { id } = ws.getUserData();
160
343
  const streamId = decodeNumber(buffer, "Uint32");
161
- this.protocol.clientStreams.end(id, streamId);
344
+ this.protocol.endClientStream(id, streamId);
162
345
  }
163
346
  [ClientMessageType.ClientStreamAbort](ws, buffer) {
164
347
  const { id } = ws.getUserData();
165
348
  const streamId = decodeNumber(buffer, "Uint32");
166
- this.protocol.clientStreams.abort(id, streamId);
349
+ this.protocol.abortClientStream(id, streamId);
167
350
  }
168
351
  [ClientMessageType.ServerStreamPull](ws, buffer) {
169
352
  const { id } = ws.getUserData();
170
353
  const streamId = decodeNumber(buffer, "Uint32");
171
- this.protocol.serverStreams.pull(id, streamId);
354
+ this.protocol.pullServerStream(id, streamId);
172
355
  }
173
356
  [ClientMessageType.ServerStreamAbort](ws, buffer) {
174
357
  const { id } = ws.getUserData();
175
358
  const streamId = decodeNumber(buffer, "Uint32");
176
- this.protocol.serverStreams.abort(id, streamId);
359
+ this.protocol.abortServerStream(id, streamId);
177
360
  }
178
361
  }
362
+
363
+ //# sourceMappingURL=server.js.map
@@ -1 +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 us_socket_local_port,\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 = '127.0.0.1', port = 0, unix } = this.options\n if (unix) {\n this.server.listen_unix((socket) => {\n if (socket) {\n this.logger.info('Server started on unix://%s', unix)\n resolve()\n } else {\n reject(new Error('Failed to start WebSockets server'))\n }\n }, unix)\n } else {\n this.server.listen(hostname, port, (socket) => {\n if (socket) {\n this.logger.info(\n 'WebSocket Server started on %s:%s',\n hostname,\n us_socket_local_port(socket),\n )\n resolve()\n } else {\n reject(new Error('Failed to start WebSockets server'))\n }\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}
1
+ {"mappings":"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","names":["context: TransportPluginContext","options: WsTransportOptions","ws: WsTransportSocket","error: any","connection: Connection<WsConnectionData>","messageType: ServerMessageType","buffer: ArrayBuffer","res: HttpResponse","req: HttpRequest","metadata: ProtocolApiCallOptions['metadata']","format: ReturnType<typeof getFormat>","payload: any","stream: Readable","cause: any"],"sources":["../src/server.ts"],"sourcesContent":["import {\n App,\n type HttpRequest,\n type HttpResponse,\n SSLApp,\n type TemplatedApp,\n us_socket_local_port,\n} from 'uWebSockets.js'\nimport { randomUUID } from 'node:crypto'\nimport { once } from 'node:events'\nimport { Duplex, Readable } from 'node:stream'\nimport { Scope } from '@nmtjs/core'\nimport {\n ClientMessageType,\n decodeNumber,\n ErrorCode,\n ProtocolBlob,\n type ServerMessageType,\n} from '@nmtjs/protocol/common'\nimport {\n Connection,\n getFormat,\n isIterableResult,\n isSubscriptionResult,\n type ProtocolApiCallOptions,\n ProtocolClientStream,\n ProtocolError,\n ProtocolInjectables,\n type Transport,\n type TransportPluginContext,\n UnsupportedContentTypeError,\n UnsupportedFormatError,\n} from '@nmtjs/protocol/server'\nimport {\n AllowedHttpMethod,\n HttpCode,\n HttpCodeMap,\n HttpStatusText,\n} from './http.ts'\nimport { WsTransportInjectables } from './injectables.ts'\nimport type {\n WsConnectionData,\n WsTransportOptions,\n WsTransportSocket,\n WsUserData,\n} from './types.ts'\nimport {\n getRequestBody,\n getRequestData,\n readableToArrayBuffer,\n send,\n setHeaders,\n} from './utils.ts'\n\nconst DEFAULT_ALLOWED_METHODS = ['post'] as ('get' | 'post')[]\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 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: async (res, req, socketContext) => {\n const ac = new AbortController()\n\n res.onAborted(ac.abort.bind(ac))\n\n const requestData = getRequestData(req, res)\n const contentType =\n requestData.query.get('content-type') ||\n requestData.headers.get('content-type')\n const acceptType =\n requestData.query.get('accept') || requestData.headers.get('accept')\n\n const connectionId = randomUUID()\n\n try {\n const { context } = await this.protocol.addConnection(\n this,\n { id: connectionId, data: { type: 'ws' } },\n { acceptType, contentType },\n )\n context.container.provide(\n WsTransportInjectables.connectionData,\n requestData,\n )\n if (!ac.signal.aborted) {\n res.cork(() => {\n res.upgrade(\n {\n id: connectionId,\n request: requestData,\n contentType,\n acceptType,\n backpressure: null,\n context,\n } as WsUserData,\n req.getHeader('sec-websocket-key'),\n req.getHeader('sec-websocket-protocol'),\n req.getHeader('sec-websocket-extensions'),\n socketContext,\n )\n })\n }\n } catch (error) {\n this.logger.debug(\n new Error('Failed to upgrade connection', { cause: error }),\n )\n if (!ac.signal.aborted) {\n res.cork(() => {\n res.writeStatus('500 Internal Server Error')\n res.endWithoutBody()\n })\n }\n }\n },\n open: (ws: WsTransportSocket) => {\n const { id } = ws.getUserData()\n this.logger.debug('Connection %s opened', id)\n this.clients.set(id, ws)\n },\n message: async (ws: WsTransportSocket, buffer) => {\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 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.removeConnection(id)\n },\n })\n .get('/api/:namespace/:procedure', this.httpHandler.bind(this))\n .post('/api/:namespace/:procedure', this.httpHandler.bind(this))\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 = '127.0.0.1', port = 0, unix } = this.options\n if (unix) {\n this.server.listen_unix((socket) => {\n if (socket) {\n this.logger.info('Server started on unix://%s', unix)\n resolve()\n } else {\n reject(new Error('Failed to start WebSockets server'))\n }\n }, unix)\n } else {\n this.server.listen(hostname, port, (socket) => {\n if (socket) {\n this.logger.info(\n 'WebSocket Server started on %s:%s',\n hostname,\n us_socket_local_port(socket),\n )\n resolve()\n } else {\n reject(new Error('Failed to start WebSockets server'))\n }\n })\n }\n })\n }\n\n async stop() {\n this.server.close()\n }\n\n // TODO: decompose this mess\n protected async httpHandler(res: HttpResponse, req: HttpRequest) {\n this.applyCors(res, req)\n\n const ac = new AbortController()\n\n res.onAborted(ac.abort.bind(ac))\n\n const method = req.getMethod() as 'get' | 'post'\n const namespace = req.getParameter('namespace')\n const procedure = req.getParameter('procedure')\n const requestData = getRequestData(req, res)\n\n if (!namespace || !procedure) {\n const status = HttpCode.NotFound\n const text = HttpStatusText[status]\n return void res.cork(() => {\n if (ac.signal.aborted) return\n res.writeStatus(`${status} ${text}`)\n res.endWithoutBody()\n })\n }\n\n const isBlob = requestData.headers.get('x-neemata-blob') === 'true'\n\n const contentType = requestData.headers.get('content-type')\n const acceptType = requestData.headers.get('accept')\n const connectionId = randomUUID()\n const connection = new Connection<WsConnectionData>({\n id: connectionId,\n data: { type: 'http' },\n })\n const responseHeaders = new Headers()\n const container = this.context.container.fork(Scope.Call)\n container.provide(ProtocolInjectables.connection, connection)\n container.provide(WsTransportInjectables.connectionData, requestData)\n container.provide(\n WsTransportInjectables.httpResponseHeaders,\n responseHeaders,\n )\n\n const body = method === 'post' ? getRequestBody(res) : undefined\n\n const metadata: ProtocolApiCallOptions['metadata'] = (metadata) => {\n const allowHttpMethod =\n metadata.get(AllowedHttpMethod) ?? DEFAULT_ALLOWED_METHODS\n if (!allowHttpMethod.includes(method)) {\n throw new ProtocolError(ErrorCode.NotFound)\n }\n }\n let format: ReturnType<typeof getFormat>\n try {\n format = getFormat(this.context.format, {\n acceptType,\n contentType: isBlob ? '*/*' : contentType,\n })\n\n let payload: any = undefined\n\n if (body) {\n if (isBlob) {\n const type = contentType || 'application/octet-stream'\n const contentLength = requestData.headers.get('content-length')\n const size = contentLength\n ? Number.parseInt(contentLength)\n : undefined\n const stream = new ProtocolClientStream(-1, { size, type })\n body.pipe(stream)\n payload = stream\n } else {\n const buffer = await readableToArrayBuffer(body)\n if (buffer.byteLength > 0) {\n payload = format.decoder.decode(buffer)\n }\n }\n }\n\n const result = await this.protocol.call({\n connection,\n namespace,\n procedure,\n payload,\n metadata,\n container,\n signal: ac.signal,\n })\n\n if (isIterableResult(result) || isSubscriptionResult(result)) {\n res.cork(() => {\n if (ac.signal.aborted) return\n const status = HttpCode.NotImplemented\n const text = HttpStatusText[status]\n res.writeStatus(`${status} ${text}`)\n res.end()\n })\n } else {\n const { output } = result\n\n if (output instanceof ProtocolBlob) {\n const { source, metadata } = output\n const { type } = metadata\n\n let stream: Readable\n\n if (source instanceof ReadableStream) {\n stream = Readable.fromWeb(source as any)\n } else if (source instanceof Readable || source instanceof Duplex) {\n stream = Readable.from(source)\n } else {\n throw new Error('Invalid stream source')\n }\n\n res.cork(() => {\n if (ac.signal.aborted) return\n responseHeaders.set('X-Neemata-Blob', 'true')\n responseHeaders.set('Content-Type', type)\n if (metadata.size)\n res.writeHeader('Content-Length', metadata.size.toString())\n setHeaders(res, responseHeaders)\n })\n\n ac.signal.addEventListener('abort', () => stream.destroy(), {\n once: true,\n })\n\n stream.on('data', (chunk) => {\n console.log({ chunk })\n if (ac.signal.aborted) return\n const buf = Buffer.from(chunk)\n const ab = buf.buffer.slice(\n buf.byteOffset,\n buf.byteOffset + buf.byteLength,\n )\n const ok = res.write(ab)\n if (!ok) {\n stream.pause()\n res.onWritable(() => {\n stream.resume()\n return true\n })\n }\n })\n await once(stream, 'end')\n if (stream.readableAborted) {\n res.end(undefined, true)\n } else {\n res.end()\n }\n } else {\n res.cork(() => {\n if (ac.signal.aborted) return\n const status = HttpCode.OK\n const text = HttpStatusText[status]\n const buffer = format.encoder.encode(output)\n res.writeStatus(`${status} ${text}`)\n responseHeaders.set('Content-Type', format.encoder.contentType)\n setHeaders(res, responseHeaders)\n res.end(buffer)\n })\n }\n }\n } catch (error) {\n if (ac.signal.aborted) return\n if (error instanceof UnsupportedFormatError) {\n res.cork(() => {\n if (ac.signal.aborted) return\n const status =\n error instanceof UnsupportedContentTypeError\n ? HttpCode.UnsupportedMediaType\n : HttpCode.NotAcceptable\n const text = HttpStatusText[status]\n res.writeStatus(`${status} ${text}`)\n res.end()\n })\n } else if (error instanceof ProtocolError) {\n res.cork(() => {\n if (ac.signal.aborted) return\n const status =\n error.code in HttpCodeMap\n ? HttpCodeMap[error.code]\n : HttpCode.InternalServerError\n const text = HttpStatusText[status]\n res.writeStatus(`${status} ${text}`)\n res.end(format!.encoder.encode(error))\n })\n } else {\n this.logError(error, 'Unknown error while processing request')\n res.cork(() => {\n if (ac.signal.aborted) return\n const status = HttpCode.InternalServerError\n const text = HttpStatusText[status]\n const payload = format!.encoder.encode(\n new ProtocolError(\n ErrorCode.InternalServerError,\n 'Internal Server Error',\n ),\n )\n res.writeStatus(`${status} ${text}`)\n res.end(payload)\n })\n }\n } finally {\n container.dispose().catch((error) => {\n this.logError(error, 'Error while disposing call container')\n })\n }\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: any,\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 if (this.options.cors === false) return\n\n const origin = req.getHeader('origin')\n if (!origin) return\n\n let allowed = false\n\n if (this.options.cors === undefined || this.options.cors === true) {\n allowed = true\n } else if (Array.isArray(this.options.cors)) {\n allowed = this.options.cors.includes(origin)\n } else {\n allowed = this.options.cors(origin)\n }\n\n if (!allowed) return\n\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.pushClientStream(\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.endClientStream(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.abortClientStream(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.pullServerStream(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.abortServerStream(id, streamId)\n }\n}\n"],"version":3,"file":"server.js"}
package/dist/transport.js CHANGED
@@ -3,3 +3,5 @@ import { WsTransportServer } from "./server.js";
3
3
  export const WsTransport = createTransport("WsTransport", (context, options) => {
4
4
  return new WsTransportServer(context, options);
5
5
  });
6
+
7
+ //# sourceMappingURL=transport.js.map