@rangojs/router 0.17.0 → 0.18.0

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 (152) hide show
  1. package/README.md +3 -2
  2. package/dist/types/browser/cookie-name.d.ts +6 -0
  3. package/dist/types/browser/history-state.d.ts +16 -0
  4. package/dist/types/cache/cache-key-utils.d.ts +17 -2
  5. package/dist/types/cache/cache-policy.d.ts +17 -0
  6. package/dist/types/cache/cache-scope.d.ts +98 -14
  7. package/dist/types/cache/cache-tag.d.ts +92 -7
  8. package/dist/types/cache/cf/cf-base64.d.ts +6 -0
  9. package/dist/types/cache/cf/cf-cache-constants.d.ts +11 -0
  10. package/dist/types/cache/cf/cf-cache-store.d.ts +185 -44
  11. package/dist/types/cache/cf/cf-cache-types.d.ts +31 -4
  12. package/dist/types/cache/cf/cf-shell-frame.d.ts +95 -0
  13. package/dist/types/cache/cf/cf-tag-marker-memo.d.ts +34 -0
  14. package/dist/types/cache/handle-snapshot.d.ts +4 -3
  15. package/dist/types/cache/index.d.ts +1 -0
  16. package/dist/types/cache/isolate-tag-memo.d.ts +149 -0
  17. package/dist/types/cache/shell-memo.d.ts +178 -0
  18. package/dist/types/cache/shell-snapshot.d.ts +110 -21
  19. package/dist/types/cache/tag-invalidation.d.ts +30 -3
  20. package/dist/types/cache/types.d.ts +207 -43
  21. package/dist/types/cache/vercel/vercel-cache-store.d.ts +111 -13
  22. package/dist/types/prerender/build-shell-capture.d.ts +11 -4
  23. package/dist/types/router/instrument.d.ts +8 -0
  24. package/dist/types/router/middleware-types.d.ts +6 -1
  25. package/dist/types/router/segment-resolution/loader-cache.d.ts +40 -11
  26. package/dist/types/router/segment-resolution/loader-snapshot.d.ts +21 -10
  27. package/dist/types/router/segment-resolution/mask-nested.d.ts +65 -24
  28. package/dist/types/rsc/full-payload.d.ts +14 -0
  29. package/dist/types/rsc/handler.d.ts +1 -1
  30. package/dist/types/rsc/shell-build-manifest.d.ts +8 -0
  31. package/dist/types/rsc/shell-capture-constants.d.ts +53 -6
  32. package/dist/types/rsc/shell-capture.d.ts +146 -15
  33. package/dist/types/rsc/shell-serve.d.ts +140 -17
  34. package/dist/types/rsc/types.d.ts +7 -0
  35. package/dist/types/server/context.d.ts +109 -15
  36. package/dist/types/server/cookie-store.d.ts +21 -0
  37. package/dist/types/server/request-context.d.ts +159 -33
  38. package/dist/types/ssr/index.d.ts +9 -0
  39. package/dist/types/ssr/ssr-root.d.ts +9 -8
  40. package/dist/types/testing/flight.entry.d.ts +7 -0
  41. package/dist/types/testing/run-loader.d.ts +18 -3
  42. package/dist/types/testing/serve-shell-request.d.ts +132 -0
  43. package/dist/types/testing/shell-status.d.ts +23 -10
  44. package/dist/types/types/handler-context.d.ts +14 -1
  45. package/dist/types/urls/pattern-types.d.ts +22 -18
  46. package/dist/types/vite/router-discovery.d.ts +29 -2
  47. package/dist/vite/index.js +46 -9
  48. package/package.json +1 -1
  49. package/skills/breadcrumbs/SKILL.md +17 -7
  50. package/skills/cache-guide/SKILL.md +123 -51
  51. package/skills/caching/SKILL.md +253 -23
  52. package/skills/catalog.json +1 -1
  53. package/skills/client-urls/SKILL.md +11 -6
  54. package/skills/cloudflare/SKILL.md +15 -0
  55. package/skills/comparison/references/framework-comparison.md +44 -32
  56. package/skills/defer-hydration/SKILL.md +50 -30
  57. package/skills/deployment-caching/SKILL.md +5 -2
  58. package/skills/document-cache/SKILL.md +8 -2
  59. package/skills/handler-use/SKILL.md +2 -0
  60. package/skills/hooks/handle-and-actions.md +3 -1
  61. package/skills/hooks/state.md +3 -1
  62. package/skills/loader/SKILL.md +161 -39
  63. package/skills/middleware/SKILL.md +16 -9
  64. package/skills/migrate-nextjs/SKILL.md +67 -36
  65. package/skills/migrate-react-router/SKILL.md +2 -1
  66. package/skills/migrate-react-router/component-migration.md +3 -1
  67. package/skills/migrate-react-router/data-and-actions.md +3 -1
  68. package/skills/migrate-react-router/route-mapping.md +7 -4
  69. package/skills/observability/SKILL.md +64 -0
  70. package/skills/parallel/SKILL.md +13 -8
  71. package/skills/ppr/SKILL.md +655 -363
  72. package/skills/prerender/SKILL.md +27 -14
  73. package/skills/rango/SKILL.md +52 -33
  74. package/skills/route/SKILL.md +12 -7
  75. package/skills/router-setup/SKILL.md +4 -2
  76. package/skills/scripts/SKILL.md +8 -1
  77. package/skills/server-actions/SKILL.md +11 -0
  78. package/skills/shell-manifest/SKILL.md +21 -12
  79. package/skills/testing/SKILL.md +25 -21
  80. package/skills/testing/cache-prerender.md +15 -14
  81. package/skills/testing/loader.md +18 -1
  82. package/skills/testing/serve-shell-request.md +188 -0
  83. package/skills/theme/SKILL.md +52 -4
  84. package/skills/typesafety/env-and-bindings.md +10 -2
  85. package/skills/use-cache/SKILL.md +39 -16
  86. package/skills/vercel/SKILL.md +14 -2
  87. package/skills/view-transitions/SKILL.md +1 -1
  88. package/src/browser/cookie-name.ts +23 -0
  89. package/src/browser/history-state.ts +23 -0
  90. package/src/browser/rsc-router.tsx +5 -0
  91. package/src/cache/cache-key-utils.ts +22 -2
  92. package/src/cache/cache-policy.ts +22 -0
  93. package/src/cache/cache-runtime.ts +34 -7
  94. package/src/cache/cache-scope.ts +345 -33
  95. package/src/cache/cache-tag.ts +375 -11
  96. package/src/cache/cf/cf-base64.ts +36 -4
  97. package/src/cache/cf/cf-cache-constants.ts +12 -0
  98. package/src/cache/cf/cf-cache-store.ts +990 -348
  99. package/src/cache/cf/cf-cache-types.ts +32 -4
  100. package/src/cache/cf/cf-shell-frame.ts +258 -0
  101. package/src/cache/cf/cf-tag-marker-memo.ts +143 -39
  102. package/src/cache/handle-snapshot.ts +4 -3
  103. package/src/cache/index.ts +2 -0
  104. package/src/cache/isolate-tag-memo.ts +308 -0
  105. package/src/cache/shell-memo.ts +341 -0
  106. package/src/cache/shell-snapshot.ts +217 -27
  107. package/src/cache/tag-invalidation.ts +104 -19
  108. package/src/cache/types.ts +211 -43
  109. package/src/cache/vercel/vercel-cache-store.ts +545 -61
  110. package/src/prerender/build-shell-capture.ts +65 -11
  111. package/src/route-definition/dsl-helpers.ts +4 -3
  112. package/src/router/handler-context.ts +38 -4
  113. package/src/router/instrument.ts +54 -2
  114. package/src/router/intercept-resolution.ts +19 -7
  115. package/src/router/loader-resolution.ts +63 -32
  116. package/src/router/match-api.ts +28 -9
  117. package/src/router/match-handlers.ts +5 -0
  118. package/src/router/match-middleware/cache-lookup.ts +17 -0
  119. package/src/router/match-middleware/cache-store.ts +31 -11
  120. package/src/router/middleware-types.ts +6 -1
  121. package/src/router/middleware.ts +23 -4
  122. package/src/router/prerender-match.ts +6 -0
  123. package/src/router/segment-resolution/fresh.ts +18 -9
  124. package/src/router/segment-resolution/helpers.ts +4 -2
  125. package/src/router/segment-resolution/loader-cache.ts +227 -56
  126. package/src/router/segment-resolution/loader-snapshot.ts +203 -51
  127. package/src/router/segment-resolution/mask-nested.ts +136 -42
  128. package/src/router/segment-resolution/revalidation.ts +27 -10
  129. package/src/rsc/full-payload.ts +25 -1
  130. package/src/rsc/handler.ts +14 -2
  131. package/src/rsc/progressive-enhancement.ts +3 -2
  132. package/src/rsc/response-cache-serve.ts +9 -6
  133. package/src/rsc/rsc-rendering.ts +601 -181
  134. package/src/rsc/shell-build-manifest.ts +27 -9
  135. package/src/rsc/shell-capture-constants.ts +60 -6
  136. package/src/rsc/shell-capture.ts +1001 -250
  137. package/src/rsc/shell-serve.ts +316 -34
  138. package/src/rsc/types.ts +7 -0
  139. package/src/server/context.ts +219 -28
  140. package/src/server/cookie-store.ts +87 -62
  141. package/src/server/request-context.ts +263 -38
  142. package/src/ssr/index.tsx +96 -37
  143. package/src/ssr/ssr-root.tsx +9 -8
  144. package/src/testing/flight.entry.ts +14 -0
  145. package/src/testing/run-loader.ts +63 -5
  146. package/src/testing/serve-shell-request.ts +378 -0
  147. package/src/testing/shell-status.ts +34 -12
  148. package/src/theme/ThemeProvider.tsx +7 -6
  149. package/src/types/handler-context.ts +14 -1
  150. package/src/urls/pattern-types.ts +22 -18
  151. package/src/vite/discovery/shell-prerender-phase.ts +9 -0
  152. package/src/vite/router-discovery.ts +14 -4
