UNPKG

@microsoft/microsoft-graph-client

Version:
460 lines 21.6 kB
"use strict"; /** * ------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. * See License in the project root for license information. * ------------------------------------------------------------------------------------------- */ Object.defineProperty(exports, "__esModule", { value: true }); exports.BatchRequestContent = void 0; var tslib_1 = require("tslib"); /** * @module BatchRequestContent */ var RequestMethod_1 = require("../RequestMethod"); /** * @class * Class for handling BatchRequestContent */ var BatchRequestContent = /** @class */ (function () { /** * @public * @constructor * Constructs a BatchRequestContent instance * @param {BatchRequestStep[]} [requests] - Array of requests value * @returns An instance of a BatchRequestContent */ function BatchRequestContent(requests) { this.requests = new Map(); if (typeof requests !== "undefined") { var limit = BatchRequestContent.requestLimit; if (requests.length > limit) { var error = new Error("Maximum requests limit exceeded, Max allowed number of requests are ".concat(limit)); error.name = "Limit Exceeded Error"; throw error; } for (var _i = 0, requests_1 = requests; _i < requests_1.length; _i++) { var req = requests_1[_i]; this.addRequest(req); } } } /** * @private * @static * Validates the dependency chain of the requests * * Note: * Individual requests can depend on other individual requests. Currently, requests can only depend on a single other request, and must follow one of these three patterns: * 1. Parallel - no individual request states a dependency in the dependsOn property. * 2. Serial - all individual requests depend on the previous individual request. * 3. Same - all individual requests that state a dependency in the dependsOn property, state the same dependency. * As JSON batching matures, these limitations will be removed. * @see {@link https://developer.microsoft.com/en-us/graph/docs/concepts/known_issues#json-batching} * * @param {Map<string, BatchRequestStep>} requests - The map of requests. * @returns The boolean indicating the validation status */ BatchRequestContent.validateDependencies = function (requests) { var isParallel = function (reqs) { var iterator = reqs.entries(); var cur = iterator.next(); while (!cur.done) { var curReq = cur.value[1]; if (curReq.dependsOn !== undefined && curReq.dependsOn.length > 0) { return false; } cur = iterator.next(); } return true; }; var isSerial = function (reqs) { var iterator = reqs.entries(); var cur = iterator.next(); var firstRequest = cur.value[1]; if (firstRequest.dependsOn !== undefined && firstRequest.dependsOn.length > 0) { return false; } var prev = cur; cur = iterator.next(); while (!cur.done) { var curReq = cur.value[1]; if (curReq.dependsOn === undefined || curReq.dependsOn.length !== 1 || curReq.dependsOn[0] !== prev.value[1].id) { return false; } prev = cur; cur = iterator.next(); } return true; }; var isSame = function (reqs) { var iterator = reqs.entries(); var cur = iterator.next(); var firstRequest = cur.value[1]; var dependencyId; if (firstRequest.dependsOn === undefined || firstRequest.dependsOn.length === 0) { dependencyId = firstRequest.id; } else { if (firstRequest.dependsOn.length === 1) { var fDependencyId = firstRequest.dependsOn[0]; if (fDependencyId !== firstRequest.id && reqs.has(fDependencyId)) { dependencyId = fDependencyId; } else { return false; } } else { return false; } } cur = iterator.next(); while (!cur.done) { var curReq = cur.value[1]; if ((curReq.dependsOn === undefined || curReq.dependsOn.length === 0) && dependencyId !== curReq.id) { return false; } if (curReq.dependsOn !== undefined && curReq.dependsOn.length !== 0) { if (curReq.dependsOn.length === 1 && (curReq.id === dependencyId || curReq.dependsOn[0] !== dependencyId)) { return false; } if (curReq.dependsOn.length > 1) { return false; } } cur = iterator.next(); } return true; }; if (requests.size === 0) { var error = new Error("Empty requests map, Please provide at least one request."); error.name = "Empty Requests Error"; throw error; } return isParallel(requests) || isSerial(requests) || isSame(requests); }; /** * @private * @static * @async * Converts Request Object instance to a JSON * @param {IsomorphicRequest} request - The IsomorphicRequest Object instance * @returns A promise that resolves to JSON representation of a request */ BatchRequestContent.getRequestData = function (request) { return tslib_1.__awaiter(this, void 0, void 0, function () { var requestData, hasHttpRegex, headers, _a; return tslib_1.__generator(this, function (_b) { switch (_b.label) { case 0: requestData = { url: "", }; hasHttpRegex = new RegExp("^https?://"); // Stripping off hostname, port and url scheme requestData.url = hasHttpRegex.test(request.url) ? "/" + request.url.split(/.*?\/\/.*?\//)[1] : request.url; requestData.method = request.method; headers = {}; request.headers.forEach(function (value, key) { headers[key] = value; }); if (Object.keys(headers).length) { requestData.headers = headers; } if (!(request.method === RequestMethod_1.RequestMethod.PATCH || request.method === RequestMethod_1.RequestMethod.POST || request.method === RequestMethod_1.RequestMethod.PUT)) return [3 /*break*/, 2]; _a = requestData; return [4 /*yield*/, BatchRequestContent.getRequestBody(request)]; case 1: _a.body = _b.sent(); _b.label = 2; case 2: /** * TODO: Check any other property needs to be used from the Request object and add them */ return [2 /*return*/, requestData]; } }); }); }; /** * @private * @static * @async * Gets the body of a Request object instance * @param {IsomorphicRequest} request - The IsomorphicRequest object instance * @returns The Promise that resolves to a body value of a Request */ BatchRequestContent.getRequestBody = function (request) { return tslib_1.__awaiter(this, void 0, void 0, function () { var bodyParsed, body, cloneReq, e_1, blob_1, reader_1, buffer, e_2; return tslib_1.__generator(this, function (_a) { switch (_a.label) { case 0: bodyParsed = false; _a.label = 1; case 1: _a.trys.push([1, 3, , 4]); cloneReq = request.clone(); return [4 /*yield*/, cloneReq.json()]; case 2: body = _a.sent(); bodyParsed = true; return [3 /*break*/, 4]; case 3: e_1 = _a.sent(); return [3 /*break*/, 4]; case 4: if (!!bodyParsed) return [3 /*break*/, 12]; _a.label = 5; case 5: _a.trys.push([5, 11, , 12]); if (!(typeof Blob !== "undefined")) return [3 /*break*/, 8]; return [4 /*yield*/, request.blob()]; case 6: blob_1 = _a.sent(); reader_1 = new FileReader(); return [4 /*yield*/, new Promise(function (resolve) { reader_1.addEventListener("load", function () { var dataURL = reader_1.result; /** * Some valid dataURL schemes: * 1. data:text/vnd-example+xyz;foo=bar;base64,R0lGODdh * 2. data:text/plain;charset=UTF-8;page=21,the%20data:1234,5678 * 3. data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg== * 4. data:image/png,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg== * 5. data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg== * @see Syntax {@link https://en.wikipedia.org/wiki/Data_URI_scheme} for more */ var regex = new RegExp("^s*data:(.+?/.+?(;.+?=.+?)*)?(;base64)?,(.*)s*$"); var segments = regex.exec(dataURL); resolve(segments[4]); }, false); reader_1.readAsDataURL(blob_1); })]; case 7: body = _a.sent(); return [3 /*break*/, 10]; case 8: if (!(typeof Buffer !== "undefined")) return [3 /*break*/, 10]; return [4 /*yield*/, request.buffer()]; case 9: buffer = _a.sent(); body = buffer.toString("base64"); _a.label = 10; case 10: bodyParsed = true; return [3 /*break*/, 12]; case 11: e_2 = _a.sent(); return [3 /*break*/, 12]; case 12: return [2 /*return*/, body]; } }); }); }; /** * @public * Adds a request to the batch request content * @param {BatchRequestStep} request - The request value * @returns The id of the added request */ BatchRequestContent.prototype.addRequest = function (request) { var limit = BatchRequestContent.requestLimit; if (request.id === "") { var error = new Error("Id for a request is empty, Please provide an unique id"); error.name = "Empty Id For Request"; throw error; } if (this.requests.size === limit) { var error = new Error("Maximum requests limit exceeded, Max allowed number of requests are ".concat(limit)); error.name = "Limit Exceeded Error"; throw error; } if (this.requests.has(request.id)) { var error = new Error("Adding request with duplicate id ".concat(request.id, ", Make the id of the requests unique")); error.name = "Duplicate RequestId Error"; throw error; } this.requests.set(request.id, request); return request.id; }; /** * @public * Removes request from the batch payload and its dependencies from all dependents * @param {string} requestId - The id of a request that needs to be removed * @returns The boolean indicating removed status */ BatchRequestContent.prototype.removeRequest = function (requestId) { var deleteStatus = this.requests.delete(requestId); var iterator = this.requests.entries(); var cur = iterator.next(); /** * Removing dependencies where this request is present as a dependency */ while (!cur.done) { var dependencies = cur.value[1].dependsOn; if (typeof dependencies !== "undefined") { var index = dependencies.indexOf(requestId); if (index !== -1) { dependencies.splice(index, 1); } if (dependencies.length === 0) { delete cur.value[1].dependsOn; } } cur = iterator.next(); } return deleteStatus; }; /** * @public * @async * Serialize content from BatchRequestContent instance * @returns The body content to make batch request */ BatchRequestContent.prototype.getContent = function () { return tslib_1.__awaiter(this, void 0, void 0, function () { var requests, requestBody, iterator, cur, error, error, requestStep, batchRequestData, error; return tslib_1.__generator(this, function (_a) { switch (_a.label) { case 0: requests = []; requestBody = { requests: requests, }; iterator = this.requests.entries(); cur = iterator.next(); if (cur.done) { error = new Error("No requests added yet, Please add at least one request."); error.name = "Empty Payload"; throw error; } if (!BatchRequestContent.validateDependencies(this.requests)) { error = new Error("Invalid dependency found, Dependency should be:\n1. Parallel - no individual request states a dependency in the dependsOn property.\n2. Serial - all individual requests depend on the previous individual request.\n3. Same - all individual requests that state a dependency in the dependsOn property, state the same dependency."); error.name = "Invalid Dependency"; throw error; } _a.label = 1; case 1: if (!!cur.done) return [3 /*break*/, 3]; requestStep = cur.value[1]; return [4 /*yield*/, BatchRequestContent.getRequestData(requestStep.request)]; case 2: batchRequestData = (_a.sent()); /** * @see{@https://tools.ietf.org/html/rfc7578#section-4.4} * TODO- Setting/Defaulting of content-type header to the correct value * @see {@link https://developer.microsoft.com/en-us/graph/docs/concepts/json_batching#request-format} */ if (batchRequestData.body !== undefined && (batchRequestData.headers === undefined || batchRequestData.headers["content-type"] === undefined)) { error = new Error("Content-type header is not mentioned for request #".concat(requestStep.id, ", For request having body, Content-type header should be mentioned")); error.name = "Invalid Content-type header"; throw error; } batchRequestData.id = requestStep.id; if (requestStep.dependsOn !== undefined && requestStep.dependsOn.length > 0) { batchRequestData.dependsOn = requestStep.dependsOn; } requests.push(batchRequestData); cur = iterator.next(); return [3 /*break*/, 1]; case 3: requestBody.requests = requests; return [2 /*return*/, requestBody]; } }); }); }; /** * @public * Adds a dependency for a given dependent request * @param {string} dependentId - The id of the dependent request * @param {string} [dependencyId] - The id of the dependency request, if not specified the preceding request will be considered as a dependency * @returns Nothing */ BatchRequestContent.prototype.addDependency = function (dependentId, dependencyId) { if (!this.requests.has(dependentId)) { var error = new Error("Dependent ".concat(dependentId, " does not exists, Please check the id")); error.name = "Invalid Dependent"; throw error; } if (typeof dependencyId !== "undefined" && !this.requests.has(dependencyId)) { var error = new Error("Dependency ".concat(dependencyId, " does not exists, Please check the id")); error.name = "Invalid Dependency"; throw error; } if (typeof dependencyId !== "undefined") { var dependent = this.requests.get(dependentId); if (dependent.dependsOn === undefined) { dependent.dependsOn = []; } if (dependent.dependsOn.indexOf(dependencyId) !== -1) { var error = new Error("Dependency ".concat(dependencyId, " is already added for the request ").concat(dependentId)); error.name = "Duplicate Dependency"; throw error; } dependent.dependsOn.push(dependencyId); } else { var iterator = this.requests.entries(); var prev = void 0; var cur = iterator.next(); while (!cur.done && cur.value[1].id !== dependentId) { prev = cur; cur = iterator.next(); } if (typeof prev !== "undefined") { var dId = prev.value[0]; if (cur.value[1].dependsOn === undefined) { cur.value[1].dependsOn = []; } if (cur.value[1].dependsOn.indexOf(dId) !== -1) { var error = new Error("Dependency ".concat(dId, " is already added for the request ").concat(dependentId)); error.name = "Duplicate Dependency"; throw error; } cur.value[1].dependsOn.push(dId); } else { var error = new Error("Can't add dependency ".concat(dependencyId, ", There is only a dependent request in the batch")); error.name = "Invalid Dependency Addition"; throw error; } } }; /** * @public * Removes a dependency for a given dependent request id * @param {string} dependentId - The id of the dependent request * @param {string} [dependencyId] - The id of the dependency request, if not specified will remove all the dependencies of that request * @returns The boolean indicating removed status */ BatchRequestContent.prototype.removeDependency = function (dependentId, dependencyId) { var request = this.requests.get(dependentId); if (typeof request === "undefined" || request.dependsOn === undefined || request.dependsOn.length === 0) { return false; } if (typeof dependencyId !== "undefined") { var index = request.dependsOn.indexOf(dependencyId); if (index === -1) { return false; } request.dependsOn.splice(index, 1); return true; } else { delete request.dependsOn; return true; } }; /** * @private * @static * Limit for number of requests {@link - https://developer.microsoft.com/en-us/graph/docs/concepts/known_issues#json-batching} */ BatchRequestContent.requestLimit = 20; return BatchRequestContent; }()); exports.BatchRequestContent = BatchRequestContent; //# sourceMappingURL=BatchRequestContent.js.map