@adonisjs/inertia 4.0.0-next.0 → 4.0.0-next.10

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.
Files changed (89) hide show
  1. package/README.md +8 -5
  2. package/build/bin/test.d.ts +1 -0
  3. package/build/chunk-4EZ2J6OA.js +7 -0
  4. package/build/chunk-5QRJHXXQ.js +91 -0
  5. package/build/chunk-DISC5OYC.js +46 -0
  6. package/build/chunk-MLKGABMK.js +9 -0
  7. package/build/chunk-YQ72YL64.js +813 -0
  8. package/build/factories/inertia_factory.d.ts +137 -0
  9. package/build/factories/main.d.ts +1 -0
  10. package/build/factories/main.js +175 -0
  11. package/build/index.d.ts +7 -19
  12. package/build/index.js +21 -307
  13. package/build/providers/inertia_provider.d.ts +86 -13
  14. package/build/providers/inertia_provider.js +48 -18
  15. package/build/src/client/helpers.d.ts +27 -0
  16. package/build/src/client/helpers.js +30 -0
  17. package/build/src/client/react/context.d.ts +24 -0
  18. package/build/src/client/react/index.d.ts +3 -0
  19. package/build/src/client/react/index.js +72 -0
  20. package/build/src/client/react/link.d.ts +64 -0
  21. package/build/src/client/react/router.d.ts +33 -0
  22. package/build/src/client/vite.d.ts +65 -0
  23. package/build/src/{plugins → client}/vite.js +6 -2
  24. package/build/src/debug.d.ts +22 -0
  25. package/build/src/define_config.d.ts +30 -0
  26. package/build/src/headers.d.ts +61 -0
  27. package/build/src/index_pages.d.ts +32 -0
  28. package/build/src/inertia.d.ts +261 -0
  29. package/build/src/inertia_manager.d.ts +47 -0
  30. package/build/src/inertia_middleware.d.ts +76 -86
  31. package/build/src/inertia_middleware.js +110 -3
  32. package/build/src/plugins/edge/plugin.d.ts +30 -6
  33. package/build/src/plugins/edge/plugin.js +13 -9
  34. package/build/src/plugins/edge/tags.d.ts +47 -0
  35. package/build/src/plugins/edge/utils.d.ts +26 -0
  36. package/build/src/plugins/japa/api_client.d.ts +136 -22
  37. package/build/src/plugins/japa/api_client.js +36 -48
  38. package/build/src/props.d.ts +276 -0
  39. package/build/src/server_renderer.d.ts +54 -0
  40. package/build/src/symbols.d.ts +25 -0
  41. package/build/src/types.d.ts +400 -4
  42. package/build/tests/helpers.d.ts +35 -0
  43. package/build/tests/index_pages.spec.d.ts +1 -0
  44. package/build/tests/inertia.spec.d.ts +1 -0
  45. package/build/tests/inertia_page.spec.d.ts +1 -0
  46. package/build/tests/middleware.spec.d.ts +1 -0
  47. package/build/tests/plugins/api_client.spec.d.ts +1 -0
  48. package/build/tests/plugins/edge.plugin.spec.d.ts +1 -0
  49. package/build/tests/provider.spec.d.ts +1 -0
  50. package/build/tests/types/react.spec.d.ts +65 -0
  51. package/build/tests/types/shared_props.spec.d.ts +1 -0
  52. package/build/tests/types/to_component_props.spec.d.ts +1 -0
  53. package/build/tests/types/to_page_props.spec.d.ts +1 -0
  54. package/package.json +99 -71
  55. package/build/app.css.stub +0 -13
  56. package/build/chunk-AWCR2NAY.js +0 -412
  57. package/build/config.stub +0 -33
  58. package/build/react/app.tsx.stub +0 -38
  59. package/build/react/errors/not_found.tsx.stub +0 -14
  60. package/build/react/errors/server_error.tsx.stub +0 -14
  61. package/build/react/home.tsx.stub +0 -349
  62. package/build/react/root.edge.stub +0 -76
  63. package/build/react/ssr.tsx.stub +0 -17
  64. package/build/react/tsconfig.json.stub +0 -15
  65. package/build/solid/app.tsx.stub +0 -38
  66. package/build/solid/errors/not_found.tsx.stub +0 -14
  67. package/build/solid/errors/server_error.tsx.stub +0 -14
  68. package/build/solid/home.tsx.stub +0 -358
  69. package/build/solid/root.edge.stub +0 -73
  70. package/build/solid/ssr.tsx.stub +0 -19
  71. package/build/solid/tsconfig.json.stub +0 -16
  72. package/build/src/helpers.d.ts +0 -12
  73. package/build/src/helpers.js +0 -14
  74. package/build/src/plugins/vite.d.ts +0 -26
  75. package/build/svelte/app.ts.stub +0 -32
  76. package/build/svelte/errors/not_found.svelte.stub +0 -10
  77. package/build/svelte/errors/server_error.svelte.stub +0 -14
  78. package/build/svelte/home.svelte.stub +0 -339
  79. package/build/svelte/root.edge.stub +0 -75
  80. package/build/svelte/ssr.ts.stub +0 -19
  81. package/build/svelte/tsconfig.json.stub +0 -14
  82. package/build/types-DVqEHBD1.d.ts +0 -240
  83. package/build/vue/app.ts.stub +0 -41
  84. package/build/vue/errors/not_found.vue.stub +0 -10
  85. package/build/vue/errors/server_error.vue.stub +0 -14
  86. package/build/vue/home.vue.stub +0 -343
  87. package/build/vue/root.edge.stub +0 -75
  88. package/build/vue/ssr.ts.stub +0 -22
  89. package/build/vue/tsconfig.json.stub +0 -16
