@blacklizard/inertia-express 3.0.0 → 3.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +60 -20
- package/dist/core/index.d.ts +2 -2
- package/dist/core/index.js +2 -2
- package/dist/{core-ChQbBw-k.js → core-PN_yVSCS.js} +612 -370
- package/dist/core-PN_yVSCS.js.map +1 -0
- package/dist/express/index.d.ts +57 -12
- package/dist/express/index.d.ts.map +1 -1
- package/dist/express/index.js +127 -35
- package/dist/express/index.js.map +1 -1
- package/dist/{index-PWaujyMo.d.ts → index-C7vBpEDY.d.ts} +201 -8
- package/dist/index-C7vBpEDY.d.ts.map +1 -0
- package/package.json +5 -1
- package/dist/core-ChQbBw-k.js.map +0 -1
- package/dist/index-PWaujyMo.d.ts.map +0 -1
package/README.md
CHANGED
|
@@ -18,9 +18,10 @@ The internal core is framework-agnostic, so future adapters for Fastify, Hono, N
|
|
|
18
18
|
- `res.inertia(component, props, options)` Express helper
|
|
19
19
|
- Shared props (static or per-request)
|
|
20
20
|
- Optional, deferred (with rescue), always, merge, deep-merge, once, and infinite-scroll props
|
|
21
|
+
- Live props (`liveProps` channel listeners) and `broadcastProps` payloads for your realtime server
|
|
21
22
|
- Partial reloads (`X-Inertia-Partial-Data` / `X-Inertia-Partial-Except`)
|
|
22
23
|
- Asset version handling and automatic 409 + `X-Inertia-Location` on mismatch
|
|
23
|
-
- Inertia-aware redirects (auto 303 after PUT/PATCH/DELETE)
|
|
24
|
+
- Inertia-aware redirects (auto 303 after PUT/PATCH/DELETE/QUERY, 409 + `X-Inertia-Redirect` for `#fragment` targets, empty 200 → redirect back)
|
|
24
25
|
- External redirects via `res.inertiaLocation()`
|
|
25
26
|
- Validation error helpers
|
|
26
27
|
- Pluggable root view
|
|
@@ -88,7 +89,7 @@ Pass options to `inertia({ ... })`:
|
|
|
88
89
|
| `ssr` | `SsrRenderer` | SSR hook returning `{ head, body }`. See [SSR](#server-side-rendering-ssr). |
|
|
89
90
|
| `cache` | `InertiaCacheOptions` | View cache for SSR HTML. See [View cache](#view-cache). |
|
|
90
91
|
| `edgeCache` | `EdgeCachePolicy` | CDN `Cache-Control` policy. See [Edge caching](#edge-caching-cdn). |
|
|
91
|
-
| `flashFromSession` | `boolean` |
|
|
92
|
+
| `flashFromSession` | `boolean` | Surface `req.session.flash` as the top-level `flash` page key. Default off. |
|
|
92
93
|
|
|
93
94
|
If no `rootView` is given, the middleware emits a minimal default HTML shell with an empty `<div id="app">` plus the v3 `<script type="application/json" data-page="app">` page tag, so you can wire up a Vite client manually.
|
|
94
95
|
|
|
@@ -121,11 +122,12 @@ inertia({
|
|
|
121
122
|
auth: { user: req.user ?? null },
|
|
122
123
|
csrf: req.csrfToken?.(),
|
|
123
124
|
flash: req.session?.flash ?? {},
|
|
124
|
-
errors: req.session?.errors ?? {},
|
|
125
125
|
}),
|
|
126
126
|
});
|
|
127
127
|
```
|
|
128
128
|
|
|
129
|
+
Validation errors do not need wiring here: `errors` is shared on every page automatically (see [Validation errors](#validation-errors)).
|
|
130
|
+
|
|
129
131
|
## Prop helpers
|
|
130
132
|
|
|
131
133
|
Every prop value is either a plain value, a bare closure (evaluated on each
|
|
@@ -134,7 +136,7 @@ built by one of the constructors below. Descriptors are chainable and mirror
|
|
|
134
136
|
inertia-laravel's prop classes; the resolver is a port of its `PropsResolver`.
|
|
135
137
|
|
|
136
138
|
```ts
|
|
137
|
-
import { always, deepMerge, defer, merge, once, optional, scroll } from "@blacklizard/inertia-express";
|
|
139
|
+
import { always, deepMerge, defer, live, merge, once, optional, scroll } from "@blacklizard/inertia-express";
|
|
138
140
|
```
|
|
139
141
|
|
|
140
142
|
A bare closure replaces 2.x's `lazy()`:
|
|
@@ -260,6 +262,41 @@ app.get("/posts", async (req, res) => {
|
|
|
260
262
|
|
|
261
263
|
Laravel: `Inertia::scroll()`
|
|
262
264
|
|
|
265
|
+
### `live`
|
|
266
|
+
|
|
267
|
+
A prop the client refreshes when a realtime event arrives. `live(value, { on,
|
|
268
|
+
channel, throttle? })` resolves like a plain prop and lists its channel
|
|
269
|
+
listeners in the page object's `liveProps`; `always`, `optional`, `defer` and
|
|
270
|
+
`once` descriptors accept the same options through `.live(options)`. Merge and
|
|
271
|
+
scroll props cannot be live. Events are strings and channels are explicit: a
|
|
272
|
+
bare string channel is public, and `{ name, type }` sets `private`,
|
|
273
|
+
`presence` or `encrypted-private`. `throttle` is in milliseconds.
|
|
274
|
+
|
|
275
|
+
`broadcastProps(props, onRescue?)` resolves every prop (no partial or once
|
|
276
|
+
filtering, rescued props omitted) into the `{ __inertia: { props } }` payload
|
|
277
|
+
to send with the event; `resolveBroadcastProps` returns the bare props map. The
|
|
278
|
+
adapter does not open sockets: send the payload with your own realtime server.
|
|
279
|
+
`req.inertia.socketId` carries the `X-Socket-Id` header (`null` when absent) so
|
|
280
|
+
that server can skip the sender.
|
|
281
|
+
|
|
282
|
+
```ts
|
|
283
|
+
import { broadcastProps, live } from "@blacklizard/inertia-express";
|
|
284
|
+
|
|
285
|
+
app.get("/leads", async (req, res) => {
|
|
286
|
+
await res.inertia("Leads/Index", {
|
|
287
|
+
leads: live(() => loadLeads(), { on: "LeadUpdated", channel: { name: "leads", type: "private" } }),
|
|
288
|
+
});
|
|
289
|
+
});
|
|
290
|
+
|
|
291
|
+
// After a lead changes (Socket.IO shown)
|
|
292
|
+
// The client subscribes to the declared event on the declared channel.
|
|
293
|
+
io.to("leads")
|
|
294
|
+
.except(req.inertia?.socketId ?? [])
|
|
295
|
+
.emit("LeadUpdated", await broadcastProps({ leads: () => loadLeads() }));
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
Laravel: `Inertia::live()` / `->live()`
|
|
299
|
+
|
|
263
300
|
### Rescue hook and fragment preservation
|
|
264
301
|
|
|
265
302
|
Pass `onRescue: (error, path, req) => …` to `inertia({ … })` to report errors
|
|
@@ -302,18 +339,10 @@ The middleware applies this filtering automatically. Partial reload filtering is
|
|
|
302
339
|
|
|
303
340
|
## Validation errors
|
|
304
341
|
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
```ts
|
|
308
|
-
inertia({
|
|
309
|
-
sharedProps: (req) => ({ errors: req.session?.errors ?? {} }),
|
|
310
|
-
});
|
|
311
|
-
```
|
|
342
|
+
Record validation errors with `res.inertiaErrors(errors, bag?)`. Errors are stored per bag (`default` when no bag is given); a repeated bag replaces the earlier one and other bags are kept.
|
|
312
343
|
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
- Writes errors to `req.session.errors` if a session is present.
|
|
316
|
-
- Otherwise stores them on `res.locals.inertiaErrors` for the same response.
|
|
344
|
+
- With a session, it writes `req.session.inertia.errors[bag] = errors`; the next render reads them and clears them (read-once).
|
|
345
|
+
- Without a session, it writes the same bags map to `res.locals.inertiaErrors` for the current response.
|
|
317
346
|
|
|
318
347
|
```ts
|
|
319
348
|
app.post("/users", (req, res) => {
|
|
@@ -326,11 +355,22 @@ app.post("/users", (req, res) => {
|
|
|
326
355
|
});
|
|
327
356
|
```
|
|
328
357
|
|
|
329
|
-
|
|
358
|
+
The `errors` prop is shared on every page (`{}` when empty, listed in `sharedProps`, kept on partial reloads) whether or not `flashFromSession` is on, so no `sharedProps` wiring is needed. Bags are remapped when the page is read, as in inertia-laravel's `Middleware::resolveValidationErrors`:
|
|
359
|
+
|
|
360
|
+
- Errors stored without a bag come back flat: `props.errors.email`.
|
|
361
|
+
- If the request carries `X-Inertia-Error-Bag: signup`, those same errors come back as `props.errors.signup.email`.
|
|
362
|
+
- Errors stored under a named bag (`res.inertiaErrors(errors, "createUser")`) come back keyed by name, `props.errors.createUser.email`, when no `default` bag is stored. If a `default` bag is stored as well, only `default` is returned (flat, or under the header name) and the named bags are dropped.
|
|
363
|
+
|
|
364
|
+
An explicit `errors` key in your shared or page props wins over the shared one.
|
|
330
365
|
|
|
331
366
|
## Redirects
|
|
332
367
|
|
|
333
|
-
For Inertia requests, `res.redirect(url)` after a `PUT`, `PATCH`, or `
|
|
368
|
+
For Inertia requests, a `302` from `res.redirect(url)` after a `PUT`, `PATCH`, `DELETE` or `QUERY` is automatically promoted to status `303`. This is required by the Inertia protocol to ensure the follow-up request is a `GET`.
|
|
369
|
+
|
|
370
|
+
Two more inertia-laravel middleware rules apply to Inertia requests:
|
|
371
|
+
|
|
372
|
+
- **Fragment redirects** (`Middleware::onRedirectWithFragment`) — a redirect whose URL contains `#` is answered with `409`, `X-Inertia-Redirect: <url>` (encoded like `Location`) and an empty body, so the client can navigate and keep the fragment. Prefetch requests get the normal redirect.
|
|
373
|
+
- **Empty responses** (`Middleware::onEmptyResponse`) — a `200` with an empty body (`res.end()`, `res.send("")`) becomes a redirect back to the `Referer`, or `/` without one (`303` after PUT/PATCH/DELETE/QUERY, `302` otherwise). Responses whose headers were already sent (`res.flushHeaders()`, streaming) and handlers that never respond are not covered.
|
|
334
374
|
|
|
335
375
|
For external redirects (different host or full reload), use `res.inertiaLocation()`:
|
|
336
376
|
|
|
@@ -342,7 +382,7 @@ For Inertia (XHR) visits this returns `409 X-Inertia-Location: <url>` which the
|
|
|
342
382
|
|
|
343
383
|
## Asset versioning
|
|
344
384
|
|
|
345
|
-
Pass a `version` resolver. When a client's `X-Inertia-Version` header doesn't match the current value on a `GET`, the middleware responds with `409` + `X-Inertia-Location: <same-url
|
|
385
|
+
Pass a `version` resolver. When a client's `X-Inertia-Version` header doesn't match the current value on a `GET`, the middleware responds with `409` + `X-Inertia-Location: <same-url>` and `X-Inertia-Version: <current version>` (inertia-laravel's `Middleware::onVersionChange`), and the Inertia client performs a full reload.
|
|
346
386
|
|
|
347
387
|
```ts
|
|
348
388
|
inertia({
|
|
@@ -557,13 +597,13 @@ Failures on individual routes never halt the run — inspect `summary.results` t
|
|
|
557
597
|
|
|
558
598
|
## Flash from session
|
|
559
599
|
|
|
560
|
-
Set `flashFromSession: true` to
|
|
600
|
+
Set `flashFromSession: true` to surface `req.session.flash` as the top-level `flash` page key (a sibling of `props`, read on the client via `usePage().flash`) and clear it after read:
|
|
561
601
|
|
|
562
602
|
```ts
|
|
563
603
|
inertia({ flashFromSession: true });
|
|
564
604
|
```
|
|
565
605
|
|
|
566
|
-
Off by default
|
|
606
|
+
Off by default. Requires a session middleware that exposes `req.session`. The option gates only `flash`; validation errors are shared as the `errors` prop on every page regardless (see [Validation errors](#validation-errors)).
|
|
567
607
|
|
|
568
608
|
## Edge caching (CDN)
|
|
569
609
|
|
package/dist/core/index.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { $ as
|
|
2
|
-
export { AlwaysProp, BuildPageInput, ComputeCacheKeyInput, CreatePageInput, DefaultRootViewInput, DeferProp, ErrorPageInput, INERTIA_HEADERS, INERTIA_LOCATION_STATUS, INERTIA_REDIRECT_STATUS, type InertiaPage, type InertiaRequestInfo, MergeProp, type OnceMetadata, OnceProp, OptionalProp, type PageProps, PropDescriptor, type PropKind, type PropSource, type PropsMetadata, PropsResolver, type RenderOptions, type RescueHandler, ResolvePropsInput, ResolvePropsResult, type ScrollMetadata, type ScrollOptions, ScrollProp, type SharedPropsInput, SsrCacheEntry, SsrCacheStore, ValidationErrors, type VersionResolver, always, buildPage, canonicalStringify, computeSsrCacheKey, createPage, deepMerge, defer, encodePageScript, inertiaRedirectStatus, isPropDescriptor, isVersionMismatch, leadsToOnly, matchesExcept, matchesOnly, merge, once, optional, parseInertiaRequest, pathIsSameOrDescendant, renderDefaultHtml, renderErrorPage, resolveProps, resolveVersion, scopeErrors, scroll, unpackDotProps };
|
|
1
|
+
import { $ as ComputeCacheKeyInput, A as PropDescriptor, B as DefaultRootViewInput, C as live, D as scroll, E as optional, F as matchesExcept, G as INERTIA_HEADERS, H as encodePageScript, I as matchesOnly, J as ValidationErrorBags, K as PREFETCH_HEADERS, L as pathIsSameOrDescendant, M as PropSource, N as ScrollOptions, O as LiveChannelInput, P as leadsToOnly, Q as unpackDotProps, R as CreatePageInput, S as isPropDescriptor, T as once, U as renderDefaultHtml, V as ErrorPageInput, W as renderErrorPage, X as resolveValidationErrors, Y as ValidationErrors, Z as scopeErrors, _ as OptionalProp, _t as ScrollMetadata, a as INERTIA_LOCATION_STATUS, at as resolveBroadcastProps, b as deepMerge, c as PropsResolver, ct as LiveChannel, d as resolveProps, dt as LiveMetadata, et as SsrCacheEntry, f as AlwaysProp, ft as OnceMetadata, g as OnceProp, gt as RescueHandler, h as MergeProp, ht as RenderOptions, i as buildPage, it as broadcastProps, j as PropKind, k as LiveOptions, l as ResolvePropsInput, lt as LiveChannelType, m as LiveProp, mt as PropsMetadata, n as resolveVersion, nt as canonicalStringify, o as INERTIA_REDIRECT_STATUS, ot as InertiaPage, p as DeferProp, pt as PageProps, q as parseInertiaRequest, r as BuildPageInput, rt as computeSsrCacheKey, s as inertiaRedirectStatus, st as InertiaRequestInfo, t as isVersionMismatch, tt as SsrCacheStore, u as ResolvePropsResult, ut as LiveListener, v as ScrollProp, vt as SharedPropsInput, w as merge, x as defer, y as always, yt as VersionResolver, z as createPage } from "../index-C7vBpEDY.js";
|
|
2
|
+
export { AlwaysProp, BuildPageInput, ComputeCacheKeyInput, CreatePageInput, DefaultRootViewInput, DeferProp, ErrorPageInput, INERTIA_HEADERS, INERTIA_LOCATION_STATUS, INERTIA_REDIRECT_STATUS, type InertiaPage, type InertiaRequestInfo, type LiveChannel, type LiveChannelInput, type LiveChannelType, type LiveListener, type LiveMetadata, type LiveOptions, LiveProp, MergeProp, type OnceMetadata, OnceProp, OptionalProp, PREFETCH_HEADERS, type PageProps, PropDescriptor, type PropKind, type PropSource, type PropsMetadata, PropsResolver, type RenderOptions, type RescueHandler, ResolvePropsInput, ResolvePropsResult, type ScrollMetadata, type ScrollOptions, ScrollProp, type SharedPropsInput, SsrCacheEntry, SsrCacheStore, ValidationErrorBags, ValidationErrors, type VersionResolver, always, broadcastProps, buildPage, canonicalStringify, computeSsrCacheKey, createPage, deepMerge, defer, encodePageScript, inertiaRedirectStatus, isPropDescriptor, isVersionMismatch, leadsToOnly, live, matchesExcept, matchesOnly, merge, once, optional, parseInertiaRequest, pathIsSameOrDescendant, renderDefaultHtml, renderErrorPage, resolveBroadcastProps, resolveProps, resolveValidationErrors, resolveVersion, scopeErrors, scroll, unpackDotProps };
|
package/dist/core/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { A as
|
|
2
|
-
export { INERTIA_HEADERS, INERTIA_LOCATION_STATUS, INERTIA_REDIRECT_STATUS, PropDescriptor, PropsResolver, always, buildPage, canonicalStringify, computeSsrCacheKey, createPage, deepMerge, defer, encodePageScript, inertiaRedirectStatus, isPropDescriptor, isVersionMismatch, leadsToOnly, matchesExcept, matchesOnly, merge, once, optional, parseInertiaRequest, pathIsSameOrDescendant, renderDefaultHtml, renderErrorPage, resolveProps, resolveVersion, scopeErrors, scroll, unpackDotProps };
|
|
1
|
+
import { A as isPropDescriptor, C as matchesExcept, D as always, E as unpackDotProps, F as scroll, I as PropDescriptor, M as merge, N as once, O as deepMerge, P as optional, S as leadsToOnly, T as pathIsSameOrDescendant, _ as computeSsrCacheKey, a as INERTIA_REDIRECT_STATUS, b as PropsResolver, c as encodePageScript, d as INERTIA_HEADERS, f as PREFETCH_HEADERS, g as canonicalStringify, h as scopeErrors, i as INERTIA_LOCATION_STATUS, j as live, k as defer, l as renderDefaultHtml, m as resolveValidationErrors, n as resolveVersion, o as inertiaRedirectStatus, p as parseInertiaRequest, r as buildPage, s as createPage, t as isVersionMismatch, u as renderErrorPage, v as broadcastProps, w as matchesOnly, x as resolveProps, y as resolveBroadcastProps } from "../core-PN_yVSCS.js";
|
|
2
|
+
export { INERTIA_HEADERS, INERTIA_LOCATION_STATUS, INERTIA_REDIRECT_STATUS, PREFETCH_HEADERS, PropDescriptor, PropsResolver, always, broadcastProps, buildPage, canonicalStringify, computeSsrCacheKey, createPage, deepMerge, defer, encodePageScript, inertiaRedirectStatus, isPropDescriptor, isVersionMismatch, leadsToOnly, live, matchesExcept, matchesOnly, merge, once, optional, parseInertiaRequest, pathIsSameOrDescendant, renderDefaultHtml, renderErrorPage, resolveBroadcastProps, resolveProps, resolveValidationErrors, resolveVersion, scopeErrors, scroll, unpackDotProps };
|