remix 3.0.0-beta.0 → 3.0.0-beta.2

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.
Files changed (88) hide show
  1. package/dist/fetch-router.d.ts +7 -0
  2. package/dist/fetch-router.d.ts.map +1 -1
  3. package/dist/node-tsx/load-module.d.ts +2 -0
  4. package/dist/node-tsx/load-module.d.ts.map +1 -0
  5. package/dist/node-tsx/load-module.js +2 -0
  6. package/dist/node-tsx.d.ts +3 -0
  7. package/dist/node-tsx.d.ts.map +1 -0
  8. package/{src/node-serve.ts → dist/node-tsx.js} +2 -1
  9. package/dist/render-middleware.d.ts +2 -0
  10. package/dist/render-middleware.d.ts.map +1 -0
  11. package/dist/render-middleware.js +2 -0
  12. package/dist/route-pattern/href.d.ts +2 -0
  13. package/dist/route-pattern/href.d.ts.map +1 -0
  14. package/dist/route-pattern/href.js +2 -0
  15. package/dist/route-pattern/join.d.ts +2 -0
  16. package/dist/route-pattern/join.d.ts.map +1 -0
  17. package/dist/route-pattern/join.js +2 -0
  18. package/dist/route-pattern/match.d.ts +2 -0
  19. package/dist/route-pattern/match.d.ts.map +1 -0
  20. package/dist/route-pattern/match.js +2 -0
  21. package/package.json +158 -44
  22. package/src/assert/README.md +109 -0
  23. package/src/assets/README.md +539 -0
  24. package/src/async-context-middleware/README.md +100 -0
  25. package/src/auth/README.md +445 -0
  26. package/src/auth-middleware/README.md +246 -0
  27. package/src/cli/README.md +78 -0
  28. package/src/compression-middleware/README.md +176 -0
  29. package/src/cookie/README.md +106 -0
  30. package/src/cop-middleware/README.md +117 -0
  31. package/src/cors-middleware/README.md +174 -0
  32. package/src/csrf-middleware/README.md +99 -0
  33. package/src/data-schema/README.md +422 -0
  34. package/src/data-table/README.md +552 -0
  35. package/src/data-table-mysql/README.md +97 -0
  36. package/src/data-table-postgres/README.md +74 -0
  37. package/src/data-table-sqlite/README.md +84 -0
  38. package/src/fetch-proxy/README.md +46 -0
  39. package/src/fetch-router/README.md +902 -0
  40. package/src/fetch-router.ts +7 -0
  41. package/src/file-storage/README.md +57 -0
  42. package/src/file-storage-s3/README.md +47 -0
  43. package/src/form-data-middleware/README.md +109 -0
  44. package/src/form-data-parser/README.md +160 -0
  45. package/src/fs/README.md +60 -0
  46. package/src/headers/README.md +629 -0
  47. package/src/html-template/README.md +101 -0
  48. package/src/lazy-file/README.md +109 -0
  49. package/src/logger-middleware/README.md +132 -0
  50. package/src/method-override-middleware/README.md +71 -0
  51. package/src/mime/README.md +110 -0
  52. package/src/multipart-parser/README.md +241 -0
  53. package/src/node-fetch-server/README.md +352 -0
  54. package/src/node-tsx/README.md +79 -0
  55. package/src/node-tsx/load-module.ts +2 -0
  56. package/{dist/node-serve.js → src/node-tsx.ts} +2 -1
  57. package/src/render-middleware/README.md +99 -0
  58. package/src/render-middleware.ts +2 -0
  59. package/src/route-pattern/README.md +291 -0
  60. package/src/route-pattern/href.ts +2 -0
  61. package/src/route-pattern/join.ts +2 -0
  62. package/src/route-pattern/match.ts +2 -0
  63. package/src/session/README.md +171 -0
  64. package/src/session-middleware/README.md +109 -0
  65. package/src/session-storage-memcache/README.md +37 -0
  66. package/src/session-storage-redis/README.md +37 -0
  67. package/src/static-middleware/README.md +89 -0
  68. package/src/tar-parser/README.md +74 -0
  69. package/src/terminal/README.md +92 -0
  70. package/src/test/README.md +430 -0
  71. package/src/ui/README.md +219 -0
  72. package/src/ui/accordion/README.md +166 -0
  73. package/src/ui/anchor/README.md +153 -0
  74. package/src/ui/animation/README.md +316 -0
  75. package/src/ui/breadcrumbs/README.md +55 -0
  76. package/src/ui/button/README.md +44 -0
  77. package/src/ui/combobox/README.md +145 -0
  78. package/src/ui/glyph/README.md +72 -0
  79. package/src/ui/listbox/README.md +115 -0
  80. package/src/ui/menu/README.md +96 -0
  81. package/src/ui/popover/README.md +122 -0
  82. package/src/ui/scroll-lock/README.md +33 -0
  83. package/src/ui/select/README.md +107 -0
  84. package/src/ui/server/README.md +90 -0
  85. package/src/ui/test/README.md +107 -0
  86. package/src/ui/theme/README.md +103 -0
  87. package/dist/node-serve.d.ts +0 -2
  88. package/dist/node-serve.d.ts.map +0 -1
