@rangojs/router 0.0.0-experimental.97 → 0.0.0-experimental.98914650
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 +24 -9
- package/dist/bin/rango.js +157 -63
- package/dist/testing/vitest.js +82 -0
- package/dist/vite/index.js +1584 -639
- package/package.json +71 -21
- package/skills/api-client/SKILL.md +211 -0
- package/skills/breadcrumbs/SKILL.md +60 -0
- package/skills/bundle-analysis/SKILL.md +159 -0
- package/skills/cache-guide/SKILL.md +222 -30
- package/skills/caching/SKILL.md +263 -8
- package/skills/composability/SKILL.md +27 -2
- package/skills/css/SKILL.md +76 -0
- package/skills/document-cache/SKILL.md +78 -55
- package/skills/handler-use/SKILL.md +3 -1
- package/skills/hooks/SKILL.md +235 -28
- package/skills/host-router/SKILL.md +122 -22
- package/skills/i18n/SKILL.md +276 -0
- package/skills/intercept/SKILL.md +29 -5
- package/skills/layout/SKILL.md +13 -9
- package/skills/links/SKILL.md +173 -17
- package/skills/loader/SKILL.md +170 -23
- package/skills/middleware/SKILL.md +16 -10
- package/skills/migrate-nextjs/SKILL.md +38 -16
- package/skills/mime-routes/SKILL.md +27 -0
- package/skills/observability/SKILL.md +137 -0
- package/skills/parallel/SKILL.md +11 -7
- package/skills/prerender/SKILL.md +14 -33
- package/skills/rango/SKILL.md +250 -25
- package/skills/react-compiler/SKILL.md +168 -0
- package/skills/response-routes/SKILL.md +114 -47
- package/skills/route/SKILL.md +42 -5
- package/skills/router-setup/SKILL.md +3 -3
- package/skills/server-actions/SKILL.md +78 -42
- package/skills/tailwind/SKILL.md +27 -3
- package/skills/testing/SKILL.md +129 -0
- package/skills/testing/bindings.md +89 -0
- package/skills/testing/cache-prerender.md +124 -0
- package/skills/testing/client-components.md +122 -0
- package/skills/testing/e2e-parity.md +125 -0
- package/skills/testing/flight.md +92 -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 +121 -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 +120 -0
- package/skills/typesafety/SKILL.md +316 -26
- package/skills/use-cache/SKILL.md +36 -5
- package/skills/vercel/SKILL.md +107 -0
- package/skills/view-transitions/SKILL.md +294 -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 +14 -27
- package/src/browser/cookie-name.ts +140 -0
- package/src/browser/event-controller.ts +37 -143
- 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 +30 -59
- package/src/browser/navigation-client.ts +96 -84
- package/src/browser/navigation-store-handle.ts +38 -0
- package/src/browser/navigation-store.ts +32 -82
- package/src/browser/navigation-transaction.ts +9 -59
- package/src/browser/partial-update.ts +60 -127
- package/src/browser/prefetch/cache.ts +82 -72
- package/src/browser/prefetch/fetch.ts +108 -33
- package/src/browser/prefetch/queue.ts +6 -3
- package/src/browser/rango-state.ts +157 -115
- package/src/browser/react/Link.tsx +0 -2
- package/src/browser/react/NavigationProvider.tsx +41 -48
- package/src/browser/react/ScrollRestoration.tsx +10 -6
- package/src/browser/react/filter-segment-order.ts +0 -2
- package/src/browser/react/index.ts +0 -48
- package/src/browser/react/location-state-shared.ts +166 -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-link-status.ts +0 -4
- package/src/browser/react/use-navigation.ts +0 -3
- 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 +20 -5
- package/src/browser/react/use-search-params.ts +0 -5
- package/src/browser/react/use-segments.ts +0 -13
- package/src/browser/response-adapter.ts +52 -1
- package/src/browser/rsc-router.tsx +70 -34
- package/src/browser/scroll-restoration.ts +22 -14
- package/src/browser/segment-structure-assert.ts +2 -2
- package/src/browser/server-action-bridge.ts +168 -44
- package/src/browser/types.ts +36 -21
- 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 +3 -0
- package/src/build/index.ts +8 -2
- package/src/build/prefix-tree-utils.ts +123 -0
- package/src/build/route-trie.ts +89 -10
- package/src/build/route-types/codegen.ts +4 -4
- package/src/build/route-types/include-resolution.ts +1 -1
- package/src/build/route-types/param-extraction.ts +6 -3
- package/src/build/route-types/per-module-writer.ts +7 -4
- package/src/build/route-types/router-processing.ts +122 -22
- package/src/build/route-types/scan-filter.ts +1 -1
- package/src/build/route-types/source-scan.ts +118 -0
- package/src/build/runtime-discovery.ts +9 -20
- package/src/cache/cache-error.ts +104 -0
- package/src/cache/cache-policy.ts +68 -28
- package/src/cache/cache-runtime.ts +134 -32
- package/src/cache/cache-scope.ts +100 -74
- package/src/cache/cache-tag.ts +98 -0
- package/src/cache/cf/cf-cache-store.ts +2255 -238
- package/src/cache/cf/index.ts +6 -16
- package/src/cache/document-cache.ts +61 -20
- package/src/cache/handle-snapshot.ts +63 -0
- package/src/cache/index.ts +22 -20
- package/src/cache/memory-segment-store.ts +136 -37
- package/src/cache/profile-registry.ts +6 -30
- package/src/cache/read-through-swr.ts +41 -11
- package/src/cache/segment-codec.ts +0 -16
- package/src/cache/tag-invalidation.ts +230 -0
- package/src/cache/types.ts +33 -100
- package/src/cache/vercel/index.ts +11 -0
- package/src/cache/vercel/vercel-cache-store.ts +799 -0
- package/src/client.rsc.tsx +6 -21
- package/src/client.tsx +25 -61
- package/src/component-utils.ts +19 -0
- package/src/context-var.ts +17 -5
- package/src/decode-loader-results.ts +36 -0
- package/src/defer.ts +196 -0
- package/src/deps/ssr.ts +0 -1
- package/src/errors.ts +30 -4
- package/src/handle.ts +31 -23
- package/src/handles/MetaTags.tsx +0 -14
- package/src/handles/breadcrumbs.ts +16 -5
- package/src/handles/meta.ts +0 -39
- package/src/host/cookie-handler.ts +0 -36
- package/src/host/errors.ts +0 -24
- package/src/host/index.ts +8 -2
- package/src/host/pattern-matcher.ts +7 -50
- 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 +63 -9
- package/src/index.ts +64 -9
- package/src/internal-debug.ts +2 -4
- 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/network-error-thrower.tsx +1 -6
- package/src/outlet-provider.tsx +1 -5
- package/src/prerender/param-hash.ts +10 -11
- package/src/prerender/store.ts +32 -37
- package/src/prerender.ts +61 -6
- package/src/redirect-origin.ts +100 -0
- package/src/response-utils.ts +9 -0
- package/src/reverse.ts +65 -40
- package/src/root-error-boundary.tsx +1 -19
- package/src/route-content-wrapper.tsx +7 -72
- package/src/route-definition/dsl-helpers.ts +244 -281
- package/src/route-definition/helper-factories.ts +29 -139
- package/src/route-definition/helpers-types.ts +40 -17
- package/src/route-definition/redirect.ts +43 -9
- package/src/route-definition/resolve-handler-use.ts +6 -0
- package/src/route-definition/use-item-types.ts +32 -0
- package/src/route-map-builder.ts +0 -16
- package/src/route-types.ts +19 -41
- package/src/router/basename.ts +14 -0
- package/src/router/content-negotiation.ts +15 -15
- package/src/router/error-handling.ts +13 -17
- package/src/router/find-match.ts +44 -23
- package/src/router/handler-context.ts +4 -41
- package/src/router/intercept-resolution.ts +14 -19
- package/src/router/lazy-includes.ts +9 -46
- package/src/router/loader-resolution.ts +91 -46
- package/src/router/logging.ts +0 -6
- package/src/router/manifest.ts +18 -29
- package/src/router/match-api.ts +0 -20
- package/src/router/match-context.ts +0 -22
- package/src/router/match-handlers.ts +57 -58
- package/src/router/match-middleware/background-revalidation.ts +0 -7
- package/src/router/match-middleware/cache-lookup.ts +150 -271
- package/src/router/match-middleware/cache-store.ts +3 -33
- 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 +31 -80
- package/src/router/metrics.ts +0 -34
- package/src/router/middleware-types.ts +5 -112
- package/src/router/middleware.ts +118 -133
- package/src/router/navigation-snapshot.ts +0 -51
- package/src/router/params-util.ts +23 -0
- package/src/router/pattern-matching.ts +62 -67
- package/src/router/prerender-match.ts +99 -63
- package/src/router/preview-match.ts +3 -1
- package/src/router/request-classification.ts +28 -62
- package/src/router/revalidation.ts +50 -56
- package/src/router/route-snapshot.ts +0 -1
- package/src/router/router-context.ts +0 -27
- package/src/router/router-interfaces.ts +68 -35
- package/src/router/router-options.ts +55 -1
- package/src/router/router-registry.ts +2 -5
- package/src/router/segment-resolution/fresh.ts +44 -63
- package/src/router/segment-resolution/helpers.ts +34 -0
- package/src/router/segment-resolution/loader-cache.ts +40 -37
- package/src/router/segment-resolution/revalidation.ts +203 -285
- 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 +36 -0
- package/src/router/segment-resolution.ts +4 -1
- package/src/router/segment-wrappers.ts +0 -3
- package/src/router/state-cookie-name.ts +33 -0
- package/src/router/substitute-pattern-params.ts +56 -0
- package/src/router/telemetry-otel.ts +0 -20
- package/src/router/telemetry.ts +96 -19
- package/src/router/timeout.ts +0 -20
- package/src/router/trie-matching.ts +87 -48
- package/src/router/types.ts +9 -63
- package/src/router/url-params.ts +0 -5
- package/src/router.ts +80 -41
- package/src/rsc/handler-context.ts +3 -2
- package/src/rsc/handler.ts +83 -78
- package/src/rsc/helpers.ts +93 -5
- package/src/rsc/index.ts +1 -1
- package/src/rsc/json-route-result.ts +38 -0
- package/src/rsc/manifest-init.ts +28 -41
- package/src/rsc/origin-guard.ts +39 -25
- package/src/rsc/progressive-enhancement.ts +12 -1
- package/src/rsc/redirect-guard.ts +99 -0
- package/src/rsc/response-error.ts +79 -12
- package/src/rsc/response-route-handler.ts +76 -62
- package/src/rsc/rsc-rendering.ts +41 -60
- package/src/rsc/runtime-warnings.ts +23 -10
- package/src/rsc/server-action.ts +62 -67
- package/src/rsc/ssr-setup.ts +16 -0
- package/src/rsc/types.ts +10 -5
- package/src/runtime-env.ts +18 -0
- package/src/search-params.ts +4 -20
- package/src/segment-loader-promise.ts +14 -2
- package/src/segment-system.tsx +199 -142
- package/src/serialize.ts +243 -0
- package/src/server/context.ts +150 -51
- package/src/server/cookie-store.ts +80 -5
- package/src/server/handle-store.ts +7 -24
- package/src/server/loader-registry.ts +5 -24
- package/src/server/request-context.ts +165 -87
- package/src/ssr/index.tsx +14 -14
- 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 +618 -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 +232 -0
- package/src/testing/generated-routes.ts +183 -0
- package/src/testing/index.ts +99 -0
- package/src/testing/internal/context.ts +348 -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 +330 -0
- package/src/testing/render-route.tsx +566 -0
- package/src/testing/run-loader.ts +378 -0
- package/src/testing/run-middleware.ts +205 -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 +0 -52
- package/src/theme/ThemeScript.tsx +0 -6
- package/src/theme/constants.ts +0 -12
- package/src/theme/index.ts +0 -7
- package/src/theme/theme-context.ts +1 -5
- package/src/theme/theme-script.ts +0 -14
- 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 +97 -22
- package/src/types/index.ts +1 -10
- package/src/types/loader-types.ts +6 -3
- package/src/types/request-scope.ts +0 -19
- package/src/types/route-config.ts +6 -50
- package/src/types/route-entry.ts +0 -6
- package/src/types/segments.ts +18 -14
- package/src/urls/include-helper.ts +9 -56
- package/src/urls/index.ts +1 -11
- package/src/urls/path-helper-types.ts +19 -5
- package/src/urls/path-helper.ts +17 -106
- package/src/urls/pattern-types.ts +36 -19
- package/src/urls/response-types.ts +20 -19
- package/src/urls/type-extraction.ts +58 -139
- package/src/urls/urls-function.ts +1 -18
- package/src/use-loader.tsx +292 -107
- package/src/vite/debug.ts +1 -0
- package/src/vite/discovery/bundle-postprocess.ts +8 -7
- package/src/vite/discovery/discover-routers.ts +95 -82
- package/src/vite/discovery/discovery-errors.ts +194 -0
- package/src/vite/discovery/prerender-collection.ts +26 -34
- package/src/vite/discovery/route-types-writer.ts +40 -84
- package/src/vite/discovery/state.ts +39 -1
- package/src/vite/discovery/virtual-module-codegen.ts +14 -34
- package/src/vite/index.ts +4 -0
- package/src/vite/plugin-types.ts +185 -10
- package/src/vite/plugins/cjs-to-esm.ts +3 -18
- package/src/vite/plugins/client-ref-dedup.ts +0 -11
- package/src/vite/plugins/client-ref-hashing.ts +12 -11
- package/src/vite/plugins/cloudflare-protocol-stub.ts +1 -21
- package/src/vite/plugins/expose-action-id.ts +4 -75
- package/src/vite/plugins/expose-id-utils.ts +3 -54
- package/src/vite/plugins/expose-ids/export-analysis.ts +76 -34
- package/src/vite/plugins/expose-ids/handler-transform.ts +6 -74
- package/src/vite/plugins/expose-ids/loader-transform.ts +3 -20
- package/src/vite/plugins/expose-ids/router-transform.ts +0 -13
- package/src/vite/plugins/expose-internal-ids.ts +57 -67
- package/src/vite/plugins/performance-tracks.ts +9 -16
- package/src/vite/plugins/refresh-cmd.ts +1 -1
- package/src/vite/plugins/use-cache-transform.ts +26 -49
- package/src/vite/plugins/vercel-output.ts +258 -0
- package/src/vite/plugins/version-injector.ts +2 -32
- package/src/vite/plugins/version-plugin.ts +32 -23
- package/src/vite/plugins/virtual-entries.ts +35 -17
- package/src/vite/rango.ts +148 -115
- package/src/vite/router-discovery.ts +220 -68
- package/src/vite/utils/ast-handler-extract.ts +15 -31
- package/src/vite/utils/bundle-analysis.ts +10 -15
- package/src/vite/utils/client-chunks.ts +184 -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 +1 -73
- package/src/vite/utils/prerender-utils.ts +0 -34
- package/src/vite/utils/shared-utils.ts +95 -43
- 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/router/middleware-cookies.ts +0 -55
|
@@ -8,7 +8,8 @@
|
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
import type { CookieOptions } from "../router/middleware-types.js";
|
|
11
|
-
import { getRequestContext } from "./request-context.js";
|
|
11
|
+
import { getRequestContext, _getRequestContext } from "./request-context.js";
|
|
12
|
+
import { isInsideCacheScope } from "./context.js";
|
|
12
13
|
import { INSIDE_CACHE_EXEC } from "../cache/taint.js";
|
|
13
14
|
|
|
14
15
|
/**
|
|
@@ -84,10 +85,23 @@ export interface ReadonlyHeaders {
|
|
|
84
85
|
type HeadersIterator<T> = IterableIterator<T>;
|
|
85
86
|
|
|
86
87
|
/**
|
|
87
|
-
* Throw if called inside a "use cache" function
|
|
88
|
-
*
|
|
89
|
-
*
|
|
90
|
-
*
|
|
88
|
+
* Throw if called inside a cache boundary — either a "use cache" function
|
|
89
|
+
* (`INSIDE_CACHE_EXEC` stamped on ctx by the cache runtime) or a `cache()`
|
|
90
|
+
* DSL boundary (`isInsideCacheScope()` — the render-store flag set while
|
|
91
|
+
* resolving a `type: "cache"` route entry).
|
|
92
|
+
*
|
|
93
|
+
* Reading request-scoped data (cookies, headers) inside a cached scope
|
|
94
|
+
* produces per-request values that are NOT reflected in the cache key, so
|
|
95
|
+
* they would be frozen into the shared cache entry and served to the wrong
|
|
96
|
+
* users. This is the same hazard for both scopes: a `cache()` boundary caches
|
|
97
|
+
* everything except loaders (it is the document-level "PPR shell"), so a read
|
|
98
|
+
* here is baked into the shell exactly like a `"use cache"` return value is
|
|
99
|
+
* baked into its cache entry.
|
|
100
|
+
*
|
|
101
|
+
* `isInsideCacheScope()` returns false inside loaders (loaders always run
|
|
102
|
+
* fresh on every request, even on a cache hit), so reading cookies()/headers()
|
|
103
|
+
* from a loader is allowed — loaders are the dynamic "holes" of a cached
|
|
104
|
+
* document.
|
|
91
105
|
*/
|
|
92
106
|
function assertNotInsideCacheContext(ctx: unknown, fnName: string): void {
|
|
93
107
|
if (
|
|
@@ -106,6 +120,16 @@ function assertNotInsideCacheContext(ctx: unknown, fnName: string): void {
|
|
|
106
120
|
` const data = await getCachedData(locale); // locale is now in the cache key`,
|
|
107
121
|
);
|
|
108
122
|
}
|
|
123
|
+
if (isInsideCacheScope()) {
|
|
124
|
+
throw new Error(
|
|
125
|
+
`${fnName}() cannot be called inside a cache() boundary. ` +
|
|
126
|
+
`A cache() scope caches everything except loaders, so request-scoped ` +
|
|
127
|
+
`data (cookies, headers) read here would be frozen into the shared ` +
|
|
128
|
+
`cached shell and served to other users. Read it inside a loader ` +
|
|
129
|
+
`instead — loaders always run fresh on every request, even on a cache hit:\n\n` +
|
|
130
|
+
` loader("user", () => getUser(cookies().get("session")?.value));`,
|
|
131
|
+
);
|
|
132
|
+
}
|
|
109
133
|
}
|
|
110
134
|
|
|
111
135
|
const HEADERS_MUTATION_METHODS = new Set(["set", "append", "delete"]);
|
|
@@ -144,6 +168,57 @@ export function headers(): ReadonlyHeaders {
|
|
|
144
168
|
}) as unknown as ReadonlyHeaders;
|
|
145
169
|
}
|
|
146
170
|
|
|
171
|
+
/**
|
|
172
|
+
* Force the calling client's caches to miss from now on, from the server seat:
|
|
173
|
+
* write a rotated `Set-Cookie` for the rango state. The responding client
|
|
174
|
+
* applies it on receipt, and its history cache is marked stale by the
|
|
175
|
+
* jar-divergence observer at its next read. Per-client and lazy — it rotates
|
|
176
|
+
* only the client that receives this response, not every client.
|
|
177
|
+
*
|
|
178
|
+
* Idempotent within a request (one `Set-Cookie`). Inert (a dev warning) when
|
|
179
|
+
* called outside a request context. Like `cookies()`, it throws inside a
|
|
180
|
+
* `"use cache"` / `cache()` boundary, but is allowed from a loader (loaders are
|
|
181
|
+
* the dynamic holes of a cached document).
|
|
182
|
+
*/
|
|
183
|
+
export function invalidateClientCache(): void {
|
|
184
|
+
const ctx = _getRequestContext();
|
|
185
|
+
if (!ctx) {
|
|
186
|
+
if (process.env.NODE_ENV !== "production") {
|
|
187
|
+
console.warn(
|
|
188
|
+
"[rango] invalidateClientCache() was called outside a request context; ignored.",
|
|
189
|
+
);
|
|
190
|
+
}
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
193
|
+
assertNotInsideCacheContext(ctx, "invalidateClientCache");
|
|
194
|
+
ctx._rotateStateCookie();
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Suppress a server action's automatic client-cache invalidation: tell the
|
|
199
|
+
* action bridge this action changed nothing a route renders, so it should leave
|
|
200
|
+
* the client's state and caches alone (no rotation, no prefetch wipe, no
|
|
201
|
+
* broadcast, no revalidation refetch). Per-response, not per-action-definition —
|
|
202
|
+
* only the execution knows whether anything changed.
|
|
203
|
+
*
|
|
204
|
+
* Sets an internal response header the bridge reads. Idempotent within a
|
|
205
|
+
* request. Inert (a dev warning) outside a request context — there is no
|
|
206
|
+
* automatic invalidation to suppress.
|
|
207
|
+
*/
|
|
208
|
+
export function keepClientCache(): void {
|
|
209
|
+
const ctx = _getRequestContext();
|
|
210
|
+
if (!ctx) {
|
|
211
|
+
if (process.env.NODE_ENV !== "production") {
|
|
212
|
+
console.warn(
|
|
213
|
+
"[rango] keepClientCache() was called outside a request context; ignored.",
|
|
214
|
+
);
|
|
215
|
+
}
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
218
|
+
assertNotInsideCacheContext(ctx, "keepClientCache");
|
|
219
|
+
ctx._setKeepCacheDirective();
|
|
220
|
+
}
|
|
221
|
+
|
|
147
222
|
/**
|
|
148
223
|
* Create a CookieStore backed by a RequestContext.
|
|
149
224
|
* @internal Shared between cookies() shorthand and context methods.
|
|
@@ -45,10 +45,6 @@ function createLateHandlePushError(
|
|
|
45
45
|
return error;
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
-
/**
|
|
49
|
-
* Deep clone handle data to create a snapshot.
|
|
50
|
-
* @internal
|
|
51
|
-
*/
|
|
52
48
|
function cloneHandleData(data: HandleData): HandleData {
|
|
53
49
|
const clone: HandleData = {};
|
|
54
50
|
for (const handleName in data) {
|
|
@@ -205,11 +201,9 @@ export function createHandleStore(): HandleStore {
|
|
|
205
201
|
return {
|
|
206
202
|
track<T>(promise: Promise<T>): Promise<T> {
|
|
207
203
|
inflightCount++;
|
|
208
|
-
// Use .then(
|
|
209
|
-
//
|
|
210
|
-
//
|
|
211
|
-
// rejection on a new branch that nobody catches, which can crash
|
|
212
|
-
// the server process.
|
|
204
|
+
// Use .then() instead of .finally() to avoid creating an unhandled rejection
|
|
205
|
+
// branch when the promise rejects. .finally() re-throws on a new branch that
|
|
206
|
+
// can crash the process if not caught.
|
|
213
207
|
const onSettle = () => {
|
|
214
208
|
inflightCount--;
|
|
215
209
|
notifyDrain();
|
|
@@ -255,42 +249,32 @@ export function createHandleStore(): HandleStore {
|
|
|
255
249
|
},
|
|
256
250
|
|
|
257
251
|
async *stream(): AsyncGenerator<HandleData, void, unknown> {
|
|
258
|
-
// Auto-seal: stream() is called after all track() registrations.
|
|
259
252
|
sealInternal();
|
|
260
253
|
|
|
261
|
-
// Set up completion handler
|
|
262
254
|
this.settled.then(() => {
|
|
263
255
|
completed = true;
|
|
264
256
|
signalEmission();
|
|
265
257
|
});
|
|
266
258
|
|
|
267
|
-
//
|
|
268
|
-
// This allows multiple handles pushing in quick succession to be batched
|
|
259
|
+
// Batch rapid synchronous pushes with initial delay
|
|
269
260
|
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
270
261
|
|
|
271
|
-
// If we already have data, yield the accumulated state
|
|
272
262
|
if (Object.keys(data).length > 0) {
|
|
273
|
-
// Clear pending emissions since we're yielding current state
|
|
274
263
|
pendingEmissions = [];
|
|
275
264
|
const snapshot = cloneHandleData(data);
|
|
276
265
|
yield snapshot;
|
|
277
266
|
}
|
|
278
267
|
|
|
279
|
-
// Continue streaming on each push
|
|
280
268
|
while (!completed) {
|
|
281
269
|
await waitForEmission();
|
|
282
270
|
|
|
283
|
-
// Yield all pending emissions (yield latest only)
|
|
284
271
|
if (pendingEmissions.length > 0) {
|
|
285
|
-
// Skip intermediate states, yield the latest
|
|
286
272
|
const latest = pendingEmissions[pendingEmissions.length - 1];
|
|
287
273
|
pendingEmissions = [];
|
|
288
274
|
yield latest;
|
|
289
275
|
}
|
|
290
276
|
}
|
|
291
277
|
|
|
292
|
-
// Final yield only if there are pending emissions that weren't yielded
|
|
293
|
-
// (handles that pushed after our last yield but before completion)
|
|
294
278
|
if (pendingEmissions.length > 0) {
|
|
295
279
|
yield cloneHandleData(data);
|
|
296
280
|
}
|
|
@@ -314,12 +298,11 @@ export function createHandleStore(): HandleStore {
|
|
|
314
298
|
if (!data[handleName]) {
|
|
315
299
|
data[handleName] = {};
|
|
316
300
|
}
|
|
317
|
-
// Replace
|
|
318
|
-
//
|
|
319
|
-
//
|
|
301
|
+
// Replace (not append) to avoid handle bleeding between routes.
|
|
302
|
+
// Cached segment restoration should replace existing data for that
|
|
303
|
+
// segment, not accumulate on top of data from a different route.
|
|
320
304
|
data[handleName][segmentId] = [...segmentHandles[handleName]];
|
|
321
305
|
}
|
|
322
|
-
// Trigger emission for streaming
|
|
323
306
|
pendingEmissions.push(cloneHandleData(data));
|
|
324
307
|
signalEmission();
|
|
325
308
|
},
|
|
@@ -11,17 +11,10 @@ import {
|
|
|
11
11
|
type LoaderRegistryEntry,
|
|
12
12
|
} from "./fetchable-loader-store.js";
|
|
13
13
|
|
|
14
|
-
//
|
|
15
|
-
//
|
|
16
|
-
// The source of truth is fetchableLoaderRegistry in loader.ts, which is populated
|
|
17
|
-
// when createLoader() runs. This cache exists to:
|
|
18
|
-
// 1. Avoid repeated lookups/imports for the same loader
|
|
19
|
-
// 2. Support lazy loading in production (loaders imported on-demand)
|
|
20
|
-
// 3. Provide a stable reference for the RSC handler
|
|
14
|
+
// Cache populated by getLoaderLazy() when loaders are first accessed.
|
|
15
|
+
// Source of truth is fetchableLoaderRegistry in loader.ts (populated on createLoader).
|
|
21
16
|
const loaderRegistry = new Map<string, LoaderRegistryEntry>();
|
|
22
17
|
|
|
23
|
-
// Lazy import map - set by the loader manifest
|
|
24
|
-
// Maps loader $$id to a function that imports the loader module
|
|
25
18
|
type LazyLoaderImport = () => Promise<{ $$id: string }>;
|
|
26
19
|
let lazyLoaderImports: Map<string, LazyLoaderImport> | null = null;
|
|
27
20
|
|
|
@@ -44,30 +37,25 @@ export function setLoaderImports(
|
|
|
44
37
|
export async function getLoaderLazy(
|
|
45
38
|
id: string,
|
|
46
39
|
): Promise<LoaderRegistryEntry | undefined> {
|
|
47
|
-
//
|
|
48
|
-
// createLoader() updates it
|
|
49
|
-
// here ensures we pick up the fresh function after a loader file change.
|
|
40
|
+
// Check fetchableLoaderRegistry first — it's the source of truth.
|
|
41
|
+
// createLoader() updates it on HMR, ensuring fresh functions after file changes.
|
|
50
42
|
const fetchable = getFetchableLoader(id);
|
|
51
43
|
if (fetchable) {
|
|
52
44
|
loaderRegistry.set(id, fetchable);
|
|
53
45
|
return fetchable;
|
|
54
46
|
}
|
|
55
47
|
|
|
56
|
-
// Fall back to local cache (populated by previous lazy imports in production)
|
|
57
48
|
const existing = loaderRegistry.get(id);
|
|
58
49
|
if (existing) {
|
|
59
50
|
return existing;
|
|
60
51
|
}
|
|
61
52
|
|
|
62
|
-
// Try to lazy load from the import map (production mode)
|
|
63
53
|
if (lazyLoaderImports && lazyLoaderImports.size > 0) {
|
|
64
54
|
const lazyImport = lazyLoaderImports.get(id);
|
|
65
55
|
if (lazyImport) {
|
|
66
56
|
try {
|
|
67
|
-
// Import the loader module - this triggers createLoader which registers fn
|
|
68
57
|
await lazyImport();
|
|
69
58
|
|
|
70
|
-
// Now try to get from fetchable registry (createLoader registered it)
|
|
71
59
|
const registered = getFetchableLoader(id);
|
|
72
60
|
if (registered) {
|
|
73
61
|
loaderRegistry.set(id, registered);
|
|
@@ -79,18 +67,14 @@ export async function getLoaderLazy(
|
|
|
79
67
|
}
|
|
80
68
|
}
|
|
81
69
|
|
|
82
|
-
// Dev
|
|
83
|
-
// ID format in dev: "src/path/to/file.ts#ExportName"
|
|
70
|
+
// Dev fallback: parse ID (format: "src/path/to/file.ts#ExportName") and import
|
|
84
71
|
const hashIndex = id.indexOf("#");
|
|
85
72
|
if (hashIndex !== -1) {
|
|
86
73
|
const filePath = id.slice(0, hashIndex);
|
|
87
74
|
|
|
88
75
|
try {
|
|
89
|
-
// In dev mode, Vite handles dynamic imports
|
|
90
|
-
// Just importing the module triggers createLoader which registers the fn
|
|
91
76
|
await import(/* @vite-ignore */ `/${filePath}`);
|
|
92
77
|
|
|
93
|
-
// Now try to get from fetchable registry
|
|
94
78
|
const registered = getFetchableLoader(id);
|
|
95
79
|
if (registered) {
|
|
96
80
|
loaderRegistry.set(id, registered);
|
|
@@ -115,15 +99,12 @@ export function registerLoaderById(loader: {
|
|
|
115
99
|
if (!loader.$$id) {
|
|
116
100
|
return;
|
|
117
101
|
}
|
|
118
|
-
// For fetchable loaders, fn is stored in the fetchable registry by $$id.
|
|
119
|
-
// Always re-check the fetchable registry so HMR picks up the new function.
|
|
120
102
|
const fetchable = getFetchableLoader(loader.$$id);
|
|
121
103
|
if (fetchable) {
|
|
122
104
|
loaderRegistry.set(loader.$$id, fetchable);
|
|
123
105
|
return;
|
|
124
106
|
}
|
|
125
107
|
|
|
126
|
-
// Fall back to using fn from the loader object (non-fetchable loaders)
|
|
127
108
|
if (loader.fn) {
|
|
128
109
|
loaderRegistry.set(loader.$$id, {
|
|
129
110
|
fn: loader.fn,
|