Estructura inicial del proyecto

This commit is contained in:
2026-06-02 16:57:08 +00:00
commit 8b306b9afc
9864 changed files with 1435687 additions and 0 deletions

View File

@ -0,0 +1,172 @@
/*! @azure/msal-node v5.2.2 2026-05-19 */
'use strict';
import { createAuthError, ClientAuthErrorCodes, createNetworkError } from '@azure/msal-common/node';
import { HttpMethod } from '../utils/Constants.mjs';
/*
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License.
*/
/**
* HTTP client implementation using Node.js native fetch API.
*
* This class provides a clean interface for making HTTP requests using the modern
* fetch API available in Node.js 18+. It replaces the previous implementation that
* relied on custom proxy handling and the legacy http/https modules.
*/
class HttpClient {
/**
* Sends an HTTP GET request to the specified URL.
*
* This method handles GET requests with optional timeout support. The timeout
* is implemented using AbortController, which provides a clean way to cancel
* fetch requests that take too long to complete.
*
* @param url - The target URL for the GET request
* @param options - Optional request configuration including headers
* @param timeout - Optional timeout in milliseconds. If specified, the request
* will be aborted if it doesn't complete within this time
* @returns Promise that resolves to a NetworkResponse containing headers, body, and status
* @throws {AuthError} When the request times out or response parsing fails
* @throws {NetworkError} When the network request fails
*/
async sendGetRequestAsync(url, options, timeout) {
return this.sendRequest(url, HttpMethod.GET, options, timeout);
}
/**
* Sends an HTTP POST request to the specified URL.
*
* This method handles POST requests with request body support. Currently,
* timeout functionality is not exposed for POST requests, but the underlying
* implementation supports it through the shared sendRequest method.
*
* @param url - The target URL for the POST request
* @param options - Optional request configuration including headers and body
* @returns Promise that resolves to a NetworkResponse containing headers, body, and status
* @throws {AuthError} When the request times out or response parsing fails
* @throws {NetworkError} When the network request fails
*/
async sendPostRequestAsync(url, options) {
return this.sendRequest(url, HttpMethod.POST, options);
}
/**
* Core HTTP request implementation using native fetch API.
*
* This method handles GET and POST HTTP requests with comprehensive
* timeout support and error handling. The timeout mechanism works as follows:
*
* 1. An AbortController is created for each request
* 2. If a timeout is specified, setTimeout is used to call abort() after the delay
* 3. The abort signal is passed to fetch, which will reject the promise if aborted
* 4. Cleanup occurs in both success and error cases to prevent timer leaks
*
* Error handling priority:
* 1. Timeout errors (AbortError) are converted to "Request timeout" messages
* 2. Network/connection errors are wrapped with "Network request failed" prefix
* 3. JSON parsing errors are wrapped with "Failed to parse response" prefix
*
* @param url - The target URL for the request
* @param method - HTTP method (GET or POST)
* @param options - Optional request configuration (headers, body)
* @param timeout - Optional timeout in milliseconds for request cancellation
* @returns Promise resolving to NetworkResponse with parsed JSON body
* @throws {AuthError} For timeouts or JSON parsing errors
* @throws {NetworkError} For network failures
*/
async sendRequest(url, method, options, timeout) {
/*
* Setup timeout mechanism using AbortController
* This provides a standard way to cancel fetch requests
*/
const controller = new AbortController();
let timeoutId;
/*
* Configure timeout if specified
* The setTimeout will trigger abort() if the request takes too long
*/
if (timeout) {
timeoutId = setTimeout(() => {
// Calling abort() will cause fetch to reject with AbortError
controller.abort();
}, timeout);
}
const fetchOptions = {
method: method,
headers: getFetchHeaders(options),
signal: controller.signal, // Enable cancellation via AbortController
};
if (method === HttpMethod.POST) {
fetchOptions.body = options?.body || "";
}
let response;
try {
response = await fetch(url, fetchOptions);
}
catch (error) {
// Clean up timeout to prevent memory leaks
if (timeoutId) {
clearTimeout(timeoutId);
}
if (error instanceof Error && error.name === "AbortError") {
throw createAuthError(ClientAuthErrorCodes.networkError, "Request timeout");
}
const baseAuthError = createAuthError(ClientAuthErrorCodes.networkError, `Network request failed: ${error instanceof Error ? error.message : "unknown"}`);
throw createNetworkError(baseAuthError, undefined, undefined, error instanceof Error ? error : undefined);
}
// Clean up timeout to prevent memory leaks
if (timeoutId) {
clearTimeout(timeoutId);
}
try {
return {
headers: getHeaderDict(response.headers),
body: (await response.json()),
status: response.status,
};
}
catch (error) {
throw createAuthError(ClientAuthErrorCodes.tokenParsingError, `Failed to parse response: ${error instanceof Error ? error.message : "unknown"}`);
}
}
}
/**
* Converts a fetch Headers object to a plain JavaScript object.
*
* The fetch API returns headers as a Headers object with methods like get(), has(),
* etc. However, the rest of the MSAL codebase expects headers as a simple key-value
* object. This function performs that conversion.
*
* @param headers - The Headers object returned by fetch response
* @returns A plain object with header names as keys and values as strings
*/
function getHeaderDict(headers) {
const headerDict = {};
headers.forEach((value, key) => {
headerDict[key] = value;
});
return headerDict;
}
/**
* Converts NetworkRequestOptions headers to a fetch-compatible Headers object.
*
* The MSAL library uses plain objects for headers in NetworkRequestOptions,
* but the fetch API expects either a Headers object, plain object, or array
* of arrays. Using the Headers constructor provides better compatibility
* and validation.
*
* @param options - Optional NetworkRequestOptions containing headers
* @returns A Headers object ready for use with fetch API
*/
function getFetchHeaders(options) {
const headers = new Headers();
if (!(options && options.headers)) {
return headers;
}
Object.entries(options.headers).forEach(([key, value]) => {
headers.append(key, value);
});
return headers;
}
export { HttpClient };
//# sourceMappingURL=HttpClient.mjs.map

