@adonisjs/inertia 5.0.0-next.0 → 5.0.0-next.1

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.
@@ -1,38 +1,104 @@
1
- import { t as InertiaManager } from "../inertia_manager-BdcjpKFf.js";
2
- import { t as InertiaHeaders } from "../headers-DafWEpBh.js";
3
- import { t as debug_default } from "../debug-CBMTuPUm.js";
1
+ import { t as InertiaManager } from "../inertia_manager-BeqpMsuN.js";
2
+ import { t as InertiaHeaders } from "../headers-B-5pLwyD.js";
3
+ import { t as debug_default } from "../debug-Ca0ekg3M.js";
4
+ //#region src/inertia_middleware.ts
5
+ /**
6
+ * HTTP methods that require special redirect handling
7
+ * These methods should use 303 status code for redirects
8
+ */
4
9
  const MUTATION_METHODS = [
5
10
  "PUT",
6
11
  "PATCH",
7
12
  "DELETE"
8
13
  ];
14
+ /**
15
+ * Base middleware class for handling Inertia.js requests
16
+ *
17
+ * This middleware handles the initialization of the Inertia instance,
18
+ * manages request headers, handles redirects for mutation methods,
19
+ * and implements asset versioning.
20
+ *
21
+ * @example
22
+ * ```ts
23
+ * export default class InertiaMiddleware extends BaseInertiaMiddleware {
24
+ * async share() {
25
+ * return {
26
+ * user: ctx.auth?.user
27
+ * }
28
+ * }
29
+ * }
30
+ * ```
31
+ */
9
32
  var BaseInertiaMiddleware = class {
10
- getValidationErrors(ctx) {
33
+ getValidationErrors(ctx, options) {
11
34
  if (!ctx.session) return {};
35
+ const allMessages = options?.allMessages === true;
12
36
  const inputErrors = ctx.session.flashMessages.get("inputErrorsBag", {});
13
37
  const errors = Object.entries(inputErrors).reduce((result, [field, messages]) => {
14
- result[field] = Array.isArray(messages) ? messages[0] : messages;
38
+ if (allMessages) result[field] = Array.isArray(messages) ? messages : [messages];
39
+ else result[field] = Array.isArray(messages) ? messages[0] : messages;
15
40
  return result;
16
41
  }, {});
17
42
  const errorBag = ctx.request.header(InertiaHeaders.ErrorBag);
18
43
  if (errorBag) return { [errorBag]: errors };
19
44
  return errors;
20
45
  }
46
+ /**
47
+ * Initialize the Inertia instance for the current request
48
+ *
49
+ * This method creates an Inertia instance and attaches it to the
50
+ * HTTP context, making it available throughout the request lifecycle.
51
+ *
52
+ * @param ctx - The HTTP context object
53
+ *
54
+ * @example
55
+ * ```ts
56
+ * await middleware.init(ctx)
57
+ * ```
58
+ */
21
59
  async init(ctx) {
22
60
  debug_default("initiating inertia");
23
61
  ctx.inertia = (await ctx.containerResolver.make(InertiaManager)).createForRequest(ctx);
24
62
  if (this.share) ctx.inertia.share(() => this.share(ctx));
63
+ if (this.flash) ctx.inertia.flash(() => this.flash(ctx));
25
64
  }
65
+ /**
66
+ * Clean up and finalize the Inertia response
67
+ *
68
+ * This method handles the final processing of Inertia requests including:
69
+ * - Setting appropriate response headers
70
+ * - Handling redirects for mutation methods (PUT/PATCH/DELETE)
71
+ * - Managing asset versioning conflicts
72
+ *
73
+ * @param ctx - The HTTP context object
74
+ *
75
+ * @example
76
+ * ```ts
77
+ * await middleware.dispose(ctx)
78
+ * ```
79
+ */
26
80
  dispose(ctx) {
27
81
  const requestInfo = ctx.inertia.requestInfo();
28
82
  if (!requestInfo.isInertiaRequest) return;
29
83
  debug_default("disposing as inertia request");
30
84
  ctx.response.header("Vary", InertiaHeaders.Inertia);
85
+ /**
86
+ * When redirecting a PUT/PATCH/DELETE request, we must use a 303
87
+ * status code instead of a 302 to force the browser to use a GET
88
+ * request after redirecting.
89
+ *
90
+ * See https://inertiajs.com/redirects
91
+ */
31
92
  const method = ctx.request.method();
32
93
  if (ctx.response.getStatus() === 302 && MUTATION_METHODS.includes(method)) {
33
94
  debug_default("upgrading response status from 302 to 303");
34
95
  ctx.response.status(303);
35
96
  }
97
+ /**
98
+ * Handle version change
99
+ *
100
+ * See https://inertiajs.com/the-protocol#asset-versioning
101
+ */
36
102
  const version = ctx.inertia.getVersion();
37
103
  const clientVersion = requestInfo.version ?? "";
38
104
  if (method === "GET" && clientVersion !== version) {
@@ -44,4 +110,5 @@ var BaseInertiaMiddleware = class {
44
110
  }
45
111
  }
46
112
  };
113
+ //#endregion
47
114
  export { BaseInertiaMiddleware as default };
@@ -1,17 +1,72 @@
1
- import { t as debug_default } from "../../../debug-CBMTuPUm.js";
1
+ import { t as debug_default } from "../../../debug-Ca0ekg3M.js";
2
2
  import { EdgeError } from "edge-error";
3
+ //#region src/plugins/edge/utils.ts
4
+ /**
5
+ * Validates that an AST expression is one of the allowed expression types
6
+ *
7
+ * This utility function is used during Edge template compilation to ensure
8
+ * that only specific expression types are allowed in certain contexts.
9
+ *
10
+ * @param expression - The AST expression to validate
11
+ * @param expressions - Array of allowed expression type names
12
+ * @param errorCallback - Function to call when validation fails
13
+ *
14
+ * @example
15
+ * ```js
16
+ * // Ensure expression is either a literal or identifier
17
+ * isSubsetOf(astNode, ['Literal', 'Identifier'], () => {
18
+ * throw new Error('Invalid expression type')
19
+ * })
20
+ *
21
+ * // Allow only object expressions
22
+ * isSubsetOf(astNode, ['ObjectExpression'], () => {
23
+ * throw new EdgeError('Expected object expression')
24
+ * })
25
+ * ```
26
+ */
3
27
  function isSubsetOf(expression, expressions, errorCallback) {
4
28
  if (!expressions.includes(expression.type)) errorCallback();
5
29
  }
30
+ //#endregion
31
+ //#region src/plugins/edge/tags.ts
32
+ /**
33
+ * Edge tag that generates the root element for Inertia.js applications
34
+ *
35
+ * The @inertia tag creates a container element with encoded page data that Inertia.js
36
+ * uses to hydrate the client-side application. Supports customization through attributes.
37
+ *
38
+ * @example
39
+ * ```edge
40
+ * {{-- Basic usage with default div element and id="app" --}}
41
+ * @inertia()
42
+ *
43
+ * {{-- Custom element and attributes --}}
44
+ * @inertia({ as: 'main', id: 'app-root', class: 'min-h-screen' })
45
+ *
46
+ * {{-- Results in: --}}
47
+ * {{-- <main id="app-root" class="min-h-screen" data-page="{...encoded page data...}"></main> --}}
48
+ * ```
49
+ *
50
+ * Supported attributes:
51
+ * - `as`: HTML tag name for the root element (defaults to 'div')
52
+ * - `id`: Element ID (defaults to 'app')
53
+ * - `class`: CSS class names for the element
54
+ */
6
55
  const inertiaTag = {
7
56
  block: false,
8
57
  tagName: "inertia",
9
58
  seekable: true,
10
59
  compile(parser, buffer, { filename, loc, properties }) {
60
+ /**
61
+ * Handle case where no arguments are passed to the tag
62
+ */
11
63
  if (properties.jsArg.trim() === "") {
12
64
  buffer.writeExpression(`out += state.inertia(state.page)`, filename, loc.start.line);
13
65
  return;
14
66
  }
67
+ /**
68
+ * Get AST for the arguments and ensure it is a valid object expression
69
+ */
15
70
  properties.jsArg = `(${properties.jsArg})`;
16
71
  const parsed = parser.utils.transformAst(parser.utils.generateAST(properties.jsArg, loc, filename), filename, parser);
17
72
  isSubsetOf(parsed, ["ObjectExpression"], () => {
@@ -22,10 +77,34 @@ const inertiaTag = {
22
77
  filename
23
78
  });
24
79
  });
80
+ /**
81
+ * Stringify the object expression and pass it to the `inertia` helper
82
+ */
25
83
  const attributes = parser.utils.stringify(parsed);
26
84
  buffer.outputExpression(`state.inertia(state.page, ${attributes})`, filename, loc.start.line, false);
27
85
  }
28
86
  };
87
+ /**
88
+ * Edge tag that renders server-side rendered head content for Inertia.js
89
+ *
90
+ * The @inertiaHead tag outputs head tags (title, meta, etc.) that were generated
91
+ * during server-side rendering. Only relevant when SSR is enabled.
92
+ *
93
+ * @example
94
+ * ```edge
95
+ * <!DOCTYPE html>
96
+ * <html>
97
+ * <head>
98
+ * <meta charset="utf-8">
99
+ * <meta name="viewport" content="width=device-width, initial-scale=1">
100
+ * @inertiaHead()
101
+ * </head>
102
+ * <body>
103
+ * @inertia()
104
+ * </body>
105
+ * </html>
106
+ * ```
107
+ */
29
108
  const inertiaHeadTag = {
30
109
  block: false,
31
110
  tagName: "inertiaHead",
@@ -34,9 +113,44 @@ const inertiaHeadTag = {
34
113
  buffer.outputExpression("state.inertiaHead(state.page)", filename, loc.start.line, false);
35
114
  }
36
115
  };
116
+ //#endregion
117
+ //#region src/plugins/edge/plugin.ts
118
+ /**
119
+ * Edge.js plugin that registers Inertia.js tags and global functions
120
+ *
121
+ * This plugin adds the @inertia and @inertiaHead tags to Edge templates,
122
+ * along with global helper functions for rendering Inertia pages.
123
+ *
124
+ * @returns Edge plugin function that registers Inertia functionality
125
+ *
126
+ * @example
127
+ * ```js
128
+ * // Configure in config/edge.ts
129
+ * import { edgePluginInertia } from '@adonisjs/inertia/plugins/edge'
130
+ *
131
+ * edge.use(edgePluginInertia())
132
+ * ```
133
+ *
134
+ * @example
135
+ * ```edge
136
+ * {{-- Use in Edge templates --}}
137
+ * <!DOCTYPE html>
138
+ * <html>
139
+ * <head>
140
+ * @inertiaHead()
141
+ * </head>
142
+ * <body>
143
+ * @inertia({ id: 'app', class: 'min-h-screen' })
144
+ * </body>
145
+ * </html>
146
+ * ```
147
+ */
37
148
  const edgePluginInertia = () => {
38
149
  return (edge) => {
39
150
  debug_default("sharing globals and inertia tags with edge");
151
+ /**
152
+ * Register the `inertia` global used by the `@inertia` tag
153
+ */
40
154
  edge.global("inertia", (page = {}, attributes = {}) => {
41
155
  if (page.ssrBody) return page.ssrBody;
42
156
  const className = attributes?.class ? ` class="${attributes.class}"` : "";
@@ -44,12 +158,19 @@ const edgePluginInertia = () => {
44
158
  const tag = attributes?.as || "div";
45
159
  return `<script data-page="${id}" type="application/json">${JSON.stringify(page).replace(/\//g, "\\/")}<\/script><${tag} id="${id}"${className}></${tag}>`;
46
160
  });
161
+ /**
162
+ * Register the `inertiaHead` global used by the `@inertiaHead` tag
163
+ */
47
164
  edge.global("inertiaHead", (page) => {
48
165
  const { ssrHead = [] } = page || {};
49
166
  return ssrHead.join("\n");
50
167
  });
168
+ /**
169
+ * Register tags
170
+ */
51
171
  edge.registerTag(inertiaHeadTag);
52
172
  edge.registerTag(inertiaTag);
53
173
  };
54
174
  };
175
+ //#endregion
55
176
  export { edgePluginInertia };
@@ -1,11 +1,53 @@
1
- import { t as InertiaHeaders } from "../../../headers-DafWEpBh.js";
1
+ import { t as InertiaHeaders } from "../../../headers-B-5pLwyD.js";
2
2
  import { ApiRequest, ApiResponse } from "@japa/api-client";
3
+ //#region src/plugins/japa/api_client.ts
4
+ /**
5
+ * Ensure the response is an inertia response, otherwise throw an error
6
+ *
7
+ * @throws Error when the response is not an Inertia response
8
+ */
3
9
  function ensureIsInertiaResponse() {
4
10
  if (!this.header("x-inertia")) throw new Error("Not an Inertia response. Make sure to use \"withInertia()\" method when making the request");
5
11
  }
6
12
  function ensureHasAssert(assertLib) {
7
13
  if (!assertLib) throw new Error("Response assertions are not available. Make sure to install the @japa/assert plugin");
8
14
  }
15
+ /**
16
+ * Japa plugin that extends the API client with Inertia.js testing capabilities
17
+ *
18
+ * This plugin adds methods to ApiRequest and ApiResponse classes to support
19
+ * testing Inertia applications, including partial reloads and response assertions.
20
+ *
21
+ * @param app - The AdonisJS application service instance
22
+ * @returns Japa plugin function
23
+ *
24
+ * @example
25
+ * ```js
26
+ * // Configure in tests/bootstrap.ts
27
+ * import { inertiaApiClient } from '@adonisjs/inertia/plugins/japa/api_client'
28
+ *
29
+ * export const plugins: Config['plugins'] = [
30
+ * assert(),
31
+ * apiClient(app),
32
+ * inertiaApiClient(app)
33
+ * ]
34
+ * ```
35
+ *
36
+ * @example
37
+ * ```js
38
+ * // Use in tests
39
+ * test('renders dashboard page', async ({ client }) => {
40
+ * const response = await client
41
+ * .get('/dashboard')
42
+ * .withInertia()
43
+ *
44
+ * response.assertInertiaComponent('Dashboard')
45
+ * response.assertInertiaPropsContains({
46
+ * user: { name: 'John' }
47
+ * })
48
+ * })
49
+ * ```
50
+ */
9
51
  function inertiaApiClient(app) {
10
52
  return async () => {
11
53
  const inertiaConfig = app.config.get("inertia");
@@ -20,6 +62,9 @@ function inertiaApiClient(app) {
20
62
  this.header(InertiaHeaders.PartialOnly, data.join(","));
21
63
  return this;
22
64
  });
65
+ /**
66
+ * Response getters
67
+ */
23
68
  ApiResponse.getter("inertiaComponent", function() {
24
69
  ensureIsInertiaResponse.call(this);
25
70
  return this.body().component;
@@ -28,6 +73,9 @@ function inertiaApiClient(app) {
28
73
  ensureIsInertiaResponse.call(this);
29
74
  return this.body().props;
30
75
  });
76
+ /**
77
+ * Response assertions
78
+ */
31
79
  ApiResponse.macro("assertInertiaComponent", function(component) {
32
80
  ensureIsInertiaResponse.call(this);
33
81
  ensureHasAssert(this.assert);
@@ -48,4 +96,5 @@ function inertiaApiClient(app) {
48
96
  });
49
97
  };
50
98
  }
99
+ //#endregion
51
100
  export { inertiaApiClient };
@@ -1,5 +1,5 @@
1
1
  import { type AsyncOrSync } from '@adonisjs/core/types/common';
2
- import { type DeferProp, type PageProps, type AlwaysProp, type OptionalProp, type MergeableProp, type ComponentProps, type UnPackedPageProps } from './types.ts';
2
+ import { type DeferProp, type DeferOptions, type OnceProp, type PageProps, type AlwaysProp, type ScrollProp, type ScrollValue, type OnceContext, type OnceOptions, type OncePropsMap, type OptionalProp, type MergeableProp, type ComponentProps, type ScrollMetaData, type UnPackedPageProps, type ScrollPropsProvider, type ScrollResolvedValue } from './types.ts';
3
3
  import { type ContainerResolver } from '@adonisjs/core/container';
4
4
  /**
5
5
  * Creates a deferred prop that is never included in standard visits but must be shared with
@@ -9,6 +9,9 @@ import { type ContainerResolver } from '@adonisjs/core/container';
9
9
  * specifically requested by the client.
10
10
  *
11
11
  * @param fn - Function that computes the prop value when requested
12
+ * @param options - A group name string, or `{ group, rescue }`. Pass
13
+ * `{ rescue: true }` to catch resolution errors, omit the prop, and report its
14
+ * path via `rescuedProps` so the client can render the `<Deferred>` rescue slot.
12
15
  * @returns A deferred prop object with compute and merge capabilities
13
16
  *
14
17
  * @example
@@ -23,9 +26,12 @@ import { type ContainerResolver } from '@adonisjs/core/container';
23
26
  * user: user,
24
27
  * stats: userStats // Only loaded when explicitly requested
25
28
  * })
29
+ *
30
+ * // Rescue resolution failures instead of erroring the whole reload
31
+ * const permissions = defer(() => Permission.all(), { rescue: true })
26
32
  * ```
27
33
  */
28
- export declare function defer<T extends UnPackedPageProps>(fn: () => AsyncOrSync<T>, group?: string): DeferProp<T>;
34
+ export declare function defer<T extends UnPackedPageProps>(fn: () => AsyncOrSync<T>, groupOrOptions?: string | DeferOptions): DeferProp<T>;
29
35
  /**
30
36
  * Creates an optional prop that is never included in standard visits and can only be
31
37
  * explicitly requested by the client. Unlike deferred props, optional props are not
@@ -132,6 +138,81 @@ export declare function merge<T extends UnPackedPageProps | DeferProp<UnPackedPa
132
138
  * ```
133
139
  */
134
140
  export declare function deepMerge<T extends UnPackedPageProps | DeferProp<UnPackedPageProps>>(value: T): MergeableProp<T>;
141
+ /**
142
+ * Creates a once prop: a prop the server computes, the client caches across
143
+ * visits, and the server skips re-resolving on later visits where the client
144
+ * reports it already holds a fresh value.
145
+ *
146
+ * Use the `.once()` chaining method to compose with `defer`/`optional`/`merge`;
147
+ * use this standalone form for plain values and lazy callbacks.
148
+ *
149
+ * @param inner - The value, callback, or inner prop wrapper to remember
150
+ * @param options - Custom key, expiry, and force-fresh options
151
+ * @returns A once prop wrapper carrying caching metadata
152
+ *
153
+ * @example
154
+ * ```js
155
+ * // Plain value, no expiry
156
+ * return inertia.render('dashboard', {
157
+ * lookups: inertia.once(() => loadLookupTables())
158
+ * })
159
+ *
160
+ * // Custom key + expiry, composed with a deferred prop
161
+ * return inertia.render('dashboard', {
162
+ * stats: inertia.defer(() => heavyStats()).once({ key: 'stats', expiresIn: '1h' })
163
+ * })
164
+ * ```
165
+ */
166
+ export declare function once<T>(value: T, options?: OnceOptions): OnceProp<T>;
167
+ /**
168
+ * Creates an infinite-scroll prop: a mergeable, paginated value the client keeps
169
+ * extending as the user scrolls. The server labels the value's `data` array for
170
+ * keyed/directional merging (driven by the client's merge-intent header) and
171
+ * emits a pagination cursor under the page object's `scrollProps`.
172
+ *
173
+ * The value is a transformer paginator (cursor auto-derived from its metadata)
174
+ * or any `{ data, ... }`-shaped value, given directly or via a callback. For a
175
+ * non-paginator value, pass a `scrollProps` provider that computes the cursor
176
+ * from the resolved value. Chain `.deferred()` to skip the first page on the
177
+ * initial load, and `.matchOn()` to dedupe overlapping pages by a key.
178
+ *
179
+ * @param value - A transformer paginator or `{ data }` value (or a callback resolving to one)
180
+ * @param provider - Computes the cursor from the resolved value; omit for transformer paginators
181
+ * @returns A scroll prop wrapper carrying merge + pagination metadata
182
+ *
183
+ * @example
184
+ * ```js
185
+ * // Transformer paginator — cursor auto-derived from its metadata
186
+ * return inertia.render('users/index', {
187
+ * users: inertia.scroll(() => UserTransformer.paginate(rows, paginator.getMeta()))
188
+ * })
189
+ *
190
+ * // Custom / cursor source — cursor computed by a provider
191
+ * return inertia.render('feed', {
192
+ * posts: inertia.scroll(() => feed, (value) => ({
193
+ * pageName: 'cursor',
194
+ * currentPage: value.cursor,
195
+ * nextPage: value.next,
196
+ * previousPage: null,
197
+ * }))
198
+ * })
199
+ * ```
200
+ */
201
+ export declare function scroll<Item>(value: ScrollValue<Item> | (() => AsyncOrSync<ScrollValue<Item>>), provider?: ScrollPropsProvider<ScrollResolvedValue<Item>>): ScrollProp<Item>;
202
+ /**
203
+ * Type guard that checks if a prop value is a scroll prop.
204
+ *
205
+ * @param propValue - The object to check for scroll prop characteristics
206
+ * @returns True if the prop value is a scroll prop
207
+ */
208
+ export declare function isScrollProp(propValue: Object): propValue is ScrollProp<any, boolean>;
209
+ /**
210
+ * Type guard that checks if a prop value is a once prop.
211
+ *
212
+ * @param propValue - The object to check for once prop characteristics
213
+ * @returns True if the prop value is a once prop
214
+ */
215
+ export declare function isOnceProp(propValue: Object): propValue is OnceProp<any>;
135
216
  /**
136
217
  * Type guard that checks if a prop value is a deferred prop.
137
218
  *
@@ -212,37 +293,29 @@ export declare function isAlwaysProp<T extends UnPackedPageProps>(propValue: Obj
212
293
  * ```
213
294
  */
214
295
  export declare function isOptionalProp<T extends UnPackedPageProps>(propValue: Object): propValue is OptionalProp<T>;
215
- /**
216
- * Builds props for standard (non-partial) Inertia visits.
217
- *
218
- * This function processes page props and categorizes them based on their type:
219
- * - Deferred props: Skipped but communicated to client
220
- * - Optional props: Skipped entirely
221
- * - Always props: Always included
222
- * - Mergeable props: Included and marked for merging
223
- * - Regular props: Included normally
224
- *
225
- * @param pageProps - The page props to process
226
- * @param containerResolver - Container resolver for dependency injection
227
- * @returns Promise resolving to object containing processed props, deferred props list, and merge props list
228
- *
229
- * @example
230
- * ```js
231
- * const result = await buildStandardVisitProps({
232
- * user: { name: 'John' },
233
- * posts: defer(() => getPosts()),
234
- * settings: merge({ theme: 'dark' })
235
- * })
236
- * // Returns: { props: { user: {...} }, deferredProps: { default: ['posts'] }, mergeProps: ['settings'] }
237
- * ```
238
- */
239
- export declare function buildStandardVisitProps(pageProps: PageProps, containerResolver: ContainerResolver<any>): Promise<{
296
+ export declare function buildStandardVisitProps(pageProps: PageProps, containerResolver: ContainerResolver<any>, onceContext?: OnceContext, resetProps?: Set<string>, mergeIntent?: 'append' | 'prepend'): Promise<{
240
297
  props: ComponentProps;
241
298
  mergeProps: string[];
242
299
  deepMergeProps: string[];
300
+ prependProps: string[];
301
+ matchPropsOn: string[];
243
302
  deferredProps: {
244
303
  [group: string]: string[];
245
304
  };
305
+ onceProps: OncePropsMap;
306
+ scrollProps: {
307
+ [prop: string]: ScrollMetaData;
308
+ };
309
+ /**
310
+ * Deferred props are never computed on a standard visit, so nothing can be
311
+ * rescued here. Emitted for a uniform shape with the partial-reload builder
312
+ * and to match the always-present v3 `rescuedProps` wire field.
313
+ */
314
+ rescuedProps: string[];
315
+ rescuedErrors: {
316
+ prop: string;
317
+ error: unknown;
318
+ }[];
246
319
  }>;
247
320
  /**
248
321
  * Builds props for partial (cherry-picked) Inertia requests.
@@ -268,9 +341,26 @@ export declare function buildStandardVisitProps(pageProps: PageProps, containerR
268
341
  * // Returns: { props: { posts: [...], stats: [...] }, mergeProps: [], deferredProps: {} }
269
342
  * ```
270
343
  */
271
- export declare function buildPartialRequestProps(pageProps: PageProps, cherryPickProps: string[], containerResolver: ContainerResolver<any>): Promise<{
344
+ export declare function buildPartialRequestProps(pageProps: PageProps, cherryPickProps: string[], containerResolver: ContainerResolver<any>,
345
+ /**
346
+ * Partial reloads ignore the client's once cache entirely (see the once
347
+ * branch below), so this builder takes only the reference clock for expiry —
348
+ * not the full once context.
349
+ */
350
+ now?: number, resetProps?: Set<string>, mergeIntent?: 'append' | 'prepend'): Promise<{
272
351
  props: ComponentProps;
273
352
  mergeProps: string[];
274
353
  deepMergeProps: string[];
354
+ prependProps: string[];
355
+ matchPropsOn: string[];
275
356
  deferredProps: {};
357
+ onceProps: OncePropsMap;
358
+ scrollProps: {
359
+ [prop: string]: ScrollMetaData;
360
+ };
361
+ rescuedProps: string[];
362
+ rescuedErrors: {
363
+ prop: string;
364
+ error: unknown;
365
+ }[];
276
366
  }>;
@@ -23,3 +23,36 @@ export declare const DEFERRED_PROP: unique symbol;
23
23
  * Deep merging recursively merges nested objects and arrays.
24
24
  */
25
25
  export declare const DEEP_MERGE: unique symbol;
26
+ /**
27
+ * Symbol carrying the direction of a shallow array merge. When `true` the client
28
+ * prepends the incoming items (`prependProps`); when `false` it appends them
29
+ * (`mergeProps`). Ignored for deep merges — the client deep-merge path has no
30
+ * direction.
31
+ */
32
+ export declare const MERGE_PREPEND: unique symbol;
33
+ /**
34
+ * Symbol carrying the match path (relative to the prop) used for keyed merges.
35
+ * When set, the client dedupes/replaces array items by this field rather than
36
+ * concatenating. Emitted on the wire as `"<propPath>.<matchOn>"` in `matchPropsOn`.
37
+ */
38
+ export declare const MERGE_MATCH_ON: unique symbol;
39
+ /**
40
+ * Symbol used to mark props that are remembered by the client across visits.
41
+ * The server skips re-resolving a once prop when the client reports it already
42
+ * holds the value, and always emits the prop's caching metadata.
43
+ */
44
+ export declare const ONCE_PROP: unique symbol;
45
+ /**
46
+ * Symbol used to mark an infinite-scroll prop. Scroll props layer pagination
47
+ * metadata (emitted under the page object's `scrollProps`) on top of the keyed
48
+ * and directional merge primitive, so the client can continuously load pages as
49
+ * the user scrolls.
50
+ */
51
+ export declare const SCROLL_PROP: unique symbol;
52
+ /**
53
+ * Type-only discriminant carrying whether a scroll prop has been deferred via
54
+ * `.deferred()`. A deferred scroll prop is absent on the initial load, so this
55
+ * flag lets the type system treat it as optional — rejecting it on a required
56
+ * client prop, exactly like `defer()`. It is never set at runtime.
57
+ */
58
+ export declare const SCROLL_DEFERRED: unique symbol;