async DownloadPart({
    libraryId,
    objectId,
    versionHash,
    partHash,
    format="arrayBuffer",
    chunked=false,
    chunkSize=10000000,
    callback
  }) {
    if(chunked && !callback) { throw Error("No callback specified for chunked part download"); }

    if(versionHash) { objectId = this.utils.DecodeVersionHash(versionHash).objectId; }

    const encrypted = partHash.startsWith("hqpe");
    const encryption = encrypted ? "cgck" : "none";
    const path = UrlJoin("q", versionHash || objectId, "data", partHash);

    let headers = await this.authClient.AuthorizationHeader({libraryId, objectId, versionHash, encryption});

    let conk;
    if(encrypted) {
      conk = await this.EncryptionConk({libraryId, objectId});
    }

    if(!chunked) {
      // Download and decrypt entire part
      const response = await this.HttpClient.Request({headers, method: "GET", path: path});

      let data = await response.arrayBuffer();
      if(encrypted) {
        data = await Crypto.Decrypt(conk, data);
      }

      return await ResponseToFormat(
        format,
        new Response(data)
      );
    }

    // Download part in chunks
    const bytesTotal = (await this.ContentPart({libraryId, objectId, versionHash, partHash})).part.size;
    let bytesFinished = 0;

    let stream;
    if(encrypted) {
      // Set up decryption stream
      stream = await Crypto.OpenDecryptionStream(conk);

      stream = stream.on("data", async chunk => {
        // Turn buffer into desired format, if necessary
        if(format !== "buffer") {
          const arrayBuffer = chunk.buffer.slice(chunk.byteOffset, chunk.byteOffset + chunk.byteLength);

          if(format === "arrayBuffer") {
            chunk = arrayBuffer;
          } else {
            chunk = await ResponseToFormat(
              format,
              new Response(arrayBuffer)
            );
          }
        }

        callback({
          bytesFinished,
          bytesTotal,
          chunk
        });
      });
    }

    const totalChunks = Math.ceil(bytesTotal / chunkSize);
    for(let i = 0; i < totalChunks; i++) {
      headers["Range"] = `bytes=${bytesFinished}-${bytesFinished + chunkSize - 1}`;
      const response = await this.HttpClient.Request({headers, method: "GET", path: path});

      bytesFinished = Math.min(bytesFinished + chunkSize, bytesTotal);

      if(encrypted) {
        stream.write(new Uint8Array(await response.arrayBuffer()));
      } else {
        callback({bytesFinished, bytesTotal, chunk: await ResponseToFormat(format, response)});
      }
    }

    if(stream) {
      // Wait for decryption to complete
      stream.end();
      await new Promise(resolve =>
        stream.on("finish", () => {
          resolve();
        })
      );
    }
  }
/**
   * Download a part from a content object. The fromByte and range parameters can be used to specify a
   * specific section of the part to download.
   *
   * @methodGroup Parts and Files
   * @namedParams
   * @param {string=} libraryId - ID of the library
   * @param {string=} objectId - ID of the object
   * @param {string=} versionHash - Hash of the object version - if not specified, latest version will be used
   * @param {string} partHash - Hash of the part to download
   * @param {string=} format="arrayBuffer" - Format in which to return the data
   * @param {boolean=} chunked=false - If specified, part will be downloaded and decrypted in chunks. The
   * specified callback will be invoked on completion of each chunk. This is recommended for large files,
   * especially if they are encrypted.
   * @param {number=} chunkSize=1000000 - If doing chunked download, size of each chunk to fetch
   * @param {function=} callback - Will be called on completion of each chunk
   * - Signature: ({bytesFinished, bytesTotal, chunk}) => {}
   *
   * Note: If the part is encrypted, bytesFinished/bytesTotal will not exactly match the size of the data
   * received. These values correspond to the size of the encrypted data - when decrypted, the part will be
   * slightly smaller.
   *
   * @returns {Promise<ArrayBuffer>} - Part data in the specified format
   */
Download a part from a content object. The fromByte and range parameters can be used to specify a
specific section of the part to download.



If the part is encrypted, bytesFinished/bytesTotal will not exactly match the size of the data
received. These values correspond to the size of the encrypted data - when decrypted, the part will be
slightly smaller.

