@inertia-node/nest 0.1.0 → 0.1.1
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 +255 -0
- package/package.json +4 -3
package/README.md
ADDED
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
# @inertia-node/nest
|
|
2
|
+
|
|
3
|
+
NestJS adapter for Inertia.js on the Express platform.
|
|
4
|
+
|
|
5
|
+
`@inertia-node/nest` integrates Inertia into Nest controllers through a module, interceptor, decorators, guards, and a session adapter. It keeps the same protocol behavior as the Express package while using Nest conventions for routing and dependency injection.
|
|
6
|
+
|
|
7
|
+
## Features
|
|
8
|
+
|
|
9
|
+
- Provides `InertiaModule.forRoot(...)` for application-level setup.
|
|
10
|
+
- Provides `InertiaInterceptor` for controller response conversion.
|
|
11
|
+
- Provides `@Inertia(...)` and `@InertiaRenderOptions(...)` decorators.
|
|
12
|
+
- Provides `InertiaAuthGuard` and `InertiaGuestGuard`.
|
|
13
|
+
- Supports Express sessions through `nestExpressSessionAdapter()`.
|
|
14
|
+
- Supports shared props, lazy props, deferred props, validation errors, flash data, redirects, and SSR.
|
|
15
|
+
- Re-exports shared helpers from `@inertia-node/core`.
|
|
16
|
+
|
|
17
|
+
## Installation
|
|
18
|
+
|
|
19
|
+
```sh
|
|
20
|
+
pnpm add @inertia-node/nest @nestjs/common @nestjs/core @nestjs/platform-express express express-session
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
```sh
|
|
24
|
+
npm install @inertia-node/nest @nestjs/common @nestjs/core @nestjs/platform-express express express-session
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Peer dependencies:
|
|
28
|
+
|
|
29
|
+
- `@nestjs/common >=10 <12`
|
|
30
|
+
- `@nestjs/core >=10 <12`
|
|
31
|
+
- `express >=4.18 <6`
|
|
32
|
+
- `reflect-metadata >=0.1 <1`
|
|
33
|
+
- `rxjs >=7 <8`
|
|
34
|
+
|
|
35
|
+
## Quick Start
|
|
36
|
+
|
|
37
|
+
```ts
|
|
38
|
+
import {
|
|
39
|
+
Controller,
|
|
40
|
+
Get,
|
|
41
|
+
Module,
|
|
42
|
+
UseGuards,
|
|
43
|
+
UseInterceptors,
|
|
44
|
+
} from "@nestjs/common";
|
|
45
|
+
import { NestFactory } from "@nestjs/core";
|
|
46
|
+
import session from "express-session";
|
|
47
|
+
import {
|
|
48
|
+
Inertia,
|
|
49
|
+
InertiaAuthGuard,
|
|
50
|
+
InertiaGuestGuard,
|
|
51
|
+
InertiaInterceptor,
|
|
52
|
+
InertiaModule,
|
|
53
|
+
inertiaAuth,
|
|
54
|
+
nestExpressSessionAdapter,
|
|
55
|
+
} from "@inertia-node/nest";
|
|
56
|
+
|
|
57
|
+
type User = {
|
|
58
|
+
id: number;
|
|
59
|
+
name: string;
|
|
60
|
+
email: string;
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
async function findUser(id?: number): Promise<User | null> {
|
|
64
|
+
if (!id) return null;
|
|
65
|
+
return { id, name: "Ada Lovelace", email: "ada@example.com" };
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
@Controller()
|
|
69
|
+
@UseInterceptors(InertiaInterceptor)
|
|
70
|
+
class PageController {
|
|
71
|
+
@Get("/dashboard")
|
|
72
|
+
@UseGuards(InertiaAuthGuard)
|
|
73
|
+
@Inertia("Dashboard/Index")
|
|
74
|
+
dashboard() {
|
|
75
|
+
return {
|
|
76
|
+
stats: {
|
|
77
|
+
users: 42,
|
|
78
|
+
orders: 128,
|
|
79
|
+
},
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
@Get("/login")
|
|
84
|
+
@UseGuards(InertiaGuestGuard)
|
|
85
|
+
@Inertia("Auth/Login")
|
|
86
|
+
login() {
|
|
87
|
+
return {
|
|
88
|
+
title: "Sign in",
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
@Module({
|
|
94
|
+
imports: [
|
|
95
|
+
InertiaModule.forRoot({
|
|
96
|
+
version: "1",
|
|
97
|
+
session: nestExpressSessionAdapter(),
|
|
98
|
+
auth: inertiaAuth({
|
|
99
|
+
getUser: (req) => findUser(req.session?.userId),
|
|
100
|
+
login: (req, user: User) => {
|
|
101
|
+
req.session!.userId = user.id;
|
|
102
|
+
},
|
|
103
|
+
logout: (req) => {
|
|
104
|
+
delete req.session!.userId;
|
|
105
|
+
},
|
|
106
|
+
serializeUser: (user) => ({
|
|
107
|
+
id: user.id,
|
|
108
|
+
name: user.name,
|
|
109
|
+
}),
|
|
110
|
+
redirectTo: "/login",
|
|
111
|
+
home: "/dashboard",
|
|
112
|
+
}),
|
|
113
|
+
share: async ({ request }) => ({
|
|
114
|
+
locale: request.headers["accept-language"] ?? "en",
|
|
115
|
+
}),
|
|
116
|
+
rootView: ({ page }) => `
|
|
117
|
+
<!doctype html>
|
|
118
|
+
<html>
|
|
119
|
+
<head>
|
|
120
|
+
<meta charset="utf-8" />
|
|
121
|
+
<script type="module" src="/src/app.tsx"></script>
|
|
122
|
+
</head>
|
|
123
|
+
<body>
|
|
124
|
+
<div id="app" data-page='${page}'></div>
|
|
125
|
+
</body>
|
|
126
|
+
</html>`,
|
|
127
|
+
}),
|
|
128
|
+
],
|
|
129
|
+
controllers: [PageController],
|
|
130
|
+
})
|
|
131
|
+
class AppModule {}
|
|
132
|
+
|
|
133
|
+
async function bootstrap() {
|
|
134
|
+
const app = await NestFactory.create(AppModule);
|
|
135
|
+
|
|
136
|
+
app.use(
|
|
137
|
+
session({
|
|
138
|
+
secret: process.env.SESSION_SECRET ?? "replace-me",
|
|
139
|
+
resave: false,
|
|
140
|
+
saveUninitialized: false,
|
|
141
|
+
}),
|
|
142
|
+
);
|
|
143
|
+
|
|
144
|
+
await app.listen(3000);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
void bootstrap();
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
## Controller Patterns
|
|
151
|
+
|
|
152
|
+
Use the decorator form when a route always renders one component:
|
|
153
|
+
|
|
154
|
+
```ts
|
|
155
|
+
@Get("/users")
|
|
156
|
+
@Inertia("Users/Index")
|
|
157
|
+
index() {
|
|
158
|
+
return {
|
|
159
|
+
users: await loadUsers(),
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
Use explicit helper results when a route decides what to do at runtime:
|
|
165
|
+
|
|
166
|
+
```ts
|
|
167
|
+
@Post("/users")
|
|
168
|
+
async store() {
|
|
169
|
+
const valid = false;
|
|
170
|
+
|
|
171
|
+
if (!valid) {
|
|
172
|
+
return Inertia.backWithErrors({
|
|
173
|
+
email: ["Email is required."],
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
return Inertia.redirect("/users");
|
|
178
|
+
}
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
Supported explicit results:
|
|
182
|
+
|
|
183
|
+
- `Inertia.render(component, props?, options?)`
|
|
184
|
+
- `Inertia.redirect(location, status?)`
|
|
185
|
+
- `Inertia.location(location)`
|
|
186
|
+
- `Inertia.backWithErrors(errors, options?)`
|
|
187
|
+
|
|
188
|
+
## Module API
|
|
189
|
+
|
|
190
|
+
`InertiaModule.forRoot(options)` accepts `NestInertiaOptions`.
|
|
191
|
+
|
|
192
|
+
Common options:
|
|
193
|
+
|
|
194
|
+
- `version`
|
|
195
|
+
- `rootView`
|
|
196
|
+
- `share`
|
|
197
|
+
- `session`
|
|
198
|
+
- `auth`
|
|
199
|
+
- `ssr`
|
|
200
|
+
- `withAllErrors`
|
|
201
|
+
|
|
202
|
+
The module can also receive a prebuilt `@inertia-node/core` instance through `instance`.
|
|
203
|
+
|
|
204
|
+
## Auth and Session
|
|
205
|
+
|
|
206
|
+
`nestExpressSessionAdapter()` maps an Express session object to the shared session contract. Register `express-session` before serving routes that depend on auth, flash, or validation errors.
|
|
207
|
+
|
|
208
|
+
`InertiaAuthGuard` redirects unauthenticated users to `auth.redirectTo`, defaulting to `"/login"`.
|
|
209
|
+
|
|
210
|
+
`InertiaGuestGuard` redirects authenticated users to `auth.home`, defaulting to `"/dashboard"`.
|
|
211
|
+
|
|
212
|
+
## SSR
|
|
213
|
+
|
|
214
|
+
```ts
|
|
215
|
+
InertiaModule.forRoot({
|
|
216
|
+
ssr: {
|
|
217
|
+
enabled: true,
|
|
218
|
+
url: "http://127.0.0.1:13714/render",
|
|
219
|
+
timeoutMs: 1500,
|
|
220
|
+
},
|
|
221
|
+
});
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
Use `@inertia-node/ssr` to run the renderer process.
|
|
225
|
+
|
|
226
|
+
## Exports
|
|
227
|
+
|
|
228
|
+
- `InertiaModule`
|
|
229
|
+
- `InertiaInterceptor`
|
|
230
|
+
- `InertiaAuthGuard`
|
|
231
|
+
- `InertiaGuestGuard`
|
|
232
|
+
- `Inertia`
|
|
233
|
+
- `InertiaRenderOptions`
|
|
234
|
+
- `nestExpressSessionAdapter`
|
|
235
|
+
- `InertiaService`
|
|
236
|
+
- `NestInertiaOptions`
|
|
237
|
+
- `NestInertiaAsyncOptions`
|
|
238
|
+
- `NestRenderOptions`
|
|
239
|
+
- `InertiaControllerResult`
|
|
240
|
+
- Re-exported core helpers such as `always`, `defer`, `merge`, `optional`, `validationError`, `inertiaAuth`, and `createInertia`
|
|
241
|
+
|
|
242
|
+
## Troubleshooting
|
|
243
|
+
|
|
244
|
+
- If the controller response is returned as normal JSON, confirm `@UseInterceptors(InertiaInterceptor)` is applied.
|
|
245
|
+
- If auth always fails, confirm `express-session` is registered and `session: nestExpressSessionAdapter()` is configured.
|
|
246
|
+
- If validation redirects throw, confirm a session adapter is configured.
|
|
247
|
+
- If full-page requests are missing app HTML, confirm `rootView` returns a document with `data-page='${page}'`.
|
|
248
|
+
|
|
249
|
+
## Documentation
|
|
250
|
+
|
|
251
|
+
- Repository: https://github.com/inertia-node/inertia-node-adapter
|
|
252
|
+
- Quick start: https://github.com/inertia-node/inertia-node-adapter/blob/main/docs/quickstart.md
|
|
253
|
+
- Auth: https://github.com/inertia-node/inertia-node-adapter/blob/main/docs/auth.md
|
|
254
|
+
- Sessions, flash, and validation: https://github.com/inertia-node/inertia-node-adapter/blob/main/docs/session-flash-validation.md
|
|
255
|
+
- SSR: https://github.com/inertia-node/inertia-node-adapter/blob/main/docs/ssr.md
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@inertia-node/nest",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "NestJS adapter for Inertia.js on Node.js.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Inertia Node Adapter contributors",
|
|
@@ -32,10 +32,11 @@
|
|
|
32
32
|
}
|
|
33
33
|
},
|
|
34
34
|
"files": [
|
|
35
|
-
"dist"
|
|
35
|
+
"dist",
|
|
36
|
+
"README.md"
|
|
36
37
|
],
|
|
37
38
|
"dependencies": {
|
|
38
|
-
"@inertia-node/core": "0.1.
|
|
39
|
+
"@inertia-node/core": "0.1.1"
|
|
39
40
|
},
|
|
40
41
|
"peerDependencies": {
|
|
41
42
|
"@nestjs/common": ">=10 <12",
|