View File

@ -0,0 +1 @@
{"version":3,"file":"HttpClient.mjs","sources":["../../src/network/HttpClient.ts"],"sourcesContent":[null],"names":[],"mappings":"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"}

View File

@ -0,0 +1,46 @@
/*! @azure/msal-node v5.2.2 2026-05-19 */
'use strict';
import { Constants } from '@azure/msal-common/node';
import { HttpMethod } from '../utils/Constants.mjs';
/*
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License.
*/
class HttpClientWithRetries {
constructor(httpClientNoRetries, retryPolicy, logger) {
this.httpClientNoRetries = httpClientNoRetries;
this.retryPolicy = retryPolicy;
this.logger = logger;
}
async sendNetworkRequestAsyncHelper(httpMethod, url, options) {
if (httpMethod === HttpMethod.GET) {
return this.httpClientNoRetries.sendGetRequestAsync(url, options);
}
else {
return this.httpClientNoRetries.sendPostRequestAsync(url, options);
}
}
async sendNetworkRequestAsync(httpMethod, url, options) {
// the underlying network module (custom or HttpClient) will make the call
let response = await this.sendNetworkRequestAsyncHelper(httpMethod, url, options);
if ("isNewRequest" in this.retryPolicy) {
this.retryPolicy.isNewRequest = true;
}
let currentRetry = 0;
while (await this.retryPolicy.pauseForRetry(response.status, currentRetry, this.logger, response.headers[Constants.HeaderNames.RETRY_AFTER])) {
response = await this.sendNetworkRequestAsyncHelper(httpMethod, url, options);
currentRetry++;
}
return response;
}
async sendGetRequestAsync(url, options) {
return this.sendNetworkRequestAsync(HttpMethod.GET, url, options);
}
async sendPostRequestAsync(url, options) {
return this.sendNetworkRequestAsync(HttpMethod.POST, url, options);
}
}
export { HttpClientWithRetries };
//# sourceMappingURL=HttpClientWithRetries.mjs.map

View File

