mixpart

raw JSON →
0.0.5 verified Thu Apr 23 auth: no javascript maintenance

The `mixpart` library is a high-performance streaming parser for `multipart/mixed` messages in Node.js, designed for optimal memory efficiency and robust error handling. It currently ships as version `0.0.5` and is primarily intended as a private workspace package within a monorepo, implying a stable but internally-focused release cadence rather than frequent public updates. Its key differentiators include true streaming processing where each message payload is exposed as a `ReadableStream`, preventing full buffering of entire parts, and zero memory buffering for message payloads. It also features built-in memory safety configurations to guard against unbounded memory growth from malformed data, optimized search algorithms using Node.js `Buffer.indexOf` for fast boundary detection, and proper ISO-8859-1 header decoding per HTTP standards. The package also provides comprehensive TypeScript support.

error MixpartError: Header size limit exceeded.
cause The cumulative size of headers for a single multipart part exceeded the configured `maxHeaderSize` limit, often due to extremely long header lines or an excessive number of headers in malformed input.
fix
Increase the maxHeaderSize option in ParserOptions if larger headers are legitimately expected, or investigate the source of the multipart data for potential malicious input. Default is 64KB.
error MixpartError: Boundary buffer limit exceeded.
cause The internal buffer used for detecting multipart boundaries grew beyond `maxBoundaryBuffer` without finding a complete boundary, typically indicating malformed input attempting to create a fake partial boundary.
fix
Increase the maxBoundaryBuffer option in ParserOptions if very long or complex boundary patterns are legitimately expected, or, more commonly, inspect the incoming data stream for signs of corruption or malicious attempts to exhaust memory.
gotcha This package is explicitly noted as a 'private workspace package' and is 'used internally by other packages in this monorepo.' It is not intended for public installation or direct external use and may not follow standard npm release practices or support cycles for external consumers.
fix Avoid direct installation or use unless explicitly instructed by the package maintainers; seek alternative public libraries for general multipart parsing needs.
gotcha The parser includes configurable memory safety limits (e.g., `maxHeaderSize`, `maxBoundaryBuffer`). Without proper configuration or with insufficient limits, especially when processing untrusted or malformed input, the parser could still be vulnerable to unbounded memory growth or denial-of-service attacks.
fix Always configure `ParserOptions` with appropriate `maxHeaderSize` and `maxBoundaryBuffer` values based on expected input and security requirements when calling `parseMultipartStream`.
gotcha Headers are strictly decoded using ISO-8859-1 to comply with HTTP standards. Developers expecting UTF-8 for all string content, particularly for header values that might contain non-ASCII characters outside of specific encodings like RFC 2047, may encounter unexpected character representations.
fix Be aware that header values from `message.headers.get()` are ISO-8859-1 decoded. If specific header fields are known to use different encodings (e.g., RFC 2047 encoded-word syntax), additional decoding logic may be required by the application.
npm install mixpart
yarn add mixpart
pnpm add mixpart

Demonstrates how to parse a multipart/mixed stream, access headers, and stream the payload of each part. It includes a simulated multipart response for a runnable example.

import { parseMultipartStream, MultipartMessage } from "mixpart";

// Simulate a fetch call to a multipart/mixed endpoint
async function simulateMultipartFetch() {
  // In a real application, replace this with an actual fetch call
  // For demonstration, we'll create a dummy ReadableStream
  const dummyStream = new ReadableStream({
    start(controller) {
      controller.enqueue(new TextEncoder().encode(
        '--BOUNDARY\r\n'
      ));
      controller.enqueue(new TextEncoder().encode(
        'Content-Type: text/plain\r\n'
      ));
      controller.enqueue(new TextEncoder().encode(
        'X-Custom-Header: hello\r\n'
      ));
      controller.enqueue(new TextEncoder().encode(
        '\r\n'
      ));
      controller.enqueue(new TextEncoder().encode(
        'This is part one.\r\n'
      ));
      controller.enqueue(new TextEncoder().encode(
        '--BOUNDARY\r\n'
      ));
      controller.enqueue(new TextEncoder().encode(
        'Content-Type: application/json\r\n'
      ));
      controller.enqueue(new TextEncoder().encode(
        '\r\n'
      ));
      controller.enqueue(new TextEncoder().encode(
        '{"key": "value", "number": 123}\r\n'
      ));
      controller.enqueue(new TextEncoder().encode(
        '--BOUNDARY--\r\n'
      ));
      controller.close();
    }
  });

  // A mock Response object with a 'body' property
  const mockResponse = { 
    body: dummyStream,
    headers: new Headers({'content-type': 'multipart/mixed; boundary=BOUNDARY'})
  };

  for await (const message of parseMultipartStream(mockResponse as Response)) {
    console.log("\n--- New Message ---");
    console.log("Headers:");
    for (const [key, value] of message.headers.entries()) {
      console.log(`  ${key}: ${value}`);
    }

    const contentType = message.headers.get("content-type");
    const customHeader = message.headers.get("x-custom-header");

    console.log("Content-Type:", contentType);

    let payloadContent = '';
    const reader = message.payload.getReader();
    while (true) {
      const { done, value } = await reader.read();
      if (done) break;
      payloadContent += new TextDecoder().decode(value);
    }
    console.log("Payload (full):");
    console.log(payloadContent.trim()); // Trim to remove potential trailing newlines from stream simulation
  }
}

simulateMultipartFetch().catch(console.error);