@@ -81,16 +81,16 @@ function loadManifest(): Promise<ShellManifestModule | null> {
81
81
  }
82
82
 
83
83
  /**
84
- * Per-spec verdict memo for the version + integrity gates. A manifest record
84
+ * Per-spec verdict memo for the version + structural gates. A manifest record
85
85
  * is immutable for the process lifetime (content-hashed asset module), so its
86
- * gate verdict is constant — without this, EVERY request to a baked ppr route
87
- * re-decodes the full prelude base64 (hasIntactShellPayload) on the hot path:
88
- * a fresh build hit never populates the runtime store, so the store MISS +
89
- * read-through is the steady state, not a warm-up. Only the per-request
90
- * gates (tag markers, staleness) stay outside the memo. `null` memoizes a
91
- * failed verdict — deterministically invalid, don't re-pay the decode.
92
- * Spec-only keying is sound because buildVersion is process-constant on the
93
- * manifest path (folded into the shipped worker; dev never loads a manifest).
86
+ * gate verdict is constant: a fresh build hit never populates the runtime
87
+ * store, so the store MISS + read-through is the steady state, not a warm-up.
88
+ * Only the per-request gates (tag markers, staleness) stay outside the memo;
89
+ * the document HIT decodes the prelude once per serve (openShellDocument),
90
+ * partial replay never does. `null` memoizes a failed verdict —
91
+ * deterministically invalid. Spec-only keying is sound because buildVersion is
92
+ * process-constant on the manifest path (folded into the shipped worker; dev
93
+ * never loads a manifest).
94
94
  */