@ -0,0 +1 @@
{"version":3,"file":"HttpClientWithRetries.mjs","sources":["../../src/network/HttpClientWithRetries.ts"],"sourcesContent":[null],"names":[],"mappings":";;;;;AAAA;;;AAGG;MAYU,qBAAqB,CAAA;AAK9B,IAAA,WAAA,CACI,mBAAmC,EACnC,WAA6B,EAC7B,MAAc,EAAA;AAEd,QAAA,IAAI,CAAC,mBAAmB,GAAG,mBAAmB,CAAC;AAC/C,QAAA,IAAI,CAAC,WAAW,GAAG,WAAW,CAAC;AAC/B,QAAA,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;KACxB;AAEO,IAAA,MAAM,6BAA6B,CACvC,UAAsB,EACtB,GAAW,EACX,OAA+B,EAAA;AAE/B,QAAA,IAAI,UAAU,KAAK,UAAU,CAAC,GAAG,EAAE;YAC/B,OAAO,IAAI,CAAC,mBAAmB,CAAC,mBAAmB,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;AACrE,SAAA;AAAM,aAAA;YACH,OAAO,IAAI,CAAC,mBAAmB,CAAC,oBAAoB,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;AACtE,SAAA;KACJ;AAEO,IAAA,MAAM,uBAAuB,CACjC,UAAsB,EACtB,GAAW,EACX,OAA+B,EAAA;;AAG/B,QAAA,IAAI,QAAQ,GACR,MAAM,IAAI,CAAC,6BAA6B,CAAC,UAAU,EAAE,GAAG,EAAE,OAAO,CAAC,CAAC;AAEvE,QAAA,IAAI,cAAc,IAAI,IAAI,CAAC,WAAW,EAAE;AACpC,YAAA,IAAI,CAAC,WAAW,CAAC,YAAY,GAAG,IAAI,CAAC;AACxC,SAAA;QAED,IAAI,YAAY,GAAW,CAAC,CAAC;AAC7B,QAAA,OACI,MAAM,IAAI,CAAC,WAAW,CAAC,aAAa,CAChC,QAAQ,CAAC,MAAM,EACf,YAAY,EACZ,IAAI,CAAC,MAAM,EACX,QAAQ,CAAC,OAAO,CAAC,SAAS,CAAC,WAAW,CAAC,WAAW,CAAC,CACtD,EACH;AACE,YAAA,QAAQ,GAAG,MAAM,IAAI,CAAC,6BAA6B,CAC/C,UAAU,EACV,GAAG,EACH,OAAO,CACV,CAAC;AACF,YAAA,YAAY,EAAE,CAAC;AAClB,SAAA;AAED,QAAA,OAAO,QAAQ,CAAC;KACnB;AAEM,IAAA,MAAM,mBAAmB,CAC5B,GAAW,EACX,OAA+B,EAAA;AAE/B,QAAA,OAAO,IAAI,CAAC,uBAAuB,CAAC,UAAU,CAAC,GAAG,EAAE,GAAG,EAAE,OAAO,CAAC,CAAC;KACrE;AAEM,IAAA,MAAM,oBAAoB,CAC7B,GAAW,EACX,OAA+B,EAAA;AAE/B,QAAA,OAAO,IAAI,CAAC,uBAAuB,CAAC,UAAU,CAAC,IAAI,EAAE,GAAG,EAAE,OAAO,CAAC,CAAC;KACtE;AACJ;;;;"}

View File

@ -0,0 +1,92 @@
/*! @azure/msal-node v5.2.2 2026-05-19 */
'use strict';
import { Constants, UrlUtils } from '@azure/msal-common/node';
import http from 'http';
import { NodeAuthError } from '../error/NodeAuthError.mjs';
import { Constants as Constants$1 } from '../utils/Constants.mjs';
/*
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License.
*/
class LoopbackClient {
/**
* Spins up a loopback server which returns the server response when the localhost redirectUri is hit
* @param successTemplate
* @param errorTemplate
* @returns
*/
async listenForAuthCode(successTemplate, errorTemplate) {
if (this.server) {
throw NodeAuthError.createLoopbackServerAlreadyExistsError();
}
return new Promise((resolve, reject) => {
this.server = http.createServer((req, res) => {
const url = req.url;
if (!url) {
res.end(errorTemplate ||
"Error occurred loading redirectUrl");
reject(NodeAuthError.createUnableToLoadRedirectUrlError());
return;
}
else if (url === Constants.FORWARD_SLASH) {
res.end(successTemplate ||
"Auth code was successfully acquired. You can close this window now.");
return;
}
const redirectUri = this.getRedirectUri();
const parsedUrl = new URL(url, redirectUri);
const authCodeResponse = UrlUtils.getDeserializedResponse(parsedUrl.search) ||
{};
if (authCodeResponse.code) {
res.writeHead(Constants.HTTP_REDIRECT, {
location: redirectUri,
}); // Prevent auth code from being saved in the browser history
res.end();
}
if (authCodeResponse.error) {
res.end(errorTemplate ||
`Error occurred: ${authCodeResponse.error}`);
}
resolve(authCodeResponse);
});
this.server.listen(0, "127.0.0.1"); // Listen on any available port
});
}
/**
* Get the port that the loopback server is running on
* @returns
*/
getRedirectUri() {
if (!this.server || !this.server.listening) {
throw NodeAuthError.createNoLoopbackServerExistsError();
}
const address = this.server.address();
if (!address || typeof address === "string" || !address.port) {
this.closeServer();
throw NodeAuthError.createInvalidLoopbackAddressTypeError();
}
const port = address && address.port;
return `${Constants$1.HTTP_PROTOCOL}${Constants$1.LOCALHOST}:${port}`;
}
/**
* Close the loopback server
*/
closeServer() {
if (this.server) {
// Only stops accepting new connections, server will close once open/idle connections are closed.
this.server.close();
if (typeof this.server.closeAllConnections === "function") {
/*
* Close open/idle connections. This API is available in Node versions 18.2 and higher
*/
this.server.closeAllConnections();
}
this.server.unref();
this.server = undefined;
}
}
}
export { LoopbackClient };
//# sourceMappingURL=LoopbackClient.mjs.map

