@rangojs/router 0.0.0-experimental.1b930379 → 0.0.0-experimental.1fa245e2

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 (136) hide show
  1. package/AGENTS.md +4 -0
  2. package/README.md +76 -18
  3. package/dist/bin/rango.js +138 -50
  4. package/dist/vite/index.js +558 -319
  5. package/package.json +16 -15
  6. package/skills/cache-guide/SKILL.md +32 -0
  7. package/skills/caching/SKILL.md +45 -4
  8. package/skills/links/SKILL.md +3 -1
  9. package/skills/loader/SKILL.md +53 -43
  10. package/skills/middleware/SKILL.md +2 -0
  11. package/skills/parallel/SKILL.md +126 -0
  12. package/skills/prerender/SKILL.md +110 -68
  13. package/skills/route/SKILL.md +31 -0
  14. package/skills/router-setup/SKILL.md +87 -2
  15. package/skills/typesafety/SKILL.md +10 -0
  16. package/src/__internal.ts +1 -1
  17. package/src/browser/app-version.ts +14 -0
  18. package/src/browser/event-controller.ts +5 -0
  19. package/src/browser/navigation-bridge.ts +19 -13
  20. package/src/browser/navigation-client.ts +115 -58
  21. package/src/browser/navigation-store.ts +43 -8
  22. package/src/browser/navigation-transaction.ts +11 -9
  23. package/src/browser/partial-update.ts +80 -15
  24. package/src/browser/prefetch/cache.ts +57 -5
  25. package/src/browser/prefetch/fetch.ts +38 -23
  26. package/src/browser/prefetch/queue.ts +92 -20
  27. package/src/browser/prefetch/resource-ready.ts +77 -0
  28. package/src/browser/react/Link.tsx +53 -9
  29. package/src/browser/react/NavigationProvider.tsx +40 -4
  30. package/src/browser/react/context.ts +7 -2
  31. package/src/browser/react/use-handle.ts +9 -58
  32. package/src/browser/react/use-router.ts +21 -8
  33. package/src/browser/rsc-router.tsx +134 -59
  34. package/src/browser/scroll-restoration.ts +41 -42
  35. package/src/browser/segment-reconciler.ts +6 -1
  36. package/src/browser/server-action-bridge.ts +8 -6
  37. package/src/browser/types.ts +36 -5
  38. package/src/build/generate-manifest.ts +6 -6
  39. package/src/build/generate-route-types.ts +3 -0
  40. package/src/build/route-types/include-resolution.ts +8 -1
  41. package/src/build/route-types/router-processing.ts +223 -74
  42. package/src/build/route-types/scan-filter.ts +8 -1
  43. package/src/cache/cache-runtime.ts +15 -11
  44. package/src/cache/cache-scope.ts +48 -7
  45. package/src/cache/cf/cf-cache-store.ts +453 -11
  46. package/src/cache/cf/index.ts +5 -1
  47. package/src/cache/document-cache.ts +17 -7
  48. package/src/cache/index.ts +1 -0
  49. package/src/cache/taint.ts +55 -0
  50. package/src/client.tsx +2 -56
  51. package/src/context-var.ts +72 -2
  52. package/src/debug.ts +2 -2
  53. package/src/handle.ts +40 -0
  54. package/src/index.rsc.ts +3 -1
  55. package/src/index.ts +8 -0
  56. package/src/prerender/store.ts +5 -4
  57. package/src/prerender.ts +138 -77
  58. package/src/reverse.ts +22 -1
  59. package/src/route-definition/dsl-helpers.ts +73 -25
  60. package/src/route-definition/helpers-types.ts +10 -6
  61. package/src/route-definition/index.ts +3 -0
  62. package/src/route-definition/redirect.ts +11 -3
  63. package/src/route-definition/resolve-handler-use.ts +149 -0
  64. package/src/route-map-builder.ts +7 -1
  65. package/src/route-types.ts +11 -0
  66. package/src/router/content-negotiation.ts +100 -1
  67. package/src/router/find-match.ts +4 -2
  68. package/src/router/handler-context.ts +79 -23
  69. package/src/router/intercept-resolution.ts +11 -4
  70. package/src/router/lazy-includes.ts +4 -1
  71. package/src/router/loader-resolution.ts +122 -10
  72. package/src/router/logging.ts +5 -2
  73. package/src/router/manifest.ts +9 -3
  74. package/src/router/match-api.ts +124 -189
  75. package/src/router/match-middleware/background-revalidation.ts +30 -2
  76. package/src/router/match-middleware/cache-lookup.ts +88 -16
  77. package/src/router/match-middleware/cache-store.ts +53 -10
  78. package/src/router/match-middleware/intercept-resolution.ts +9 -7
  79. package/src/router/match-middleware/segment-resolution.ts +61 -5
  80. package/src/router/match-result.ts +22 -6
  81. package/src/router/metrics.ts +6 -1
  82. package/src/router/middleware-types.ts +6 -8
  83. package/src/router/middleware.ts +4 -6
  84. package/src/router/navigation-snapshot.ts +182 -0
  85. package/src/router/prerender-match.ts +110 -10
  86. package/src/router/preview-match.ts +30 -102
  87. package/src/router/request-classification.ts +310 -0
  88. package/src/router/route-snapshot.ts +245 -0
  89. package/src/router/router-context.ts +6 -1
  90. package/src/router/router-interfaces.ts +36 -4
  91. package/src/router/router-options.ts +37 -11
  92. package/src/router/segment-resolution/fresh.ts +183 -20
  93. package/src/router/segment-resolution/helpers.ts +29 -24
  94. package/src/router/segment-resolution/loader-cache.ts +1 -0
  95. package/src/router/segment-resolution/revalidation.ts +412 -297
  96. package/src/router/segment-wrappers.ts +2 -0
  97. package/src/router/types.ts +1 -0
  98. package/src/router.ts +59 -6
  99. package/src/rsc/handler.ts +460 -368
  100. package/src/rsc/manifest-init.ts +5 -1
  101. package/src/rsc/progressive-enhancement.ts +4 -0
  102. package/src/rsc/rsc-rendering.ts +5 -0
  103. package/src/rsc/server-action.ts +2 -0
  104. package/src/rsc/ssr-setup.ts +2 -2
  105. package/src/rsc/types.ts +8 -1
  106. package/src/segment-system.tsx +140 -4
  107. package/src/server/context.ts +140 -14
  108. package/src/server/loader-registry.ts +9 -8
  109. package/src/server/request-context.ts +144 -18
  110. package/src/ssr/index.tsx +4 -0
  111. package/src/static-handler.ts +18 -6
  112. package/src/types/cache-types.ts +4 -4
  113. package/src/types/handler-context.ts +137 -33
  114. package/src/types/loader-types.ts +36 -9
  115. package/src/types/route-entry.ts +8 -1
  116. package/src/types/segments.ts +2 -0
  117. package/src/urls/path-helper-types.ts +9 -2
  118. package/src/urls/path-helper.ts +48 -13
  119. package/src/urls/pattern-types.ts +12 -0
  120. package/src/urls/response-types.ts +16 -6
  121. package/src/use-loader.tsx +73 -4
  122. package/src/vite/discovery/bundle-postprocess.ts +30 -33
  123. package/src/vite/discovery/discover-routers.ts +5 -1
  124. package/src/vite/discovery/prerender-collection.ts +14 -1
  125. package/src/vite/discovery/state.ts +13 -6
  126. package/src/vite/index.ts +4 -0
  127. package/src/vite/plugin-types.ts +51 -79
  128. package/src/vite/plugins/expose-action-id.ts +1 -3
  129. package/src/vite/plugins/performance-tracks.ts +88 -0
  130. package/src/vite/plugins/refresh-cmd.ts +88 -26
  131. package/src/vite/plugins/version-plugin.ts +13 -1
  132. package/src/vite/rango.ts +163 -211
  133. package/src/vite/router-discovery.ts +153 -42
  134. package/src/vite/utils/banner.ts +3 -3
  135. package/src/vite/utils/prerender-utils.ts +18 -0
  136. package/src/vite/utils/shared-utils.ts +3 -2
