@remix-run/multipart-parser 0.13.0 → 0.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  `multipart-parser` is a fast, streaming multipart parser that works in **any JavaScript environment**, from serverless functions to traditional servers. Whether you're handling file uploads, parsing email attachments, or working with multipart API responses, `multipart-parser` has you covered.
4
4
 
5
- ## 🚀 Why multipart-parser?
5
+ ## Why multipart-parser?
6
6
 
7
7
  - **Universal JavaScript** - One library that works everywhere: Node.js, Bun, Deno, Cloudflare Workers, and browsers
8
8
  - **Blazing Fast** - Consistently outperforms popular alternatives like busboy in benchmarks
@@ -12,14 +12,14 @@
12
12
  - **Standards Based** - Built on the web standard [Streams API](https://developer.mozilla.org/en-US/docs/Web/API/Streams_API) for maximum compatibility
13
13
  - **Production Ready** - Battle-tested error handling with specific error types for common scenarios
14
14
 
15
- ## 📦 Features
15
+ ## Features
16
16
 
17
- - Parse file uploads (`multipart/form-data`) with automatic field and file detection
18
- - Support for all `multipart/*` content types (mixed, alternative, related, etc.)
19
- - Convenient `MultipartPart` API with `arrayBuffer`, `bytes`, `text`, `size`, and metadata access
20
- - Built-in file size limiting to prevent abuse
21
- - First-class Node.js support with native `http.IncomingMessage` compatibility
22
- - [Demos for every major runtime](https://github.com/remix-run/remix/tree/main/packages/multipart-parser/demos)
17
+ - **File Upload Parsing** - Parse file uploads (`multipart/form-data`) with automatic field and file detection
18
+ - **Full Multipart Support** - Support for all `multipart/*` content types (mixed, alternative, related, etc.)
19
+ - **Convenient API** - `MultipartPart` API with `arrayBuffer`, `bytes`, `text`, `size`, and metadata access
20
+ - **File Size Limiting** - Built-in file size limiting to prevent abuse
21
+ - **Node.js Support** - First-class Node.js support with native `http.IncomingMessage` compatibility
22
+ - **Runtime Demos** - [Demos for every major runtime](https://github.com/remix-run/remix/tree/main/packages/multipart-parser/demos)
23
23
 
24
24
  ## Installation
25
25
 
@@ -3,20 +3,32 @@ import Headers from '@remix-run/headers';
3
3
  * The base class for errors thrown by the multipart parser.
4
4
  */
5
5
  export declare class MultipartParseError extends Error {
6
+ /**
7
+ * @param message The error message
8
+ */
6
9
  constructor(message: string);
7
10
  }
8
11
  /**
9
12
  * An error thrown when the maximum allowed size of a header is exceeded.
10
13
  */
11
14
  export declare class MaxHeaderSizeExceededError extends MultipartParseError {
15
+ /**
16
+ * @param maxHeaderSize The maximum header size that was exceeded
17
+ */
12
18
  constructor(maxHeaderSize: number);
13
19
  }
14
20
  /**
15
21
  * An error thrown when the maximum allowed size of a file is exceeded.
16
22
  */
17
23
  export declare class MaxFileSizeExceededError extends MultipartParseError {
24
+ /**
25
+ * @param maxFileSize The maximum file size that was exceeded
26
+ */
18
27
  constructor(maxFileSize: number);
19
28
  }
29
+ /**
30
+ * Options for parsing a multipart message.
31
+ */
20
32
  export interface ParseMultipartOptions {
21
33
  /**
22
34
  * The boundary string used to separate parts in the multipart message,
@@ -27,14 +39,14 @@ export interface ParseMultipartOptions {
27
39
  * The maximum allowed size of a header in bytes. If an individual part's header
28
40
  * exceeds this size, a `MaxHeaderSizeExceededError` will be thrown.
29
41
  *
30
- * Default: 8 KiB
42
+ * @default 8192 (8 KiB)
31
43
  */
32
44
  maxHeaderSize?: number;
33
45
  /**
34
46
  * The maximum allowed size of a file in bytes. If an individual part's content
35
47
  * exceeds this size, a `MaxFileSizeExceededError` will be thrown.
36
48
  *
37
- * Default: 2 MiB
49
+ * @default 2097152 (2 MiB)
38
50
  */
39
51
  maxFileSize?: number;
40
52
  }
@@ -60,6 +72,9 @@ export declare function parseMultipart(message: Uint8Array | Iterable<Uint8Array
60
72
  * @return An async generator that yields `MultipartPart` objects
61
73
  */
62
74
  export declare function parseMultipartStream(stream: ReadableStream<Uint8Array>, options: ParseMultipartOptions): AsyncGenerator<MultipartPart, void, unknown>;
75
+ /**
76
+ * Options for configuring a `MultipartParser`.
77
+ */
63
78
  export type MultipartParserOptions = Omit<ParseMultipartOptions, 'boundary'>;
64
79
  /**
65
80
  * A streaming parser for `multipart/*` HTTP messages.
@@ -69,6 +84,10 @@ export declare class MultipartParser {
69
84
  readonly boundary: string;
70
85
  readonly maxHeaderSize: number;
71
86
  readonly maxFileSize: number;
87
+ /**
88
+ * @param boundary The boundary string used to separate parts
89
+ * @param options Options for the parser
90
+ */
72
91
  constructor(boundary: string, options?: MultipartParserOptions);
73
92
  /**
74
93
  * Write a chunk of data to the parser.
@@ -96,6 +115,10 @@ export declare class MultipartPart {
96
115
  * The raw content of this part as an array of `Uint8Array` chunks.
97
116
  */
98
117
  readonly content: Uint8Array[];
118
+ /**
119
+ * @param header The raw header bytes
120
+ * @param content The content chunks
121
+ */
99
122
  constructor(header: Uint8Array, content: Uint8Array[]);
100
123
  /**
101
124
  * The content of this part as an `ArrayBuffer`.
@@ -1 +1 @@
1
- {"version":3,"file":"multipart.d.ts","sourceRoot":"","sources":["../../src/lib/multipart.ts"],"names":[],"mappings":"AAAA,OAAO,OAAO,MAAM,oBAAoB,CAAA;AAMxC;;GAEG;AACH,qBAAa,mBAAoB,SAAQ,KAAK;gBAChC,OAAO,EAAE,MAAM;CAI5B;AAED;;GAEG;AACH,qBAAa,0BAA2B,SAAQ,mBAAmB;gBACrD,aAAa,EAAE,MAAM;CAIlC;AAED;;GAEG;AACH,qBAAa,wBAAyB,SAAQ,mBAAmB;gBACnD,WAAW,EAAE,MAAM;CAIhC;AAED,MAAM,WAAW,qBAAqB;IACpC;;;OAGG;IACH,QAAQ,EAAE,MAAM,CAAA;IAChB;;;;;OAKG;IACH,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB;;;;;OAKG;IACH,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB;AAED;;;;;;;;;GASG;AACH,wBAAiB,cAAc,CAC7B,OAAO,EAAE,UAAU,GAAG,QAAQ,CAAC,UAAU,CAAC,EAC1C,OAAO,EAAE,qBAAqB,GAC7B,SAAS,CAAC,aAAa,EAAE,IAAI,EAAE,OAAO,CAAC,CAmBzC;AAED;;;;;;;;;GASG;AACH,wBAAuB,oBAAoB,CACzC,MAAM,EAAE,cAAc,CAAC,UAAU,CAAC,EAClC,OAAO,EAAE,qBAAqB,GAC7B,cAAc,CAAC,aAAa,EAAE,IAAI,EAAE,OAAO,CAAC,CAe9C;AAED,MAAM,MAAM,sBAAsB,GAAG,IAAI,CAAC,qBAAqB,EAAE,UAAU,CAAC,CAAA;AAa5E;;GAEG;AACH,qBAAa,eAAe;;IAC1B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAA;IAC9B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;gBAahB,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,sBAAsB;IAY9D;;;;;OAKG;IACF,KAAK,CAAC,KAAK,EAAE,UAAU,GAAG,SAAS,CAAC,aAAa,EAAE,IAAI,EAAE,OAAO,CAAC;IA0HlE;;;;;;;OAOG;IACH,MAAM,IAAI,IAAI;CAKf;AAID;;GAEG;AACH,qBAAa,aAAa;;IACxB;;OAEG;IACH,QAAQ,CAAC,OAAO,EAAE,UAAU,EAAE,CAAA;gBAKlB,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,UAAU,EAAE;IAKrD;;OAEG;IACH,IAAI,WAAW,IAAI,WAAW,CAE7B;IAED;;;OAGG;IACH,IAAI,KAAK,IAAI,UAAU,CAUtB;IAED;;OAEG;IACH,IAAI,OAAO,IAAI,OAAO,CAMrB;IAED;;OAEG;IACH,IAAI,MAAM,IAAI,OAAO,CAEpB;IAED;;OAEG;IACH,IAAI,MAAM,IAAI,OAAO,CAEpB;IAED;;OAEG;IACH,IAAI,QAAQ,IAAI,MAAM,GAAG,SAAS,CAEjC;IAED;;OAEG;IACH,IAAI,SAAS,IAAI,MAAM,GAAG,SAAS,CAElC;IAED;;OAEG;IACH,IAAI,IAAI,IAAI,MAAM,GAAG,SAAS,CAE7B;IAED;;OAEG;IACH,IAAI,IAAI,IAAI,MAAM,CAQjB;IAED;;;;;OAKG;IACH,IAAI,IAAI,IAAI,MAAM,CAEjB;CACF"}
1
+ {"version":3,"file":"multipart.d.ts","sourceRoot":"","sources":["../../src/lib/multipart.ts"],"names":[],"mappings":"AAAA,OAAO,OAAO,MAAM,oBAAoB,CAAA;AAUxC;;GAEG;AACH,qBAAa,mBAAoB,SAAQ,KAAK;IAC5C;;OAEG;gBACS,OAAO,EAAE,MAAM;CAI5B;AAED;;GAEG;AACH,qBAAa,0BAA2B,SAAQ,mBAAmB;IACjE;;OAEG;gBACS,aAAa,EAAE,MAAM;CAIlC;AAED;;GAEG;AACH,qBAAa,wBAAyB,SAAQ,mBAAmB;IAC/D;;OAEG;gBACS,WAAW,EAAE,MAAM;CAIhC;AAED;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC;;;OAGG;IACH,QAAQ,EAAE,MAAM,CAAA;IAChB;;;;;OAKG;IACH,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB;;;;;OAKG;IACH,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB;AAED;;;;;;;;;GASG;AACH,wBAAiB,cAAc,CAC7B,OAAO,EAAE,UAAU,GAAG,QAAQ,CAAC,UAAU,CAAC,EAC1C,OAAO,EAAE,qBAAqB,GAC7B,SAAS,CAAC,aAAa,EAAE,IAAI,EAAE,OAAO,CAAC,CAmBzC;AAED;;;;;;;;;GASG;AACH,wBAAuB,oBAAoB,CACzC,MAAM,EAAE,cAAc,CAAC,UAAU,CAAC,EAClC,OAAO,EAAE,qBAAqB,GAC7B,cAAc,CAAC,aAAa,EAAE,IAAI,EAAE,OAAO,CAAC,CAe9C;AAED;;GAEG;AACH,MAAM,MAAM,sBAAsB,GAAG,IAAI,CAAC,qBAAqB,EAAE,UAAU,CAAC,CAAA;AAa5E;;GAEG;AACH,qBAAa,eAAe;;IAC1B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAA;IAC9B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;IAa5B;;;OAGG;gBACS,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,sBAAsB;IAY9D;;;;;OAKG;IACF,KAAK,CAAC,KAAK,EAAE,UAAU,GAAG,SAAS,CAAC,aAAa,EAAE,IAAI,EAAE,OAAO,CAAC;IA0HlE;;;;;;;OAOG;IACH,MAAM,IAAI,IAAI;CAKf;AAID;;GAEG;AACH,qBAAa,aAAa;;IACxB;;OAEG;IACH,QAAQ,CAAC,OAAO,EAAE,UAAU,EAAE,CAAA;IAK9B;;;OAGG;gBACS,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,UAAU,EAAE;IAKrD;;OAEG;IACH,IAAI,WAAW,IAAI,WAAW,CAE7B;IAED;;;OAGG;IACH,IAAI,KAAK,IAAI,UAAU,CAUtB;IAED;;OAEG;IACH,IAAI,OAAO,IAAI,OAAO,CAMrB;IAED;;OAEG;IACH,IAAI,MAAM,IAAI,OAAO,CAEpB;IAED;;OAEG;IACH,IAAI,MAAM,IAAI,OAAO,CAEpB;IAED;;OAEG;IACH,IAAI,QAAQ,IAAI,MAAM,GAAG,SAAS,CAEjC;IAED;;OAEG;IACH,IAAI,SAAS,IAAI,MAAM,GAAG,SAAS,CAElC;IAED;;OAEG;IACH,IAAI,IAAI,IAAI,MAAM,GAAG,SAAS,CAE7B;IAED;;OAEG;IACH,IAAI,IAAI,IAAI,MAAM,CAQjB;IAED;;;;;OAKG;IACH,IAAI,IAAI,IAAI,MAAM,CAEjB;CACF"}
@@ -1,10 +1,13 @@
1
1
  import Headers from '@remix-run/headers';
2
+ import { createSearch, createPartialTailSearch, } from "./buffer-search.js";
2
3
  import { readStream } from "./read-stream.js";
3
- import { createSearch, createPartialTailSearch } from "./buffer-search.js";
4
4
  /**
5
5
  * The base class for errors thrown by the multipart parser.
6
6
  */
7
7
  export class MultipartParseError extends Error {
8
+ /**
9
+ * @param message The error message
10
+ */
8
11
  constructor(message) {
9
12
  super(message);
10
13
  this.name = 'MultipartParseError';
@@ -14,6 +17,9 @@ export class MultipartParseError extends Error {
14
17
  * An error thrown when the maximum allowed size of a header is exceeded.
15
18
  */
16
19
  export class MaxHeaderSizeExceededError extends MultipartParseError {
20
+ /**
21
+ * @param maxHeaderSize The maximum header size that was exceeded
22
+ */
17
23
  constructor(maxHeaderSize) {
18
24
  super(`Multipart header size exceeds maximum allowed size of ${maxHeaderSize} bytes`);
19
25
  this.name = 'MaxHeaderSizeExceededError';
@@ -23,6 +29,9 @@ export class MaxHeaderSizeExceededError extends MultipartParseError {
23
29
  * An error thrown when the maximum allowed size of a file is exceeded.
24
30
  */
25
31
  export class MaxFileSizeExceededError extends MultipartParseError {
32
+ /**
33
+ * @param maxFileSize The maximum file size that was exceeded
34
+ */
26
35
  constructor(maxFileSize) {
27
36
  super(`File size exceeds maximum allowed size of ${maxFileSize} bytes`);
28
37
  this.name = 'MaxFileSizeExceededError';
@@ -103,6 +112,10 @@ export class MultipartParser {
103
112
  #buffer = null;
104
113
  #currentPart = null;
105
114
  #contentLength = 0;
115
+ /**
116
+ * @param boundary The boundary string used to separate parts
117
+ * @param options Options for the parser
118
+ */
106
119
  constructor(boundary, options) {
107
120
  this.boundary = boundary;
108
121
  this.maxHeaderSize = options?.maxHeaderSize ?? 8 * oneKb;
@@ -236,6 +249,10 @@ export class MultipartPart {
236
249
  content;
237
250
  #header;
238
251
  #headers;
252
+ /**
253
+ * @param header The raw header bytes
254
+ * @param content The content chunks
255
+ */
239
256
  constructor(header, content) {
240
257
  this.#header = header;
241
258
  this.content = content;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@remix-run/multipart-parser",
3
- "version": "0.13.0",
3
+ "version": "0.14.0",
4
4
  "description": "A fast, efficient parser for multipart streams in any JavaScript environment",
5
5
  "author": "Michael Jackson <mjijackson@gmail.com>",
6
6
  "repository": {
@@ -29,8 +29,8 @@
29
29
  },
30
30
  "./package.json": "./package.json"
31
31
  },
32
- "dependencies": {
33
- "@remix-run/headers": "^0.15.0"
32
+ "peerDependencies": {
33
+ "@remix-run/headers": "^0.18.0"
34
34
  },
35
35
  "devDependencies": {
36
36
  "@types/node": "^24.6.0",
@@ -1,13 +1,20 @@
1
1
  import Headers from '@remix-run/headers'
2
2
 
3
+ import {
4
+ createSearch,
5
+ createPartialTailSearch,
6
+ type SearchFunction,
7
+ type PartialTailSearchFunction,
8
+ } from './buffer-search.ts'
3
9
  import { readStream } from './read-stream.ts'
4
- import type { SearchFunction, PartialTailSearchFunction } from './buffer-search.ts'
5
- import { createSearch, createPartialTailSearch } from './buffer-search.ts'
6
10
 
7
11
  /**
8
12
  * The base class for errors thrown by the multipart parser.
9
13
  */
10
14
  export class MultipartParseError extends Error {
15
+ /**
16
+ * @param message The error message
17
+ */
11
18
  constructor(message: string) {
12
19
  super(message)
13
20
  this.name = 'MultipartParseError'
@@ -18,6 +25,9 @@ export class MultipartParseError extends Error {
18
25
  * An error thrown when the maximum allowed size of a header is exceeded.
19
26
  */
20
27
  export class MaxHeaderSizeExceededError extends MultipartParseError {
28
+ /**
29
+ * @param maxHeaderSize The maximum header size that was exceeded
30
+ */
21
31
  constructor(maxHeaderSize: number) {
22
32
  super(`Multipart header size exceeds maximum allowed size of ${maxHeaderSize} bytes`)
23
33
  this.name = 'MaxHeaderSizeExceededError'
@@ -28,12 +38,18 @@ export class MaxHeaderSizeExceededError extends MultipartParseError {
28
38
  * An error thrown when the maximum allowed size of a file is exceeded.
29
39
  */
30
40
  export class MaxFileSizeExceededError extends MultipartParseError {
41
+ /**
42
+ * @param maxFileSize The maximum file size that was exceeded
43
+ */
31
44
  constructor(maxFileSize: number) {
32
45
  super(`File size exceeds maximum allowed size of ${maxFileSize} bytes`)
33
46
  this.name = 'MaxFileSizeExceededError'
34
47
  }
35
48
  }
36
49
 
50
+ /**
51
+ * Options for parsing a multipart message.
52
+ */
37
53
  export interface ParseMultipartOptions {
38
54
  /**
39
55
  * The boundary string used to separate parts in the multipart message,
@@ -44,14 +60,14 @@ export interface ParseMultipartOptions {
44
60
  * The maximum allowed size of a header in bytes. If an individual part's header
45
61
  * exceeds this size, a `MaxHeaderSizeExceededError` will be thrown.
46
62
  *
47
- * Default: 8 KiB
63
+ * @default 8192 (8 KiB)
48
64
  */
49
65
  maxHeaderSize?: number
50
66
  /**
51
67
  * The maximum allowed size of a file in bytes. If an individual part's content
52
68
  * exceeds this size, a `MaxFileSizeExceededError` will be thrown.
53
69
  *
54
- * Default: 2 MiB
70
+ * @default 2097152 (2 MiB)
55
71
  */
56
72
  maxFileSize?: number
57
73
  }
@@ -120,6 +136,9 @@ export async function* parseMultipartStream(
120
136
  parser.finish()
121
137
  }
122
138
 
139
+ /**
140
+ * Options for configuring a `MultipartParser`.
141
+ */
123
142
  export type MultipartParserOptions = Omit<ParseMultipartOptions, 'boundary'>
124
143
 
125
144
  const MultipartParserStateStart = 0
@@ -152,6 +171,10 @@ export class MultipartParser {
152
171
  #currentPart: MultipartPart | null = null
153
172
  #contentLength = 0
154
173
 
174
+ /**
175
+ * @param boundary The boundary string used to separate parts
176
+ * @param options Options for the parser
177
+ */
155
178
  constructor(boundary: string, options?: MultipartParserOptions) {
156
179
  this.boundary = boundary
157
180
  this.maxHeaderSize = options?.maxHeaderSize ?? 8 * oneKb
@@ -321,6 +344,10 @@ export class MultipartPart {
321
344
  #header: Uint8Array
322
345
  #headers?: Headers
323
346
 
347
+ /**
348
+ * @param header The raw header bytes
349
+ * @param content The content chunks
350
+ */
324
351
  constructor(header: Uint8Array, content: Uint8Array[]) {
325
352
  this.#header = header
326
353
  this.content = content