remix 3.0.0-beta.4 → 3.0.0-beta.6

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 (143) hide show
  1. package/README.md +4 -2
  2. package/dist/assets/types/hmr.d.ts +2 -0
  3. package/dist/cli-entry.js +1 -1
  4. package/dist/data-table/cli.d.ts +2 -0
  5. package/dist/data-table/cli.d.ts.map +1 -0
  6. package/dist/{ui/scroll-lock.js → data-table/cli.js} +1 -1
  7. package/dist/node-hmr/runtime.d.ts +2 -0
  8. package/dist/node-hmr/runtime.d.ts.map +1 -0
  9. package/dist/node-hmr/runtime.js +2 -0
  10. package/dist/node-hmr/types.d.ts +2 -0
  11. package/dist/node-hmr.d.ts +2 -0
  12. package/dist/node-hmr.d.ts.map +1 -0
  13. package/dist/{ui/glyph.js → node-hmr.js} +1 -1
  14. package/dist/ui/accordion/primitives.d.ts +2 -0
  15. package/dist/ui/accordion/primitives.d.ts.map +1 -0
  16. package/dist/ui/accordion/primitives.js +2 -0
  17. package/dist/ui/button.d.ts +1 -0
  18. package/dist/ui/button.d.ts.map +1 -1
  19. package/dist/ui/button.js +1 -0
  20. package/dist/ui/checkbox.d.ts +3 -0
  21. package/dist/ui/checkbox.d.ts.map +1 -0
  22. package/dist/ui/checkbox.js +3 -0
  23. package/dist/ui/combobox/primitives.d.ts +2 -0
  24. package/dist/ui/combobox/primitives.d.ts.map +1 -0
  25. package/dist/ui/combobox/primitives.js +2 -0
  26. package/dist/ui/dev/refresh.d.ts +2 -0
  27. package/dist/ui/dev/refresh.d.ts.map +1 -0
  28. package/dist/ui/dev/refresh.js +2 -0
  29. package/dist/ui/input.d.ts +3 -0
  30. package/dist/ui/input.d.ts.map +1 -0
  31. package/dist/ui/input.js +3 -0
  32. package/dist/ui/menu/primitives.d.ts +2 -0
  33. package/dist/ui/menu/primitives.d.ts.map +1 -0
  34. package/dist/ui/menu/primitives.js +2 -0
  35. package/dist/ui/radio.d.ts +3 -0
  36. package/dist/ui/radio.d.ts.map +1 -0
  37. package/dist/ui/radio.js +3 -0
  38. package/dist/ui/select/primitives.d.ts +2 -0
  39. package/dist/ui/select/primitives.d.ts.map +1 -0
  40. package/dist/ui/select/primitives.js +2 -0
  41. package/dist/ui/tabs/primitives.d.ts +2 -0
  42. package/dist/ui/tabs/primitives.d.ts.map +1 -0
  43. package/dist/ui/tabs/primitives.js +2 -0
  44. package/dist/ui/tabs.d.ts +2 -0
  45. package/dist/ui/tabs.d.ts.map +1 -0
  46. package/{src/ui/theme.ts → dist/ui/tabs.js} +1 -1
  47. package/dist/ui/toggle/primitives.d.ts +2 -0
  48. package/dist/ui/toggle/primitives.d.ts.map +1 -0
  49. package/dist/ui/toggle/primitives.js +2 -0
  50. package/dist/ui/toggle.d.ts +3 -0
  51. package/dist/ui/toggle.d.ts.map +1 -0
  52. package/dist/ui/toggle.js +3 -0
  53. package/dist/ui-hmr/assets.d.ts +2 -0
  54. package/dist/ui-hmr/assets.d.ts.map +1 -0
  55. package/dist/ui-hmr/assets.js +2 -0
  56. package/dist/ui-hmr/node.d.ts +3 -0
  57. package/dist/ui-hmr/node.d.ts.map +1 -0
  58. package/dist/ui-hmr/node.js +3 -0
  59. package/dist/ui-hmr/runtime/browser.d.ts +2 -0
  60. package/dist/ui-hmr/runtime/browser.d.ts.map +1 -0
  61. package/dist/ui-hmr/runtime/browser.js +2 -0
  62. package/dist/ui-hmr/runtime/server.d.ts +2 -0
  63. package/dist/ui-hmr/runtime/server.d.ts.map +1 -0
  64. package/dist/ui-hmr/runtime/server.js +2 -0
  65. package/dist/ui-hmr.d.ts +2 -0
  66. package/dist/ui-hmr.d.ts.map +1 -0
  67. package/{src/ui/glyph.ts → dist/ui-hmr.js} +1 -1
  68. package/package.json +122 -142
  69. package/src/assets/README.md +322 -56
  70. package/src/assets/types/hmr.d.ts +2 -0
  71. package/src/cli/README.md +105 -1
  72. package/src/cookie/README.md +4 -4
  73. package/src/data-table/README.md +202 -68
  74. package/src/data-table/cli.ts +2 -0
  75. package/src/data-table-mysql/README.md +46 -17
  76. package/src/data-table-postgres/README.md +39 -13
  77. package/src/data-table-sqlite/README.md +38 -20
  78. package/src/fetch-proxy/README.md +25 -0
  79. package/src/form-data-parser/README.md +4 -4
  80. package/src/mime/README.md +8 -1
  81. package/src/node-fetch-server/README.md +39 -13
  82. package/src/node-hmr/README.md +307 -0
  83. package/src/node-hmr/runtime.ts +2 -0
  84. package/src/node-hmr/types.d.ts +2 -0
  85. package/{dist/ui/theme.js → src/node-hmr.ts} +1 -1
  86. package/src/route-pattern/README.md +141 -13
  87. package/src/session/README.md +1 -1
  88. package/src/session-middleware/README.md +9 -7
  89. package/src/test/README.md +161 -115
  90. package/src/ui/README.md +116 -157
  91. package/src/ui/accordion/README.md +50 -14
  92. package/src/ui/accordion/primitives/README.md +202 -0
  93. package/src/ui/accordion/primitives.ts +2 -0
  94. package/src/ui/anchor/README.md +37 -2
  95. package/src/ui/breadcrumbs/README.md +4 -4
  96. package/src/ui/button/README.md +26 -26
  97. package/src/ui/button.ts +1 -0
  98. package/src/ui/checkbox/README.md +59 -0
  99. package/src/ui/checkbox.ts +3 -0
  100. package/src/ui/combobox/README.md +58 -9
  101. package/src/ui/combobox/primitives/README.md +194 -0
  102. package/src/ui/combobox/primitives.ts +2 -0
  103. package/src/ui/dev/refresh.ts +2 -0
  104. package/src/ui/input/README.md +52 -0
  105. package/src/ui/input.ts +3 -0
  106. package/src/ui/listbox/README.md +9 -41
  107. package/src/ui/menu/README.md +55 -14
  108. package/src/ui/menu/primitives/README.md +161 -0
  109. package/src/ui/menu/primitives.ts +2 -0
  110. package/src/ui/popover/README.md +20 -39
  111. package/src/ui/radio/README.md +53 -0
  112. package/src/ui/radio.ts +3 -0
  113. package/src/ui/select/README.md +29 -19
  114. package/src/ui/select/primitives/README.md +117 -0
  115. package/src/ui/select/primitives.ts +2 -0
  116. package/src/ui/tabs/README.md +141 -0
  117. package/src/ui/tabs/primitives/README.md +141 -0
  118. package/src/ui/tabs/primitives.ts +2 -0
  119. package/src/ui/tabs.ts +2 -0
  120. package/src/ui/test/README.md +151 -60
  121. package/src/ui/toggle/README.md +56 -0
  122. package/src/ui/toggle/primitives/README.md +56 -0
  123. package/src/ui/toggle/primitives.ts +2 -0
  124. package/src/ui/toggle.ts +3 -0
  125. package/src/ui-hmr/README.md +119 -0
  126. package/{dist/ui/separator.js → src/ui-hmr/assets.ts} +1 -1
  127. package/src/ui-hmr/node.ts +3 -0
  128. package/src/ui-hmr/runtime/browser.ts +2 -0
  129. package/src/ui-hmr/runtime/server.ts +2 -0
  130. package/src/ui-hmr.ts +2 -0
  131. package/dist/ui/glyph.d.ts +0 -2
  132. package/dist/ui/glyph.d.ts.map +0 -1
  133. package/dist/ui/scroll-lock.d.ts +0 -2
  134. package/dist/ui/scroll-lock.d.ts.map +0 -1
  135. package/dist/ui/separator.d.ts +0 -2
  136. package/dist/ui/separator.d.ts.map +0 -1
  137. package/dist/ui/theme.d.ts +0 -2
  138. package/dist/ui/theme.d.ts.map +0 -1
  139. package/src/ui/glyph/README.md +0 -72
  140. package/src/ui/scroll-lock/README.md +0 -33
  141. package/src/ui/scroll-lock.ts +0 -2
  142. package/src/ui/separator.ts +0 -2
  143. package/src/ui/theme/README.md +0 -103
