ApelegHQ / ts-multipart-parser

TypeScript streaming parser for MIME multipart messages
ISC License
6 stars 1 forks source link

Provide more examples #4

Open ShookLyngs opened 10 months ago

ShookLyngs commented 10 months ago

Hi, the lib is very cool! But I find it lacks of usage/example about how to use the encodeMultipartMessage method. Could you please provide more code examples on how to encode multipart messages, and convert the resulting ReadableStream into a utf-8 renderable string?

Thanks!

corrideat commented 10 months ago

Hi @ShookLyngs!

Thanks for opening this issue. We will look into adding some more documentation, including examples.

In the meantime, you can find examples in the tests/ directory. A quick (but not necessarily the most efficient) way of converting a ReadableStream to an Uint8Array is through the Response class:

import { encodeMultipartMessage } from '@exact-realty/multipart-parser';

const ABtoU8 = new TransformStream({
    start() {},
    transform(chunk, controller) {
        controller.enqueue(new Uint8Array(chunk));
    },
});
encodeMultipartMessage('boundary', [
    {
        headers: new Headers({ 'test-header': 'example-value' }),
        body: new TextEncoder().encode('sample body'),
    },
]).pipeThrough(ABtoU8);
new Response(ABtoU8.readable)
    .arrayBuffer()
    .then((msg) => new Uint8Array(msg))
    .then(console.log); // This is the resulting Uint8Array

I say it's not the most efficient because this is converting between Uint8Array and ArrayBuffer multiple times, at ABtoU8, then at Response and then at .arrayBuffer().

A better way would be something like:

import { encodeMultipartMessage } from '@exact-realty/multipart-parser';

const reader = encodeMultipartMessage('boundary', [
    {
        headers: new Headers({ 'test-header': 'example-value' }),
        body: new TextEncoder().encode('sample body'),
    },
]).getReader();

const chunks = [];
for (;;) {
    const { done, value } = await reader.read();
    if (done) break;
    chunks.push(chunk);
}

let position = 0;
const size = chunks.reduce((acc, cv) => acc + cv.byteLength, 0);
const buffer = new ArrayBuffer(size);
const combined = new Uint8Array(buffer);

for (let chunk of chunks) {
    combined.set(new Uint8Array(chunk), position);
    position += chunk.byteLength;
}

// Result is in `combined`