@@ -0,0 +1,813 @@
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, containerResolver) {
83
+ return serialize(value, containerResolver);
84
+ }
85
+ async function buildStandardVisitProps(pageProps, containerResolver) {
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, containerResolver)).then((jsonValue) => {
145
+ newProps[key] = jsonValue;
146
+ });
147
+ } else {
148
+ return unpackPropValue(value, containerResolver).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, containerResolver) {
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, containerResolver)).then((jsonValue) => {
212
+ newProps[key] = jsonValue;
213
+ });
214
+ } else {
215
+ return unpackPropValue(value, containerResolver).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
+ #sharedStateProviders;
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
+ * @example
346
+ * ```js
347
+ * const viewName = this.#resolveRootView()
348
+ * this.ctx.view.render(viewName, { page: pageObject })
349
+ * ```
350
+ */
351
+ #resolveRootView() {
352
+ return typeof this.config.rootView === "function" ? this.config.rootView(this.ctx) : this.config.rootView;
353
+ }
354
+ /**
355
+ * Constructs and serializes the page props for a given component
356
+ *
357
+ * Handles both full page loads and partial requests with prop filtering.
358
+ * Merges shared state providers with page-specific props, and handles
359
+ * prop cherry-picking for partial reloads based on the `only` and `except` parameters.
360
+ *
361
+ * @param component - The component name being rendered
362
+ * @param requestInfo - Information about the current request
363
+ * @param pageProps - Raw page props to be processed
364
+ *
365
+ * @example
366
+ * ```js
367
+ * const result = await this.#buildPageProps('Dashboard', requestInfo, {
368
+ * user: { name: 'John' },
369
+ * posts: defer(() => getPosts())
370
+ * })
371
+ * ```
372
+ */
373
+ async #buildPageProps(component, requestInfo, pageProps) {
374
+ let finalProps;
375
+ if (this.#sharedStateProviders) {
376
+ const sharedState = await Promise.all(
377
+ this.#sharedStateProviders.map((provider) => {
378
+ return typeof provider === "function" ? provider() : provider;
379
+ })
380
+ ).then((resolvedSharedState) => {
381
+ return resolvedSharedState.reduce((result, state) => {
382
+ return { ...result, ...state };
383
+ }, {});
384
+ });
385
+ finalProps = { ...sharedState, ...pageProps };
386
+ } else {
387
+ finalProps = { ...pageProps };
388
+ }
389
+ if (requestInfo.partialComponent === component) {
390
+ const only = requestInfo.onlyProps;
391
+ const except = requestInfo.exceptProps ?? [];
392
+ const cherryPickProps = Object.keys(finalProps).filter((propName) => {
393
+ if (only) {
394
+ return only.includes(propName) && !except.includes(propName);
395
+ }
396
+ return !except.includes(propName);
397
+ });
398
+ debug_default("building props for a partial reload %O", requestInfo);
399
+ debug_default("cherry picking props %s", cherryPickProps);
400
+ return buildPartialRequestProps(finalProps, cherryPickProps, this.ctx.containerResolver);
401
+ }
402
+ debug_default("building props for a standard visit %O", requestInfo);
403
+ return buildStandardVisitProps(finalProps, this.ctx.containerResolver);
404
+ }
405
+ /**
406
+ * Handle Inertia AJAX request by setting appropriate headers
407
+ *
408
+ * Sets the `X-Inertia` header to 'true' indicating this is an Inertia response,
409
+ * then returns the page object which will be serialized as JSON.
410
+ *
411
+ * @param pageObject - The page object to return
412
+ *
413
+ * @example
414
+ * ```js
415
+ * const pageObj = await this.page('Dashboard', props)
416
+ * return this.#handleInertiaRequest(pageObj)
417
+ * ```
418
+ */
419
+ #handleInertiaRequest(pageObject) {
420
+ this.ctx.response.header(InertiaHeaders.Inertia, "true");
421
+ return pageObject;
422
+ }
423
+ /**
424
+ * Render page with server-side rendering
425
+ *
426
+ * @param pageObject - The page object to render
427
+ * @param viewProps - Additional props to pass to the root view template
428
+ * @returns Promise resolving to the rendered HTML string
429
+ */
430
+ async #renderWithSSR(pageObject, viewProps) {
431
+ if (!this.#serverRenderer) {
432
+ throw new Error("Cannot server render pages without a server renderer");
433
+ }
434
+ debug_default("server-side rendering %O", pageObject);
435
+ const { head, body } = await this.#serverRenderer.render(pageObject);
436
+ return this.ctx.view.render(this.#resolveRootView(), {
437
+ page: { ssrHead: head, ssrBody: body, ...pageObject },
438
+ ...viewProps
439
+ });
440
+ }
441
+ /**
442
+ * Render page with client-side rendering only
443
+ *
444
+ * @param pageObject - The page object to render
445
+ * @param viewProps - Additional props to pass to the root view template
446
+ * @returns Promise resolving to the rendered HTML string
447
+ */
448
+ async #renderClientSide(pageObject, viewProps) {
449
+ debug_default("rendering shell for SPA %O", pageObject);
450
+ return this.ctx.view.render(this.#resolveRootView(), { page: pageObject, ...viewProps });
451
+ }
452
+ /**
453
+ * Extract Inertia-specific information from request headers
454
+ *
455
+ * Parses various Inertia headers to determine request type and props filtering.
456
+ *
457
+ * @param reCompute - Whether to recompute the request info instead of using cached version
458
+ * @returns The request information object containing Inertia-specific data
459
+ *
460
+ * @example
461
+ * ```js
462
+ * const info = inertia.requestInfo()
463
+ * if (info.isInertiaRequest) {
464
+ * // Handle as Inertia request
465
+ * }
466
+ * ```
467
+ */
468
+ requestInfo(reCompute) {
469
+ if (reCompute) {
470
+ this.#cachedRequestInfo = void 0;
471
+ }
472
+ this.#cachedRequestInfo = this.#cachedRequestInfo ?? {
473
+ version: this.ctx.request.header(InertiaHeaders.Version),
474
+ isInertiaRequest: !!this.ctx.request.header(InertiaHeaders.Inertia),
475
+ isPartialRequest: !!this.ctx.request.header(InertiaHeaders.PartialComponent),
476
+ partialComponent: this.ctx.request.header(InertiaHeaders.PartialComponent),
477
+ onlyProps: this.ctx.request.header(InertiaHeaders.PartialOnly)?.split(","),
478
+ exceptProps: this.ctx.request.header(InertiaHeaders.PartialExcept)?.split(","),
479
+ resetProps: this.ctx.request.header(InertiaHeaders.Reset)?.split(","),
480
+ errorBag: this.ctx.request.header(InertiaHeaders.ErrorBag)
481
+ };
482
+ return this.#cachedRequestInfo;
483
+ }
484
+ /**
485
+ * Compute and cache the assets version
486
+ *
487
+ * Uses Vite manifest hash when available, otherwise defaults to '1'.
488
+ *
489
+ * @returns The computed version string for asset versioning
490
+ */
491
+ getVersion() {
492
+ if (this.#cachedVersion) {
493
+ return this.#cachedVersion;
494
+ }
495
+ if (this.#vite?.hasManifestFile) {
496
+ this.#cachedVersion = createHash("md5").update(JSON.stringify(this.#vite.manifest())).digest("hex");
497
+ } else {
498
+ this.#cachedVersion = "1";
499
+ }
500
+ return this.#cachedVersion;
501
+ }
502
+ /**
503
+ * Determine if server-side rendering is enabled for a specific component
504
+ *
505
+ * Checks global SSR settings and component-specific configuration.
506
+ *
507
+ * @param component - The component name to check
508
+ * @returns Promise resolving to true if SSR is enabled for the component
509
+ *
510
+ * @example
511
+ * ```js
512
+ * const shouldSSR = await inertia.ssrEnabled('UserProfile')
513
+ * if (shouldSSR) {
514
+ * // Render on server
515
+ * }
516
+ * ```
517
+ */
518
+ async ssrEnabled(component) {
519
+ if (!this.config.ssr.enabled) {
520
+ return false;
521
+ }
522
+ if (typeof this.config.ssr.pages === "function") {
523
+ return this.config.ssr.pages(this.ctx, component);
524
+ }
525
+ if (this.config.ssr.pages) {
526
+ return this.config.ssr.pages?.includes(component);
527
+ }
528
+ return true;
529
+ }
530
+ /**
531
+ * Share props across all pages
532
+ *
533
+ * Merges the provided props with existing shared state, making them available
534
+ * to all pages rendered by this Inertia instance. Shared props are included
535
+ * in every page render alongside page-specific props.
536
+ *
537
+ * @param sharedState - Props to share across all pages
538
+ * @returns The Inertia instance for method chaining
539
+ *
540
+ * @example
541
+ * ```js
542
+ * // Share user data across all pages
543
+ * inertia.share({
544
+ * user: getCurrentUser(),
545
+ * flash: getFlashMessages()
546
+ * })
547
+ *
548
+ * // Chain multiple shares
549
+ * inertia
550
+ * .share({ currentUser: user })
551
+ * .share({ permissions: userPermissions })
552
+ * ```
553
+ */
554
+ share(sharedState) {
555
+ if (!this.#sharedStateProviders) {
556
+ this.#sharedStateProviders = [];
557
+ }
558
+ this.#sharedStateProviders.push(sharedState);
559
+ return this;
560
+ }
561
+ /**
562
+ * Build a page object with processed props and metadata
563
+ *
564
+ * Creates the complete page object that will be sent to the client or used for SSR.
565
+ *
566
+ * @param page - The page component name
567
+ * @param pageProps - Props to pass to the page component
568
+ * @returns Promise resolving to the complete page object
569
+ *
570
+ * @example
571
+ * ```js
572
+ * const pageObject = await inertia.page('Dashboard', {
573
+ * user: { name: 'John' },
574
+ * posts: defer(() => getPosts())
575
+ * })
576
+ * ```
577
+ */
578
+ async page(page, pageProps) {
579
+ const requestInfo = this.requestInfo();
580
+ const { props, mergeProps, deferredProps, deepMergeProps } = await this.#buildPageProps(
581
+ page,
582
+ requestInfo,
583
+ pageProps
584
+ );
585
+ return {
586
+ component: page,
587
+ url: this.ctx.request.url(true),
588
+ version: this.getVersion(),
589
+ clearHistory: this.#shouldClearHistory,
590
+ encryptHistory: this.#shouldEncryptHistory,
591
+ props,
592
+ deferredProps,
593
+ mergeProps,
594
+ deepMergeProps
595
+ };
596
+ }
597
+ /**
598
+ * Render a page using Inertia
599
+ *
600
+ * This method handles three distinct rendering scenarios:
601
+ * 1. Inertia requests - Returns JSON page object for client-side navigation
602
+ * 2. Initial page loads with SSR - Returns HTML with server-rendered content
603
+ * 3. Initial page loads without SSR - Returns HTML for client-side hydration
604
+ *
605
+ * @param page - The page component name to render
606
+ * @param pageProps - Props to pass to the page component
607
+ * @param viewProps - Additional props to pass to the root view template
608
+ * @returns Promise resolving to PageObject for Inertia requests, HTML string for initial page loads
609
+ *
610
+ * @example
611
+ * ```js
612
+ * // For Inertia requests, returns PageObject
613
+ * const result = await inertia.render('Profile', {
614
+ * user: getCurrentUser(),
615
+ * posts: defer(() => getUserPosts())
616
+ * })
617
+ *
618
+ * // For initial page loads, returns HTML string
619
+ * const html = await inertia.render('Home', { welcome: 'Hello World' })
620
+ * ```
621
+ */
622
+ async render(page, pageProps, viewProps) {
623
+ const requestInfo = this.requestInfo();
624
+ const pageObject = await this.page(page, pageProps);
625
+ const isInertiaRequest = requestInfo.isInertiaRequest;
626
+ if (isInertiaRequest) {
627
+ return this.#handleInertiaRequest(pageObject);
628
+ }
629
+ const shouldUseSSR = await this.ssrEnabled(page);
630
+ if (shouldUseSSR) {
631
+ return this.#renderWithSSR(pageObject, viewProps);
632
+ }
633
+ return this.#renderClientSide(pageObject, viewProps);
634
+ }
635
+ /**
636
+ * Clear the browser history on the next navigation
637
+ *
638
+ * Instructs the client to clear the browser history stack when navigating.
639
+ *
640
+ * @example
641
+ * ```js
642
+ * inertia.clearHistory()
643
+ * return inertia.render('Dashboard', props)
644
+ * ```
645
+ */
646
+ clearHistory() {
647
+ this.#shouldClearHistory = true;
648
+ }
649
+ /**
650
+ * Control whether browser history should be encrypted
651
+ *
652
+ * Enables or disables encryption of sensitive data in browser history.
653
+ *
654
+ * @param encrypt - Whether to encrypt history (defaults to true)
655
+ *
656
+ * @example
657
+ * ```js
658
+ * // Enable encryption for sensitive pages
659
+ * inertia.encryptHistory(true)
660
+ *
661
+ * // Disable encryption for public pages
662
+ * inertia.encryptHistory(false)
663
+ * ```
664
+ */
665
+ encryptHistory(encrypt = true) {
666
+ this.#shouldEncryptHistory = encrypt;
667
+ }
668
+ /**
669
+ * Redirect to a different location
670
+ *
671
+ * Sets the appropriate headers to redirect the client to a new URL.
672
+ * Uses a 409 status code which Inertia.js interprets as a redirect instruction.
673
+ *
674
+ * @param url - The URL to redirect to
675
+ *
676
+ * @example
677
+ * ```js
678
+ * // Redirect after login
679
+ * inertia.location('/dashboard')
680
+ *
681
+ * // Redirect with full URL
682
+ * inertia.location('https://example.com/external')
683
+ * ```
684
+ */
685
+ location(url) {
686
+ this.ctx.response.header(InertiaHeaders.Location, url);
687
+ this.ctx.response.status(409);
688
+ }
689
+ };
690
+
691
+ // src/server_renderer.ts
692
+ import { pathToFileURL } from "url";
693
+ var ServerRenderer = class {
694
+ /**
695
+ * Shared module runner instance for Vite's runtime API.
696
+ * Used in development mode to execute SSR entry points.
697
+ */
698
+ #runtime;
699
+ /**
700
+ * Inertia configuration object containing SSR settings
701
+ */
702
+ #config;
703
+ /**
704
+ * Vite instance for development mode rendering and asset management
705
+ */
706
+ #vite;
707
+ /**
708
+ * Creates a new ServerRenderer instance.
709
+ *
710
+ * @param config - Inertia configuration object containing SSR settings
711
+ * @param vite - Vite instance for development mode rendering and asset management
712
+ *
713
+ * @example
714
+ * ```js
715
+ * const renderer = new ServerRenderer(config, vite)
716
+ * ```
717
+ */
718
+ constructor(config, vite) {
719
+ this.#config = config;
720
+ this.#vite = vite;
721
+ }
722
+ /**
723
+ * Renders an Inertia page on the server.
724
+ *
725
+ * In development mode, uses Vite's Runtime API to execute the SSR entrypoint.
726
+ * In production mode, imports and uses the pre-built SSR bundle.
727
+ *
728
+ * @param pageObject - The Inertia page object containing component, props, and metadata
729
+ * @returns Promise resolving to an object with rendered head and body HTML
730
+ *
731
+ * @example
732
+ * ```js
733
+ * const pageObject = {
734
+ * component: 'Home',
735
+ * props: { user: { name: 'John' } },
736
+ * url: '/dashboard',
737
+ * version: '1.0.0'
738
+ * }
739
+ *
740
+ * const { head, body } = await renderer.render(pageObject)
741
+ * ```
742
+ */
743
+ async render(pageObject) {
744
+ let render;
745
+ const devServer = this.#vite.getDevServer();
746
+ if (devServer) {
747
+ debug_default("creating SSR bundle using dev-server");
748
+ this.#runtime ??= await this.#vite.createModuleRunner();
749
+ this.#runtime.clearCache();
750
+ render = await this.#runtime.import(this.#config.ssr.entrypoint);
751
+ } else {
752
+ debug_default("creating SSR bundle using production build");
753
+ render = await import(pathToFileURL(this.#config.ssr.bundle).href);
754
+ }
755
+ const result = await render.default(pageObject);
756
+ debug_default("SSR bundle %o", result);
757
+ return { head: result.head, body: result.body };
758
+ }
759
+ };
760
+
761
+ // src/inertia_manager.ts
762
+ var InertiaManager = class {
763
+ /**
764
+ * Optional Vite instance for asset management
765
+ */
766
+ #vite;
767
+ /**
768
+ * Inertia configuration object
769
+ */
770
+ #config;
771
+ #serverRenderer;
772
+ /**
773
+ * Creates a new InertiaManager instance
774
+ *
775
+ * @param config - Inertia configuration object
776
+ * @param vite - Optional Vite instance for development mode and SSR
777
+ *
778
+ * @example
779
+ * ```js
780
+ * const manager = new InertiaManager({
781
+ * rootView: 'app',
782
+ * ssr: { enabled: true }
783
+ * }, vite)
784
+ * ```
785
+ */
786
+ constructor(config, vite) {
787
+ this.#config = config;
788
+ this.#vite = vite;
789
+ this.#serverRenderer = this.#vite ? new ServerRenderer(this.#config, this.#vite) : void 0;
790
+ }
791
+ /**
792
+ * Creates a new Inertia instance for a specific HTTP request
793
+ *
794
+ * @param ctx - HTTP context for the current request
795
+ * @returns A new Inertia instance configured for the given request
796
+ *
797
+ * @example
798
+ * ```js
799
+ * const inertia = manager.createForRequest(ctx)
800
+ * await inertia.render('Home', { user: ctx.auth.user })
801
+ * ```
802
+ */
803
+ createForRequest(ctx) {
804
+ return new Inertia(ctx, this.#config, this.#vite, this.#serverRenderer);
805
+ }
806
+ };
807
+
808
+ export {
809
+ symbols_exports,
810
+ Inertia,
811
+ ServerRenderer,
812
+ InertiaManager
813
+ };