@@ -1,12 +1,12 @@
1
1
  # data-table-mysql
2
2
 
3
- MySQL adapter for [`remix/data-table`](https://github.com/remix-run/remix/tree/main/packages/data-table). Use this package when you want `data-table` APIs backed by `mysql2`.
3
+ MySQL database driver for [`remix/data-table`](https://github.com/remix-run/remix/tree/main/packages/data-table), backed by `mysql2`.
4
4
 
5
5
  ## Features
6
6
 
7
- - **Native `mysql2` Integration**: Works with `mysql2/promise` `Pool` and `PoolConnection` instances
7
+ - **Native `mysql2` Integration**: Creates a pool from `mysql2` configuration or uses an existing pool or connection
8
8
  - **Full `data-table` API Support**: Queries, relations, writes, and transactions
9
- - **Adapter-Owned Compiler**: SQL compilation lives in this adapter, with optional shared pure helpers from `data-table`
9
+ - **MySQL Compiler**: SQL compilation is handled automatically for MySQL
10
10
  - **Multi-Statement Migrations**: `executeScript()` runs `up.sql` / `down.sql` files via `mysql2` (requires `multipleStatements: true`)
11
11
  - **MySQL Capabilities Enabled By Default**:
12
12
  - `returning: false`
@@ -24,17 +24,17 @@ npm i remix mysql2
24
24
  ## Usage
25
25
 
26
26
  ```ts
27
- import { createPool } from 'mysql2/promise'
28
- import { createDatabase } from 'remix/data-table'
29
- import { createMysqlDatabaseAdapter } from 'remix/data-table/mysql'
27
+ import { createMysqlDatabase } from 'remix/data-table/mysql'
30
28
 
31
- let pool = createPool(process.env.DATABASE_URL as string)
32
- let db = createDatabase(createMysqlDatabaseAdapter(pool))
29
+ let db = createMysqlDatabase({
30
+ uri: process.env.DATABASE_URL,
31
+ multipleStatements: true,
32
+ })
33
33
  ```
34
34
 
35
35
  Use `db.query(...)`, relation loading, and transactions from `remix/data-table`. Import any driver-specific types you need directly from `mysql2/promise`.
36
36
 
37
- ## Adapter Capabilities
37
+ ## Database Capabilities
38
38
 
39
39
  `data-table-mysql` reports this capability set by default:
40
40
 
@@ -48,22 +48,26 @@ Use `db.query(...)`, relation loading, and transactions from `remix/data-table`.
48
48
 
49
49
  ### Multi-Statement Migrations
50
50
 
51
- `remix/data-table/migrations` sends each migration to the adapter as a single multi-statement SQL script. mysql2 only accepts multi-statement scripts when the connection is created with `multipleStatements: true`:
51
+ `remix/data-table/migrations` sends each migration as a single multi-statement SQL script. mysql2 only accepts multi-statement scripts when the connection is created with `multipleStatements: true`:
52
52
 
53
53
  ```ts
54
- import { createPool } from 'mysql2/promise'
54
+ import { createMysqlDatabase } from 'remix/data-table/mysql'
55
55
 
56
- let pool = createPool({
56
+ let db = createMysqlDatabase({
57
57
  uri: process.env.DATABASE_URL,
58
58
  multipleStatements: true,
59
59
  })
60
60
  ```
61
61
 
62
+ Config-backed databases support `db.wipe()` and `db.reset()`. Call `await db.close()` during application shutdown to close the internally created pool. You may pass an existing `mysql2` pool or connection when your application owns the driver lifecycle; `db.close()` leaves supplied clients alone, and destructive lifecycle methods are unavailable in that mode. `db.wipe()` requires a database name in the connection config (`database`, or the path of a connection URI) and throws when none is present.
63
+
64
+ Migration runs reserve one connection for the MySQL named lock, migration SQL, and journal updates. Lock acquisition waits up to 60 seconds and fails with an error instead of allowing the migration to proceed. After a successful run the connection is unlocked and returned to the pool; if the migration or unlock fails, the reserved connection is destroyed instead of being reused, so a dirty session can never leak back into the pool. Nested migration lock acquisition throws instead of deadlocking.
65
+
62
66
  ### `returning` On MySQL
63
67
 
64
- MySQL does not natively support SQL `RETURNING`. In this adapter, using `returning` on write operations throws `DataTableQueryError`.
68
+ MySQL does not natively support SQL `RETURNING`. Using `returning` on write operations therefore throws `DataTableQueryError`.
65
69
 
66
- Use write metadata (`affectedRows`, `insertId`) on MySQL, or switch adapters when returned rows are required.
70
+ Use write metadata (`affectedRows`, `insertId`) on MySQL, or switch databases when returned rows are required.
67
71
 
68
72
  ```ts
69
73
  import { DataTableQueryError } from 'remix/data-table'
@@ -74,17 +78,42 @@ try {
74
78
  .insert({ email: 'a@example.com', status: 'active' }, { returning: ['id'] })
75
79
  } catch (error) {
76
80
  if (error instanceof DataTableQueryError) {
77
- // insert() returning is not supported by this adapter
81
+ // insert() returning is not supported by MySQL
78
82
  }
79
83
  }
80
84
  ```
81
85
 
86
+ ## Running integration tests locally
87
+
88
+ To start a local MySQL container matching CI:
89
+
90
+ ```sh
91
+ podman run --name mysql \
92
+ -e MYSQL_ROOT_PASSWORD=root \
93
+ -e MYSQL_DATABASE=remix \
94
+ -p 3306:3306 \
95
+ -d mysql:8
96
+ ```
97
+
98
+ Then run:
99
+
100
+ ```sh
101
+ REMIX_DATA_TABLE_MYSQL_TEST_URL=mysql://root:root@127.0.0.1:3306/remix \
102
+ pnpm test src/lib/driver.integration.test.ts
103
+ ```
104
+
105
+ Remove the container when you are done:
106
+
107
+ ```sh
108
+ podman rm -f mysql
109
+ ```
110
+
82
111
  ## Related Packages
83
112
 
84
113
  - [`data-table`](https://github.com/remix-run/remix/tree/main/packages/data-table) - Core query/relations API
85
114
  - [`data-schema`](https://github.com/remix-run/remix/tree/main/packages/data-schema) - Schema parsing and validation
86
- - [`data-table-postgres`](https://github.com/remix-run/remix/tree/main/packages/data-table-postgres) - PostgreSQL adapter
87
- - [`data-table-sqlite`](https://github.com/remix-run/remix/tree/main/packages/data-table-sqlite) - SQLite adapter
115
+ - [`data-table-postgres`](https://github.com/remix-run/remix/tree/main/packages/data-table-postgres) - PostgreSQL database driver
116
+ - [`data-table-sqlite`](https://github.com/remix-run/remix/tree/main/packages/data-table-sqlite) - SQLite database driver
88
117
 
89
118
  ## License
90
119
 
@@ -1,12 +1,12 @@
1
1
  # data-table-postgres
2
2
 
3
- PostgreSQL adapter for [`remix/data-table`](https://github.com/remix-run/remix/tree/main/packages/data-table). Use this package when you want `data-table` APIs backed by `pg`.
3
+ PostgreSQL database driver for [`remix/data-table`](https://github.com/remix-run/remix/tree/main/packages/data-table), backed by `pg`.
4
4
 
5
5
  ## Features
6
6
 
7
- - **Native `pg` Integration**: Works with `pg` `Pool` and `PoolClient` instances
7
+ - **Native `pg` Integration**: Creates a pool from `pg` configuration or uses an existing pool or client
8
8
  - **Full `data-table` API Support**: Queries, relations, writes, and transactions
9
- - **Adapter-Owned Compiler**: SQL compilation lives in this adapter, with optional shared pure helpers from `data-table`
9
+ - **PostgreSQL Compiler**: SQL compilation is handled automatically for PostgreSQL
10
10
  - **Multi-Statement Migrations**: `executeScript()` runs `up.sql` / `down.sql` files natively via `pg`
11
11
  - **Postgres Capabilities Enabled By Default**:
12
12
  - `returning: true`
@@ -24,20 +24,20 @@ npm i remix pg
24
24
  ## Usage
25
25
 
26
26
  ```ts
27
- import { Pool } from 'pg'
28
- import { createDatabase } from 'remix/data-table'
29
- import { createPostgresDatabaseAdapter } from 'remix/data-table/postgres'
27
+ import { createPostgresDatabase } from 'remix/data-table/postgres'
30
28
 
31
- let pool = new Pool({
29
+ let db = createPostgresDatabase({
32
30
  connectionString: process.env.DATABASE_URL,
33
31
  })
34
-
35
- let db = createDatabase(createPostgresDatabaseAdapter(pool))
36
32
  ```
37
33
 
38
34
  Use `db.query(...)`, relation loading, and transactions from `remix/data-table`. Import any driver-specific types you need directly from `pg`.
39
35
 
40
- ## Adapter Capabilities
36
+ Config-backed databases support `db.wipe()` and `db.reset()`. Call `await db.close()` during application shutdown to close the internally created pool. You may pass an existing `pg` pool or client when your application owns the driver lifecycle; `db.close()` leaves supplied clients alone, and destructive lifecycle methods are unavailable in that mode. `db.wipe()` requires a database name resolvable from the connection config (`database`, the path of `connectionString`, or the `PGDATABASE` environment variable) and throws when none is present.
37
+
38
+ Migration runs reserve one connection for the PostgreSQL advisory lock, migration SQL, and journal updates. Lock acquisition waits up to 60 seconds (via `lock_timeout`) and fails with an error instead of blocking forever. After a successful run the connection is unlocked and returned to the pool; if the migration or unlock fails, the reserved connection is destroyed instead of being reused, so a dirty session can never leak back into the pool. Nested migration lock acquisition throws instead of deadlocking.
39
+
40
+ ## Database Capabilities
41
41
 
42
42
  `data-table-postgres` reports this capability set by default:
43
43
 
@@ -51,7 +51,7 @@ Use `db.query(...)`, relation loading, and transactions from `remix/data-table`.
51
51
 
52
52
  ### Transaction Options
53
53
 
54
- Transaction options are passed through to the adapter as hints.
54
+ Transaction options are passed through to PostgreSQL as hints.
55
55
 
56
56
  ```ts
57
57
  await db.transaction(async (txDb) => txDb.exec('select 1'), {
@@ -60,12 +60,38 @@ await db.transaction(async (txDb) => txDb.exec('select 1'), {
60
60
  })
61
61
  ```
62
62
 
63
+ ## Running integration tests locally
64
+
65
+ To start a local Postgres container matching CI:
66
+
67
+ ```sh
68
+ podman run --name postgres \
69
+ -e POSTGRES_USER=postgres \
70
+ -e POSTGRES_PASSWORD=postgres \
71
+ -e POSTGRES_DB=remix \
72
+ -p 5432:5432 \
73
+ -d postgres:16
74
+ ```
75
+
76
+ Then run:
77
+
78
+ ```sh
79
+ REMIX_DATA_TABLE_POSTGRES_TEST_URL=postgres://postgres:postgres@127.0.0.1:5432/remix \
80
+ pnpm test src/lib/driver.integration.test.ts
81
+ ```
82
+
83
+ Remove the container when you are done:
84
+
85
+ ```sh
86
+ podman rm -f postgres
87
+ ```
88
+
63
89
  ## Related Packages
64
90
 
65
91
  - [`data-table`](https://github.com/remix-run/remix/tree/main/packages/data-table) - Core query/relations API
66
92
  - [`data-schema`](https://github.com/remix-run/remix/tree/main/packages/data-schema) - Schema parsing and validation
67
- - [`data-table-mysql`](https://github.com/remix-run/remix/tree/main/packages/data-table-mysql) - MySQL adapter
68
- - [`data-table-sqlite`](https://github.com/remix-run/remix/tree/main/packages/data-table-sqlite) - SQLite adapter
93
+ - [`data-table-mysql`](https://github.com/remix-run/remix/tree/main/packages/data-table-mysql) - MySQL database driver
94
+ - [`data-table-sqlite`](https://github.com/remix-run/remix/tree/main/packages/data-table-sqlite) - SQLite database driver
69
95
 
70
96
  ## License
71
97
 
@@ -1,12 +1,12 @@
1
1
  # data-table-sqlite
2
2
 
3
- SQLite adapter for [`remix/data-table`](https://github.com/remix-run/remix/tree/main/packages/data-table). Use this package when you want `data-table` APIs backed by a synchronous SQLite client.
3
+ SQLite database driver for [`remix/data-table`](https://github.com/remix-run/remix/tree/main/packages/data-table), backed by a synchronous SQLite client.
4
4
 
5
5
  ## Features
6
6
 
7
- - **Native Runtime SQLite Support**: Works with Node's `node:sqlite` `DatabaseSync`, Bun's `bun:sqlite` `Database`, and compatible synchronous SQLite clients
7
+ - **Native Runtime SQLite Support**: Opens a configured filename with Node's `node:sqlite` or Bun's `bun:sqlite`, or uses a compatible synchronous SQLite client
8
8
  - **Full `data-table` API Support**: Queries, relations, writes, and transactions
9
- - **Adapter-Owned Compiler**: SQL compilation lives in this adapter, with optional shared pure helpers from `data-table`
9
+ - **SQLite Compiler**: SQL compilation is handled automatically for SQLite
10
10
  - **Multi-Statement Migrations**: `executeScript()` runs `up.sql` / `down.sql` files via `Database.exec()`
11
11
  - **SQLite Capabilities Enabled By Default**:
12
12
  - `returning: true`
@@ -23,31 +23,42 @@ npm i remix
23
23
 
24
24
  ## Usage
25
25
 
26
- ### Node
27
-
28
26
  ```ts
29
- import { DatabaseSync } from 'node:sqlite'
30
- import { createDatabase } from 'remix/data-table'
31
- import { createSqliteDatabaseAdapter } from 'remix/data-table/sqlite'
27
+ import { createSqliteDatabase } from 'remix/data-table/sqlite'
32
28
 
33
- let sqlite = new DatabaseSync('app.db')
34
- let db = createDatabase(createSqliteDatabaseAdapter(sqlite))
29
+ let db = createSqliteDatabase({
30
+ filename: 'app.db',
31
+ foreignKeys: true,
32
+ })
35
33
  ```
36
34
 
37
- ### Bun
35
+ The config-backed database uses `node:sqlite` in Node.js and `bun:sqlite` in Bun. It supports `db.wipe()` and `db.reset()` because it can close and reopen the database file. Call `await db.close()` during application shutdown to release the connection and its file handle.
36
+
37
+ Foreign key enforcement defaults to off on every runtime. When `foreignKeys` is enabled, the database restores foreign key enforcement each time it opens the connection, including after destructive lifecycle operations.
38
+
39
+ The database also applies `pragma busy_timeout = 5000` whenever it opens the connection, so writes wait for a locked database instead of failing immediately with `SQLITE_BUSY`. Use `busyTimeout` to override the timeout in milliseconds (`0` disables the wait).
40
+
41
+ You may also pass an existing synchronous client when your application owns its lifecycle:
38
42
 
39
43
  ```ts
40
44
  import { Database } from 'bun:sqlite'
41
- import { createDatabase } from 'remix/data-table'
42
- import { createSqliteDatabaseAdapter } from 'remix/data-table/sqlite'
45
+ import { createSqliteDatabase } from 'remix/data-table/sqlite'
43
46
 
44
47
  let sqlite = new Database('app.db')
45
- let db = createDatabase(createSqliteDatabaseAdapter(sqlite))
48
+ let db = createSqliteDatabase(sqlite)
49
+
50
+ // Leaves the supplied client open.
51
+ await db.close()
52
+
53
+ // The application closes the client it owns.
54
+ sqlite.close()
46
55
  ```
47
56
 
57
+ Destructive lifecycle methods are unavailable when you pass an existing client.
58
+
48
59
  This is a good fit for local development, embedded deployments, and single-node services. Import any driver-specific types you need directly from your runtime's SQLite module.
49
60
 
50
- ## Adapter Capabilities
61
+ ## Database Capabilities
51
62
 
52
63
  `data-table-sqlite` reports this capability set by default:
53
64
 
@@ -59,23 +70,30 @@ This is a good fit for local development, embedded deployments, and single-node
59
70
 
60
71
  ## Advanced Usage
61
72
 
73
+ ### Destructive Lifecycle And Locking
74
+
75
+ `db.wipe()` and `db.reset()` assume a single process owns the database file. Stop other processes before wiping: on POSIX systems another process keeps writing to the deleted inode, and on Windows an open handle blocks deletion entirely. Wiping removes the `-wal`, `-shm`, and `-journal` sidecar files along with the main database file so a freshly created database never associates with stale sidecars.
76
+
77
+ SQLite migrations run without a cross-process migration lock (`migrationLock: false`), so run migrations from one process at a time.
78
+
79
+ `filename` resolves against the current working directory — for `remix db` commands, wherever you invoke the CLI. Prefer absolute paths or paths derived from `import.meta.dirname`.
80
+
62
81
  ### In-Memory Database For Tests
63
82
 
64
83
  ```ts
65
84
  import { DatabaseSync } from 'node:sqlite'
66
- import { createDatabase } from 'remix/data-table'
67
- import { createSqliteDatabaseAdapter } from 'remix/data-table/sqlite'
85
+ import { createSqliteDatabase } from 'remix/data-table/sqlite'
68
86
 
69
87
  let sqlite = new DatabaseSync(':memory:')
70
- let db = createDatabase(createSqliteDatabaseAdapter(sqlite))
88
+ let db = createSqliteDatabase(sqlite)
71
89
  ```
72
90
 
73
91
  ## Related Packages
74
92
 
75
93
  - [`data-table`](https://github.com/remix-run/remix/tree/main/packages/data-table) - Core query/relations API
76
94
  - [`data-schema`](https://github.com/remix-run/remix/tree/main/packages/data-schema) - Schema parsing and validation
77
- - [`data-table-postgres`](https://github.com/remix-run/remix/tree/main/packages/data-table-postgres) - PostgreSQL adapter
78
- - [`data-table-mysql`](https://github.com/remix-run/remix/tree/main/packages/data-table-mysql) - MySQL adapter
95
+ - [`data-table-postgres`](https://github.com/remix-run/remix/tree/main/packages/data-table-postgres) - PostgreSQL database driver
96
+ - [`data-table-mysql`](https://github.com/remix-run/remix/tree/main/packages/data-table-mysql) - MySQL database driver
79
97
 
80
98
  ## License
81
99
 
@@ -7,6 +7,7 @@ HTTP proxy utilities built on the web [Fetch API](https://developer.mozilla.org/
7
7
  - **Web Standards** - Built on the standard [JavaScript Fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API)
8
8
  - **Cookie Rewriting** - Supports rewriting `Set-Cookie` headers received from target server
9
9
  - **Forwarding Headers** - Supports `X-Forwarded-Proto`, `X-Forwarded-Host`, and `X-Forwarded-Port` headers
10
+ - **Encoding Headers** - Strips stale encoding and framing headers from proxied responses
10
11
  - **Custom Fetch** - Supports custom `fetch` implementations
11
12
 
12
13
  ## Installation
@@ -36,9 +37,33 @@ let title = text.match(/<title>([^<]+)<\/title>/)[1]
36
37
  assert(title.includes('Remix'))
37
38
  ```
38
39
 
40
+ ## Encoding and Framing Headers
41
+
42
+ Since proxying is done via `fetch` rather than raw HTTP messages, some encoding and framing headers need to be removed.
43
+
44
+ The incoming `Accept-Encoding` request header describes the final client, so it is not forwarded to the target server.
45
+
46
+ Since `fetch` can decompress upstream responses and does not expose raw HTTP transfer framing, `fetch-proxy` strips response headers that may no longer describe the returned body: `Content-Encoding`, related `Content-Length`, and `Transfer-Encoding`.
47
+
48
+ To support serving compressed responses to the final client, you'll need to compress the response after the proxy returns it, e.g. with the [`compressResponse` helper from `remix/response`](https://github.com/remix-run/remix/tree/main/packages/response#compress-responses):
49
+
50
+ ```ts
51
+ import { createFetchProxy } from 'remix/fetch-proxy'
52
+ import { compressResponse } from 'remix/response/compress'
53
+
54
+ let proxy = createFetchProxy('https://remix.run')
55
+
56
+ async function handleFetch(request: Request): Promise<Response> {
57
+ let response = await proxy(request)
58
+
59
+ return compressResponse(response, request)
60
+ }
61
+ ```
62
+
39
63
  ## Related Packages
40
64
 
41
65
  - [`node-fetch-server`](https://github.com/remix-run/remix/tree/main/packages/node-fetch-server) - Build HTTP servers for Node.js using the web fetch API
66
+ - [`response`](https://github.com/remix-run/remix/tree/main/packages/response) - Create, transform, and compress Fetch API responses
42
67
 
43
68
  ## License
44
69
 
@@ -7,7 +7,7 @@ A streaming `multipart/form-data` parser that solves memory issues with file upl
7
7
  - **Drop-in replacement** for `request.formData()` with streaming file upload support
8
8
  - **Minimal buffering** - processes file upload streams with minimal memory footprint
9
9
  - **Standards-based** - built on the [web Streams API](https://developer.mozilla.org/en-US/docs/Web/API/Streams_API) and [File API](https://developer.mozilla.org/en-US/docs/Web/API/File)
10
- - **Smart fallback** - automatically uses native `request.formData()` for non-`multipart/form-data` requests
10
+ - **Smart fallback** - parses `application/x-www-form-urlencoded` requests with the same total size and field count limits, and uses native `request.formData()` for other form requests
11
11
  - **Storage agnostic** - works with any storage backend (local disk, S3, R2, etc.)
12
12
 
13
13
  ## Why You Need This
@@ -74,7 +74,7 @@ async function requestHandler(request: Request) {
74
74
 
75
75
  To validate the resulting `FormData` object with `remix/data-schema`, use the `remix/data-schema/form-data` helpers.
76
76
 
77
- To limit the overall shape of multipart requests, use the `maxHeaderSize`, `maxFileSize`, `maxFiles`, `maxParts`, and `maxTotalSize` options. By default, `parseFormData()` uses `maxFiles = 20`, `maxParts = 1000`, and `maxTotalSize = maxFiles * maxFileSize + 1 MiB`.
77
+ To limit the overall shape of multipart requests, use the `maxHeaderSize`, `maxFileSize`, `maxFiles`, `maxParts`, and `maxTotalSize` options. For `application/x-www-form-urlencoded` requests, `maxParts` limits the number of form fields and `maxTotalSize` limits the raw request body size. By default, `parseFormData()` uses `maxFiles = 20`, `maxParts = 1000`, and `maxTotalSize = maxFiles * maxFileSize + 1 MiB`.
78
78
 
79
79
  Known limit errors are thrown directly so you can handle them with `instanceof` checks. Other failures while parsing the request body are wrapped in `FormDataParseError`, with the original error available as `error.cause`. Errors thrown or rejected by your `uploadHandler` are not wrapped.
80
80
 
@@ -106,9 +106,9 @@ try {
106
106
  } else if (error instanceof MaxFileSizeExceededError) {
107
107
  console.error(`Files may not be larger than 10 MiB`)
108
108
  } else if (error instanceof MaxPartsExceededError) {
109
- console.error(`Request may not contain more than 25 multipart parts`)
109
+ console.error(`Request may not contain more than 25 form fields or multipart parts`)
110
110
  } else if (error instanceof MaxTotalSizeExceededError) {
111
- console.error(`Multipart request may not exceed 12 MiB of total content`)
111
+ console.error(`Form data request may not exceed 12 MiB of total content`)
112
112
  } else if (error instanceof FormDataParseError) {
113
113
  console.error(`Could not parse form data:`, error.cause ?? error)
114
114
  } else {
@@ -86,12 +86,19 @@ mimeTypeToContentType('image/png') // 'image/png'
86
86
  Registers or overrides a MIME type for one or more file extensions.
87
87
 
88
88
  ```ts
89
- import { defineMimeType } from 'remix/mime'
89
+ import { defineMimeType, detectMimeType } from 'remix/mime'
90
90
 
91
91
  defineMimeType({
92
92
  extensions: ['myformat'],
93
93
  mimeType: 'application/x-myformat',
94
94
  })
95
+
96
+ defineMimeType({
97
+ extensions: ['be.pit'],
98
+ mimeType: 'application/x-be-pit-document',
99
+ })
100
+
101
+ detectMimeType('filename.be.pit') // 'application/x-be-pit-document'
95
102
  ```
96
103
 
97
104
  You can also optionally configure the charset and whether the MIME type is compressible:
@@ -8,7 +8,8 @@ Build Node.js servers with web-standard Fetch API primitives. `node-fetch-server
8
8
  - **Node.js HTTP Integration** - Works directly with `node:http`, `node:https`, and `node:http2`
9
9
  - **Streaming Support** - Response support with `ReadableStream`
10
10
  - **Custom Hostname** - Configuration for deployment flexibility
11
- - **Client Info** - Access to client connection info (IP address, port)
11
+ - **Proxy Header Support** - Opt in to trusted `Forwarded`, `X-Forwarded-Host`, `X-Forwarded-Proto`, and `X-Forwarded-For` headers
12
+ - **Client Info** - Access to client connection info (IP address, port, and trusted proxy address)
12
13
  - **TypeScript** - Full TypeScript support with type definitions
13
14
 
14
15
  ## Installation
@@ -146,9 +147,34 @@ let server = http.createServer(createRequestListener(handler, { host: hostname }
146
147
  server.listen(3000)
147
148
  ```
148
149
 
150
+ ### Trusted Proxy Headers
151
+
152
+ If your app runs behind a trusted reverse proxy, Node.js sees the proxy connection instead of the original client connection. Enable `trustProxy` to use trusted proxy headers when constructing `request.url` and client information:
153
+
154
+ - `Forwarded: proto` and `X-Forwarded-Proto` can provide the original request protocol.
155
+ - `Forwarded: host` and `X-Forwarded-Host` can provide the original request host.
156
+ - `Forwarded: for` and `X-Forwarded-For` can provide the original client address.
157
+
158
+ Only enable this option when your server is reachable exclusively through a trusted proxy that overwrites these headers. Otherwise, clients can spoof the host, protocol, and client address.
159
+
160
+ ```ts
161
+ import * as http from 'node:http'
162
+ import { createRequestListener } from 'remix/node-fetch-server'
163
+
164
+ let server = http.createServer(
165
+ createRequestListener(handler, {
166
+ trustProxy: true,
167
+ }),
168
+ )
169
+
170
+ server.listen(3000)
171
+ ```
172
+
173
+ When `host` or `protocol` are set, those fixed options take precedence over trusted proxy headers.
174
+
149
175
  ### Accessing Client Information
150
176
 
151
- Get client connection details (IP address, port) for logging or security:
177
+ Get client connection details (IP address, port) for logging or security. When `trustProxy` is enabled, `client.address` uses trusted `Forwarded` or `X-Forwarded-For` values when present:
152
178
 
153
179
  ```ts
154
180
  import { type FetchHandler } from 'remix/node-fetch-server'
@@ -308,9 +334,9 @@ pnpm run bench:update-readme
308
334
 
309
335
  <!-- benchmarks:start -->
310
336
 
311
- Last updated: 2026-04-29T17:19:30.407Z
337
+ Last updated: 2026-07-23T20:29:32.942Z
312
338
 
313
- Environment: Darwin 25.3.0, Apple M1 Pro, Node.js v24.15.0
339
+ Environment: Darwin 25.4.0, Apple M5 Pro, Node.js v24.18.0
314
340
 
315
341
  Command: `wrk -t12 -c400 -d30s`
316
342
 
@@ -320,9 +346,9 @@ Simple HTML response benchmarks without inspecting the incoming request.
320
346
 
321
347
  | Server | Version | Requests/sec | Avg latency | Transfer/sec |
322
348
  | ------------------------- | --------: | -----------: | ----------: | -----------: |
323
- | `node:http` | `24.15.0` | `47,110` | `10.66ms` | `9.66MB` |
324
- | `remix/node-fetch-server` | `0.13.0` | `43,317` | `11.69ms` | `8.80MB` |
325
- | `express` | `5.2.1` | `39,752` | `13.69ms` | `9.59MB` |
349
+ | `node:http` | `24.18.0` | `66,594` | `5.96ms` | `13.65MB` |
350
+ | `remix/node-fetch-server` | `0.14.0` | `61,587` | `7.88ms` | `12.51MB` |
351
+ | `express` | `5.2.1` | `58,424` | `8.42ms` | `14.10MB` |
326
352
 
327
353
  ### Small Body
328
354
 
@@ -330,9 +356,9 @@ POST benchmarks that read and print the request method, headers, and a small bod
330
356
 
331
357
  | Server | Version | Requests/sec | Avg latency | Transfer/sec |
332
358
  | ------------------------- | --------: | -----------: | ----------: | -----------: |
333
- | `remix/node-fetch-server` | `0.13.0` | `25,430` | `24.25ms` | `5.17MB` |
334
- | `node:http` | `24.15.0` | `25,088` | `23.89ms` | `5.14MB` |
335
- | `express` | `5.2.1` | `22,845` | `27.16ms` | `5.51MB` |
359
+ | `node:http` | `24.18.0` | `35,303` | `15.60ms` | `7.24MB` |
360
+ | `express` | `5.2.1` | `32,614` | `16.93ms` | `7.87MB` |
361
+ | `remix/node-fetch-server` | `0.14.0` | `29,521` | `18.98ms` | `6.00MB` |
336
362
 
337
363
  ### Large Body
338
364
 
@@ -340,9 +366,9 @@ POST benchmarks that read and print the request method, headers, and a 1 MB body
340
366
 
341
367
  | Server | Version | Requests/sec | Avg latency | Transfer/sec |
342
368
  | ------------------------- | --------: | -----------: | ----------: | -----------: |
343
- | `remix/node-fetch-server` | `0.13.0` | `1,086` | `217.69ms` | `225.87KB` |
344
- | `node:http` | `24.15.0` | `1,079` | `198.67ms` | `226.54KB` |
345
- | `express` | `5.2.1` | `1,022` | `216.07ms` | `252.51KB` |
369
+ | `node:http` | `24.18.0` | `1,798` | `206.65ms` | `377.42KB` |
370
+ | `remix/node-fetch-server` | `0.14.0` | `1,752` | `167.69ms` | `364.40KB` |
371
+ | `express` | `5.2.1` | `1,731` | `223.19ms` | `427.67KB` |
346
372
 
347
373
  <!-- benchmarks:end -->
348
374