95
95
  const validatedSpecs = new Map<string, ValidatedBuildShellEntry | null>();
96
96
 
@@ -259,6 +259,24 @@ async function fetchDevShellEntry(
259
259
  }
260
260
  }
261
261
 
262
+ /**
263
+ * Whether a build-time shell exists for `pathname` (the caller checks the
264
+ * request is search-less, like the entries lookupBuildShell serves): a
265
+ * manifest entry for the path in production, a Prerender route in dev. No
266
+ * asset load and no dev capture: it only decides whether a request that
267
+ * cannot read the build shell deserves a warning.
268
+ */
269
+ export async function hasBuildShell(
270
+ pathname: string,
271
+ dev?: DevShellLookup,
272
+ ): Promise<boolean> {
273
+ if (globalThis.__loadShellManifestModule === undefined) {
274
+ return dev?.isPrerenderRoute === true;
275
+ }
276
+ const mod = await loadManifest();
277
+ return mod?.default[buildShellManifestKey(pathname)] !== undefined;
278
+ }
279
+
262
280
  /**
263
281
  * Look up the baked shell entry for a request, applying every serve gate:
264
282
  * search-less requests only (the build captured the bare pathname; a
@@ -14,18 +14,72 @@
14
14
  * costs latency-to-HIT only — never a served response — and 5s spuriously
15
15
  * refused legitimately-slow deferred shell material (a real storefront's meta
16
16
  * chains settle at ~7s). Ceiling math: workerd's waitUntil lifetime is ~30s
17
- * past response completion, and a guaranteed two-attempt envelope needs
18
- * 2x budget + the in-place retry delay + store I/O, i.e. budget <= ~14s. The
19
- * 15s default deliberately sits just past that: attempt 1 always gets its
20
- * full 15s, but when it consumed the whole budget the in-place RETRY may be
21
- * truncated by the platform kill on workerd — degrading to the existing
22
- * best-effort contract (the key stays MISS; a later request re-captures).
17
+ * past response completion. An attempt that consumed the whole budget is not
18
+ * retried in place (shell-capture.ts noShellCauses), so the envelope is one
19
+ * budget plus store I/O; the retry follows only an attempt that ended early
20
+ * (a cold-module abort). Past the ceiling the platform kill degrades to the
21
+ * existing best-effort contract (the key stays MISS; a later request
22
+ * re-captures).
23
23
  * Node/dev and build-time captures have no waitUntil ceiling. The per-route
24
24
  * `ppr.captureTimeout` knob remains for tightening below the default. See
25
25
  * docs/design/ppr-shell-resume.md (Cost model).
26
26
  */
