@rangojs/router 0.26.3 → 0.26.4

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/bin/rango.js CHANGED
@@ -1644,7 +1644,7 @@ var init_package = __esm({
1644
1644
  "package.json"() {
1645
1645
  package_default = {
1646
1646
  name: "@rangojs/router",
1647
- version: "0.26.3",
1647
+ version: "0.26.4",
1648
1648
  description: "Django-inspired RSC router with composable URL patterns",
1649
1649
  keywords: [
1650
1650
  "react",
@@ -13,6 +13,18 @@ export declare function watchRunnerReloads(events: RunnerReloadEvents | undefine
13
13
  * @internal
14
14
  */
15
15
  export declare function droppedByRunnerReload(): boolean;
16
+ type Serve = () => Promise<Response>;
17
+ /**
18
+ * Serves a request on this router copy, or on the router a runner full reload
19
+ * re-created when the reload dropped this copy before the request or while it
20
+ * ran. What a request imports after the clear is the fresh copy, so one the
21
+ * reload lands inside fails or answers the wrong route: its outcome is
22
+ * discarded. Only GET and HEAD re-run, since a re-run repeats side effects and
23
+ * cannot re-read a body. A reload after the response is returned still splits
24
+ * its stream.
25
+ * @internal
26
+ */
27
+ export declare function serveAcrossRunnerReload(request: Request, serve: Serve, recreated: () => Promise<Serve | undefined>): Promise<Response>;
16
28
  /**
17
29
  * The router the reload re-created for `routerId`, or undefined when none
18
30
  * registered within DEV_RECREATED_ROUTER_WAIT_MS. Importing `sourceFile`
@@ -7078,7 +7078,7 @@ function resolveVersionsFrom(table, routerId2) {
7078
7078
  // package.json
7079
7079
  var package_default = {
7080
7080
  name: "@rangojs/router",
7081
- version: "0.26.3",
7081
+ version: "0.26.4",
7082
7082
  description: "Django-inspired RSC router with composable URL patterns",
7083
7083
  keywords: [
7084
7084
  "react",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rangojs/router",
3
- "version": "0.26.3",
3
+ "version": "0.26.4",
4
4
  "description": "Django-inspired RSC router with composable URL patterns",
5
5
  "keywords": [
6
6
  "react",
@@ -45,6 +45,43 @@ export function droppedByRunnerReload(): boolean {
45
45
  return runnerReloaded;
46
46
  }
47
47
 
48
+ type Serve = () => Promise<Response>;
49
+
50
+ /**
51
+ * Serves a request on this router copy, or on the router a runner full reload
52
+ * re-created when the reload dropped this copy before the request or while it
53
+ * ran. What a request imports after the clear is the fresh copy, so one the
54
+ * reload lands inside fails or answers the wrong route: its outcome is
55
+ * discarded. Only GET and HEAD re-run, since a re-run repeats side effects and
56
+ * cannot re-read a body. A reload after the response is returned still splits
57
+ * its stream.
58
+ * @internal
59
+ */
60
+ export async function serveAcrossRunnerReload(
61
+ request: Request,
62
+ serve: Serve,
63
+ recreated: () => Promise<Serve | undefined>,
64
+ ): Promise<Response> {
65
+ if (runnerReloaded) {
66
+ const rerun = await recreated();
67
+ return (rerun ?? serve)();
68
+ }
69
+ if (request.method !== "GET" && request.method !== "HEAD") return serve();
70
+ const settled = await serve().then(
71
+ (response) => ({ response }),
72
+ (error: unknown) => ({ error }),
73
+ );
74
+ const rerun = runnerReloaded ? await recreated() : undefined;
75
+ if (rerun) {
76
+ if ("response" in settled) {
77
+ void settled.response.body?.cancel().catch(() => {});
78
+ }
79
+ return rerun();
80
+ }
81
+ if ("error" in settled) throw settled.error;
82
+ return settled.response;
83
+ }
84
+
48
85
  /**
49
86
  * The router the reload re-created for `routerId`, or undefined when none
50
87
  * registered within DEV_RECREATED_ROUTER_WAIT_MS. Importing `sourceFile`
package/src/router.ts CHANGED
@@ -134,8 +134,8 @@ import {
134
134
  resolvePrefetchConcurrency,
135
135
  } from "./router/prefetch-limits.js";
136
136
  import {
137
- droppedByRunnerReload,
138
137
  routerAfterRunnerReload,
138
+ serveAcrossRunnerReload,
139
139
  } from "./router/dev-reload-handoff.js";
140
140
 
141
141
  // Re-export public types and values from extracted modules
@@ -1293,18 +1293,30 @@ export function createRouter<TEnv = any>(
1293
1293
  });
1294
1294
  }
1295
1295
 
1296
- // Dev: a runner full reload dropped this router's module copy
1297
- // (router/dev-reload-handoff.ts, #1186).
1298
- if (process.env.NODE_ENV !== "production" && droppedByRunnerReload()) {
1299
- const reloaded = await routerAfterRunnerReload(
1300
- routerId,
1301
- __sourceFile,
1296
+ // Dev: a runner full reload can drop this router's module copy before
1297
+ // or during the request (router/dev-reload-handoff.ts, #1186).
1298
+ if (process.env.NODE_ENV !== "production") {
1299
+ return serveAcrossRunnerReload(
1300
+ request,
1301
+ () => serve(request, input),
1302
+ async () => {
1303
+ const reloaded = await routerAfterRunnerReload(
1304
+ routerId,
1305
+ __sourceFile,
1306
+ );
1307
+ return reloaded && reloaded !== router
1308
+ ? () => reloaded.fetch(request, input)
1309
+ : undefined;
1310
+ },
1302
1311
  );
1303
- if (reloaded && reloaded !== router) {
1304
- return reloaded.fetch(request, input);
1305
- }
1306
1312
  }
1313
+ return serve(request, input);
1314
+ };
1307
1315
 
1316
+ async function serve(
1317
+ request: Request,
1318
+ input: RouterRequestInput<TEnv>,
1319
+ ): Promise<Response> {
1308
1320
  // Trigger lazy import of per-router manifest data before route matching.
1309
1321
  // No-op if data is already loaded or no loader is registered.
1310
1322
  await ensureRouterManifest(routerId);
@@ -1325,7 +1337,7 @@ export function createRouter<TEnv = any>(
1325
1337
  ) => Promise<Response>;
1326
1338
  }
1327
1339
  return handler!(request, input);
1328
- };
1340
+ }
1329
1341
  })(),
1330
1342
 
1331
1343
  // Low-level route matching for request classification