@@ -20,7 +20,12 @@ import type {
20
20
  DefaultRouteName,
21
21
  } from "../types/global-namespace.js";
22
22
  import type { Handle } from "../handle.js";
23
- import { type ContextVar, contextGet, contextSet } from "../context-var.js";
23
+ import {
24
+ type ContextVar,
25
+ contextGet,
26
+ contextSet,
27
+ isNonCacheable,
28
+ } from "../context-var.js";
24
29
  import { createHandleStore, type HandleStore } from "./handle-store.js";
25
30
  import { isHandle } from "../handle.js";
26
31
  import { track, type MetricsStore } from "./context.js";
@@ -30,7 +35,11 @@ import type { Theme, ResolvedThemeConfig } from "../theme/types.js";
30
35
  import { THEME_COOKIE } from "../theme/constants.js";
31
36
  import type { LocationStateEntry } from "../browser/react/location-state-shared.js";
32
37
  import { NOCACHE_SYMBOL, assertNotInsideCacheExec } from "../cache/taint.js";
33
- import { createReverseFunction } from "../router/handler-context.js";
38
+ import { isInsideCacheScope } from "./context.js";
39
+ import {
40
+ createReverseFunction,
41
+ stripInternalParams,
42
+ } from "../router/handler-context.js";
34
43
  import { getGlobalRouteMap, isRouteRootScoped } from "../route-map-builder.js";
