diff --git a/packages/core/util.ts b/packages/core/util.ts index d5e5b191d..9bac79d7d 100644 --- a/packages/core/util.ts +++ b/packages/core/util.ts @@ -133,7 +133,23 @@ export function hOP(o: any, p: T): boolean { return Object.hasOwnProperty.call(o, p); } - +/** + * @returns validates and returns a valid atob conversion +*/ +export function parseToAtob(str: string): string { + const base64Regex = /^[A-Za-z0-9+/]+={0,2}$/; + try { + // test if str has been JSON.stringified + const parsed = JSON.parse(str); + if(base64Regex.test(parsed)){ + return atob(parsed); + } + return null; + } catch (err) { + // Not a valid JSON string, check if it's a standalone Base64 string + return base64Regex.test(str) ? atob(str) : null; + } +} /** * Generates a ~unique hash code diff --git a/packages/queryable/behaviors/parsers.ts b/packages/queryable/behaviors/parsers.ts index f649e01df..6fc113003 100644 --- a/packages/queryable/behaviors/parsers.ts +++ b/packages/queryable/behaviors/parsers.ts @@ -1,5 +1,5 @@ import { Queryable } from "../queryable.js"; -import { hOP, TimelinePipe } from "@pnp/core"; +import { hOP, TimelinePipe, parseToAtob } from "@pnp/core"; import { isFunc } from "@pnp/core"; export function DefaultParse(): TimelinePipe { @@ -25,7 +25,21 @@ export function TextParse(): TimelinePipe { export function BlobParse(): TimelinePipe { - return parseBinderWithErrorCheck(r => r.blob()); + return parseBinderWithErrorCheck( async (response) => { + const responseBody = parseToAtob(await response.clone().text()); + // handle batch responses for things that are base64, like photos https://github.com/pnp/pnpjs/issues/2825 + if(responseBody){ + // Create an array buffer from the binary string + const arrayBuffer = new ArrayBuffer(responseBody.length); + const uint8Array = new Uint8Array(arrayBuffer); + for (let i = 0; i < responseBody.length; i++) { + uint8Array[i] = responseBody.charCodeAt(i); + } + // Create a Blob from the array buffer + return new Blob([arrayBuffer], {type:response.headers.get("Content-Type")}); + } + return response.blob(); + }); } export function JSONParse(): TimelinePipe {