@nmtjs/http-transport 0.1.8 → 0.15.0-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE.md CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2024 Denis Ilchyshyn
1
+ Copyright (c) 2025 Denys Ilchyshyn
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4
4
 
package/README.md CHANGED
@@ -1 +1,9 @@
1
- ## HTTP 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
@@ -0,0 +1,146 @@
1
+ import { createMetadataKey } from '@nmtjs/core';
2
+ import { ErrorCode } from '@nmtjs/protocol';
3
+ export var HttpStatus;
4
+ (function (HttpStatus) {
5
+ HttpStatus[HttpStatus["Continue"] = 100] = "Continue";
6
+ HttpStatus[HttpStatus["SwitchingProtocols"] = 101] = "SwitchingProtocols";
7
+ HttpStatus[HttpStatus["Processing"] = 102] = "Processing";
8
+ HttpStatus[HttpStatus["EarlyHints"] = 103] = "EarlyHints";
9
+ HttpStatus[HttpStatus["OK"] = 200] = "OK";
10
+ HttpStatus[HttpStatus["Created"] = 201] = "Created";
11
+ HttpStatus[HttpStatus["Accepted"] = 202] = "Accepted";
12
+ HttpStatus[HttpStatus["NonAuthoritativeInformation"] = 203] = "NonAuthoritativeInformation";
13
+ HttpStatus[HttpStatus["NoContent"] = 204] = "NoContent";
14
+ HttpStatus[HttpStatus["ResetContent"] = 205] = "ResetContent";
15
+ HttpStatus[HttpStatus["PartialContent"] = 206] = "PartialContent";
16
+ HttpStatus[HttpStatus["MultiStatus"] = 207] = "MultiStatus";
17
+ HttpStatus[HttpStatus["AlreadyReported"] = 208] = "AlreadyReported";
18
+ HttpStatus[HttpStatus["IMUsed"] = 226] = "IMUsed";
19
+ HttpStatus[HttpStatus["MultipleChoices"] = 300] = "MultipleChoices";
20
+ HttpStatus[HttpStatus["MovedPermanently"] = 301] = "MovedPermanently";
21
+ HttpStatus[HttpStatus["Found"] = 302] = "Found";
22
+ HttpStatus[HttpStatus["SeeOther"] = 303] = "SeeOther";
23
+ HttpStatus[HttpStatus["NotModified"] = 304] = "NotModified";
24
+ HttpStatus[HttpStatus["UseProxy"] = 305] = "UseProxy";
25
+ HttpStatus[HttpStatus["TemporaryRedirect"] = 307] = "TemporaryRedirect";
26
+ HttpStatus[HttpStatus["PermanentRedirect"] = 308] = "PermanentRedirect";
27
+ HttpStatus[HttpStatus["BadRequest"] = 400] = "BadRequest";
28
+ HttpStatus[HttpStatus["Unauthorized"] = 401] = "Unauthorized";
29
+ HttpStatus[HttpStatus["PaymentRequired"] = 402] = "PaymentRequired";
30
+ HttpStatus[HttpStatus["Forbidden"] = 403] = "Forbidden";
31
+ HttpStatus[HttpStatus["NotFound"] = 404] = "NotFound";
32
+ HttpStatus[HttpStatus["MethodNotAllowed"] = 405] = "MethodNotAllowed";
33
+ HttpStatus[HttpStatus["NotAcceptable"] = 406] = "NotAcceptable";
34
+ HttpStatus[HttpStatus["ProxyAuthenticationRequired"] = 407] = "ProxyAuthenticationRequired";
35
+ HttpStatus[HttpStatus["RequestTimeout"] = 408] = "RequestTimeout";
36
+ HttpStatus[HttpStatus["Conflict"] = 409] = "Conflict";
37
+ HttpStatus[HttpStatus["Gone"] = 410] = "Gone";
38
+ HttpStatus[HttpStatus["LengthRequired"] = 411] = "LengthRequired";
39
+ HttpStatus[HttpStatus["PreconditionFailed"] = 412] = "PreconditionFailed";
40
+ HttpStatus[HttpStatus["PayloadTooLarge"] = 413] = "PayloadTooLarge";
41
+ HttpStatus[HttpStatus["URITooLong"] = 414] = "URITooLong";
42
+ HttpStatus[HttpStatus["UnsupportedMediaType"] = 415] = "UnsupportedMediaType";
43
+ HttpStatus[HttpStatus["RangeNotSatisfiable"] = 416] = "RangeNotSatisfiable";
44
+ HttpStatus[HttpStatus["ExpectationFailed"] = 417] = "ExpectationFailed";
45
+ HttpStatus[HttpStatus["ImATeapot"] = 418] = "ImATeapot";
46
+ HttpStatus[HttpStatus["MisdirectedRequest"] = 421] = "MisdirectedRequest";
47
+ HttpStatus[HttpStatus["UnprocessableEntity"] = 422] = "UnprocessableEntity";
48
+ HttpStatus[HttpStatus["Locked"] = 423] = "Locked";
49
+ HttpStatus[HttpStatus["FailedDependency"] = 424] = "FailedDependency";
50
+ HttpStatus[HttpStatus["TooEarly"] = 425] = "TooEarly";
51
+ HttpStatus[HttpStatus["UpgradeRequired"] = 426] = "UpgradeRequired";
52
+ HttpStatus[HttpStatus["PreconditionRequired"] = 428] = "PreconditionRequired";
53
+ HttpStatus[HttpStatus["TooManyRequests"] = 429] = "TooManyRequests";
54
+ HttpStatus[HttpStatus["RequestHeaderFieldsTooLarge"] = 431] = "RequestHeaderFieldsTooLarge";
55
+ HttpStatus[HttpStatus["UnavailableForLegalReasons"] = 451] = "UnavailableForLegalReasons";
56
+ HttpStatus[HttpStatus["InternalServerError"] = 500] = "InternalServerError";
57
+ HttpStatus[HttpStatus["NotImplemented"] = 501] = "NotImplemented";
58
+ HttpStatus[HttpStatus["BadGateway"] = 502] = "BadGateway";
59
+ HttpStatus[HttpStatus["ServiceUnavailable"] = 503] = "ServiceUnavailable";
60
+ HttpStatus[HttpStatus["GatewayTimeout"] = 504] = "GatewayTimeout";
61
+ HttpStatus[HttpStatus["HTTPVersionNotSupported"] = 505] = "HTTPVersionNotSupported";
62
+ HttpStatus[HttpStatus["VariantAlsoNegotiates"] = 506] = "VariantAlsoNegotiates";
63
+ HttpStatus[HttpStatus["InsufficientStorage"] = 507] = "InsufficientStorage";
64
+ HttpStatus[HttpStatus["LoopDetected"] = 508] = "LoopDetected";
65
+ HttpStatus[HttpStatus["NotExtended"] = 510] = "NotExtended";
66
+ HttpStatus[HttpStatus["NetworkAuthenticationRequired"] = 511] = "NetworkAuthenticationRequired";
67
+ })(HttpStatus || (HttpStatus = {}));
68
+ export const HttpStatusText = {
69
+ [HttpStatus.Continue]: 'Continue',
70
+ [HttpStatus.SwitchingProtocols]: 'Switching Protocols',
71
+ [HttpStatus.Processing]: 'Processing',
72
+ [HttpStatus.EarlyHints]: 'Early Hints',
73
+ [HttpStatus.OK]: 'OK',
74
+ [HttpStatus.Created]: 'Created',
75
+ [HttpStatus.Accepted]: 'Accepted',
76
+ [HttpStatus.NonAuthoritativeInformation]: 'Non-Authoritative Information',
77
+ [HttpStatus.NoContent]: 'No Content',
78
+ [HttpStatus.ResetContent]: 'Reset Content',
79
+ [HttpStatus.PartialContent]: 'Partial Content',
80
+ [HttpStatus.MultiStatus]: 'Multi-Status',
81
+ [HttpStatus.AlreadyReported]: 'Already Reported',
82
+ [HttpStatus.IMUsed]: 'IM Used',
83
+ [HttpStatus.MultipleChoices]: 'Multiple Choices',
84
+ [HttpStatus.MovedPermanently]: 'Moved Permanently',
85
+ [HttpStatus.Found]: 'Found',
86
+ [HttpStatus.SeeOther]: 'See Other',
87
+ [HttpStatus.NotModified]: 'Not Modified',
88
+ [HttpStatus.UseProxy]: 'Use Proxy',
89
+ [HttpStatus.TemporaryRedirect]: 'Temporary Redirect',
90
+ [HttpStatus.PermanentRedirect]: 'Permanent Redirect',
91
+ [HttpStatus.BadRequest]: 'Bad Request',
92
+ [HttpStatus.Unauthorized]: 'Unauthorized',
93
+ [HttpStatus.PaymentRequired]: 'Payment Required',
94
+ [HttpStatus.Forbidden]: 'Forbidden',
95
+ [HttpStatus.NotFound]: 'Not Found',
96
+ [HttpStatus.MethodNotAllowed]: 'Method Not Allowed',
97
+ [HttpStatus.NotAcceptable]: 'Not Acceptable',
98
+ [HttpStatus.ProxyAuthenticationRequired]: 'Proxy Authentication Required',
99
+ [HttpStatus.RequestTimeout]: 'Request Timeout',
100
+ [HttpStatus.Conflict]: 'Conflict',
101
+ [HttpStatus.Gone]: 'Gone',
102
+ [HttpStatus.LengthRequired]: 'Length Required',
103
+ [HttpStatus.PreconditionFailed]: 'Precondition Failed',
104
+ [HttpStatus.PayloadTooLarge]: 'Payload Too Large',
105
+ [HttpStatus.URITooLong]: 'URI Too Long',
106
+ [HttpStatus.UnsupportedMediaType]: 'Unsupported Media Type',
107
+ [HttpStatus.RangeNotSatisfiable]: 'Range Not Satisfiable',
108
+ [HttpStatus.ExpectationFailed]: 'Expectation Failed',
109
+ [HttpStatus.ImATeapot]: "I'm a Teapot",
110
+ [HttpStatus.MisdirectedRequest]: 'Misdirected Request',
111
+ [HttpStatus.UnprocessableEntity]: 'Unprocessable Entity',
112
+ [HttpStatus.Locked]: 'Locked',
113
+ [HttpStatus.FailedDependency]: 'Failed Dependency',
114
+ [HttpStatus.TooEarly]: 'Too Early',
115
+ [HttpStatus.UpgradeRequired]: 'Upgrade Required',
116
+ [HttpStatus.PreconditionRequired]: 'Precondition Required',
117
+ [HttpStatus.TooManyRequests]: 'Too Many Requests',
118
+ [HttpStatus.RequestHeaderFieldsTooLarge]: 'Request Header Fields Too Large',
119
+ [HttpStatus.UnavailableForLegalReasons]: 'Unavailable For Legal Reasons',
120
+ [HttpStatus.InternalServerError]: 'Internal Server Error',
121
+ [HttpStatus.NotImplemented]: 'Not Implemented',
122
+ [HttpStatus.BadGateway]: 'Bad Gateway',
123
+ [HttpStatus.ServiceUnavailable]: 'Service Unavailable',
124
+ [HttpStatus.GatewayTimeout]: 'Gateway Timeout',
125
+ [HttpStatus.HTTPVersionNotSupported]: 'HTTP Version Not Supported',
126
+ [HttpStatus.VariantAlsoNegotiates]: 'Variant Also Negotiates',
127
+ [HttpStatus.InsufficientStorage]: 'Insufficient Storage',
128
+ [HttpStatus.LoopDetected]: 'Loop Detected',
129
+ [HttpStatus.NotExtended]: 'Not Extended',
130
+ [HttpStatus.NetworkAuthenticationRequired]: 'Network Authentication Required',
131
+ };
132
+ export const HttpCodeMap = {
133
+ [ErrorCode.ValidationError]: HttpStatus.BadRequest,
134
+ [ErrorCode.BadRequest]: HttpStatus.BadRequest,
135
+ [ErrorCode.NotFound]: HttpStatus.NotFound,
136
+ [ErrorCode.Forbidden]: HttpStatus.Forbidden,
137
+ [ErrorCode.Unauthorized]: HttpStatus.Unauthorized,
138
+ [ErrorCode.InternalServerError]: HttpStatus.InternalServerError,
139
+ [ErrorCode.NotAcceptable]: HttpStatus.NotAcceptable,
140
+ [ErrorCode.RequestTimeout]: HttpStatus.RequestTimeout,
141
+ [ErrorCode.GatewayTimeout]: HttpStatus.GatewayTimeout,
142
+ [ErrorCode.ServiceUnavailable]: HttpStatus.ServiceUnavailable,
143
+ [ErrorCode.ClientRequestError]: HttpStatus.BadRequest,
144
+ [ErrorCode.ConnectionError]: HttpStatus.NotAcceptable,
145
+ };
146
+ export const AllowedHttpMethod = createMetadataKey('http:method');
package/dist/index.js CHANGED
@@ -1,5 +1,4 @@
1
- export * from "./lib/server.js";
2
- export * from "./lib/transport.js";
3
- export * from "./lib/types.js";
4
- export * from "./lib/utils.js";
5
- export * from "./lib/injectables.js";
1
+ export * from "./injectables.js";
2
+ export * from "./server.js";
3
+ export * from "./types.js";
4
+ export * from "./utils.js";
@@ -0,0 +1,4 @@
1
+ import { createLazyInjectable, Scope } from '@nmtjs/core';
2
+ import { connectionData as connectionDataInjectable } from '@nmtjs/gateway';
3
+ export const connectionData = connectionDataInjectable.$withType();
4
+ export const httpResponseHeaders = createLazyInjectable(Scope.Call);
@@ -0,0 +1,67 @@
1
+ import { ProxyableTransportType } from '@nmtjs/gateway';
2
+ import * as injectables from "../injectables.js";
3
+ import { createHTTPTransportWorker } from "../server.js";
4
+ import { InternalServerErrorHttpResponse, NotFoundHttpResponse, StatusResponse, } from "../utils.js";
5
+ function adapterFactory(params) {
6
+ let server = null;
7
+ function createServer() {
8
+ return globalThis.Bun.serve({
9
+ ...params.runtime,
10
+ unix: params.listen.unix,
11
+ port: params.listen.port ?? 0,
12
+ hostname: params.listen.hostname,
13
+ reusePort: params.listen.reusePort,
14
+ tls: params.tls
15
+ ? {
16
+ cert: params.tls.cert,
17
+ key: params.tls.key,
18
+ passphrase: params.tls.passphrase,
19
+ }
20
+ : undefined,
21
+ // @ts-expect-error
22
+ routes: {
23
+ ...params.runtime?.routes,
24
+ '/healthy': { GET: StatusResponse },
25
+ },
26
+ async fetch(request, server) {
27
+ const url = new URL(request.url);
28
+ try {
29
+ if (request.headers.get('upgrade') === 'websocket')
30
+ return NotFoundHttpResponse();
31
+ const { body, headers, method } = request;
32
+ return await params.fetchHandler({ url, method, headers }, body, request.signal);
33
+ }
34
+ catch (err) {
35
+ // TODO: proper logging
36
+ console.error(err);
37
+ // params.logger.error({ err }, 'Error in fetch handler')
38
+ return InternalServerErrorHttpResponse();
39
+ }
40
+ },
41
+ });
42
+ }
43
+ return {
44
+ runtime: {
45
+ get bun() {
46
+ return server;
47
+ },
48
+ },
49
+ start: async () => {
50
+ server = createServer();
51
+ return server.url.href;
52
+ },
53
+ stop: async () => {
54
+ if (server) {
55
+ await server.stop();
56
+ server = null;
57
+ }
58
+ },
59
+ };
60
+ }
61
+ export const HttpTransport = {
62
+ proxyable: ProxyableTransportType.HTTP,
63
+ injectables,
64
+ factory(options) {
65
+ return createHTTPTransportWorker(adapterFactory, options);
66
+ },
67
+ };
@@ -0,0 +1,94 @@
1
+ import { ProxyableTransportType } from '@nmtjs/gateway';
2
+ import * as injectables from "../injectables.js";
3
+ import { createHTTPTransportWorker } from "../server.js";
4
+ import { InternalServerErrorHttpResponse, NotFoundHttpResponse, StatusResponse, } from "../utils.js";
5
+ function adapterFactory(params) {
6
+ let server = null;
7
+ function createServer() {
8
+ const listenOptions = params.listen.unix
9
+ ? { path: params.listen.unix }
10
+ : {
11
+ port: params.listen.port,
12
+ hostname: params.listen.hostname,
13
+ reusePort: params.listen.reusePort,
14
+ };
15
+ const options = {
16
+ ...listenOptions,
17
+ tls: params.tls
18
+ ? {
19
+ cert: params.tls.cert,
20
+ key: params.tls.key,
21
+ passphrase: params.tls.passphrase,
22
+ }
23
+ : undefined,
24
+ };
25
+ return new Promise((resolve) => {
26
+ const server = globalThis.Deno.serve({
27
+ ...params.runtime,
28
+ ...options,
29
+ handler: async (request, info) => {
30
+ const url = new URL(request.url);
31
+ if (url.pathname === '/healthy') {
32
+ return StatusResponse();
33
+ }
34
+ try {
35
+ if (request.headers.get('upgrade') === 'websocket') {
36
+ return NotFoundHttpResponse();
37
+ }
38
+ const { headers, method, body } = request;
39
+ return await params.fetchHandler({ url, method, headers }, body, request.signal);
40
+ }
41
+ catch (err) {
42
+ // TODO: proper logging
43
+ console.error(err);
44
+ // params.logger.error({ err }, 'Error in fetch handler')
45
+ return InternalServerErrorHttpResponse();
46
+ }
47
+ },
48
+ onListen(addr) {
49
+ setTimeout(() => {
50
+ resolve({ server, addr });
51
+ }, 1);
52
+ },
53
+ });
54
+ });
55
+ }
56
+ return {
57
+ runtime: {
58
+ get deno() {
59
+ return server;
60
+ },
61
+ },
62
+ start: async () => {
63
+ const { server: _server, addr } = await createServer();
64
+ server = _server;
65
+ switch (addr.transport) {
66
+ case 'unix':
67
+ case 'unixpacket':
68
+ return `unix://${addr.path}`;
69
+ case 'tcp':
70
+ case 'udp': {
71
+ const proto = params.tls ? 'https' : 'http';
72
+ return `${proto}://${addr.hostname}:${addr.port}`;
73
+ }
74
+ case 'vsock':
75
+ return `vsock://${addr.cid}:${addr.port}`;
76
+ default:
77
+ throw new Error(`Unsupported address transport`);
78
+ }
79
+ },
80
+ stop: async () => {
81
+ if (server) {
82
+ await server.shutdown();
83
+ server = null;
84
+ }
85
+ },
86
+ };
87
+ }
88
+ export const HttpTransport = {
89
+ proxyable: ProxyableTransportType.HTTP,
90
+ injectables,
91
+ factory(options) {
92
+ return createHTTPTransportWorker(adapterFactory, options);
93
+ },
94
+ };
@@ -0,0 +1,136 @@
1
+ import {} from 'node:dns';
2
+ import { setTimeout } from 'node:timers/promises';
3
+ import { ProxyableTransportType } from '@nmtjs/gateway';
4
+ import * as injectables from "../injectables.js";
5
+ import { createHTTPTransportWorker } from "../server.js";
6
+ import { InternalServerErrorHttpResponse, NotFoundHttpResponse, StatusResponse, } from "../utils.js";
7
+ import { App, SSLApp, us_socket_local_port } from 'uWebSockets.js';
8
+ function adapterFactory(params) {
9
+ const server = params.tls
10
+ ? SSLApp({
11
+ passphrase: params.tls.passphrase,
12
+ key_file_name: params.tls.key,
13
+ cert_file_name: params.tls.cert,
14
+ })
15
+ : App();
16
+ server
17
+ .get('/healthy', async (res) => {
18
+ res.onAborted(() => { });
19
+ const response = StatusResponse();
20
+ res.cork(async () => {
21
+ res
22
+ .writeStatus(`${response.status} ${response.statusText}`)
23
+ .end(await response.arrayBuffer());
24
+ });
25
+ })
26
+ .any('/*', async (res, req) => {
27
+ const controller = new AbortController();
28
+ res.onAborted(() => {
29
+ res.aborted = true;
30
+ controller.abort();
31
+ });
32
+ let response = NotFoundHttpResponse();
33
+ const headers = new Headers();
34
+ const method = req.getMethod();
35
+ req.forEach((k, v) => headers.append(k, v));
36
+ const host = headers.get('host') || 'localhost';
37
+ const proto = headers.get('x-forwarded-proto') || params.tls ? 'https' : 'http';
38
+ const url = new URL(req.getUrl(), `${proto}://${host}`);
39
+ try {
40
+ const body = new ReadableStream({
41
+ start(controller) {
42
+ res.onData((chunk, isLast) => {
43
+ if (chunk) {
44
+ const copy = Buffer.allocUnsafe(chunk.byteLength);
45
+ copy.set(new Uint8Array(chunk));
46
+ controller.enqueue(copy);
47
+ }
48
+ if (isLast)
49
+ controller.close();
50
+ });
51
+ res.onAborted(() => controller.error());
52
+ },
53
+ });
54
+ response = await params.fetchHandler({ url, method, headers }, body, controller.signal);
55
+ }
56
+ catch (err) {
57
+ // TODO: proper logging
58
+ console.error(err);
59
+ // params.logger.error({ err }, 'Error in fetch handler')
60
+ response = InternalServerErrorHttpResponse();
61
+ }
62
+ if (res.aborted)
63
+ return undefined;
64
+ else {
65
+ res.cork(() => {
66
+ if (res.aborted)
67
+ return undefined;
68
+ res.writeStatus(`${response.status.toString()} ${response.statusText}`);
69
+ response.headers.forEach((v, k) => res.writeHeader(k, v));
70
+ });
71
+ if (response.body) {
72
+ try {
73
+ const reader = response.body.getReader();
74
+ let chunk = await reader.read();
75
+ do {
76
+ if (res.aborted)
77
+ break;
78
+ if (chunk.value)
79
+ res.cork(() => res.write(chunk.value));
80
+ chunk = await reader.read();
81
+ } while (!chunk.done);
82
+ if (!res.aborted)
83
+ res.cork(() => res.end());
84
+ }
85
+ catch {
86
+ if (!res.aborted)
87
+ res.cork(() => res.close());
88
+ }
89
+ }
90
+ else {
91
+ if (!res.aborted)
92
+ res.cork(() => res.end());
93
+ }
94
+ }
95
+ });
96
+ return {
97
+ runtime: { node: server },
98
+ start: () => new Promise((resolve, reject) => {
99
+ if (params.listen.unix) {
100
+ server.listen_unix((socket) => {
101
+ if (socket) {
102
+ resolve('unix://' + params.listen.unix);
103
+ }
104
+ else {
105
+ reject(new Error('Failed to start WebSockets server'));
106
+ }
107
+ }, params.listen.unix);
108
+ }
109
+ else if (typeof params.listen.port === 'number') {
110
+ const proto = params.tls ? 'https' : 'http';
111
+ const hostname = params.listen.hostname || '127.0.0.1';
112
+ server.listen(hostname, params.listen.port, (socket) => {
113
+ if (socket) {
114
+ resolve(`${proto}://${hostname}:${us_socket_local_port(socket)}`);
115
+ }
116
+ else {
117
+ reject(new Error('Failed to start WebSockets server'));
118
+ }
119
+ });
120
+ }
121
+ else {
122
+ reject(new Error('Invalid listen parameters'));
123
+ }
124
+ }),
125
+ stop: () => {
126
+ server.close();
127
+ },
128
+ };
129
+ }
130
+ export const HttpTransport = {
131
+ proxyable: ProxyableTransportType.HTTP,
132
+ injectables,
133
+ factory(options) {
134
+ return createHTTPTransportWorker(adapterFactory, options);
135
+ },
136
+ };