35
44
  import { invariant } from "../errors.js";
36
45
  import { isAutoGeneratedRouteName } from "../route-name.js";
@@ -58,10 +67,10 @@ export interface RequestContext<
58
67
  originalUrl: URL;
59
68
  /** URL pathname */
60
69
  pathname: string;
61
- /** URL search params (system params like _rsc* are NOT filtered here) */
70
+ /** URL search params (with internal `_rsc*` params stripped, same as `url.searchParams`) */
62
71
  searchParams: URLSearchParams;
63
- /** Variables set by middleware (same as ctx.var) */
64
- var: Record<string, any>;
72
+ /** @internal Shared variable backing store for ctx.get()/ctx.set(). */
73
+ _variables: Record<string, any>;
65
74
  /** Get a variable set by middleware */
66
75
  get: {
67
76
  <T>(contextVar: ContextVar<T>): T | undefined;
@@ -69,8 +78,12 @@ export interface RequestContext<
69
78
  };
70
79
  /** Set a variable (shared with middleware and handlers) */
71
80
  set: {
72
- <T>(contextVar: ContextVar<T>, value: T): void;
73
- <K extends string>(key: K, value: any): void;
81
+ <T>(
82
+ contextVar: ContextVar<T>,
83
+ value: T,
84
+ options?: { cache?: boolean },
85
+ ): void;
86
+ <K extends string>(key: K, value: any, options?: { cache?: boolean }): void;
74
87
  };
75
88
  /**
76
89
  * Route params (populated after route matching)
@@ -258,6 +271,41 @@ export interface RequestContext<
258
271
  /** @internal Previous route key (from the navigation source), used for revalidation */
259
272
  _prevRouteKey?: string;
260
273
 
274
+ /**
275
+ * @internal Render barrier for experimental `rendered()` API.
276
+ * Resolves when all non-loader segments have settled and handle data
277
+ * is available. Used by DSL loaders that call `ctx.rendered()`.
278
+ */
279
+ _renderBarrier: Promise<void>;
280
+
281
+ /**
282
+ * @internal Resolve the render barrier. Accepts resolved segments, filters
283
+ * out loaders, and captures non-loader segment IDs as the handle ordering.
284
+ * Called after segment resolution (fresh) or handle replay (cache/prerender).
285
+ */
286
+ _resolveRenderBarrier: (
287
+ segments: Array<{ type: string; id: string }>,
288
+ ) => void;
289
+
290
+ /**
291
+ * @internal Segment order at barrier resolution time, used by loader
292
+ * ctx.use(handle) to collect handle data in correct order.
293
+ */
294
+ _renderBarrierSegmentOrder?: string[];
295
+
296
+ /**
297
+ * @internal Set to true when the matched entry tree contains any `loading()`
298
+ * entries (streaming). Used by rendered() to fail fast.
299
+ */
300
+ _treeHasStreaming?: boolean;
301
+
302
+ /**
303
+ * @internal Loader IDs that have called rendered() and are waiting for the
304
+ * barrier. Used to detect deadlocks when a handler tries to await the same
305
+ * loader via ctx.use(Loader).
306
+ */
307
+ _renderBarrierWaiters?: Set<string>;
308
+
261
309
  /** @internal Per-request error dedup set for onError reporting */
