A fast 642B utility that makes reading multipart responses simple
npm install merosA utility that makes reading multipart responses simple
This is free to use software, but if you do like it, consider supporting me ❤️


- No dependencies
- Seamless api
- Super performant
- Supports _any_[^1] content-type
- _preamble_ and _epilogue_ don't yield
- Browser/Node Compatible
- Plugs into existing libraries like Relay and rxjs
[^1]: By default, we'll look for JSON, and parse that for you. If not, we'll give you the body as what was streamed.
> Visit /examples for more info!
``ts
// Relies on bundler/environment detection
import { meros } from 'meros';
const parts = await fetch('/api').then(meros);
// As a simple Async Generator
for await (const part of parts) {
// Do something with this part
}
// Used with rxjs streams
from(parts).subscribe((part) => {
// Do something with it
});
`
#### _Browser_
`ts
import { meros } from 'meros/browser';
// import { meros } from 'https://cdn.skypack.dev/meros';
const parts = await fetch('/api').then(meros);
`
#### _Node_
`ts
import http from 'http';
import { meros } from 'meros/node';
const response = await new Promise((resolve) => {
const request = http.get(http://example.com/api, (response) => {
resolve(response);
});
request.end();
});
const parts = await meros(response);
`
Meros offers two flavours, both for the browser and for node; but their api's are fundamentally the same.
> Note: The type Response is used loosely here and simply alludes to Node's IncomingMessage or the browser'sResponse
> type.
Returns: Promise
Meros returns a promise that will resolve to an AsyncGenerator if the response is of multipart/mixed mime, or simplyResponse
returns the if something else; helpful for middlewares. The idea here being that you run meros as a chain off
fetch.
`ts`
fetch('/api').then(meros);
> If the content-type is NOT a multipart, then meros will resolve with the response argument.`
>
>
> Example on how to handle this case
>
> ts`
> import { meros } from 'meros';
>
> const response = await fetch('/api'); // Assume this isnt multipart
> const parts = await meros(response);
>
> if (parts[Symbol.asyncIterator] < 'u') {
> for await (const part of parts) {
> // Do something with this part
> }
> } else {
> const data = await parts.json();
> }
>
>
>
each Part gives you access to:
- json: boolean ~ Tells you the body would be a JavaScript object of your defined generic T.headers: object
- ~ A key-value pair of all headers discovered from this part.body: T | Fallback
- ~ Is the _body_ of the part, either as a JavaScript object (noted by json) _or_ the base typeBuffer | string
of the environment (, for Node and Browser respectively).
#### options.multiple: boolean
Default: false
Setting this to true will yield once for all available parts of a chunk, rather than yielding once per part. This is
an optimization technique for technologies like GraphQL where rather than commit the payload to the store, to be
added-to in the next process-tick we can simply do that synchronously.
> Warning: This will alter the behaviour and yield arrays—than yield payloads.
`ts
const chunks = await fetch('/api').then((response) => meros(response, { multiple: true }));
// As a simple Async Generator
for await (const parts of chunks) {
for (const part of parts) {
// Do something with this part, maybe aggregate?
}
}
`
> via the /bench directory with Node v18.0.0
`
Node
✔ meros ~ 1,271,218 ops/sec ± 0.84%
✘ it-multipart ~ 700,039 ops/sec ± 0.72%
--
it-multipart (FAILED @ "should match reference patch set")
Browser
✔ meros ~ 800,941 ops/sec ± 1.06%
✘ fetch-multipart-graphql ~ 502,175 ops/sec ± 0.75%
--
fetch-multipart-graphql (FAILED @ "should match reference patch set")
`
Why the name? _meros_ comes from Ancient Greek μέρος méros, meaning "part".
This library aims to implement [RFC1341] in its entirety, however we aren't there yet. That being said, you may very
well use this library in other scenarios like streaming in file form uploads.
Another goal here is to aide in being the defacto standard transport library to support
@defer and @stream GraphQL directives
- No support the /alternative , /digest _or_ /parallel` subtype at this time.
- No support for nested multiparts
Special thanks to Luke Edwards for performance guidance and high level api design.
This library is simple, a mere few hundred bytes. It's easy to copy, and easy to alter. If you do, that is fine ❤️ I'm
all for the freedom of software. But please give credit where credit is due.
MIT © Marais Rossouw
[rfc1341]: https://tools.ietf.org/html/rfc1341 'The Multipart Content-Type'