@@ -0,0 +1,101 @@
1
+ # html-template
2
+
3
+ Safe HTML template literals for Remix. `html-template` automatically escapes interpolated values to prevent XSS while still supporting explicit trusted HTML insertion.
4
+
5
+ ## Features
6
+
7
+ - **Automatic HTML escaping** - All interpolated values are escaped by default
8
+ - **Explicit raw HTML** - Use `html.raw` when you need unescaped HTML from trusted sources
9
+ - **Composable** - SafeHtml values can be nested without double-escaping
10
+ - **Type-safe** - Full TypeScript support with branded types
11
+ - **Zero dependencies** - Lightweight and self-contained
12
+ - **Runtime agnostic** - Works in Node.js, Bun, Deno, browsers, and edge runtimes
13
+
14
+ ## Installation
15
+
16
+ ```sh
17
+ npm i remix
18
+ ```
19
+
20
+ ## Usage
21
+
22
+ ```ts
23
+ import { html } from 'remix/html-template'
24
+
25
+ let userInput = '<script>alert("XSS")</script>'
26
+ let greeting = html`<h1>Hello ${userInput}!</h1>`
27
+
28
+ console.log(String(greeting))
29
+ // Output: <h1>Hello &lt;script&gt;alert("XSS")&lt;/script&gt;!</h1>
30
+ ```
31
+
32
+ By default, all interpolated values are automatically escaped to prevent XSS attacks.
33
+
34
+ If you have trusted HTML that should not be escaped, use `html.raw`:
35
+
36
+ ```ts
37
+ import { html } from 'remix/html-template'
38
+
39
+ let trustedIcon = '<svg>...</svg>'
40
+ let button = html.raw`<button>${trustedIcon} Click me</button>`
41
+
42
+ console.log(String(button))
43
+ // => <button><svg>...</svg> Click me</button>
44
+ ```
45
+
46
+ **Warning**: Only use `html.raw` with content you trust. Never use it with user input.
47
+
48
+ ### Composing HTML Fragments
49
+
50
+ SafeHtml values can be nested without double-escaping:
51
+
52
+ ```ts
53
+ import { html } from 'remix/html-template'
54
+
55
+ let title = html`<h1>My Title</h1>`
56
+ let content = html`<p>Some content with ${userInput}</p>`
57
+
58
+ let page = html`
59
+ <!doctype html>
60
+ <html>
61
+ <body>
62
+ ${title} ${content}
63
+ </body>
64
+ </html>
65
+ `
66
+ ```
67
+
68
+ ### Working with Arrays
69
+
70
+ You can interpolate arrays of values, which will be flattened and joined:
71
+
72
+ ```ts
73
+ import { html } from 'remix/html-template'
74
+
75
+ let items = ['Apple', 'Banana', 'Cherry']
76
+ let list = html`
77
+ <ul>
78
+ ${items.map((item) => html`<li>${item}</li>`)}
79
+ </ul>
80
+ `
81
+ ```
82
+
83
+ ### Conditional Rendering
84
+
85
+ Use `null` or `undefined` to render nothing:
86
+
87
+ ```ts
88
+ import { html } from 'remix/html-template'
89
+
90
+ let showError = false
91
+ let errorMessage = 'Something went wrong'
92
+ let page = html`<div>${showError ? html`<div class="error">${errorMessage}</div>` : null}</div>`
93
+ ```
94
+
95
+ ## Related Packages
96
+
97
+ - [`remix/router`](https://github.com/remix-run/remix/tree/main/packages/fetch-router) - HTTP router that works great with html-template
98
+
99
+ ## License
100
+
101
+ See [LICENSE](https://github.com/remix-run/remix/blob/main/LICENSE)
@@ -0,0 +1,109 @@
1
+ # lazy-file
2
+
3
+ A lazy, streaming `Blob`/`File` implementation for JavaScript.
4
+
5
+ It allows you to easily create [Blob](https://developer.mozilla.org/en-US/docs/Web/API/Blob)-like and [File](https://developer.mozilla.org/en-US/docs/Web/API/File)-like objects that defer reading their contents until needed, which is ideal for situations where a file's contents do not fit in memory all at once. When file contents are read, they are streamed to avoid buffering.
6
+
7
+ ## Features
8
+
9
+ - **Deferred Loading** - Blob/file contents loaded on demand to minimize memory usage
10
+ - **Familiar Interface** - `LazyBlob` and `LazyFile` implement the same interface as native `Blob` and `File`
11
+ - **Easy Conversion** - Convert to native `ReadableStream` with `.stream()`, or to native `Blob`/`File` with `.toBlob()` and `.toFile()`
12
+ - **Standard Constructors** - Accepts all the same content types as the original [`Blob()`](https://developer.mozilla.org/en-US/docs/Web/API/Blob/Blob) and [`File()`](https://developer.mozilla.org/en-US/docs/Web/API/File/File) constructors
13
+ - **Slice Support** - Supports [`Blob.slice()`](https://developer.mozilla.org/en-US/docs/Web/API/Blob/slice), even on streaming content
14
+
15
+ ## Why You Need This
16
+
17
+ JavaScript's [File API](https://developer.mozilla.org/en-US/docs/Web/API/File) is useful, but it's not a great fit for streaming server environments where you don't want to buffer file contents. In particular, [`the File() constructor`](https://developer.mozilla.org/en-US/docs/Web/API/File/File) requires the contents of a file to be supplied up front when the object is first created, like this:
18
+
19
+ ```ts
20
+ let file = new File(['hello world'], 'hello.txt', { type: 'text/plain' })
21
+ ```
22
+
23
+ A `LazyFile` improves this model by accepting an additional content type in its constructor: `LazyContent`.
24
+
25
+ ```ts
26
+ let lazyContent: LazyContent = {
27
+ /* See below for usage */
28
+ }
29
+ let lazyFile = new LazyFile(lazyContent, 'hello.txt', { type: 'text/plain' })
30
+ ```
31
+
32
+ All other `File` functionality works as you'd expect.
33
+
34
+ ## Installation
35
+
36
+ ```sh
37
+ npm i remix
38
+ ```
39
+
40
+ ## Usage
41
+
42
+ The low-level API can be used to create a `LazyFile` that streams content from anywhere:
43
+
44
+ ```ts
45
+ import { type LazyContent, LazyFile } from 'remix/lazy-file'
46
+
47
+ let content: LazyContent = {
48
+ // The total length of this file in bytes.
49
+ byteLength: 100000,
50
+ // A function that provides a stream of data for the file contents,
51
+ // beginning at the `start` index and ending at `end`.
52
+ stream(start, end) {
53
+ // ... read the file contents from somewhere and return a ReadableStream
54
+ return new ReadableStream({
55
+ start(controller) {
56
+ controller.enqueue('X'.repeat(100000).slice(start, end))
57
+ controller.close()
58
+ },
59
+ })
60
+ },
61
+ }
62
+
63
+ let lazyFile = new LazyFile(content, 'example.txt', { type: 'text/plain' })
64
+ await lazyFile.arrayBuffer() // ArrayBuffer of the file's content
65
+ lazyFile.name // "example.txt"
66
+ lazyFile.type // "text/plain"
67
+ ```
68
+
69
+ All file contents are read on-demand and nothing is ever buffered unless you explicitly call `.toFile()` or `.toBlob()`.
70
+
71
+ ### Streaming Content
72
+
73
+ Use `.stream()` to get a `ReadableStream` for `Response` and other streaming APIs:
74
+
75
+ ```ts
76
+ import { openLazyFile } from 'remix/fs'
77
+
78
+ let lazyFile = openLazyFile('./large-video.mp4')
79
+
80
+ let response = new Response(lazyFile.stream(), {
81
+ headers: {
82
+ 'Content-Type': lazyFile.type,
83
+ 'Content-Length': String(lazyFile.size),
84
+ },
85
+ })
86
+ ```
87
+
88
+ ### Converting to Native File/Blob
89
+
90
+ For non-streaming APIs that require a complete `File` or `Blob` (e.g. `FormData`), use `.toFile()` or `.toBlob()`.
91
+
92
+ ```ts
93
+ let lazyFile = openLazyFile('./document.pdf')
94
+ let realFile = await lazyFile.toFile()
95
+
96
+ let formData = new FormData()
97
+ formData.append('document', realFile)
98
+ ```
99
+
100
+ > **Note:** `.toFile()` and `.toBlob()` read the entire file into memory. Only use these for non-streaming APIs that require a complete `File` or `Blob` (e.g. `FormData`). Always prefer `.stream()` if possible.
101
+
102
+ ## Related Packages
103
+
104
+ - [`fs`](https://github.com/remix-run/remix/tree/main/packages/fs) - Filesystem utilities for reading and writing files using the Web `File` API
105
+ - [`file-storage`](https://github.com/remix-run/remix/tree/main/packages/file-storage) - Storage abstraction for files on disk or in memory
106
+
107
+ ## License
108
+
109
+ See [LICENSE](https://github.com/remix-run/remix/blob/main/LICENSE)
@@ -0,0 +1,132 @@
1
+ # logger-middleware
2
+
3
+ HTTP request/response logging middleware for Remix. It logs request metadata and response details with configurable output formats, and exposes the configured log function on request context.
4
+
5
+ ## Features
6
+
7
+ - **Request/Response Logging** - Logs method, path, status, and response metadata
8
+ - **Context Logger** - Exposes `context.logger` (or `context.get(Logger)`)
9
+ - **Token-Based Formatting** - Customize log output with built-in placeholders
10
+ - **Structured Timing Data** - Includes request duration and timestamps
11
+ - **Colorized Output** - Highlights method, status, duration, and content length in TTY output
12
+
13
+ ## Installation
14
+
15
+ ```sh
16
+ npm i remix
17
+ ```
18
+
19
+ ## Usage
20
+
21
+ ```ts
22
+ import { createRouter } from 'remix/router'
23
+ import { logger } from 'remix/middleware/logger'
24
+
25
+ let router = createRouter({
26
+ middleware: [logger()],
27
+ })
28
+
29
+ router.get('/users/:id', (context) => {
30
+ context.logger(`Loading user ${context.params.id}`)
31
+ return Response.json(loadUser(context.params.id))
32
+ })
33
+
34
+ // Logs: [19/Nov/2025:14:32:10 -0800] GET /users/123 200 1234
35
+ ```
36
+
37
+ Use `context.logger(message)` (or `context.get(Logger)(message)`) for app logs that should use the configured logger.
38
+
39
+ ### Custom Format
40
+
41
+ You can use the `format` option to customize the log format. The following tokens are available:
42
+
43
+ - `%date` - Date and time in Apache/nginx format (dd/Mon/yyyy:HH:mm:ss ±zzzz)
44
+ - `%dateISO` - Date and time in ISO format
45
+ - `%duration` - Request duration in milliseconds
46
+ - `%contentLength` - Response Content-Length header
47
+ - `%contentType` - Response Content-Type header
48
+ - `%host` - Request URL host
49
+ - `%hostname` - Request URL hostname
50
+ - `%method` - Request method
51
+ - `%path` - Request pathname + search
52
+ - `%pathname` - Request pathname
53
+ - `%port` - Request port
54
+ - `%query` - Request query string (search)
55
+ - `%referer` - Request Referer header
56
+ - `%search` - Request search string
57
+ - `%status` - Response status code
58
+ - `%statusText` - Response status text
59
+ - `%url` - Full request URL
60
+ - `%userAgent` - Request User-Agent header
61
+
62
+ ```ts
63
+ let router = createRouter({
64
+ middleware: [
65
+ logger({
66
+ format: '%method %path - %status (%duration ms)',
67
+ }),
68
+ ],
69
+ })
70
+ // Logs: GET /users/123 - 200 (42 ms)
71
+ ```
72
+
73
+ For Apache-style combined log format, you can use the following format:
74
+
75
+ ```ts
76
+ let router = createRouter({
77
+ middleware: [
78
+ logger({
79
+ format: '%host - - [%date] "%method %path" %status %contentLength "%referer" "%userAgent"',
80
+ }),
81
+ ],
82
+ })
83
+ ```
84
+
85
+ ### Colorized Output
86
+
87
+ Logger output automatically uses ANSI colors for high-signal tokens when terminal color detection allows them. Set `colors` to `false` to disable colorized output or `true` to force it on. When the `process` global is defined, color detection respects `CI`, `NO_COLOR`, `FORCE_COLOR`, `TERM=dumb`, and TTY output streams.
88
+
89
+ ```ts
90
+ let router = createRouter({
91
+ middleware: [
92
+ logger({
93
+ colors: false,
94
+ }),
95
+ ],
96
+ })
97
+ ```
98
+
99
+ The following tokens are colorized when colors are enabled:
100
+
101
+ - `%method`
102
+ - `%status`
103
+ - `%duration`
104
+ - `%contentLength`
105
+
106
+ ### Custom Logger
107
+
108
+ You can use a custom logger to write logs to a file or other stream.
109
+
110
+ ```ts
111
+ import { createWriteStream } from 'node:fs'
112
+
113
+ let logStream = createWriteStream('access.log', { flags: 'a' })
114
+
115
+ let router = createRouter({
116
+ middleware: [
117
+ logger({
118
+ log(message) {
119
+ logStream.write(message + '\n')
120
+ },
121
+ }),
122
+ ],
123
+ })
124
+ ```
125
+
126
+ ## Related Packages
127
+
128
+ - [`fetch-router`](https://github.com/remix-run/remix/tree/main/packages/fetch-router) - Router for the web Fetch API
129
+
130
+ ## License
131
+
132
+ See [LICENSE](https://github.com/remix-run/remix/blob/main/LICENSE)
@@ -0,0 +1,71 @@
1
+ # method-override-middleware
2
+
3
+ Method override middleware for Remix. It allows HTML forms to simulate `PUT`, `PATCH`, and `DELETE` requests using a hidden form field.
4
+
5
+ ## Features
6
+
7
+ - **Form Method Overrides** - Translate posted form fields into request methods
8
+ - **HTML Form Friendly** - Supports REST-style routes from standard browser forms
9
+ - **Configurable Field Name** - Choose a custom override field key
10
+
11
+ ## Installation
12
+
13
+ ```sh
14
+ npm i remix
15
+ ```
16
+
17
+ ## Usage
18
+
19
+ This middleware runs after [the `formData` middleware](https://github.com/remix-run/remix/tree/main/packages/form-data-middleware) and updates the request context's `context.method` with the value of the method override field. This is useful for simulating RESTful API request methods like PUT and DELETE using HTML forms.
20
+
21
+ ```ts
22
+ import { createRouter } from 'remix/router'
23
+ import { formData } from 'remix/middleware/form-data'
24
+ import { methodOverride } from 'remix/middleware/method-override'
25
+
26
+ let router = createRouter({
27
+ // methodOverride must come AFTER formData middleware
28
+ middleware: [formData(), methodOverride()],
29
+ })
30
+
31
+ router.delete('/users/:id', async (context) => {
32
+ let userId = context.params.id
33
+ // Delete user logic...
34
+ return new Response('User deleted')
35
+ })
36
+ ```
37
+
38
+ In your HTML form:
39
+
40
+ ```html
41
+ <form method="POST" action="/users/123">
42
+ <input type="hidden" name="_method" value="DELETE" />
43
+ <button type="submit">Delete User</button>
44
+ </form>
45
+ ```
46
+
47
+ ### Custom Field Name
48
+
49
+ You can customize the name of the method override field by passing a `fieldName` option to the `methodOverride()` middleware.
50
+
51
+ ```ts
52
+ let router = createRouter({
53
+ middleware: [formData(), methodOverride({ fieldName: '__method__' })],
54
+ })
55
+ ```
56
+
57
+ ```html
58
+ <form method="POST" action="/users/123">
59
+ <input type="hidden" name="__method__" value="PUT" />
60
+ <button type="submit">Update User</button>
61
+ </form>
62
+ ```
63
+
64
+ ## Related Packages
65
+
66
+ - [`fetch-router`](https://github.com/remix-run/remix/tree/main/packages/fetch-router) - Router for the web Fetch API
67
+ - [`form-data-middleware`](https://github.com/remix-run/remix/tree/main/packages/form-data-middleware) - Required for parsing form data
68
+
69
+ ## License
70
+
71
+ See [LICENSE](https://github.com/remix-run/remix/blob/main/LICENSE)
@@ -0,0 +1,110 @@
1
+ # mime
2
+
3
+ MIME type detection and content-type helpers for Remix. This package maps extensions to MIME types and provides utilities for charset and compressibility checks.
4
+
5
+ ## Features
6
+
7
+ - **MIME Detection** - Detect MIME types from extensions and filenames
8
+ - **Content-Type Helpers** - Build `Content-Type` values with charset handling
9
+ - **Compression Signals** - Check whether a media type is likely compressible
10
+ - **Generated Data** - Built from [mime-db](https://github.com/jshttp/mime-db)
11
+
12
+ ## Installation
13
+
14
+ ```sh
15
+ npm i remix
16
+ ```
17
+
18
+ ## Usage
19
+
20
+ ### `detectMimeType(extension)`
21
+
22
+ Detects the MIME type for a given file extension or filename.
23
+
24
+ ```ts
25
+ import { detectMimeType } from 'remix/mime'
26
+
27
+ detectMimeType('txt') // 'text/plain'
28
+ detectMimeType('.txt') // 'text/plain'
29
+ detectMimeType('file.txt') // 'text/plain'
30
+ detectMimeType('path/to/file.txt') // 'text/plain'
31
+ detectMimeType('unknown') // undefined
32
+ ```
33
+
34
+ ### `detectContentType(extension)`
35
+
36
+ Detects the Content-Type header value for a given file extension or filename, including `charset` for text-based types. See [`mimeTypeToContentType`](#mimetypetocontenttypemimetype) for charset logic.
37
+
38
+ ```ts
39
+ import { detectContentType } from 'remix/mime'
40
+
41
+ detectContentType('css') // 'text/css; charset=utf-8'
42
+ detectContentType('.json') // 'application/json; charset=utf-8'
43
+ detectContentType('image.png') // 'image/png'
44
+ detectContentType('path/to/file.unknown') // undefined
45
+ ```
46
+
47
+ ### `isCompressibleMimeType(mimeType)`
48
+
49
+ Checks if a MIME type is known to be compressible.
50
+
51
+ ```ts
52
+ import { isCompressibleMimeType } from 'remix/mime'
53
+
54
+ isCompressibleMimeType('text/html') // true
55
+ isCompressibleMimeType('application/json') // true
56
+ isCompressibleMimeType('image/png') // false
57
+ isCompressibleMimeType('video/mp4') // false
58
+ ```
59
+
60
+ For convenience, the function also accepts a full Content-Type header value:
61
+
62
+ ```ts
63
+ import { isCompressibleMimeType } from 'remix/mime'
64
+
65
+ isCompressibleMimeType('text/html; charset=utf-8') // true
66
+ isCompressibleMimeType('application/json; charset=utf-8') // true
67
+ isCompressibleMimeType('image/png; charset=utf-8') // false
68
+ isCompressibleMimeType('video/mp4; charset=utf-8') // false
69
+ ```
70
+
71
+ ### `mimeTypeToContentType(mimeType)`
72
+
73
+ Converts a MIME type to a Content-Type header value, adding `; charset=utf-8` to text-based MIME types: `text/*` (except `text/xml` which has built-in encoding declarations), `application/json`, `application/javascript`, and all `+json` suffixed types. All other types are returned unchanged.
74
+
75
+ ```ts
76
+ import { mimeTypeToContentType } from 'remix/mime'
77
+
78
+ mimeTypeToContentType('text/css') // 'text/css; charset=utf-8'
79
+ mimeTypeToContentType('application/json') // 'application/json; charset=utf-8'
80
+ mimeTypeToContentType('application/ld+json') // 'application/ld+json; charset=utf-8'
81
+ mimeTypeToContentType('image/png') // 'image/png'
82
+ ```
83
+
84
+ ### `defineMimeType(definition)`
85
+
86
+ Registers or overrides a MIME type for one or more file extensions.
87
+
88
+ ```ts
89
+ import { defineMimeType } from 'remix/mime'
90
+
91
+ defineMimeType({
92
+ extensions: ['myformat'],
93
+ mimeType: 'application/x-myformat',
94
+ })
95
+ ```
96
+
97
+ You can also optionally configure the charset and whether the MIME type is compressible:
98
+
99
+ ```ts
100
+ defineMimeType({
101
+ extensions: ['myformat'],
102
+ mimeType: 'application/x-myformat',
103
+ compressible: true,
104
+ charset: 'utf-8',
105
+ })
106
+ ```
107
+
108
+ ## License
109
+
110
+ MIT