@rangojs/router 0.0.0-experimental.eb0645d3 → 0.0.0-experimental.f1468e3c
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/AGENTS.md +8 -0
- package/README.md +126 -16
- package/dist/bin/rango.js +319 -95
- package/dist/testing/vitest.js +82 -0
- package/dist/vite/index.js +2724 -1053
- package/package.json +68 -14
- package/skills/api-client/SKILL.md +211 -0
- package/skills/breadcrumbs/SKILL.md +64 -2
- package/skills/bundle-analysis/SKILL.md +159 -0
- package/skills/cache-guide/SKILL.md +224 -32
- package/skills/caching/SKILL.md +279 -17
- package/skills/composability/SKILL.md +27 -3
- package/skills/css/SKILL.md +76 -0
- package/skills/debug-manifest/SKILL.md +4 -2
- package/skills/document-cache/SKILL.md +78 -55
- package/skills/handler-use/SKILL.md +11 -9
- package/skills/hooks/SKILL.md +243 -29
- package/skills/host-router/SKILL.md +83 -23
- package/skills/i18n/SKILL.md +276 -0
- package/skills/intercept/SKILL.md +68 -19
- package/skills/layout/SKILL.md +13 -9
- package/skills/links/SKILL.md +190 -23
- package/skills/loader/SKILL.md +235 -9
- package/skills/middleware/SKILL.md +18 -10
- package/skills/migrate-nextjs/SKILL.md +43 -19
- package/skills/migrate-react-router/SKILL.md +8 -2
- package/skills/mime-routes/SKILL.md +28 -1
- package/skills/observability/SKILL.md +172 -0
- package/skills/parallel/SKILL.md +18 -7
- package/skills/prerender/SKILL.md +65 -60
- package/skills/rango/SKILL.md +251 -24
- package/skills/react-compiler/SKILL.md +168 -0
- package/skills/response-routes/SKILL.md +115 -48
- package/skills/route/SKILL.md +46 -5
- package/skills/router-setup/SKILL.md +30 -8
- package/skills/scripts/SKILL.md +179 -0
- package/skills/server-actions/SKILL.md +775 -0
- package/skills/tailwind/SKILL.md +27 -3
- package/skills/testing/SKILL.md +130 -0
- package/skills/testing/bindings.md +103 -0
- package/skills/testing/cache-prerender.md +127 -0
- package/skills/testing/client-components.md +124 -0
- package/skills/testing/e2e-parity.md +125 -0
- package/skills/testing/flight.md +91 -0
- package/skills/testing/handles.md +129 -0
- package/skills/testing/loader.md +128 -0
- package/skills/testing/middleware.md +99 -0
- package/skills/testing/render-handler.md +122 -0
- package/skills/testing/response-routes.md +95 -0
- package/skills/testing/reverse-and-types.md +84 -0
- package/skills/testing/server-actions.md +107 -0
- package/skills/testing/server-tree.md +128 -0
- package/skills/testing/setup.md +123 -0
- package/skills/typesafety/SKILL.md +322 -29
- package/skills/use-cache/SKILL.md +57 -14
- package/skills/view-transitions/SKILL.md +337 -0
- package/src/__augment-tests__/augment.ts +81 -0
- package/src/__augment-tests__/augmented.check.ts +116 -0
- package/src/__internal.ts +0 -65
- package/src/browser/action-coordinator.ts +53 -36
- package/src/browser/action-fence.ts +47 -0
- package/src/browser/app-shell.ts +39 -0
- package/src/browser/connection-warmup.ts +134 -0
- package/src/browser/cookie-name.ts +140 -0
- package/src/browser/event-controller.ts +192 -150
- package/src/browser/history-state.ts +21 -0
- package/src/browser/index.ts +3 -3
- package/src/browser/invalidate-client-cache.ts +52 -0
- package/src/browser/navigation-bridge.ts +94 -25
- package/src/browser/navigation-client.ts +121 -84
- package/src/browser/navigation-store-handle.ts +38 -0
- package/src/browser/navigation-store.ts +115 -67
- package/src/browser/navigation-transaction.ts +9 -59
- package/src/browser/network-error-handler.ts +34 -7
- package/src/browser/partial-update.ts +147 -128
- package/src/browser/prefetch/cache.ts +107 -56
- package/src/browser/prefetch/fetch.ts +204 -34
- package/src/browser/prefetch/queue.ts +6 -3
- package/src/browser/rango-state.ts +158 -76
- package/src/browser/react/Link.tsx +30 -7
- package/src/browser/react/NavigationProvider.tsx +283 -118
- package/src/browser/react/ScrollRestoration.tsx +10 -6
- package/src/browser/react/deferred-handle-resolution.ts +75 -0
- package/src/browser/react/filter-segment-order.ts +66 -7
- package/src/browser/react/index.ts +0 -48
- package/src/browser/react/location-state-shared.ts +178 -8
- package/src/browser/react/location-state.ts +39 -14
- package/src/browser/react/use-action.ts +6 -15
- package/src/browser/react/use-handle.ts +17 -14
- package/src/browser/react/use-href.tsx +8 -1
- package/src/browser/react/use-link-status.ts +33 -8
- package/src/browser/react/use-navigation.ts +10 -5
- package/src/browser/react/use-params.ts +11 -11
- package/src/browser/react/use-reverse.ts +106 -0
- package/src/browser/react/use-router.ts +25 -3
- package/src/browser/react/use-search-params.ts +0 -5
- package/src/browser/react/use-segments.ts +11 -21
- package/src/browser/response-adapter.ts +99 -8
- package/src/browser/rsc-router.tsx +91 -24
- package/src/browser/scroll-restoration.ts +30 -17
- package/src/browser/segment-structure-assert.ts +2 -2
- package/src/browser/server-action-bridge.ts +214 -55
- package/src/browser/types.ts +80 -9
- package/src/browser/validate-redirect-origin.ts +43 -16
- package/src/build/collect-fallback-refs.ts +107 -0
- package/src/build/generate-manifest.ts +60 -35
- package/src/build/generate-route-types.ts +2 -1
- package/src/build/index.ts +8 -2
- package/src/build/prefix-tree-utils.ts +123 -0
- package/src/build/route-trie.ts +117 -14
- package/src/build/route-types/ast-route-extraction.ts +15 -8
- package/src/build/route-types/codegen.ts +16 -5
- package/src/build/route-types/include-resolution.ts +117 -23
- package/src/build/route-types/param-extraction.ts +6 -3
- package/src/build/route-types/per-module-writer.ts +22 -6
- package/src/build/route-types/router-processing.ts +55 -28
- package/src/build/route-types/scan-filter.ts +1 -1
- package/src/build/route-types/source-scan.ts +216 -0
- package/src/build/runtime-discovery.ts +9 -20
- package/src/cache/cache-error.ts +104 -0
- package/src/cache/cache-key-utils.ts +29 -13
- package/src/cache/cache-policy.ts +108 -34
- package/src/cache/cache-runtime.ts +224 -41
- package/src/cache/cache-scope.ts +188 -82
- package/src/cache/cache-tag.ts +103 -0
- package/src/cache/cf/cf-base64.ts +33 -0
- package/src/cache/cf/cf-cache-constants.ts +127 -0
- package/src/cache/cf/cf-cache-store.ts +1989 -378
- package/src/cache/cf/cf-cache-types.ts +349 -0
- package/src/cache/cf/cf-kv-utils.ts +46 -0
- package/src/cache/cf/cf-tag-marker-memo.ts +105 -0
- package/src/cache/cf/index.ts +6 -16
- package/src/cache/document-cache.ts +89 -21
- package/src/cache/handle-snapshot.ts +70 -0
- package/src/cache/index.ts +10 -20
- package/src/cache/memory-segment-store.ts +136 -37
- package/src/cache/profile-registry.ts +46 -31
- package/src/cache/read-through-swr.ts +56 -12
- package/src/cache/segment-codec.ts +9 -17
- package/src/cache/tag-invalidation.ts +230 -0
- package/src/cache/types.ts +37 -100
- package/src/client.rsc.tsx +44 -21
- package/src/client.tsx +36 -61
- package/src/cloudflare/index.ts +11 -0
- package/src/cloudflare/tracing.ts +109 -0
- package/src/component-utils.ts +19 -0
- package/src/components/DefaultDocument.tsx +8 -2
- package/src/context-var.ts +18 -6
- package/src/decode-loader-results.ts +52 -0
- package/src/defer.ts +196 -0
- package/src/deps/ssr.ts +0 -1
- package/src/encode-kv.ts +49 -0
- package/src/errors.ts +30 -4
- package/src/escape-script.ts +52 -0
- package/src/handle.ts +31 -23
- package/src/handles/MetaTags.tsx +62 -19
- package/src/handles/Scripts.tsx +183 -0
- package/src/handles/breadcrumbs.ts +37 -8
- package/src/handles/is-thenable.ts +19 -0
- package/src/handles/meta.ts +51 -40
- package/src/handles/script.ts +244 -0
- package/src/host/cookie-handler.ts +9 -60
- package/src/host/errors.ts +0 -24
- package/src/host/index.ts +8 -2
- package/src/host/pattern-matcher.ts +23 -52
- package/src/host/router.ts +107 -99
- package/src/host/testing.ts +40 -27
- package/src/host/types.ts +37 -4
- package/src/host/utils.ts +1 -1
- package/src/href-client.ts +137 -22
- package/src/index.rsc.ts +96 -12
- package/src/index.ts +94 -14
- package/src/internal-debug.ts +11 -10
- package/src/loader-store.ts +500 -0
- package/src/loader.rsc.ts +20 -13
- package/src/loader.ts +12 -11
- package/src/missing-id-error.ts +68 -0
- package/src/outlet-context.ts +1 -1
- package/src/outlet-provider.tsx +1 -5
- package/src/prerender/param-hash.ts +16 -16
- package/src/prerender/store.ts +32 -37
- package/src/prerender.ts +61 -6
- package/src/redirect-origin.ts +100 -0
- package/src/regex-escape.ts +8 -0
- package/src/render-error-thrower.tsx +20 -0
- package/src/response-utils.ts +34 -0
- package/src/reverse.ts +65 -40
- package/src/root-error-boundary.tsx +1 -19
- package/src/route-content-wrapper.tsx +19 -77
- package/src/route-definition/dsl-helpers.ts +304 -309
- package/src/route-definition/helper-factories.ts +28 -140
- package/src/route-definition/helpers-types.ts +82 -55
- package/src/route-definition/index.ts +1 -2
- package/src/route-definition/redirect.ts +44 -11
- package/src/route-definition/resolve-handler-use.ts +12 -1
- package/src/route-definition/use-item-types.ts +29 -0
- package/src/route-map-builder.ts +0 -16
- package/src/route-types.ts +19 -46
- package/src/router/basename.ts +14 -0
- package/src/router/content-negotiation.ts +73 -25
- package/src/router/error-handling.ts +45 -18
- package/src/router/find-match.ts +44 -23
- package/src/router/handler-context.ts +27 -43
- package/src/router/instrument.ts +350 -0
- package/src/router/intercept-resolution.ts +39 -20
- package/src/router/lazy-includes.ts +10 -47
- package/src/router/loader-resolution.ts +155 -72
- package/src/router/logging.ts +0 -6
- package/src/router/manifest.ts +18 -29
- package/src/router/match-api.ts +9 -24
- package/src/router/match-context.ts +0 -22
- package/src/router/match-handlers.ts +58 -58
- package/src/router/match-middleware/background-revalidation.ts +40 -24
- package/src/router/match-middleware/cache-lookup.ts +159 -285
- package/src/router/match-middleware/cache-store.ts +64 -52
- package/src/router/match-middleware/intercept-resolution.ts +0 -22
- package/src/router/match-middleware/segment-resolution.ts +0 -22
- package/src/router/match-pipelines.ts +1 -42
- package/src/router/match-result.ts +44 -74
- package/src/router/metrics.ts +0 -34
- package/src/router/middleware-types.ts +7 -134
- package/src/router/middleware.ts +247 -166
- package/src/router/navigation-snapshot.ts +0 -51
- package/src/router/params-util.ts +23 -0
- package/src/router/pattern-matching.ts +85 -94
- package/src/router/prefetch-cache-ttl.ts +51 -0
- package/src/router/prerender-match.ts +104 -65
- package/src/router/preview-match.ts +3 -1
- package/src/router/request-classification.ts +28 -62
- package/src/router/revalidation.ts +123 -73
- package/src/router/route-snapshot.ts +0 -1
- package/src/router/router-context.ts +3 -28
- package/src/router/router-interfaces.ts +83 -35
- package/src/router/router-options.ts +136 -5
- package/src/router/router-registry.ts +2 -5
- package/src/router/segment-resolution/fresh.ts +97 -84
- package/src/router/segment-resolution/helpers.ts +86 -6
- package/src/router/segment-resolution/loader-cache.ts +76 -39
- package/src/router/segment-resolution/revalidation.ts +272 -320
- package/src/router/segment-resolution/static-store.ts +19 -5
- package/src/router/segment-resolution/streamed-handler-telemetry.ts +52 -0
- package/src/router/segment-resolution/view-transition-default.ts +56 -0
- package/src/router/segment-resolution.ts +5 -1
- package/src/router/segment-wrappers.ts +6 -5
- package/src/router/state-cookie-name.ts +33 -0
- package/src/router/substitute-pattern-params.ts +56 -0
- package/src/router/telemetry-otel.ts +161 -199
- package/src/router/telemetry.ts +96 -19
- package/src/router/timeout.ts +0 -20
- package/src/router/tracing.ts +206 -0
- package/src/router/trie-matching.ts +162 -64
- package/src/router/types.ts +9 -63
- package/src/router/url-params.ts +0 -5
- package/src/router.ts +110 -55
- package/src/rsc/handler-context.ts +3 -2
- package/src/rsc/handler.ts +264 -220
- package/src/rsc/helpers.ts +100 -6
- package/src/rsc/index.ts +2 -5
- package/src/rsc/json-route-result.ts +38 -0
- package/src/rsc/loader-fetch.ts +114 -38
- package/src/rsc/manifest-init.ts +28 -41
- package/src/rsc/origin-guard.ts +39 -25
- package/src/rsc/progressive-enhancement.ts +117 -11
- package/src/rsc/redirect-guard.ts +99 -0
- package/src/rsc/response-cache-serve.ts +238 -0
- package/src/rsc/response-error.ts +79 -12
- package/src/rsc/response-route-handler.ts +88 -188
- package/src/rsc/rsc-rendering.ts +98 -76
- package/src/rsc/runtime-warnings.ts +23 -10
- package/src/rsc/server-action.ts +281 -117
- package/src/rsc/ssr-setup.ts +16 -0
- package/src/rsc/transition-gate.ts +89 -0
- package/src/rsc/types.ts +23 -5
- package/src/runtime-env.ts +18 -0
- package/src/search-params.ts +35 -30
- package/src/segment-loader-promise.ts +31 -4
- package/src/segment-system.tsx +254 -143
- package/src/serialize.ts +243 -0
- package/src/server/context.ts +163 -51
- package/src/server/cookie-parse.ts +32 -0
- package/src/server/cookie-store.ts +80 -5
- package/src/server/handle-store.ts +21 -38
- package/src/server/loader-registry.ts +33 -42
- package/src/server/request-context.ts +287 -178
- package/src/ssr/index.tsx +21 -16
- package/src/static-handler.ts +10 -13
- package/src/testing/cache-status.ts +162 -0
- package/src/testing/collect-handle.ts +40 -0
- package/src/testing/dispatch.ts +701 -0
- package/src/testing/dom.entry.ts +22 -0
- package/src/testing/e2e/fixture.ts +188 -0
- package/src/testing/e2e/index.ts +128 -0
- package/src/testing/e2e/matchers.ts +35 -0
- package/src/testing/e2e/page-helpers.ts +272 -0
- package/src/testing/e2e/parity.ts +387 -0
- package/src/testing/e2e/server.ts +195 -0
- package/src/testing/flight-matchers.ts +97 -0
- package/src/testing/flight-normalize.ts +11 -0
- package/src/testing/flight-runtime.d.ts +57 -0
- package/src/testing/flight-tree.ts +682 -0
- package/src/testing/flight.entry.ts +52 -0
- package/src/testing/flight.ts +257 -0
- package/src/testing/generated-routes.ts +183 -0
- package/src/testing/index.ts +105 -0
- package/src/testing/internal/context.ts +371 -0
- package/src/testing/internal/flight-client-globals.ts +30 -0
- package/src/testing/internal/seed-vars.ts +54 -0
- package/src/testing/render-handler.ts +357 -0
- package/src/testing/render-route.tsx +581 -0
- package/src/testing/run-loader.ts +385 -0
- package/src/testing/run-middleware.ts +205 -0
- package/src/testing/run-transition-when.ts +164 -0
- package/src/testing/vitest-stubs/cloudflare-email.ts +9 -0
- package/src/testing/vitest-stubs/cloudflare-workers.ts +21 -0
- package/src/testing/vitest-stubs/plugin-rsc.ts +16 -0
- package/src/testing/vitest-stubs/version.ts +5 -0
- package/src/testing/vitest.ts +305 -0
- package/src/theme/ThemeProvider.tsx +20 -58
- package/src/theme/ThemeScript.tsx +7 -9
- package/src/theme/constants.ts +52 -13
- package/src/theme/index.ts +0 -7
- package/src/theme/theme-context.ts +1 -5
- package/src/theme/theme-script.ts +22 -21
- package/src/theme/use-theme.ts +0 -3
- package/src/types/boundaries.ts +0 -35
- package/src/types/cache-types.ts +13 -4
- package/src/types/error-types.ts +30 -90
- package/src/types/global-namespace.ts +54 -41
- package/src/types/handler-context.ts +110 -62
- package/src/types/index.ts +3 -10
- package/src/types/loader-types.ts +11 -9
- package/src/types/request-scope.ts +112 -0
- package/src/types/route-config.ts +6 -50
- package/src/types/route-entry.ts +0 -6
- package/src/types/segments.ts +135 -14
- package/src/urls/include-helper.ts +9 -56
- package/src/urls/index.ts +1 -11
- package/src/urls/path-helper-types.ts +29 -12
- package/src/urls/path-helper.ts +17 -106
- package/src/urls/pattern-types.ts +36 -19
- package/src/urls/response-types.ts +22 -29
- package/src/urls/type-extraction.ts +58 -139
- package/src/urls/urls-function.ts +1 -19
- package/src/use-loader.tsx +292 -107
- package/src/vite/debug.ts +185 -0
- package/src/vite/discovery/bundle-postprocess.ts +8 -7
- package/src/vite/discovery/discover-routers.ts +126 -85
- package/src/vite/discovery/discovery-errors.ts +194 -0
- package/src/vite/discovery/gate-state.ts +171 -0
- package/src/vite/discovery/prerender-collection.ts +96 -68
- package/src/vite/discovery/route-types-writer.ts +40 -84
- package/src/vite/discovery/self-gen-tracking.ts +27 -1
- package/src/vite/discovery/state.ts +44 -0
- package/src/vite/discovery/virtual-module-codegen.ts +14 -34
- package/src/vite/index.ts +2 -0
- package/src/vite/inject-client-debug.ts +36 -0
- package/src/vite/plugin-types.ts +126 -8
- package/src/vite/plugins/cjs-to-esm.ts +16 -19
- package/src/vite/plugins/client-ref-dedup.ts +16 -11
- package/src/vite/plugins/client-ref-hashing.ts +28 -15
- package/src/vite/plugins/cloudflare-protocol-stub.ts +1 -21
- package/src/vite/plugins/expose-action-id.ts +48 -95
- package/src/vite/plugins/expose-id-utils.ts +88 -55
- package/src/vite/plugins/expose-ids/export-analysis.ts +101 -34
- package/src/vite/plugins/expose-ids/handler-transform.ts +11 -90
- package/src/vite/plugins/expose-ids/loader-transform.ts +14 -24
- package/src/vite/plugins/expose-ids/router-transform.ts +118 -29
- package/src/vite/plugins/expose-internal-ids.ts +505 -486
- package/src/vite/plugins/performance-tracks.ts +26 -25
- package/src/vite/plugins/refresh-cmd.ts +1 -1
- package/src/vite/plugins/use-cache-transform.ts +73 -83
- package/src/vite/plugins/version-injector.ts +40 -29
- package/src/vite/plugins/version-plugin.ts +37 -40
- package/src/vite/plugins/virtual-entries.ts +39 -25
- package/src/vite/rango.ts +109 -118
- package/src/vite/router-discovery.ts +718 -119
- package/src/vite/utils/ast-handler-extract.ts +26 -35
- package/src/vite/utils/banner.ts +1 -1
- package/src/vite/utils/bundle-analysis.ts +10 -15
- package/src/vite/utils/client-chunks.ts +184 -0
- package/src/vite/utils/directive-prologue.ts +40 -0
- package/src/vite/utils/forward-user-plugins.ts +171 -0
- package/src/vite/utils/manifest-utils.ts +4 -59
- package/src/vite/utils/package-resolution.ts +20 -52
- package/src/vite/utils/prerender-utils.ts +54 -39
- package/src/vite/utils/shared-utils.ts +90 -41
- package/src/browser/action-response-classifier.ts +0 -99
- package/src/browser/react/use-client-cache.ts +0 -58
- package/src/browser/shallow.ts +0 -40
- package/src/handles/index.ts +0 -7
- package/src/network-error-thrower.tsx +0 -23
- package/src/router/middleware-cookies.ts +0 -55
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: observability
|
|
3
|
+
description: Debug Rango request performance with debugPerformance, Server-Timing, structured telemetry, and tracing
|
|
4
|
+
argument-hint:
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Observability
|
|
8
|
+
|
|
9
|
+
Use this when you need to understand request latency, cache decisions,
|
|
10
|
+
revalidation behavior, loader overlap, or production traces.
|
|
11
|
+
|
|
12
|
+
Rango exposes two complementary observability surfaces:
|
|
13
|
+
|
|
14
|
+
1. **Performance timeline** (`debugPerformance`) — per-request waterfall for
|
|
15
|
+
local or targeted debugging. It prints to the console and emits
|
|
16
|
+
`Server-Timing`.
|
|
17
|
+
2. **Structured telemetry** (`telemetry`) — lifecycle events sent to a pluggable
|
|
18
|
+
sink for production monitoring, OpenTelemetry, or custom metrics.
|
|
19
|
+
|
|
20
|
+
The essentials are below. The exported `TelemetryEvent` union type
|
|
21
|
+
(`import type { TelemetryEvent } from "@rangojs/router"`) is the full event
|
|
22
|
+
contract — every event kind and its fields are typed there.
|
|
23
|
+
|
|
24
|
+
## Performance timeline
|
|
25
|
+
|
|
26
|
+
Enable globally while debugging:
|
|
27
|
+
|
|
28
|
+
```typescript
|
|
29
|
+
import { createRouter } from "@rangojs/router";
|
|
30
|
+
|
|
31
|
+
const router = createRouter({
|
|
32
|
+
document: Document,
|
|
33
|
+
urls: urlpatterns,
|
|
34
|
+
debugPerformance: true,
|
|
35
|
+
});
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Or enable for selected requests from middleware:
|
|
39
|
+
|
|
40
|
+
```typescript
|
|
41
|
+
middleware(async (ctx, next) => {
|
|
42
|
+
if (ctx.url.searchParams.has("debug")) {
|
|
43
|
+
ctx.debugPerformance();
|
|
44
|
+
}
|
|
45
|
+
await next();
|
|
46
|
+
});
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Call `ctx.debugPerformance()` before `await next()`. The request then prints a
|
|
50
|
+
shared-axis waterfall and adds a `Server-Timing` header.
|
|
51
|
+
|
|
52
|
+
Read the timeline as intervals:
|
|
53
|
+
|
|
54
|
+
- `handler:total` is the whole router request.
|
|
55
|
+
- `render:total` / `ssr-render-html` show the render pass.
|
|
56
|
+
- `loader:*` rows should overlap render work. If a loader starts only after the
|
|
57
|
+
render bar, it is serialized latency.
|
|
58
|
+
- Cache, route matching, middleware pre/post, RSC serialization, and SSR phases
|
|
59
|
+
appear as separate spans, so the slow phase is visible without guessing.
|
|
60
|
+
|
|
61
|
+
## Structured telemetry
|
|
62
|
+
|
|
63
|
+
Use telemetry when you want durable production events rather than a one-request
|
|
64
|
+
debug waterfall.
|
|
65
|
+
|
|
66
|
+
```typescript
|
|
67
|
+
import { createRouter, createConsoleSink } from "@rangojs/router";
|
|
68
|
+
|
|
69
|
+
const router = createRouter({
|
|
70
|
+
document: Document,
|
|
71
|
+
urls: urlpatterns,
|
|
72
|
+
telemetry: createConsoleSink(),
|
|
73
|
+
});
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
For OpenTelemetry — phase spans come from the `tracing` slot
|
|
77
|
+
(`createOTelTracing`), discrete-fact spans from the `telemetry` sink
|
|
78
|
+
(`createOTelSink`):
|
|
79
|
+
|
|
80
|
+
```typescript
|
|
81
|
+
import {
|
|
82
|
+
createRouter,
|
|
83
|
+
createOTelTracing,
|
|
84
|
+
createOTelSink,
|
|
85
|
+
} from "@rangojs/router";
|
|
86
|
+
import { trace } from "@opentelemetry/api";
|
|
87
|
+
|
|
88
|
+
const tracer = trace.getTracer("my-app");
|
|
89
|
+
|
|
90
|
+
const router = createRouter({
|
|
91
|
+
document: Document,
|
|
92
|
+
urls: urlpatterns,
|
|
93
|
+
tracing: createOTelTracing(tracer), // request/loader/render/… phase spans
|
|
94
|
+
telemetry: createOTelSink(tracer), // handler errors, cache decisions, …
|
|
95
|
+
});
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
On **Cloudflare Workers**, use `createCloudflareTracing` for the `tracing` slot
|
|
99
|
+
instead — it emits the same phases as native Cloudflare custom spans (in the
|
|
100
|
+
Workers trace waterfall, next to the automatic KV/D1/fetch spans), with no
|
|
101
|
+
`@opentelemetry/api` dependency:
|
|
102
|
+
|
|
103
|
+
```typescript
|
|
104
|
+
import { createRouter } from "@rangojs/router";
|
|
105
|
+
import { createCloudflareTracing } from "@rangojs/router/cloudflare";
|
|
106
|
+
|
|
107
|
+
const router = createRouter({
|
|
108
|
+
document: Document,
|
|
109
|
+
urls: urlpatterns,
|
|
110
|
+
tracing: createCloudflareTracing(), // all phases on by default
|
|
111
|
+
// tracing: createCloudflareTracing({ spans: { ssr: false } }), // toggle phases
|
|
112
|
+
});
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
Both factories return a `RouterTracingConfig` for the same `tracing` slot;
|
|
116
|
+
`telemetry` stays independent (events only, no phase spans). Phase spans:
|
|
117
|
+
`rango.request`, `rango.middleware`, `rango.action`, `rango.loader`,
|
|
118
|
+
`rango.render`, `rango.ssr` — the same phases the `debugPerformance` timeline
|
|
119
|
+
shows, co-emitted from one site. Off-platform (no Cloudflare tracing destination
|
|
120
|
+
/ no OTel SDK) every span call is a transparent pass-through, so the request
|
|
121
|
+
behaves as if tracing were off.
|
|
122
|
+
|
|
123
|
+
Custom sinks implement `emit(event)`:
|
|
124
|
+
|
|
125
|
+
```typescript
|
|
126
|
+
import { createRouter } from "@rangojs/router";
|
|
127
|
+
|
|
128
|
+
const router = createRouter({
|
|
129
|
+
document: Document,
|
|
130
|
+
urls: urlpatterns,
|
|
131
|
+
telemetry: {
|
|
132
|
+
emit(event) {
|
|
133
|
+
myMetrics.record(event);
|
|
134
|
+
},
|
|
135
|
+
},
|
|
136
|
+
});
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
Events include `request.start/end/error`, `loader.start/end/error`,
|
|
140
|
+
`handler.error`, `cache.decision`, `revalidation.decision`, `request.timeout`,
|
|
141
|
+
and `request.origin-rejected`.
|
|
142
|
+
|
|
143
|
+
## Debugging revalidation and stale data
|
|
144
|
+
|
|
145
|
+
When stale UI or unexpected partial renders are the question, use all three
|
|
146
|
+
layers together:
|
|
147
|
+
|
|
148
|
+
```typescript
|
|
149
|
+
import { createConsoleSink, createRouter } from "@rangojs/router";
|
|
150
|
+
|
|
151
|
+
const router = createRouter({
|
|
152
|
+
document: Document,
|
|
153
|
+
urls: urlpatterns,
|
|
154
|
+
debugPerformance: true,
|
|
155
|
+
telemetry: createConsoleSink(),
|
|
156
|
+
});
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
Then inspect:
|
|
160
|
+
|
|
161
|
+
- `revalidation.decision` telemetry to see which segment re-ran or skipped.
|
|
162
|
+
- cache spans / `cache.decision` events to see hit, miss, stale, and background
|
|
163
|
+
revalidation behavior.
|
|
164
|
+
- loader spans to confirm live loaders overlap the render rather than blocking
|
|
165
|
+
first paint.
|
|
166
|
+
- the `Server-Timing` header to compare local logs with browser-network timing.
|
|
167
|
+
|
|
168
|
+
## Zero-overhead defaults
|
|
169
|
+
|
|
170
|
+
`debugPerformance` is off by default, and `telemetry` emits nothing unless a sink
|
|
171
|
+
is configured. Per-request `ctx.debugPerformance()` lets you turn on the
|
|
172
|
+
waterfall only for the route, user, or query param you are investigating.
|
package/skills/parallel/SKILL.md
CHANGED
|
@@ -8,9 +8,6 @@ argument-hint: [@slot-name]
|
|
|
8
8
|
|
|
9
9
|
Parallel routes render multiple components simultaneously in named slots.
|
|
10
10
|
|
|
11
|
-
Canonical semantics reference:
|
|
12
|
-
[docs/execution-model.md](../../docs/internal/execution-model.md)
|
|
13
|
-
|
|
14
11
|
## Basic Parallel Routes
|
|
15
12
|
|
|
16
13
|
```typescript
|
|
@@ -237,6 +234,8 @@ A slot's `loading()` (whether from `handler.use` or explicit) makes that slot an
|
|
|
237
234
|
|
|
238
235
|
The `parallel` mount site has the narrowest allow-list for `handler.use` items — slots cannot bring their own middleware or layout, only `revalidate`, `loader`, `loading`, `errorBoundary`, `notFoundBoundary`, and `transition`. See [skills/handler-use](../handler-use/SKILL.md) for the full table and merge rules.
|
|
239
236
|
|
|
237
|
+
`transition` is allowed in the slot allow-list, but slot-level rendering does **not** currently apply a `<ViewTransition>` wrapper — only the layout/route wraps take effect at render time. For a modal-only morph today, use an element-level React `<ViewTransition>` inside the slot's component. The reverse direction is the useful guarantee: a layout-level `transition()` fires when the layout's default outlet content changes but **not** when a `<ParallelOutlet />` mounts new content (modal opens are not subtree updates of the layout VT). See [skills/view-transitions](../view-transitions/SKILL.md) for the wrap rules and the intercept caveat.
|
|
238
|
+
|
|
240
239
|
### Two scopes for explicit `use`: shared (broadcast) and slot-local
|
|
241
240
|
|
|
242
241
|
`parallel({...slots}, () => [...use])` runs the shared `use()` callback **once per slot** ([dsl-helpers.ts](../../src/route-definition/dsl-helpers.ts)) — items in that callback land on every slot's entry. That's the right behavior for the items the parallel allow-list permits and that accumulate (`loader`, `revalidate`, `errorBoundary`, `notFoundBoundary`, `transition`). (Slots cannot bring `middleware` or `layout` — see the allowed-types note above.)
|
|
@@ -331,6 +330,8 @@ parallel({
|
|
|
331
330
|
Control when parallel routes revalidate:
|
|
332
331
|
|
|
333
332
|
```typescript
|
|
333
|
+
import * as CartActions from "./actions/cart";
|
|
334
|
+
|
|
334
335
|
parallel(
|
|
335
336
|
{
|
|
336
337
|
"@cart": () => <CartSummary />,
|
|
@@ -338,7 +339,7 @@ parallel(
|
|
|
338
339
|
() => [
|
|
339
340
|
loader(CartLoader),
|
|
340
341
|
// Revalidate when cart actions occur
|
|
341
|
-
revalidate((
|
|
342
|
+
revalidate((ctx) => ctx.isAction(CartActions) || undefined),
|
|
342
343
|
]
|
|
343
344
|
)
|
|
344
345
|
```
|
|
@@ -347,6 +348,13 @@ Revalidating only the parallel does not re-run outer handlers/layouts.
|
|
|
347
348
|
If the slot reads `ctx.get()` data established above it, opt the outer
|
|
348
349
|
segment into revalidation as well.
|
|
349
350
|
|
|
351
|
+
A `revalidate()` callback may return a hard `boolean`, a soft
|
|
352
|
+
`{ defaultShouldRevalidate }` object, or nothing (`void` / `null` /
|
|
353
|
+
`undefined`) to defer to the next revalidator. See
|
|
354
|
+
[loader/SKILL.md#revalidate-return-shapes](../loader/SKILL.md#revalidate-return-shapes)
|
|
355
|
+
for the full contract — it's the same across `loader()`, `path()`,
|
|
356
|
+
`layout()`, `parallel()`, and `intercept()`.
|
|
357
|
+
|
|
350
358
|
### Revalidation Contracts for Parallel Dependencies
|
|
351
359
|
|
|
352
360
|
Prefer named revalidation contracts shared by both the upstream producer and
|
|
@@ -354,8 +362,10 @@ the parallel consumer:
|
|
|
354
362
|
|
|
355
363
|
```typescript
|
|
356
364
|
// revalidation-contracts.ts
|
|
357
|
-
|
|
358
|
-
|
|
365
|
+
import * as CartActions from "./actions/cart";
|
|
366
|
+
|
|
367
|
+
export const revalidateCartData = (ctx) =>
|
|
368
|
+
ctx.isAction(CartActions) || undefined;
|
|
359
369
|
|
|
360
370
|
layout(CartLayout, () => [
|
|
361
371
|
revalidate(revalidateCartData), // producer reruns
|
|
@@ -423,6 +433,7 @@ function MyLayout() {
|
|
|
423
433
|
```typescript
|
|
424
434
|
import { urls } from "@rangojs/router";
|
|
425
435
|
import { Outlet, ParallelOutlet } from "@rangojs/router/client";
|
|
436
|
+
import * as CartActions from "./actions/cart";
|
|
426
437
|
|
|
427
438
|
function ShopLayout() {
|
|
428
439
|
return (
|
|
@@ -473,7 +484,7 @@ export const shopPatterns = urls(({
|
|
|
473
484
|
() => [
|
|
474
485
|
loader(CartLoader),
|
|
475
486
|
loading(<CartSkeleton />),
|
|
476
|
-
revalidate((
|
|
487
|
+
revalidate((ctx) => ctx.isAction(CartActions) || undefined),
|
|
477
488
|
]
|
|
478
489
|
),
|
|
479
490
|
|
|
@@ -11,9 +11,6 @@ deserialization path, same segment system. The worker handles every request --
|
|
|
11
11
|
there are NO static .html or .rsc files served from assets. The worker reads
|
|
12
12
|
pre-computed Flight payloads instead of executing handler code.
|
|
13
13
|
|
|
14
|
-
Canonical semantics reference:
|
|
15
|
-
[docs/execution-model.md](../../docs/internal/execution-model.md)
|
|
16
|
-
|
|
17
14
|
## API: Prerender
|
|
18
15
|
|
|
19
16
|
### Static Route (no params)
|
|
@@ -122,6 +119,8 @@ interface BuildContext<TParams> {
|
|
|
122
119
|
use: <T>(handle: Handle<T>) => (data: T) => void; // Push handle data
|
|
123
120
|
url: URL; // Synthetic URL from pattern + params
|
|
124
121
|
pathname: string; // Pathname from synthetic URL
|
|
122
|
+
searchParams: URLSearchParams; // URLSearchParams from the synthetic URL (always empty for prerender)
|
|
123
|
+
search: {}; // Typed search params -- always {} for prerender (no real query string)
|
|
125
124
|
set(key: string, value: any): void; // Set context variable (string key)
|
|
126
125
|
set<T>(contextVar: ContextVar<T>, value: T): void; // Set typed context variable
|
|
127
126
|
get(key: string): any; // Read context variable (string key)
|
|
@@ -244,16 +243,16 @@ path("/blog/:slug", BlogPost, { name: "blog.post" }, () => [
|
|
|
244
243
|
|
|
245
244
|
## Interaction with DSL Items
|
|
246
245
|
|
|
247
|
-
| DSL item | Behavior with Prerender
|
|
248
|
-
| -------------- |
|
|
249
|
-
| `loader()` | Live at runtime, bundled normally. Use `cache()` for caching.
|
|
250
|
-
| `revalidate()` | Not allowed without Passthrough. Allowed with Passthrough.
|
|
251
|
-
| `cache()` | Orthogonal -- use on parent layouts and loaders.
|
|
252
|
-
| `layout()` | Child layouts inside path are pre-rendered. Parent layouts are live.
|
|
253
|
-
| `parallel()` | Parallel slots inside path are pre-rendered.
|
|
254
|
-
| `middleware()` | Skipped during pre-render (no request). Runs at request time for loaders.
|
|
255
|
-
| `loading()` | Ignored without Passthrough. Works for live fallback with Passthrough.
|
|
256
|
-
| `intercept()` | Pre-rendered at build time. Intercept variant stored under `/i` key alongside main segments. At runtime, the correct variant is served based on `ctx.isIntercept`. `when
|
|
246
|
+
| DSL item | Behavior with Prerender |
|
|
247
|
+
| -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
248
|
+
| `loader()` | Live at runtime, bundled normally. Use `cache()` for caching. |
|
|
249
|
+
| `revalidate()` | Not allowed without Passthrough. Allowed with Passthrough. |
|
|
250
|
+
| `cache()` | Orthogonal -- use on parent layouts and loaders. |
|
|
251
|
+
| `layout()` | Child layouts inside path are pre-rendered. Parent layouts are live. |
|
|
252
|
+
| `parallel()` | Parallel slots inside path are pre-rendered. |
|
|
253
|
+
| `middleware()` | Skipped during pre-render (no request). Runs at request time for loaders. |
|
|
254
|
+
| `loading()` | Ignored without Passthrough. Works for live fallback with Passthrough. |
|
|
255
|
+
| `intercept()` | Pre-rendered at build time. Intercept variant stored under `/i` key alongside main segments. At runtime, the correct variant is served based on `ctx.isIntercept`. `when` config conditions are skipped at build time (all intercepts are pre-rendered unconditionally). |
|
|
257
256
|
|
|
258
257
|
When Passthrough revalidation is enabled, remember that revalidation is
|
|
259
258
|
still partial: opting a child segment into revalidation does not
|
|
@@ -346,14 +345,31 @@ export const TocSidebar = Static(() => {
|
|
|
346
345
|
|
|
347
346
|
### Error behavior at build time
|
|
348
347
|
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
348
|
+
When a render throws a non-`Skip` error, it is **surfaced to the build** — never
|
|
349
|
+
baked into a frozen error page served as a 200 (issue #587). What happens next is
|
|
350
|
+
controlled by `prerender.onError` in your `rango()` options:
|
|
351
|
+
|
|
352
|
+
```ts
|
|
353
|
+
rango({ prerender: { onError: "warn" } }); // default is "fail"
|
|
354
|
+
```
|
|
355
355
|
|
|
356
|
-
|
|
356
|
+
| Handler outcome | `onError: "fail"` (default) | `onError: "warn"` |
|
|
357
|
+
| --------------------------- | -------------------------------------------- | -------------------------------- |
|
|
358
|
+
| JSX / `null` | Normal prerender entry, log OK | Normal prerender entry, log OK |
|
|
359
|
+
| `return ctx.passthrough()` | Skip entry, log PASS (Passthrough routes) | Skip entry, log PASS |
|
|
360
|
+
| `throw new Skip("reason")` | Skip entry, log SKIP, continue | Skip entry, log SKIP, continue |
|
|
361
|
+
| `throw new Error("reason")` | Log FAIL, stop ALL pre-rendering, fail build | Log WARN, skip the URL, continue |
|
|
362
|
+
|
|
363
|
+
With `"warn"` the errored entry is logged and left un-baked (never served as a baked
|
|
364
|
+
200 error page). `"warn"` is a build-unblock, not a runtime contract: the route falls
|
|
365
|
+
through to normal resolution — it may render live (its handler is still bundled) or
|
|
366
|
+
404 (once other baked entries trigger prerender handler eviction), so the outcome
|
|
367
|
+
depends on the rest of the build, and a skipped `Static()` handler's evicted code can
|
|
368
|
+
surface as an error. For DEFINED runtime behavior reach for `Passthrough()` (a live
|
|
369
|
+
fallback) or `throw new Skip()` (an intentional skip — works in the render fn, not
|
|
370
|
+
only `getParams()`); otherwise prefer the default `"fail"`.
|
|
371
|
+
|
|
372
|
+
Both `Skip` and hard errors propagate to the router's `onError` callback with phase
|
|
357
373
|
`"prerender"` or `"static"`.
|
|
358
374
|
|
|
359
375
|
### Build logs
|
|
@@ -361,21 +377,23 @@ Both error types propagate to the router's `onError` callback with phase
|
|
|
361
377
|
The build produces per-URL timing logs:
|
|
362
378
|
|
|
363
379
|
```
|
|
364
|
-
[
|
|
365
|
-
[
|
|
366
|
-
[
|
|
367
|
-
[
|
|
368
|
-
[
|
|
369
|
-
|
|
370
|
-
[
|
|
371
|
-
[
|
|
372
|
-
[
|
|
373
|
-
[
|
|
380
|
+
[rango] Pre-rendering 12 URL(s) (concurrency: 4)...
|
|
381
|
+
[rango] OK /articles/hello (42ms)
|
|
382
|
+
[rango] PASS /articles/remote-only (5ms) - live fallback
|
|
383
|
+
[rango] SKIP /articles/draft-post (3ms) - Article is a draft
|
|
384
|
+
[rango] Pre-render complete: 11 done, 1 skipped (1204ms total)
|
|
385
|
+
|
|
386
|
+
[rango] Rendering 3 static handler(s)...
|
|
387
|
+
[rango] OK DocsLayout (28ms)
|
|
388
|
+
[rango] SKIP TocSidebar (1ms) - Not ready
|
|
389
|
+
[rango] Static render complete: 2 done, 1 skipped (120ms total)
|
|
374
390
|
```
|
|
375
391
|
|
|
376
|
-
A `FAIL` line is logged per-URL when a handler throws a non-Skip error
|
|
377
|
-
error is re-thrown immediately, so no
|
|
378
|
-
stops at the first failure.
|
|
392
|
+
A `FAIL` line is logged per-URL when a handler throws a non-Skip error (with the
|
|
393
|
+
default `prerender.onError: "fail"`). The error is re-thrown immediately, so no
|
|
394
|
+
summary line is printed — the build stops at the first failure. Under
|
|
395
|
+
`prerender.onError: "warn"` the same case logs a `WARN` line, skips that URL, and
|
|
396
|
+
the build continues.
|
|
379
397
|
|
|
380
398
|
### Dev mode behavior
|
|
381
399
|
|
|
@@ -466,9 +484,9 @@ export const Product = Passthrough(ProductDef, async (ctx) => {
|
|
|
466
484
|
Passthrough entries are logged distinctly:
|
|
467
485
|
|
|
468
486
|
```
|
|
469
|
-
[
|
|
470
|
-
[
|
|
471
|
-
[
|
|
487
|
+
[rango] OK /blog/a (42ms)
|
|
488
|
+
[rango] PASS /blog/b (3ms) - live fallback
|
|
489
|
+
[rango] OK /blog/c (38ms)
|
|
472
490
|
```
|
|
473
491
|
|
|
474
492
|
## Edge Cases and Constraints
|
|
@@ -591,12 +609,12 @@ At runtime, the cache-lookup middleware checks `ctx.isIntercept`:
|
|
|
591
609
|
(filtered by `namespace?.startsWith("intercept:")`) and sets up slots.
|
|
592
610
|
- **Direct navigation**: looks up `paramHash` (no suffix). Standard prerender path.
|
|
593
611
|
- **Intercept miss (no `/i` entry)**: falls through to the normal pipeline so
|
|
594
|
-
intercept-resolution middleware runs live. This handles `when
|
|
612
|
+
intercept-resolution middleware runs live. This handles `when` config conditions
|
|
595
613
|
that prevented pre-rendering.
|
|
596
614
|
|
|
597
|
-
The `when
|
|
615
|
+
The `when` config selector receives an `InterceptSelectorContext` with `from.pathname`
|
|
598
616
|
which is unknown at build time. All intercepts are pre-rendered unconditionally;
|
|
599
|
-
`when
|
|
617
|
+
`when` is evaluated at runtime by the intercept-resolution middleware.
|
|
600
618
|
|
|
601
619
|
### Example: Pre-rendered route with intercept
|
|
602
620
|
|
|
@@ -615,10 +633,13 @@ layout(ShopLayout, () => [
|
|
|
615
633
|
|
|
616
634
|
// Intercept detail from shop index into a modal.
|
|
617
635
|
// At build time, this is resolved and stored under the /i key.
|
|
618
|
-
intercept(
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
636
|
+
intercept(
|
|
637
|
+
"@modal",
|
|
638
|
+
".detail",
|
|
639
|
+
<ProductModal />,
|
|
640
|
+
{ when: ({ from }) => from.pathname === "/shop" },
|
|
641
|
+
() => [loader(ProductLoader)],
|
|
642
|
+
),
|
|
622
643
|
])
|
|
623
644
|
```
|
|
624
645
|
|
|
@@ -640,16 +661,7 @@ At runtime, the cache-lookup middleware uses these flags:
|
|
|
640
661
|
|
|
641
662
|
## Contributor Checklist
|
|
642
663
|
|
|
643
|
-
Before changing prerender behavior,
|
|
644
|
-
|
|
645
|
-
### Docs to re-read
|
|
646
|
-
|
|
647
|
-
- [Prerender API design](../../docs/prerender-api-design.md) -- canonical
|
|
648
|
-
architecture: build-time flow, runtime flow, storage, Passthrough, intercept
|
|
649
|
-
- [Execution model](../../docs/internal/execution-model.md) -- handler-first
|
|
650
|
-
ordering, middleware scope, context visibility rules
|
|
651
|
-
- [Semantic change checklist](../../docs/internal/semantic-change-checklist.md)
|
|
652
|
-
-- gate for any change to execution semantics
|
|
664
|
+
Before changing prerender behavior, run these tests.
|
|
653
665
|
|
|
654
666
|
### Tests to run
|
|
655
667
|
|
|
@@ -676,10 +688,3 @@ pnpm --filter @rangojs/router exec playwright test handler-first
|
|
|
676
688
|
dev/build-only and do not need a production counterpart.
|
|
677
689
|
- Behavioral assertions (rendered content, loader freshness, Passthrough
|
|
678
690
|
fallback, intercept variant selection) must work in the production build.
|
|
679
|
-
|
|
680
|
-
## Maintenance References
|
|
681
|
-
|
|
682
|
-
- [Stability next steps plan](../../docs/internal/stability-next-steps-plan.md)
|
|
683
|
-
-- completed parity and cleanup pass (reference for decisions made)
|
|
684
|
-
- [Test quality baseline](../../docs/internal/test-quality-baseline.md) --
|
|
685
|
-
measured test inventory, sleep debt, production coverage gaps
|