@rangojs/router 0.0.0-experimental.103 → 0.0.0-experimental.105

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 CHANGED
@@ -943,9 +943,9 @@ import { createHostRouter } from "@rangojs/router/host";
943
943
 
944
944
  const hostRouter = createHostRouter();
945
945
 
946
- hostRouter.host(["*.localhost"]).map(() => import("./apps/admin/handler.js"));
947
- hostRouter.host(["localhost"]).map(() => import("./apps/site/handler.js"));
948
- hostRouter.fallback().map(() => import("./apps/site/handler.js"));
946
+ hostRouter.host(["*.localhost"]).lazy(() => import("./apps/admin/handler.js"));
947
+ hostRouter.host(["localhost"]).lazy(() => import("./apps/site/handler.js"));
948
+ hostRouter.fallback().lazy(() => import("./apps/site/handler.js"));
949
949
 
950
950
  export default {
951
951
  async fetch(request, env, ctx) {
@@ -954,7 +954,7 @@ export default {
954
954
  };
955
955
  ```
956
956
 
957
- Each sub-app has its own `createRouter()` and `urls()`. The host router lazily imports the matched app's handler. Patterns are matched in registration order — register more specific patterns (subdomains) before catch-alls.
957
+ Use `.lazy(() => import("./sub-app"))` to mount a lazily-imported sub-app (a module whose `default` export is a handler or nested host router), and `.map((request) => Response)` for an inline request handler. Only `.lazy()` mounts are imported during build-time discovery; `.map(() => import(...))` is a type error. Each sub-app has its own `createRouter()` and `urls()`. Patterns are matched in registration order — register more specific patterns (subdomains) before catch-alls.
958
958
 
959
959
  ## Meta Tags
960
960
 
@@ -2040,7 +2040,7 @@ import { resolve } from "node:path";
2040
2040
  // package.json
2041
2041
  var package_default = {
2042
2042
  name: "@rangojs/router",
2043
- version: "0.0.0-experimental.103",
2043
+ version: "0.0.0-experimental.105",
2044
2044
  description: "Django-inspired RSC router with composable URL patterns",
2045
2045
  keywords: [
2046
2046
  "react",
@@ -2205,7 +2205,8 @@ var package_default = {
2205
2205
  peerDependencies: {
2206
2206
  "@cloudflare/vite-plugin": "^1.25.0",
2207
2207
  "@vitejs/plugin-rsc": "^0.5.23",
2208
- react: "^18.0.0 || ^19.0.0",
2208
+ react: ">=19.2.6 <20",
2209
+ "react-dom": ">=19.2.6 <20",
2209
2210
  vite: "^7.3.0"
2210
2211
  },
2211
2212
  peerDependenciesMeta: {
@@ -3777,6 +3778,8 @@ function createDiscoveryState(entryPath, opts) {
3777
3778
  projectRoot: "",
3778
3779
  isBuildMode: false,
3779
3780
  userResolveAlias: void 0,
3781
+ userRunnerConfig: void 0,
3782
+ userResolvePlugins: [],
3780
3783
  scanFilter: void 0,
3781
3784
  cachedRouterFiles: void 0,
3782
3785
  opts,
@@ -3839,9 +3842,12 @@ function checkSelfGenWrite(state, filePath, consume) {
3839
3842
 
3840
3843
  // src/vite/utils/manifest-utils.ts
3841
3844
  function flattenLeafEntries(prefixTree, routeManifest, result) {
3842
- function visit(node) {
3845
+ function visit(node, ancestorStaticPrefixes) {
3843
3846
  const children = node.children || {};
3844
3847
  if (Object.keys(children).length === 0 && node.routes && node.routes.length > 0) {
3848
+ if (ancestorStaticPrefixes.has(node.staticPrefix)) {
3849
+ return;
3850
+ }
3845
3851
  const routes = {};
3846
3852
  for (const name of node.routes) {
3847
3853
  if (name in routeManifest) {
@@ -3850,13 +3856,15 @@ function flattenLeafEntries(prefixTree, routeManifest, result) {
3850
3856
  }
3851
3857
  result.push({ staticPrefix: node.staticPrefix, routes });
3852
3858
  } else {
3859
+ const nextAncestors = new Set(ancestorStaticPrefixes);
3860
+ nextAncestors.add(node.staticPrefix);
3853
3861
  for (const child of Object.values(children)) {
3854
- visit(child);
3862
+ visit(child, nextAncestors);
3855
3863
  }
3856
3864
  }
3857
3865
  }
3858
3866
  for (const node of Object.values(prefixTree)) {
3859
- visit(node);
3867
+ visit(node, /* @__PURE__ */ new Set());
3860
3868
  }
3861
3869
  }
3862
3870
  function buildRouteToStaticPrefix(prefixTree, result) {
@@ -4433,6 +4441,80 @@ async function renderStaticHandlers(state, rscEnv, registry) {
4433
4441
  );
4434
4442
  }
4435
4443
 
4444
+ // src/vite/discovery/discovery-errors.ts
4445
+ function indent(text, pad) {
4446
+ return text.split("\n").map((line) => line.length > 0 ? pad + line : line).join("\n");
4447
+ }
4448
+ async function invokeLazyMount(loader, context, errors) {
4449
+ try {
4450
+ await loader();
4451
+ } catch (error) {
4452
+ errors.push({ context, error });
4453
+ }
4454
+ }
4455
+ function isLazyMount(route) {
4456
+ return !!route && route.kind === "lazy" && typeof route.handler === "function";
4457
+ }
4458
+ async function resolveHostRouterHandlers(hostRegistry) {
4459
+ const errors = [];
4460
+ for (const [hostId, entry] of hostRegistry) {
4461
+ for (const route of entry.routes) {
4462
+ if (isLazyMount(route)) {
4463
+ await invokeLazyMount(
4464
+ route.handler,
4465
+ `host "${hostId}" route handler`,
4466
+ errors
4467
+ );
4468
+ }
4469
+ }
4470
+ if (isLazyMount(entry.fallback)) {
4471
+ await invokeLazyMount(
4472
+ entry.fallback.handler,
4473
+ `host "${hostId}" fallback handler`,
4474
+ errors
4475
+ );
4476
+ }
4477
+ }
4478
+ return errors;
4479
+ }
4480
+ function formatNoRoutersError(entryPath, errors) {
4481
+ const base = `[rsc-router] No routers found in registry after importing ${entryPath}`;
4482
+ if (errors.length === 0) {
4483
+ return base;
4484
+ }
4485
+ const formatted = errors.map(({ context, error }) => {
4486
+ const err = error instanceof Error ? error : new Error(String(error));
4487
+ const detail = err.stack ?? err.message;
4488
+ return ` - while resolving ${context}:
4489
+ ${indent(detail, " ")}`;
4490
+ }).join("\n");
4491
+ return `${base}
4492
+
4493
+ ${errors.length} error(s) were caught during host-router discovery and likely explain why no routers were registered:
4494
+ ${formatted}`;
4495
+ }
4496
+ function toCause(errors) {
4497
+ if (errors.length === 0) return void 0;
4498
+ if (errors.length === 1) return errors[0].error;
4499
+ return new AggregateError(
4500
+ errors.map((e) => e.error),
4501
+ "Multiple host-router handlers failed during discovery"
4502
+ );
4503
+ }
4504
+ var DiscoveryError = class _DiscoveryError extends Error {
4505
+ constructor(entryPath, caught) {
4506
+ super(formatNoRoutersError(entryPath, caught));
4507
+ const cause = toCause(caught);
4508
+ if (cause !== void 0) {
4509
+ this.cause = cause;
4510
+ }
4511
+ this.name = "DiscoveryError";
4512
+ this.entryPath = entryPath;
4513
+ this.caught = caught;
4514
+ Object.setPrototypeOf(this, _DiscoveryError.prototype);
4515
+ }
4516
+ };
4517
+
4436
4518
  // src/vite/discovery/discover-routers.ts
4437
4519
  var debug10 = createRangoDebugger(NS.discovery);
4438
4520
  async function discoverRouters(state, rscEnv) {
@@ -4449,27 +4531,17 @@ async function discoverRouters(state, rscEnv) {
4449
4531
  );
4450
4532
  let registry = serverMod.RouterRegistry;
4451
4533
  if (!registry || registry.size === 0) {
4534
+ const discoveryErrors = [];
4452
4535
  try {
4453
4536
  const hostRegistry = serverMod.HostRouterRegistry;
4454
4537
  if (hostRegistry && hostRegistry.size > 0) {
4455
4538
  console.log(
4456
4539
  `[rsc-router] Found ${hostRegistry.size} host router(s), resolving lazy handlers...`
4457
4540
  );
4458
- for (const [, entry] of hostRegistry) {
4459
- for (const route of entry.routes) {
4460
- if (typeof route.handler === "function") {
4461
- try {
4462
- await route.handler();
4463
- } catch {
4464
- }
4465
- }
4466
- }
4467
- if (entry.fallback && typeof entry.fallback.handler === "function") {
4468
- try {
4469
- await entry.fallback.handler();
4470
- } catch {
4471
- }
4472
- }
4541
+ const handlerErrors = await resolveHostRouterHandlers(hostRegistry);
4542
+ discoveryErrors.push(...handlerErrors);
4543
+ for (const { context, error } of handlerErrors) {
4544
+ debug10?.("caught error while resolving %s: %O", context, error);
4473
4545
  }
4474
4546
  const freshServerMod = await rscEnv.runner.import(
4475
4547
  "@rangojs/router/server"
@@ -4480,12 +4552,11 @@ async function discoverRouters(state, rscEnv) {
4480
4552
  registry = freshRegistry;
4481
4553
  }
4482
4554
  }
4483
- } catch {
4555
+ } catch (error) {
4556
+ discoveryErrors.push({ context: "host-router discovery", error });
4484
4557
  }
4485
4558
  if (!registry || registry.size === 0) {
4486
- throw new Error(
4487
- `[rsc-router] No routers found in registry after importing ${state.resolvedEntryPath}`
4488
- );
4559
+ throw new DiscoveryError(state.resolvedEntryPath, discoveryErrors);
4489
4560
  }
4490
4561
  }
4491
4562
  const buildMod = await timed(
@@ -5162,6 +5233,52 @@ function createDiscoveryGate(s, debug11) {
5162
5233
  };
5163
5234
  }
5164
5235
 
5236
+ // src/vite/utils/forward-user-plugins.ts
5237
+ function isDenied(name) {
5238
+ return name.startsWith("vite:") || name === "rsc" || name.startsWith("rsc:") || name.startsWith("@rangojs/router") || name.startsWith("@cloudflare/vite-plugin") || name.startsWith("vite-plugin-cloudflare");
5239
+ }
5240
+ function hasResolutionHooks(p) {
5241
+ return Boolean(p.resolveId || p.load);
5242
+ }
5243
+ function stripToResolutionHooks(p) {
5244
+ const stripped = { name: p.name };
5245
+ if (p.enforce) stripped.enforce = p.enforce;
5246
+ if (p.applyToEnvironment)
5247
+ stripped.applyToEnvironment = p.applyToEnvironment;
5248
+ if (p.resolveId) stripped.resolveId = p.resolveId;
5249
+ if (p.load) stripped.load = p.load;
5250
+ return stripped;
5251
+ }
5252
+ function selectForwardableResolvePlugins(plugins) {
5253
+ if (!plugins) return [];
5254
+ const forwarded = [];
5255
+ for (const p of plugins) {
5256
+ const name = p?.name;
5257
+ if (!name || isDenied(name)) continue;
5258
+ if (!hasResolutionHooks(p)) continue;
5259
+ forwarded.push(stripToResolutionHooks(p));
5260
+ }
5261
+ return forwarded;
5262
+ }
5263
+ function pickForwardedRunnerConfig(config) {
5264
+ const r = config.resolve ?? {};
5265
+ const resolve10 = {};
5266
+ if (r.alias !== void 0) resolve10.alias = r.alias;
5267
+ if (r.dedupe !== void 0) resolve10.dedupe = r.dedupe;
5268
+ if (r.conditions !== void 0) resolve10.conditions = r.conditions;
5269
+ if (r.mainFields !== void 0) resolve10.mainFields = r.mainFields;
5270
+ if (r.extensions !== void 0) resolve10.extensions = r.extensions;
5271
+ if (r.preserveSymlinks !== void 0)
5272
+ resolve10.preserveSymlinks = r.preserveSymlinks;
5273
+ const userEsbuild = config.esbuild;
5274
+ const esbuild = userEsbuild && typeof userEsbuild === "object" ? { ...userEsbuild, jsx: "automatic", jsxImportSource: "react" } : { jsx: "automatic", jsxImportSource: "react" };
5275
+ return {
5276
+ resolve: resolve10,
5277
+ define: config.define,
5278
+ esbuild
5279
+ };
5280
+ }
5281
+
5165
5282
  // src/vite/router-discovery.ts
5166
5283
  var debugDiscovery = createRangoDebugger(NS.discovery);
5167
5284
  var debugRoutes = createRangoDebugger(NS.routes);
@@ -5184,14 +5301,23 @@ function ensureCloudflareProtocolLoaderRegistered() {
5184
5301
  async function createTempRscServer(state, options = {}) {
5185
5302
  ensureCloudflareProtocolLoaderRegistered();
5186
5303
  const { default: rsc } = await import("@vitejs/plugin-rsc");
5304
+ const runnerConfig = state.userRunnerConfig;
5305
+ const resolveConfig = runnerConfig?.resolve ?? {
5306
+ alias: state.userResolveAlias
5307
+ };
5308
+ const esbuildConfig = runnerConfig?.esbuild ?? {
5309
+ jsx: "automatic",
5310
+ jsxImportSource: "react"
5311
+ };
5187
5312
  return createViteServer({
5188
5313
  root: state.projectRoot,
5189
5314
  configFile: false,
5190
5315
  server: { middlewareMode: true },
5191
5316
  appType: "custom",
5192
5317
  logLevel: "silent",
5193
- resolve: { alias: state.userResolveAlias },
5194
- esbuild: { jsx: "automatic", jsxImportSource: "react" },
5318
+ resolve: resolveConfig,
5319
+ ...runnerConfig?.define ? { define: runnerConfig.define } : {},
5320
+ esbuild: esbuildConfig,
5195
5321
  ...options.cacheDir && { cacheDir: options.cacheDir },
5196
5322
  plugins: [
5197
5323
  rsc({
@@ -5209,7 +5335,11 @@ async function createTempRscServer(state, options = {}) {
5209
5335
  // Dev prerender must use dev-mode IDs (path-based) to match the workerd
5210
5336
  // runtime. forceBuild produces hashed IDs for production bundle consistency.
5211
5337
  exposeInternalIds(options.forceBuild ? { forceBuild: true } : void 0),
5212
- exposeRouterId()
5338
+ exposeRouterId(),
5339
+ // Forwarded user resolution plugins (e.g. vite-tsconfig-paths). Stripped
5340
+ // to resolveId/load and placed last so framework resolution runs first;
5341
+ // Vite re-sorts by `enforce`, so `enforce: "pre"` resolvers still lead.
5342
+ ...state.userResolvePlugins
5213
5343
  ]
5214
5344
  });
5215
5345
  }
@@ -5292,6 +5422,10 @@ function createRouterDiscoveryPlugin(entryPath, opts) {
5292
5422
  viteCommand = config.command;
5293
5423
  viteMode = config.mode;
5294
5424
  s.userResolveAlias = config.resolve.alias;
5425
+ s.userRunnerConfig = pickForwardedRunnerConfig(config);
5426
+ s.userResolvePlugins = selectForwardableResolvePlugins(
5427
+ config.plugins
5428
+ );
5295
5429
  if (!s.resolvedEntryPath && opts?.routerPathRef?.path) {
5296
5430
  s.resolvedEntryPath = opts.routerPathRef.path;
5297
5431
  }
@@ -5987,7 +6121,8 @@ ${err.stack}` : null
5987
6121
  ].filter(Boolean).join("\n");
5988
6122
  throw new Error(
5989
6123
  `[rsc-router] Build-time router discovery failed:
5990
- ${details}`
6124
+ ${details}`,
6125
+ { cause: err }
5991
6126
  );
5992
6127
  } finally {
5993
6128
  delete globalThis.__rscRouterDiscoveryActive;
@@ -6213,7 +6348,15 @@ async function rango(options) {
6213
6348
  esbuildOptions: sharedEsbuildOptions
6214
6349
  },
6215
6350
  resolve: {
6216
- alias: rangoAliases
6351
+ alias: rangoAliases,
6352
+ // Force a single React/React-DOM copy across all three RSC
6353
+ // environments. RSC requires exactly one react/react-dom instance
6354
+ // per environment runtime; consumer install topologies (pnpm
6355
+ // strict layout, experimental React pins, third-party "use client"
6356
+ // packages) can otherwise resolve duplicate copies, causing
6357
+ // "Invalid hook call" / lost context. Child environments inherit
6358
+ // this root dedupe, and Vite merges it with any consumer dedupe.
6359
+ dedupe: ["react", "react-dom"]
6217
6360
  },
6218
6361
  build: {
6219
6362
  rollupOptions: { onwarn }
@@ -6240,10 +6383,6 @@ async function rango(options) {
6240
6383
  build: {
6241
6384
  outDir: "./dist/rsc/ssr"
6242
6385
  },
6243
- resolve: {
6244
- // Ensure single React instance in SSR child environment
6245
- dedupe: ["react", "react-dom"]
6246
- },
6247
6386
  // Pre-bundle SSR entry and React for proper module linking with childEnvironments
6248
6387
  // All deps must be listed to avoid late discovery triggering ERR_OUTDATED_OPTIMIZED_DEP
6249
6388
  optimizeDeps: {
@@ -6339,7 +6478,15 @@ ${list}`);
6339
6478
  rollupOptions: { onwarn }
6340
6479
  },