View File

@ -0,0 +1 @@
{"version":3,"file":"LoopbackClient.mjs","sources":["../../src/network/LoopbackClient.ts"],"sourcesContent":[null],"names":["CommonConstants","Constants"],"mappings":";;;;;;;AAAA;;;AAGG;MAYU,cAAc,CAAA;AAGvB;;;;;AAKG;AACH,IAAA,MAAM,iBAAiB,CACnB,eAAwB,EACxB,aAAsB,EAAA;QAEtB,IAAI,IAAI,CAAC,MAAM,EAAE;AACb,YAAA,MAAM,aAAa,CAAC,sCAAsC,EAAE,CAAC;AAChE,SAAA;QAED,OAAO,IAAI,OAAO,CAAoB,CAAC,OAAO,EAAE,MAAM,KAAI;AACtD,YAAA,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,YAAY,CAC3B,CAAC,GAAyB,EAAE,GAAwB,KAAI;AACpD,gBAAA,MAAM,GAAG,GAAG,GAAG,CAAC,GAAG,CAAC;gBACpB,IAAI,CAAC,GAAG,EAAE;oBACN,GAAG,CAAC,GAAG,CACH,aAAa;AACT,wBAAA,oCAAoC,CAC3C,CAAC;AACF,oBAAA,MAAM,CACF,aAAa,CAAC,kCAAkC,EAAE,CACrD,CAAC;oBACF,OAAO;AACV,iBAAA;AAAM,qBAAA,IAAI,GAAG,KAAKA,SAAe,CAAC,aAAa,EAAE;oBAC9C,GAAG,CAAC,GAAG,CACH,eAAe;AACX,wBAAA,qEAAqE,CAC5E,CAAC;oBACF,OAAO;AACV,iBAAA;AAED,gBAAA,MAAM,WAAW,GAAG,IAAI,CAAC,cAAc,EAAE,CAAC;gBAC1C,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC;gBAC5C,MAAM,gBAAgB,GAClB,QAAQ,CAAC,uBAAuB,CAAC,SAAS,CAAC,MAAM,CAAC;AAClD,oBAAA,EAAE,CAAC;gBACP,IAAI,gBAAgB,CAAC,IAAI,EAAE;AACvB,oBAAA,GAAG,CAAC,SAAS,CAACA,SAAe,CAAC,aAAa,EAAE;AACzC,wBAAA,QAAQ,EAAE,WAAW;qBACxB,CAAC,CAAC;oBACH,GAAG,CAAC,GAAG,EAAE,CAAC;AACb,iBAAA;gBACD,IAAI,gBAAgB,CAAC,KAAK,EAAE;oBACxB,GAAG,CAAC,GAAG,CACH,aAAa;AACT,wBAAA,CAAA,gBAAA,EAAmB,gBAAgB,CAAC,KAAK,CAAA,CAAE,CAClD,CAAC;AACL,iBAAA;gBACD,OAAO,CAAC,gBAAgB,CAAC,CAAC;AAC9B,aAAC,CACJ,CAAC;YACF,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,WAAW,CAAC,CAAC;AACvC,SAAC,CAAC,CAAC;KACN;AAED;;;AAGG;IACH,cAAc,GAAA;QACV,IAAI,CAAC,IAAI,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE;AACxC,YAAA,MAAM,aAAa,CAAC,iCAAiC,EAAE,CAAC;AAC3D,SAAA;QAED,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;AACtC,QAAA,IAAI,CAAC,OAAO,IAAI,OAAO,OAAO,KAAK,QAAQ,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE;YAC1D,IAAI,CAAC,WAAW,EAAE,CAAC;AACnB,YAAA,MAAM,aAAa,CAAC,qCAAqC,EAAE,CAAC;AAC/D,SAAA;AAED,QAAA,MAAM,IAAI,GAAG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;QAErC,OAAO,CAAA,EAAGC,WAAS,CAAC,aAAa,CAAA,EAAGA,WAAS,CAAC,SAAS,CAAA,CAAA,EAAI,IAAI,CAAA,CAAE,CAAC;KACrE;AAED;;AAEG;IACH,WAAW,GAAA;QACP,IAAI,IAAI,CAAC,MAAM,EAAE;;AAEb,YAAA,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;YAEpB,IAAI,OAAO,IAAI,CAAC,MAAM,CAAC,mBAAmB,KAAK,UAAU,EAAE;AACvD;;AAEG;AACH,gBAAA,IAAI,CAAC,MAAM,CAAC,mBAAmB,EAAE,CAAC;AACrC,aAAA;AACD,YAAA,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;AACpB,YAAA,IAAI,CAAC,MAAM,GAAG,SAAS,CAAC;AAC3B,SAAA;KACJ;AACJ;;;;"}