262
310
  _reportedErrors: WeakSet<object>;
263
311
 
@@ -274,6 +322,15 @@ export interface RequestContext<
274
322
 
275
323
  /** @internal Request-scoped performance metrics store */
276
324
  _metricsStore?: MetricsStore;
325
+
326
+ /** @internal Router basename for this request (used by redirect()) */
327
+ _basename?: string;
328
+
329
+ /**
330
+ * @internal RouteSnapshot from classifyRequest, reused by match/matchPartial
331
+ * to avoid a second resolveRoute call. Cleared on HMR invalidation.
332
+ */
333
+ _classifiedRoute?: import("../router/route-snapshot.js").RouteSnapshot;
277
334
  }
278
335
 
279
336
  /**
@@ -300,10 +357,18 @@ export type PublicRequestContext<
300
357
  | "_routeName"
301
358
  | "_prevRouteKey"
302
359
  | "_reportedErrors"
360
+ | "_renderBarrier"
361
+ | "_resolveRenderBarrier"
362
+ | "_renderBarrierSegmentOrder"
363
+ | "_treeHasStreaming"
364
+ | "_renderBarrierWaiters"
303
365
  | "_reportBackgroundError"
304
366
  | "_debugPerformance"
305
367
  | "_metricsStore"
368
+ | "_basename"
306
369
  | "_setStatus"
370
+ | "_variables"
371
+ | "_classifiedRoute"
307
372
  | "res"
308
373
  >;
309
374
 
@@ -503,6 +568,18 @@ export function createRequestContext<TEnv>(
503
568
  responseCookieCache = null;
504
569
  };
505
570
 
571
+ // Guard: throw if a response-level side effect is called inside a cache() scope.
572
+ // Uses ALS to detect the scope (set during segment resolution).
573
+ function assertNotInsideCacheScopeALS(methodName: string): void {
574
+ if (isInsideCacheScope()) {
575
+ throw new Error(
576
+ `ctx.${methodName}() cannot be called inside a cache() boundary. ` +
577
+ `On cache hit the handler is skipped, so this side effect would be lost. ` +
578
+ `Move ctx.${methodName}() to a middleware or layout outside the cache() scope.`,
579
+ );
580
+ }
581
+ }
582
+
506
583
  // Effective cookie read: response stub Set-Cookie wins, then original header.
507
584
  // The stub IS the source of truth for same-request mutations.
508
585
  const effectiveCookie = (name: string): string | undefined => {
@@ -555,20 +632,31 @@ export function createRequestContext<TEnv>(
555
632
  invalidateResponseCookieCache();
556
633
  };
557
634
 
635
+ // Strip internal _rsc* params so userland sees a clean URL.
636
+ const cleanUrl = stripInternalParams(url);
637
+
558
638
  // Build the context object first (without use), then add use
559
639
  const ctx: RequestContext<TEnv> = {
560
640
  env,
561
641
  request,
562
- url,
642
+ url: cleanUrl,
563
643
  originalUrl: new URL(request.url),
564
644
  pathname: url.pathname,
565
- searchParams: url.searchParams,
566
- var: variables,
567
- get: ((keyOrVar: any) =>
568
- contextGet(variables, keyOrVar)) as RequestContext<TEnv>["get"],
569
- set: ((keyOrVar: any, value: any) => {
645
+ searchParams: cleanUrl.searchParams,
646
+ _variables: variables,
647
+ get: ((keyOrVar: any) => {
648
+ if (isNonCacheable(variables, keyOrVar) && isInsideCacheScope()) {
649
+ throw new Error(
650
+ `ctx.get() for a non-cacheable variable cannot be called inside a cache() boundary. ` +
651
+ `The variable was created with { cache: false } or set with { cache: false }, ` +
652
+ `and its value would be stale on cache hit. Move the read outside the cached scope.`,
653
+ );
654
+ }
655
+ return contextGet(variables, keyOrVar);
656
+ }) as RequestContext<TEnv>["get"],
657
+ set: ((keyOrVar: any, value: any, options?: any) => {
570
658
  assertNotInsideCacheExec(ctx, "set");
571
- contextSet(variables, keyOrVar, value);
659
+ contextSet(variables, keyOrVar, value, options);
572
660
  }) as RequestContext<TEnv>["set"],
573
661
  params: {} as Record<string, string>,
574
662
 
@@ -606,6 +694,7 @@ export function createRequestContext<TEnv>(
606
694
 
607
695
  setCookie(name: string, value: string, options?: CookieOptions): void {
608
696
  assertNotInsideCacheExec(ctx, "setCookie");
697
+ assertNotInsideCacheScopeALS("setCookie");
609
698
  stubResponse.headers.append(
610
699
  "Set-Cookie",
611
700
  serializeCookieValue(name, value, options),
@@ -618,6 +707,7 @@ export function createRequestContext<TEnv>(
618
707
  options?: Pick<CookieOptions, "domain" | "path">,
619
708
  ): void {
620
709
  assertNotInsideCacheExec(ctx, "deleteCookie");
710
+ assertNotInsideCacheScopeALS("deleteCookie");
621
711
  stubResponse.headers.append(
622
712
  "Set-Cookie",
623
713
  serializeCookieValue(name, "", { ...options, maxAge: 0 }),
@@ -627,11 +717,13 @@ export function createRequestContext<TEnv>(
627
717
 
628
718
  header(name: string, value: string): void {
629
719
  assertNotInsideCacheExec(ctx, "header");
720
+ assertNotInsideCacheScopeALS("header");
630
721
  stubResponse.headers.set(name, value);
631
722
  },
632
723
 
633
724
  setStatus(status: number): void {
634
725
  assertNotInsideCacheExec(ctx, "setStatus");
726
+ assertNotInsideCacheScopeALS("setStatus");
635
727
  stubResponse = new Response(null, {
636
728
  status,
637
729
  headers: stubResponse.headers,
@@ -670,6 +762,7 @@ export function createRequestContext<TEnv>(
670
762
 
671
763
  onResponse(callback: (response: Response) => Response): void {
672
764
  assertNotInsideCacheExec(ctx, "onResponse");
765
+ assertNotInsideCacheScopeALS("onResponse");
673
766
  this._onResponseCallbacks.push(callback);
674
767
  },
675
768
 
@@ -697,9 +790,38 @@ export function createRequestContext<TEnv>(
697
790
  _reportedErrors: new WeakSet<object>(),
698
791
  _metricsStore: undefined,
699
792
 
793
+ // Render barrier: deferred promise resolved after non-loader segments settle.
794
+ _renderBarrier: null as any, // set below
795
+ _resolveRenderBarrier: null as any, // set below
796
+ _renderBarrierSegmentOrder: undefined,
797
+
700
798
  reverse: createReverseFunction(getGlobalRouteMap(), undefined, {}),
701
799
  };
702
800
 
801
+ // Create deferred render barrier. Phase 1: non-streaming only, so all handlers
802
+ // complete synchronously during resolveAllSegments. The barrier is a simple
803
+ // deferred promise resolved after segment resolution (or after handle replay
804
+ // on cache/prerender paths). No HandleStore sealing here — that stays in the
805
+ // existing lifecycle (rsc-rendering.ts, cache-scope.ts, etc.).
806
+ let barrierResolved = false;
807
+ let resolveBarrier: () => void;
808
+ ctx._renderBarrier = new Promise<void>((resolve) => {
809
+ resolveBarrier = resolve;
810
+ });
811
+ ctx._resolveRenderBarrier = (
812
+ segments: Array<{ type: string; id: string }>,
813
+ ) => {
814
+ if (barrierResolved) return;
815
+ barrierResolved = true;
816
+ ctx._renderBarrierSegmentOrder = segments
817
+ .filter((s) => s.type !== "loader")
818
+ .map((s) => s.id);
819
+ // Clear deadlock detection set — once the barrier resolves, the loaders
820
+ // waiting on it will settle and the deadlock window is closed.
821
+ ctx._renderBarrierWaiters = undefined;
822
+ resolveBarrier();
823
+ };
824
+
703
825
  // Now create use() with access to ctx
704
826
  ctx.use = createUseFunction({
705
827
  handleStore,
@@ -882,14 +1004,13 @@ export function createUseFunction<TEnv>(
882
1004
  pathname: ctx.pathname,
883
1005
  url: ctx.url,
884
1006
  env: ctx.env as any,
885
- var: ctx.var as any,
886
1007
  get: ctx.get as any,
887
- use: <TDep, TDepParams = any>(
1008
+ use: (<TDep, TDepParams = any>(
888
1009
  dep: LoaderDefinition<TDep, TDepParams>,
889
1010
  ): Promise<TDep> => {
890
1011
  // Recursive call - will start dep loader if not already started
891
1012
  return ctx.use(dep);
892
- },
1013
+ }) as LoaderContext["use"],
893
1014
  method: "GET",
894
1015
  body: undefined,
895
1016
  reverse: createReverseFunction(
@@ -898,9 +1019,14 @@ export function createUseFunction<TEnv>(
898
1019
  ctx.params as Record<string, string>,
899
1020
  ctx._routeName ? isRouteRootScoped(ctx._routeName) : undefined,
900
1021
  ),
1022
+ rendered: () => {
1023
+ throw new Error(
1024
+ `ctx.rendered() is only available in DSL loaders (registered via loader() in urls()). ` +
1025
+ `It cannot be used from request-context loaders or server actions.`,
1026
+ );
1027
+ },
901
1028
  };
902
1029
 
903
- // Start loader execution with tracking
904
1030
  const doneLoader = track(`loader:${loader.$$id}`, 2);
905
1031
  const promise = Promise.resolve(loaderFn(loaderCtx)).finally(() => {
906
1032
  doneLoader();
package/src/ssr/index.tsx CHANGED
@@ -129,6 +129,7 @@ interface RscPayload {
129
129
  matched?: string[];
130
130
  pathname?: string;
131
131
  params?: Record<string, string>;
132
+ basename?: string;
132
133
  themeConfig?: ResolvedThemeConfig | null;
133
134
  initialTheme?: Theme;
134
135
  version?: string;
@@ -168,6 +169,7 @@ function createSsrEventController(opts: {
168
169
  const state: DerivedNavigationState = {
169
170
  state: "idle",
170
171
  isStreaming: false,
172
+ isNavigating: false,
171
173
  location,
172
174
  pendingUrl: null,
173
175
  inflightActions: [],
@@ -260,6 +262,7 @@ export function createSSRHandler<TEnv = unknown>(deps: SSRDependencies<TEnv>) {
260
262
  function SsrRoot() {
261
263
  payload ??= createFromReadableStream<RscPayload>(rscStream1);
262
264
  const resolved = React.use(payload);
265
+
263
266
  const themeConfig = resolved.metadata?.themeConfig ?? null;
264
267
  const pathname = resolved.metadata?.pathname ?? "/";
265
268
 
@@ -285,6 +288,7 @@ export function createSSRHandler<TEnv = unknown>(deps: SSRDependencies<TEnv>) {
285
288
  navigate: async () => {},
286
289
  refresh: async () => {},
287
290
  version: resolved.metadata?.version,
291
+ basename: resolved.metadata?.basename,
288
292
  };
289
293
 
290
294
  // Build content tree from segments.
@@ -32,11 +32,21 @@
32
32
  */
