@remix-run/form-data-middleware 0.2.2 → 0.3.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
@@ -1,11 +1,11 @@
1
1
  # form-data-middleware
2
2
 
3
- Form body parsing middleware for Remix. It parses incoming [`FormData`](https://developer.mozilla.org/en-US/docs/Web/API/FormData) and exposes it via `context.get(FormData)`.
3
+ Form body parsing middleware for Remix. It parses incoming [`FormData`](https://developer.mozilla.org/en-US/docs/Web/API/FormData) and exposes it via `context.formData` (or `context.get(FormData)`).
4
4
 
5
5
  ## Features
6
6
 
7
7
  - **Request Form Parsing** - Parses request body form data once per request
8
- - **File Access** - Uploaded files are available from `context.get(FormData)`
8
+ - **File Access** - Uploaded files are available from `context.formData` (or `context.get(FormData)`)
9
9
  - **Custom Upload Handling** - Supports pluggable upload handlers for file processing
10
10
  - **Error Control** - Optional suppression for malformed form data
11
11
 
@@ -17,20 +17,22 @@ npm i remix
17
17
 
18
18
  ## Usage
19
19
 
20
- Use the `formData()` middleware at the router level to parse `FormData` from the request body and make it available on request context via `context.get(FormData)`.
20
+ Use the `formData()` middleware at the router level to parse `FormData` from the request body and make it available as `context.formData` (or `context.get(FormData)`).
21
+
22
+ When `formData()` runs successfully it always provides a `FormData` value. Requests that do not contain a form body, including `GET` and `HEAD` requests, receive an empty `FormData`.
21
23
 
22
24
  Uploaded files are available in the parsed `FormData` object. For a single file field, use `formData.get(name)`. For repeated file fields, use `formData.getAll(name)`.
23
25
 
24
26
  ```ts
25
- import { createRouter } from 'remix/fetch-router'
26
- import { formData } from 'remix/form-data-middleware'
27
+ import { createRouter } from 'remix/router'
28
+ import { formData } from 'remix/middleware/form-data'
27
29
 
28
30
  let router = createRouter({
29
31
  middleware: [formData()],
30
32
  })
31
33
 
32
34
  router.post('/users', async (context) => {
33
- let formData = context.get(FormData)
35
+ let formData = context.formData
34
36
  let name = formData.get('name')
35
37
  let email = formData.get('email')
36
38
 
@@ -41,12 +43,14 @@ router.post('/users', async (context) => {
41
43
  })
42
44
  ```
43
45
 
46
+ Use `context.formData` (or `context.get(FormData)`).
47
+
44
48
  ### Custom File Upload Handler
45
49
 
46
50
  You can use a custom upload handler to customize how file uploads are handled. The return value of the upload handler will be used as the value of the form field in the `FormData` object.
47
51
 
48
52
  ```ts
49
- import { formData } from 'remix/form-data-middleware'
53
+ import { formData } from 'remix/middleware/form-data'
50
54
  import { writeFile } from 'node:fs/promises'
51
55
 
52
56
  let router = createRouter({
@@ -83,7 +87,7 @@ let router = createRouter({
83
87
 
84
88
  ### Suppress Parse Errors
85
89
 
86
- Some requests may contain invalid form data that cannot be parsed. You can suppress those malformed-body parse errors by setting `suppressErrors` to `true`. In these cases, `context.get(FormData)` will be an empty `FormData` object. Multipart limit violations from `maxHeaderSize`, `maxFiles`, `maxFileSize`, `maxParts`, or `maxTotalSize` are never suppressed.
90
+ Some requests may contain invalid form data that cannot be parsed. You can suppress those malformed-body parse errors by setting `suppressErrors` to `true`. In these cases, `context.formData` will be an empty `FormData` object. Multipart limit violations from `maxHeaderSize`, `maxFiles`, `maxFileSize`, `maxParts`, or `maxTotalSize` are never suppressed.
87
91
 
88
92
  ```ts
89
93
  let router = createRouter({
@@ -1,6 +1,5 @@
1
1
  import { type FileUploadHandler, type ParseFormDataOptions } from '@remix-run/form-data-parser';
2
2
  import type { Middleware } from '@remix-run/fetch-router';
3
- type SetFormDataContextTransform = readonly [readonly [typeof FormData, FormData]];
4
3
  /**
5
4
  * Options for the {@link formData} middleware.
6
5
  */
@@ -25,6 +24,9 @@ export interface FormDataOptions extends ParseFormDataOptions {
25
24
  * @param options Options for parsing form data
26
25
  * @returns A middleware function that parses form data
27
26
  */
28
- export declare function formData(options?: FormDataOptions): Middleware<any, any, SetFormDataContextTransform>;
29
- export {};
27
+ export declare function formData(options?: FormDataOptions): Middleware<{
28
+ key: typeof FormData;
29
+ value: FormData;
30
+ property: 'formData';
31
+ }>;
30
32
  //# sourceMappingURL=form-data.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"form-data.d.ts","sourceRoot":"","sources":["../../src/lib/form-data.ts"],"names":[],"mappings":"AAAA,OAAO,EAOL,KAAK,iBAAiB,EACtB,KAAK,oBAAoB,EAC1B,MAAM,6BAA6B,CAAA;AACpC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAA;AAEzD,KAAK,2BAA2B,GAAG,SAAS,CAAC,SAAS,CAAC,OAAO,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAA;AAYlF;;GAEG;AACH,MAAM,WAAW,eAAgB,SAAQ,oBAAoB;IAC3D;;;;;OAKG;IACH,cAAc,CAAC,EAAE,OAAO,CAAA;IACxB;;;;OAIG;IACH,aAAa,CAAC,EAAE,iBAAiB,CAAA;CAClC;AAED;;;;;GAKG;AACH,wBAAgB,QAAQ,CACtB,OAAO,CAAC,EAAE,eAAe,GACxB,UAAU,CAAC,GAAG,EAAE,GAAG,EAAE,2BAA2B,CAAC,CAiCnD"}
1
+ {"version":3,"file":"form-data.d.ts","sourceRoot":"","sources":["../../src/lib/form-data.ts"],"names":[],"mappings":"AAAA,OAAO,EAOL,KAAK,iBAAiB,EACtB,KAAK,oBAAoB,EAC1B,MAAM,6BAA6B,CAAA;AACpC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAA;AAYzD;;GAEG;AACH,MAAM,WAAW,eAAgB,SAAQ,oBAAoB;IAC3D;;;;;OAKG;IACH,cAAc,CAAC,EAAE,OAAO,CAAA;IACxB;;;;OAIG;IACH,aAAa,CAAC,EAAE,iBAAiB,CAAA;CAClC;AAED;;;;;GAKG;AACH,wBAAgB,QAAQ,CACtB,OAAO,CAAC,EAAE,eAAe,GACxB,UAAU,CAAC;IAAE,GAAG,EAAE,OAAO,QAAQ,CAAC;IAAC,KAAK,EAAE,QAAQ,CAAC;IAAC,QAAQ,EAAE,UAAU,CAAA;CAAE,CAAC,CAyC7E"}
@@ -17,26 +17,33 @@ export function formData(options) {
17
17
  let uploadHandler = options?.uploadHandler;
18
18
  return async (context) => {
19
19
  if (context.has(FormData)) {
20
+ let formData = context.get(FormData);
21
+ if (formData != null) {
22
+ context.set(FormData, formData, { property: 'formData' });
23
+ }
20
24
  return;
21
25
  }
22
26
  if (context.method === 'GET' || context.method === 'HEAD') {
27
+ context.set(FormData, new FormData(), { property: 'formData' });
23
28
  return;
24
29
  }
25
30
  let contentType = context.headers.get('Content-Type');
26
31
  if (contentType == null ||
27
32
  (!contentType.startsWith('multipart/') &&
28
33
  !contentType.startsWith('application/x-www-form-urlencoded'))) {
29
- context.set(FormData, new FormData());
34
+ context.set(FormData, new FormData(), { property: 'formData' });
30
35
  return;
31
36
  }
32
37
  try {
33
- context.set(FormData, await parseFormData(context.request, options, uploadHandler));
38
+ context.set(FormData, await parseFormData(context.request, options, uploadHandler), {
39
+ property: 'formData',
40
+ });
34
41
  }
35
42
  catch (error) {
36
43
  if (!suppressErrors || isMultipartLimitError(error)) {
37
44
  throw error;
38
45
  }
39
- context.set(FormData, new FormData());
46
+ context.set(FormData, new FormData(), { property: 'formData' });
40
47
  }
41
48
  };
42
49
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@remix-run/form-data-middleware",
3
- "version": "0.2.2",
3
+ "version": "0.3.0",
4
4
  "description": "Middleware for parsing FormData from request bodies",
5
5
  "author": "Michael Jackson <mjijackson@gmail.com>",
6
6
  "license": "MIT",
@@ -28,14 +28,14 @@
28
28
  "devDependencies": {
29
29
  "@types/node": "^24.6.0",
30
30
  "@typescript/native-preview": "7.0.0-dev.20251125.1",
31
- "@remix-run/form-data-parser": "0.17.0",
32
- "@remix-run/fetch-router": "0.18.1",
33
- "@remix-run/assert": "0.1.0",
34
- "@remix-run/test": "0.2.0"
31
+ "@remix-run/form-data-parser": "0.17.1",
32
+ "@remix-run/test": "0.4.0",
33
+ "@remix-run/assert": "0.2.0",
34
+ "@remix-run/fetch-router": "0.19.0"
35
35
  },
36
36
  "dependencies": {
37
- "@remix-run/fetch-router": "^0.18.1",
38
- "@remix-run/form-data-parser": "^0.17.0"
37
+ "@remix-run/fetch-router": "^0.19.0",
38
+ "@remix-run/form-data-parser": "^0.17.1"
39
39
  },
40
40
  "keywords": [
41
41
  "fetch",
@@ -10,8 +10,6 @@ import {
10
10
  } from '@remix-run/form-data-parser'
11
11
  import type { Middleware } from '@remix-run/fetch-router'
12
12
 
13
- type SetFormDataContextTransform = readonly [readonly [typeof FormData, FormData]]
14
-
15
13
  function isMultipartLimitError(error: unknown): boolean {
16
14
  return (
17
15
  error instanceof MaxFilesExceededError ||
@@ -49,16 +47,22 @@ export interface FormDataOptions extends ParseFormDataOptions {
49
47
  */
50
48
  export function formData(
51
49
  options?: FormDataOptions,
52
- ): Middleware<any, any, SetFormDataContextTransform> {
50
+ ): Middleware<{ key: typeof FormData; value: FormData; property: 'formData' }> {
53
51
  let suppressErrors = options?.suppressErrors ?? false
54
52
  let uploadHandler = options?.uploadHandler
55
53
 
56
54
  return async (context) => {
57
55
  if (context.has(FormData)) {
56
+ let formData = context.get(FormData)
57
+ if (formData != null) {
58
+ context.set(FormData, formData, { property: 'formData' })
59
+ }
60
+
58
61
  return
59
62
  }
60
63
 
61
64
  if (context.method === 'GET' || context.method === 'HEAD') {
65
+ context.set(FormData, new FormData(), { property: 'formData' })
62
66
  return
63
67
  }
64
68
 
@@ -68,18 +72,20 @@ export function formData(
68
72
  (!contentType.startsWith('multipart/') &&
69
73
  !contentType.startsWith('application/x-www-form-urlencoded'))
70
74
  ) {
71
- context.set(FormData, new FormData())
75
+ context.set(FormData, new FormData(), { property: 'formData' })
72
76
  return
73
77
  }
74
78
 
75
79
  try {
76
- context.set(FormData, await parseFormData(context.request, options, uploadHandler))
80
+ context.set(FormData, await parseFormData(context.request, options, uploadHandler), {
81
+ property: 'formData',
82
+ })
77
83
  } catch (error) {
78
84
  if (!suppressErrors || isMultipartLimitError(error)) {
79
85
  throw error
80
86
  }
81
87
 
82
- context.set(FormData, new FormData())
88
+ context.set(FormData, new FormData(), { property: 'formData' })
83
89
  }
84
90
  }
85
91
  }