@adonisjs/inertia 4.0.0-next.0 → 4.0.0-next.2
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 +8 -5
- package/build/bin/test.d.ts +1 -0
- package/build/chunk-4EZ2J6OA.js +7 -0
- package/build/chunk-DISC5OYC.js +46 -0
- package/build/chunk-GO6QSFRS.js +761 -0
- package/build/chunk-MLKGABMK.js +9 -0
- package/build/chunk-PDP56GPP.js +75 -0
- package/build/factories/inertia_factory.d.ts +137 -0
- package/build/factories/main.d.ts +1 -0
- package/build/factories/main.js +175 -0
- package/build/index.d.ts +7 -19
- package/build/index.js +21 -307
- package/build/providers/inertia_provider.d.ts +86 -13
- package/build/providers/inertia_provider.js +48 -18
- package/build/src/client/helpers.d.ts +25 -0
- package/build/src/{helpers.js → client/helpers.js} +3 -1
- package/build/src/client/vite.d.ts +63 -0
- package/build/src/{plugins → client}/vite.js +6 -2
- package/build/src/debug.d.ts +22 -0
- package/build/src/define_config.d.ts +29 -0
- package/build/src/headers.d.ts +61 -0
- package/build/src/index_pages.d.ts +5 -0
- package/build/src/inertia.d.ts +253 -0
- package/build/src/inertia_manager.d.ts +46 -0
- package/build/src/inertia_middleware.d.ts +74 -87
- package/build/src/inertia_middleware.js +110 -3
- package/build/src/plugins/edge/plugin.d.ts +30 -6
- package/build/src/plugins/edge/plugin.js +13 -9
- package/build/src/plugins/edge/tags.d.ts +47 -0
- package/build/src/plugins/edge/utils.d.ts +26 -0
- package/build/src/plugins/japa/api_client.d.ts +136 -22
- package/build/src/plugins/japa/api_client.js +36 -48
- package/build/src/props.d.ts +269 -0
- package/build/src/server_renderer.d.ts +54 -0
- package/build/src/symbols.d.ts +25 -0
- package/build/src/types.d.ts +404 -4
- package/build/tests/helpers.d.ts +35 -0
- package/build/tests/index_pages.spec.d.ts +1 -0
- package/build/tests/inertia.spec.d.ts +1 -0
- package/build/tests/inertia_page.spec.d.ts +1 -0
- package/build/tests/middleware.spec.d.ts +1 -0
- package/build/tests/plugins/api_client.spec.d.ts +1 -0
- package/build/tests/plugins/edge.plugin.spec.d.ts +1 -0
- package/build/tests/provider.spec.d.ts +1 -0
- package/build/tests/types/shared_props.spec.d.ts +1 -0
- package/build/tests/types/to_component_props.spec.d.ts +1 -0
- package/build/tests/types/to_page_props.spec.d.ts +1 -0
- package/package.json +77 -67
- package/build/app.css.stub +0 -13
- package/build/chunk-AWCR2NAY.js +0 -412
- package/build/config.stub +0 -33
- package/build/react/app.tsx.stub +0 -38
- package/build/react/errors/not_found.tsx.stub +0 -14
- package/build/react/errors/server_error.tsx.stub +0 -14
- package/build/react/home.tsx.stub +0 -349
- package/build/react/root.edge.stub +0 -76
- package/build/react/ssr.tsx.stub +0 -17
- package/build/react/tsconfig.json.stub +0 -15
- package/build/solid/app.tsx.stub +0 -38
- package/build/solid/errors/not_found.tsx.stub +0 -14
- package/build/solid/errors/server_error.tsx.stub +0 -14
- package/build/solid/home.tsx.stub +0 -358
- package/build/solid/root.edge.stub +0 -73
- package/build/solid/ssr.tsx.stub +0 -19
- package/build/solid/tsconfig.json.stub +0 -16
- package/build/src/helpers.d.ts +0 -12
- package/build/src/plugins/vite.d.ts +0 -26
- package/build/svelte/app.ts.stub +0 -32
- package/build/svelte/errors/not_found.svelte.stub +0 -10
- package/build/svelte/errors/server_error.svelte.stub +0 -14
- package/build/svelte/home.svelte.stub +0 -339
- package/build/svelte/root.edge.stub +0 -75
- package/build/svelte/ssr.ts.stub +0 -19
- package/build/svelte/tsconfig.json.stub +0 -14
- package/build/types-DVqEHBD1.d.ts +0 -240
- package/build/vue/app.ts.stub +0 -41
- package/build/vue/errors/not_found.vue.stub +0 -10
- package/build/vue/errors/server_error.vue.stub +0 -14
- package/build/vue/home.vue.stub +0 -343
- package/build/vue/root.edge.stub +0 -75
- package/build/vue/ssr.ts.stub +0 -22
- package/build/vue/tsconfig.json.stub +0 -16
|
@@ -0,0 +1,761 @@
|
|
|
1
|
+
import {
|
|
2
|
+
debug_default
|
|
3
|
+
} from "./chunk-4EZ2J6OA.js";
|
|
4
|
+
import {
|
|
5
|
+
InertiaHeaders
|
|
6
|
+
} from "./chunk-DISC5OYC.js";
|
|
7
|
+
import {
|
|
8
|
+
__export
|
|
9
|
+
} from "./chunk-MLKGABMK.js";
|
|
10
|
+
|
|
11
|
+
// src/symbols.ts
|
|
12
|
+
var symbols_exports = {};
|
|
13
|
+
__export(symbols_exports, {
|
|
14
|
+
ALWAYS_PROP: () => ALWAYS_PROP,
|
|
15
|
+
DEEP_MERGE: () => DEEP_MERGE,
|
|
16
|
+
DEFERRED_PROP: () => DEFERRED_PROP,
|
|
17
|
+
OPTIONAL_PROP: () => OPTIONAL_PROP,
|
|
18
|
+
TO_BE_MERGED: () => TO_BE_MERGED
|
|
19
|
+
});
|
|
20
|
+
var ALWAYS_PROP = Symbol.for("ALWAYS_PROP");
|
|
21
|
+
var OPTIONAL_PROP = Symbol.for("OPTIONAL_PROP");
|
|
22
|
+
var TO_BE_MERGED = Symbol.for("TO_BE_MERGED");
|
|
23
|
+
var DEFERRED_PROP = Symbol.for("DEFERRED_PROP");
|
|
24
|
+
var DEEP_MERGE = Symbol.for("DEEP_MERGE");
|
|
25
|
+
|
|
26
|
+
// src/inertia.ts
|
|
27
|
+
import { createHash } from "crypto";
|
|
28
|
+
|
|
29
|
+
// src/props.ts
|
|
30
|
+
import { serialize } from "@adonisjs/core/transformers";
|
|
31
|
+
function isObject(value) {
|
|
32
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
33
|
+
}
|
|
34
|
+
function defer(fn, group = "default") {
|
|
35
|
+
return {
|
|
36
|
+
group,
|
|
37
|
+
compute: fn,
|
|
38
|
+
merge() {
|
|
39
|
+
return merge(this);
|
|
40
|
+
},
|
|
41
|
+
[DEFERRED_PROP]: true
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
function optional(fn) {
|
|
45
|
+
return {
|
|
46
|
+
compute: fn,
|
|
47
|
+
[OPTIONAL_PROP]: true
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
function always(value) {
|
|
51
|
+
return {
|
|
52
|
+
value,
|
|
53
|
+
[ALWAYS_PROP]: true
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
function merge(value) {
|
|
57
|
+
return {
|
|
58
|
+
value,
|
|
59
|
+
[TO_BE_MERGED]: true,
|
|
60
|
+
[DEEP_MERGE]: false
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
function deepMerge(value) {
|
|
64
|
+
return {
|
|
65
|
+
value,
|
|
66
|
+
[TO_BE_MERGED]: true,
|
|
67
|
+
[DEEP_MERGE]: true
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
function isDeferredProp(propValue) {
|
|
71
|
+
return DEFERRED_PROP in propValue;
|
|
72
|
+
}
|
|
73
|
+
function isMergeableProp(propValue) {
|
|
74
|
+
return TO_BE_MERGED in propValue;
|
|
75
|
+
}
|
|
76
|
+
function isAlwaysProp(propValue) {
|
|
77
|
+
return ALWAYS_PROP in propValue;
|
|
78
|
+
}
|
|
79
|
+
function isOptionalProp(propValue) {
|
|
80
|
+
return OPTIONAL_PROP in propValue;
|
|
81
|
+
}
|
|
82
|
+
async function unpackPropValue(value) {
|
|
83
|
+
return serialize(value);
|
|
84
|
+
}
|
|
85
|
+
async function buildStandardVisitProps(pageProps) {
|
|
86
|
+
const mergeProps = [];
|
|
87
|
+
const deepMergeProps = [];
|
|
88
|
+
const newProps = {};
|
|
89
|
+
const deferredProps = {};
|
|
90
|
+
const unpackedValues = [];
|
|
91
|
+
for (const [key, value] of Object.entries(pageProps)) {
|
|
92
|
+
if (isObject(value)) {
|
|
93
|
+
if (isDeferredProp(value)) {
|
|
94
|
+
deferredProps[value.group] = deferredProps[value.group] ?? [];
|
|
95
|
+
deferredProps[value.group].push(key);
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
98
|
+
if (isOptionalProp(value)) {
|
|
99
|
+
continue;
|
|
100
|
+
}
|
|
101
|
+
if (isAlwaysProp(value)) {
|
|
102
|
+
unpackedValues.push({ key, value: value.value });
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
105
|
+
if (isMergeableProp(value)) {
|
|
106
|
+
if (value[DEEP_MERGE]) {
|
|
107
|
+
deepMergeProps.push(key);
|
|
108
|
+
} else {
|
|
109
|
+
mergeProps.push(key);
|
|
110
|
+
}
|
|
111
|
+
if (isObject(value.value) && isDeferredProp(value.value)) {
|
|
112
|
+
deferredProps[value.value.group] = deferredProps[value.value.group] ?? [];
|
|
113
|
+
deferredProps[value.value.group].push(key);
|
|
114
|
+
unpackedValues.push({
|
|
115
|
+
key,
|
|
116
|
+
value: value.value.compute
|
|
117
|
+
});
|
|
118
|
+
} else {
|
|
119
|
+
unpackedValues.push({
|
|
120
|
+
key,
|
|
121
|
+
value: value.value
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
continue;
|
|
125
|
+
}
|
|
126
|
+
unpackedValues.push({
|
|
127
|
+
key,
|
|
128
|
+
value
|
|
129
|
+
});
|
|
130
|
+
} else {
|
|
131
|
+
if (typeof value === "function") {
|
|
132
|
+
unpackedValues.push({
|
|
133
|
+
key,
|
|
134
|
+
value
|
|
135
|
+
});
|
|
136
|
+
continue;
|
|
137
|
+
}
|
|
138
|
+
newProps[key] = value;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
await Promise.all(
|
|
142
|
+
unpackedValues.map(async ({ key, value }) => {
|
|
143
|
+
if (typeof value === "function") {
|
|
144
|
+
return Promise.resolve(value()).then((r) => unpackPropValue(r)).then((jsonValue) => {
|
|
145
|
+
newProps[key] = jsonValue;
|
|
146
|
+
});
|
|
147
|
+
} else {
|
|
148
|
+
return unpackPropValue(value).then((jsonValue) => {
|
|
149
|
+
newProps[key] = jsonValue;
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
})
|
|
153
|
+
);
|
|
154
|
+
return {
|
|
155
|
+
props: newProps,
|
|
156
|
+
mergeProps,
|
|
157
|
+
deepMergeProps,
|
|
158
|
+
deferredProps
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
async function buildPartialRequestProps(pageProps, cherryPickProps) {
|
|
162
|
+
const mergeProps = [];
|
|
163
|
+
const deepMergeProps = [];
|
|
164
|
+
const newProps = {};
|
|
165
|
+
const unpackedValues = [];
|
|
166
|
+
for (const [key, value] of Object.entries(pageProps)) {
|
|
167
|
+
if (isObject(value)) {
|
|
168
|
+
if (isAlwaysProp(value)) {
|
|
169
|
+
unpackedValues.push({ key, value: value.value });
|
|
170
|
+
continue;
|
|
171
|
+
}
|
|
172
|
+
if (!cherryPickProps.includes(key)) {
|
|
173
|
+
continue;
|
|
174
|
+
}
|
|
175
|
+
if (isDeferredProp(value)) {
|
|
176
|
+
unpackedValues.push({ key, value: value.compute });
|
|
177
|
+
continue;
|
|
178
|
+
}
|
|
179
|
+
if (isOptionalProp(value)) {
|
|
180
|
+
unpackedValues.push({ key, value: value.compute });
|
|
181
|
+
continue;
|
|
182
|
+
}
|
|
183
|
+
if (isMergeableProp(value)) {
|
|
184
|
+
if (value[DEEP_MERGE]) {
|
|
185
|
+
deepMergeProps.push(key);
|
|
186
|
+
} else {
|
|
187
|
+
mergeProps.push(key);
|
|
188
|
+
}
|
|
189
|
+
if (isObject(value.value) && isDeferredProp(value.value)) {
|
|
190
|
+
unpackedValues.push({ key, value: value.value.compute });
|
|
191
|
+
} else {
|
|
192
|
+
unpackedValues.push({ key, value: value.value });
|
|
193
|
+
}
|
|
194
|
+
continue;
|
|
195
|
+
}
|
|
196
|
+
unpackedValues.push({ key, value });
|
|
197
|
+
} else {
|
|
198
|
+
if (!cherryPickProps.includes(key)) {
|
|
199
|
+
continue;
|
|
200
|
+
}
|
|
201
|
+
if (typeof value === "function") {
|
|
202
|
+
unpackedValues.push({ key, value });
|
|
203
|
+
continue;
|
|
204
|
+
}
|
|
205
|
+
newProps[key] = value;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
await Promise.all(
|
|
209
|
+
unpackedValues.map(async ({ key, value }) => {
|
|
210
|
+
if (typeof value === "function") {
|
|
211
|
+
return Promise.resolve(value()).then((r) => unpackPropValue(r)).then((jsonValue) => {
|
|
212
|
+
newProps[key] = jsonValue;
|
|
213
|
+
});
|
|
214
|
+
} else {
|
|
215
|
+
return unpackPropValue(value).then((jsonValue) => {
|
|
216
|
+
newProps[key] = jsonValue;
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
})
|
|
220
|
+
);
|
|
221
|
+
return {
|
|
222
|
+
props: newProps,
|
|
223
|
+
mergeProps,
|
|
224
|
+
deepMergeProps,
|
|
225
|
+
deferredProps: {}
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
// src/inertia.ts
|
|
230
|
+
var Inertia = class {
|
|
231
|
+
/**
|
|
232
|
+
* Creates a new Inertia instance
|
|
233
|
+
*
|
|
234
|
+
* @param ctx - HTTP context for the current request
|
|
235
|
+
* @param config - Inertia configuration object
|
|
236
|
+
* @param vite - Vite instance for asset management
|
|
237
|
+
* @param serverRenderer - Optional server renderer for SSR
|
|
238
|
+
*
|
|
239
|
+
* @example
|
|
240
|
+
* ```js
|
|
241
|
+
* const inertia = new Inertia(ctx, {
|
|
242
|
+
* rootView: 'app',
|
|
243
|
+
* ssr: { enabled: true }
|
|
244
|
+
* }, vite, serverRenderer)
|
|
245
|
+
* ```
|
|
246
|
+
*/
|
|
247
|
+
constructor(ctx, config, vite, serverRenderer) {
|
|
248
|
+
this.ctx = ctx;
|
|
249
|
+
this.config = config;
|
|
250
|
+
if (debug_default.enabled) {
|
|
251
|
+
debug_default(
|
|
252
|
+
'instantiating inertia instance for request "%s" using config %O',
|
|
253
|
+
ctx.request.url(),
|
|
254
|
+
this.config
|
|
255
|
+
);
|
|
256
|
+
}
|
|
257
|
+
this.#shouldClearHistory = false;
|
|
258
|
+
this.#vite = vite;
|
|
259
|
+
this.#serverRenderer = serverRenderer;
|
|
260
|
+
this.#shouldEncryptHistory = config.encryptHistory ?? false;
|
|
261
|
+
this.#cachedVersion = this.config.assetsVersion ? String(this.config.assetsVersion) : void 0;
|
|
262
|
+
}
|
|
263
|
+
#sharedState;
|
|
264
|
+
#cachedRequestInfo;
|
|
265
|
+
/**
|
|
266
|
+
* Optional server-side renderer for SSR functionality
|
|
267
|
+
*/
|
|
268
|
+
#serverRenderer;
|
|
269
|
+
/**
|
|
270
|
+
* Vite instance for asset management and manifest handling
|
|
271
|
+
*/
|
|
272
|
+
#vite;
|
|
273
|
+
/**
|
|
274
|
+
* Flag to control whether the next navigation should clear browser history
|
|
275
|
+
*/
|
|
276
|
+
#shouldClearHistory;
|
|
277
|
+
/**
|
|
278
|
+
* Flag to control whether browser history should be encrypted
|
|
279
|
+
*/
|
|
280
|
+
#shouldEncryptHistory;
|
|
281
|
+
/**
|
|
282
|
+
* Cached version string/number for asset versioning
|
|
283
|
+
*/
|
|
284
|
+
#cachedVersion;
|
|
285
|
+
/**
|
|
286
|
+
* Defer prop evaluation until client-side rendering
|
|
287
|
+
*
|
|
288
|
+
* @example
|
|
289
|
+
* ```js
|
|
290
|
+
* {
|
|
291
|
+
* expensiveData: inertia.defer(() => computeExpensiveData())
|
|
292
|
+
* }
|
|
293
|
+
* ```
|
|
294
|
+
*/
|
|
295
|
+
defer = defer;
|
|
296
|
+
/**
|
|
297
|
+
* Always include prop in both server and client renders
|
|
298
|
+
*
|
|
299
|
+
* @example
|
|
300
|
+
* ```js
|
|
301
|
+
* {
|
|
302
|
+
* currentUser: inertia.always(() => getCurrentUser())
|
|
303
|
+
* }
|
|
304
|
+
* ```
|
|
305
|
+
*/
|
|
306
|
+
always = always;
|
|
307
|
+
/**
|
|
308
|
+
* Merge prop with existing client-side data
|
|
309
|
+
*
|
|
310
|
+
* @example
|
|
311
|
+
* ```js
|
|
312
|
+
* {
|
|
313
|
+
* posts: inertia.merge(() => getPosts())
|
|
314
|
+
* }
|
|
315
|
+
* ```
|
|
316
|
+
*/
|
|
317
|
+
merge = merge;
|
|
318
|
+
/**
|
|
319
|
+
* Include prop only when specifically requested
|
|
320
|
+
*
|
|
321
|
+
* @example
|
|
322
|
+
* ```js
|
|
323
|
+
* {
|
|
324
|
+
* optionalData: inertia.optional(() => getOptionalData())
|
|
325
|
+
* }
|
|
326
|
+
* ```
|
|
327
|
+
*/
|
|
328
|
+
optional = optional;
|
|
329
|
+
/**
|
|
330
|
+
* Deep merge prop with existing client-side data
|
|
331
|
+
*
|
|
332
|
+
* @example
|
|
333
|
+
* ```js
|
|
334
|
+
* {
|
|
335
|
+
* settings: inertia.deepMerge(() => getSettings())
|
|
336
|
+
* }
|
|
337
|
+
* ```
|
|
338
|
+
*/
|
|
339
|
+
deepMerge = deepMerge;
|
|
340
|
+
/**
|
|
341
|
+
* Resolve the root view template
|
|
342
|
+
*
|
|
343
|
+
* Handles both static strings and dynamic functions for the root view.
|
|
344
|
+
*/
|
|
345
|
+
#resolveRootView() {
|
|
346
|
+
return typeof this.config.rootView === "function" ? this.config.rootView(this.ctx) : this.config.rootView;
|
|
347
|
+
}
|
|
348
|
+
/**
|
|
349
|
+
* Constructs and serializes the page props for a given component
|
|
350
|
+
*
|
|
351
|
+
* Handles both full page loads and partial requests with prop filtering.
|
|
352
|
+
*
|
|
353
|
+
* @param component - The component name being rendered
|
|
354
|
+
* @param requestInfo - Information about the current request
|
|
355
|
+
* @param pageProps - Raw page props to be processed
|
|
356
|
+
*/
|
|
357
|
+
#buildPageProps(component, requestInfo, pageProps) {
|
|
358
|
+
const finalProps = { ...this.#sharedState, ...pageProps };
|
|
359
|
+
if (requestInfo.partialComponent === component) {
|
|
360
|
+
const only = requestInfo.onlyProps;
|
|
361
|
+
const except = requestInfo.exceptProps ?? [];
|
|
362
|
+
const cherryPickProps = Object.keys(finalProps).filter((propName) => {
|
|
363
|
+
if (only) {
|
|
364
|
+
return only.includes(propName) && !except.includes(propName);
|
|
365
|
+
}
|
|
366
|
+
return !except.includes(propName);
|
|
367
|
+
});
|
|
368
|
+
debug_default("building props for a partial reload %O", requestInfo);
|
|
369
|
+
debug_default("cherry picking props %s", cherryPickProps);
|
|
370
|
+
return buildPartialRequestProps(finalProps, cherryPickProps);
|
|
371
|
+
}
|
|
372
|
+
debug_default("building props for a standard visit %O", requestInfo);
|
|
373
|
+
return buildStandardVisitProps(finalProps);
|
|
374
|
+
}
|
|
375
|
+
/**
|
|
376
|
+
* Handle Inertia request by setting headers and returning page object
|
|
377
|
+
*
|
|
378
|
+
* @param pageObject - The page object to return
|
|
379
|
+
*/
|
|
380
|
+
#handleInertiaRequest(pageObject) {
|
|
381
|
+
this.ctx.response.header(InertiaHeaders.Inertia, "true");
|
|
382
|
+
return pageObject;
|
|
383
|
+
}
|
|
384
|
+
/**
|
|
385
|
+
* Render page with server-side rendering
|
|
386
|
+
*
|
|
387
|
+
* @param pageObject - The page object to render
|
|
388
|
+
* @param viewProps - Additional props to pass to the root view template
|
|
389
|
+
*/
|
|
390
|
+
async #renderWithSSR(pageObject, viewProps) {
|
|
391
|
+
if (!this.#serverRenderer) {
|
|
392
|
+
throw new Error("Cannot server render pages without a server renderer");
|
|
393
|
+
}
|
|
394
|
+
debug_default("server-side rendering %O", pageObject);
|
|
395
|
+
const { head, body } = await this.#serverRenderer.render(pageObject);
|
|
396
|
+
return this.ctx.view.render(this.#resolveRootView(), {
|
|
397
|
+
page: { ssrHead: head, ssrBody: body, ...pageObject },
|
|
398
|
+
...viewProps
|
|
399
|
+
});
|
|
400
|
+
}
|
|
401
|
+
/**
|
|
402
|
+
* Render page with client-side rendering only
|
|
403
|
+
*
|
|
404
|
+
* @param pageObject - The page object to render
|
|
405
|
+
* @param viewProps - Additional props to pass to the root view template
|
|
406
|
+
*/
|
|
407
|
+
async #renderClientSide(pageObject, viewProps) {
|
|
408
|
+
debug_default("rendering shell for SPA %O", pageObject);
|
|
409
|
+
return this.ctx.view.render(this.#resolveRootView(), { page: pageObject, ...viewProps });
|
|
410
|
+
}
|
|
411
|
+
/**
|
|
412
|
+
* Extract Inertia-specific information from request headers
|
|
413
|
+
*
|
|
414
|
+
* Parses various Inertia headers to determine request type and props filtering.
|
|
415
|
+
*
|
|
416
|
+
* @example
|
|
417
|
+
* ```js
|
|
418
|
+
* const info = inertia.requestInfo()
|
|
419
|
+
* if (info.isInertiaRequest) {
|
|
420
|
+
* // Handle as Inertia request
|
|
421
|
+
* }
|
|
422
|
+
* ```
|
|
423
|
+
*/
|
|
424
|
+
requestInfo(reCompute) {
|
|
425
|
+
if (reCompute) {
|
|
426
|
+
this.#cachedRequestInfo = void 0;
|
|
427
|
+
}
|
|
428
|
+
this.#cachedRequestInfo = this.#cachedRequestInfo ?? {
|
|
429
|
+
version: this.ctx.request.header(InertiaHeaders.Version),
|
|
430
|
+
isInertiaRequest: !!this.ctx.request.header(InertiaHeaders.Inertia),
|
|
431
|
+
isPartialRequest: !!this.ctx.request.header(InertiaHeaders.PartialComponent),
|
|
432
|
+
partialComponent: this.ctx.request.header(InertiaHeaders.PartialComponent),
|
|
433
|
+
onlyProps: this.ctx.request.header(InertiaHeaders.PartialOnly)?.split(","),
|
|
434
|
+
exceptProps: this.ctx.request.header(InertiaHeaders.PartialExcept)?.split(","),
|
|
435
|
+
resetProps: this.ctx.request.header(InertiaHeaders.Reset)?.split(","),
|
|
436
|
+
errorBag: this.ctx.request.header(InertiaHeaders.ErrorBag)
|
|
437
|
+
};
|
|
438
|
+
return this.#cachedRequestInfo;
|
|
439
|
+
}
|
|
440
|
+
/**
|
|
441
|
+
* Compute and cache the assets version
|
|
442
|
+
*
|
|
443
|
+
* Uses Vite manifest hash when available, otherwise defaults to '1'.
|
|
444
|
+
*/
|
|
445
|
+
getVersion() {
|
|
446
|
+
if (this.#cachedVersion) {
|
|
447
|
+
return this.#cachedVersion;
|
|
448
|
+
}
|
|
449
|
+
if (this.#vite?.hasManifestFile) {
|
|
450
|
+
this.#cachedVersion = createHash("md5").update(JSON.stringify(this.#vite.manifest)).digest("hex");
|
|
451
|
+
} else {
|
|
452
|
+
this.#cachedVersion = "1";
|
|
453
|
+
}
|
|
454
|
+
return this.#cachedVersion;
|
|
455
|
+
}
|
|
456
|
+
/**
|
|
457
|
+
* Determine if server-side rendering is enabled for a specific component
|
|
458
|
+
*
|
|
459
|
+
* Checks global SSR settings and component-specific configuration.
|
|
460
|
+
*
|
|
461
|
+
* @param component - The component name to check
|
|
462
|
+
*
|
|
463
|
+
* @example
|
|
464
|
+
* ```js
|
|
465
|
+
* const shouldSSR = await inertia.ssrEnabled('UserProfile')
|
|
466
|
+
* if (shouldSSR) {
|
|
467
|
+
* // Render on server
|
|
468
|
+
* }
|
|
469
|
+
* ```
|
|
470
|
+
*/
|
|
471
|
+
async ssrEnabled(component) {
|
|
472
|
+
if (!this.config.ssr.enabled) {
|
|
473
|
+
return false;
|
|
474
|
+
}
|
|
475
|
+
if (typeof this.config.ssr.pages === "function") {
|
|
476
|
+
return this.config.ssr.pages(this.ctx, component);
|
|
477
|
+
}
|
|
478
|
+
if (this.config.ssr.pages) {
|
|
479
|
+
return this.config.ssr.pages?.includes(component);
|
|
480
|
+
}
|
|
481
|
+
return true;
|
|
482
|
+
}
|
|
483
|
+
/**
|
|
484
|
+
* Share props across all pages
|
|
485
|
+
*
|
|
486
|
+
* Merges the provided props with existing shared state, making them available
|
|
487
|
+
* to all pages rendered by this Inertia instance. Shared props are included
|
|
488
|
+
* in every page render alongside page-specific props.
|
|
489
|
+
*
|
|
490
|
+
* @param sharedState - Props to share across all pages
|
|
491
|
+
*
|
|
492
|
+
* @example
|
|
493
|
+
* ```js
|
|
494
|
+
* // Share user data across all pages
|
|
495
|
+
* inertia.share({
|
|
496
|
+
* user: getCurrentUser(),
|
|
497
|
+
* flash: getFlashMessages()
|
|
498
|
+
* })
|
|
499
|
+
*
|
|
500
|
+
* // Chain multiple shares
|
|
501
|
+
* inertia
|
|
502
|
+
* .share({ currentUser: user })
|
|
503
|
+
* .share({ permissions: userPermissions })
|
|
504
|
+
* ```
|
|
505
|
+
*/
|
|
506
|
+
share(sharedState) {
|
|
507
|
+
this.#sharedState = { ...this.#sharedState, ...sharedState };
|
|
508
|
+
return this;
|
|
509
|
+
}
|
|
510
|
+
/**
|
|
511
|
+
* Build a page object with processed props and metadata
|
|
512
|
+
*
|
|
513
|
+
* Creates the complete page object that will be sent to the client or used for SSR.
|
|
514
|
+
*
|
|
515
|
+
* @param page - The page component name
|
|
516
|
+
* @param pageProps - Props to pass to the page component
|
|
517
|
+
*
|
|
518
|
+
* @example
|
|
519
|
+
* ```js
|
|
520
|
+
* const pageObject = await inertia.page('Dashboard', {
|
|
521
|
+
* user: { name: 'John' },
|
|
522
|
+
* posts: defer(() => getPosts())
|
|
523
|
+
* })
|
|
524
|
+
* ```
|
|
525
|
+
*/
|
|
526
|
+
async page(page, pageProps) {
|
|
527
|
+
const requestInfo = this.requestInfo();
|
|
528
|
+
const { props, mergeProps, deferredProps, deepMergeProps } = await this.#buildPageProps(
|
|
529
|
+
page,
|
|
530
|
+
requestInfo,
|
|
531
|
+
pageProps
|
|
532
|
+
);
|
|
533
|
+
return {
|
|
534
|
+
component: page,
|
|
535
|
+
url: this.ctx.request.url(true),
|
|
536
|
+
version: this.getVersion(),
|
|
537
|
+
clearHistory: this.#shouldClearHistory,
|
|
538
|
+
encryptHistory: this.#shouldEncryptHistory,
|
|
539
|
+
props,
|
|
540
|
+
deferredProps,
|
|
541
|
+
mergeProps,
|
|
542
|
+
deepMergeProps
|
|
543
|
+
};
|
|
544
|
+
}
|
|
545
|
+
/**
|
|
546
|
+
* Render a page using Inertia
|
|
547
|
+
*
|
|
548
|
+
* This method handles three distinct rendering scenarios:
|
|
549
|
+
* 1. Inertia requests - Returns JSON page object for client-side navigation
|
|
550
|
+
* 2. Initial page loads with SSR - Returns HTML with server-rendered content
|
|
551
|
+
* 3. Initial page loads without SSR - Returns HTML for client-side hydration
|
|
552
|
+
*
|
|
553
|
+
* @param page - The page component name to render
|
|
554
|
+
* @param pageProps - Props to pass to the page component
|
|
555
|
+
* @param viewProps - Additional props to pass to the root view template
|
|
556
|
+
*
|
|
557
|
+
* @returns PageObject for Inertia requests, HTML string for initial page loads
|
|
558
|
+
*
|
|
559
|
+
* @example
|
|
560
|
+
* ```js
|
|
561
|
+
* // For Inertia requests, returns PageObject
|
|
562
|
+
* const result = await inertia.render('Profile', {
|
|
563
|
+
* user: getCurrentUser(),
|
|
564
|
+
* posts: defer(() => getUserPosts())
|
|
565
|
+
* })
|
|
566
|
+
*
|
|
567
|
+
* // For initial page loads, returns HTML string
|
|
568
|
+
* const html = await inertia.render('Home', { welcome: 'Hello World' })
|
|
569
|
+
* ```
|
|
570
|
+
*/
|
|
571
|
+
async render(page, pageProps, viewProps) {
|
|
572
|
+
const requestInfo = this.requestInfo();
|
|
573
|
+
const pageObject = await this.page(page, pageProps);
|
|
574
|
+
const isInertiaRequest = requestInfo.isInertiaRequest;
|
|
575
|
+
if (isInertiaRequest) {
|
|
576
|
+
return this.#handleInertiaRequest(pageObject);
|
|
577
|
+
}
|
|
578
|
+
const shouldUseSSR = await this.ssrEnabled(page);
|
|
579
|
+
if (shouldUseSSR) {
|
|
580
|
+
return this.#renderWithSSR(pageObject, viewProps);
|
|
581
|
+
}
|
|
582
|
+
return this.#renderClientSide(pageObject, viewProps);
|
|
583
|
+
}
|
|
584
|
+
/**
|
|
585
|
+
* Clear the browser history on the next navigation
|
|
586
|
+
*
|
|
587
|
+
* Instructs the client to clear the browser history stack when navigating.
|
|
588
|
+
*
|
|
589
|
+
* @example
|
|
590
|
+
* ```js
|
|
591
|
+
* inertia.clearHistory()
|
|
592
|
+
* return inertia.render('Dashboard', props)
|
|
593
|
+
* ```
|
|
594
|
+
*/
|
|
595
|
+
clearHistory() {
|
|
596
|
+
this.#shouldClearHistory = true;
|
|
597
|
+
}
|
|
598
|
+
/**
|
|
599
|
+
* Control whether browser history should be encrypted
|
|
600
|
+
*
|
|
601
|
+
* Enables or disables encryption of sensitive data in browser history.
|
|
602
|
+
*
|
|
603
|
+
* @param encrypt - Whether to encrypt history (defaults to true)
|
|
604
|
+
*
|
|
605
|
+
* @example
|
|
606
|
+
* ```js
|
|
607
|
+
* // Enable encryption for sensitive pages
|
|
608
|
+
* inertia.encryptHistory(true)
|
|
609
|
+
*
|
|
610
|
+
* // Disable encryption for public pages
|
|
611
|
+
* inertia.encryptHistory(false)
|
|
612
|
+
* ```
|
|
613
|
+
*/
|
|
614
|
+
encryptHistory(encrypt = true) {
|
|
615
|
+
this.#shouldEncryptHistory = encrypt;
|
|
616
|
+
}
|
|
617
|
+
/**
|
|
618
|
+
* Redirect to a different location
|
|
619
|
+
*
|
|
620
|
+
* Sets the appropriate headers to redirect the client to a new URL.
|
|
621
|
+
* Uses a 409 status code which Inertia.js interprets as a redirect instruction.
|
|
622
|
+
*
|
|
623
|
+
* @param url - The URL to redirect to
|
|
624
|
+
*
|
|
625
|
+
* @example
|
|
626
|
+
* ```js
|
|
627
|
+
* // Redirect after login
|
|
628
|
+
* inertia.location('/dashboard')
|
|
629
|
+
*
|
|
630
|
+
* // Redirect with full URL
|
|
631
|
+
* inertia.location('https://example.com/external')
|
|
632
|
+
* ```
|
|
633
|
+
*/
|
|
634
|
+
location(url) {
|
|
635
|
+
this.ctx.response.header(InertiaHeaders.Location, url);
|
|
636
|
+
this.ctx.response.status(409);
|
|
637
|
+
}
|
|
638
|
+
};
|
|
639
|
+
|
|
640
|
+
// src/server_renderer.ts
|
|
641
|
+
import { pathToFileURL } from "url";
|
|
642
|
+
var ServerRenderer = class {
|
|
643
|
+
/**
|
|
644
|
+
* Shared module runner instance for Vite's runtime API.
|
|
645
|
+
* Used in development mode to execute SSR entry points.
|
|
646
|
+
*/
|
|
647
|
+
#runtime;
|
|
648
|
+
/**
|
|
649
|
+
* Inertia configuration object containing SSR settings
|
|
650
|
+
*/
|
|
651
|
+
#config;
|
|
652
|
+
/**
|
|
653
|
+
* Vite instance for development mode rendering and asset management
|
|
654
|
+
*/
|
|
655
|
+
#vite;
|
|
656
|
+
/**
|
|
657
|
+
* Creates a new ServerRenderer instance.
|
|
658
|
+
*
|
|
659
|
+
* @param config - Inertia configuration object containing SSR settings
|
|
660
|
+
* @param vite - Vite instance for development mode rendering and asset management
|
|
661
|
+
*
|
|
662
|
+
* @example
|
|
663
|
+
* ```js
|
|
664
|
+
* const renderer = new ServerRenderer(config, vite)
|
|
665
|
+
* ```
|
|
666
|
+
*/
|
|
667
|
+
constructor(config, vite) {
|
|
668
|
+
this.#config = config;
|
|
669
|
+
this.#vite = vite;
|
|
670
|
+
}
|
|
671
|
+
/**
|
|
672
|
+
* Renders an Inertia page on the server.
|
|
673
|
+
*
|
|
674
|
+
* In development mode, uses Vite's Runtime API to execute the SSR entrypoint.
|
|
675
|
+
* In production mode, imports and uses the pre-built SSR bundle.
|
|
676
|
+
*
|
|
677
|
+
* @param pageObject - The Inertia page object containing component, props, and metadata
|
|
678
|
+
* @returns Promise resolving to an object with rendered head and body HTML
|
|
679
|
+
*
|
|
680
|
+
* @example
|
|
681
|
+
* ```typescript
|
|
682
|
+
* const pageObject = {
|
|
683
|
+
* component: 'Home',
|
|
684
|
+
* props: { user: { name: 'John' } },
|
|
685
|
+
* url: '/dashboard',
|
|
686
|
+
* version: '1.0.0'
|
|
687
|
+
* }
|
|
688
|
+
*
|
|
689
|
+
* const { head, body } = await renderer.render(pageObject)
|
|
690
|
+
* ```
|
|
691
|
+
*/
|
|
692
|
+
async render(pageObject) {
|
|
693
|
+
let render;
|
|
694
|
+
const devServer = this.#vite.getDevServer();
|
|
695
|
+
if (devServer) {
|
|
696
|
+
debug_default("creating SSR bundle using dev-server");
|
|
697
|
+
this.#runtime ??= await this.#vite.createModuleRunner();
|
|
698
|
+
this.#runtime.clearCache();
|
|
699
|
+
render = await this.#runtime.import(this.#config.ssr.entrypoint);
|
|
700
|
+
} else {
|
|
701
|
+
debug_default("creating SSR bundle using production build");
|
|
702
|
+
render = await import(pathToFileURL(this.#config.ssr.bundle).href);
|
|
703
|
+
}
|
|
704
|
+
const result = await render.default(pageObject);
|
|
705
|
+
debug_default("SSR bundle %o", result);
|
|
706
|
+
return { head: result.head, body: result.body };
|
|
707
|
+
}
|
|
708
|
+
};
|
|
709
|
+
|
|
710
|
+
// src/inertia_manager.ts
|
|
711
|
+
var InertiaManager = class {
|
|
712
|
+
/**
|
|
713
|
+
* Optional Vite instance for asset management
|
|
714
|
+
*/
|
|
715
|
+
#vite;
|
|
716
|
+
/**
|
|
717
|
+
* Inertia configuration object
|
|
718
|
+
*/
|
|
719
|
+
#config;
|
|
720
|
+
#serverRenderer;
|
|
721
|
+
/**
|
|
722
|
+
* Creates a new InertiaManager instance
|
|
723
|
+
*
|
|
724
|
+
* @param config - Inertia configuration object
|
|
725
|
+
* @param vite - Optional Vite instance for development mode and SSR
|
|
726
|
+
*
|
|
727
|
+
* @example
|
|
728
|
+
* ```js
|
|
729
|
+
* const manager = new InertiaManager({
|
|
730
|
+
* rootView: 'app',
|
|
731
|
+
* ssr: { enabled: true }
|
|
732
|
+
* }, vite)
|
|
733
|
+
* ```
|
|
734
|
+
*/
|
|
735
|
+
constructor(config, vite) {
|
|
736
|
+
this.#config = config;
|
|
737
|
+
this.#vite = vite;
|
|
738
|
+
this.#serverRenderer = this.#vite ? new ServerRenderer(this.#config, this.#vite) : void 0;
|
|
739
|
+
}
|
|
740
|
+
/**
|
|
741
|
+
* Creates a new Inertia instance for a specific HTTP request
|
|
742
|
+
*
|
|
743
|
+
* @param ctx - HTTP context for the current request
|
|
744
|
+
*
|
|
745
|
+
* @example
|
|
746
|
+
* ```js
|
|
747
|
+
* const inertia = manager.createForRequest(ctx)
|
|
748
|
+
* await inertia.render('Home', { user: ctx.auth.user })
|
|
749
|
+
* ```
|
|
750
|
+
*/
|
|
751
|
+
createForRequest(ctx) {
|
|
752
|
+
return new Inertia(ctx, this.#config, this.#vite, this.#serverRenderer);
|
|
753
|
+
}
|
|
754
|
+
};
|
|
755
|
+
|
|
756
|
+
export {
|
|
757
|
+
symbols_exports,
|
|
758
|
+
Inertia,
|
|
759
|
+
ServerRenderer,
|
|
760
|
+
InertiaManager
|
|
761
|
+
};
|