33
33
  import type { ReactNode } from "react";
34
34
  import type { Handler } from "./types.js";
35
- import type { PrerenderOptions, StaticBuildContext } from "./prerender.js";
35
+ import type { StaticBuildContext } from "./prerender.js";
36
+ import type { UseItems, HandlerUseItem } from "./route-types.js";
36
37
  import { isCachedFunction } from "./cache/taint.js";
37
38
 
38
39
  // -- Types ------------------------------------------------------------------
39
40
 
41
+ export interface StaticHandlerOptions {
42
+ /**
43
+ * Keep handler in server bundle for live fallback (default: false).
44
+ * false: handler replaced with stub, source-only APIs excluded from bundle.
45
+ * true: handler stays in bundle, renders live at request time.
46
+ */
47
+ passthrough?: boolean;
48
+ }
49
+
40
50
  export interface StaticHandlerDefinition<
41
51
  TParams extends Record<string, any> = any,
42
52
  > {
@@ -46,14 +56,16 @@ export interface StaticHandlerDefinition<
46
56
  /** In dev mode, the actual handler function that layout/path/parallel can call. */
47
57
  handler: Handler<TParams>;
48
58
  /** Static handler options (passthrough support). */
49
- options?: PrerenderOptions;
59
+ options?: StaticHandlerOptions;
60
+ /** Composable default DSL items merged when the handler is mounted. */
61
+ use?: () => UseItems<HandlerUseItem>;
50
62
  }