6341
6480
  resolve: {
6342
- alias: rangoAliases
6481
+ alias: rangoAliases,
6482
+ // Force a single React/React-DOM copy across all three RSC
6483
+ // environments. RSC requires exactly one react/react-dom instance
6484
+ // per environment runtime; consumer install topologies (pnpm
6485
+ // strict layout, experimental React pins, third-party "use client"
6486
+ // packages) can otherwise resolve duplicate copies, causing
6487
+ // "Invalid hook call" / lost context. Child environments inherit
6488
+ // this root dedupe, and Vite merges it with any consumer dedupe.
6489
+ dedupe: ["react", "react-dom"]
6343
6490
  },
6344
6491
  environments: {
6345
6492
  client: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rangojs/router",
3
- "version": "0.0.0-experimental.103",
3
+ "version": "0.0.0-experimental.105",
4
4
  "description": "Django-inspired RSC router with composable URL patterns",
5
5
  "keywords": [
6
6
  "react",
@@ -165,7 +165,8 @@
165
165
  "peerDependencies": {
166
166
  "@cloudflare/vite-plugin": "^1.25.0",
167
167
  "@vitejs/plugin-rsc": "^0.5.23",
168
- "react": "^18.0.0 || ^19.0.0",
168
+ "react": ">=19.2.6 <20",
169
+ "react-dom": ">=19.2.6 <20",
169
170
  "vite": "^7.3.0"
170
171
  },
171
172
  "peerDependenciesMeta": {
@@ -22,9 +22,9 @@ import { createHostRouter } from "@rangojs/router/host";
22
22
 
23
23
  const router = createHostRouter();
24
24
 
25
- router.host(["."]).map(() => import("./apps/main"));
26
- router.host(["admin.*"]).map(() => import("./apps/admin"));
27
- router.host(["api.*"]).map(() => import("./apps/api"));
25
+ router.host(["."]).lazy(() => import("./apps/main"));
26
+ router.host(["admin.*"]).lazy(() => import("./apps/admin"));
27
+ router.host(["api.*"]).lazy(() => import("./apps/api"));
28
28
 
29
29
  export default {
30
30
  fetch(request: Request, env: Env, ctx: ExecutionContext) {
@@ -33,7 +33,31 @@ export default {
33
33
  };
34
34
  ```
35
35
 
36
- Each `.map()` receives either a direct handler `(request, input) => Response` or a lazy import `() => import(...)`. Lazy imports resolve a module with a `default` export that is either a handler function or another `HostRouter` (for nesting).
36
+ ## Inline handlers (`.map`) vs lazy mounts (`.lazy`)
37
+
38
+ A host pattern maps to one of two things, and you pick the method by intent:
39
+
40
+ | Method | Argument | Use for |
41
+ | ------- | ------------------------------ | ------------------------------------------------------------ |
42
+ | `.map` | `(request, input) => Response` | An inline request handler that produces a response directly. |
43
+ | `.lazy` | `() => import("./sub-app")` | A lazily-imported handler or nested host router (a sub-app). |
44
+
45
+ ```typescript
46
+ // Lazy mount: the module's default export is a handler or a HostRouter.
47
+ router.host(["admin.*"]).lazy(() => import("./apps/admin"));
48
+
49
+ // Inline handler: returns a Response itself (sync or async).
50
+ router.host(["health.*"]).map(() => new Response("ok"));
51
+ router
52
+ .host(["echo.*"])
53
+ .map((request) => new Response(new URL(request.url).pathname));
54
+ ```
55
+
56
+ Why two methods instead of one overloaded `.map()`:
57
+
58
+ - **Build-time discovery** invokes only `.lazy()` mounts (to trigger each sub-app's `createRouter()` registration). Inline `.map()` handlers are never invoked during discovery, so they can't crash it or pollute its errors.
59
+ - `.map(() => import("./sub-app"))` is a **type error** — a lazy import resolves to a module, not a `Response`. Use `.lazy()` for imports. (If the types are bypassed, e.g. from JS, a `.map()` handler that resolves to a module throws a clear `HostRouterError` at request time instead of returning the module.)
60
+ - A lazy loader may declare an ignored parameter (`.lazy((_request?) => import("./x"))`); `.lazy()` accepts it because intent is explicit, not inferred from the signature.
37
61
 
38
62
  ## Pattern Syntax
39
63
 
@@ -65,8 +89,8 @@ const hosts = defineHosts({
65
89
  app: [".", "www.*"],
66
90
  });
67
91
 
68
- router.host(hosts.admin).map(() => import("./apps/admin"));
69
- router.host(hosts.app).map(() => import("./apps/main"));
92
+ router.host(hosts.admin).lazy(() => import("./apps/admin"));
93
+ router.host(hosts.app).lazy(() => import("./apps/main"));
70
94
  ```
71
95
 
72
96
  Returns a frozen object — keys are autocompleted by TypeScript.
@@ -88,7 +112,7 @@ router.use(async (request, input, next) => {
88
112
  router
89
113
  .host(["admin.*"])
90
114
  .use(requireAuth)
91
- .map(() => import("./apps/admin"));
115
+ .lazy(() => import("./apps/admin"));
92
116
  ```
93
117
 
94
118
  Middleware signature: `(request: Request, input: RouterRequestInput, next: () => Promise<Response>) => Promise<Response>`
@@ -179,40 +203,41 @@ const request = createTestRequest({
179
203
  });
180
204
 
181
205
  // Test which route would match (without executing)
182
- router.test("admin.example.com"); // { pattern, handler } | null
206
+ router.test("admin.example.com"); // { pattern, handler, kind } | null
183
207
  ```
184
208
 
185
209
  ## Error Types
186
210
 
187
211
  All errors extend `HostRouterError`:
188
212
 
189
- | Error | When |
190
- | ----------------------------- | ------------------------------------------- |
191
- | `InvalidPatternError` | Pattern is empty, non-string, or has spaces |
192
- | `HostOverrideNotAllowedError` | Cookie override from disallowed host |
193
- | `InvalidHostnameError` | Cookie value isn't a valid hostname |
194
- | `HostValidationError` | Custom `validate` function threw |
195
- | `NoRouteMatchError` | No host pattern matched the request |
196
- | `InvalidHandlerError` | Handler is not a function |
213
+ | Error | When |
214
+ | ----------------------------- | ------------------------------------------------------------------------------------------------- |
215
+ | `InvalidPatternError` | Pattern is empty, non-string, or has spaces |
216
+ | `HostOverrideNotAllowedError` | Cookie override from disallowed host |
217
+ | `InvalidHostnameError` | Cookie value isn't a valid hostname |
218
+ | `HostValidationError` | Custom `validate` function threw |
219
+ | `NoRouteMatchError` | No host pattern matched the request |
220
+ | `InvalidHandlerError` | Handler is not a function, or a lazy mount resolved to a module without a usable `default` export |
221
+ | `HostRouterError` | A `.map()` inline handler resolved to a module namespace (a misused lazy import — use `.lazy()`) |
197
222
 
198
223
  See the fallback section above for a `NoRouteMatchError` catch example.
199
224
 
200
225
  ## Nesting Host Routers
201
226
 
202
- A lazy handler can resolve to another `HostRouter`:
227
+ A lazy mount can resolve to another `HostRouter`:
203
228
 
204
229
  ```typescript
205
230
  // apps/regional.ts
206
231
  import { createHostRouter } from "@rangojs/router/host";
207
232
 
208
233
  const regional = createHostRouter();
209
- regional.host(["us.*"]).map(() => import("./regions/us"));
210
- regional.host(["eu.*"]).map(() => import("./regions/eu"));
234
+ regional.host(["us.*"]).lazy(() => import("./regions/us"));
235
+ regional.host(["eu.*"]).lazy(() => import("./regions/eu"));
211
236
 
212
237
  export default regional;
213
238
  ```
214
239
 
215
240
  ```typescript
216
241
  // host-router.ts
217
- router.host(["**.regional.example.com"]).map(() => import("./apps/regional"));
242
+ router.host(["**.regional.example.com"]).lazy(() => import("./apps/regional"));
218
243
  ```
package/src/host/index.ts CHANGED
@@ -11,8 +11,8 @@
11
11
  *
12
12
  * const router = createHostRouter();
13
13
  *
14
- * router.host(['.']).map(() => import('./apps/main'));
15
- * router.host(['admin.*']).map(() => import('./apps/admin'));
14
+ * router.host(['.']).lazy(() => import('./apps/main'));
15
+ * router.host(['admin.*']).lazy(() => import('./apps/admin'));
16
16
  *
17
17
  * export default {
18
18
  * fetch(request) {