Add PBandGraphOauth scaffold and auth UI
This commit is contained in:
Generated
Vendored
+41
@@ -0,0 +1,41 @@
|
||||
/**
|
||||
* -------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License.
|
||||
* See License in the project root for license information.
|
||||
* -------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
import { GraphClientError } from "../../../GraphClientError";
|
||||
import { FileObject, SliceType } from "../../LargeFileUploadTask";
|
||||
import { Range } from "../Range";
|
||||
|
||||
/**
|
||||
* @class
|
||||
* Class used for creating LargeFileUploadTask fileobject.
|
||||
* This class accepts files of type ArrayBuffer, Blob, Uint8Array.
|
||||
*/
|
||||
export class FileUpload implements FileObject<SliceType> {
|
||||
/**
|
||||
* @public
|
||||
* @constructor
|
||||
* @param {ArrayBuffer | Blob | Uint8Array} content - The file to be uploaded
|
||||
* @param {string} name - The name of the file to be uploaded
|
||||
* @param {number} size - The total size of the file to be uploaded
|
||||
* @returns An instance of the FileUpload class
|
||||
*/
|
||||
public constructor(public content: ArrayBuffer | Blob | Uint8Array, public name: string, public size: number) {
|
||||
if (!content || !name || !size) {
|
||||
throw new GraphClientError("Please provide the upload content, name of the file and size of the file");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
* Slices the file content to the given range
|
||||
* @param {Range} range - The range value
|
||||
* @returns The sliced file part
|
||||
*/
|
||||
public sliceFile(range: Range): ArrayBuffer | Blob | Uint8Array {
|
||||
return this.content.slice(range.minValue, range.maxValue + 1);
|
||||
}
|
||||
}
|
||||
Generated
Vendored
+146
@@ -0,0 +1,146 @@
|
||||
import { GraphClientError } from "../../../GraphClientError";
|
||||
import { FileObject, SliceType } from "../../LargeFileUploadTask";
|
||||
import { Range } from "../Range";
|
||||
|
||||
/**
|
||||
* @interface
|
||||
* Interface to store slice of a stream and range of the slice.
|
||||
* @property {Buffer} fileSlice - The slice of the stream
|
||||
* @property {Range} range - The range of the slice
|
||||
*/
|
||||
interface SliceRecord {
|
||||
fileSlice: Buffer;
|
||||
range: Range;
|
||||
}
|
||||
|
||||
/**
|
||||
* @class
|
||||
* FileObject class for Readable Stream upload
|
||||
*/
|
||||
export class StreamUpload implements FileObject<NodeStream> {
|
||||
/**
|
||||
* @private
|
||||
* Represents a cache of the last attempted upload slice.
|
||||
* This can be used when resuming a previously failed slice upload.
|
||||
*/
|
||||
private previousSlice: SliceRecord;
|
||||
|
||||
public constructor(public content: NodeStream, public name: string, public size: number) {
|
||||
if (!content || !name || !size) {
|
||||
throw new GraphClientError("Please provide the Readable Stream content, name of the file and size of the file");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
* Slices the file content to the given range
|
||||
* @param {Range} range - The range value
|
||||
* @returns The sliced file part
|
||||
*/
|
||||
public async sliceFile(range: Range): Promise<SliceType> {
|
||||
let rangeSize = range.maxValue - range.minValue + 1;
|
||||
/* readable.readable Is true if it is safe to call readable.read(),
|
||||
* which means the stream has not been destroyed or emitted 'error' or 'end'
|
||||
*/
|
||||
const bufs = [];
|
||||
|
||||
/**
|
||||
* The sliceFile reads the first `rangeSize` number of bytes from the stream.
|
||||
* The previousSlice property is used to seek the range of bytes in the previous slice.
|
||||
* Suppose, the sliceFile reads bytes from `10 - 20` from the stream but the upload of this slice fails.
|
||||
* When the user resumes, the stream will have bytes from position 21.
|
||||
* The previousSlice.Range is used to compare if the requested range is cached in the previousSlice property or present in the Readable Stream.
|
||||
*/
|
||||
if (this.previousSlice) {
|
||||
if (range.minValue < this.previousSlice.range.minValue) {
|
||||
throw new GraphClientError("An error occurred while uploading the stream. Please restart the stream upload from the first byte of the file.");
|
||||
}
|
||||
|
||||
if (range.minValue < this.previousSlice.range.maxValue) {
|
||||
const previousRangeMin = this.previousSlice.range.minValue;
|
||||
const previousRangeMax = this.previousSlice.range.maxValue;
|
||||
|
||||
// Check if the requested range is same as previously sliced range
|
||||
if (range.minValue === previousRangeMin && range.maxValue === previousRangeMax) {
|
||||
return this.previousSlice.fileSlice;
|
||||
}
|
||||
|
||||
/**
|
||||
* The following check considers a possibility
|
||||
* of an upload failing after some of the bytes of the previous slice
|
||||
* were successfully uploaded.
|
||||
* Example - Previous slice range - `10 - 20`. Current requested range is `15 - 20`.
|
||||
*/
|
||||
if (range.maxValue === previousRangeMax) {
|
||||
return this.previousSlice.fileSlice.slice(range.minValue, range.maxValue + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* If an upload fails after some of the bytes of the previous slice
|
||||
* were successfully uploaded and the new Range.Maximum is greater than the previous Range.Maximum
|
||||
* Example - Previous slice range - `10 - 20`. Current requested range is `15 - 25`,
|
||||
* then read the bytes from position 15 to 20 from previousSlice.fileSlice and read bytes from position 21 to 25 from the Readable Stream
|
||||
*/
|
||||
bufs.push(this.previousSlice.fileSlice.slice(range.minValue, previousRangeMax + 1));
|
||||
|
||||
rangeSize = range.maxValue - previousRangeMax;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.content && this.content.readable) {
|
||||
if (this.content.readableLength >= rangeSize) {
|
||||
bufs.push(this.content.read(rangeSize));
|
||||
} else {
|
||||
bufs.push(await this.readNBytesFromStream(rangeSize));
|
||||
}
|
||||
} else {
|
||||
throw new GraphClientError("Stream is not readable.");
|
||||
}
|
||||
const slicedChunk = Buffer.concat(bufs);
|
||||
this.previousSlice = { fileSlice: slicedChunk, range };
|
||||
|
||||
return slicedChunk;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* Reads the specified byte size from the stream
|
||||
* @param {number} size - The size of bytes to be read
|
||||
* @returns Buffer with the given length of data.
|
||||
*/
|
||||
|
||||
private readNBytesFromStream(size: number): Promise<Buffer> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const chunks = [];
|
||||
let remainder = size;
|
||||
let length = 0;
|
||||
this.content.on("end", () => {
|
||||
if (remainder > 0) {
|
||||
return reject(new GraphClientError("Stream ended before reading required range size"));
|
||||
}
|
||||
});
|
||||
this.content.on("readable", () => {
|
||||
/**
|
||||
* (chunk = this.content.read(size)) can return null if size of stream is less than 'size' parameter.
|
||||
* Read the remainder number of bytes from the stream iteratively as they are available.
|
||||
*/
|
||||
let chunk;
|
||||
while (length < size && (chunk = this.content.read(remainder)) !== null) {
|
||||
length += chunk.length;
|
||||
chunks.push(chunk);
|
||||
if (remainder > 0) {
|
||||
remainder = size - length;
|
||||
}
|
||||
}
|
||||
|
||||
if (length === size) {
|
||||
return resolve(Buffer.concat(chunks));
|
||||
}
|
||||
|
||||
if (!this.content || !this.content.readable) {
|
||||
return reject(new GraphClientError("Error encountered while reading the stream during the upload"));
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
Generated
Vendored
+16
@@ -0,0 +1,16 @@
|
||||
/* eslint-disable @typescript-eslint/type-annotation-spacing */
|
||||
import { Range } from "../Range";
|
||||
|
||||
/**
|
||||
* Interface enabling progress handling with callbacks.
|
||||
*/
|
||||
export interface UploadEventHandlers {
|
||||
/**
|
||||
* Parameters that are passed into the progress, completed, failure callback options.
|
||||
*/
|
||||
extraCallbackParam?: unknown;
|
||||
/**
|
||||
* Callback function called on each slice upload during the LargeFileUploadTask.upload() process
|
||||
*/
|
||||
progress?: (range?: Range, extraCallbackParam?: unknown) => void;
|
||||
}
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
/**
|
||||
* -------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License.
|
||||
* See License in the project root for license information.
|
||||
* -------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/**
|
||||
* @module Range
|
||||
*/
|
||||
|
||||
/**
|
||||
* @class
|
||||
* Class representing Range
|
||||
*/
|
||||
export class Range {
|
||||
/**
|
||||
* @public
|
||||
* The minimum value of the range
|
||||
*/
|
||||
public minValue: number;
|
||||
|
||||
/**
|
||||
* @public
|
||||
* The maximum value of the range
|
||||
*/
|
||||
public maxValue: number;
|
||||
|
||||
/**
|
||||
* @public
|
||||
* @constructor
|
||||
* Creates a range for given min and max values
|
||||
* @param {number} [minVal = -1] - The minimum value.
|
||||
* @param {number} [maxVal = -1] - The maximum value.
|
||||
* @returns An instance of a Range
|
||||
*/
|
||||
public constructor(minVal = -1, maxVal = -1) {
|
||||
this.minValue = minVal;
|
||||
this.maxValue = maxVal;
|
||||
}
|
||||
}
|
||||
Generated
Vendored
+77
@@ -0,0 +1,77 @@
|
||||
/**
|
||||
* -------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License.
|
||||
* See License in the project root for license information.
|
||||
* -------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/**
|
||||
* Class representing a successful file upload result
|
||||
*/
|
||||
export class UploadResult {
|
||||
/**
|
||||
* @private
|
||||
* Location value looked up in the response header
|
||||
*/
|
||||
private _location: string;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* Response body of the final raw response
|
||||
*/
|
||||
private _responseBody: unknown;
|
||||
|
||||
/**
|
||||
* @public
|
||||
* Get of the location value.
|
||||
* Location value is looked up in the response header
|
||||
*/
|
||||
public get location(): string {
|
||||
return this._location;
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
* Set the location value
|
||||
* Location value is looked up in the response header
|
||||
*/
|
||||
public set location(location: string) {
|
||||
this._location = location;
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
* Get The response body from the completed upload response
|
||||
*/
|
||||
public get responseBody() {
|
||||
return this._responseBody;
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
* Set the response body from the completed upload response
|
||||
*/
|
||||
public set responseBody(responseBody: unknown) {
|
||||
this._responseBody = responseBody;
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
* @param {responseBody} responsebody - The response body from the completed upload response
|
||||
* @param {location} location - The location value from the headers from the completed upload response
|
||||
*/
|
||||
public constructor(responseBody: unknown, location: string) {
|
||||
// Response body or the location parameter can be undefined.
|
||||
this._location = location;
|
||||
this._responseBody = responseBody;
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
* @param {responseBody} responseBody - The response body from the completed upload response
|
||||
* @param {responseHeaders} responseHeaders - The headers from the completed upload response
|
||||
*/
|
||||
public static CreateUploadResult(responseBody?: unknown, responseHeaders?: Headers) {
|
||||
return new UploadResult(responseBody, responseHeaders.get("location"));
|
||||
}
|
||||
}
|
||||
+378
@@ -0,0 +1,378 @@
|
||||
/**
|
||||
* -------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License.
|
||||
* See License in the project root for license information.
|
||||
* -------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/**
|
||||
* @module LargeFileUploadTask
|
||||
*/
|
||||
|
||||
import { GraphClientError } from "../GraphClientError";
|
||||
import { GraphResponseHandler } from "../GraphResponseHandler";
|
||||
import { Client } from "../index";
|
||||
import { ResponseType } from "../ResponseType";
|
||||
import { UploadEventHandlers } from "./FileUploadTask/Interfaces/IUploadEventHandlers";
|
||||
import { Range } from "./FileUploadTask/Range";
|
||||
import { UploadResult } from "./FileUploadTask/UploadResult";
|
||||
|
||||
/**
|
||||
* @interface
|
||||
* Signature to representing key value pairs
|
||||
* @property {[key: string] : string | number} - The Key value pair
|
||||
*/
|
||||
interface KeyValuePairObjectStringNumber {
|
||||
[key: string]: string | number;
|
||||
}
|
||||
|
||||
/**
|
||||
* @interface
|
||||
* Signature to represent the resulting response in the status enquiry request
|
||||
* @property {string} expirationDateTime - The expiration time of the upload session
|
||||
* @property {string[]} nextExpectedRanges - The ranges expected in next consecutive request in the upload
|
||||
*/
|
||||
interface UploadStatusResponse {
|
||||
expirationDateTime: string;
|
||||
nextExpectedRanges: string[];
|
||||
}
|
||||
|
||||
/**
|
||||
* @interface
|
||||
* Signature to define options for upload task
|
||||
* @property {number} [rangeSize = LargeFileUploadTask.DEFAULT_FILE_SIZE] - Specifies the range chunk size
|
||||
* @property {UploadEventHandlers} uploadEventHandlers - UploadEventHandlers attached to an upload task
|
||||
*/
|
||||
export interface LargeFileUploadTaskOptions {
|
||||
rangeSize?: number;
|
||||
uploadEventHandlers?: UploadEventHandlers;
|
||||
}
|
||||
|
||||
/**
|
||||
* @interface
|
||||
* Signature to represent upload session resulting from the session creation in the server
|
||||
* @property {string} url - The URL to which the file upload is made
|
||||
* @property {Date} expiry - The expiration of the time of the upload session
|
||||
*/
|
||||
export interface LargeFileUploadSession {
|
||||
url: string;
|
||||
expiry: Date;
|
||||
isCancelled?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* @type
|
||||
* Representing the return type of the sliceFile function that is type of the slice of a given range.
|
||||
*/
|
||||
export type SliceType = ArrayBuffer | Blob | Uint8Array;
|
||||
|
||||
/**
|
||||
* @interface
|
||||
* Signature to define the properties and content of the file in upload task
|
||||
* @property {ArrayBuffer | File} content - The actual file content
|
||||
* @property {string} name - Specifies the file name with extension
|
||||
* @property {number} size - Specifies size of the file
|
||||
*/
|
||||
export interface FileObject<T> {
|
||||
content: T;
|
||||
name: string;
|
||||
size: number;
|
||||
sliceFile(range: Range): SliceType | Promise<SliceType>;
|
||||
}
|
||||
|
||||
/**
|
||||
* @class
|
||||
* Class representing LargeFileUploadTask
|
||||
*/
|
||||
export class LargeFileUploadTask<T> {
|
||||
/**
|
||||
* @private
|
||||
* Default value for the rangeSize
|
||||
*/
|
||||
private DEFAULT_FILE_SIZE: number = 5 * 1024 * 1024;
|
||||
|
||||
/**
|
||||
* @protected
|
||||
* The GraphClient instance
|
||||
*/
|
||||
protected client: Client;
|
||||
|
||||
/**
|
||||
* @protected
|
||||
* The object holding file details
|
||||
*/
|
||||
protected file: FileObject<T>;
|
||||
|
||||
/**
|
||||
* @protected
|
||||
* The object holding options for the task
|
||||
*/
|
||||
protected options: LargeFileUploadTaskOptions;
|
||||
|
||||
/**
|
||||
* @protected
|
||||
* The object for upload session
|
||||
*/
|
||||
protected uploadSession: LargeFileUploadSession;
|
||||
|
||||
/**
|
||||
* @protected
|
||||
* The next range needs to be uploaded
|
||||
*/
|
||||
protected nextRange: Range;
|
||||
|
||||
/**
|
||||
* @public
|
||||
* @static
|
||||
* @async
|
||||
* Makes request to the server to create an upload session
|
||||
* @param {Client} client - The GraphClient instance
|
||||
* @param {string} requestUrl - The URL to create the upload session
|
||||
* @param {any} payload - The payload that needs to be sent
|
||||
* @param {KeyValuePairObjectStringNumber} headers - The headers that needs to be sent
|
||||
* @returns The promise that resolves to LargeFileUploadSession
|
||||
*/
|
||||
public static async createUploadSession(client: Client, requestUrl: string, payload: any, headers: KeyValuePairObjectStringNumber = {}): Promise<LargeFileUploadSession> {
|
||||
const session = await client
|
||||
.api(requestUrl)
|
||||
.headers(headers)
|
||||
.post(payload);
|
||||
const largeFileUploadSession: LargeFileUploadSession = {
|
||||
url: session.uploadUrl,
|
||||
expiry: new Date(session.expirationDateTime),
|
||||
isCancelled: false,
|
||||
};
|
||||
return largeFileUploadSession;
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
* @constructor
|
||||
* Constructs a LargeFileUploadTask
|
||||
* @param {Client} client - The GraphClient instance
|
||||
* @param {FileObject} file - The FileObject holding details of a file that needs to be uploaded
|
||||
* @param {LargeFileUploadSession} uploadSession - The upload session to which the upload has to be done
|
||||
* @param {LargeFileUploadTaskOptions} options - The upload task options
|
||||
* @returns An instance of LargeFileUploadTask
|
||||
*/
|
||||
public constructor(client: Client, file: FileObject<T>, uploadSession: LargeFileUploadSession, options: LargeFileUploadTaskOptions = {}) {
|
||||
this.client = client;
|
||||
|
||||
if (!file.sliceFile) {
|
||||
throw new GraphClientError("Please pass the FileUpload object, StreamUpload object or any custom implementation of the FileObject interface");
|
||||
} else {
|
||||
this.file = file;
|
||||
}
|
||||
this.file = file;
|
||||
if (!options.rangeSize) {
|
||||
options.rangeSize = this.DEFAULT_FILE_SIZE;
|
||||
}
|
||||
|
||||
this.options = options;
|
||||
this.uploadSession = uploadSession;
|
||||
this.nextRange = new Range(0, this.options.rangeSize - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* Parses given range string to the Range instance
|
||||
* @param {string[]} ranges - The ranges value
|
||||
* @returns The range instance
|
||||
*/
|
||||
private parseRange(ranges: string[]): Range {
|
||||
const rangeStr = ranges[0];
|
||||
if (typeof rangeStr === "undefined" || rangeStr === "") {
|
||||
return new Range();
|
||||
}
|
||||
const firstRange = rangeStr.split("-");
|
||||
const minVal = parseInt(firstRange[0], 10);
|
||||
let maxVal = parseInt(firstRange[1], 10);
|
||||
if (Number.isNaN(maxVal)) {
|
||||
maxVal = this.file.size - 1;
|
||||
}
|
||||
return new Range(minVal, maxVal);
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* Updates the expiration date and the next range
|
||||
* @param {UploadStatusResponse} response - The response of the upload status
|
||||
* @returns Nothing
|
||||
*/
|
||||
private updateTaskStatus(response: UploadStatusResponse): void {
|
||||
this.uploadSession.expiry = new Date(response.expirationDateTime);
|
||||
this.nextRange = this.parseRange(response.nextExpectedRanges);
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
* Gets next range that needs to be uploaded
|
||||
* @returns The range instance
|
||||
*/
|
||||
public getNextRange(): Range {
|
||||
if (this.nextRange.minValue === -1) {
|
||||
return this.nextRange;
|
||||
}
|
||||
const minVal = this.nextRange.minValue;
|
||||
let maxValue = minVal + this.options.rangeSize - 1;
|
||||
if (maxValue >= this.file.size) {
|
||||
maxValue = this.file.size - 1;
|
||||
}
|
||||
return new Range(minVal, maxValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated This function has been moved into FileObject interface.
|
||||
* @public
|
||||
* Slices the file content to the given range
|
||||
* @param {Range} range - The range value
|
||||
* @returns The sliced ArrayBuffer or Blob
|
||||
*/
|
||||
public sliceFile(range: Range): ArrayBuffer | Blob {
|
||||
console.warn("The LargeFileUploadTask.sliceFile() function has been deprecated and moved into the FileObject interface.");
|
||||
if (this.file.content instanceof ArrayBuffer || this.file.content instanceof Blob || this.file.content instanceof Uint8Array) {
|
||||
return this.file.content.slice(range.minValue, range.maxValue + 1);
|
||||
}
|
||||
throw new GraphClientError("The LargeFileUploadTask.sliceFile() function expects only Blob, ArrayBuffer or Uint8Array file content. Please note that the sliceFile() function is deprecated.");
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
* @async
|
||||
* Uploads file to the server in a sequential order by slicing the file
|
||||
* @returns The promise resolves to uploaded response
|
||||
*/
|
||||
public async upload(): Promise<UploadResult> {
|
||||
const uploadEventHandlers = this.options && this.options.uploadEventHandlers;
|
||||
while (!this.uploadSession.isCancelled) {
|
||||
const nextRange = this.getNextRange();
|
||||
if (nextRange.maxValue === -1) {
|
||||
const err = new Error("Task with which you are trying to upload is already completed, Please check for your uploaded file");
|
||||
err.name = "Invalid Session";
|
||||
throw err;
|
||||
}
|
||||
const fileSlice = await this.file.sliceFile(nextRange);
|
||||
const rawResponse = await this.uploadSliceGetRawResponse(fileSlice, nextRange, this.file.size);
|
||||
if (!rawResponse) {
|
||||
throw new GraphClientError("Something went wrong! Large file upload slice response is null.");
|
||||
}
|
||||
|
||||
const responseBody = await GraphResponseHandler.getResponse(rawResponse);
|
||||
/**
|
||||
* (rawResponse.status === 201) -> This condition is applicable for OneDrive, PrintDocument and Outlook APIs.
|
||||
* (rawResponse.status === 200 && responseBody.id) -> This additional condition is applicable only for OneDrive API.
|
||||
*/
|
||||
if (rawResponse.status === 201 || (rawResponse.status === 200 && responseBody.id)) {
|
||||
this.reportProgress(uploadEventHandlers, nextRange);
|
||||
return UploadResult.CreateUploadResult(responseBody, rawResponse.headers);
|
||||
}
|
||||
|
||||
/* Handling the API issue where the case of Outlook upload response property -'nextExpectedRanges' is not uniform.
|
||||
* https://github.com/microsoftgraph/msgraph-sdk-serviceissues/issues/39
|
||||
*/
|
||||
const res: UploadStatusResponse = {
|
||||
expirationDateTime: responseBody.expirationDateTime || responseBody.ExpirationDateTime,
|
||||
nextExpectedRanges: responseBody.NextExpectedRanges || responseBody.nextExpectedRanges,
|
||||
};
|
||||
this.updateTaskStatus(res);
|
||||
this.reportProgress(uploadEventHandlers, nextRange);
|
||||
}
|
||||
}
|
||||
|
||||
private reportProgress(uploadEventHandlers: UploadEventHandlers, nextRange: Range) {
|
||||
if (uploadEventHandlers && uploadEventHandlers.progress) {
|
||||
uploadEventHandlers.progress(nextRange, uploadEventHandlers.extraCallbackParam);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
* @async
|
||||
* Uploads given slice to the server
|
||||
* @param {ArrayBuffer | Blob | File} fileSlice - The file slice
|
||||
* @param {Range} range - The range value
|
||||
* @param {number} totalSize - The total size of a complete file
|
||||
* @returns The response body of the upload slice result
|
||||
*/
|
||||
public async uploadSlice(fileSlice: ArrayBuffer | Blob | File, range: Range, totalSize: number): Promise<unknown> {
|
||||
return await this.client
|
||||
.api(this.uploadSession.url)
|
||||
.headers({
|
||||
"Content-Length": `${range.maxValue - range.minValue + 1}`,
|
||||
"Content-Range": `bytes ${range.minValue}-${range.maxValue}/${totalSize}`,
|
||||
"Content-Type": "application/octet-stream",
|
||||
})
|
||||
.put(fileSlice);
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
* @async
|
||||
* Uploads given slice to the server
|
||||
* @param {unknown} fileSlice - The file slice
|
||||
* @param {Range} range - The range value
|
||||
* @param {number} totalSize - The total size of a complete file
|
||||
* @returns The raw response of the upload slice result
|
||||
*/
|
||||
public async uploadSliceGetRawResponse(fileSlice: unknown, range: Range, totalSize: number): Promise<Response> {
|
||||
return await this.client
|
||||
.api(this.uploadSession.url)
|
||||
.headers({
|
||||
"Content-Length": `${range.maxValue - range.minValue + 1}`,
|
||||
"Content-Range": `bytes ${range.minValue}-${range.maxValue}/${totalSize}`,
|
||||
"Content-Type": "application/octet-stream",
|
||||
})
|
||||
.responseType(ResponseType.RAW)
|
||||
.put(fileSlice);
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
* @async
|
||||
* Deletes upload session in the server
|
||||
* @returns The promise resolves to cancelled response
|
||||
*/
|
||||
public async cancel(): Promise<unknown> {
|
||||
const cancelResponse = await this.client
|
||||
.api(this.uploadSession.url)
|
||||
.responseType(ResponseType.RAW)
|
||||
.delete();
|
||||
if (cancelResponse.status === 204) {
|
||||
this.uploadSession.isCancelled = true;
|
||||
}
|
||||
return cancelResponse;
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
* @async
|
||||
* Gets status for the upload session
|
||||
* @returns The promise resolves to the status enquiry response
|
||||
*/
|
||||
public async getStatus(): Promise<unknown> {
|
||||
const response = await this.client.api(this.uploadSession.url).get();
|
||||
this.updateTaskStatus(response);
|
||||
return response;
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
* @async
|
||||
* Resumes upload session and continue uploading the file from the last sent range
|
||||
* @returns The promise resolves to the uploaded response
|
||||
*/
|
||||
public async resume(): Promise<unknown> {
|
||||
await this.getStatus();
|
||||
return await this.upload();
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
* @async
|
||||
* Get the upload session information
|
||||
* @returns The large file upload session
|
||||
*/
|
||||
public getUploadSession(): LargeFileUploadSession {
|
||||
return this.uploadSession;
|
||||
}
|
||||
}
|
||||
Generated
Vendored
+233
@@ -0,0 +1,233 @@
|
||||
/**
|
||||
* -------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License.
|
||||
* See License in the project root for license information.
|
||||
* -------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/**
|
||||
* @module OneDriveLargeFileUploadTask
|
||||
*/
|
||||
|
||||
import { GraphClientError } from "../GraphClientError";
|
||||
import { Client } from "../index";
|
||||
import { FileUpload } from "./FileUploadTask/FileObjectClasses/FileUpload";
|
||||
import { UploadEventHandlers } from "./FileUploadTask/Interfaces/IUploadEventHandlers";
|
||||
import { FileObject, LargeFileUploadSession, LargeFileUploadTask, LargeFileUploadTaskOptions } from "./LargeFileUploadTask";
|
||||
import { getValidRangeSize } from "./OneDriveLargeFileUploadTaskUtil";
|
||||
|
||||
/**
|
||||
* @interface
|
||||
* Signature to define options when creating an upload task
|
||||
* @property {string} fileName - Specifies the name of a file to be uploaded (with extension)
|
||||
* @property {string} [fileDescription] - Specifies the description of the file to be uploaded
|
||||
* @property {string} [path] - The path to which the file needs to be uploaded
|
||||
* @property {number} [rangeSize] - Specifies the range chunk size
|
||||
* @property {string} [conflictBehavior] - Conflict behaviour option
|
||||
* @property {UploadEventHandlers} [uploadEventHandlers] - UploadEventHandlers attached to an upload task
|
||||
*/
|
||||
export interface OneDriveLargeFileUploadOptions {
|
||||
fileName: string;
|
||||
fileDescription?: string;
|
||||
path?: string;
|
||||
rangeSize?: number;
|
||||
conflictBehavior?: string;
|
||||
uploadEventHandlers?: UploadEventHandlers;
|
||||
/// <summary>
|
||||
/// Default upload session url is : "/me/drive/root:/{file-path}:/createUploadSession"
|
||||
/// Set this property to override the default upload session url. Example: "/me/drive/special/{name}"
|
||||
/// </summary>
|
||||
uploadSessionURL?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* @interface
|
||||
* Signature to define options when creating an upload task
|
||||
* @property {string} fileName - Specifies the name of a file to be uploaded (with extension)
|
||||
* @property {string} [fileDescription] - Specifies the description of the file to be uploaded
|
||||
* @property {string} [conflictBehavior] - Conflict behaviour option
|
||||
*/
|
||||
interface OneDriveFileUploadSessionPayLoad {
|
||||
fileName: string;
|
||||
fileDescription?: string;
|
||||
conflictBehavior?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* @interface
|
||||
* Signature to define the file information when processing an upload task
|
||||
* @property {File | Uint8Array} content - The file content
|
||||
* @property {number} size - The size of file
|
||||
*/
|
||||
interface FileInfo {
|
||||
content: File | Uint8Array;
|
||||
size: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* @class
|
||||
* Class representing OneDriveLargeFileUploadTask
|
||||
*/
|
||||
export class OneDriveLargeFileUploadTask<T> extends LargeFileUploadTask<T> {
|
||||
/**
|
||||
* @private
|
||||
* @static
|
||||
* Default path for the file being uploaded
|
||||
*/
|
||||
private static DEFAULT_UPLOAD_PATH = "/";
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @static
|
||||
* Constructs the create session url for Onedrive
|
||||
* @param {string} fileName - The name of the file
|
||||
* @param {path} [path = OneDriveLargeFileUploadTask.DEFAULT_UPLOAD_PATH] - The path for the upload
|
||||
* @returns The constructed create session url
|
||||
*/
|
||||
private static constructCreateSessionUrl(fileName: string, path: string = OneDriveLargeFileUploadTask.DEFAULT_UPLOAD_PATH): string {
|
||||
fileName = fileName.trim();
|
||||
path = path.trim();
|
||||
if (path === "") {
|
||||
path = "/";
|
||||
}
|
||||
if (path[0] !== "/") {
|
||||
path = `/${path}`;
|
||||
}
|
||||
if (path[path.length - 1] !== "/") {
|
||||
path = `${path}/`;
|
||||
}
|
||||
// we choose to encode each component of the file path separately because when encoding full URI
|
||||
// with encodeURI, special characters like # or % in the file name doesn't get encoded as desired
|
||||
return `/me/drive/root:${path
|
||||
.split("/")
|
||||
.map((p) => encodeURIComponent(p))
|
||||
.join("/")}${encodeURIComponent(fileName)}:/createUploadSession`;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @static
|
||||
* Get file information
|
||||
* @param {Blob | Uint8Array | File} file - The file entity
|
||||
* @param {string} fileName - The file name
|
||||
* @returns {FileInfo} The file information
|
||||
*/
|
||||
private static getFileInfo(file: Blob | Uint8Array | File, fileName: string): FileInfo {
|
||||
let content;
|
||||
let size;
|
||||
if (typeof Blob !== "undefined" && file instanceof Blob) {
|
||||
content = new File([file as Blob], fileName);
|
||||
size = content.size;
|
||||
} else if (typeof File !== "undefined" && file instanceof File) {
|
||||
content = file as File;
|
||||
size = content.size;
|
||||
} else if (typeof Uint8Array !== "undefined" && file instanceof Uint8Array) {
|
||||
const b = file as Uint8Array;
|
||||
size = b.byteLength;
|
||||
content = b.buffer.slice(b.byteOffset, b.byteOffset + b.byteLength);
|
||||
}
|
||||
return {
|
||||
content,
|
||||
size,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
* @static
|
||||
* @async
|
||||
* Creates a OneDriveLargeFileUploadTask
|
||||
* @param {Client} client - The GraphClient instance
|
||||
* @param {Blob | Uint8Array | File} file - File represented as Blob, Uint8Array or File
|
||||
* @param {OneDriveLargeFileUploadOptions} options - The options for upload task
|
||||
* @returns The promise that will be resolves to OneDriveLargeFileUploadTask instance
|
||||
*/
|
||||
public static async create(client: Client, file: Blob | Uint8Array | File, options: OneDriveLargeFileUploadOptions): Promise<OneDriveLargeFileUploadTask<Blob | ArrayBuffer | Uint8Array>> {
|
||||
if (!client || !file || !options) {
|
||||
throw new GraphClientError("Please provide the Graph client instance, file object and OneDriveLargeFileUploadOptions value");
|
||||
}
|
||||
const fileName = options.fileName;
|
||||
const fileInfo = OneDriveLargeFileUploadTask.getFileInfo(file, fileName);
|
||||
const fileObj = new FileUpload(fileInfo.content, fileName, fileInfo.size);
|
||||
return this.createTaskWithFileObject<Blob | ArrayBuffer | Uint8Array>(client, fileObj, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
* @static
|
||||
* @async
|
||||
* Creates a OneDriveLargeFileUploadTask
|
||||
* @param {Client} client - The GraphClient instance
|
||||
* @param {FileObject} fileObject - FileObject instance
|
||||
* @param {OneDriveLargeFileUploadOptions} options - The options for upload task
|
||||
* @returns The promise that will be resolves to OneDriveLargeFileUploadTask instance
|
||||
*/
|
||||
public static async createTaskWithFileObject<T>(client: Client, fileObject: FileObject<T>, options: OneDriveLargeFileUploadOptions): Promise<OneDriveLargeFileUploadTask<T>> {
|
||||
if (!client || !fileObject || !options) {
|
||||
throw new GraphClientError("Please provide the Graph client instance, FileObject interface implementation and OneDriveLargeFileUploadOptions value");
|
||||
}
|
||||
const requestUrl = options.uploadSessionURL ? options.uploadSessionURL: OneDriveLargeFileUploadTask.constructCreateSessionUrl(options.fileName, options.path);
|
||||
const uploadSessionPayload: OneDriveFileUploadSessionPayLoad = {
|
||||
fileName: options.fileName,
|
||||
fileDescription: options.fileDescription,
|
||||
conflictBehavior: options.conflictBehavior,
|
||||
};
|
||||
const session = await OneDriveLargeFileUploadTask.createUploadSession(client, requestUrl, uploadSessionPayload);
|
||||
const rangeSize = getValidRangeSize(options.rangeSize);
|
||||
return new OneDriveLargeFileUploadTask(client, fileObject, session, {
|
||||
rangeSize,
|
||||
uploadEventHandlers: options.uploadEventHandlers,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
* @static
|
||||
* @async
|
||||
* Makes request to the server to create an upload session
|
||||
* @param {Client} client - The GraphClient instance
|
||||
* @param {string} requestUrl - The URL to create the upload session
|
||||
* @param {string} payloadOptions - The payload option. Default conflictBehavior is 'rename'
|
||||
* @returns The promise that resolves to LargeFileUploadSession
|
||||
*/
|
||||
public static async createUploadSession(client: Client, requestUrl: string, payloadOptions: OneDriveFileUploadSessionPayLoad): Promise<LargeFileUploadSession> {
|
||||
const payload = {
|
||||
item: {
|
||||
"@microsoft.graph.conflictBehavior": payloadOptions?.conflictBehavior || "rename",
|
||||
name: payloadOptions?.fileName,
|
||||
description: payloadOptions?.fileDescription,
|
||||
},
|
||||
};
|
||||
return super.createUploadSession(client, requestUrl, payload);
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
* @constructor
|
||||
* Constructs a OneDriveLargeFileUploadTask
|
||||
* @param {Client} client - The GraphClient instance
|
||||
* @param {FileObject} file - The FileObject holding details of a file that needs to be uploaded
|
||||
* @param {LargeFileUploadSession} uploadSession - The upload session to which the upload has to be done
|
||||
* @param {LargeFileUploadTaskOptions} options - The upload task options
|
||||
* @returns An instance of OneDriveLargeFileUploadTask
|
||||
*/
|
||||
public constructor(client: Client, file: FileObject<T>, uploadSession: LargeFileUploadSession, options: LargeFileUploadTaskOptions) {
|
||||
super(client, file, uploadSession, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
* Commits upload session to end uploading
|
||||
* @param {string} requestUrl - The URL to commit the upload session
|
||||
* @param {string} conflictBehavior - Conflict behaviour option. Default is 'rename'
|
||||
* @returns The promise resolves to committed response
|
||||
*/
|
||||
public async commit(requestUrl: string, conflictBehavior = "rename"): Promise<unknown> {
|
||||
const payload = {
|
||||
name: this.file.name,
|
||||
"@microsoft.graph.conflictBehavior": conflictBehavior,
|
||||
"@microsoft.graph.sourceUrl": this.uploadSession.url,
|
||||
};
|
||||
return await this.client.api(requestUrl).put(payload);
|
||||
}
|
||||
}
|
||||
Generated
Vendored
+46
@@ -0,0 +1,46 @@
|
||||
/**
|
||||
* -------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License.
|
||||
* See License in the project root for license information.
|
||||
* -------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/**
|
||||
* @module OneDriveLargeFileUploadTaskUtil
|
||||
*/
|
||||
|
||||
/**
|
||||
* @constant
|
||||
* Default value for the rangeSize
|
||||
* Recommended size is between 5 - 10 MB {@link https://developer.microsoft.com/en-us/graph/docs/api-reference/v1.0/api/driveitem_createuploadsession#best-practices}
|
||||
*/
|
||||
const DEFAULT_FILE_SIZE: number = 5 * 1024 * 1024;
|
||||
|
||||
/**
|
||||
* @constant
|
||||
* Rounds off the given value to a multiple of 320 KB
|
||||
* @param {number} value - The value
|
||||
* @returns The rounded off value
|
||||
*/
|
||||
const roundTo320KB = (value: number): number => {
|
||||
if (value > 320 * 1024) {
|
||||
value = Math.floor(value / (320 * 1024)) * 320 * 1024;
|
||||
}
|
||||
return value;
|
||||
};
|
||||
|
||||
/**
|
||||
* @constant
|
||||
* Get the valid rangeSize for a file slicing (validity is based on the constrains mentioned in here
|
||||
* {@link https://developer.microsoft.com/en-us/graph/docs/api-reference/v1.0/api/driveitem_createuploadsession#upload-bytes-to-the-upload-session})
|
||||
*
|
||||
* @param {number} [rangeSize = DEFAULT_FILE_SIZE] - The rangeSize value.
|
||||
* @returns The valid rangeSize
|
||||
*/
|
||||
export const getValidRangeSize = (rangeSize: number = DEFAULT_FILE_SIZE): number => {
|
||||
const sixtyMB = 60 * 1024 * 1024;
|
||||
if (rangeSize > sixtyMB) {
|
||||
rangeSize = sixtyMB;
|
||||
}
|
||||
return roundTo320KB(rangeSize);
|
||||
};
|
||||
+219
@@ -0,0 +1,219 @@
|
||||
/**
|
||||
* -------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License.
|
||||
* See License in the project root for license information.
|
||||
* -------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/**
|
||||
* @module PageIterator
|
||||
*/
|
||||
|
||||
import { FetchOptions } from "../IFetchOptions";
|
||||
import { Client } from "../index";
|
||||
import { MiddlewareOptions } from "../middleware/options/IMiddlewareOptions";
|
||||
|
||||
/**
|
||||
* Signature representing PageCollection
|
||||
* @property {any[]} value - The collection value
|
||||
* @property {string} [@odata.nextLink] - The nextLink value
|
||||
* @property {string} [@odata.deltaLink] - The deltaLink value
|
||||
* @property {any} Additional - Any number of additional properties (This is to accept the any additional data returned by in the response to the nextLink request)
|
||||
*/
|
||||
export interface PageCollection {
|
||||
value: any[];
|
||||
"@odata.nextLink"?: string;
|
||||
"@odata.deltaLink"?: string;
|
||||
[Key: string]: any;
|
||||
}
|
||||
|
||||
/**
|
||||
* Signature to define the request options to be sent during request.
|
||||
* The values of the GraphRequestOptions properties are passed to the Graph Request object.
|
||||
* @property {HeadersInit} headers - the header options for the request
|
||||
* @property {MiddlewareOptions[]} middlewareoptions - The middleware options for the request
|
||||
* @property {FetchOptions} options - The fetch options for the request
|
||||
*/
|
||||
export interface GraphRequestOptions {
|
||||
headers?: HeadersInit;
|
||||
middlewareOptions?: MiddlewareOptions[];
|
||||
options?: FetchOptions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Signature representing callback for page iterator
|
||||
* @property {Function} callback - The callback function which should return boolean to continue the continue/stop the iteration.
|
||||
*/
|
||||
export type PageIteratorCallback = (data: any) => boolean;
|
||||
|
||||
/**
|
||||
* @class
|
||||
* Class for PageIterator
|
||||
*/
|
||||
export class PageIterator {
|
||||
/**
|
||||
* @private
|
||||
* Member holding the GraphClient instance
|
||||
*/
|
||||
private client: Client;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* Member holding the page collection
|
||||
*/
|
||||
private collection: any[];
|
||||
|
||||
/**
|
||||
* @private
|
||||
* Member variable referring to nextLink of the page collection
|
||||
*/
|
||||
private nextLink: string | undefined;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* Member variable referring to deltaLink of the request
|
||||
*/
|
||||
private deltaLink: string | undefined;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* Holding callback for Iteration.
|
||||
*/
|
||||
|
||||
private callback: PageIteratorCallback;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* Member holding a complete/incomplete status of an iterator
|
||||
*/
|
||||
private complete: boolean;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* Information to be added to the request
|
||||
*/
|
||||
private requestOptions: GraphRequestOptions;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* Member holding the current position on the collection
|
||||
*/
|
||||
private cursor: number;
|
||||
|
||||
/**
|
||||
* @public
|
||||
* @constructor
|
||||
* Creates new instance for PageIterator
|
||||
* @param {Client} client - The graph client instance
|
||||
* @param {PageCollection} pageCollection - The page collection object
|
||||
* @param {PageIteratorCallback} callBack - The callback function
|
||||
* @param {GraphRequestOptions} requestOptions - The request options
|
||||
* @returns An instance of a PageIterator
|
||||
*/
|
||||
public constructor(client: Client, pageCollection: PageCollection, callback: PageIteratorCallback, requestOptions?: GraphRequestOptions) {
|
||||
this.client = client;
|
||||
this.collection = pageCollection.value;
|
||||
this.nextLink = pageCollection["@odata.nextLink"];
|
||||
this.deltaLink = pageCollection["@odata.deltaLink"];
|
||||
this.callback = callback;
|
||||
this.cursor = 0;
|
||||
this.complete = false;
|
||||
this.requestOptions = requestOptions;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* Iterates over a collection by enqueuing entries one by one and kicking the callback with the enqueued entry
|
||||
* @returns A boolean indicating the continue flag to process next page
|
||||
*/
|
||||
private iterationHelper(): boolean {
|
||||
if (this.collection === undefined) {
|
||||
return false;
|
||||
}
|
||||
let advance = true;
|
||||
while (advance && this.cursor < this.collection.length) {
|
||||
const item = this.collection[this.cursor];
|
||||
advance = this.callback(item);
|
||||
this.cursor++;
|
||||
}
|
||||
return advance;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @async
|
||||
* Helper to make a get request to fetch next page with nextLink url and update the page iterator instance with the returned response
|
||||
* @returns A promise that resolves to a response data with next page collection
|
||||
*/
|
||||
private async fetchAndUpdateNextPageData(): Promise<any> {
|
||||
let graphRequest = this.client.api(this.nextLink);
|
||||
if (this.requestOptions) {
|
||||
if (this.requestOptions.headers) {
|
||||
graphRequest = graphRequest.headers(this.requestOptions.headers);
|
||||
}
|
||||
if (this.requestOptions.middlewareOptions) {
|
||||
graphRequest = graphRequest.middlewareOptions(this.requestOptions.middlewareOptions);
|
||||
}
|
||||
if (this.requestOptions.options) {
|
||||
graphRequest = graphRequest.options(this.requestOptions.options);
|
||||
}
|
||||
}
|
||||
|
||||
const response: PageCollection = await graphRequest.get();
|
||||
this.collection = response.value;
|
||||
this.cursor = 0;
|
||||
this.nextLink = response["@odata.nextLink"];
|
||||
this.deltaLink = response["@odata.deltaLink"];
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
* Getter to get the deltaLink in the current response
|
||||
* @returns A deltaLink which is being used to make delta requests in future
|
||||
*/
|
||||
public getDeltaLink(): string | undefined {
|
||||
return this.deltaLink;
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
* @async
|
||||
* Iterates over the collection and kicks callback for each item on iteration. Fetches next set of data through nextLink and iterates over again
|
||||
* This happens until the nextLink is drained out or the user responds with a red flag to continue from callback
|
||||
* @returns A Promise that resolves to nothing on completion and throws error incase of any discrepancy.
|
||||
*/
|
||||
public async iterate(): Promise<any> {
|
||||
let advance = this.iterationHelper();
|
||||
while (advance) {
|
||||
if (this.nextLink !== undefined) {
|
||||
await this.fetchAndUpdateNextPageData();
|
||||
advance = this.iterationHelper();
|
||||
} else {
|
||||
advance = false;
|
||||
}
|
||||
}
|
||||
if (this.nextLink === undefined && this.cursor >= this.collection.length) {
|
||||
this.complete = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
* @async
|
||||
* To resume the iteration
|
||||
* Note: This internally calls the iterate method, It's just for more readability.
|
||||
* @returns A Promise that resolves to nothing on completion and throws error incase of any discrepancy
|
||||
*/
|
||||
public async resume(): Promise<any> {
|
||||
return this.iterate();
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
* To get the completeness status of the iterator
|
||||
* @returns Boolean indicating the completeness
|
||||
*/
|
||||
public isComplete(): boolean {
|
||||
return this.complete;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user