123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538 |
- "use strict";
- // Licensed to the .NET Foundation under one or more agreements.
- // The .NET Foundation licenses this file to you under the MIT license.
- Object.defineProperty(exports, "__esModule", { value: true });
- exports.TransportSendQueue = exports.HttpConnection = void 0;
- const AccessTokenHttpClient_1 = require("./AccessTokenHttpClient");
- const DefaultHttpClient_1 = require("./DefaultHttpClient");
- const Errors_1 = require("./Errors");
- const ILogger_1 = require("./ILogger");
- const ITransport_1 = require("./ITransport");
- const LongPollingTransport_1 = require("./LongPollingTransport");
- const ServerSentEventsTransport_1 = require("./ServerSentEventsTransport");
- const Utils_1 = require("./Utils");
- const WebSocketTransport_1 = require("./WebSocketTransport");
- const MAX_REDIRECTS = 100;
- /** @private */
- class HttpConnection {
- constructor(url, options = {}) {
- this._stopPromiseResolver = () => { };
- this.features = {};
- this._negotiateVersion = 1;
- Utils_1.Arg.isRequired(url, "url");
- this._logger = Utils_1.createLogger(options.logger);
- this.baseUrl = this._resolveUrl(url);
- options = options || {};
- options.logMessageContent = options.logMessageContent === undefined ? false : options.logMessageContent;
- if (typeof options.withCredentials === "boolean" || options.withCredentials === undefined) {
- options.withCredentials = options.withCredentials === undefined ? true : options.withCredentials;
- }
- else {
- throw new Error("withCredentials option was not a 'boolean' or 'undefined' value");
- }
- options.timeout = options.timeout === undefined ? 100 * 1000 : options.timeout;
- let webSocketModule = null;
- let eventSourceModule = null;
- if (Utils_1.Platform.isNode && typeof require !== "undefined") {
- // In order to ignore the dynamic require in webpack builds we need to do this magic
- // @ts-ignore: TS doesn't know about these names
- const requireFunc = typeof __webpack_require__ === "function" ? __non_webpack_require__ : require;
- webSocketModule = requireFunc("ws");
- eventSourceModule = requireFunc("eventsource");
- }
- if (!Utils_1.Platform.isNode && typeof WebSocket !== "undefined" && !options.WebSocket) {
- options.WebSocket = WebSocket;
- }
- else if (Utils_1.Platform.isNode && !options.WebSocket) {
- if (webSocketModule) {
- options.WebSocket = webSocketModule;
- }
- }
- if (!Utils_1.Platform.isNode && typeof EventSource !== "undefined" && !options.EventSource) {
- options.EventSource = EventSource;
- }
- else if (Utils_1.Platform.isNode && !options.EventSource) {
- if (typeof eventSourceModule !== "undefined") {
- options.EventSource = eventSourceModule;
- }
- }
- this._httpClient = new AccessTokenHttpClient_1.AccessTokenHttpClient(options.httpClient || new DefaultHttpClient_1.DefaultHttpClient(this._logger), options.accessTokenFactory);
- this._connectionState = "Disconnected" /* Disconnected */;
- this._connectionStarted = false;
- this._options = options;
- this.onreceive = null;
- this.onclose = null;
- }
- async start(transferFormat) {
- transferFormat = transferFormat || ITransport_1.TransferFormat.Binary;
- Utils_1.Arg.isIn(transferFormat, ITransport_1.TransferFormat, "transferFormat");
- this._logger.log(ILogger_1.LogLevel.Debug, `Starting connection with transfer format '${ITransport_1.TransferFormat[transferFormat]}'.`);
- if (this._connectionState !== "Disconnected" /* Disconnected */) {
- return Promise.reject(new Error("Cannot start an HttpConnection that is not in the 'Disconnected' state."));
- }
- this._connectionState = "Connecting" /* Connecting */;
- this._startInternalPromise = this._startInternal(transferFormat);
- await this._startInternalPromise;
- // The TypeScript compiler thinks that connectionState must be Connecting here. The TypeScript compiler is wrong.
- if (this._connectionState === "Disconnecting" /* Disconnecting */) {
- // stop() was called and transitioned the client into the Disconnecting state.
- const message = "Failed to start the HttpConnection before stop() was called.";
- this._logger.log(ILogger_1.LogLevel.Error, message);
- // We cannot await stopPromise inside startInternal since stopInternal awaits the startInternalPromise.
- await this._stopPromise;
- return Promise.reject(new Errors_1.AbortError(message));
- }
- else if (this._connectionState !== "Connected" /* Connected */) {
- // stop() was called and transitioned the client into the Disconnecting state.
- const message = "HttpConnection.startInternal completed gracefully but didn't enter the connection into the connected state!";
- this._logger.log(ILogger_1.LogLevel.Error, message);
- return Promise.reject(new Errors_1.AbortError(message));
- }
- this._connectionStarted = true;
- }
- send(data) {
- if (this._connectionState !== "Connected" /* Connected */) {
- return Promise.reject(new Error("Cannot send data if the connection is not in the 'Connected' State."));
- }
- if (!this._sendQueue) {
- this._sendQueue = new TransportSendQueue(this.transport);
- }
- // Transport will not be null if state is connected
- return this._sendQueue.send(data);
- }
- async stop(error) {
- if (this._connectionState === "Disconnected" /* Disconnected */) {
- this._logger.log(ILogger_1.LogLevel.Debug, `Call to HttpConnection.stop(${error}) ignored because the connection is already in the disconnected state.`);
- return Promise.resolve();
- }
- if (this._connectionState === "Disconnecting" /* Disconnecting */) {
- this._logger.log(ILogger_1.LogLevel.Debug, `Call to HttpConnection.stop(${error}) ignored because the connection is already in the disconnecting state.`);
- return this._stopPromise;
- }
- this._connectionState = "Disconnecting" /* Disconnecting */;
- this._stopPromise = new Promise((resolve) => {
- // Don't complete stop() until stopConnection() completes.
- this._stopPromiseResolver = resolve;
- });
- // stopInternal should never throw so just observe it.
- await this._stopInternal(error);
- await this._stopPromise;
- }
- async _stopInternal(error) {
- // Set error as soon as possible otherwise there is a race between
- // the transport closing and providing an error and the error from a close message
- // We would prefer the close message error.
- this._stopError = error;
- try {
- await this._startInternalPromise;
- }
- catch (e) {
- // This exception is returned to the user as a rejected Promise from the start method.
- }
- // The transport's onclose will trigger stopConnection which will run our onclose event.
- // The transport should always be set if currently connected. If it wasn't set, it's likely because
- // stop was called during start() and start() failed.
- if (this.transport) {
- try {
- await this.transport.stop();
- }
- catch (e) {
- this._logger.log(ILogger_1.LogLevel.Error, `HttpConnection.transport.stop() threw error '${e}'.`);
- this._stopConnection();
- }
- this.transport = undefined;
- }
- else {
- this._logger.log(ILogger_1.LogLevel.Debug, "HttpConnection.transport is undefined in HttpConnection.stop() because start() failed.");
- }
- }
- async _startInternal(transferFormat) {
- // Store the original base url and the access token factory since they may change
- // as part of negotiating
- let url = this.baseUrl;
- this._accessTokenFactory = this._options.accessTokenFactory;
- this._httpClient._accessTokenFactory = this._accessTokenFactory;
- try {
- if (this._options.skipNegotiation) {
- if (this._options.transport === ITransport_1.HttpTransportType.WebSockets) {
- // No need to add a connection ID in this case
- this.transport = this._constructTransport(ITransport_1.HttpTransportType.WebSockets);
- // We should just call connect directly in this case.
- // No fallback or negotiate in this case.
- await this._startTransport(url, transferFormat);
- }
- else {
- throw new Error("Negotiation can only be skipped when using the WebSocket transport directly.");
- }
- }
- else {
- let negotiateResponse = null;
- let redirects = 0;
- do {
- negotiateResponse = await this._getNegotiationResponse(url);
- // the user tries to stop the connection when it is being started
- if (this._connectionState === "Disconnecting" /* Disconnecting */ || this._connectionState === "Disconnected" /* Disconnected */) {
- throw new Errors_1.AbortError("The connection was stopped during negotiation.");
- }
- if (negotiateResponse.error) {
- throw new Error(negotiateResponse.error);
- }
- if (negotiateResponse.ProtocolVersion) {
- throw new Error("Detected a connection attempt to an ASP.NET SignalR Server. This client only supports connecting to an ASP.NET Core SignalR Server. See https://aka.ms/signalr-core-differences for details.");
- }
- if (negotiateResponse.url) {
- url = negotiateResponse.url;
- }
- if (negotiateResponse.accessToken) {
- // Replace the current access token factory with one that uses
- // the returned access token
- const accessToken = negotiateResponse.accessToken;
- this._accessTokenFactory = () => accessToken;
- // set the factory to undefined so the AccessTokenHttpClient won't retry with the same token, since we know it won't change until a connection restart
- this._httpClient._accessToken = accessToken;
- this._httpClient._accessTokenFactory = undefined;
- }
- redirects++;
- } while (negotiateResponse.url && redirects < MAX_REDIRECTS);
- if (redirects === MAX_REDIRECTS && negotiateResponse.url) {
- throw new Error("Negotiate redirection limit exceeded.");
- }
- await this._createTransport(url, this._options.transport, negotiateResponse, transferFormat);
- }
- if (this.transport instanceof LongPollingTransport_1.LongPollingTransport) {
- this.features.inherentKeepAlive = true;
- }
- if (this._connectionState === "Connecting" /* Connecting */) {
- // Ensure the connection transitions to the connected state prior to completing this.startInternalPromise.
- // start() will handle the case when stop was called and startInternal exits still in the disconnecting state.
- this._logger.log(ILogger_1.LogLevel.Debug, "The HttpConnection connected successfully.");
- this._connectionState = "Connected" /* Connected */;
- }
- // stop() is waiting on us via this.startInternalPromise so keep this.transport around so it can clean up.
- // This is the only case startInternal can exit in neither the connected nor disconnected state because stopConnection()
- // will transition to the disconnected state. start() will wait for the transition using the stopPromise.
- }
- catch (e) {
- this._logger.log(ILogger_1.LogLevel.Error, "Failed to start the connection: " + e);
- this._connectionState = "Disconnected" /* Disconnected */;
- this.transport = undefined;
- // if start fails, any active calls to stop assume that start will complete the stop promise
- this._stopPromiseResolver();
- return Promise.reject(e);
- }
- }
- async _getNegotiationResponse(url) {
- const headers = {};
- const [name, value] = Utils_1.getUserAgentHeader();
- headers[name] = value;
- const negotiateUrl = this._resolveNegotiateUrl(url);
- this._logger.log(ILogger_1.LogLevel.Debug, `Sending negotiation request: ${negotiateUrl}.`);
- try {
- const response = await this._httpClient.post(negotiateUrl, {
- content: "",
- headers: { ...headers, ...this._options.headers },
- timeout: this._options.timeout,
- withCredentials: this._options.withCredentials,
- });
- if (response.statusCode !== 200) {
- return Promise.reject(new Error(`Unexpected status code returned from negotiate '${response.statusCode}'`));
- }
- const negotiateResponse = JSON.parse(response.content);
- if (!negotiateResponse.negotiateVersion || negotiateResponse.negotiateVersion < 1) {
- // Negotiate version 0 doesn't use connectionToken
- // So we set it equal to connectionId so all our logic can use connectionToken without being aware of the negotiate version
- negotiateResponse.connectionToken = negotiateResponse.connectionId;
- }
- return negotiateResponse;
- }
- catch (e) {
- let errorMessage = "Failed to complete negotiation with the server: " + e;
- if (e instanceof Errors_1.HttpError) {
- if (e.statusCode === 404) {
- errorMessage = errorMessage + " Either this is not a SignalR endpoint or there is a proxy blocking the connection.";
- }
- }
- this._logger.log(ILogger_1.LogLevel.Error, errorMessage);
- return Promise.reject(new Errors_1.FailedToNegotiateWithServerError(errorMessage));
- }
- }
- _createConnectUrl(url, connectionToken) {
- if (!connectionToken) {
- return url;
- }
- return url + (url.indexOf("?") === -1 ? "?" : "&") + `id=${connectionToken}`;
- }
- async _createTransport(url, requestedTransport, negotiateResponse, requestedTransferFormat) {
- let connectUrl = this._createConnectUrl(url, negotiateResponse.connectionToken);
- if (this._isITransport(requestedTransport)) {
- this._logger.log(ILogger_1.LogLevel.Debug, "Connection was provided an instance of ITransport, using that directly.");
- this.transport = requestedTransport;
- await this._startTransport(connectUrl, requestedTransferFormat);
- this.connectionId = negotiateResponse.connectionId;
- return;
- }
- const transportExceptions = [];
- const transports = negotiateResponse.availableTransports || [];
- let negotiate = negotiateResponse;
- for (const endpoint of transports) {
- const transportOrError = this._resolveTransportOrError(endpoint, requestedTransport, requestedTransferFormat);
- if (transportOrError instanceof Error) {
- // Store the error and continue, we don't want to cause a re-negotiate in these cases
- transportExceptions.push(`${endpoint.transport} failed:`);
- transportExceptions.push(transportOrError);
- }
- else if (this._isITransport(transportOrError)) {
- this.transport = transportOrError;
- if (!negotiate) {
- try {
- negotiate = await this._getNegotiationResponse(url);
- }
- catch (ex) {
- return Promise.reject(ex);
- }
- connectUrl = this._createConnectUrl(url, negotiate.connectionToken);
- }
- try {
- await this._startTransport(connectUrl, requestedTransferFormat);
- this.connectionId = negotiate.connectionId;
- return;
- }
- catch (ex) {
- this._logger.log(ILogger_1.LogLevel.Error, `Failed to start the transport '${endpoint.transport}': ${ex}`);
- negotiate = undefined;
- transportExceptions.push(new Errors_1.FailedToStartTransportError(`${endpoint.transport} failed: ${ex}`, ITransport_1.HttpTransportType[endpoint.transport]));
- if (this._connectionState !== "Connecting" /* Connecting */) {
- const message = "Failed to select transport before stop() was called.";
- this._logger.log(ILogger_1.LogLevel.Debug, message);
- return Promise.reject(new Errors_1.AbortError(message));
- }
- }
- }
- }
- if (transportExceptions.length > 0) {
- return Promise.reject(new Errors_1.AggregateErrors(`Unable to connect to the server with any of the available transports. ${transportExceptions.join(" ")}`, transportExceptions));
- }
- return Promise.reject(new Error("None of the transports supported by the client are supported by the server."));
- }
- _constructTransport(transport) {
- switch (transport) {
- case ITransport_1.HttpTransportType.WebSockets:
- if (!this._options.WebSocket) {
- throw new Error("'WebSocket' is not supported in your environment.");
- }
- return new WebSocketTransport_1.WebSocketTransport(this._httpClient, this._accessTokenFactory, this._logger, this._options.logMessageContent, this._options.WebSocket, this._options.headers || {});
- case ITransport_1.HttpTransportType.ServerSentEvents:
- if (!this._options.EventSource) {
- throw new Error("'EventSource' is not supported in your environment.");
- }
- return new ServerSentEventsTransport_1.ServerSentEventsTransport(this._httpClient, this._httpClient._accessToken, this._logger, this._options);
- case ITransport_1.HttpTransportType.LongPolling:
- return new LongPollingTransport_1.LongPollingTransport(this._httpClient, this._logger, this._options);
- default:
- throw new Error(`Unknown transport: ${transport}.`);
- }
- }
- _startTransport(url, transferFormat) {
- this.transport.onreceive = this.onreceive;
- this.transport.onclose = (e) => this._stopConnection(e);
- return this.transport.connect(url, transferFormat);
- }
- _resolveTransportOrError(endpoint, requestedTransport, requestedTransferFormat) {
- const transport = ITransport_1.HttpTransportType[endpoint.transport];
- if (transport === null || transport === undefined) {
- this._logger.log(ILogger_1.LogLevel.Debug, `Skipping transport '${endpoint.transport}' because it is not supported by this client.`);
- return new Error(`Skipping transport '${endpoint.transport}' because it is not supported by this client.`);
- }
- else {
- if (transportMatches(requestedTransport, transport)) {
- const transferFormats = endpoint.transferFormats.map((s) => ITransport_1.TransferFormat[s]);
- if (transferFormats.indexOf(requestedTransferFormat) >= 0) {
- if ((transport === ITransport_1.HttpTransportType.WebSockets && !this._options.WebSocket) ||
- (transport === ITransport_1.HttpTransportType.ServerSentEvents && !this._options.EventSource)) {
- this._logger.log(ILogger_1.LogLevel.Debug, `Skipping transport '${ITransport_1.HttpTransportType[transport]}' because it is not supported in your environment.'`);
- return new Errors_1.UnsupportedTransportError(`'${ITransport_1.HttpTransportType[transport]}' is not supported in your environment.`, transport);
- }
- else {
- this._logger.log(ILogger_1.LogLevel.Debug, `Selecting transport '${ITransport_1.HttpTransportType[transport]}'.`);
- try {
- return this._constructTransport(transport);
- }
- catch (ex) {
- return ex;
- }
- }
- }
- else {
- this._logger.log(ILogger_1.LogLevel.Debug, `Skipping transport '${ITransport_1.HttpTransportType[transport]}' because it does not support the requested transfer format '${ITransport_1.TransferFormat[requestedTransferFormat]}'.`);
- return new Error(`'${ITransport_1.HttpTransportType[transport]}' does not support ${ITransport_1.TransferFormat[requestedTransferFormat]}.`);
- }
- }
- else {
- this._logger.log(ILogger_1.LogLevel.Debug, `Skipping transport '${ITransport_1.HttpTransportType[transport]}' because it was disabled by the client.`);
- return new Errors_1.DisabledTransportError(`'${ITransport_1.HttpTransportType[transport]}' is disabled by the client.`, transport);
- }
- }
- }
- _isITransport(transport) {
- return transport && typeof (transport) === "object" && "connect" in transport;
- }
- _stopConnection(error) {
- this._logger.log(ILogger_1.LogLevel.Debug, `HttpConnection.stopConnection(${error}) called while in state ${this._connectionState}.`);
- this.transport = undefined;
- // If we have a stopError, it takes precedence over the error from the transport
- error = this._stopError || error;
- this._stopError = undefined;
- if (this._connectionState === "Disconnected" /* Disconnected */) {
- this._logger.log(ILogger_1.LogLevel.Debug, `Call to HttpConnection.stopConnection(${error}) was ignored because the connection is already in the disconnected state.`);
- return;
- }
- if (this._connectionState === "Connecting" /* Connecting */) {
- this._logger.log(ILogger_1.LogLevel.Warning, `Call to HttpConnection.stopConnection(${error}) was ignored because the connection is still in the connecting state.`);
- throw new Error(`HttpConnection.stopConnection(${error}) was called while the connection is still in the connecting state.`);
- }
- if (this._connectionState === "Disconnecting" /* Disconnecting */) {
- // A call to stop() induced this call to stopConnection and needs to be completed.
- // Any stop() awaiters will be scheduled to continue after the onclose callback fires.
- this._stopPromiseResolver();
- }
- if (error) {
- this._logger.log(ILogger_1.LogLevel.Error, `Connection disconnected with error '${error}'.`);
- }
- else {
- this._logger.log(ILogger_1.LogLevel.Information, "Connection disconnected.");
- }
- if (this._sendQueue) {
- this._sendQueue.stop().catch((e) => {
- this._logger.log(ILogger_1.LogLevel.Error, `TransportSendQueue.stop() threw error '${e}'.`);
- });
- this._sendQueue = undefined;
- }
- this.connectionId = undefined;
- this._connectionState = "Disconnected" /* Disconnected */;
- if (this._connectionStarted) {
- this._connectionStarted = false;
- try {
- if (this.onclose) {
- this.onclose(error);
- }
- }
- catch (e) {
- this._logger.log(ILogger_1.LogLevel.Error, `HttpConnection.onclose(${error}) threw error '${e}'.`);
- }
- }
- }
- _resolveUrl(url) {
- // startsWith is not supported in IE
- if (url.lastIndexOf("https://", 0) === 0 || url.lastIndexOf("http://", 0) === 0) {
- return url;
- }
- if (!Utils_1.Platform.isBrowser) {
- throw new Error(`Cannot resolve '${url}'.`);
- }
- // Setting the url to the href propery of an anchor tag handles normalization
- // for us. There are 3 main cases.
- // 1. Relative path normalization e.g "b" -> "http://localhost:5000/a/b"
- // 2. Absolute path normalization e.g "/a/b" -> "http://localhost:5000/a/b"
- // 3. Networkpath reference normalization e.g "//localhost:5000/a/b" -> "http://localhost:5000/a/b"
- const aTag = window.document.createElement("a");
- aTag.href = url;
- this._logger.log(ILogger_1.LogLevel.Information, `Normalizing '${url}' to '${aTag.href}'.`);
- return aTag.href;
- }
- _resolveNegotiateUrl(url) {
- const index = url.indexOf("?");
- let negotiateUrl = url.substring(0, index === -1 ? url.length : index);
- if (negotiateUrl[negotiateUrl.length - 1] !== "/") {
- negotiateUrl += "/";
- }
- negotiateUrl += "negotiate";
- negotiateUrl += index === -1 ? "" : url.substring(index);
- if (negotiateUrl.indexOf("negotiateVersion") === -1) {
- negotiateUrl += index === -1 ? "?" : "&";
- negotiateUrl += "negotiateVersion=" + this._negotiateVersion;
- }
- return negotiateUrl;
- }
- }
- exports.HttpConnection = HttpConnection;
- function transportMatches(requestedTransport, actualTransport) {
- return !requestedTransport || ((actualTransport & requestedTransport) !== 0);
- }
- /** @private */
- class TransportSendQueue {
- constructor(_transport) {
- this._transport = _transport;
- this._buffer = [];
- this._executing = true;
- this._sendBufferedData = new PromiseSource();
- this._transportResult = new PromiseSource();
- this._sendLoopPromise = this._sendLoop();
- }
- send(data) {
- this._bufferData(data);
- if (!this._transportResult) {
- this._transportResult = new PromiseSource();
- }
- return this._transportResult.promise;
- }
- stop() {
- this._executing = false;
- this._sendBufferedData.resolve();
- return this._sendLoopPromise;
- }
- _bufferData(data) {
- if (this._buffer.length && typeof (this._buffer[0]) !== typeof (data)) {
- throw new Error(`Expected data to be of type ${typeof (this._buffer)} but was of type ${typeof (data)}`);
- }
- this._buffer.push(data);
- this._sendBufferedData.resolve();
- }
- async _sendLoop() {
- while (true) {
- await this._sendBufferedData.promise;
- if (!this._executing) {
- if (this._transportResult) {
- this._transportResult.reject("Connection stopped.");
- }
- break;
- }
- this._sendBufferedData = new PromiseSource();
- const transportResult = this._transportResult;
- this._transportResult = undefined;
- const data = typeof (this._buffer[0]) === "string" ?
- this._buffer.join("") :
- TransportSendQueue._concatBuffers(this._buffer);
- this._buffer.length = 0;
- try {
- await this._transport.send(data);
- transportResult.resolve();
- }
- catch (error) {
- transportResult.reject(error);
- }
- }
- }
- static _concatBuffers(arrayBuffers) {
- const totalLength = arrayBuffers.map((b) => b.byteLength).reduce((a, b) => a + b);
- const result = new Uint8Array(totalLength);
- let offset = 0;
- for (const item of arrayBuffers) {
- result.set(new Uint8Array(item), offset);
- offset += item.byteLength;
- }
- return result.buffer;
- }
- }
- exports.TransportSendQueue = TransportSendQueue;
- class PromiseSource {
- constructor() {
- this.promise = new Promise((resolve, reject) => [this._resolver, this._rejecter] = [resolve, reject]);
- }
- resolve() {
- this._resolver();
- }
- reject(reason) {
- this._rejecter(reason);
- }
- }
- //# sourceMappingURL=HttpConnection.js.map
|