Package Exports
- meros
- meros/browser
- meros/node
Readme
meros
· From Ancient Greek μέρος (méros, "part").
A fast utility for reading streamed multipart/mixed responses.
⚙️ Install
yarn add meros
🚀 Usage
// Rely on bundler/environment dection
import { meros } from 'meros';
const parts = await fetch('/fetch-multipart').then(meros);
// As a simple Async Generator
for await (const part of parts) {
// Do something with this part
}
// Used with rxjs streams
from(parts).pipe(
tap((part) => {
// Do something with it
}),
);
Specific Environment
// Browser
import { meros } from 'meros/browser';
// import { meros } from 'https://cdn.skypack.dev/meros';
const parts = await fetch('/fetch-multipart').then(meros);
// Node
import http from 'http';
import { meros } from 'meros/node';
const response = await new Promise((resolve) => {
const request = http.get(`http://my-domain/mock-ep`, (response) => {
resolve(response);
});
request.end();
});
const parts = await meros(response);
🎒 Notes
This library aims to implement RFC1341 in its entirety, however there have been some types left out as we aim to be on the consuming side, than the server side (but we do support Node clients).
content-type
is assumed to stay consistent between parts, and therefore the "fall through" approach is recommended and to only be given at the start. Ie only give itcontent-type
as a header once, and only for the first chunk.
Please note;
Because encapsulation boundaries must not appear in the body parts being encapsulated, a user agent must exercise care to choose a unique boundary.
~ RFC1341 7.2.1
So be sure to calculate a boundary that can be guaranteed to never exist in the body.
- We do not support the
/alternative
,/digest
or/parallel
subtype at this time. - We also do not support nested multiparts
🔎 API
Browser ~ function meros<T=unknown>(response: Response): Promise<Response | AsyncGenerator<T>>;
Node ~ function meros<T=unknown>(response: IncomingMessage): Promise<IncomingMessage | AsyncGenerator<T>>;
Returns an async generator that yields on every part. Worth noting that if multiple parts are present in one chunk, each part will yield independently.
If the
content-type
is a multipart, then it will resolve with the response argument.
💨 Benchmark
Ran with Node v15.1.0
Validation :: node
✔ meros
✘ it-multipart (FAILED @ "should match reference patch set")
Benchmark :: node
meros x 7,892 ops/sec ±0.92% (72 runs sampled)
it-multipart x 6,161 ops/sec ±1.77% (76 runs sampled)
Validation :: browser
✔ meros
✘ fetch-multipart-graphql (FAILED @ "should match reference patch set")
Benchmark :: browser
meros x 13,641 ops/sec ±2.42% (74 runs sampled)
fetch-multipart-graphql x 8,406 ops/sec ±1.88% (74 runs sampled)
Reference patch set
content-type: "multipart/mixed; boundary=abc123"
preamble
--abc123
Content-Type: application/json
Content-Length: 17
{"hello":"world"}
--abc123
Content-Type: application/json
Content-Length: 17
{"other":"world"}
--abc123
Content-Type: application/json
Content-Length: 19
{"another":"world"}
--abc123
Content-Type: application/json
Content-Length: 39
{"massive":{"nested":{"world":"okay"}}}
--abc123
Content-Type: text/plain
Content-Length: 22
"should be plain text"
--abc123--
epilogue
--abc123
Content-Type: application/json
Content-Length: 19
{"shouldnt":"work"}
❤ Thanks
Special thanks to Luke Edwards for performance guidance and high level api design.
License
MIT © Marais Rossouw