27
27
  export const SHELL_CAPTURE_MAX_WAIT_MS = 15_000;
28
28
 
29
+ /**
30
+ * The shell key for one request partition (cache-scope.ts
31
+ * resolveShellPartition): the route cache() `key()` or store keyGenerator
32
+ * result that partitions the route's record partitions its shell too, so
33
+ * each partition captures and serves its own. Here, in the leaf module, so
34
+ * the testing helper `shellCacheKey` (testing/shell-status.ts) calls it
35
+ * without pulling shell-serve.ts.
36
+ *
37
+ * The partition is URI-encoded: it is request-derived, and raw it could end
38
+ * in a suffix another key is built with (navigationShellKey), so a partition
39
+ * `gold:navigation` named gold's navigation entry and its document shell
40
+ * replayed to gold's navigations. Encoded, it holds no `:` or `|`.
41
+ */
42
+ export function partitionShellKey(key: string, partition: string): string {
43
+ return `${key}|${encodeURIComponent(partition)}`;
44
+ }
45
+
46
+ /**
47
+ * The navigation-only entry beside a document shell key (a cold partial
48
+ * request's capture, rsc-rendering.ts). A suffix after the (encoded)
49
+ * partition: partitionShellKey keeps the two unambiguous.
50
+ */
51
+ export function navigationShellKey(key: string): string {
52
+ return `${key}:navigation`;
53
+ }
54
+
55
+ /**
56
+ * Fixed number of macrotask hops between `quiesce` resolving and the abort. These
57
+ * give React's fizz worker turns to flush the settled shell into the prelude and
58
+ * mark still-pending boundaries as POSTPONED (rather than errored) before
59
+ * controller.abort() lands. Not a wall-clock wait. Taken by captureShellHTML
60
+ * (ssr/index.tsx) and by the testing SSR stub (testing/serve-shell-request.ts),
61
+ * so the stub freezes the same Flight the real capture would.
62
+ *
63
+ * Why 16 and not the original 2: under the REPLAY-ONLY capture model
64
+ * (docs/design/ppr-shell-resume.md), the capture Flight render serializes ring-3
65
+ * cached segments that are ALREADY serialized, so it emits the whole shell payload
66
+ * in the first tick and the gate declares quiesce almost immediately (~a few ms).
67
+ * On the old fresh-execution path the Flight dribbled out as handlers ran, so
68
+ * Flight-quiet effectively meant "the shell has rendered" and 2 hops sufficed.
69
+ *
70
+ * Hops alone are NOT render-readiness: fizz cannot emit even <html> until the
71
+ * payload root settles, nor complete a shell whose client components are
72
+ * still loading — real module-runner I/O in dev (100ms+ cold), which no fixed
73
+ * count of near-zero-cost task hops can buy. captureShellHTML therefore
74
+ * awaits the payload-settled signal (SsrRootOptions.onPayloadSettled) and
75
+ * then the client-reference loads in flight in the isolate (captureClientLoads),
76
+ * deadline-bounded, between quiesce and these hops; the hops then only flush
77
+ * the settled tree and mark pending boundaries POSTPONED. Still task-based
78
+ * (masked loaders never emit, so more hops never lets a hole settle). Bounded
79
+ * by maxWaitMs end to end.
80
+ */
81
+ export const POST_QUIESCE_TASK_HOPS = 16;
82
+
29
83
  /**
30
84
  * Hard cap on one capture TASK — runShellCapture end to end (both attempts +
31
85
  * the in-place retry delay). SHELL_CAPTURE_MAX_WAIT_MS arms only inside