@returns {Promise} - Part data in the specified format
Download a part from a content object . The fromByte and range parameters can be used to specify a specific section of the part to download . If the part is encrypted bytesFinished / bytesTotal will not exactly match the size of the data received . These values correspond to the size of the encrypted data - when decrypted the part will be slightly smaller . @returns { Promise } - Part data in the specified format
async DownloadPart({
    libraryId,
    objectId,
    versionHash,
    partHash,
    format="arrayBuffer",
    chunked=false,
    chunkSize=10000000,
    callback
  }) {
    if(chunked && !callback) { throw Error("No callback specified for chunked part download"); }
    if(versionHash) { objectId = this.utils.DecodeVersionHash(versionHash).objectId; }
    const encrypted = partHash.startsWith("hqpe");
    const encryption = encrypted ? "cgck" : "none";
    const path = UrlJoin("q", versionHash || objectId, "data", partHash);
    let headers = await this.authClient.AuthorizationHeader({libraryId, objectId, versionHash, encryption});
    let conk;
    if(encrypted) {
      conk = await this.EncryptionConk({libraryId, objectId});
    }
    if(!chunked) {
      const response = await this.HttpClient.Request({headers, method: "GET", path: path});
      let data = await response.arrayBuffer();
      if(encrypted) {
        data = await Crypto.Decrypt(conk, data);
      }
      return await ResponseToFormat(
        format,
        new Response(data)
      );
    }
    const bytesTotal = (await this.ContentPart({libraryId, objectId, versionHash, partHash})).part.size;
    let bytesFinished = 0;
    let stream;
    if(encrypted) {
      stream = await Crypto.OpenDecryptionStream(conk);
      stream = stream.on("data", async chunk => {
        if(format !== "buffer") {
          const arrayBuffer = chunk.buffer.slice(chunk.byteOffset, chunk.byteOffset + chunk.byteLength);
          if(format === "arrayBuffer") {
            chunk = arrayBuffer;
          } else {
            chunk = await ResponseToFormat(
              format,
              new Response(arrayBuffer)
            );
          }
        }
        callback({
          bytesFinished,
          bytesTotal,
          chunk
        });
      });
    }
    const totalChunks = Math.ceil(bytesTotal / chunkSize);
    for(let i = 0; i < totalChunks; i++) {
      headers["Range"] = `bytes=${bytesFinished}-${bytesFinished + chunkSize - 1}`;
      const response = await this.HttpClient.Request({headers, method: "GET", path: path});
      bytesFinished = Math.min(bytesFinished + chunkSize, bytesTotal);
      if(encrypted) {
        stream.write(new Uint8Array(await response.arrayBuffer()));
      } else {
        callback({bytesFinished, bytesTotal, chunk: await ResponseToFormat(format, response)});
      }
    }
    if(stream) {
      stream.end();
      await new Promise(resolve =>
        stream.on("finish", () => {
          resolve();
        })
      );
    }
  }
async DownloadPart ( { libraryId , objectId , versionHash , partHash , format = "arrayBuffer" , chunked = false , chunkSize = 10000000 , callback } ) { if ( chunked && ! callback ) { throw Error ( "No callback specified for chunked part download" ) ; } if ( versionHash ) { objectId = this . utils . DecodeVersionHash ( versionHash ) . objectId ; } const encrypted = partHash . startsWith ( "hqpe" ) ; const encryption = encrypted ? "cgck" : "none" ; const path = UrlJoin ( "q" , versionHash || objectId , "data" , partHash ) ; let headers = await this . authClient . AuthorizationHeader ( { libraryId , objectId , versionHash , encryption } ) ; let conk ; if ( encrypted ) { conk = await this . EncryptionConk ( { libraryId , objectId } ) ; } if ( ! chunked ) { const response = await this . HttpClient . Request ( { headers , method : "GET" , path : path } ) ; let data = await response . arrayBuffer ( ) ; if ( encrypted ) { data = await Crypto . Decrypt ( conk , data ) ; } return await ResponseToFormat ( format , new Response ( data ) ) ; } const bytesTotal = ( await this . ContentPart ( { libraryId , objectId , versionHash , partHash } ) ) . part . size ; let bytesFinished = 0 ; let stream ; if ( encrypted ) { stream = await Crypto . OpenDecryptionStream ( conk ) ; stream = stream . on ( "data" , async chunk => { if ( format !== "buffer" ) { const arrayBuffer = chunk . buffer . slice ( chunk . byteOffset , chunk . byteOffset + chunk . byteLength ) ; if ( format === "arrayBuffer" ) { chunk = arrayBuffer ; } else { chunk = await ResponseToFormat ( format , new Response ( arrayBuffer ) ) ; } } callback ( { bytesFinished , bytesTotal , chunk } ) ; } ) ; } const totalChunks = Math . ceil ( bytesTotal / chunkSize ) ; for ( let i = 0 ; i < totalChunks ; i ++ ) { headers [ "Range" ] = ` ${ bytesFinished } ${ bytesFinished + chunkSize - 1 } ` ; const response = await this . HttpClient . Request ( { headers , method : "GET" , path : path } ) ; bytesFinished = Math . min ( bytesFinished + chunkSize , bytesTotal ) ; if ( encrypted ) { stream . write ( new Uint8Array ( await response . arrayBuffer ( ) ) ) ; } else { callback ( { bytesFinished , bytesTotal , chunk : await ResponseToFormat ( format , response ) } ) ; } } if ( stream ) { stream . end ( ) ; await new Promise ( resolve => stream . on ( "finish" , ( ) => { resolve ( ) ; } ) ) ; } }
Download a part from a content object.
Download a part from a content object .
// Download and decrypt entire part // Download part in chunks // Set up decryption stream // Turn buffer into desired format, if necessary // Wait for decryption to complete