51
63
 
52
64
  // -- Function ---------------------------------------------------------------
53
65
 
54
66
  export function Static<TParams extends Record<string, any> = {}>(
55
67
  handler: (ctx: StaticBuildContext) => ReactNode | Promise<ReactNode>,
56
- options?: PrerenderOptions,
68
+ options?: StaticHandlerOptions,
57
69
  __injectedId?: string,
58
70
  ): StaticHandlerDefinition<TParams>;
59
71
 
@@ -61,7 +73,7 @@ export function Static<TParams extends Record<string, any> = {}>(
61
73
 
62
74
  export function Static<TParams extends Record<string, any>>(
63
75
  handler: Function,
64
- optionsOrId?: PrerenderOptions | string,
76
+ optionsOrId?: StaticHandlerOptions | string,
65
77
  maybeId?: string,
66
78
  ): StaticHandlerDefinition<TParams> {
67
79
  if (isCachedFunction(handler)) {
@@ -72,13 +84,13 @@ export function Static<TParams extends Record<string, any>>(
72
84
  );
73
85
  }
74
86
 
75
- let options: PrerenderOptions | undefined;
87
+ let options: StaticHandlerOptions | undefined;
76
88
  let id: string;
77
89
 
78
90
  if (typeof optionsOrId === "string") {
79
91
  id = optionsOrId;
80
92
  } else {
81
- options = optionsOrId as PrerenderOptions | undefined;
93
+ options = optionsOrId as StaticHandlerOptions | undefined;
82
94
  id = maybeId ?? "";
83
95
  }
84
96
 
@@ -5,8 +5,8 @@
5
5
  * during cache key generation (before middleware runs).
6
6
  *
7
7
  * Note: While the full RequestContext is passed, middleware-set variables
8
- * (ctx.var, ctx.get()) may not be populated yet since cache lookup
9
- * happens before middleware execution.
8
+ * read via `ctx.get()` may not be populated yet since cache lookup happens
9
+ * before middleware execution.
10
10
  */
11
11
  export type { RequestContext as CacheContext } from "../server/request-context.js";
12
12
 
@@ -101,7 +101,7 @@ export interface CacheOptions<TEnv = unknown> {
101
101
  * Return false to skip cache for this request (always fetch fresh).
102
102
  *
103
103
  * Has access to full RequestContext including env, request, params, cookies, etc.
104
- * Note: Middleware-set variables (ctx.var) may not be populated yet.
104
+ * Note: Middleware-set variables read via `ctx.get()` may not be populated yet.
105
105
  *
106
106
  * @example
107
107
  * ```typescript
@@ -123,7 +123,7 @@ export interface CacheOptions<TEnv = unknown> {
123
123
  * Bypasses default key generation AND store's keyGenerator.
124
124
  *
125
125
  * Has access to full RequestContext including env, request, params, cookies, etc.
126
- * Note: Middleware-set variables (ctx.var) may not be populated yet.
126
+ * Note: Middleware-set variables read via `ctx.get()` may not be populated yet.
127
127
  *
128
128
  * @example
129
129
  * ```typescript