@cloudflare/puppeteer
Version:
A high-level API to control headless Chrome over the DevTools Protocol
74 lines (65 loc) • 2.23 kB
text/typescript
/**
* @license
* Copyright 2025 Google Inc.
* SPDX-License-Identifier: Apache-2.0
*/
const HEADER_SIZE = 4; // Uint32
const MAX_MESSAGE_SIZE = 1048575; // Workers size is < 1MB
const FIRST_CHUNK_DATA_SIZE = MAX_MESSAGE_SIZE - HEADER_SIZE;
export const messageToChunks = (data: string): Uint8Array[] => {
const encoder = new TextEncoder();
const encodedUint8Array = encoder.encode(data);
// We only include the header into the first chunk
const firstChunk = new Uint8Array(
Math.min(MAX_MESSAGE_SIZE, HEADER_SIZE + encodedUint8Array.length)
);
const view = new DataView(firstChunk.buffer);
view.setUint32(0, encodedUint8Array.length, true);
firstChunk.set(
encodedUint8Array.slice(0, FIRST_CHUNK_DATA_SIZE),
HEADER_SIZE
);
const chunks: Uint8Array[] = [firstChunk];
for (let i = FIRST_CHUNK_DATA_SIZE; i < data.length; i += MAX_MESSAGE_SIZE) {
chunks.push(encodedUint8Array.slice(i, i + MAX_MESSAGE_SIZE));
}
return chunks;
};
export const chunksToMessage = (
chunks: Uint8Array[],
sessionid: string
): string | null => {
if (chunks.length === 0) {
return null;
}
const emptyBuffer = new Uint8Array(0);
const firstChunk = chunks[0] || emptyBuffer;
const view = new DataView(firstChunk.buffer);
const expectedBytes = view.getUint32(0, true);
let totalBytes = -HEADER_SIZE;
for (let i = 0; i < chunks.length; ++i) {
const curChunk = chunks[i] || emptyBuffer;
totalBytes += curChunk.length;
if (totalBytes > expectedBytes) {
throw new Error(
`Should have gotten the exact number of bytes but we got more. SessionID: ${sessionid}`
);
}
if (totalBytes === expectedBytes) {
const chunksToCombine = chunks.splice(0, i + 1);
chunksToCombine[0] = firstChunk.subarray(HEADER_SIZE);
const combined = new Uint8Array(expectedBytes);
let offset = 0;
for (let j = 0; j <= i; ++j) {
const chunk = chunksToCombine[j] || emptyBuffer;
combined.set(chunk, offset);
offset += chunk.length;
}
const decoder = new TextDecoder();
// return decoder.decode(combined)
const message = decoder.decode(combined);
return message;
}
}
return null;
};