Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@microsoft/kiota-http-fetchlibrary

Package Overview
Dependencies
Maintainers
2
Versions
74
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@microsoft/kiota-http-fetchlibrary - npm Package Compare versions

Comparing version 1.0.0-preview.8 to 1.0.0-preview.9

dist/cjs/src/observabilityOptions.d.ts

11

dist/cjs/src/fetchRequestAdapter.d.ts
import { AuthenticationProvider, BackingStoreFactory, Parsable, ParsableFactory, ParseNodeFactory, RequestAdapter, RequestInformation, ResponseHandler, SerializationWriterFactory } from "@microsoft/kiota-abstractions";
import { HttpClient } from "./httpClient";
import { ObservabilityOptions } from "./observabilityOptions";
export declare class FetchRequestAdapter implements RequestAdapter {

@@ -11,2 +12,3 @@ readonly authenticationProvider: AuthenticationProvider;

getSerializationWriterFactory(): SerializationWriterFactory;
private readonly observabilityOptions;
/**

@@ -18,7 +20,11 @@ * Instantiates a new http core service

* @param httpClient the http client to use to execute requests.
* @param observabilityOptions the observability options to use.
*/
constructor(authenticationProvider: AuthenticationProvider, parseNodeFactory?: ParseNodeFactory, serializationWriterFactory?: SerializationWriterFactory, httpClient?: HttpClient);
constructor(authenticationProvider: AuthenticationProvider, parseNodeFactory?: ParseNodeFactory, serializationWriterFactory?: SerializationWriterFactory, httpClient?: HttpClient, observabilityOptions?: ObservabilityOptions);
private getResponseContentType;
private static readonly responseTypeAttributeKey;
sendCollectionOfPrimitiveAsync: <ResponseType_1>(requestInfo: RequestInformation, responseType: "string" | "number" | "boolean" | "Date", responseHandler: ResponseHandler | undefined, errorMappings: Record<string, ParsableFactory<Parsable>> | undefined) => Promise<ResponseType_1[] | undefined>;
sendCollectionAsync: <ModelType extends Parsable>(requestInfo: RequestInformation, type: ParsableFactory<ModelType>, responseHandler: ResponseHandler | undefined, errorMappings: Record<string, ParsableFactory<Parsable>> | undefined) => Promise<ModelType[] | undefined>;
private startTracingSpan;
static readonly eventResponseHandlerInvokedKey = "com.microsoft.kiota.response_handler_invoked";
sendAsync: <ModelType extends Parsable>(requestInfo: RequestInformation, type: ParsableFactory<ModelType>, responseHandler: ResponseHandler | undefined, errorMappings: Record<string, ParsableFactory<Parsable>> | undefined) => Promise<ModelType | undefined>;

@@ -32,4 +38,7 @@ sendPrimitiveAsync: <ResponseType_1>(requestInfo: RequestInformation, responseType: "string" | "number" | "boolean" | "Date" | "ArrayBuffer", responseHandler: ResponseHandler | undefined, errorMappings: Record<string, ParsableFactory<Parsable>> | undefined) => Promise<ResponseType_1 | undefined>;

private purgeResponseBody;
static readonly errorMappingFoundAttributeName = "com.microsoft.kiota.error.mapping_found";
static readonly errorBodyFoundAttributeName = "com.microsoft.kiota.error.body_found";
private throwFailedResponses;
private getHttpResponseMessage;
static readonly authenticateChallengedEventKey = "com.microsoft.kiota.authenticate_challenge_received";
private retryCAEResponseIfRequired;

@@ -36,0 +45,0 @@ private getClaimsFromResponse;

565

dist/cjs/src/fetchRequestAdapter.js

@@ -6,4 +6,9 @@ "use strict";

const kiota_abstractions_1 = require("@microsoft/kiota-abstractions");
const api_1 = require("@opentelemetry/api");
const httpClient_1 = require("./httpClient");
const observabilityOptions_1 = require("./observabilityOptions");
class FetchRequestAdapter {
getSerializationWriterFactory() {
return this.serializationWriterFactory;
}
/**

@@ -15,4 +20,5 @@ * Instantiates a new http core service

* @param httpClient the http client to use to execute requests.
* @param observabilityOptions the observability options to use.
*/
constructor(authenticationProvider, parseNodeFactory = kiota_abstractions_1.ParseNodeFactoryRegistry.defaultInstance, serializationWriterFactory = kiota_abstractions_1.SerializationWriterFactoryRegistry.defaultInstance, httpClient = new httpClient_1.HttpClient()) {
constructor(authenticationProvider, parseNodeFactory = kiota_abstractions_1.ParseNodeFactoryRegistry.defaultInstance, serializationWriterFactory = kiota_abstractions_1.SerializationWriterFactoryRegistry.defaultInstance, httpClient = new httpClient_1.HttpClient(), observabilityOptions = new observabilityOptions_1.ObservabilityOptionsImpl()) {
this.authenticationProvider = authenticationProvider;

@@ -35,169 +41,255 @@ this.parseNodeFactory = parseNodeFactory;

};
this.sendCollectionOfPrimitiveAsync = (requestInfo, responseType, responseHandler, errorMappings) => tslib_1.__awaiter(this, void 0, void 0, function* () {
this.sendCollectionOfPrimitiveAsync = (requestInfo, responseType, responseHandler, errorMappings) => {
if (!requestInfo) {
throw new Error("requestInfo cannot be null");
}
const response = yield this.getHttpResponseMessage(requestInfo);
if (responseHandler) {
return yield responseHandler.handleResponseAsync(response, errorMappings);
}
else {
return this.startTracingSpan(requestInfo, "sendCollectionOfPrimitiveAsync", (span) => tslib_1.__awaiter(this, void 0, void 0, function* () {
try {
yield this.throwFailedResponses(response, errorMappings);
if (this.shouldReturnUndefined(response))
return undefined;
switch (responseType) {
case "string":
case "number":
case "boolean":
case "Date":
// eslint-disable-next-line no-case-declarations
const rootNode = yield this.getRootParseNode(response);
if (responseType === "string") {
return rootNode.getCollectionOfPrimitiveValues();
const response = yield this.getHttpResponseMessage(requestInfo, span);
if (responseHandler) {
span.addEvent(FetchRequestAdapter.eventResponseHandlerInvokedKey);
return yield responseHandler.handleResponseAsync(response, errorMappings);
}
else {
try {
yield this.throwFailedResponses(response, errorMappings, span);
if (this.shouldReturnUndefined(response))
return undefined;
switch (responseType) {
case "string":
case "number":
case "boolean":
case "Date":
// eslint-disable-next-line no-case-declarations
const rootNode = yield this.getRootParseNode(response);
return api_1.trace.getTracer(this.observabilityOptions.getTracerInstrumentationName()).startActiveSpan(`getCollectionOf${responseType}Value`, (deserializeSpan) => {
try {
span.setAttribute(FetchRequestAdapter.responseTypeAttributeKey, responseType);
if (responseType === "string") {
return rootNode.getCollectionOfPrimitiveValues();
}
else if (responseType === "number") {
return rootNode.getCollectionOfPrimitiveValues();
}
else if (responseType === "boolean") {
return rootNode.getCollectionOfPrimitiveValues();
}
else if (responseType === "Date") {
return rootNode.getCollectionOfPrimitiveValues();
}
else if (responseType === "Duration") {
return rootNode.getCollectionOfPrimitiveValues();
}
else if (responseType === "DateOnly") {
return rootNode.getCollectionOfPrimitiveValues();
}
else if (responseType === "TimeOnly") {
return rootNode.getCollectionOfPrimitiveValues();
}
else {
throw new Error("unexpected type to deserialize");
}
}
finally {
deserializeSpan.end();
}
});
}
else if (responseType === "number") {
return rootNode.getCollectionOfPrimitiveValues();
}
else if (responseType === "boolean") {
return rootNode.getCollectionOfPrimitiveValues();
}
else if (responseType === "Date") {
return rootNode.getCollectionOfPrimitiveValues();
}
else if (responseType === "Duration") {
return rootNode.getCollectionOfPrimitiveValues();
}
else if (responseType === "DateOnly") {
return rootNode.getCollectionOfPrimitiveValues();
}
else if (responseType === "TimeOnly") {
return rootNode.getCollectionOfPrimitiveValues();
}
else {
throw new Error("unexpected type to deserialize");
}
}
finally {
yield this.purgeResponseBody(response);
}
}
}
finally {
yield this.purgeResponseBody(response);
span.end();
}
}
});
this.sendCollectionAsync = (requestInfo, type, responseHandler, errorMappings) => tslib_1.__awaiter(this, void 0, void 0, function* () {
}));
};
this.sendCollectionAsync = (requestInfo, type, responseHandler, errorMappings) => {
if (!requestInfo) {
throw new Error("requestInfo cannot be null");
}
const response = yield this.getHttpResponseMessage(requestInfo);
if (responseHandler) {
return yield responseHandler.handleResponseAsync(response, errorMappings);
}
else {
return this.startTracingSpan(requestInfo, "sendCollectionAsync", (span) => tslib_1.__awaiter(this, void 0, void 0, function* () {
try {
yield this.throwFailedResponses(response, errorMappings);
if (this.shouldReturnUndefined(response))
return undefined;
const rootNode = yield this.getRootParseNode(response);
const result = rootNode.getCollectionOfObjectValues(type);
return result;
const response = yield this.getHttpResponseMessage(requestInfo, span);
if (responseHandler) {
span.addEvent(FetchRequestAdapter.eventResponseHandlerInvokedKey);
return yield responseHandler.handleResponseAsync(response, errorMappings);
}
else {
try {
yield this.throwFailedResponses(response, errorMappings, span);
if (this.shouldReturnUndefined(response))
return undefined;
const rootNode = yield this.getRootParseNode(response);
return api_1.trace.getTracer(this.observabilityOptions.getTracerInstrumentationName()).startActiveSpan("getCollectionOfObjectValues", (deserializeSpan) => {
try {
const result = rootNode.getCollectionOfObjectValues(type);
span.setAttribute(FetchRequestAdapter.responseTypeAttributeKey, "object[]");
return result;
}
finally {
deserializeSpan.end();
}
});
}
finally {
yield this.purgeResponseBody(response);
}
}
}
finally {
yield this.purgeResponseBody(response);
span.end();
}
}
});
this.sendAsync = (requestInfo, type, responseHandler, errorMappings) => tslib_1.__awaiter(this, void 0, void 0, function* () {
}));
};
this.startTracingSpan = (requestInfo, methodName, callback) => {
var _a;
const urlTemplate = decodeURIComponent((_a = requestInfo.urlTemplate) !== null && _a !== void 0 ? _a : "");
const telemetryPathValue = urlTemplate.replace(/\{\?[^}]+\}/gi, "");
return api_1.trace.getTracer(this.observabilityOptions.getTracerInstrumentationName()).startActiveSpan(`${methodName} - ${telemetryPathValue}`, (span) => tslib_1.__awaiter(this, void 0, void 0, function* () {
try {
span.setAttribute("http.uri_template", urlTemplate);
return yield callback(span);
}
finally {
span.end();
}
}));
};
this.sendAsync = (requestInfo, type, responseHandler, errorMappings) => {
if (!requestInfo) {
throw new Error("requestInfo cannot be null");
}
const response = yield this.getHttpResponseMessage(requestInfo);
if (responseHandler) {
return yield responseHandler.handleResponseAsync(response, errorMappings);
}
else {
return this.startTracingSpan(requestInfo, "sendAsync", (span) => tslib_1.__awaiter(this, void 0, void 0, function* () {
try {
yield this.throwFailedResponses(response, errorMappings);
if (this.shouldReturnUndefined(response))
return undefined;
const rootNode = yield this.getRootParseNode(response);
const result = rootNode.getObjectValue(type);
return result;
const response = yield this.getHttpResponseMessage(requestInfo, span);
if (responseHandler) {
span.addEvent(FetchRequestAdapter.eventResponseHandlerInvokedKey);
return yield responseHandler.handleResponseAsync(response, errorMappings);
}
else {
try {
yield this.throwFailedResponses(response, errorMappings, span);
if (this.shouldReturnUndefined(response))
return undefined;
const rootNode = yield this.getRootParseNode(response);
return api_1.trace.getTracer(this.observabilityOptions.getTracerInstrumentationName()).startActiveSpan("getObjectValue", (deserializeSpan) => {
try {
span.setAttribute(FetchRequestAdapter.responseTypeAttributeKey, "object");
const result = rootNode.getObjectValue(type);
return result;
}
finally {
deserializeSpan.end();
}
});
}
finally {
yield this.purgeResponseBody(response);
}
}
}
finally {
yield this.purgeResponseBody(response);
span.end();
}
}
});
this.sendPrimitiveAsync = (requestInfo, responseType, responseHandler, errorMappings) => tslib_1.__awaiter(this, void 0, void 0, function* () {
}));
};
this.sendPrimitiveAsync = (requestInfo, responseType, responseHandler, errorMappings) => {
if (!requestInfo) {
throw new Error("requestInfo cannot be null");
}
const response = yield this.getHttpResponseMessage(requestInfo);
if (responseHandler) {
return yield responseHandler.handleResponseAsync(response, errorMappings);
}
else {
return this.startTracingSpan(requestInfo, "sendPrimitiveAsync", (span) => tslib_1.__awaiter(this, void 0, void 0, function* () {
try {
yield this.throwFailedResponses(response, errorMappings);
if (this.shouldReturnUndefined(response))
return undefined;
switch (responseType) {
case "ArrayBuffer":
// eslint-disable-next-line no-case-declarations
if (!response.body) {
const response = yield this.getHttpResponseMessage(requestInfo, span);
if (responseHandler) {
span.addEvent(FetchRequestAdapter.eventResponseHandlerInvokedKey);
return yield responseHandler.handleResponseAsync(response, errorMappings);
}
else {
try {
yield this.throwFailedResponses(response, errorMappings, span);
if (this.shouldReturnUndefined(response))
return undefined;
switch (responseType) {
case "ArrayBuffer":
// eslint-disable-next-line no-case-declarations
if (!response.body) {
return undefined;
}
return (yield response.arrayBuffer());
case "string":
case "number":
case "boolean":
case "Date":
// eslint-disable-next-line no-case-declarations
const rootNode = yield this.getRootParseNode(response);
span.setAttribute(FetchRequestAdapter.responseTypeAttributeKey, responseType);
return api_1.trace.getTracer(this.observabilityOptions.getTracerInstrumentationName()).startActiveSpan(`get${responseType}Value`, (deserializeSpan) => {
try {
if (responseType === "string") {
return rootNode.getStringValue();
}
else if (responseType === "number") {
return rootNode.getNumberValue();
}
else if (responseType === "boolean") {
return rootNode.getBooleanValue();
}
else if (responseType === "Date") {
return rootNode.getDateValue();
}
else if (responseType === "Duration") {
return rootNode.getDurationValue();
}
else if (responseType === "DateOnly") {
return rootNode.getDateOnlyValue();
}
else if (responseType === "TimeOnly") {
return rootNode.getTimeOnlyValue();
}
else {
throw new Error("unexpected type to deserialize");
}
}
finally {
deserializeSpan.end();
}
});
}
return (yield response.arrayBuffer());
case "string":
case "number":
case "boolean":
case "Date":
// eslint-disable-next-line no-case-declarations
const rootNode = yield this.getRootParseNode(response);
if (responseType === "string") {
return rootNode.getStringValue();
}
else if (responseType === "number") {
return rootNode.getNumberValue();
}
else if (responseType === "boolean") {
return rootNode.getBooleanValue();
}
else if (responseType === "Date") {
return rootNode.getDateValue();
}
else if (responseType === "Duration") {
return rootNode.getDurationValue();
}
else if (responseType === "DateOnly") {
return rootNode.getDateOnlyValue();
}
else if (responseType === "TimeOnly") {
return rootNode.getTimeOnlyValue();
}
else {
throw new Error("unexpected type to deserialize");
}
}
finally {
yield this.purgeResponseBody(response);
}
}
}
finally {
yield this.purgeResponseBody(response);
span.end();
}
}
});
this.sendNoResponseContentAsync = (requestInfo, responseHandler, errorMappings) => tslib_1.__awaiter(this, void 0, void 0, function* () {
}));
};
this.sendNoResponseContentAsync = (requestInfo, responseHandler, errorMappings) => {
if (!requestInfo) {
throw new Error("requestInfo cannot be null");
}
const response = yield this.getHttpResponseMessage(requestInfo);
if (responseHandler) {
return yield responseHandler.handleResponseAsync(response, errorMappings);
}
try {
yield this.throwFailedResponses(response, errorMappings);
}
finally {
yield this.purgeResponseBody(response);
}
});
return this.startTracingSpan(requestInfo, "sendNoResponseContentAsync", (span) => tslib_1.__awaiter(this, void 0, void 0, function* () {
try {
const response = yield this.getHttpResponseMessage(requestInfo, span);
if (responseHandler) {
span.addEvent(FetchRequestAdapter.eventResponseHandlerInvokedKey);
return yield responseHandler.handleResponseAsync(response, errorMappings);
}
try {
yield this.throwFailedResponses(response, errorMappings, span);
}
finally {
yield this.purgeResponseBody(response);
}
}
finally {
span.end();
}
}));
};
this.enableBackingStore = (backingStoreFactory) => {

@@ -212,9 +304,16 @@ this.parseNodeFactory = (0, kiota_abstractions_1.enableBackingStoreForParseNodeFactory)(this.parseNodeFactory);

};
this.getRootParseNode = (response) => tslib_1.__awaiter(this, void 0, void 0, function* () {
const payload = yield response.arrayBuffer();
const responseContentType = this.getResponseContentType(response);
if (!responseContentType)
throw new Error("no response content type found for deserialization");
return this.parseNodeFactory.getRootParseNode(responseContentType, payload);
});
this.getRootParseNode = (response) => {
return api_1.trace.getTracer(this.observabilityOptions.getTracerInstrumentationName()).startActiveSpan("getRootParseNode", (span) => tslib_1.__awaiter(this, void 0, void 0, function* () {
try {
const payload = yield response.arrayBuffer();
const responseContentType = this.getResponseContentType(response);
if (!responseContentType)
throw new Error("no response content type found for deserialization");
return this.parseNodeFactory.getRootParseNode(responseContentType, payload);
}
finally {
span.end();
}
}));
};
this.shouldReturnUndefined = (response) => {

@@ -229,40 +328,96 @@ return response.status === 204 || !response.body;

});
this.throwFailedResponses = (response, errorMappings) => tslib_1.__awaiter(this, void 0, void 0, function* () {
var _a, _b;
if (response.ok)
return;
const statusCode = response.status;
const statusCodeAsString = statusCode.toString();
if (!errorMappings || (!errorMappings[statusCodeAsString] && !(statusCode >= 400 && statusCode < 500 && errorMappings["4XX"]) && !(statusCode >= 500 && statusCode < 600 && errorMappings["5XX"])))
throw new kiota_abstractions_1.ApiError("the server returned an unexpected status code and no error class is registered for this code " + statusCode);
const factory = (_b = (_a = errorMappings[statusCodeAsString]) !== null && _a !== void 0 ? _a : (statusCode >= 400 && statusCode < 500 ? errorMappings["4XX"] : undefined)) !== null && _b !== void 0 ? _b : (statusCode >= 500 && statusCode < 600 ? errorMappings["5XX"] : undefined);
const rootNode = yield this.getRootParseNode(response);
const error = rootNode.getObjectValue(factory);
if (error)
throw error;
else
throw new kiota_abstractions_1.ApiError("unexpected error type" + typeof error);
this.throwFailedResponses = (response, errorMappings, spanForAttributes) => {
return api_1.trace.getTracer(this.observabilityOptions.getTracerInstrumentationName()).startActiveSpan("throwFailedResponses", (span) => tslib_1.__awaiter(this, void 0, void 0, function* () {
var _a, _b;
try {
if (response.ok)
return;
spanForAttributes.setStatus({
code: api_1.SpanStatusCode.ERROR,
message: "received_error_response",
});
const statusCode = response.status;
const statusCodeAsString = statusCode.toString();
if (!errorMappings || (!errorMappings[statusCodeAsString] && !(statusCode >= 400 && statusCode < 500 && errorMappings["4XX"]) && !(statusCode >= 500 && statusCode < 600 && errorMappings["5XX"]))) {
spanForAttributes.setAttribute(FetchRequestAdapter.errorMappingFoundAttributeName, false);
const error = new kiota_abstractions_1.ApiError("the server returned an unexpected status code and no error class is registered for this code " + statusCode);
spanForAttributes.recordException(error);
throw error;
}
spanForAttributes.setAttribute(FetchRequestAdapter.errorMappingFoundAttributeName, true);
const factory = (_b = (_a = errorMappings[statusCodeAsString]) !== null && _a !== void 0 ? _a : (statusCode >= 400 && statusCode < 500 ? errorMappings["4XX"] : undefined)) !== null && _b !== void 0 ? _b : (statusCode >= 500 && statusCode < 600 ? errorMappings["5XX"] : undefined);
const rootNode = yield this.getRootParseNode(response);
let error = api_1.trace.getTracer(this.observabilityOptions.getTracerInstrumentationName()).startActiveSpan("getObjectValue", (deserializeSpan) => {
try {
return rootNode.getObjectValue(factory);
}
finally {
deserializeSpan.end();
}
});
spanForAttributes.setAttribute(FetchRequestAdapter.errorBodyFoundAttributeName, !!error);
if (!error)
error = new kiota_abstractions_1.ApiError("unexpected error type" + typeof error);
spanForAttributes.recordException(error);
throw error;
}
finally {
span.end();
}
}));
};
this.getHttpResponseMessage = (requestInfo, spanForAttributes, claims) => {
return api_1.trace.getTracer(this.observabilityOptions.getTracerInstrumentationName()).startActiveSpan("getHttpResponseMessage", (span) => tslib_1.__awaiter(this, void 0, void 0, function* () {
try {
if (!requestInfo) {
throw new Error("requestInfo cannot be null");
}
this.setBaseUrlForRequestInformation(requestInfo);
const additionalContext = {};
if (claims) {
additionalContext["claims"] = claims;
}
yield this.authenticationProvider.authenticateRequest(requestInfo, additionalContext);
const request = yield this.getRequestFromRequestInformation(requestInfo, spanForAttributes);
if (this.observabilityOptions) {
requestInfo.addRequestOptions([this.observabilityOptions]);
}
let response = yield this.httpClient.executeFetch(requestInfo.URL, request, requestInfo.getRequestOptions());
response = yield this.retryCAEResponseIfRequired(requestInfo, response, spanForAttributes, claims);
if (response) {
const responseContentLength = response.headers.get("Content-Length");
if (responseContentLength) {
spanForAttributes.setAttribute("http.response_content_length", parseInt(responseContentLength));
}
const responseContentType = response.headers.get("Content-Type");
if (responseContentType) {
spanForAttributes.setAttribute("http.response_content_type", responseContentType);
}
spanForAttributes.setAttribute("http.status_code", response.status);
// getting the http.flavor (protocol version) is impossible with fetch API
}
return response;
}
finally {
span.end();
}
}));
};
this.retryCAEResponseIfRequired = (requestInfo, response, spanForAttributes, claims) => tslib_1.__awaiter(this, void 0, void 0, function* () {
return api_1.trace.getTracer(this.observabilityOptions.getTracerInstrumentationName()).startActiveSpan("retryCAEResponseIfRequired", (span) => tslib_1.__awaiter(this, void 0, void 0, function* () {
try {
const responseClaims = this.getClaimsFromResponse(response, claims);
if (responseClaims) {
span.addEvent(FetchRequestAdapter.authenticateChallengedEventKey);
spanForAttributes.setAttribute("http.retry_count", 1);
yield this.purgeResponseBody(response);
return yield this.getHttpResponseMessage(requestInfo, spanForAttributes, responseClaims);
}
return response;
}
finally {
span.end();
}
}));
});
this.getHttpResponseMessage = (requestInfo, claims) => tslib_1.__awaiter(this, void 0, void 0, function* () {
if (!requestInfo) {
throw new Error("requestInfo cannot be null");
}
this.setBaseUrlForRequestInformation(requestInfo);
const additionalContext = {};
if (claims) {
additionalContext["claims"] = claims;
}
yield this.authenticationProvider.authenticateRequest(requestInfo, additionalContext);
const request = this.getRequestFromRequestInformation(requestInfo);
const response = yield this.httpClient.executeFetch(requestInfo.URL, request, requestInfo.getRequestOptions());
return yield this.retryCAEResponseIfRequired(requestInfo, response, claims);
});
this.retryCAEResponseIfRequired = (requestInfo, response, claims) => tslib_1.__awaiter(this, void 0, void 0, function* () {
const responseClaims = this.getClaimsFromResponse(response, claims);
if (responseClaims) {
yield this.purgeResponseBody(response);
return yield this.getHttpResponseMessage(requestInfo, responseClaims);
}
return response;
});
this.getClaimsFromResponse = (response, claims) => {

@@ -288,10 +443,38 @@ if (response.status === 401 && !claims) {

};
this.getRequestFromRequestInformation = (requestInfo) => {
var _a;
const request = {
method: (_a = requestInfo.httpMethod) === null || _a === void 0 ? void 0 : _a.toString(),
headers: requestInfo.headers,
body: requestInfo.content,
};
return request;
this.getRequestFromRequestInformation = (requestInfo, spanForAttributes) => {
return api_1.trace.getTracer(this.observabilityOptions.getTracerInstrumentationName()).startActiveSpan("getRequestFromRequestInformation", (span) => tslib_1.__awaiter(this, void 0, void 0, function* () {
var _a;
try {
const method = (_a = requestInfo.httpMethod) === null || _a === void 0 ? void 0 : _a.toString();
const uri = requestInfo.URL;
spanForAttributes.setAttribute("http.method", method !== null && method !== void 0 ? method : "");
const uriContainsScheme = uri.indexOf("://") > -1;
const schemeSplatUri = uri.split("://");
if (uriContainsScheme) {
spanForAttributes.setAttribute("http.scheme", schemeSplatUri[0]);
}
const uriWithoutScheme = uriContainsScheme ? schemeSplatUri[1] : uri;
spanForAttributes.setAttribute("http.host", uriWithoutScheme.split("/")[0]);
if (this.observabilityOptions.includeEUIIAttributes) {
spanForAttributes.setAttribute("http.uri", decodeURIComponent(uri));
}
const requestContentLength = requestInfo.headers["Content-Length"];
if (requestContentLength) {
spanForAttributes.setAttribute("http.request_content_length", parseInt(requestContentLength));
}
const requestContentType = requestInfo.headers["Content-Type"];
if (requestContentType) {
spanForAttributes.setAttribute("http.request_content_type", requestContentType);
}
const request = {
method,
headers: requestInfo.headers,
body: requestInfo.content,
};
return request;
}
finally {
span.end();
}
}));
};

@@ -310,7 +493,15 @@ if (!authenticationProvider) {

}
if (!observabilityOptions) {
throw new Error("observability options cannot be null");
}
else {
this.observabilityOptions = new observabilityOptions_1.ObservabilityOptionsImpl(observabilityOptions);
}
}
getSerializationWriterFactory() {
return this.serializationWriterFactory;
}
}
exports.FetchRequestAdapter = FetchRequestAdapter;
FetchRequestAdapter.responseTypeAttributeKey = "com.microsoft.kiota.response.type";
FetchRequestAdapter.eventResponseHandlerInvokedKey = "com.microsoft.kiota.response_handler_invoked";
FetchRequestAdapter.errorMappingFoundAttributeName = "com.microsoft.kiota.error.mapping_found";
FetchRequestAdapter.errorBodyFoundAttributeName = "com.microsoft.kiota.error.body_found";
FetchRequestAdapter.authenticateChallengedEventKey = "com.microsoft.kiota.authenticate_challenge_received";

@@ -82,3 +82,5 @@ /**

execute(url: string, requestInit: RequestInit, requestOptions?: Record<string, RequestOption> | undefined): Promise<Response>;
static readonly chaosHandlerTriggeredEventKey = "com.microsoft.kiota.chaos_handler_triggered";
private runChaos;
}
//# sourceMappingURL=chaosHandler.d.ts.map

@@ -10,3 +10,4 @@ "use strict";

exports.ChaosHandler = void 0;
const tslib_1 = require("tslib");
const api_1 = require("@opentelemetry/api");
const observabilityOptions_1 = require("../observabilityOptions");
const ChaosHandlerData_1 = require("./options/ChaosHandlerData");

@@ -164,15 +165,30 @@ const chaosStrategy_1 = require("./options/chaosStrategy");

execute(url, requestInit, requestOptions) {
return tslib_1.__awaiter(this, void 0, void 0, function* () {
if (Math.floor(Math.random() * 100) < this.options.chaosPercentage) {
return Promise.resolve(this.createChaosResponse(url, requestInit));
}
else {
if (!this.next) {
throw new Error("Please set the next middleware to continue the request");
const obsOptions = (0, observabilityOptions_1.getObservabilityOptionsFromRequest)(requestOptions);
if (obsOptions) {
return api_1.trace.getTracer(obsOptions.getTracerInstrumentationName()).startActiveSpan("chaosHandler - execute", (span) => {
try {
span.setAttribute("com.microsoft.kiota.handler.chaos.enable", true);
return this.runChaos(url, requestInit, requestOptions);
}
return yield this.next.execute(url, requestInit, requestOptions);
finally {
span.end();
}
});
}
return this.runChaos(url, requestInit, requestOptions);
}
runChaos(url, requestInit, requestOptions, span) {
if (Math.floor(Math.random() * 100) < this.options.chaosPercentage) {
span === null || span === void 0 ? void 0 : span.addEvent(ChaosHandler.chaosHandlerTriggeredEventKey);
return Promise.resolve(this.createChaosResponse(url, requestInit));
}
else {
if (!this.next) {
throw new Error("Please set the next middleware to continue the request");
}
});
return this.next.execute(url, requestInit, requestOptions);
}
}
}
exports.ChaosHandler = ChaosHandler;
ChaosHandler.chaosHandlerTriggeredEventKey = "com.microsoft.kiota.chaos_handler_triggered";

@@ -13,2 +13,5 @@ "use strict";

class ParametersNameDecodingHandlerOptions {
getKey() {
return exports.ParametersNameDecodingHandlerOptionsKey;
}
/**

@@ -25,6 +28,3 @@ * @public

}
getKey() {
return exports.ParametersNameDecodingHandlerOptionsKey;
}
}
exports.ParametersNameDecodingHandlerOptions = ParametersNameDecodingHandlerOptions;

@@ -15,3 +15,3 @@ /**

*/
export declare type ShouldRedirect = (response: Response) => boolean;
export type ShouldRedirect = (response: Response) => boolean;
export declare const RedirectHandlerOptionKey = "RedirectHandlerOption";

@@ -18,0 +18,0 @@ /**

@@ -16,3 +16,3 @@ /**

*/
export declare type ShouldRetry = (delay: number, attempt: number, request: string, options: RequestInit | undefined, response: FetchResponse) => boolean;
export type ShouldRetry = (delay: number, attempt: number, request: string, options: RequestInit | undefined, response: FetchResponse) => boolean;
export declare const RetryHandlerOptionKey = "RetryHandlerOptionKey";

@@ -19,0 +19,0 @@ /**

@@ -14,3 +14,3 @@ /**

export declare class ParametersNameDecodingHandler implements Middleware {
private options;
private readonly options;
/**

@@ -35,3 +35,4 @@ * @public

execute(url: string, requestInit: RequestInit, requestOptions?: Record<string, RequestOption>): Promise<Response>;
private decodeParameters;
}
//# sourceMappingURL=parametersNameDecodingHandler.d.ts.map

@@ -10,2 +10,4 @@ "use strict";

exports.ParametersNameDecodingHandler = void 0;
const api_1 = require("@opentelemetry/api");
const observabilityOptions_1 = require("../observabilityOptions");
const parametersNameDecodingOptions_1 = require("./options/parametersNameDecodingOptions");

@@ -38,3 +40,2 @@ /**

execute(url, requestInit, requestOptions) {
var _a, _b;
let currentOptions = this.options;

@@ -44,2 +45,18 @@ if (requestOptions && requestOptions[parametersNameDecodingOptions_1.ParametersNameDecodingHandlerOptionsKey]) {

}
const obsOptions = (0, observabilityOptions_1.getObservabilityOptionsFromRequest)(requestOptions);
if (obsOptions) {
return api_1.trace.getTracer(obsOptions.getTracerInstrumentationName()).startActiveSpan("parametersNameDecodingHandler - execute", (span) => {
try {
span.setAttribute("com.microsoft.kiota.handler.parameters_name_decoding.enable", currentOptions.enable);
return this.decodeParameters(url, requestInit, currentOptions, requestOptions);
}
finally {
span.end();
}
});
}
return this.decodeParameters(url, requestInit, currentOptions, requestOptions);
}
decodeParameters(url, requestInit, currentOptions, requestOptions) {
var _a, _b;
let updatedUrl = url;

@@ -46,0 +63,0 @@ if (currentOptions && currentOptions.enable && url.indexOf("%") > -1 && currentOptions.charactersToDecode && currentOptions.charactersToDecode.length > 0) {

@@ -106,2 +106,3 @@ /**

* @param {RedirectHandlerOptions} currentOptions - The redirect handler options instance
* @param {string} tracerName - The name to use for the tracer
* @returns A promise that resolves to nothing

@@ -108,0 +109,0 @@ */

@@ -15,2 +15,4 @@ "use strict";

const kiota_abstractions_1 = require("@microsoft/kiota-abstractions");
const api_1 = require("@opentelemetry/api");
const observabilityOptions_1 = require("../observabilityOptions");
const redirectHandlerOptions_1 = require("./options/redirectHandlerOptions");

@@ -103,5 +105,6 @@ /**

* @param {RedirectHandlerOptions} currentOptions - The redirect handler options instance
* @param {string} tracerName - The name to use for the tracer
* @returns A promise that resolves to nothing
*/
executeWithRedirect(url, fetchRequestInit, redirectCount, currentOptions, requestOptions) {
executeWithRedirect(url, fetchRequestInit, redirectCount, currentOptions, requestOptions, tracerName) {
var _a;

@@ -128,2 +131,14 @@ return tslib_1.__awaiter(this, void 0, void 0, function* () {

}
if (tracerName) {
return api_1.trace.getTracer(tracerName).startActiveSpan(`redirectHandler - redirect ${redirectCount}`, (span) => {
try {
span.setAttribute("com.microsoft.kiota.handler.redirect.count", redirectCount);
span.setAttribute("http.status_code", response.status);
return this.executeWithRedirect(url, fetchRequestInit, redirectCount, currentOptions, requestOptions);
}
finally {
span.end();
}
});
}
return yield this.executeWithRedirect(url, fetchRequestInit, redirectCount, currentOptions, requestOptions);

@@ -150,2 +165,14 @@ }

requestInit.redirect = RedirectHandler.MANUAL_REDIRECT;
const obsOptions = (0, observabilityOptions_1.getObservabilityOptionsFromRequest)(requestOptions);
if (obsOptions) {
return api_1.trace.getTracer(obsOptions.getTracerInstrumentationName()).startActiveSpan("redirectHandler - execute", (span) => {
try {
span.setAttribute("com.microsoft.kiota.handler.redirect.enable", true);
return this.executeWithRedirect(url, requestInit, redirectCount, currentOptions, requestOptions, obsOptions.getTracerInstrumentationName());
}
finally {
span.end();
}
});
}
return this.executeWithRedirect(url, requestInit, redirectCount, currentOptions, requestOptions);

@@ -152,0 +179,0 @@ }

@@ -98,2 +98,3 @@ /**

* @param {RetryHandlerOptions} currentOptions - The retry middleware options instance
* @param {string} tracerName - The name to use for the tracer
* @returns A Promise that resolves to nothing

@@ -100,0 +101,0 @@ */

@@ -15,2 +15,4 @@ "use strict";

const kiota_abstractions_1 = require("@microsoft/kiota-abstractions");
const api_1 = require("@opentelemetry/api");
const observabilityOptions_1 = require("../observabilityOptions");
const headersUtil_1 = require("../utils/headersUtil");

@@ -123,5 +125,6 @@ const retryHandlerOptions_1 = require("./options/retryHandlerOptions");

* @param {RetryHandlerOptions} currentOptions - The retry middleware options instance
* @param {string} tracerName - The name to use for the tracer
* @returns A Promise that resolves to nothing
*/
executeWithRetry(url, fetchRequestInit, retryAttempts, currentOptions, requestOptions) {
executeWithRetry(url, fetchRequestInit, retryAttempts, currentOptions, requestOptions, tracerName) {
var _a;

@@ -140,2 +143,14 @@ return tslib_1.__awaiter(this, void 0, void 0, function* () {

}
if (tracerName) {
return yield api_1.trace.getTracer(tracerName).startActiveSpan(`retryHandler - attempt ${retryAttempts}`, (span) => {
try {
span.setAttribute("http.retry_count", retryAttempts);
span.setAttribute("http.status_code", response.status);
return this.executeWithRetry(url, fetchRequestInit, retryAttempts, currentOptions, requestOptions);
}
finally {
span.end();
}
});
}
return yield this.executeWithRetry(url, fetchRequestInit, retryAttempts, currentOptions, requestOptions);

@@ -161,2 +176,14 @@ }

}
const obsOptions = (0, observabilityOptions_1.getObservabilityOptionsFromRequest)(requestOptions);
if (obsOptions) {
return api_1.trace.getTracer(obsOptions.getTracerInstrumentationName()).startActiveSpan("retryHandler - execute", (span) => {
try {
span.setAttribute("com.microsoft.kiota.handler.retry.enable", true);
return this.executeWithRetry(url, requestInit, retryAttempts, currentOptions, requestOptions, obsOptions.getTracerInstrumentationName());
}
finally {
span.end();
}
});
}
return this.executeWithRetry(url, requestInit, retryAttempts, currentOptions, requestOptions);

@@ -163,0 +190,0 @@ }

@@ -7,3 +7,3 @@ /**

*/
export declare type FetchRequestInfo = string;
export type FetchRequestInfo = string;
/**

@@ -14,4 +14,4 @@ * Use Record type to store request headers.

*/
export declare type FetchHeadersInit = Record<string, string>;
export declare type FetchHeaders = Headers & {
export type FetchHeadersInit = Record<string, string>;
export type FetchHeaders = Headers & {
append?(name: string, value: string): void;

@@ -39,6 +39,6 @@ delete?(name: string): void;

};
export declare type FetchResponse = Omit<Response, "headers"> & {
export type FetchResponse = Omit<Response, "headers"> & {
headers: FetchHeaders;
};
export declare type FetchRequestInit = Omit<RequestInit, "body" | "headers" | "redirect"> & {
export type FetchRequestInit = Omit<RequestInit, "body" | "headers" | "redirect"> & {
/**

@@ -45,0 +45,0 @@ * Request's body

import { AuthenticationProvider, BackingStoreFactory, Parsable, ParsableFactory, ParseNodeFactory, RequestAdapter, RequestInformation, ResponseHandler, SerializationWriterFactory } from "@microsoft/kiota-abstractions";
import { HttpClient } from "./httpClient";
import { ObservabilityOptions } from "./observabilityOptions";
export declare class FetchRequestAdapter implements RequestAdapter {

@@ -11,2 +12,3 @@ readonly authenticationProvider: AuthenticationProvider;

getSerializationWriterFactory(): SerializationWriterFactory;
private readonly observabilityOptions;
/**

@@ -18,7 +20,11 @@ * Instantiates a new http core service

* @param httpClient the http client to use to execute requests.
* @param observabilityOptions the observability options to use.
*/
constructor(authenticationProvider: AuthenticationProvider, parseNodeFactory?: ParseNodeFactory, serializationWriterFactory?: SerializationWriterFactory, httpClient?: HttpClient);
constructor(authenticationProvider: AuthenticationProvider, parseNodeFactory?: ParseNodeFactory, serializationWriterFactory?: SerializationWriterFactory, httpClient?: HttpClient, observabilityOptions?: ObservabilityOptions);
private getResponseContentType;
private static readonly responseTypeAttributeKey;
sendCollectionOfPrimitiveAsync: <ResponseType_1>(requestInfo: RequestInformation, responseType: "string" | "number" | "boolean" | "Date", responseHandler: ResponseHandler | undefined, errorMappings: Record<string, ParsableFactory<Parsable>> | undefined) => Promise<ResponseType_1[] | undefined>;
sendCollectionAsync: <ModelType extends Parsable>(requestInfo: RequestInformation, type: ParsableFactory<ModelType>, responseHandler: ResponseHandler | undefined, errorMappings: Record<string, ParsableFactory<Parsable>> | undefined) => Promise<ModelType[] | undefined>;
private startTracingSpan;
static readonly eventResponseHandlerInvokedKey = "com.microsoft.kiota.response_handler_invoked";
sendAsync: <ModelType extends Parsable>(requestInfo: RequestInformation, type: ParsableFactory<ModelType>, responseHandler: ResponseHandler | undefined, errorMappings: Record<string, ParsableFactory<Parsable>> | undefined) => Promise<ModelType | undefined>;

@@ -32,4 +38,7 @@ sendPrimitiveAsync: <ResponseType_1>(requestInfo: RequestInformation, responseType: "string" | "number" | "boolean" | "Date" | "ArrayBuffer", responseHandler: ResponseHandler | undefined, errorMappings: Record<string, ParsableFactory<Parsable>> | undefined) => Promise<ResponseType_1 | undefined>;

private purgeResponseBody;
static readonly errorMappingFoundAttributeName = "com.microsoft.kiota.error.mapping_found";
static readonly errorBodyFoundAttributeName = "com.microsoft.kiota.error.body_found";
private throwFailedResponses;
private getHttpResponseMessage;
static readonly authenticateChallengedEventKey = "com.microsoft.kiota.authenticate_challenge_received";
private retryCAEResponseIfRequired;

@@ -36,0 +45,0 @@ private getClaimsFromResponse;

import { ApiError, BackingStoreFactorySingleton, enableBackingStoreForParseNodeFactory, enableBackingStoreForSerializationWriterFactory, ParseNodeFactoryRegistry, SerializationWriterFactoryRegistry } from "@microsoft/kiota-abstractions";
import { SpanStatusCode, trace } from "@opentelemetry/api";
import { HttpClient } from "./httpClient";
import { ObservabilityOptionsImpl } from "./observabilityOptions";
export class FetchRequestAdapter {
getSerializationWriterFactory() {
return this.serializationWriterFactory;
}
/**

@@ -10,4 +15,5 @@ * Instantiates a new http core service

* @param httpClient the http client to use to execute requests.
* @param observabilityOptions the observability options to use.
*/
constructor(authenticationProvider, parseNodeFactory = ParseNodeFactoryRegistry.defaultInstance, serializationWriterFactory = SerializationWriterFactoryRegistry.defaultInstance, httpClient = new HttpClient()) {
constructor(authenticationProvider, parseNodeFactory = ParseNodeFactoryRegistry.defaultInstance, serializationWriterFactory = SerializationWriterFactoryRegistry.defaultInstance, httpClient = new HttpClient(), observabilityOptions = new ObservabilityOptionsImpl()) {
this.authenticationProvider = authenticationProvider;

@@ -30,168 +36,254 @@ this.parseNodeFactory = parseNodeFactory;

};
this.sendCollectionOfPrimitiveAsync = async (requestInfo, responseType, responseHandler, errorMappings) => {
this.sendCollectionOfPrimitiveAsync = (requestInfo, responseType, responseHandler, errorMappings) => {
if (!requestInfo) {
throw new Error("requestInfo cannot be null");
}
const response = await this.getHttpResponseMessage(requestInfo);
if (responseHandler) {
return await responseHandler.handleResponseAsync(response, errorMappings);
}
else {
return this.startTracingSpan(requestInfo, "sendCollectionOfPrimitiveAsync", async (span) => {
try {
await this.throwFailedResponses(response, errorMappings);
if (this.shouldReturnUndefined(response))
return undefined;
switch (responseType) {
case "string":
case "number":
case "boolean":
case "Date":
// eslint-disable-next-line no-case-declarations
const rootNode = await this.getRootParseNode(response);
if (responseType === "string") {
return rootNode.getCollectionOfPrimitiveValues();
const response = await this.getHttpResponseMessage(requestInfo, span);
if (responseHandler) {
span.addEvent(FetchRequestAdapter.eventResponseHandlerInvokedKey);
return await responseHandler.handleResponseAsync(response, errorMappings);
}
else {
try {
await this.throwFailedResponses(response, errorMappings, span);
if (this.shouldReturnUndefined(response))
return undefined;
switch (responseType) {
case "string":
case "number":
case "boolean":
case "Date":
// eslint-disable-next-line no-case-declarations
const rootNode = await this.getRootParseNode(response);
return trace.getTracer(this.observabilityOptions.getTracerInstrumentationName()).startActiveSpan(`getCollectionOf${responseType}Value`, (deserializeSpan) => {
try {
span.setAttribute(FetchRequestAdapter.responseTypeAttributeKey, responseType);
if (responseType === "string") {
return rootNode.getCollectionOfPrimitiveValues();
}
else if (responseType === "number") {
return rootNode.getCollectionOfPrimitiveValues();
}
else if (responseType === "boolean") {
return rootNode.getCollectionOfPrimitiveValues();
}
else if (responseType === "Date") {
return rootNode.getCollectionOfPrimitiveValues();
}
else if (responseType === "Duration") {
return rootNode.getCollectionOfPrimitiveValues();
}
else if (responseType === "DateOnly") {
return rootNode.getCollectionOfPrimitiveValues();
}
else if (responseType === "TimeOnly") {
return rootNode.getCollectionOfPrimitiveValues();
}
else {
throw new Error("unexpected type to deserialize");
}
}
finally {
deserializeSpan.end();
}
});
}
else if (responseType === "number") {
return rootNode.getCollectionOfPrimitiveValues();
}
else if (responseType === "boolean") {
return rootNode.getCollectionOfPrimitiveValues();
}
else if (responseType === "Date") {
return rootNode.getCollectionOfPrimitiveValues();
}
else if (responseType === "Duration") {
return rootNode.getCollectionOfPrimitiveValues();
}
else if (responseType === "DateOnly") {
return rootNode.getCollectionOfPrimitiveValues();
}
else if (responseType === "TimeOnly") {
return rootNode.getCollectionOfPrimitiveValues();
}
else {
throw new Error("unexpected type to deserialize");
}
}
finally {
await this.purgeResponseBody(response);
}
}
}
finally {
await this.purgeResponseBody(response);
span.end();
}
}
});
};
this.sendCollectionAsync = async (requestInfo, type, responseHandler, errorMappings) => {
this.sendCollectionAsync = (requestInfo, type, responseHandler, errorMappings) => {
if (!requestInfo) {
throw new Error("requestInfo cannot be null");
}
const response = await this.getHttpResponseMessage(requestInfo);
if (responseHandler) {
return await responseHandler.handleResponseAsync(response, errorMappings);
}
else {
return this.startTracingSpan(requestInfo, "sendCollectionAsync", async (span) => {
try {
await this.throwFailedResponses(response, errorMappings);
if (this.shouldReturnUndefined(response))
return undefined;
const rootNode = await this.getRootParseNode(response);
const result = rootNode.getCollectionOfObjectValues(type);
return result;
const response = await this.getHttpResponseMessage(requestInfo, span);
if (responseHandler) {
span.addEvent(FetchRequestAdapter.eventResponseHandlerInvokedKey);
return await responseHandler.handleResponseAsync(response, errorMappings);
}
else {
try {
await this.throwFailedResponses(response, errorMappings, span);
if (this.shouldReturnUndefined(response))
return undefined;
const rootNode = await this.getRootParseNode(response);
return trace.getTracer(this.observabilityOptions.getTracerInstrumentationName()).startActiveSpan("getCollectionOfObjectValues", (deserializeSpan) => {
try {
const result = rootNode.getCollectionOfObjectValues(type);
span.setAttribute(FetchRequestAdapter.responseTypeAttributeKey, "object[]");
return result;
}
finally {
deserializeSpan.end();
}
});
}
finally {
await this.purgeResponseBody(response);
}
}
}
finally {
await this.purgeResponseBody(response);
span.end();
}
}
});
};
this.sendAsync = async (requestInfo, type, responseHandler, errorMappings) => {
this.startTracingSpan = (requestInfo, methodName, callback) => {
var _a;
const urlTemplate = decodeURIComponent((_a = requestInfo.urlTemplate) !== null && _a !== void 0 ? _a : "");
const telemetryPathValue = urlTemplate.replace(/\{\?[^}]+\}/gi, "");
return trace.getTracer(this.observabilityOptions.getTracerInstrumentationName()).startActiveSpan(`${methodName} - ${telemetryPathValue}`, async (span) => {
try {
span.setAttribute("http.uri_template", urlTemplate);
return await callback(span);
}
finally {
span.end();
}
});
};
this.sendAsync = (requestInfo, type, responseHandler, errorMappings) => {
if (!requestInfo) {
throw new Error("requestInfo cannot be null");
}
const response = await this.getHttpResponseMessage(requestInfo);
if (responseHandler) {
return await responseHandler.handleResponseAsync(response, errorMappings);
}
else {
return this.startTracingSpan(requestInfo, "sendAsync", async (span) => {
try {
await this.throwFailedResponses(response, errorMappings);
if (this.shouldReturnUndefined(response))
return undefined;
const rootNode = await this.getRootParseNode(response);
const result = rootNode.getObjectValue(type);
return result;
const response = await this.getHttpResponseMessage(requestInfo, span);
if (responseHandler) {
span.addEvent(FetchRequestAdapter.eventResponseHandlerInvokedKey);
return await responseHandler.handleResponseAsync(response, errorMappings);
}
else {
try {
await this.throwFailedResponses(response, errorMappings, span);
if (this.shouldReturnUndefined(response))
return undefined;
const rootNode = await this.getRootParseNode(response);
return trace.getTracer(this.observabilityOptions.getTracerInstrumentationName()).startActiveSpan("getObjectValue", (deserializeSpan) => {
try {
span.setAttribute(FetchRequestAdapter.responseTypeAttributeKey, "object");
const result = rootNode.getObjectValue(type);
return result;
}
finally {
deserializeSpan.end();
}
});
}
finally {
await this.purgeResponseBody(response);
}
}
}
finally {
await this.purgeResponseBody(response);
span.end();
}
}
});
};
this.sendPrimitiveAsync = async (requestInfo, responseType, responseHandler, errorMappings) => {
this.sendPrimitiveAsync = (requestInfo, responseType, responseHandler, errorMappings) => {
if (!requestInfo) {
throw new Error("requestInfo cannot be null");
}
const response = await this.getHttpResponseMessage(requestInfo);
if (responseHandler) {
return await responseHandler.handleResponseAsync(response, errorMappings);
}
else {
return this.startTracingSpan(requestInfo, "sendPrimitiveAsync", async (span) => {
try {
await this.throwFailedResponses(response, errorMappings);
if (this.shouldReturnUndefined(response))
return undefined;
switch (responseType) {
case "ArrayBuffer":
// eslint-disable-next-line no-case-declarations
if (!response.body) {
const response = await this.getHttpResponseMessage(requestInfo, span);
if (responseHandler) {
span.addEvent(FetchRequestAdapter.eventResponseHandlerInvokedKey);
return await responseHandler.handleResponseAsync(response, errorMappings);
}
else {
try {
await this.throwFailedResponses(response, errorMappings, span);
if (this.shouldReturnUndefined(response))
return undefined;
switch (responseType) {
case "ArrayBuffer":
// eslint-disable-next-line no-case-declarations
if (!response.body) {
return undefined;
}
return (await response.arrayBuffer());
case "string":
case "number":
case "boolean":
case "Date":
// eslint-disable-next-line no-case-declarations
const rootNode = await this.getRootParseNode(response);
span.setAttribute(FetchRequestAdapter.responseTypeAttributeKey, responseType);
return trace.getTracer(this.observabilityOptions.getTracerInstrumentationName()).startActiveSpan(`get${responseType}Value`, (deserializeSpan) => {
try {
if (responseType === "string") {
return rootNode.getStringValue();
}
else if (responseType === "number") {
return rootNode.getNumberValue();
}
else if (responseType === "boolean") {
return rootNode.getBooleanValue();
}
else if (responseType === "Date") {
return rootNode.getDateValue();
}
else if (responseType === "Duration") {
return rootNode.getDurationValue();
}
else if (responseType === "DateOnly") {
return rootNode.getDateOnlyValue();
}
else if (responseType === "TimeOnly") {
return rootNode.getTimeOnlyValue();
}
else {
throw new Error("unexpected type to deserialize");
}
}
finally {
deserializeSpan.end();
}
});
}
return (await response.arrayBuffer());
case "string":
case "number":
case "boolean":
case "Date":
// eslint-disable-next-line no-case-declarations
const rootNode = await this.getRootParseNode(response);
if (responseType === "string") {
return rootNode.getStringValue();
}
else if (responseType === "number") {
return rootNode.getNumberValue();
}
else if (responseType === "boolean") {
return rootNode.getBooleanValue();
}
else if (responseType === "Date") {
return rootNode.getDateValue();
}
else if (responseType === "Duration") {
return rootNode.getDurationValue();
}
else if (responseType === "DateOnly") {
return rootNode.getDateOnlyValue();
}
else if (responseType === "TimeOnly") {
return rootNode.getTimeOnlyValue();
}
else {
throw new Error("unexpected type to deserialize");
}
}
finally {
await this.purgeResponseBody(response);
}
}
}
finally {
await this.purgeResponseBody(response);
span.end();
}
}
});
};
this.sendNoResponseContentAsync = async (requestInfo, responseHandler, errorMappings) => {
this.sendNoResponseContentAsync = (requestInfo, responseHandler, errorMappings) => {
if (!requestInfo) {
throw new Error("requestInfo cannot be null");
}
const response = await this.getHttpResponseMessage(requestInfo);
if (responseHandler) {
return await responseHandler.handleResponseAsync(response, errorMappings);
}
try {
await this.throwFailedResponses(response, errorMappings);
}
finally {
await this.purgeResponseBody(response);
}
return this.startTracingSpan(requestInfo, "sendNoResponseContentAsync", async (span) => {
try {
const response = await this.getHttpResponseMessage(requestInfo, span);
if (responseHandler) {
span.addEvent(FetchRequestAdapter.eventResponseHandlerInvokedKey);
return await responseHandler.handleResponseAsync(response, errorMappings);
}
try {
await this.throwFailedResponses(response, errorMappings, span);
}
finally {
await this.purgeResponseBody(response);
}
}
finally {
span.end();
}
});
};

@@ -207,8 +299,15 @@ this.enableBackingStore = (backingStoreFactory) => {

};
this.getRootParseNode = async (response) => {
const payload = await response.arrayBuffer();
const responseContentType = this.getResponseContentType(response);
if (!responseContentType)
throw new Error("no response content type found for deserialization");
return this.parseNodeFactory.getRootParseNode(responseContentType, payload);
this.getRootParseNode = (response) => {
return trace.getTracer(this.observabilityOptions.getTracerInstrumentationName()).startActiveSpan("getRootParseNode", async (span) => {
try {
const payload = await response.arrayBuffer();
const responseContentType = this.getResponseContentType(response);
if (!responseContentType)
throw new Error("no response content type found for deserialization");
return this.parseNodeFactory.getRootParseNode(responseContentType, payload);
}
finally {
span.end();
}
});
};

@@ -224,39 +323,95 @@ this.shouldReturnUndefined = (response) => {

};
this.throwFailedResponses = async (response, errorMappings) => {
var _a, _b;
if (response.ok)
return;
const statusCode = response.status;
const statusCodeAsString = statusCode.toString();
if (!errorMappings || (!errorMappings[statusCodeAsString] && !(statusCode >= 400 && statusCode < 500 && errorMappings["4XX"]) && !(statusCode >= 500 && statusCode < 600 && errorMappings["5XX"])))
throw new ApiError("the server returned an unexpected status code and no error class is registered for this code " + statusCode);
const factory = (_b = (_a = errorMappings[statusCodeAsString]) !== null && _a !== void 0 ? _a : (statusCode >= 400 && statusCode < 500 ? errorMappings["4XX"] : undefined)) !== null && _b !== void 0 ? _b : (statusCode >= 500 && statusCode < 600 ? errorMappings["5XX"] : undefined);
const rootNode = await this.getRootParseNode(response);
const error = rootNode.getObjectValue(factory);
if (error)
throw error;
else
throw new ApiError("unexpected error type" + typeof error);
this.throwFailedResponses = (response, errorMappings, spanForAttributes) => {
return trace.getTracer(this.observabilityOptions.getTracerInstrumentationName()).startActiveSpan("throwFailedResponses", async (span) => {
var _a, _b;
try {
if (response.ok)
return;
spanForAttributes.setStatus({
code: SpanStatusCode.ERROR,
message: "received_error_response",
});
const statusCode = response.status;
const statusCodeAsString = statusCode.toString();
if (!errorMappings || (!errorMappings[statusCodeAsString] && !(statusCode >= 400 && statusCode < 500 && errorMappings["4XX"]) && !(statusCode >= 500 && statusCode < 600 && errorMappings["5XX"]))) {
spanForAttributes.setAttribute(FetchRequestAdapter.errorMappingFoundAttributeName, false);
const error = new ApiError("the server returned an unexpected status code and no error class is registered for this code " + statusCode);
spanForAttributes.recordException(error);
throw error;
}
spanForAttributes.setAttribute(FetchRequestAdapter.errorMappingFoundAttributeName, true);
const factory = (_b = (_a = errorMappings[statusCodeAsString]) !== null && _a !== void 0 ? _a : (statusCode >= 400 && statusCode < 500 ? errorMappings["4XX"] : undefined)) !== null && _b !== void 0 ? _b : (statusCode >= 500 && statusCode < 600 ? errorMappings["5XX"] : undefined);
const rootNode = await this.getRootParseNode(response);
let error = trace.getTracer(this.observabilityOptions.getTracerInstrumentationName()).startActiveSpan("getObjectValue", (deserializeSpan) => {
try {
return rootNode.getObjectValue(factory);
}
finally {
deserializeSpan.end();
}
});
spanForAttributes.setAttribute(FetchRequestAdapter.errorBodyFoundAttributeName, !!error);
if (!error)
error = new ApiError("unexpected error type" + typeof error);
spanForAttributes.recordException(error);
throw error;
}
finally {
span.end();
}
});
};
this.getHttpResponseMessage = async (requestInfo, claims) => {
if (!requestInfo) {
throw new Error("requestInfo cannot be null");
}
this.setBaseUrlForRequestInformation(requestInfo);
const additionalContext = {};
if (claims) {
additionalContext["claims"] = claims;
}
await this.authenticationProvider.authenticateRequest(requestInfo, additionalContext);
const request = this.getRequestFromRequestInformation(requestInfo);
const response = await this.httpClient.executeFetch(requestInfo.URL, request, requestInfo.getRequestOptions());
return await this.retryCAEResponseIfRequired(requestInfo, response, claims);
this.getHttpResponseMessage = (requestInfo, spanForAttributes, claims) => {
return trace.getTracer(this.observabilityOptions.getTracerInstrumentationName()).startActiveSpan("getHttpResponseMessage", async (span) => {
try {
if (!requestInfo) {
throw new Error("requestInfo cannot be null");
}
this.setBaseUrlForRequestInformation(requestInfo);
const additionalContext = {};
if (claims) {
additionalContext["claims"] = claims;
}
await this.authenticationProvider.authenticateRequest(requestInfo, additionalContext);
const request = await this.getRequestFromRequestInformation(requestInfo, spanForAttributes);
if (this.observabilityOptions) {
requestInfo.addRequestOptions([this.observabilityOptions]);
}
let response = await this.httpClient.executeFetch(requestInfo.URL, request, requestInfo.getRequestOptions());
response = await this.retryCAEResponseIfRequired(requestInfo, response, spanForAttributes, claims);
if (response) {
const responseContentLength = response.headers.get("Content-Length");
if (responseContentLength) {
spanForAttributes.setAttribute("http.response_content_length", parseInt(responseContentLength));
}
const responseContentType = response.headers.get("Content-Type");
if (responseContentType) {
spanForAttributes.setAttribute("http.response_content_type", responseContentType);
}
spanForAttributes.setAttribute("http.status_code", response.status);
// getting the http.flavor (protocol version) is impossible with fetch API
}
return response;
}
finally {
span.end();
}
});
};
this.retryCAEResponseIfRequired = async (requestInfo, response, claims) => {
const responseClaims = this.getClaimsFromResponse(response, claims);
if (responseClaims) {
await this.purgeResponseBody(response);
return await this.getHttpResponseMessage(requestInfo, responseClaims);
}
return response;
this.retryCAEResponseIfRequired = async (requestInfo, response, spanForAttributes, claims) => {
return trace.getTracer(this.observabilityOptions.getTracerInstrumentationName()).startActiveSpan("retryCAEResponseIfRequired", async (span) => {
try {
const responseClaims = this.getClaimsFromResponse(response, claims);
if (responseClaims) {
span.addEvent(FetchRequestAdapter.authenticateChallengedEventKey);
spanForAttributes.setAttribute("http.retry_count", 1);
await this.purgeResponseBody(response);
return await this.getHttpResponseMessage(requestInfo, spanForAttributes, responseClaims);
}
return response;
}
finally {
span.end();
}
});
};

@@ -283,10 +438,38 @@ this.getClaimsFromResponse = (response, claims) => {

};
this.getRequestFromRequestInformation = (requestInfo) => {
var _a;
const request = {
method: (_a = requestInfo.httpMethod) === null || _a === void 0 ? void 0 : _a.toString(),
headers: requestInfo.headers,
body: requestInfo.content,
};
return request;
this.getRequestFromRequestInformation = (requestInfo, spanForAttributes) => {
return trace.getTracer(this.observabilityOptions.getTracerInstrumentationName()).startActiveSpan("getRequestFromRequestInformation", async (span) => {
var _a;
try {
const method = (_a = requestInfo.httpMethod) === null || _a === void 0 ? void 0 : _a.toString();
const uri = requestInfo.URL;
spanForAttributes.setAttribute("http.method", method !== null && method !== void 0 ? method : "");
const uriContainsScheme = uri.indexOf("://") > -1;
const schemeSplatUri = uri.split("://");
if (uriContainsScheme) {
spanForAttributes.setAttribute("http.scheme", schemeSplatUri[0]);
}
const uriWithoutScheme = uriContainsScheme ? schemeSplatUri[1] : uri;
spanForAttributes.setAttribute("http.host", uriWithoutScheme.split("/")[0]);
if (this.observabilityOptions.includeEUIIAttributes) {
spanForAttributes.setAttribute("http.uri", decodeURIComponent(uri));
}
const requestContentLength = requestInfo.headers["Content-Length"];
if (requestContentLength) {
spanForAttributes.setAttribute("http.request_content_length", parseInt(requestContentLength));
}
const requestContentType = requestInfo.headers["Content-Type"];
if (requestContentType) {
spanForAttributes.setAttribute("http.request_content_type", requestContentType);
}
const request = {
method,
headers: requestInfo.headers,
body: requestInfo.content,
};
return request;
}
finally {
span.end();
}
});
};

@@ -305,6 +488,14 @@ if (!authenticationProvider) {

}
if (!observabilityOptions) {
throw new Error("observability options cannot be null");
}
else {
this.observabilityOptions = new ObservabilityOptionsImpl(observabilityOptions);
}
}
getSerializationWriterFactory() {
return this.serializationWriterFactory;
}
}
FetchRequestAdapter.responseTypeAttributeKey = "com.microsoft.kiota.response.type";
FetchRequestAdapter.eventResponseHandlerInvokedKey = "com.microsoft.kiota.response_handler_invoked";
FetchRequestAdapter.errorMappingFoundAttributeName = "com.microsoft.kiota.error.mapping_found";
FetchRequestAdapter.errorBodyFoundAttributeName = "com.microsoft.kiota.error.body_found";
FetchRequestAdapter.authenticateChallengedEventKey = "com.microsoft.kiota.authenticate_challenge_received";

@@ -82,3 +82,5 @@ /**

execute(url: string, requestInit: RequestInit, requestOptions?: Record<string, RequestOption> | undefined): Promise<Response>;
static readonly chaosHandlerTriggeredEventKey = "com.microsoft.kiota.chaos_handler_triggered";
private runChaos;
}
//# sourceMappingURL=chaosHandler.d.ts.map

@@ -7,2 +7,4 @@ /**

*/
import { trace } from "@opentelemetry/api";
import { getObservabilityOptionsFromRequest } from "../observabilityOptions";
import { httpStatusCode, methodStatusCode } from "./options/ChaosHandlerData";

@@ -159,4 +161,20 @@ import { ChaosStrategy } from "./options/chaosStrategy";

}
async execute(url, requestInit, requestOptions) {
execute(url, requestInit, requestOptions) {
const obsOptions = getObservabilityOptionsFromRequest(requestOptions);
if (obsOptions) {
return trace.getTracer(obsOptions.getTracerInstrumentationName()).startActiveSpan("chaosHandler - execute", (span) => {
try {
span.setAttribute("com.microsoft.kiota.handler.chaos.enable", true);
return this.runChaos(url, requestInit, requestOptions);
}
finally {
span.end();
}
});
}
return this.runChaos(url, requestInit, requestOptions);
}
runChaos(url, requestInit, requestOptions, span) {
if (Math.floor(Math.random() * 100) < this.options.chaosPercentage) {
span === null || span === void 0 ? void 0 : span.addEvent(ChaosHandler.chaosHandlerTriggeredEventKey);
return Promise.resolve(this.createChaosResponse(url, requestInit));

@@ -168,5 +186,6 @@ }

}
return await this.next.execute(url, requestInit, requestOptions);
return this.next.execute(url, requestInit, requestOptions);
}
}
}
ChaosHandler.chaosHandlerTriggeredEventKey = "com.microsoft.kiota.chaos_handler_triggered";

@@ -10,2 +10,5 @@ /**

export class ParametersNameDecodingHandlerOptions {
getKey() {
return ParametersNameDecodingHandlerOptionsKey;
}
/**

@@ -22,5 +25,2 @@ * @public

}
getKey() {
return ParametersNameDecodingHandlerOptionsKey;
}
}

@@ -15,3 +15,3 @@ /**

*/
export declare type ShouldRedirect = (response: Response) => boolean;
export type ShouldRedirect = (response: Response) => boolean;
export declare const RedirectHandlerOptionKey = "RedirectHandlerOption";

@@ -18,0 +18,0 @@ /**

@@ -16,3 +16,3 @@ /**

*/
export declare type ShouldRetry = (delay: number, attempt: number, request: string, options: RequestInit | undefined, response: FetchResponse) => boolean;
export type ShouldRetry = (delay: number, attempt: number, request: string, options: RequestInit | undefined, response: FetchResponse) => boolean;
export declare const RetryHandlerOptionKey = "RetryHandlerOptionKey";

@@ -19,0 +19,0 @@ /**

@@ -14,3 +14,3 @@ /**

export declare class ParametersNameDecodingHandler implements Middleware {
private options;
private readonly options;
/**

@@ -35,3 +35,4 @@ * @public

execute(url: string, requestInit: RequestInit, requestOptions?: Record<string, RequestOption>): Promise<Response>;
private decodeParameters;
}
//# sourceMappingURL=parametersNameDecodingHandler.d.ts.map

@@ -7,2 +7,4 @@ /**

*/
import { trace } from "@opentelemetry/api";
import { getObservabilityOptionsFromRequest } from "../observabilityOptions";
import { ParametersNameDecodingHandlerOptions, ParametersNameDecodingHandlerOptionsKey } from "./options/parametersNameDecodingOptions";

@@ -35,3 +37,2 @@ /**

execute(url, requestInit, requestOptions) {
var _a, _b;
let currentOptions = this.options;

@@ -41,2 +42,18 @@ if (requestOptions && requestOptions[ParametersNameDecodingHandlerOptionsKey]) {

}
const obsOptions = getObservabilityOptionsFromRequest(requestOptions);
if (obsOptions) {
return trace.getTracer(obsOptions.getTracerInstrumentationName()).startActiveSpan("parametersNameDecodingHandler - execute", (span) => {
try {
span.setAttribute("com.microsoft.kiota.handler.parameters_name_decoding.enable", currentOptions.enable);
return this.decodeParameters(url, requestInit, currentOptions, requestOptions);
}
finally {
span.end();
}
});
}
return this.decodeParameters(url, requestInit, currentOptions, requestOptions);
}
decodeParameters(url, requestInit, currentOptions, requestOptions) {
var _a, _b;
let updatedUrl = url;

@@ -43,0 +60,0 @@ if (currentOptions && currentOptions.enable && url.indexOf("%") > -1 && currentOptions.charactersToDecode && currentOptions.charactersToDecode.length > 0) {

@@ -106,2 +106,3 @@ /**

* @param {RedirectHandlerOptions} currentOptions - The redirect handler options instance
* @param {string} tracerName - The name to use for the tracer
* @returns A promise that resolves to nothing

@@ -108,0 +109,0 @@ */

@@ -11,2 +11,4 @@ /**

import { HttpMethod } from "@microsoft/kiota-abstractions";
import { trace } from "@opentelemetry/api";
import { getObservabilityOptionsFromRequest } from "../observabilityOptions";
import { RedirectHandlerOptionKey, RedirectHandlerOptions } from "./options/redirectHandlerOptions";

@@ -99,5 +101,6 @@ /**

* @param {RedirectHandlerOptions} currentOptions - The redirect handler options instance
* @param {string} tracerName - The name to use for the tracer
* @returns A promise that resolves to nothing
*/
async executeWithRedirect(url, fetchRequestInit, redirectCount, currentOptions, requestOptions) {
async executeWithRedirect(url, fetchRequestInit, redirectCount, currentOptions, requestOptions, tracerName) {
var _a;

@@ -123,2 +126,14 @@ const response = await ((_a = this.next) === null || _a === void 0 ? void 0 : _a.execute(url, fetchRequestInit, requestOptions));

}
if (tracerName) {
return trace.getTracer(tracerName).startActiveSpan(`redirectHandler - redirect ${redirectCount}`, (span) => {
try {
span.setAttribute("com.microsoft.kiota.handler.redirect.count", redirectCount);
span.setAttribute("http.status_code", response.status);
return this.executeWithRedirect(url, fetchRequestInit, redirectCount, currentOptions, requestOptions);
}
finally {
span.end();
}
});
}
return await this.executeWithRedirect(url, fetchRequestInit, redirectCount, currentOptions, requestOptions);

@@ -144,2 +159,14 @@ }

requestInit.redirect = RedirectHandler.MANUAL_REDIRECT;
const obsOptions = getObservabilityOptionsFromRequest(requestOptions);
if (obsOptions) {
return trace.getTracer(obsOptions.getTracerInstrumentationName()).startActiveSpan("redirectHandler - execute", (span) => {
try {
span.setAttribute("com.microsoft.kiota.handler.redirect.enable", true);
return this.executeWithRedirect(url, requestInit, redirectCount, currentOptions, requestOptions, obsOptions.getTracerInstrumentationName());
}
finally {
span.end();
}
});
}
return this.executeWithRedirect(url, requestInit, redirectCount, currentOptions, requestOptions);

@@ -146,0 +173,0 @@ }

@@ -98,2 +98,3 @@ /**

* @param {RetryHandlerOptions} currentOptions - The retry middleware options instance
* @param {string} tracerName - The name to use for the tracer
* @returns A Promise that resolves to nothing

@@ -100,0 +101,0 @@ */

@@ -11,2 +11,4 @@ /**

import { HttpMethod } from "@microsoft/kiota-abstractions";
import { trace } from "@opentelemetry/api";
import { getObservabilityOptionsFromRequest } from "../observabilityOptions";
import { getRequestHeader, setRequestHeader } from "../utils/headersUtil";

@@ -117,5 +119,6 @@ import { RetryHandlerOptionKey, RetryHandlerOptions } from "./options/retryHandlerOptions";

* @param {RetryHandlerOptions} currentOptions - The retry middleware options instance
* @param {string} tracerName - The name to use for the tracer
* @returns A Promise that resolves to nothing
*/
async executeWithRetry(url, fetchRequestInit, retryAttempts, currentOptions, requestOptions) {
async executeWithRetry(url, fetchRequestInit, retryAttempts, currentOptions, requestOptions, tracerName) {
var _a;

@@ -133,2 +136,14 @@ const response = await ((_a = this.next) === null || _a === void 0 ? void 0 : _a.execute(url, fetchRequestInit, requestOptions));

}
if (tracerName) {
return await trace.getTracer(tracerName).startActiveSpan(`retryHandler - attempt ${retryAttempts}`, (span) => {
try {
span.setAttribute("http.retry_count", retryAttempts);
span.setAttribute("http.status_code", response.status);
return this.executeWithRetry(url, fetchRequestInit, retryAttempts, currentOptions, requestOptions);
}
finally {
span.end();
}
});
}
return await this.executeWithRetry(url, fetchRequestInit, retryAttempts, currentOptions, requestOptions);

@@ -153,2 +168,14 @@ }

}
const obsOptions = getObservabilityOptionsFromRequest(requestOptions);
if (obsOptions) {
return trace.getTracer(obsOptions.getTracerInstrumentationName()).startActiveSpan("retryHandler - execute", (span) => {
try {
span.setAttribute("com.microsoft.kiota.handler.retry.enable", true);
return this.executeWithRetry(url, requestInit, retryAttempts, currentOptions, requestOptions, obsOptions.getTracerInstrumentationName());
}
finally {
span.end();
}
});
}
return this.executeWithRetry(url, requestInit, retryAttempts, currentOptions, requestOptions);

@@ -155,0 +182,0 @@ }

@@ -7,3 +7,3 @@ /**

*/
export declare type FetchRequestInfo = string;
export type FetchRequestInfo = string;
/**

@@ -14,4 +14,4 @@ * Use Record type to store request headers.

*/
export declare type FetchHeadersInit = Record<string, string>;
export declare type FetchHeaders = Headers & {
export type FetchHeadersInit = Record<string, string>;
export type FetchHeaders = Headers & {
append?(name: string, value: string): void;

@@ -39,6 +39,6 @@ delete?(name: string): void;

};
export declare type FetchResponse = Omit<Response, "headers"> & {
export type FetchResponse = Omit<Response, "headers"> & {
headers: FetchHeaders;
};
export declare type FetchRequestInit = Omit<RequestInit, "body" | "headers" | "redirect"> & {
export type FetchRequestInit = Omit<RequestInit, "body" | "headers" | "redirect"> & {
/**

@@ -45,0 +45,0 @@ * Request's body

{
"name": "@microsoft/kiota-http-fetchlibrary",
"version": "1.0.0-preview.8",
"description": "Kiota request adapter implementation with fetch",
"keywords": [
"Kiota",
"OpenAPI",
"HTTP",
"fetch"
],
"homepage": "https://github.com/microsoft/kiota-typescript#readme",
"bugs": {
"url": "https://github.com/microsoft/kiota-typescript/issues"
},
"repository": {
"type": "git",
"url": "git://github.com/microsoft/kiota-typescript.git"
},
"license": "MIT",
"author": "Microsoft",
"main": "dist/cjs/src/index.js",
"browser": {
"./dist/es/src/index.js": "./dist/es/src/browser/index.js",
"./dist/es/src/middlewares/middlewareFactory.js": "./dist/es/src/middlewares/browser/middlewareFactory.js"
},
"types": "dist/cjs/src/index.d.ts",
"files": [
"dist/",
"src/",
"dom.shim.d.ts"
],
"scripts": {
"build": "npm run build:cjs && npm run build:es",
"build:cjs": "tsc -b tsconfig.cjs.json",
"build:es": "tsc -b tsconfig.es.json",
"build:test": "tsc -b tsconfig.cjs.test.json && tsc -b tsconfig.es.test.json",
"clean": "rm -r ./dist",
"karma": "npm run rollup && karma start --single-run --browsers ChromeHeadless karma.conf.js",
"lint": "eslint . --ext .ts",
"lint:fix": "eslint . --ext .ts --fix",
"rollup": "rollup -c",
"test": "npm run test:cjs && npm run test:es && npm run karma",
"test:cjs": "tsc -b tsconfig.cjs.test.json && mocha 'dist/cjs/test/common/**/*.js' && mocha 'dist/cjs/test/node/**/*.js'",
"test:es": "tsc -b tsconfig.es.test.json && mocha 'dist/es/test/common/**/*.js' --require esm && mocha 'dist/es/test/node/**/*.js' --require esm"
},
"dependencies": {
"@microsoft/kiota-abstractions": "1.0.0-preview.6",
"node-fetch": "^2.6.5",
"tslib": "^2.3.1"
},
"gitHead": "dcb807e06d70b5c893c13e1e398b67d64f06fc87"
"name": "@microsoft/kiota-http-fetchlibrary",
"version": "1.0.0-preview.9",
"description": "Kiota request adapter implementation with fetch",
"keywords": [
"Kiota",
"OpenAPI",
"HTTP",
"fetch"
],
"homepage": "https://github.com/microsoft/kiota-typescript#readme",
"bugs": {
"url": "https://github.com/microsoft/kiota-typescript/issues"
},
"repository": {
"type": "git",
"url": "git://github.com/microsoft/kiota-typescript.git"
},
"license": "MIT",
"author": "Microsoft",
"main": "dist/cjs/src/index.js",
"browser": {
"./dist/es/src/index.js": "./dist/es/src/browser/index.js",
"./dist/es/src/middlewares/middlewareFactory.js": "./dist/es/src/middlewares/browser/middlewareFactory.js"
},
"types": "dist/cjs/src/index.d.ts",
"files": [
"dist/",
"src/",
"dom.shim.d.ts"
],
"scripts": {
"build": "npm run build:cjs && npm run build:es",
"build:cjs": "tsc -b tsconfig.cjs.json",
"build:es": "tsc -b tsconfig.es.json",
"build:test": "tsc -b tsconfig.cjs.test.json && tsc -b tsconfig.es.test.json",
"clean": "rm -r ./dist",
"karma": "npm run rollup && karma start --single-run --browsers ChromeHeadless karma.conf.js",
"lint": "eslint . --ext .ts",
"lint:fix": "eslint . --ext .ts --fix",
"rollup": "rollup -c",
"test": "npm run build && npm run build:test && npm run test:cjs && npm run karma",
"test:cjs": "mocha 'dist/cjs/test/common/**/*.js' && mocha 'dist/cjs/test/node/**/*.js'"
},
"dependencies": {
"@microsoft/kiota-abstractions": "^1.0.0-preview.8",
"@opentelemetry/api": "^1.2.0",
"node-fetch": "^2.6.5",
"tslib": "^2.3.1"
},
"gitHead": "7a256295bd1eb3618b6fee86292b1cea33ffc526"
}

@@ -1,4 +0,6 @@

import { ApiError, AuthenticationProvider, BackingStoreFactory, BackingStoreFactorySingleton, DateOnly, Duration, enableBackingStoreForParseNodeFactory, enableBackingStoreForSerializationWriterFactory, Parsable, ParsableFactory, ParseNode,ParseNodeFactory, ParseNodeFactoryRegistry, RequestAdapter, RequestInformation, ResponseHandler, SerializationWriterFactory, SerializationWriterFactoryRegistry, TimeOnly } from "@microsoft/kiota-abstractions";
import { ApiError, AuthenticationProvider, BackingStoreFactory, BackingStoreFactorySingleton, DateOnly, Duration, enableBackingStoreForParseNodeFactory, enableBackingStoreForSerializationWriterFactory, Parsable, ParsableFactory, ParseNode, ParseNodeFactory, ParseNodeFactoryRegistry, RequestAdapter, RequestInformation, ResponseHandler, SerializationWriterFactory, SerializationWriterFactoryRegistry, TimeOnly } from "@microsoft/kiota-abstractions";
import { Span, SpanStatusCode, trace } from "@opentelemetry/api";
import { HttpClient } from "./httpClient";
import { ObservabilityOptions, ObservabilityOptionsImpl } from "./observabilityOptions";

@@ -11,2 +13,3 @@ export class FetchRequestAdapter implements RequestAdapter {

}
private readonly observabilityOptions: ObservabilityOptionsImpl;
/**

@@ -18,4 +21,5 @@ * Instantiates a new http core service

* @param httpClient the http client to use to execute requests.
* @param observabilityOptions the observability options to use.
*/
public constructor(public readonly authenticationProvider: AuthenticationProvider, private parseNodeFactory: ParseNodeFactory = ParseNodeFactoryRegistry.defaultInstance, private serializationWriterFactory: SerializationWriterFactory = SerializationWriterFactoryRegistry.defaultInstance, private readonly httpClient: HttpClient = new HttpClient()) {
public constructor(public readonly authenticationProvider: AuthenticationProvider, private parseNodeFactory: ParseNodeFactory = ParseNodeFactoryRegistry.defaultInstance, private serializationWriterFactory: SerializationWriterFactory = SerializationWriterFactoryRegistry.defaultInstance, private readonly httpClient: HttpClient = new HttpClient(), observabilityOptions: ObservabilityOptions = new ObservabilityOptionsImpl()) {
if (!authenticationProvider) {

@@ -33,2 +37,7 @@ throw new Error("authentication provider cannot be null");

}
if (!observabilityOptions) {
throw new Error("observability options cannot be null");
} else {
this.observabilityOptions = new ObservabilityOptionsImpl(observabilityOptions);
}
}

@@ -42,141 +51,218 @@ private getResponseContentType = (response: Response): string | undefined => {

};
public sendCollectionOfPrimitiveAsync = async <ResponseType>(requestInfo: RequestInformation, responseType: "string" | "number" | "boolean" | "Date", responseHandler: ResponseHandler | undefined, errorMappings: Record<string, ParsableFactory<Parsable>> | undefined): Promise<ResponseType[] | undefined> => {
private static readonly responseTypeAttributeKey = "com.microsoft.kiota.response.type";
public sendCollectionOfPrimitiveAsync = <ResponseType>(requestInfo: RequestInformation, responseType: "string" | "number" | "boolean" | "Date", responseHandler: ResponseHandler | undefined, errorMappings: Record<string, ParsableFactory<Parsable>> | undefined): Promise<ResponseType[] | undefined> => {
if (!requestInfo) {
throw new Error("requestInfo cannot be null");
}
const response = await this.getHttpResponseMessage(requestInfo);
if (responseHandler) {
return await responseHandler.handleResponseAsync(response, errorMappings);
} else {
return this.startTracingSpan(requestInfo, "sendCollectionOfPrimitiveAsync", async (span) => {
try {
await this.throwFailedResponses(response, errorMappings);
if (this.shouldReturnUndefined(response)) return undefined;
switch (responseType) {
case "string":
case "number":
case "boolean":
case "Date":
// eslint-disable-next-line no-case-declarations
const rootNode = await this.getRootParseNode(response);
if (responseType === "string") {
return rootNode.getCollectionOfPrimitiveValues<string>() as unknown as ResponseType[];
} else if (responseType === "number") {
return rootNode.getCollectionOfPrimitiveValues<number>() as unknown as ResponseType[];
} else if (responseType === "boolean") {
return rootNode.getCollectionOfPrimitiveValues<boolean>() as unknown as ResponseType[];
} else if (responseType === "Date") {
return rootNode.getCollectionOfPrimitiveValues<Date>() as unknown as ResponseType[];
} else if (responseType === "Duration") {
return rootNode.getCollectionOfPrimitiveValues<Duration>() as unknown as ResponseType[];
} else if (responseType === "DateOnly") {
return rootNode.getCollectionOfPrimitiveValues<DateOnly>() as unknown as ResponseType[];
} else if (responseType === "TimeOnly") {
return rootNode.getCollectionOfPrimitiveValues<TimeOnly>() as unknown as ResponseType[];
} else {
throw new Error("unexpected type to deserialize");
const response = await this.getHttpResponseMessage(requestInfo, span);
if (responseHandler) {
span.addEvent(FetchRequestAdapter.eventResponseHandlerInvokedKey);
return await responseHandler.handleResponseAsync(response, errorMappings);
} else {
try {
await this.throwFailedResponses(response, errorMappings, span);
if (this.shouldReturnUndefined(response)) return undefined;
switch (responseType) {
case "string":
case "number":
case "boolean":
case "Date":
// eslint-disable-next-line no-case-declarations
const rootNode = await this.getRootParseNode(response);
return trace.getTracer(this.observabilityOptions.getTracerInstrumentationName()).startActiveSpan(`getCollectionOf${responseType}Value`, (deserializeSpan) => {
try {
span.setAttribute(FetchRequestAdapter.responseTypeAttributeKey, responseType);
if (responseType === "string") {
return rootNode.getCollectionOfPrimitiveValues<string>() as unknown as ResponseType[];
} else if (responseType === "number") {
return rootNode.getCollectionOfPrimitiveValues<number>() as unknown as ResponseType[];
} else if (responseType === "boolean") {
return rootNode.getCollectionOfPrimitiveValues<boolean>() as unknown as ResponseType[];
} else if (responseType === "Date") {
return rootNode.getCollectionOfPrimitiveValues<Date>() as unknown as ResponseType[];
} else if (responseType === "Duration") {
return rootNode.getCollectionOfPrimitiveValues<Duration>() as unknown as ResponseType[];
} else if (responseType === "DateOnly") {
return rootNode.getCollectionOfPrimitiveValues<DateOnly>() as unknown as ResponseType[];
} else if (responseType === "TimeOnly") {
return rootNode.getCollectionOfPrimitiveValues<TimeOnly>() as unknown as ResponseType[];
} else {
throw new Error("unexpected type to deserialize");
}
} finally {
deserializeSpan.end();
}
});
}
} finally {
await this.purgeResponseBody(response);
}
}
} finally {
await this.purgeResponseBody(response);
span.end();
}
}
});
};
public sendCollectionAsync = async <ModelType extends Parsable>(requestInfo: RequestInformation, type: ParsableFactory<ModelType>, responseHandler: ResponseHandler | undefined, errorMappings: Record<string, ParsableFactory<Parsable>> | undefined): Promise<ModelType[] | undefined> => {
public sendCollectionAsync = <ModelType extends Parsable>(requestInfo: RequestInformation, type: ParsableFactory<ModelType>, responseHandler: ResponseHandler | undefined, errorMappings: Record<string, ParsableFactory<Parsable>> | undefined): Promise<ModelType[] | undefined> => {
if (!requestInfo) {
throw new Error("requestInfo cannot be null");
}
const response = await this.getHttpResponseMessage(requestInfo);
if (responseHandler) {
return await responseHandler.handleResponseAsync(response, errorMappings);
} else {
return this.startTracingSpan(requestInfo, "sendCollectionAsync", async (span) => {
try {
await this.throwFailedResponses(response, errorMappings);
if (this.shouldReturnUndefined(response)) return undefined;
const rootNode = await this.getRootParseNode(response);
const result = rootNode.getCollectionOfObjectValues(type);
return result as unknown as ModelType[];
const response = await this.getHttpResponseMessage(requestInfo, span);
if (responseHandler) {
span.addEvent(FetchRequestAdapter.eventResponseHandlerInvokedKey);
return await responseHandler.handleResponseAsync(response, errorMappings);
} else {
try {
await this.throwFailedResponses(response, errorMappings, span);
if (this.shouldReturnUndefined(response)) return undefined;
const rootNode = await this.getRootParseNode(response);
return trace.getTracer(this.observabilityOptions.getTracerInstrumentationName()).startActiveSpan("getCollectionOfObjectValues", (deserializeSpan) => {
try {
const result = rootNode.getCollectionOfObjectValues(type);
span.setAttribute(FetchRequestAdapter.responseTypeAttributeKey, "object[]");
return result as unknown as ModelType[];
} finally {
deserializeSpan.end();
}
});
} finally {
await this.purgeResponseBody(response);
}
}
} finally {
await this.purgeResponseBody(response);
span.end();
}
}
});
};
public sendAsync = async <ModelType extends Parsable>(requestInfo: RequestInformation, type: ParsableFactory<ModelType>, responseHandler: ResponseHandler | undefined, errorMappings: Record<string, ParsableFactory<Parsable>> | undefined): Promise<ModelType | undefined> => {
private startTracingSpan = <T>(requestInfo: RequestInformation, methodName: string, callback: (arg0: Span) => Promise<T>): Promise<T> => {
const urlTemplate = decodeURIComponent(requestInfo.urlTemplate ?? "");
const telemetryPathValue = urlTemplate.replace(/\{\?[^}]+\}/gi, "");
return trace.getTracer(this.observabilityOptions.getTracerInstrumentationName()).startActiveSpan(`${methodName} - ${telemetryPathValue}`, async (span) => {
try {
span.setAttribute("http.uri_template", urlTemplate);
return await callback(span);
} finally {
span.end();
}
});
};
public static readonly eventResponseHandlerInvokedKey = "com.microsoft.kiota.response_handler_invoked";
public sendAsync = <ModelType extends Parsable>(requestInfo: RequestInformation, type: ParsableFactory<ModelType>, responseHandler: ResponseHandler | undefined, errorMappings: Record<string, ParsableFactory<Parsable>> | undefined): Promise<ModelType | undefined> => {
if (!requestInfo) {
throw new Error("requestInfo cannot be null");
}
const response = await this.getHttpResponseMessage(requestInfo);
if (responseHandler) {
return await responseHandler.handleResponseAsync(response, errorMappings);
} else {
return this.startTracingSpan(requestInfo, "sendAsync", async (span) => {
try {
await this.throwFailedResponses(response, errorMappings);
if (this.shouldReturnUndefined(response)) return undefined;
const rootNode = await this.getRootParseNode(response);
const result = rootNode.getObjectValue(type);
return result as unknown as ModelType;
const response = await this.getHttpResponseMessage(requestInfo, span);
if (responseHandler) {
span.addEvent(FetchRequestAdapter.eventResponseHandlerInvokedKey);
return await responseHandler.handleResponseAsync(response, errorMappings);
} else {
try {
await this.throwFailedResponses(response, errorMappings, span);
if (this.shouldReturnUndefined(response)) return undefined;
const rootNode = await this.getRootParseNode(response);
return trace.getTracer(this.observabilityOptions.getTracerInstrumentationName()).startActiveSpan("getObjectValue", (deserializeSpan) => {
try {
span.setAttribute(FetchRequestAdapter.responseTypeAttributeKey, "object");
const result = rootNode.getObjectValue(type);
return result as unknown as ModelType;
} finally {
deserializeSpan.end();
}
});
} finally {
await this.purgeResponseBody(response);
}
}
} finally {
await this.purgeResponseBody(response);
span.end();
}
}
}) as Promise<ModelType>;
};
public sendPrimitiveAsync = async <ResponseType>(requestInfo: RequestInformation, responseType: "string" | "number" | "boolean" | "Date" | "ArrayBuffer", responseHandler: ResponseHandler | undefined, errorMappings: Record<string, ParsableFactory<Parsable>> | undefined): Promise<ResponseType | undefined> => {
public sendPrimitiveAsync = <ResponseType>(requestInfo: RequestInformation, responseType: "string" | "number" | "boolean" | "Date" | "ArrayBuffer", responseHandler: ResponseHandler | undefined, errorMappings: Record<string, ParsableFactory<Parsable>> | undefined): Promise<ResponseType | undefined> => {
if (!requestInfo) {
throw new Error("requestInfo cannot be null");
}
const response = await this.getHttpResponseMessage(requestInfo);
if (responseHandler) {
return await responseHandler.handleResponseAsync(response, errorMappings);
} else {
return this.startTracingSpan(requestInfo, "sendPrimitiveAsync", async (span) => {
try {
await this.throwFailedResponses(response, errorMappings);
if (this.shouldReturnUndefined(response)) return undefined;
switch (responseType) {
case "ArrayBuffer":
// eslint-disable-next-line no-case-declarations
if (!response.body) {
return undefined;
const response = await this.getHttpResponseMessage(requestInfo, span);
if (responseHandler) {
span.addEvent(FetchRequestAdapter.eventResponseHandlerInvokedKey);
return await responseHandler.handleResponseAsync(response, errorMappings);
} else {
try {
await this.throwFailedResponses(response, errorMappings, span);
if (this.shouldReturnUndefined(response)) return undefined;
switch (responseType) {
case "ArrayBuffer":
// eslint-disable-next-line no-case-declarations
if (!response.body) {
return undefined;
}
return (await response.arrayBuffer()) as unknown as ResponseType;
case "string":
case "number":
case "boolean":
case "Date":
// eslint-disable-next-line no-case-declarations
const rootNode = await this.getRootParseNode(response);
span.setAttribute(FetchRequestAdapter.responseTypeAttributeKey, responseType);
return trace.getTracer(this.observabilityOptions.getTracerInstrumentationName()).startActiveSpan(`get${responseType}Value`, (deserializeSpan) => {
try {
if (responseType === "string") {
return rootNode.getStringValue() as unknown as ResponseType;
} else if (responseType === "number") {
return rootNode.getNumberValue() as unknown as ResponseType;
} else if (responseType === "boolean") {
return rootNode.getBooleanValue() as unknown as ResponseType;
} else if (responseType === "Date") {
return rootNode.getDateValue() as unknown as ResponseType;
} else if (responseType === "Duration") {
return rootNode.getDurationValue() as unknown as ResponseType;
} else if (responseType === "DateOnly") {
return rootNode.getDateOnlyValue() as unknown as ResponseType;
} else if (responseType === "TimeOnly") {
return rootNode.getTimeOnlyValue() as unknown as ResponseType;
} else {
throw new Error("unexpected type to deserialize");
}
} finally {
deserializeSpan.end();
}
});
}
return (await response.arrayBuffer()) as unknown as ResponseType;
case "string":
case "number":
case "boolean":
case "Date":
// eslint-disable-next-line no-case-declarations
const rootNode = await this.getRootParseNode(response);
if (responseType === "string") {
return rootNode.getStringValue() as unknown as ResponseType;
} else if (responseType === "number") {
return rootNode.getNumberValue() as unknown as ResponseType;
} else if (responseType === "boolean") {
return rootNode.getBooleanValue() as unknown as ResponseType;
} else if (responseType === "Date") {
return rootNode.getDateValue() as unknown as ResponseType;
} else if (responseType === "Duration") {
return rootNode.getDurationValue() as unknown as ResponseType;
} else if (responseType === "DateOnly") {
return rootNode.getDateOnlyValue() as unknown as ResponseType;
} else if (responseType === "TimeOnly") {
return rootNode.getTimeOnlyValue() as unknown as ResponseType;
} else {
throw new Error("unexpected type to deserialize");
}
} finally {
await this.purgeResponseBody(response);
}
}
} finally {
await this.purgeResponseBody(response);
span.end();
}
}
}) as Promise<ResponseType>;
};
public sendNoResponseContentAsync = async (requestInfo: RequestInformation, responseHandler: ResponseHandler | undefined, errorMappings: Record<string, ParsableFactory<Parsable>> | undefined): Promise<void> => {
public sendNoResponseContentAsync = (requestInfo: RequestInformation, responseHandler: ResponseHandler | undefined, errorMappings: Record<string, ParsableFactory<Parsable>> | undefined): Promise<void> => {
if (!requestInfo) {
throw new Error("requestInfo cannot be null");
}
const response = await this.getHttpResponseMessage(requestInfo);
if (responseHandler) {
return await responseHandler.handleResponseAsync(response, errorMappings);
}
try {
await this.throwFailedResponses(response, errorMappings);
} finally {
await this.purgeResponseBody(response);
}
return this.startTracingSpan(requestInfo, "sendNoResponseContentAsync", async (span) => {
try {
const response = await this.getHttpResponseMessage(requestInfo, span);
if (responseHandler) {
span.addEvent(FetchRequestAdapter.eventResponseHandlerInvokedKey);
return await responseHandler.handleResponseAsync(response, errorMappings);
}
try {
await this.throwFailedResponses(response, errorMappings, span);
} finally {
await this.purgeResponseBody(response);
}
} finally {
span.end();
}
});
};

@@ -191,8 +277,14 @@ public enableBackingStore = (backingStoreFactory?: BackingStoreFactory | undefined): void => {

};
private getRootParseNode = async (response: Response): Promise<ParseNode> => {
const payload = await response.arrayBuffer();
const responseContentType = this.getResponseContentType(response);
if (!responseContentType) throw new Error("no response content type found for deserialization");
private getRootParseNode = (response: Response): Promise<ParseNode> => {
return trace.getTracer(this.observabilityOptions.getTracerInstrumentationName()).startActiveSpan("getRootParseNode", async (span) => {
try {
const payload = await response.arrayBuffer();
const responseContentType = this.getResponseContentType(response);
if (!responseContentType) throw new Error("no response content type found for deserialization");
return this.parseNodeFactory.getRootParseNode(responseContentType, payload);
return this.parseNodeFactory.getRootParseNode(responseContentType, payload);
} finally {
span.end();
}
});
};

@@ -208,40 +300,98 @@ private shouldReturnUndefined = (response: Response): boolean => {

};
private throwFailedResponses = async (response: Response, errorMappings: Record<string, ParsableFactory<Parsable>> | undefined): Promise<void> => {
if (response.ok) return;
public static readonly errorMappingFoundAttributeName = "com.microsoft.kiota.error.mapping_found";
public static readonly errorBodyFoundAttributeName = "com.microsoft.kiota.error.body_found";
private throwFailedResponses = (response: Response, errorMappings: Record<string, ParsableFactory<Parsable>> | undefined, spanForAttributes: Span): Promise<void> => {
return trace.getTracer(this.observabilityOptions.getTracerInstrumentationName()).startActiveSpan("throwFailedResponses", async (span) => {
try {
if (response.ok) return;
const statusCode = response.status;
const statusCodeAsString = statusCode.toString();
if (!errorMappings || (!errorMappings[statusCodeAsString] && !(statusCode >= 400 && statusCode < 500 && errorMappings["4XX"]) && !(statusCode >= 500 && statusCode < 600 && errorMappings["5XX"]))) throw new ApiError("the server returned an unexpected status code and no error class is registered for this code " + statusCode);
spanForAttributes.setStatus({
code: SpanStatusCode.ERROR,
message: "received_error_response",
});
const factory = errorMappings[statusCodeAsString] ?? (statusCode >= 400 && statusCode < 500 ? errorMappings["4XX"] : undefined) ?? (statusCode >= 500 && statusCode < 600 ? errorMappings["5XX"] : undefined);
const statusCode = response.status;
const statusCodeAsString = statusCode.toString();
if (!errorMappings || (!errorMappings[statusCodeAsString] && !(statusCode >= 400 && statusCode < 500 && errorMappings["4XX"]) && !(statusCode >= 500 && statusCode < 600 && errorMappings["5XX"]))) {
spanForAttributes.setAttribute(FetchRequestAdapter.errorMappingFoundAttributeName, false);
const error = new ApiError("the server returned an unexpected status code and no error class is registered for this code " + statusCode);
spanForAttributes.recordException(error);
throw error;
}
spanForAttributes.setAttribute(FetchRequestAdapter.errorMappingFoundAttributeName, true);
const rootNode = await this.getRootParseNode(response);
const error = rootNode.getObjectValue(factory);
const factory = errorMappings[statusCodeAsString] ?? (statusCode >= 400 && statusCode < 500 ? errorMappings["4XX"] : undefined) ?? (statusCode >= 500 && statusCode < 600 ? errorMappings["5XX"] : undefined);
if (error) throw error;
else throw new ApiError("unexpected error type" + typeof error);
const rootNode = await this.getRootParseNode(response);
let error = trace.getTracer(this.observabilityOptions.getTracerInstrumentationName()).startActiveSpan("getObjectValue", (deserializeSpan) => {
try {
return rootNode.getObjectValue(factory);
} finally {
deserializeSpan.end();
}
});
spanForAttributes.setAttribute(FetchRequestAdapter.errorBodyFoundAttributeName, !!error);
if (!error) error = new ApiError("unexpected error type" + typeof error) as unknown as Parsable;
spanForAttributes.recordException(error as unknown as Error);
throw error;
} finally {
span.end();
}
});
};
private getHttpResponseMessage = async (requestInfo: RequestInformation, claims?: string): Promise<Response> => {
if (!requestInfo) {
throw new Error("requestInfo cannot be null");
}
this.setBaseUrlForRequestInformation(requestInfo);
const additionalContext = {} as Record<string, unknown>;
if (claims) {
additionalContext["claims"] = claims;
}
await this.authenticationProvider.authenticateRequest(requestInfo, additionalContext);
private getHttpResponseMessage = (requestInfo: RequestInformation, spanForAttributes: Span, claims?: string): Promise<Response> => {
return trace.getTracer(this.observabilityOptions.getTracerInstrumentationName()).startActiveSpan("getHttpResponseMessage", async (span) => {
try {
if (!requestInfo) {
throw new Error("requestInfo cannot be null");
}
this.setBaseUrlForRequestInformation(requestInfo);
const additionalContext = {} as Record<string, unknown>;
if (claims) {
additionalContext["claims"] = claims;
}
await this.authenticationProvider.authenticateRequest(requestInfo, additionalContext);
const request = this.getRequestFromRequestInformation(requestInfo);
const response = await this.httpClient.executeFetch(requestInfo.URL, request, requestInfo.getRequestOptions());
const request = await this.getRequestFromRequestInformation(requestInfo, spanForAttributes);
if (this.observabilityOptions) {
requestInfo.addRequestOptions([this.observabilityOptions]);
}
let response = await this.httpClient.executeFetch(requestInfo.URL, request, requestInfo.getRequestOptions());
return await this.retryCAEResponseIfRequired(requestInfo, response, claims);
response = await this.retryCAEResponseIfRequired(requestInfo, response, spanForAttributes, claims);
if (response) {
const responseContentLength = response.headers.get("Content-Length");
if (responseContentLength) {
spanForAttributes.setAttribute("http.response_content_length", parseInt(responseContentLength));
}
const responseContentType = response.headers.get("Content-Type");
if (responseContentType) {
spanForAttributes.setAttribute("http.response_content_type", responseContentType);
}
spanForAttributes.setAttribute("http.status_code", response.status);
// getting the http.flavor (protocol version) is impossible with fetch API
}
return response;
} finally {
span.end();
}
});
};
private retryCAEResponseIfRequired = async (requestInfo: RequestInformation, response: Response, claims?: string) => {
const responseClaims = this.getClaimsFromResponse(response, claims);
if (responseClaims) {
await this.purgeResponseBody(response);
return await this.getHttpResponseMessage(requestInfo, responseClaims);
}
return response;
public static readonly authenticateChallengedEventKey = "com.microsoft.kiota.authenticate_challenge_received";
private retryCAEResponseIfRequired = async (requestInfo: RequestInformation, response: Response, spanForAttributes: Span, claims?: string) => {
return trace.getTracer(this.observabilityOptions.getTracerInstrumentationName()).startActiveSpan("retryCAEResponseIfRequired", async (span) => {
try {
const responseClaims = this.getClaimsFromResponse(response, claims);
if (responseClaims) {
span.addEvent(FetchRequestAdapter.authenticateChallengedEventKey);
spanForAttributes.setAttribute("http.retry_count", 1);
await this.purgeResponseBody(response);
return await this.getHttpResponseMessage(requestInfo, spanForAttributes, responseClaims);
}
return response;
} finally {
span.end();
}
});
};

@@ -268,10 +418,37 @@ private getClaimsFromResponse = (response: Response, claims?: string) => {

};
private getRequestFromRequestInformation = (requestInfo: RequestInformation): RequestInit => {
const request = {
method: requestInfo.httpMethod?.toString(),
headers: requestInfo.headers,
body: requestInfo.content,
} as RequestInit;
return request;
private getRequestFromRequestInformation = (requestInfo: RequestInformation, spanForAttributes: Span): Promise<RequestInit> => {
return trace.getTracer(this.observabilityOptions.getTracerInstrumentationName()).startActiveSpan("getRequestFromRequestInformation", async (span) => {
try {
const method = requestInfo.httpMethod?.toString();
const uri = requestInfo.URL;
spanForAttributes.setAttribute("http.method", method ?? "");
const uriContainsScheme = uri.indexOf("://") > -1;
const schemeSplatUri = uri.split("://");
if (uriContainsScheme) {
spanForAttributes.setAttribute("http.scheme", schemeSplatUri[0]);
}
const uriWithoutScheme = uriContainsScheme ? schemeSplatUri[1] : uri;
spanForAttributes.setAttribute("http.host", uriWithoutScheme.split("/")[0]);
if (this.observabilityOptions.includeEUIIAttributes) {
spanForAttributes.setAttribute("http.uri", decodeURIComponent(uri));
}
const requestContentLength = requestInfo.headers["Content-Length"];
if (requestContentLength) {
spanForAttributes.setAttribute("http.request_content_length", parseInt(requestContentLength));
}
const requestContentType = requestInfo.headers["Content-Type"];
if (requestContentType) {
spanForAttributes.setAttribute("http.request_content_type", requestContentType);
}
const request = {
method,
headers: requestInfo.headers,
body: requestInfo.content,
} as RequestInit;
return request;
} finally {
span.end();
}
});
};
}

@@ -13,4 +13,6 @@ /**

import { HttpMethod, RequestOption } from "@microsoft/kiota-abstractions";
import { Span, trace } from "@opentelemetry/api";
import { FetchHeaders, FetchRequestInit, FetchResponse } from "../utils/fetchDefinitions";
import { getObservabilityOptionsFromRequest } from "../observabilityOptions";
import { FetchHeaders, FetchRequestInit } from "../utils/fetchDefinitions";
import { Middleware } from "./middleware";

@@ -190,4 +192,20 @@ import { httpStatusCode, methodStatusCode } from "./options/ChaosHandlerData";

public async execute(url: string, requestInit: RequestInit, requestOptions?: Record<string, RequestOption> | undefined): Promise<Response> {
public execute(url: string, requestInit: RequestInit, requestOptions?: Record<string, RequestOption> | undefined): Promise<Response> {
const obsOptions = getObservabilityOptionsFromRequest(requestOptions);
if (obsOptions) {
return trace.getTracer(obsOptions.getTracerInstrumentationName()).startActiveSpan("chaosHandler - execute", (span) => {
try {
span.setAttribute("com.microsoft.kiota.handler.chaos.enable", true);
return this.runChaos(url, requestInit, requestOptions);
} finally {
span.end();
}
});
}
return this.runChaos(url, requestInit, requestOptions);
}
public static readonly chaosHandlerTriggeredEventKey = "com.microsoft.kiota.chaos_handler_triggered";
private runChaos(url: string, requestInit: RequestInit, requestOptions?: Record<string, RequestOption> | undefined, span?: Span): Promise<Response> {
if (Math.floor(Math.random() * 100) < this.options.chaosPercentage) {
span?.addEvent(ChaosHandler.chaosHandlerTriggeredEventKey);
return Promise.resolve(this.createChaosResponse(url, requestInit as FetchRequestInit));

@@ -198,5 +216,5 @@ } else {

}
return await this.next.execute(url, requestInit, requestOptions);
return this.next.execute(url, requestInit, requestOptions);
}
}
}

@@ -9,3 +9,5 @@ /**

import { RequestOption } from "@microsoft/kiota-abstractions";
import { trace } from "@opentelemetry/api";
import { getObservabilityOptionsFromRequest } from "../observabilityOptions";
import { Middleware } from "./middleware";

@@ -25,3 +27,3 @@ import { ParametersNameDecodingHandlerOptions, ParametersNameDecodingHandlerOptionsKey } from "./options/parametersNameDecodingOptions";

*/
public constructor(private options: ParametersNameDecodingHandlerOptions = new ParametersNameDecodingHandlerOptions()) {
public constructor(private readonly options: ParametersNameDecodingHandlerOptions = new ParametersNameDecodingHandlerOptions()) {
if (!options) {

@@ -47,2 +49,16 @@ throw new Error("The options parameter is required.");

}
const obsOptions = getObservabilityOptionsFromRequest(requestOptions);
if (obsOptions) {
return trace.getTracer(obsOptions.getTracerInstrumentationName()).startActiveSpan("parametersNameDecodingHandler - execute", (span) => {
try {
span.setAttribute("com.microsoft.kiota.handler.parameters_name_decoding.enable", currentOptions.enable);
return this.decodeParameters(url, requestInit, currentOptions, requestOptions);
} finally {
span.end();
}
});
}
return this.decodeParameters(url, requestInit, currentOptions, requestOptions);
}
private decodeParameters(url: string, requestInit: RequestInit, currentOptions: ParametersNameDecodingHandlerOptions, requestOptions?: Record<string, RequestOption>): Promise<Response> {
let updatedUrl = url;

@@ -49,0 +65,0 @@ if (currentOptions && currentOptions.enable && url.indexOf("%") > -1 && currentOptions.charactersToDecode && currentOptions.charactersToDecode.length > 0) {

@@ -12,4 +12,6 @@ /**

import { RequestOption, HttpMethod } from "@microsoft/kiota-abstractions";
import { HttpMethod, RequestOption } from "@microsoft/kiota-abstractions";
import { trace } from "@opentelemetry/api";
import { getObservabilityOptionsFromRequest } from "../observabilityOptions";
import { FetchRequestInit, FetchResponse } from "../utils/fetchDefinitions";

@@ -153,5 +155,6 @@ import { Middleware } from "./middleware";

* @param {RedirectHandlerOptions} currentOptions - The redirect handler options instance
* @param {string} tracerName - The name to use for the tracer
* @returns A promise that resolves to nothing
*/
private async executeWithRedirect(url: string, fetchRequestInit: FetchRequestInit, redirectCount: number, currentOptions: RedirectHandlerOptions, requestOptions?: Record<string, RequestOption>): Promise<FetchResponse> {
private async executeWithRedirect(url: string, fetchRequestInit: FetchRequestInit, redirectCount: number, currentOptions: RedirectHandlerOptions, requestOptions?: Record<string, RequestOption>, tracerName?: string): Promise<FetchResponse> {
const response = await this.next?.execute(url, fetchRequestInit as RequestInit, requestOptions);

@@ -175,2 +178,13 @@ if (!response) {

}
if (tracerName) {
return trace.getTracer(tracerName).startActiveSpan(`redirectHandler - redirect ${redirectCount}`, (span) => {
try {
span.setAttribute("com.microsoft.kiota.handler.redirect.count", redirectCount);
span.setAttribute("http.status_code", response.status);
return this.executeWithRedirect(url, fetchRequestInit, redirectCount, currentOptions, requestOptions);
} finally {
span.end();
}
});
}
return await this.executeWithRedirect(url, fetchRequestInit, redirectCount, currentOptions, requestOptions);

@@ -196,4 +210,15 @@ } else {

(requestInit as FetchRequestInit).redirect = RedirectHandler.MANUAL_REDIRECT;
const obsOptions = getObservabilityOptionsFromRequest(requestOptions);
if (obsOptions) {
return trace.getTracer(obsOptions.getTracerInstrumentationName()).startActiveSpan("redirectHandler - execute", (span) => {
try {
span.setAttribute("com.microsoft.kiota.handler.redirect.enable", true);
return this.executeWithRedirect(url, requestInit as FetchRequestInit, redirectCount, currentOptions, requestOptions, obsOptions.getTracerInstrumentationName());
} finally {
span.end();
}
});
}
return this.executeWithRedirect(url, requestInit as FetchRequestInit, redirectCount, currentOptions, requestOptions);
}
}

@@ -13,3 +13,5 @@ /**

import { HttpMethod, RequestOption } from "@microsoft/kiota-abstractions";
import { trace } from "@opentelemetry/api";
import { getObservabilityOptionsFromRequest } from "../observabilityOptions";
import { FetchRequestInit, FetchResponse } from "../utils/fetchDefinitions";

@@ -156,5 +158,6 @@ import { getRequestHeader, setRequestHeader } from "../utils/headersUtil";

* @param {RetryHandlerOptions} currentOptions - The retry middleware options instance
* @param {string} tracerName - The name to use for the tracer
* @returns A Promise that resolves to nothing
*/
private async executeWithRetry(url: string, fetchRequestInit: FetchRequestInit, retryAttempts: number, currentOptions: RetryHandlerOptions, requestOptions?: Record<string, RequestOption>): Promise<FetchResponse> {
private async executeWithRetry(url: string, fetchRequestInit: FetchRequestInit, retryAttempts: number, currentOptions: RetryHandlerOptions, requestOptions?: Record<string, RequestOption>, tracerName?: string): Promise<FetchResponse> {
const response = await this.next?.execute(url, fetchRequestInit as RequestInit, requestOptions);

@@ -164,9 +167,21 @@ if (!response) {

}
if (retryAttempts < currentOptions.maxRetries && this.isRetry(response!) && this.isBuffered(fetchRequestInit) && currentOptions.shouldRetry(currentOptions.delay, retryAttempts, url, fetchRequestInit! as RequestInit, response)) {
if (retryAttempts < currentOptions.maxRetries && this.isRetry(response) && this.isBuffered(fetchRequestInit) && currentOptions.shouldRetry(currentOptions.delay, retryAttempts, url, fetchRequestInit as RequestInit, response)) {
++retryAttempts;
setRequestHeader(fetchRequestInit, RetryHandler.RETRY_ATTEMPT_HEADER, retryAttempts.toString());
if (response) {
const delay = this.getDelay(response!, retryAttempts, currentOptions.delay);
const delay = this.getDelay(response, retryAttempts, currentOptions.delay);
await this.sleep(delay);
}
if (tracerName) {
return await trace.getTracer(tracerName).startActiveSpan(`retryHandler - attempt ${retryAttempts}`, (span) => {
try {
span.setAttribute("http.retry_count", retryAttempts);
span.setAttribute("http.status_code", response.status);
return this.executeWithRetry(url, fetchRequestInit, retryAttempts, currentOptions, requestOptions);
} finally {
span.end();
}
});
}
return await this.executeWithRetry(url, fetchRequestInit, retryAttempts, currentOptions, requestOptions);

@@ -192,4 +207,15 @@ } else {

}
const obsOptions = getObservabilityOptionsFromRequest(requestOptions);
if (obsOptions) {
return trace.getTracer(obsOptions.getTracerInstrumentationName()).startActiveSpan("retryHandler - execute", (span) => {
try {
span.setAttribute("com.microsoft.kiota.handler.retry.enable", true);
return this.executeWithRetry(url, requestInit as FetchRequestInit, retryAttempts, currentOptions, requestOptions, obsOptions.getTracerInstrumentationName());
} finally {
span.end();
}
});
}
return this.executeWithRetry(url, requestInit as FetchRequestInit, retryAttempts, currentOptions, requestOptions);
}
}

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc