@zerotal/inertia 1.13.5 → 1.14.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/CHANGELOG.md CHANGED
@@ -8,6 +8,26 @@ follows the Zerotal monorepo's unified versioning.
8
8
 
9
9
  ## [Unreleased]
10
10
 
11
+ ## [1.14.0] — 2026-09-01
12
+
13
+ ### Changed — **BREAKING**
14
+
15
+ - **`inertia.ssr: true` no longer registers `POST /__ssr`.** Rendering and the endpoint are
16
+ separate decisions: `ssr` renders in-process, `ssrEndpoint` exposes the route.
17
+
18
+ Most apps need no change. `ssr: true` still means "server-render every first page load",
19
+ which is what it is named for. Add `ssrEndpoint: true` only if something outside the web
20
+ process calls `/__ssr` — a separate renderer, a second host.
21
+
22
+ The endpoint exists because upstream Inertia runs on hosts with no JavaScript runtime:
23
+ PHP cannot import a `.tsx`, so it posts to a Node process. Bun is a JavaScript runtime,
24
+ so `ssr` imports the component and renders it inline, with no serialisation and no
25
+ network hop. The endpoint remains for the case that is still real — deliberately moving
26
+ render CPU off the web process — and is no longer something an app gets by accident.
27
+
28
+ Turning rendering on should not open a route that renders arbitrary components from POST
29
+ input, however well guarded. One switch, one thing.
30
+
11
31
  ## [1.13.5] — 2026-09-01
12
32
 
13
33
  ### Fixed
package/api-surface.md CHANGED
@@ -241,6 +241,7 @@ interface InertiaConfigShape = {
241
241
  htmlTemplate: string
242
242
  pagesDir: string
243
243
  ssr: boolean
244
+ ssrEndpoint: boolean
244
245
  ssrSecret: string
245
246
  version: string
246
247
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zerotal/inertia",
3
- "version": "1.13.5",
3
+ "version": "1.14.0",
4
4
  "license": "MIT",
5
5
  "maturity": "stable",
6
6
  "private": false,
@@ -34,7 +34,7 @@
34
34
  "typecheck": "tsc --noEmit"
35
35
  },
36
36
  "dependencies": {
37
- "@zerotal/core": "1.13.5"
37
+ "@zerotal/core": "1.14.0"
38
38
  },
39
39
  "peerDependencies": {
40
40
  "react": "^18 || ^19",
package/src/config.ts CHANGED
@@ -14,20 +14,44 @@ export interface InertiaConfigShape {
14
14
  */
15
15
  pagesDir: string;
16
16
  /**
17
- * Enable server-side rendering.
17
+ * Server-render every first page load.
18
18
  *
19
- * When true, InertiaProvider registers POST /__ssr which accepts
20
- * { component, props, url } and returns { body, head } - the same
21
- * contract as the Inertia Node SSR server. The Inertia client calls
22
- * this endpoint when rendering the first page load on the server.
19
+ * `Inertia.render()` renders the component into the root, injects the page's
20
+ * `<Head>` into the served `<head>`, and marks the root `data-server-rendered`
21
+ * so the client hydrates it. One line; no controller changes.
23
22
  *
24
- * Pages are rendered with the framework they're authored in: React `.tsx`
25
- * via `react-dom/server`, or Vue `.vue` via `@inertiajs/vue3` + `vue/server-renderer`.
26
- * Install the server renderer for the framework(s) the app uses.
23
+ * Pages render with the framework they are authored in: React `.tsx` via
24
+ * `react-dom/server`, Vue `.vue` via `@inertiajs/vue3` + `vue/server-renderer`.
25
+ * Install the server renderer for the framework the app uses.
26
+ *
27
+ * **This renders in-process and registers no route.** Until 1.14.0 it did the
28
+ * opposite — it registered `POST /__ssr` and rendered nothing — so an app that
29
+ * set it got an HTTP endpoint it had not asked for and the empty root it
30
+ * already had. See {@link ssrEndpoint} for the endpoint, which is now its own
31
+ * decision.
27
32
  *
28
33
  * Default: false
29
34
  */
30
35
  ssr: boolean;
36
+ /**
37
+ * Expose `POST /__ssr` for a renderer running outside this process.
38
+ *
39
+ * The endpoint accepts `{ component, props, url }` and returns `{ body, head }` —
40
+ * the contract upstream Inertia uses, where the web framework has no JavaScript
41
+ * runtime and must hand rendering to a separate Node process.
42
+ *
43
+ * **Zerotal does not need that boundary.** Bun *is* a JavaScript runtime, so
44
+ * {@link ssr} imports the component and renders it inline. The endpoint remains
45
+ * for the one case that is still real: deliberately moving render CPU off the
46
+ * web process, onto another process or another host.
47
+ *
48
+ * Separate from {@link ssr} since 1.14.0. Turning rendering on should not open a
49
+ * route that renders arbitrary components from POST input, however well guarded —
50
+ * one switch, one thing.
51
+ *
52
+ * Default: false
53
+ */
54
+ ssrEndpoint: boolean;
31
55
  /**
32
56
  * Shared secret required to reach `POST /__ssr` from off-box.
33
57
  *
@@ -105,6 +129,7 @@ const defaults: InertiaConfigShape = {
105
129
  assetsUrl: "/",
106
130
  pagesDir: DEFAULT_PAGES_DIR,
107
131
  ssr: false,
132
+ ssrEndpoint: false,
108
133
  ssrSecret: "",
109
134
  encryptHistory: false,
110
135
  devtools: {
@@ -135,7 +160,7 @@ function _envFlag(name: string): boolean | null {
135
160
  * export default InertiaConfig({
136
161
  * htmlTemplate: './resources/app.html',
137
162
  * version: Bun.env['ASSET_VERSION'] ?? '1',
138
- * ssr: true, // enable SSR endpoint at POST /__ssr
163
+ * ssr: true, // server-render every first page load
139
164
  * });
140
165
  */
141
166
  export function InertiaConfig(options: Partial<InertiaConfigShape> = {}): InertiaConfigShape {
@@ -103,8 +103,11 @@ export class InertiaProvider extends ServiceProvider {
103
103
  // installed, so React apps are unaffected.
104
104
  await registerVueRuntimeLoader(process.cwd());
105
105
 
106
- // 3. Register SSR endpoint when enabled
107
- if (config.get<boolean>("inertia.ssr", false)) {
106
+ // 3. Register the SSR endpoint when the app asks for it — `ssrEndpoint`, not
107
+ // `ssr`. Rendering happens in-process (see `inertia.ts`); this route exists only
108
+ // for a renderer running somewhere else, and turning rendering on should not
109
+ // open a route that renders arbitrary components from POST input.
110
+ if (config.get<boolean>("inertia.ssrEndpoint", false)) {
108
111
  // Throttled as well as loopback-gated: rendering a page is real CPU, and this route
109
112
  // sits outside every application guard.
110
113
  Router.post(