@solidjs/router 1.0.0-next.7 → 1.0.0-next.9

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/dist/claims.js CHANGED
@@ -84,7 +84,14 @@ export function setupLinkClaims(router, explicitLinks) {
84
84
  // linkState derives from (the in-flight pendingTarget is readable in the
85
85
  // effect phase because the isRouting write flushes after the target is
86
86
  // assigned), the effect phase sweeps the registry untracked.
87
- createRenderEffect(() => (router.location.pathname, router.isRouting()), () => registry.forEach(a => refresh(a, claimed.get(a))));
87
+ //
88
+ // `transparent` keeps the effect invisible to the hydration id scheme.
89
+ // This setup is client-only, so an id-consuming node here has no server
90
+ // counterpart and every subsequent hydration id would shift by one child
91
+ // slot — lazy-route lookups miss and hydration leaves server nodes
92
+ // unclaimed. (The option is honored by the runtime but missing from the
93
+ // published EffectOptions type, hence the cast.)
94
+ createRenderEffect(() => (router.location.pathname, router.isRouting()), () => registry.forEach(a => refresh(a, claimed.get(a))), { transparent: true });
88
95
  onCleanup(registerElementClaim(node => {
89
96
  if (node.nodeName.toUpperCase() !== "A")
90
97
  return;
@@ -157,6 +157,13 @@ function actionImpl(fn, options = {}) {
157
157
  form && setFormBusy(form, 1);
158
158
  let settled;
159
159
  let response;
160
+ // The transport consumer is awaited before a single-flight mutation
161
+ // resolves, so a counter delta over the call tells whether this action's
162
+ // metadata was already applied. Overlapping mutations can cross-attribute
163
+ // a run (skipping one default revalidation another pass just covered) —
164
+ // a far smaller window than predicting from the function's identity,
165
+ // which misses every response the server returned without flight data.
166
+ const flightApplicationsBefore = flightApplications;
160
167
  try {
161
168
  settled = await settleActionResult(run({
162
169
  call: runMutation,
@@ -167,7 +174,7 @@ function actionImpl(fn, options = {}) {
167
174
  }
168
175
  : undefined
169
176
  }));
170
- response = await handleResponse(settled.value, settled.error, router.navigatorFactory());
177
+ response = await handleResponse(settled.value, settled.error, router.navigatorFactory(), flightApplications !== flightApplicationsBefore);
171
178
  }
172
179
  finally {
173
180
  form && setFormBusy(form, -1);
@@ -263,6 +270,11 @@ async function settleActionResult(result) {
263
270
  }
264
271
  return result;
265
272
  }
273
+ // Invocation count of the flight-data consumer. An action compares it across
274
+ // its mutation call to learn whether the transport already applied this
275
+ // response's metadata (and so the default revalidation pass must not run
276
+ // again and wipe the freshly seeded cache).
277
+ let flightApplications = 0;
266
278
  /**
267
279
  * Registers the router as the single-flight consumer of the server function
268
280
  * transport. Subscribing is the opt-in: while registered, the transport
@@ -275,7 +287,10 @@ async function settleActionResult(result) {
275
287
  * collection work on the server. Returns the unsubscribe function.
276
288
  */
277
289
  export function setupFlightDataConsumer(router) {
278
- return subscribeFlightData((data, { response }) => applyResponseMetadata(response, router.navigatorFactory(), data));
290
+ return subscribeFlightData((data, { response }) => {
291
+ flightApplications++;
292
+ return applyResponseMetadata(response, router.navigatorFactory(), data);
293
+ });
279
294
  }
280
295
  /**
281
296
  * Applies a server function response's integration metadata: `X-Revalidate`
@@ -306,7 +321,7 @@ async function applyResponseMetadata(metadata, navigate, flightData) {
306
321
  // trigger revalidation
307
322
  await revalidate(keys, false);
308
323
  }
309
- async function handleResponse(response, error, navigate) {
324
+ async function handleResponse(response, error, navigate, metadataHandled) {
310
325
  let data;
311
326
  let flightData;
312
327
  let metadata;
@@ -335,6 +350,10 @@ async function handleResponse(response, error, navigate) {
335
350
  return { error: response };
336
351
  else
337
352
  data = response;
338
- await applyResponseMetadata(metadata, navigate, flightData);
353
+ // The transport consumer applies metadata before returning a server
354
+ // function's unwrapped value. Do not treat that value as a second plain
355
+ // action response and invalidate the freshly seeded query cache again.
356
+ if (!metadataHandled || metadata || flightData)
357
+ await applyResponseMetadata(metadata, navigate, flightData);
339
358
  return data != null ? { data } : undefined;
340
359
  }
package/dist/index.d.ts CHANGED
@@ -4,6 +4,6 @@ export { useHref, useIsRouting, useLinkState, useLocation, useMatch, useNavigate
4
4
  export type { LinkState } from "./routing.js";
5
5
  export { mergeSearchString as _mergeSearchString } from "./utils.js";
6
6
  export { int } from "./paths.js";
7
- export type { RoutePaths, PathParamsOf, PathEnd, TypedMatchFilter } from "./paths.js";
7
+ export type { RoutePaths, PathParamsOf, PathEnd, TypedMatchFilter, DefaultSearchTypes } from "./paths.js";
8
8
  export * from "./data/index.js";
9
- export type { Location, LocationChange, SearchParams, MatchFilter, MatchFilters, NavigateOptions, Navigator, OutputMatch, Params, PathMatch, RouteSectionProps, RoutePreloadFunc, RoutePreloadFuncArgs, RouteDefinition, RouteDescription, RouteMatch, RouterIntegration, RouterUtils, SetParams, Submission, BeforeLeaveEventArgs, TypedPath, TypedSearchPath, StandardSchemaV1 } from "./types.js";
9
+ export type { Location, LocationChange, SearchParams, MatchFilter, MatchFilters, NavigateOptions, Navigator, OutputMatch, Params, PathMatch, RouteSectionProps, RoutePreloadFunc, RoutePreloadFuncArgs, RouteDefinition, RouteDescription, RouteMatch, RouterIntegration, RouterUtils, SetParams, SetSearchParams, Submission, BeforeLeaveEventArgs, TypedPath, TypedSearchPath, StandardSchemaV1 } from "./types.js";
package/dist/index.js CHANGED
@@ -267,7 +267,16 @@ function setupLinkClaims(router, explicitLinks) {
267
267
  // linkState derives from (the in-flight pendingTarget is readable in the
268
268
  // effect phase because the isRouting write flushes after the target is
269
269
  // assigned), the effect phase sweeps the registry untracked.
270
- createRenderEffect(() => (router.location.pathname, router.isRouting()), () => registry.forEach(a => refresh(a, claimed.get(a))));
270
+ //
271
+ // `transparent` keeps the effect invisible to the hydration id scheme.
272
+ // This setup is client-only, so an id-consuming node here has no server
273
+ // counterpart and every subsequent hydration id would shift by one child
274
+ // slot — lazy-route lookups miss and hydration leaves server nodes
275
+ // unclaimed. (The option is honored by the runtime but missing from the
276
+ // published EffectOptions type, hence the cast.)
277
+ createRenderEffect(() => (router.location.pathname, router.isRouting()), () => registry.forEach(a => refresh(a, claimed.get(a))), {
278
+ transparent: true
279
+ });
271
280
  onCleanup(registerElementClaim(node => {
272
281
  if (node.nodeName.toUpperCase() !== "A") return;
273
282
  const a = node;
@@ -2372,6 +2381,13 @@ function actionImpl(fn, options = {}) {
2372
2381
  form && setFormBusy(form, 1);
2373
2382
  let settled;
2374
2383
  let response;
2384
+ // The transport consumer is awaited before a single-flight mutation
2385
+ // resolves, so a counter delta over the call tells whether this action's
2386
+ // metadata was already applied. Overlapping mutations can cross-attribute
2387
+ // a run (skipping one default revalidation another pass just covered) —
2388
+ // a far smaller window than predicting from the function's identity,
2389
+ // which misses every response the server returned without flight data.
2390
+ const flightApplicationsBefore = flightApplications;
2375
2391
  try {
2376
2392
  settled = await settleActionResult(run({
2377
2393
  call: runMutation,
@@ -2379,7 +2395,7 @@ function actionImpl(fn, options = {}) {
2379
2395
  for (const hook of submitHooks.values()) hook(...variables);
2380
2396
  } : undefined
2381
2397
  }));
2382
- response = await handleResponse(settled.value, settled.error, router.navigatorFactory());
2398
+ response = await handleResponse(settled.value, settled.error, router.navigatorFactory(), flightApplications !== flightApplicationsBefore);
2383
2399
  } finally {
2384
2400
  form && setFormBusy(form, -1);
2385
2401
  }
@@ -2474,6 +2490,12 @@ async function settleActionResult(result) {
2474
2490
  return result;
2475
2491
  }
2476
2492
 
2493
+ // Invocation count of the flight-data consumer. An action compares it across
2494
+ // its mutation call to learn whether the transport already applied this
2495
+ // response's metadata (and so the default revalidation pass must not run
2496
+ // again and wipe the freshly seeded cache).
2497
+ let flightApplications = 0;
2498
+
2477
2499
  /**
2478
2500
  * Registers the router as the single-flight consumer of the server function
2479
2501
  * transport. Subscribing is the opt-in: while registered, the transport
@@ -2488,7 +2510,10 @@ async function settleActionResult(result) {
2488
2510
  function setupFlightDataConsumer(router) {
2489
2511
  return subscribeFlightData((data, {
2490
2512
  response
2491
- }) => applyResponseMetadata(response, router.navigatorFactory(), data));
2513
+ }) => {
2514
+ flightApplications++;
2515
+ return applyResponseMetadata(response, router.navigatorFactory(), data);
2516
+ });
2492
2517
  }
2493
2518
 
2494
2519
  /**
@@ -2518,7 +2543,7 @@ async function applyResponseMetadata(metadata, navigate, flightData) {
2518
2543
  // trigger revalidation
2519
2544
  await revalidate(keys, false);
2520
2545
  }
2521
- async function handleResponse(response, error, navigate) {
2546
+ async function handleResponse(response, error, navigate, metadataHandled) {
2522
2547
  let data;
2523
2548
  let flightData;
2524
2549
  let metadata;
@@ -2544,7 +2569,10 @@ async function handleResponse(response, error, navigate) {
2544
2569
  } else if (error) return {
2545
2570
  error: response
2546
2571
  };else data = response;
2547
- await applyResponseMetadata(metadata, navigate, flightData);
2572
+ // The transport consumer applies metadata before returning a server
2573
+ // function's unwrapped value. Do not treat that value as a second plain
2574
+ // action response and invalidate the freshly seeded query cache again.
2575
+ if (!metadataHandled || metadata || flightData) await applyResponseMetadata(metadata, navigate, flightData);
2548
2576
  return data != null ? {
2549
2577
  data
2550
2578
  } : undefined;
package/package.json CHANGED
@@ -6,7 +6,7 @@
6
6
  "Ryan Turnquist"
7
7
  ],
8
8
  "license": "MIT",
9
- "version": "1.0.0-next.7",
9
+ "version": "1.0.0-next.9",
10
10
  "homepage": "https://github.com/solidjs/solid-router#readme",
11
11
  "repository": {
12
12
  "type": "git",