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.
- package/README.md +4 -2
- package/dist/assets/types/hmr.d.ts +2 -0
- package/dist/cli-entry.js +1 -1
- package/dist/data-table/cli.d.ts +2 -0
- package/dist/data-table/cli.d.ts.map +1 -0
- package/dist/{ui/scroll-lock.js → data-table/cli.js} +1 -1
- package/dist/node-hmr/runtime.d.ts +2 -0
- package/dist/node-hmr/runtime.d.ts.map +1 -0
- package/dist/node-hmr/runtime.js +2 -0
- package/dist/node-hmr/types.d.ts +2 -0
- package/dist/node-hmr.d.ts +2 -0
- package/dist/node-hmr.d.ts.map +1 -0
- package/dist/{ui/glyph.js → node-hmr.js} +1 -1
- package/dist/ui/accordion/primitives.d.ts +2 -0
- package/dist/ui/accordion/primitives.d.ts.map +1 -0
- package/dist/ui/accordion/primitives.js +2 -0
- package/dist/ui/button.d.ts +1 -0
- package/dist/ui/button.d.ts.map +1 -1
- package/dist/ui/button.js +1 -0
- package/dist/ui/checkbox.d.ts +3 -0
- package/dist/ui/checkbox.d.ts.map +1 -0
- package/dist/ui/checkbox.js +3 -0
- package/dist/ui/combobox/primitives.d.ts +2 -0
- package/dist/ui/combobox/primitives.d.ts.map +1 -0
- package/dist/ui/combobox/primitives.js +2 -0
- package/dist/ui/dev/refresh.d.ts +2 -0
- package/dist/ui/dev/refresh.d.ts.map +1 -0
- package/dist/ui/dev/refresh.js +2 -0
- package/dist/ui/input.d.ts +3 -0
- package/dist/ui/input.d.ts.map +1 -0
- package/dist/ui/input.js +3 -0
- package/dist/ui/menu/primitives.d.ts +2 -0
- package/dist/ui/menu/primitives.d.ts.map +1 -0
- package/dist/ui/menu/primitives.js +2 -0
- package/dist/ui/radio.d.ts +3 -0
- package/dist/ui/radio.d.ts.map +1 -0
- package/dist/ui/radio.js +3 -0
- package/dist/ui/select/primitives.d.ts +2 -0
- package/dist/ui/select/primitives.d.ts.map +1 -0
- package/dist/ui/select/primitives.js +2 -0
- package/dist/ui/tabs/primitives.d.ts +2 -0
- package/dist/ui/tabs/primitives.d.ts.map +1 -0
- package/dist/ui/tabs/primitives.js +2 -0
- package/dist/ui/tabs.d.ts +2 -0
- package/dist/ui/tabs.d.ts.map +1 -0
- package/{src/ui/theme.ts → dist/ui/tabs.js} +1 -1
- package/dist/ui/toggle/primitives.d.ts +2 -0
- package/dist/ui/toggle/primitives.d.ts.map +1 -0
- package/dist/ui/toggle/primitives.js +2 -0
- package/dist/ui/toggle.d.ts +3 -0
- package/dist/ui/toggle.d.ts.map +1 -0
- package/dist/ui/toggle.js +3 -0
- package/dist/ui-hmr/assets.d.ts +2 -0
- package/dist/ui-hmr/assets.d.ts.map +1 -0
- package/dist/ui-hmr/assets.js +2 -0
- package/dist/ui-hmr/node.d.ts +3 -0
- package/dist/ui-hmr/node.d.ts.map +1 -0
- package/dist/ui-hmr/node.js +3 -0
- package/dist/ui-hmr/runtime/browser.d.ts +2 -0
- package/dist/ui-hmr/runtime/browser.d.ts.map +1 -0
- package/dist/ui-hmr/runtime/browser.js +2 -0
- package/dist/ui-hmr/runtime/server.d.ts +2 -0
- package/dist/ui-hmr/runtime/server.d.ts.map +1 -0
- package/dist/ui-hmr/runtime/server.js +2 -0
- package/dist/ui-hmr.d.ts +2 -0
- package/dist/ui-hmr.d.ts.map +1 -0
- package/{src/ui/glyph.ts → dist/ui-hmr.js} +1 -1
- package/package.json +122 -142
- package/src/assets/README.md +322 -56
- package/src/assets/types/hmr.d.ts +2 -0
- package/src/cli/README.md +105 -1
- package/src/cookie/README.md +4 -4
- package/src/data-table/README.md +202 -68
- package/src/data-table/cli.ts +2 -0
- package/src/data-table-mysql/README.md +46 -17
- package/src/data-table-postgres/README.md +39 -13
- package/src/data-table-sqlite/README.md +38 -20
- package/src/fetch-proxy/README.md +25 -0
- package/src/form-data-parser/README.md +4 -4
- package/src/mime/README.md +8 -1
- package/src/node-fetch-server/README.md +39 -13
- package/src/node-hmr/README.md +307 -0
- package/src/node-hmr/runtime.ts +2 -0
- package/src/node-hmr/types.d.ts +2 -0
- package/{dist/ui/theme.js → src/node-hmr.ts} +1 -1
- package/src/route-pattern/README.md +141 -13
- package/src/session/README.md +1 -1
- package/src/session-middleware/README.md +9 -7
- package/src/test/README.md +161 -115
- package/src/ui/README.md +116 -157
- package/src/ui/accordion/README.md +50 -14
- package/src/ui/accordion/primitives/README.md +202 -0
- package/src/ui/accordion/primitives.ts +2 -0
- package/src/ui/anchor/README.md +37 -2
- package/src/ui/breadcrumbs/README.md +4 -4
- package/src/ui/button/README.md +26 -26
- package/src/ui/button.ts +1 -0
- package/src/ui/checkbox/README.md +59 -0
- package/src/ui/checkbox.ts +3 -0
- package/src/ui/combobox/README.md +58 -9
- package/src/ui/combobox/primitives/README.md +194 -0
- package/src/ui/combobox/primitives.ts +2 -0
- package/src/ui/dev/refresh.ts +2 -0
- package/src/ui/input/README.md +52 -0
- package/src/ui/input.ts +3 -0
- package/src/ui/listbox/README.md +9 -41
- package/src/ui/menu/README.md +55 -14
- package/src/ui/menu/primitives/README.md +161 -0
- package/src/ui/menu/primitives.ts +2 -0
- package/src/ui/popover/README.md +20 -39
- package/src/ui/radio/README.md +53 -0
- package/src/ui/radio.ts +3 -0
- package/src/ui/select/README.md +29 -19
- package/src/ui/select/primitives/README.md +117 -0
- package/src/ui/select/primitives.ts +2 -0
- package/src/ui/tabs/README.md +141 -0
- package/src/ui/tabs/primitives/README.md +141 -0
- package/src/ui/tabs/primitives.ts +2 -0
- package/src/ui/tabs.ts +2 -0
- package/src/ui/test/README.md +151 -60
- package/src/ui/toggle/README.md +56 -0
- package/src/ui/toggle/primitives/README.md +56 -0
- package/src/ui/toggle/primitives.ts +2 -0
- package/src/ui/toggle.ts +3 -0
- package/src/ui-hmr/README.md +119 -0
- package/{dist/ui/separator.js → src/ui-hmr/assets.ts} +1 -1
- package/src/ui-hmr/node.ts +3 -0
- package/src/ui-hmr/runtime/browser.ts +2 -0
- package/src/ui-hmr/runtime/server.ts +2 -0
- package/src/ui-hmr.ts +2 -0
- package/dist/ui/glyph.d.ts +0 -2
- package/dist/ui/glyph.d.ts.map +0 -1
- package/dist/ui/scroll-lock.d.ts +0 -2
- package/dist/ui/scroll-lock.d.ts.map +0 -1
- package/dist/ui/separator.d.ts +0 -2
- package/dist/ui/separator.d.ts.map +0 -1
- package/dist/ui/theme.d.ts +0 -2
- package/dist/ui/theme.d.ts.map +0 -1
- package/src/ui/glyph/README.md +0 -72
- package/src/ui/scroll-lock/README.md +0 -33
- package/src/ui/scroll-lock.ts +0 -2
- package/src/ui/separator.ts +0 -2
- package/src/ui/theme/README.md +0 -103
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
# data-table-mysql
|
|
2
2
|
|
|
3
|
-
MySQL
|
|
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**:
|
|
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
|
-
- **
|
|
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 {
|
|
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
|
|
32
|
-
|
|
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
|
-
##
|
|
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
|
|
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 {
|
|
54
|
+
import { createMysqlDatabase } from 'remix/data-table/mysql'
|
|
55
55
|
|
|
56
|
-
let
|
|
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`.
|
|
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
|
|
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
|
|
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
|
|
87
|
-
- [`data-table-sqlite`](https://github.com/remix-run/remix/tree/main/packages/data-table-sqlite) - SQLite
|
|
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
|
|
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**:
|
|
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
|
-
- **
|
|
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 {
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
|
68
|
-
- [`data-table-sqlite`](https://github.com/remix-run/remix/tree/main/packages/data-table-sqlite) - SQLite
|
|
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
|
|
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**:
|
|
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
|
-
- **
|
|
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 {
|
|
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
|
|
34
|
-
|
|
29
|
+
let db = createSqliteDatabase({
|
|
30
|
+
filename: 'app.db',
|
|
31
|
+
foreignKeys: true,
|
|
32
|
+
})
|
|
35
33
|
```
|
|
36
34
|
|
|
37
|
-
|
|
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 {
|
|
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 =
|
|
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
|
-
##
|
|
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 {
|
|
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 =
|
|
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
|
|
78
|
-
- [`data-table-mysql`](https://github.com/remix-run/remix/tree/main/packages/data-table-mysql) - MySQL
|
|
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** -
|
|
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(`
|
|
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 {
|
package/src/mime/README.md
CHANGED
|
@@ -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
|
-
- **
|
|
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-
|
|
337
|
+
Last updated: 2026-07-23T20:29:32.942Z
|
|
312
338
|
|
|
313
|
-
Environment: Darwin 25.
|
|
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.
|
|
324
|
-
| `remix/node-fetch-server` | `0.
|
|
325
|
-
| `express` | `5.2.1` | `
|
|
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
|
-
| `
|
|
334
|
-
| `
|
|
335
|
-
| `
|
|
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
|
-
| `
|
|
344
|
-
| `node
|
|
345
|
-
| `express` | `5.2.1` | `1,
|
|
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
|
|