@zerotal/inertia 1.14.3 → 1.15.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 +21 -0
- package/api-surface.md +3 -0
- package/package.json +2 -2
- package/src/PageRegistry.ts +48 -10
- package/src/index.ts +1 -0
- package/src/pages.ts +20 -1
- package/src/provider/InertiaProvider.ts +9 -0
package/CHANGELOG.md
CHANGED
|
@@ -8,6 +8,27 @@ follows the Zerotal monorepo's unified versioning.
|
|
|
8
8
|
|
|
9
9
|
## [Unreleased]
|
|
10
10
|
|
|
11
|
+
## [1.15.0] — 2026-09-04
|
|
12
|
+
|
|
13
|
+
### Added
|
|
14
|
+
|
|
15
|
+
- **`bun zt route:types` now regenerates the page registry too.** Adding a page and rendering
|
|
16
|
+
it failed typecheck with `TS2345: Argument of type '"ops/orders"' is not assignable to
|
|
17
|
+
parameter of type 'PageName'` — accurate and unhelpful, because it reads as a mistyped page
|
|
18
|
+
name when the actual state is a registry that has not been rebuilt. `route:types` is the
|
|
19
|
+
command whose name says it fixes that and used to regenerate only the routes half.
|
|
20
|
+
|
|
21
|
+
`InertiaProvider` registers `generatePageRegistry` through core's `registerTypeGenerator`,
|
|
22
|
+
so one command refreshes both, and `route:types --check` gates on both in CI. `PageName`
|
|
23
|
+
also carries a doc comment saying what to run, so the editor hover answers the question the
|
|
24
|
+
compiler error raises.
|
|
25
|
+
|
|
26
|
+
### Fixed
|
|
27
|
+
|
|
28
|
+
- **`generatePageRegistry` rewrote `pages.generated.ts` even when nothing had changed**,
|
|
29
|
+
churning its mtime on every dev rebuild and at every production boot — which is what a file
|
|
30
|
+
watcher keys on. It now compares before writing.
|
|
31
|
+
|
|
11
32
|
## [1.14.0] — 2026-09-01
|
|
12
33
|
|
|
13
34
|
### Changed — **BREAKING**
|
package/api-surface.md
CHANGED
|
@@ -3,6 +3,9 @@
|
|
|
3
3
|
<!-- AUTO-GENERATED by scripts/api-surface.ts. Do not edit by hand.
|
|
4
4
|
Run `bun run api:surface` to regenerate after an intentional API change. -->
|
|
5
5
|
|
|
6
|
+
> Not a guide — this is a flat, alphabetical snapshot used to detect unintended
|
|
7
|
+
> API changes. For how to use these, read the [documentation](https://zerotal.dev/docs).
|
|
8
|
+
|
|
6
9
|
## . `(./src/index.ts)`
|
|
7
10
|
|
|
8
11
|
class AlwaysProp = {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zerotal/inertia",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.15.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.
|
|
37
|
+
"@zerotal/core": "1.15.0"
|
|
38
38
|
},
|
|
39
39
|
"peerDependencies": {
|
|
40
40
|
"react": "^18 || ^19",
|
package/src/PageRegistry.ts
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
* Import paths in the generated file are computed relative to the generated
|
|
12
12
|
* file's own location (`resources/js/`), so any pages directory works.
|
|
13
13
|
*
|
|
14
|
-
* Run via: bun zt inertia:build
|
|
14
|
+
* Run via: bun zt route:types (or bun zt inertia:build, which also bundles).
|
|
15
15
|
* Or automatically during InertiaProvider.onBooted() in production.
|
|
16
16
|
*/
|
|
17
17
|
import { config } from "@zerotal/core";
|
|
@@ -24,21 +24,39 @@ import { DEFAULT_PAGES_DIR } from "./config.ts";
|
|
|
24
24
|
const GENERATED_DIR = "resources/js";
|
|
25
25
|
const GENERATED_FILE = `${GENERATED_DIR}/pages.generated.ts`;
|
|
26
26
|
|
|
27
|
+
/**
|
|
28
|
+
* What a registry generation did, for `route:types` to report and `--check` to
|
|
29
|
+
* gate on.
|
|
30
|
+
*
|
|
31
|
+
* @internal Returned by the `@internal` {@link generatePageRegistry}; the shape
|
|
32
|
+
* core's type-generator hook expects, not app-facing API.
|
|
33
|
+
*/
|
|
34
|
+
export interface PageRegistryResult {
|
|
35
|
+
/** The generated file, relative to the project root. */
|
|
36
|
+
file: string;
|
|
37
|
+
/** Page count, phrased for a summary line. */
|
|
38
|
+
summary: string;
|
|
39
|
+
/** Whether the file on disk differed from what the scan produced. */
|
|
40
|
+
changed: boolean;
|
|
41
|
+
}
|
|
42
|
+
|
|
27
43
|
/**
|
|
28
44
|
* Scan the pages directory and (re)write `resources/js/pages.generated.ts`, a map of
|
|
29
45
|
* page name → dynamic `import()` thunk that `Bun.build({ splitting: true })` turns into
|
|
30
|
-
* one lazy-loaded chunk per page. Called by the `
|
|
31
|
-
* and by `InertiaProvider` at boot in production.
|
|
46
|
+
* one lazy-loaded chunk per page. Called by the `route:types` / `inertia:build` /
|
|
47
|
+
* `make:page` commands and by `InertiaProvider` at boot in production.
|
|
32
48
|
*
|
|
33
49
|
* @param cwd - Project root to scan and write relative to. Defaults to `process.cwd()`.
|
|
34
50
|
* @param pagesDir - Pages directory relative to `cwd`. Defaults to the `inertia.pagesDir` config (`resources/js/pages`).
|
|
35
|
-
* @
|
|
51
|
+
* @param options - `check: true` compares against disk and reports without writing.
|
|
52
|
+
* @returns What was generated, and whether it differed from the file on disk.
|
|
36
53
|
* @internal Framework scaffolding; not called from application code.
|
|
37
54
|
*/
|
|
38
55
|
export async function generatePageRegistry(
|
|
39
56
|
cwd = process.cwd(),
|
|
40
57
|
pagesDir: string = config.safe("inertia.pagesDir", DEFAULT_PAGES_DIR),
|
|
41
|
-
|
|
58
|
+
options: { check?: boolean } = {},
|
|
59
|
+
): Promise<PageRegistryResult> {
|
|
42
60
|
// Normalise to a cwd-relative POSIX path without a trailing slash.
|
|
43
61
|
const dir = pagesDir.replace(/\\/g, "/").replace(/\/+$/, "");
|
|
44
62
|
|
|
@@ -79,7 +97,7 @@ export async function generatePageRegistry(
|
|
|
79
97
|
|
|
80
98
|
const content = [
|
|
81
99
|
"// Auto-generated by @zerotal/inertia — do not edit manually.",
|
|
82
|
-
"// Regenerate with: bun zt inertia:build",
|
|
100
|
+
"// Regenerate with: bun zt route:types (or bun zt inertia:build, which also bundles)",
|
|
83
101
|
"//",
|
|
84
102
|
"// IMPORTANT: These are dynamic import THUNKS, not static imports.",
|
|
85
103
|
"// Bun.build with splitting:true creates one .js chunk per page.",
|
|
@@ -107,9 +125,29 @@ export async function generatePageRegistry(
|
|
|
107
125
|
"",
|
|
108
126
|
].join("\n");
|
|
109
127
|
|
|
110
|
-
|
|
128
|
+
// Compare before writing. The file is regenerated on every dev rebuild and at
|
|
129
|
+
// boot in production, and rewriting identical bytes churns the mtime — which
|
|
130
|
+
// is what a file watcher keys on, so the write would retrigger the rebuild
|
|
131
|
+
// that produced it. It also gives `route:types --check` something to gate on.
|
|
132
|
+
const target = `${cwd}/${GENERATED_FILE}`;
|
|
133
|
+
const existing = await Bun.file(target)
|
|
134
|
+
.text()
|
|
135
|
+
.catch(() => null);
|
|
136
|
+
const changed = existing !== content;
|
|
137
|
+
|
|
138
|
+
if (changed && options.check !== true) {
|
|
139
|
+
await Bun.write(target, content);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
if (changed) {
|
|
143
|
+
frameworkLog("inertia").info(`Generated page registry: ${thunks.length} pages`, {
|
|
144
|
+
pages: thunks.length,
|
|
145
|
+
});
|
|
146
|
+
}
|
|
111
147
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
148
|
+
return {
|
|
149
|
+
file: GENERATED_FILE,
|
|
150
|
+
summary: `${thunks.length} page${thunks.length === 1 ? "" : "s"}`,
|
|
151
|
+
changed,
|
|
152
|
+
};
|
|
115
153
|
}
|
package/src/index.ts
CHANGED
|
@@ -64,6 +64,7 @@ export { PrecognitionMiddleware } from "./middleware/PrecognitionMiddleware.ts";
|
|
|
64
64
|
export { sharedProps } from "./SharedProps.ts";
|
|
65
65
|
export { assetVersion, setAssetVersion } from "./version.ts";
|
|
66
66
|
export { generatePageRegistry } from "./PageRegistry.ts";
|
|
67
|
+
export type { PageRegistryResult } from "./PageRegistry.ts";
|
|
67
68
|
// The typed page registry: `InertiaPageRegistry` is what `pages.generated.ts`
|
|
68
69
|
// augments, `SharedProps` is what the app declares for `Inertia.share()`.
|
|
69
70
|
export type {
|
package/src/pages.ts
CHANGED
|
@@ -88,12 +88,31 @@ type AllSharedProps = SharedProps & BuiltInSharedProps;
|
|
|
88
88
|
/** The generated `pages` map, or an empty map before the registry exists. */
|
|
89
89
|
type PageModules = InertiaPageRegistry extends { pages: infer Map } ? Map : Record<never, never>;
|
|
90
90
|
|
|
91
|
-
/**
|
|
91
|
+
/**
|
|
92
|
+
* Every page name in the generated registry. `never` until it is generated.
|
|
93
|
+
*
|
|
94
|
+
* **If a name you can see on disk is rejected here, the registry is stale, not
|
|
95
|
+
* the name** — `resources/js/pages.generated.ts` is written by a scan of the
|
|
96
|
+
* pages directory and does not know about a file added since. Regenerate it:
|
|
97
|
+
*
|
|
98
|
+
* ```sh
|
|
99
|
+
* bun zt route:types
|
|
100
|
+
* ```
|
|
101
|
+
*
|
|
102
|
+
* TypeScript reports the mismatch as TS2345 ("not assignable to parameter of
|
|
103
|
+
* type 'PageName'"), which reads like a typo, so this note is here to be the
|
|
104
|
+
* first thing the hover shows.
|
|
105
|
+
*/
|
|
92
106
|
export type PageName = Extract<keyof PageModules, string>;
|
|
93
107
|
|
|
94
108
|
/**
|
|
95
109
|
* What the Inertia helpers accept as a component name: the generated page names
|
|
96
110
|
* once the registry exists, any string before that.
|
|
111
|
+
*
|
|
112
|
+
* The `never` fallback is a bootstrap — a new app type-checks before its first
|
|
113
|
+
* build — but it does mean page names are unchecked until the registry exists
|
|
114
|
+
* once, so the first error of this kind arrives after a build that succeeded.
|
|
115
|
+
* See {@link PageName} if a name you can see on disk is being rejected.
|
|
97
116
|
*/
|
|
98
117
|
export type PageTarget = [PageName] extends [never] ? string : PageName;
|
|
99
118
|
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { ServiceProvider, Router, ConfigError, ThrottleMiddleware } from "@zerotal/core";
|
|
2
|
+
import { registerTypeGenerator } from "@zerotal/core/commands";
|
|
2
3
|
import {
|
|
3
4
|
registerDevBuildHook,
|
|
4
5
|
pruneBuildOutput,
|
|
@@ -132,6 +133,14 @@ export class InertiaProvider extends ServiceProvider {
|
|
|
132
133
|
// trigger a full pages-manifest sync + asset rebuild without @zerotal/core
|
|
133
134
|
// importing @zerotal/inertia (which would create a circular dependency).
|
|
134
135
|
const cwd = process.cwd();
|
|
136
|
+
|
|
137
|
+
// Same inversion, for `bun zt route:types`. The page registry and the route
|
|
138
|
+
// map are both "types generated from the file tree" and go stale on the same
|
|
139
|
+
// edits, but only the routes half was wired to the command named for it —
|
|
140
|
+
// so adding a page, running `route:types`, and getting the same `PageName`
|
|
141
|
+
// error back sent people looking at their page name instead of the registry.
|
|
142
|
+
registerTypeGenerator("inertia", (options) => generatePageRegistry(cwd, undefined, options));
|
|
143
|
+
|
|
135
144
|
registerDevBuildHook("inertia", async () => {
|
|
136
145
|
await generatePageRegistry(cwd);
|
|
137
146
|
const plugins = [...(await detectCssPlugins(cwd)), ...(await detectVuePlugin(cwd))];
|