@rangojs/router 0.0.0-experimental.14 → 0.0.0-experimental.141
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 +17 -0
- package/README.md +432 -7
- package/dist/bin/rango.js +2073 -213
- package/dist/testing/vitest.js +82 -0
- package/dist/vite/index.js +7258 -2714
- package/dist/vite/plugins/cloudflare-protocol-loader-hook.mjs +76 -0
- package/package.json +140 -67
- package/skills/api-client/SKILL.md +211 -0
- package/skills/breadcrumbs/SKILL.md +329 -0
- package/skills/bundle-analysis/SKILL.md +159 -0
- package/skills/cache-guide/SKILL.md +487 -0
- package/skills/caching/SKILL.md +357 -25
- package/skills/comparison/SKILL.md +50 -0
- package/skills/comparison/agents/openai.yaml +4 -0
- package/skills/comparison/references/framework-comparison.md +837 -0
- package/skills/composability/SKILL.md +246 -0
- package/skills/css/SKILL.md +76 -0
- package/skills/debug-manifest/SKILL.md +16 -10
- package/skills/document-cache/SKILL.md +87 -62
- package/skills/fonts/SKILL.md +6 -4
- package/skills/handler-use/SKILL.md +364 -0
- package/skills/hooks/SKILL.md +557 -79
- package/skills/host-router/SKILL.md +320 -0
- package/skills/i18n/SKILL.md +276 -0
- package/skills/intercept/SKILL.md +207 -15
- package/skills/layout/SKILL.md +146 -6
- package/skills/links/SKILL.md +304 -25
- package/skills/loader/SKILL.md +616 -54
- package/skills/middleware/SKILL.md +217 -37
- package/skills/migrate-nextjs/SKILL.md +611 -0
- package/skills/migrate-react-router/SKILL.md +927 -0
- package/skills/mime-routes/SKILL.md +42 -11
- package/skills/observability/SKILL.md +194 -0
- package/skills/parallel/SKILL.md +284 -3
- package/skills/ppr/SKILL.md +293 -0
- package/skills/prerender/SKILL.md +437 -52
- package/skills/rango/SKILL.md +369 -22
- package/skills/react-compiler/SKILL.md +168 -0
- package/skills/response-routes/SKILL.md +263 -121
- package/skills/route/SKILL.md +350 -21
- package/skills/router-setup/SKILL.md +246 -33
- package/skills/scripts/SKILL.md +179 -0
- package/skills/server-actions/SKILL.md +775 -0
- package/skills/shell-manifest/SKILL.md +185 -0
- package/skills/streams-and-websockets/SKILL.md +283 -0
- package/skills/tailwind/SKILL.md +27 -3
- package/skills/testing/SKILL.md +126 -222
- 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 +131 -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 +85 -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/theme/SKILL.md +9 -8
- package/skills/typesafety/SKILL.md +532 -103
- package/skills/use-cache/SKILL.md +367 -0
- package/skills/vercel/SKILL.md +128 -0
- 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 +77 -44
- package/src/bin/rango.ts +312 -15
- package/src/browser/action-coordinator.ts +114 -0
- package/src/browser/action-fence.ts +47 -0
- package/src/browser/app-shell.ts +39 -0
- package/src/browser/app-version.ts +14 -0
- package/src/browser/connection-warmup.ts +134 -0
- package/src/browser/cookie-name.ts +140 -0
- package/src/browser/event-controller.ts +293 -202
- package/src/browser/history-state.ts +101 -0
- package/src/browser/index.ts +3 -3
- package/src/browser/intercept-utils.ts +52 -0
- package/src/browser/invalidate-client-cache.ts +52 -0
- package/src/browser/link-interceptor.ts +24 -4
- package/src/browser/logging.ts +11 -0
- package/src/browser/merge-segment-loaders.ts +20 -12
- package/src/browser/navigation-bridge.ts +385 -576
- package/src/browser/navigation-client.ts +245 -75
- package/src/browser/navigation-store-handle.ts +38 -0
- package/src/browser/navigation-store.ts +184 -118
- package/src/browser/navigation-transaction.ts +247 -0
- package/src/browser/network-error-handler.ts +88 -0
- package/src/browser/partial-update.ts +412 -364
- package/src/browser/prefetch/cache.ts +359 -0
- package/src/browser/prefetch/fetch.ts +452 -0
- package/src/browser/prefetch/observer.ts +65 -0
- package/src/browser/prefetch/policy.ts +48 -0
- package/src/browser/prefetch/queue.ts +209 -0
- package/src/browser/prefetch/resource-ready.ts +77 -0
- package/src/browser/rango-state.ts +194 -0
- package/src/browser/react/Link.tsx +275 -68
- package/src/browser/react/NavigationProvider.tsx +265 -109
- package/src/browser/react/ScrollRestoration.tsx +10 -6
- package/src/browser/react/context.ts +11 -0
- package/src/browser/react/filter-segment-order.ts +70 -0
- package/src/browser/react/index.ts +0 -48
- package/src/browser/react/location-state-shared.ts +272 -60
- package/src/browser/react/location-state.ts +90 -20
- package/src/browser/react/mount-context.ts +6 -1
- package/src/browser/react/nonce-context.ts +23 -0
- package/src/browser/react/shallow-equal.ts +27 -0
- package/src/browser/react/use-action.ts +35 -66
- package/src/browser/react/use-handle.ts +39 -126
- package/src/browser/react/use-href.tsx +8 -1
- package/src/browser/react/use-link-status.ts +39 -13
- package/src/browser/react/use-navigation.ts +53 -69
- package/src/browser/react/use-params.ts +75 -0
- package/src/browser/react/use-pathname.ts +47 -0
- package/src/browser/react/use-reverse.ts +106 -0
- package/src/browser/react/use-router.ts +98 -0
- package/src/browser/react/use-search-params.ts +51 -0
- package/src/browser/react/use-segments.ts +72 -99
- package/src/browser/response-adapter.ts +164 -0
- package/src/browser/rsc-router.tsx +300 -72
- package/src/browser/scroll-restoration.ts +138 -50
- package/src/browser/segment-reconciler.ts +243 -0
- package/src/browser/segment-structure-assert.ts +17 -1
- package/src/browser/server-action-bridge.ts +668 -613
- package/src/browser/types.ts +223 -51
- package/src/browser/validate-redirect-origin.ts +56 -0
- package/src/build/collect-fallback-refs.ts +107 -0
- package/src/build/generate-manifest.ts +252 -161
- package/src/build/generate-route-types.ts +41 -1038
- package/src/build/index.ts +12 -7
- package/src/build/prefix-tree-utils.ts +123 -0
- package/src/build/route-trie.ts +225 -42
- package/src/build/route-types/ast-helpers.ts +25 -0
- package/src/build/route-types/ast-route-extraction.ts +105 -0
- package/src/build/route-types/codegen.ts +113 -0
- package/src/build/route-types/include-resolution.ts +812 -0
- package/src/build/route-types/param-extraction.ts +51 -0
- package/src/build/route-types/per-module-writer.ts +144 -0
- package/src/build/route-types/router-processing.ts +695 -0
- package/src/build/route-types/scan-filter.ts +85 -0
- package/src/build/route-types/source-scan.ts +216 -0
- package/src/build/runtime-discovery.ts +223 -0
- package/src/cache/background-task.ts +34 -0
- package/src/cache/cache-error.ts +104 -0
- package/src/cache/cache-key-utils.ts +60 -0
- package/src/cache/cache-policy.ts +199 -0
- package/src/cache/cache-runtime.ts +525 -0
- package/src/cache/cache-scope.ts +298 -332
- 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 +2508 -158
- 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 +17 -17
- package/src/cache/document-cache.ts +199 -92
- package/src/cache/handle-capture.ts +81 -0
- package/src/cache/handle-snapshot.ts +111 -0
- package/src/cache/index.ts +24 -35
- package/src/cache/memory-segment-store.ts +363 -30
- package/src/cache/profile-registry.ts +88 -0
- package/src/cache/read-through-swr.ts +178 -0
- package/src/cache/segment-codec.ts +248 -0
- package/src/cache/shell-snapshot.ts +368 -0
- package/src/cache/tag-invalidation.ts +230 -0
- package/src/cache/taint.ts +153 -0
- package/src/cache/types.ts +222 -211
- package/src/cache/vercel/index.ts +11 -0
- package/src/cache/vercel/vercel-cache-store.ts +1113 -0
- package/src/client.rsc.tsx +43 -21
- package/src/client.tsx +131 -347
- package/src/cloudflare/index.ts +11 -0
- package/src/cloudflare/tracing.ts +109 -0
- package/src/component-utils.ts +23 -4
- package/src/components/DefaultDocument.tsx +13 -3
- package/src/context-var.ts +168 -0
- package/src/debug.ts +19 -9
- package/src/decode-loader-results.ts +52 -0
- package/src/defer.ts +185 -0
- package/src/deps/ssr.ts +0 -1
- package/src/encode-kv.ts +49 -0
- package/src/errors.ts +106 -10
- package/src/escape-script.ts +52 -0
- package/src/handle.ts +110 -35
- package/src/handles/MetaTags.tsx +83 -59
- package/src/handles/Scripts.tsx +183 -0
- package/src/handles/breadcrumbs.ts +93 -0
- package/src/handles/deferred-resolution.ts +127 -0
- package/src/handles/is-thenable.ts +18 -0
- package/src/handles/meta.ts +44 -53
- package/src/handles/script.ts +244 -0
- package/src/host/cookie-handler.ts +20 -65
- package/src/host/errors.ts +21 -30
- package/src/host/index.ts +13 -9
- package/src/host/pattern-matcher.ts +50 -79
- package/src/host/router.ts +151 -121
- package/src/host/testing.ts +45 -32
- package/src/host/types.ts +52 -11
- package/src/host/utils.ts +2 -2
- package/src/href-client.ts +192 -57
- package/src/index.rsc.ts +173 -35
- package/src/index.ts +241 -73
- package/src/internal-debug.ts +9 -2
- package/src/loader-store.ts +500 -0
- package/src/loader.rsc.ts +31 -99
- package/src/loader.ts +30 -12
- package/src/missing-id-error.ts +68 -0
- package/src/outlet-context.ts +1 -1
- package/src/outlet-provider.tsx +41 -0
- package/src/prerender/param-hash.ts +16 -14
- package/src/prerender/store.ts +121 -21
- package/src/prerender.ts +460 -26
- 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 +62 -0
- package/src/reverse.ts +198 -128
- package/src/root-error-boundary.tsx +42 -48
- package/src/route-content-wrapper.tsx +22 -77
- package/src/route-definition/dsl-helpers.ts +1116 -0
- package/src/route-definition/helper-factories.ts +88 -0
- package/src/route-definition/helpers-types.ts +505 -0
- package/src/route-definition/index.ts +54 -0
- package/src/route-definition/redirect.ts +134 -0
- package/src/route-definition/resolve-handler-use.ts +160 -0
- package/src/route-definition/use-item-types.ts +29 -0
- package/src/route-definition.ts +1 -1481
- package/src/route-map-builder.ts +82 -144
- package/src/route-name.ts +53 -0
- package/src/route-types.ts +71 -45
- package/src/router/basename.ts +14 -0
- package/src/router/content-negotiation.ts +263 -0
- package/src/router/debug-manifest.ts +72 -0
- package/src/router/error-handling.ts +54 -27
- package/src/router/find-match.ts +245 -0
- package/src/router/handler-context.ts +377 -125
- package/src/router/instrument.ts +350 -0
- package/src/router/intercept-resolution.ts +59 -28
- package/src/router/lazy-includes.ts +254 -0
- package/src/router/loader-resolution.ts +421 -157
- package/src/router/logging.ts +106 -6
- package/src/router/manifest.ts +131 -57
- package/src/router/match-api.ts +167 -246
- package/src/router/match-context.ts +4 -24
- package/src/router/match-handlers.ts +440 -0
- package/src/router/match-middleware/background-revalidation.ts +117 -93
- package/src/router/match-middleware/cache-lookup.ts +297 -150
- package/src/router/match-middleware/cache-store.ts +123 -51
- package/src/router/match-middleware/intercept-resolution.ts +44 -43
- package/src/router/match-middleware/segment-resolution.ts +64 -22
- package/src/router/match-pipelines.ts +11 -87
- package/src/router/match-result.ts +121 -50
- package/src/router/metrics.ts +219 -28
- package/src/router/middleware-types.ts +93 -0
- package/src/router/middleware.ts +505 -441
- package/src/router/navigation-snapshot.ts +133 -0
- package/src/router/params-util.ts +23 -0
- package/src/router/parse-pattern.ts +115 -0
- package/src/router/pattern-matching.ts +311 -142
- package/src/router/prefetch-cache-ttl.ts +51 -0
- package/src/router/prefetch-limits.ts +37 -0
- package/src/router/prerender-match.ts +547 -0
- package/src/router/preview-match.ts +102 -0
- package/src/router/request-classification.ts +278 -0
- package/src/router/revalidation.ts +203 -62
- package/src/router/route-snapshot.ts +246 -0
- package/src/router/router-context.ts +45 -48
- package/src/router/router-interfaces.ts +554 -0
- package/src/router/router-options.ts +779 -0
- package/src/router/router-registry.ts +21 -0
- package/src/router/segment-resolution/fresh.ts +772 -0
- package/src/router/segment-resolution/helpers.ts +348 -0
- package/src/router/segment-resolution/loader-cache.ts +250 -0
- package/src/router/segment-resolution/loader-mask.ts +44 -0
- package/src/router/segment-resolution/revalidation.ts +1331 -0
- package/src/router/segment-resolution/static-store.ts +81 -0
- 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 +25 -1354
- package/src/router/segment-wrappers.ts +292 -0
- package/src/router/state-cookie-name.ts +33 -0
- package/src/router/substitute-pattern-params.ts +75 -0
- package/src/router/telemetry-otel.ts +261 -0
- package/src/router/telemetry.ts +377 -0
- package/src/router/timeout.ts +128 -0
- package/src/router/tracing.ts +206 -0
- package/src/router/trie-matching.ts +240 -61
- package/src/router/types.ts +23 -70
- package/src/router/url-params.ts +57 -0
- package/src/router.ts +781 -2378
- package/src/rsc/full-payload.ts +70 -0
- package/src/rsc/handler-context.ts +46 -0
- package/src/rsc/handler.ts +905 -1142
- package/src/rsc/helpers.ts +275 -19
- package/src/rsc/index.ts +2 -25
- package/src/rsc/json-route-result.ts +38 -0
- package/src/rsc/loader-fetch.ts +305 -0
- package/src/rsc/manifest-init.ts +77 -0
- package/src/rsc/nonce.ts +14 -0
- package/src/rsc/origin-guard.ts +155 -0
- package/src/rsc/progressive-enhancement.ts +502 -0
- package/src/rsc/redirect-guard.ts +99 -0
- package/src/rsc/response-cache-serve.ts +238 -0
- package/src/rsc/response-error.ts +104 -0
- package/src/rsc/response-route-handler.ts +257 -0
- package/src/rsc/rsc-rendering.ts +527 -0
- package/src/rsc/runtime-warnings.ts +55 -0
- package/src/rsc/server-action.ts +522 -0
- package/src/rsc/shell-capture.ts +897 -0
- package/src/rsc/shell-serve.ts +124 -0
- package/src/rsc/ssr-setup.ts +144 -0
- package/src/rsc/transition-gate.ts +89 -0
- package/src/rsc/types.ts +95 -12
- package/src/runtime-env.ts +18 -0
- package/src/search-params.ts +99 -82
- package/src/segment-content-promise.ts +67 -0
- package/src/segment-loader-promise.ts +149 -0
- package/src/segment-system.tsx +349 -134
- package/src/serialize.ts +243 -0
- package/src/server/context.ts +459 -85
- package/src/server/cookie-parse.ts +32 -0
- package/src/server/cookie-store.ts +310 -0
- package/src/server/fetchable-loader-store.ts +11 -6
- package/src/server/handle-store.ts +123 -42
- package/src/server/loader-registry.ts +51 -100
- package/src/server/request-context.ts +848 -157
- package/src/server.ts +15 -8
- package/src/ssr/index.tsx +443 -135
- package/src/ssr/ssr-root.tsx +228 -0
- package/src/static-handler.ts +45 -18
- package/src/testing/cache-status.ts +162 -0
- package/src/testing/collect-handle.ts +46 -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 +199 -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 +584 -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 +76 -98
- package/src/theme/ThemeScript.tsx +12 -14
- package/src/theme/constants.ts +57 -15
- package/src/theme/index.ts +3 -20
- package/src/theme/theme-context.ts +5 -35
- package/src/theme/theme-script.ts +43 -39
- package/src/theme/use-theme.ts +0 -3
- package/src/types/boundaries.ts +123 -0
- package/src/types/cache-types.ts +207 -0
- package/src/types/error-types.ts +132 -0
- package/src/types/global-namespace.ts +113 -0
- package/src/types/handler-context.ts +839 -0
- package/src/types/index.ts +81 -0
- package/src/types/loader-types.ts +212 -0
- package/src/types/request-scope.ts +112 -0
- package/src/types/route-config.ts +138 -0
- package/src/types/route-entry.ts +114 -0
- package/src/types/segments.ts +271 -0
- package/src/types.ts +1 -1795
- package/src/urls/include-helper.ts +162 -0
- package/src/urls/include-provider.ts +71 -0
- package/src/urls/index.ts +44 -0
- package/src/urls/path-helper-types.ts +413 -0
- package/src/urls/path-helper.ts +280 -0
- package/src/urls/pattern-types.ts +160 -0
- package/src/urls/response-types.ts +109 -0
- package/src/urls/type-extraction.ts +316 -0
- package/src/urls/urls-function.ts +80 -0
- package/src/urls.ts +1 -1341
- package/src/use-loader.tsx +406 -141
- package/src/vercel/index.ts +11 -0
- package/src/vercel/tracing.ts +88 -0
- package/src/vite/debug.ts +185 -0
- package/src/vite/discovery/bundle-postprocess.ts +182 -0
- package/src/vite/discovery/discover-routers.ts +389 -0
- package/src/vite/discovery/discovery-errors.ts +255 -0
- package/src/vite/discovery/gate-state.ts +171 -0
- package/src/vite/discovery/prerender-collection.ts +467 -0
- package/src/vite/discovery/route-types-writer.ts +214 -0
- package/src/vite/discovery/self-gen-tracking.ts +73 -0
- package/src/vite/discovery/state.ts +161 -0
- package/src/vite/discovery/virtual-module-codegen.ts +183 -0
- package/src/vite/index.ts +23 -2255
- package/src/vite/inject-client-debug.ts +36 -0
- package/src/vite/plugin-types.ts +303 -0
- package/src/vite/plugins/cjs-to-esm.ts +90 -0
- package/src/vite/plugins/client-ref-dedup.ts +120 -0
- package/src/vite/plugins/client-ref-hashing.ts +118 -0
- package/src/vite/plugins/cloudflare-protocol-loader-hook.d.mts +23 -0
- package/src/vite/plugins/cloudflare-protocol-loader-hook.mjs +76 -0
- package/src/vite/plugins/cloudflare-protocol-stub.ts +194 -0
- package/src/vite/{expose-action-id.ts → plugins/expose-action-id.ts} +88 -110
- package/src/vite/{expose-id-utils.ts → plugins/expose-id-utils.ts} +89 -79
- package/src/vite/plugins/expose-ids/export-analysis.ts +363 -0
- package/src/vite/plugins/expose-ids/handler-transform.ts +130 -0
- package/src/vite/plugins/expose-ids/loader-transform.ts +64 -0
- package/src/vite/plugins/expose-ids/router-transform.ts +199 -0
- package/src/vite/plugins/expose-ids/types.ts +45 -0
- package/src/vite/plugins/expose-internal-ids.ts +805 -0
- package/src/vite/plugins/performance-tracks.ts +89 -0
- package/src/vite/plugins/refresh-cmd.ts +127 -0
- package/src/vite/plugins/use-cache-transform.ts +313 -0
- package/src/vite/plugins/vercel-output.ts +384 -0
- package/src/vite/plugins/version-injector.ts +94 -0
- package/src/vite/plugins/version-plugin.ts +263 -0
- package/src/vite/plugins/virtual-entries.ts +234 -0
- package/src/vite/plugins/virtual-stub-plugin.ts +29 -0
- package/src/vite/rango.ts +560 -0
- package/src/vite/router-discovery.ts +1638 -0
- package/src/vite/{ast-handler-extract.ts → utils/ast-handler-extract.ts} +200 -37
- package/src/vite/utils/banner.ts +36 -0
- package/src/vite/utils/bundle-analysis.ts +132 -0
- 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 +15 -0
- package/src/vite/utils/package-resolution.ts +89 -0
- package/src/vite/utils/prerender-utils.ts +249 -0
- package/src/vite/utils/shared-utils.ts +269 -0
- package/CLAUDE.md +0 -43
- package/dist/vite/index.named-routes.gen.ts +0 -103
- package/src/browser/lru-cache.ts +0 -69
- package/src/browser/react/use-client-cache.ts +0 -56
- package/src/browser/request-controller.ts +0 -164
- package/src/browser/shallow.ts +0 -35
- package/src/cache/memory-store.ts +0 -253
- package/src/handles/index.ts +0 -6
- package/src/href-context.ts +0 -33
- package/src/network-error-thrower.tsx +0 -21
- package/src/router.gen.ts +0 -6
- package/src/static-handler.gen.ts +0 -5
- package/src/urls.gen.ts +0 -8
- package/src/vite/expose-internal-ids.ts +0 -1167
- package/src/vite/package-resolution.ts +0 -125
- package/src/vite/virtual-entries.ts +0 -114
- /package/src/vite/{version.d.ts → plugins/version.d.ts} +0 -0
|
@@ -12,6 +12,7 @@ import type {
|
|
|
12
12
|
ActionStateListener,
|
|
13
13
|
HandleData,
|
|
14
14
|
} from "./types.js";
|
|
15
|
+
import { clearPrefetchCache } from "./prefetch/cache.js";
|
|
15
16
|
|
|
16
17
|
/**
|
|
17
18
|
* Default action state (idle with no payload)
|
|
@@ -27,9 +28,29 @@ const DEFAULT_ACTION_STATE: TrackedActionState = {
|
|
|
27
28
|
// Maximum number of history entries to cache (URLs visited)
|
|
28
29
|
const HISTORY_CACHE_SIZE = 20;
|
|
29
30
|
|
|
30
|
-
// Cache entry:
|
|
31
|
-
// stale
|
|
32
|
-
|
|
31
|
+
// Cache entry:
|
|
32
|
+
// [url-key, segments, stale, handleData?, routerId?, navInstance?, handlesPending?]
|
|
33
|
+
// stale=true means the data may be outdated and should be revalidated on access.
|
|
34
|
+
// navInstance is the monotonic nav-instance token (see navInstance below): it
|
|
35
|
+
// identifies the per-commit visit that owns this entry. generateHistoryKey is
|
|
36
|
+
// URL-only, so A->B->A reuses the same key; the token lets a late async
|
|
37
|
+
// resolution tell its own visit's entry apart from a newer same-URL visit's, so
|
|
38
|
+
// a stale nav can never clobber a fresher one.
|
|
39
|
+
// handlesPending=true means the entry's handle data is INCOMPLETE (a deferred
|
|
40
|
+
// Meta was still pending when the user navigated away, so it never streamed). A
|
|
41
|
+
// popstate return must REVALIDATE WITH A FULL RE-RENDER (no client segment IDs)
|
|
42
|
+
// to re-stream the handles — a diff-only revalidation omits unchanged segments'
|
|
43
|
+
// handles, so the deferred Meta would never land. Cleared once the deferred Meta
|
|
44
|
+
// resolves while the entry is still owned.
|
|
45
|
+
type HistoryCacheEntry = [
|
|
46
|
+
string,
|
|
47
|
+
ResolvedSegment[],
|
|
48
|
+
boolean,
|
|
49
|
+
HandleData?,
|
|
50
|
+
string?,
|
|
51
|
+
number?,
|
|
52
|
+
boolean?,
|
|
53
|
+
];
|
|
33
54
|
|
|
34
55
|
/**
|
|
35
56
|
* Shallow clone handleData to avoid reference sharing between cache entries.
|
|
@@ -37,7 +58,7 @@ type HistoryCacheEntry = [string, ResolvedSegment[], boolean, HandleData?];
|
|
|
37
58
|
* since mutations happen at the array level, not on individual data objects.
|
|
38
59
|
* This preserves any non-serializable types (React elements, functions, etc.)
|
|
39
60
|
*/
|
|
40
|
-
function cloneHandleData(handleData: HandleData): HandleData {
|
|
61
|
+
export function cloneHandleData(handleData: HandleData): HandleData {
|
|
41
62
|
const cloned: HandleData = {};
|
|
42
63
|
for (const [handleKey, segmentMap] of Object.entries(handleData)) {
|
|
43
64
|
cloned[handleKey] = {};
|
|
@@ -88,7 +109,7 @@ export interface HistoryKeyOptions {
|
|
|
88
109
|
*/
|
|
89
110
|
export function generateHistoryKey(
|
|
90
111
|
url?: string,
|
|
91
|
-
options?: HistoryKeyOptions
|
|
112
|
+
options?: HistoryKeyOptions,
|
|
92
113
|
): string {
|
|
93
114
|
if (!url) {
|
|
94
115
|
url = typeof window !== "undefined" ? window.location.href : "/";
|
|
@@ -123,14 +144,14 @@ export interface NavigationStoreConfig {
|
|
|
123
144
|
|
|
124
145
|
/**
|
|
125
146
|
* Enable cross-tab cache invalidation via BroadcastChannel (default: true)
|
|
126
|
-
* When cache is cleared (via server actions or
|
|
147
|
+
* When cache is cleared (via server actions or invalidateClientCache()),
|
|
127
148
|
* other tabs will also clear their cache
|
|
128
149
|
*/
|
|
129
150
|
crossTabSync?: boolean;
|
|
130
151
|
|
|
131
152
|
/**
|
|
132
153
|
* Auto-refresh when another tab mutates data on the same path (default: true)
|
|
133
|
-
* Triggered when cache is cleared via server actions or
|
|
154
|
+
* Triggered when cache is cleared via server actions or invalidateClientCache()
|
|
134
155
|
* Requires crossTabSync to be enabled
|
|
135
156
|
*/
|
|
136
157
|
crossTabAutoRefresh?: boolean;
|
|
@@ -182,7 +203,7 @@ function createLocation(loc: { href: string }): NavigationLocation {
|
|
|
182
203
|
* ```
|
|
183
204
|
*/
|
|
184
205
|
export function createNavigationStore(
|
|
185
|
-
config?: NavigationStoreConfig
|
|
206
|
+
config?: NavigationStoreConfig,
|
|
186
207
|
): NavigationStore {
|
|
187
208
|
// Default location from window or config
|
|
188
209
|
const defaultLocation: NavigationLocation =
|
|
@@ -232,6 +253,14 @@ export function createNavigationStore(
|
|
|
232
253
|
// Oldest entries (at front) are removed when over cacheSize limit
|
|
233
254
|
const historyCache: HistoryCacheEntry[] = [];
|
|
234
255
|
|
|
256
|
+
// Monotonic nav-instance token. Bumped each time a cache entry is created or
|
|
257
|
+
// replaced in cacheSegmentsForHistory (i.e. once per commit). Because
|
|
258
|
+
// generateHistoryKey is URL-only, two visits to the same URL share a key; this
|
|
259
|
+
// token gives each visit a distinct identity so a late async handle resolution
|
|
260
|
+
// can tell whether it still owns the live page / the target cache entry, and
|
|
261
|
+
// never overwrite a newer same-URL visit's state.
|
|
262
|
+
let navInstance = 0;
|
|
263
|
+
|
|
235
264
|
// Current history key (set on navigation, stored in history.state)
|
|
236
265
|
let currentHistoryKey = config?.initialHistoryKey || generateHistoryKey();
|
|
237
266
|
|
|
@@ -241,6 +270,10 @@ export function createNavigationStore(
|
|
|
241
270
|
config.initialHistoryKey,
|
|
242
271
|
config.initialSegments,
|
|
243
272
|
false,
|
|
273
|
+
undefined,
|
|
274
|
+
undefined,
|
|
275
|
+
++navInstance,
|
|
276
|
+
false,
|
|
244
277
|
]);
|
|
245
278
|
}
|
|
246
279
|
|
|
@@ -257,6 +290,11 @@ export function createNavigationStore(
|
|
|
257
290
|
// Used to maintain intercept context during action revalidation
|
|
258
291
|
let interceptSourceUrl: string | null = null;
|
|
259
292
|
|
|
293
|
+
// Router identity - tracks which router is currently active.
|
|
294
|
+
// When this changes on a partial response, the client forces a full
|
|
295
|
+
// tree replacement instead of reconciling with stale segments.
|
|
296
|
+
let currentRouterId: string | undefined;
|
|
297
|
+
|
|
260
298
|
// Action state tracking (for useAction hook)
|
|
261
299
|
// Maps action function ID to its tracked state
|
|
262
300
|
const actionStates = new Map<string, TrackedActionState>();
|
|
@@ -268,18 +306,17 @@ export function createNavigationStore(
|
|
|
268
306
|
/**
|
|
269
307
|
* Create a debounced function that batches rapid calls
|
|
270
308
|
*/
|
|
309
|
+
// A non-keyed notifier is the keyed one restricted to a single constant key;
|
|
310
|
+
// its own keyed instance means the "" key never collides with action keys.
|
|
271
311
|
function createDebouncedNotifier<T extends (...args: any[]) => void>(
|
|
272
312
|
fn: T,
|
|
273
|
-
ms: number = 20
|
|
313
|
+
ms: number = 20,
|
|
274
314
|
): T {
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
fn(...args);
|
|
281
|
-
}, ms);
|
|
282
|
-
}) as T;
|
|
315
|
+
const keyed = createKeyedDebouncedNotifier(
|
|
316
|
+
(_key: string, ...args: any[]) => fn(...args),
|
|
317
|
+
ms,
|
|
318
|
+
);
|
|
319
|
+
return ((...args: Parameters<T>) => keyed("", ...args)) as T;
|
|
283
320
|
}
|
|
284
321
|
|
|
285
322
|
/**
|
|
@@ -297,7 +334,7 @@ export function createNavigationStore(
|
|
|
297
334
|
setTimeout(() => {
|
|
298
335
|
timeouts.delete(key);
|
|
299
336
|
fn(key, ...args);
|
|
300
|
-
}, ms)
|
|
337
|
+
}, ms),
|
|
301
338
|
);
|
|
302
339
|
}) as T;
|
|
303
340
|
}
|
|
@@ -312,7 +349,7 @@ export function createNavigationStore(
|
|
|
312
349
|
if (listeners) {
|
|
313
350
|
listeners.forEach((listener) => listener(state));
|
|
314
351
|
}
|
|
315
|
-
}
|
|
352
|
+
},
|
|
316
353
|
);
|
|
317
354
|
|
|
318
355
|
/**
|
|
@@ -320,22 +357,35 @@ export function createNavigationStore(
|
|
|
320
357
|
*/
|
|
321
358
|
function clearCacheInternal(): void {
|
|
322
359
|
historyCache.length = 0;
|
|
360
|
+
clearPrefetchCache();
|
|
323
361
|
}
|
|
324
362
|
|
|
325
363
|
/**
|
|
326
|
-
* Mark
|
|
364
|
+
* Mark every history entry stale WITHOUT touching the prefetch caches or the
|
|
365
|
+
* rango state. Used by the jar-divergence observer: an external rotation has
|
|
366
|
+
* already changed the state value (so prefetch/HTTP entries strand under the
|
|
367
|
+
* retired key), and this tab must NOT re-rotate — only the history cache,
|
|
368
|
+
* which is not state-keyed, needs marking.
|
|
327
369
|
*/
|
|
328
|
-
function
|
|
370
|
+
function markHistoryStale(): void {
|
|
329
371
|
for (let i = 0; i < historyCache.length; i++) {
|
|
330
372
|
historyCache[i][2] = true;
|
|
331
373
|
}
|
|
332
374
|
}
|
|
333
375
|
|
|
376
|
+
/**
|
|
377
|
+
* Mark all cache entries as stale (internal - does not broadcast). Also
|
|
378
|
+
* clears the prefetch caches, which rotates the rango state.
|
|
379
|
+
*/
|
|
380
|
+
function markCacheAsStaleInternal(): void {
|
|
381
|
+
markHistoryStale();
|
|
382
|
+
clearPrefetchCache();
|
|
383
|
+
}
|
|
384
|
+
|
|
334
385
|
/**
|
|
335
386
|
* Clear the history cache and broadcast to other tabs
|
|
336
387
|
*/
|
|
337
388
|
function clearCacheAndBroadcast(): void {
|
|
338
|
-
console.log("[Browser] Clearing cache and broadcasting to other tabs");
|
|
339
389
|
clearCacheInternal();
|
|
340
390
|
broadcastInvalidation();
|
|
341
391
|
}
|
|
@@ -344,9 +394,6 @@ export function createNavigationStore(
|
|
|
344
394
|
* Mark cache as stale and broadcast to other tabs
|
|
345
395
|
*/
|
|
346
396
|
function markStaleAndBroadcast(): void {
|
|
347
|
-
console.log(
|
|
348
|
-
"[Browser] Marking cache as stale and broadcasting to other tabs"
|
|
349
|
-
);
|
|
350
397
|
markCacheAsStaleInternal();
|
|
351
398
|
broadcastInvalidation();
|
|
352
399
|
}
|
|
@@ -369,14 +416,6 @@ export function createNavigationStore(
|
|
|
369
416
|
path: currentPath,
|
|
370
417
|
segmentIds: currentSegmentIds,
|
|
371
418
|
});
|
|
372
|
-
console.log(
|
|
373
|
-
"[Browser] Broadcast sent for path:",
|
|
374
|
-
currentPath,
|
|
375
|
-
"segments:",
|
|
376
|
-
currentSegmentIds.join(", ")
|
|
377
|
-
);
|
|
378
|
-
} else {
|
|
379
|
-
console.warn("[Browser] No BroadcastChannel available");
|
|
380
419
|
}
|
|
381
420
|
}
|
|
382
421
|
|
|
@@ -393,7 +432,7 @@ export function createNavigationStore(
|
|
|
393
432
|
// Check for shared segments between tabs
|
|
394
433
|
// Routes sharing any segment (layout, loader, etc.) should invalidate together
|
|
395
434
|
const hasSharedSegment = mutatedSegmentIds.some((id) =>
|
|
396
|
-
currentSegmentIds.includes(id)
|
|
435
|
+
currentSegmentIds.includes(id),
|
|
397
436
|
);
|
|
398
437
|
|
|
399
438
|
if (!hasSharedSegment) {
|
|
@@ -401,34 +440,21 @@ export function createNavigationStore(
|
|
|
401
440
|
return;
|
|
402
441
|
}
|
|
403
442
|
|
|
404
|
-
console.log(
|
|
405
|
-
"[Browser] Cache marked stale by another tab, shared segments:",
|
|
406
|
-
mutatedSegmentIds
|
|
407
|
-
.filter((id) => currentSegmentIds.includes(id))
|
|
408
|
-
.join(", ")
|
|
409
|
-
);
|
|
410
443
|
markCacheAsStaleInternal();
|
|
411
444
|
|
|
412
445
|
// Auto-refresh if enabled and callback is registered
|
|
413
446
|
if (crossTabAutoRefresh && crossTabRefreshCallback) {
|
|
414
447
|
// If idle, refresh immediately. If loading, wait for idle then refresh.
|
|
415
448
|
if (navState.state === "idle") {
|
|
416
|
-
console.log("[Browser] Cross-tab refresh triggered (idle)");
|
|
417
449
|
crossTabRefreshCallback();
|
|
418
450
|
} else if (!pendingCrossTabRefresh) {
|
|
419
451
|
// Only queue one refresh, ignore subsequent events while loading
|
|
420
452
|
pendingCrossTabRefresh = true;
|
|
421
|
-
console.log(
|
|
422
|
-
"[Browser] Navigation in progress, deferring cross-tab refresh"
|
|
423
|
-
);
|
|
424
453
|
// Subscribe to state changes, refresh when idle
|
|
425
454
|
const listener: StateListener = () => {
|
|
426
455
|
if (navState.state === "idle") {
|
|
427
456
|
stateListeners.delete(listener);
|
|
428
457
|
pendingCrossTabRefresh = false;
|
|
429
|
-
console.log(
|
|
430
|
-
"[Browser] Cross-tab refresh triggered (deferred)"
|
|
431
|
-
);
|
|
432
458
|
crossTabRefreshCallback?.();
|
|
433
459
|
}
|
|
434
460
|
};
|
|
@@ -565,6 +591,29 @@ export function createNavigationStore(
|
|
|
565
591
|
currentHistoryKey = key;
|
|
566
592
|
},
|
|
567
593
|
|
|
594
|
+
/**
|
|
595
|
+
* Current nav-instance token: the instance of the most recently committed
|
|
596
|
+
* navigation (the value last written by cacheSegmentsForHistory). A late
|
|
597
|
+
* async handle resolution captures this at the start of its own nav and
|
|
598
|
+
* compares it back here to detect whether a NEWER navigation has since
|
|
599
|
+
* committed (token advanced), guarding against a stale nav writing a fresher
|
|
600
|
+
* nav's live state.
|
|
601
|
+
*/
|
|
602
|
+
getNavInstance(): number {
|
|
603
|
+
return navInstance;
|
|
604
|
+
},
|
|
605
|
+
|
|
606
|
+
/**
|
|
607
|
+
* The nav-instance token recorded on a specific cache entry, or undefined if
|
|
608
|
+
* no entry exists for that key. Because the history key is URL-only, this is
|
|
609
|
+
* how a late resolution tells "the entry I seeded is still mine" from "a
|
|
610
|
+
* newer same-URL visit replaced my entry".
|
|
611
|
+
*/
|
|
612
|
+
getCacheEntryInstance(historyKey: string): number | undefined {
|
|
613
|
+
const entry = historyCache.find(([key]) => key === historyKey);
|
|
614
|
+
return entry ? entry[5] : undefined;
|
|
615
|
+
},
|
|
616
|
+
|
|
568
617
|
/**
|
|
569
618
|
* Store segments for a history entry
|
|
570
619
|
* Updates existing entry if key exists, otherwise adds new entry
|
|
@@ -574,7 +623,7 @@ export function createNavigationStore(
|
|
|
574
623
|
cacheSegmentsForHistory(
|
|
575
624
|
historyKey: string,
|
|
576
625
|
segments: ResolvedSegment[],
|
|
577
|
-
handleData?: HandleData
|
|
626
|
+
handleData?: HandleData,
|
|
578
627
|
): void {
|
|
579
628
|
// Shallow clone handleData arrays to avoid reference sharing between cache entries
|
|
580
629
|
// We only clone the structure (objects and arrays), not the data items themselves,
|
|
@@ -583,15 +632,36 @@ export function createNavigationStore(
|
|
|
583
632
|
? cloneHandleData(handleData)
|
|
584
633
|
: undefined;
|
|
585
634
|
|
|
635
|
+
// Each commit (create or replace) is a new nav instance. The bump happens
|
|
636
|
+
// here, exactly once per cacheSegmentsForHistory call, so getNavInstance()
|
|
637
|
+
// reflects the visit whose entry this is.
|
|
638
|
+
const instance = ++navInstance;
|
|
639
|
+
|
|
586
640
|
// Check if entry already exists and update it
|
|
587
641
|
const existingIndex = historyCache.findIndex(
|
|
588
|
-
([key]) => key === historyKey
|
|
642
|
+
([key]) => key === historyKey,
|
|
589
643
|
);
|
|
590
644
|
if (existingIndex !== -1) {
|
|
591
|
-
historyCache[existingIndex] = [
|
|
645
|
+
historyCache[existingIndex] = [
|
|
646
|
+
historyKey,
|
|
647
|
+
segments,
|
|
648
|
+
false,
|
|
649
|
+
clonedHandleData,
|
|
650
|
+
currentRouterId,
|
|
651
|
+
instance,
|
|
652
|
+
false, // fresh commit: handles complete unless a deferred apply marks it
|
|
653
|
+
];
|
|
592
654
|
} else {
|
|
593
655
|
// Add new entry at the end (not stale)
|
|
594
|
-
historyCache.push([
|
|
656
|
+
historyCache.push([
|
|
657
|
+
historyKey,
|
|
658
|
+
segments,
|
|
659
|
+
false,
|
|
660
|
+
clonedHandleData,
|
|
661
|
+
currentRouterId,
|
|
662
|
+
instance,
|
|
663
|
+
false,
|
|
664
|
+
]);
|
|
595
665
|
// Remove oldest entries if over limit
|
|
596
666
|
while (historyCache.length > cacheSize) {
|
|
597
667
|
historyCache.shift();
|
|
@@ -603,12 +673,24 @@ export function createNavigationStore(
|
|
|
603
673
|
* Get cached segments for a history entry
|
|
604
674
|
* Returns { segments, stale, handleData } or undefined if not cached
|
|
605
675
|
*/
|
|
606
|
-
getCachedSegments(
|
|
607
|
-
|
|
608
|
-
|
|
676
|
+
getCachedSegments(historyKey: string):
|
|
677
|
+
| {
|
|
678
|
+
segments: ResolvedSegment[];
|
|
679
|
+
stale: boolean;
|
|
680
|
+
handleData?: HandleData;
|
|
681
|
+
routerId?: string;
|
|
682
|
+
handlesPending?: boolean;
|
|
683
|
+
}
|
|
684
|
+
| undefined {
|
|
609
685
|
const entry = historyCache.find(([key]) => key === historyKey);
|
|
610
686
|
if (!entry) return undefined;
|
|
611
|
-
return {
|
|
687
|
+
return {
|
|
688
|
+
segments: entry[1],
|
|
689
|
+
stale: entry[2],
|
|
690
|
+
handleData: entry[3],
|
|
691
|
+
routerId: entry[4],
|
|
692
|
+
handlesPending: entry[6],
|
|
693
|
+
};
|
|
612
694
|
},
|
|
613
695
|
|
|
614
696
|
/**
|
|
@@ -619,19 +701,39 @@ export function createNavigationStore(
|
|
|
619
701
|
},
|
|
620
702
|
|
|
621
703
|
/**
|
|
622
|
-
* Update only the handleData for an existing
|
|
623
|
-
* Does nothing if the cache entry doesn't exist
|
|
624
|
-
*
|
|
704
|
+
* Update only the handleData (and optionally the stale flag) for an existing
|
|
705
|
+
* cache entry. Does nothing if the cache entry doesn't exist.
|
|
706
|
+
*
|
|
707
|
+
* Used to fix stale handleData after async handles processing AND to flip an
|
|
708
|
+
* entry's stale / handlesPending bits for the deferred-Meta
|
|
709
|
+
* invalidate+revalidate path: while a nav's Meta is deferred-pending its
|
|
710
|
+
* entry is marked stale + handlesPending (a popstate return then revalidates
|
|
711
|
+
* with a full re-render instead of serving the carry/seed as fresh), and once
|
|
712
|
+
* the deferred Meta resolves both are cleared. When a flag is omitted the
|
|
713
|
+
* entry's current value is preserved.
|
|
625
714
|
*/
|
|
626
|
-
updateCacheHandleData(
|
|
715
|
+
updateCacheHandleData(
|
|
716
|
+
historyKey: string,
|
|
717
|
+
handleData: HandleData,
|
|
718
|
+
stale?: boolean,
|
|
719
|
+
handlesPending?: boolean,
|
|
720
|
+
): void {
|
|
627
721
|
const existingIndex = historyCache.findIndex(
|
|
628
|
-
([key]) => key === historyKey
|
|
722
|
+
([key]) => key === historyKey,
|
|
629
723
|
);
|
|
630
724
|
if (existingIndex !== -1) {
|
|
631
725
|
const entry = historyCache[existingIndex];
|
|
632
726
|
// Shallow clone handleData arrays to avoid reference sharing
|
|
633
727
|
const clonedHandleData = cloneHandleData(handleData);
|
|
634
|
-
historyCache[existingIndex] = [
|
|
728
|
+
historyCache[existingIndex] = [
|
|
729
|
+
entry[0],
|
|
730
|
+
entry[1],
|
|
731
|
+
stale ?? entry[2], // set stale when provided, else preserve current
|
|
732
|
+
clonedHandleData,
|
|
733
|
+
entry[4], // preserve routerId
|
|
734
|
+
entry[5], // preserve navInstance (entry ownership identity)
|
|
735
|
+
handlesPending ?? entry[6], // set when provided, else preserve current
|
|
736
|
+
];
|
|
635
737
|
}
|
|
636
738
|
},
|
|
637
739
|
|
|
@@ -640,14 +742,17 @@ export function createNavigationStore(
|
|
|
640
742
|
* Called after server actions to indicate data may be outdated
|
|
641
743
|
*/
|
|
642
744
|
markCacheAsStale(): void {
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
745
|
+
markCacheAsStaleInternal();
|
|
746
|
+
},
|
|
747
|
+
|
|
748
|
+
/**
|
|
749
|
+
* Mark every history entry stale WITHOUT clearing the prefetch caches or
|
|
750
|
+
* rotating the rango state. The jar-divergence observer calls this after an
|
|
751
|
+
* external rotation has already changed the state value, so re-rotating
|
|
752
|
+
* here would ping-pong with the tab that rotated.
|
|
753
|
+
*/
|
|
754
|
+
markHistoryCacheStale(): void {
|
|
755
|
+
markHistoryStale();
|
|
651
756
|
},
|
|
652
757
|
|
|
653
758
|
/**
|
|
@@ -666,14 +771,6 @@ export function createNavigationStore(
|
|
|
666
771
|
markStaleAndBroadcast();
|
|
667
772
|
},
|
|
668
773
|
|
|
669
|
-
/**
|
|
670
|
-
* Broadcast cache invalidation to other tabs without clearing local cache
|
|
671
|
-
* Used after consolidation fetch where local cache has fresh data
|
|
672
|
-
*/
|
|
673
|
-
broadcastCacheInvalidation(): void {
|
|
674
|
-
broadcastInvalidation();
|
|
675
|
-
},
|
|
676
|
-
|
|
677
774
|
/**
|
|
678
775
|
* Set the callback to invoke when cross-tab refresh is triggered
|
|
679
776
|
* Called by navigation bridge during initialization
|
|
@@ -704,6 +801,14 @@ export function createNavigationStore(
|
|
|
704
801
|
interceptSourceUrl = url;
|
|
705
802
|
},
|
|
706
803
|
|
|
804
|
+
getRouterId(): string | undefined {
|
|
805
|
+
return currentRouterId;
|
|
806
|
+
},
|
|
807
|
+
|
|
808
|
+
setRouterId(id: string): void {
|
|
809
|
+
currentRouterId = id;
|
|
810
|
+
},
|
|
811
|
+
|
|
707
812
|
// ========================================================================
|
|
708
813
|
// UI Update Notifications
|
|
709
814
|
// ========================================================================
|
|
@@ -745,7 +850,7 @@ export function createNavigationStore(
|
|
|
745
850
|
*/
|
|
746
851
|
setActionState(
|
|
747
852
|
actionId: string,
|
|
748
|
-
partial: Partial<TrackedActionState
|
|
853
|
+
partial: Partial<TrackedActionState>,
|
|
749
854
|
): void {
|
|
750
855
|
const current = actionStates.get(actionId) ?? { ...DEFAULT_ACTION_STATE };
|
|
751
856
|
const updated: TrackedActionState = {
|
|
@@ -763,7 +868,7 @@ export function createNavigationStore(
|
|
|
763
868
|
*/
|
|
764
869
|
subscribeToAction(
|
|
765
870
|
actionId: string,
|
|
766
|
-
listener: ActionStateListener
|
|
871
|
+
listener: ActionStateListener,
|
|
767
872
|
): () => void {
|
|
768
873
|
let listeners = actionListeners.get(actionId);
|
|
769
874
|
if (!listeners) {
|
|
@@ -782,42 +887,3 @@ export function createNavigationStore(
|
|
|
782
887
|
},
|
|
783
888
|
};
|
|
784
889
|
}
|
|
785
|
-
|
|
786
|
-
// Singleton store instance
|
|
787
|
-
let storeInstance: NavigationStore | null = null;
|
|
788
|
-
|
|
789
|
-
/**
|
|
790
|
-
* Initialize the global navigation store
|
|
791
|
-
*
|
|
792
|
-
* Should be called once during app initialization.
|
|
793
|
-
* Subsequent calls return the existing instance.
|
|
794
|
-
*/
|
|
795
|
-
export function initNavigationStore(
|
|
796
|
-
config?: NavigationStoreConfig
|
|
797
|
-
): NavigationStore {
|
|
798
|
-
if (!storeInstance) {
|
|
799
|
-
storeInstance = createNavigationStore(config);
|
|
800
|
-
}
|
|
801
|
-
return storeInstance;
|
|
802
|
-
}
|
|
803
|
-
|
|
804
|
-
/**
|
|
805
|
-
* Get the global navigation store
|
|
806
|
-
*
|
|
807
|
-
* Throws if store hasn't been initialized.
|
|
808
|
-
*/
|
|
809
|
-
export function getNavigationStore(): NavigationStore {
|
|
810
|
-
if (!storeInstance) {
|
|
811
|
-
throw new Error(
|
|
812
|
-
"Navigation store not initialized. Call initNavigationStore first."
|
|
813
|
-
);
|
|
814
|
-
}
|
|
815
|
-
return storeInstance;
|
|
816
|
-
}
|
|
817
|
-
|
|
818
|
-
/**
|
|
819
|
-
* Reset the store instance (for testing)
|
|
820
|
-
*/
|
|
821
|
-
export function resetNavigationStore(): void {
|
|
822
|
-
storeInstance = null;
|
|
823
|
-
}
|