@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
|
@@ -9,18 +9,10 @@ import {
|
|
|
9
9
|
} from "node:fs";
|
|
10
10
|
import { resolve } from "node:path";
|
|
11
11
|
|
|
12
|
-
/**
|
|
13
|
-
* Escape special RegExp characters in a string for safe interpolation
|
|
14
|
-
* into new RegExp() patterns.
|
|
15
|
-
*/
|
|
16
12
|
export function escapeRegExp(str: string): string {
|
|
17
13
|
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
18
14
|
}
|
|
19
15
|
|
|
20
|
-
/**
|
|
21
|
-
* Encode route param values for path interpolation while preserving path
|
|
22
|
-
* separators for wildcard params (splat-style values can include `/`).
|
|
23
|
-
*/
|
|
24
16
|
export function encodePathParam(value: unknown): string {
|
|
25
17
|
return String(value)
|
|
26
18
|
.split("/")
|
|
@@ -28,11 +20,6 @@ export function encodePathParam(value: unknown): string {
|
|
|
28
20
|
.join("/");
|
|
29
21
|
}
|
|
30
22
|
|
|
31
|
-
/**
|
|
32
|
-
* Substitute route params into a pattern, stripping constraint and optional
|
|
33
|
-
* syntax (:param(a|b)? -> value). Also handles wildcard params (*key).
|
|
34
|
-
* Optional params not present in `params` are removed from the output.
|
|
35
|
-
*/
|
|
36
23
|
export function substituteRouteParams(
|
|
37
24
|
pattern: string,
|
|
38
25
|
params: Record<string, string>,
|
|
@@ -41,16 +28,9 @@ export function substituteRouteParams(
|
|
|
41
28
|
let result = pattern;
|
|
42
29
|
let hadOmittedOptional = false;
|
|
43
30
|
|
|
44
|
-
// First pass: substitute provided params.
|
|
45
|
-
// Empty string on an optional placeholder is treated as omitted (the trie
|
|
46
|
-
// matcher fills unmatched optionals with "" — letting the second pass
|
|
47
|
-
// strip them keeps slash cleanup consistent). Empty string on required
|
|
48
|
-
// `:key` or wildcard `*key` still substitutes, matching prior behaviour.
|
|
49
31
|
for (const [key, value] of Object.entries(params)) {
|
|
50
32
|
const escaped = escapeRegExp(key);
|
|
51
33
|
if (value === "") {
|
|
52
|
-
// Only replace required placeholders (negative lookahead for `?`);
|
|
53
|
-
// leave `:key?` for the second pass.
|
|
54
34
|
result = result.replace(
|
|
55
35
|
new RegExp(`:${escaped}(\\([^)]*\\))?(?!\\?)`),
|
|
56
36
|
"",
|
|
@@ -65,13 +45,11 @@ export function substituteRouteParams(
|
|
|
65
45
|
}
|
|
66
46
|
}
|
|
67
47
|
|
|
68
|
-
// Second pass: strip remaining optional param placeholders not in params
|
|
69
48
|
result = result.replace(/:([a-zA-Z_][a-zA-Z0-9_]*)(\([^)]*\))?\?/g, () => {
|
|
70
49
|
hadOmittedOptional = true;
|
|
71
50
|
return "";
|
|
72
51
|
});
|
|
73
52
|
|
|
74
|
-
// Clean up slashes from omitted optional segments
|
|
75
53
|
if (hadOmittedOptional) {
|
|
76
54
|
const hadTrailingSlash = pattern.length > 1 && pattern.endsWith("/");
|
|
77
55
|
result = result.replace(/\/\/+/g, "/").replace(/\/+$/, "") || "/";
|
|
@@ -81,10 +59,6 @@ export function substituteRouteParams(
|
|
|
81
59
|
return result;
|
|
82
60
|
}
|
|
83
61
|
|
|
84
|
-
/**
|
|
85
|
-
* Run an async function over items with bounded concurrency.
|
|
86
|
-
* Errors propagate immediately and abort remaining work.
|
|
87
|
-
*/
|
|
88
62
|
export async function runWithConcurrency<T>(
|
|
89
63
|
items: T[],
|
|
90
64
|
concurrency: number,
|
|
@@ -105,10 +79,6 @@ export async function runWithConcurrency<T>(
|
|
|
105
79
|
await Promise.all(Array.from({ length: limit }, () => worker()));
|
|
106
80
|
}
|
|
107
81
|
|
|
108
|
-
/**
|
|
109
|
-
* Group prerender entries by their concurrency setting so each group
|
|
110
|
-
* can be rendered with the appropriate parallelism.
|
|
111
|
-
*/
|
|
112
82
|
export function groupByConcurrency<T extends { concurrency: number }>(
|
|
113
83
|
entries: T[],
|
|
114
84
|
): { concurrency: number; entries: T[] }[] {
|
|
@@ -128,10 +98,6 @@ export function groupByConcurrency<T extends { concurrency: number }>(
|
|
|
128
98
|
}));
|
|
129
99
|
}
|
|
130
100
|
|
|
131
|
-
/**
|
|
132
|
-
* Notify all routers' onError callbacks about a build-time error.
|
|
133
|
-
* Uses a synthetic request since there is no real request during build.
|
|
134
|
-
*/
|
|
135
101
|
export function notifyOnError(
|
|
136
102
|
registry: Map<string, any>,
|
|
137
103
|
error: unknown,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Plugin } from "vite";
|
|
1
|
+
import type { Plugin, ResolvedConfig } from "vite";
|
|
2
2
|
import * as Vite from "vite";
|
|
3
3
|
import { getPublishedPackageName } from "./package-resolution.js";
|
|
4
4
|
import { performanceTracksOptimizeDepsPlugin } from "../plugins/performance-tracks.js";
|
|
@@ -6,39 +6,53 @@ import {
|
|
|
6
6
|
VIRTUAL_ENTRY_BROWSER,
|
|
7
7
|
VIRTUAL_ENTRY_SSR,
|
|
8
8
|
getVirtualEntryRSC,
|
|
9
|
+
getVirtualEntryRSCHost,
|
|
10
|
+
getVirtualVersionContent,
|
|
9
11
|
VIRTUAL_IDS,
|
|
10
12
|
} from "../plugins/virtual-entries.js";
|
|
11
13
|
|
|
14
|
+
// Cloudflare preset: @cloudflare/vite-plugin sets optimizeDeps.entries (string
|
|
15
|
+
// or array) on the rsc environment. Single source for both the discovery plugin
|
|
16
|
+
// and the version injector so they target the same entry.
|
|
17
|
+
export function resolveRscEntryFromConfig(
|
|
18
|
+
config: ResolvedConfig,
|
|
19
|
+
): string | undefined {
|
|
20
|
+
const entries = (config.environments as any)?.["rsc"]?.optimizeDeps?.entries;
|
|
21
|
+
if (typeof entries === "string") return entries;
|
|
22
|
+
if (Array.isArray(entries) && entries.length > 0) return entries[0];
|
|
23
|
+
return undefined;
|
|
24
|
+
}
|
|
25
|
+
|
|
12
26
|
/**
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
27
|
+
* Rolldown plugin to provide the version virtual module during dependency
|
|
28
|
+
* optimization. Vite 8 optimizes deps with Rolldown (a Rollup-style plugin
|
|
29
|
+
* pipeline that is separate from the main plugin set), so this is a
|
|
30
|
+
* resolveId/load plugin under optimizeDeps.rolldownOptions. Any dep pulled into
|
|
31
|
+
* optimization that imports the version virtual module gets a "dev" stub here;
|
|
32
|
+
* the real VERSION is injected into runtime modules by the version plugin.
|
|
16
33
|
*/
|
|
17
|
-
const
|
|
34
|
+
const versionRolldownPlugin = {
|
|
18
35
|
name: "@rangojs/router-version",
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
loader: "js",
|
|
29
|
-
}),
|
|
30
|
-
);
|
|
36
|
+
resolveId(id: string): string | undefined {
|
|
37
|
+
if (id === VIRTUAL_IDS.version) return "\0" + VIRTUAL_IDS.version;
|
|
38
|
+
return undefined;
|
|
39
|
+
},
|
|
40
|
+
load(id: string): string | undefined {
|
|
41
|
+
if (id === "\0" + VIRTUAL_IDS.version) {
|
|
42
|
+
return getVirtualVersionContent("dev");
|
|
43
|
+
}
|
|
44
|
+
return undefined;
|
|
31
45
|
},
|
|
32
46
|
};
|
|
33
47
|
|
|
34
48
|
/**
|
|
35
|
-
* Shared
|
|
36
|
-
* Includes the version stub plugin
|
|
49
|
+
* Shared Rolldown options for dependency optimization (Vite 8).
|
|
50
|
+
* Includes the version stub plugin and the performance-tracks RSDW patch.
|
|
37
51
|
*/
|
|
38
|
-
export const
|
|
52
|
+
export const sharedRolldownOptions: {
|
|
39
53
|
plugins: any[];
|
|
40
54
|
} = {
|
|
41
|
-
plugins: [
|
|
55
|
+
plugins: [versionRolldownPlugin, performanceTracksOptimizeDepsPlugin()],
|
|
42
56
|
};
|
|
43
57
|
|
|
44
58
|
/**
|
|
@@ -47,7 +61,7 @@ export const sharedEsbuildOptions: {
|
|
|
47
61
|
*/
|
|
48
62
|
export function createVirtualEntriesPlugin(
|
|
49
63
|
entries: { client: string; ssr: string; rsc?: string },
|
|
50
|
-
routerPathRef?: { path?: string },
|
|
64
|
+
routerPathRef?: { path?: string; kind?: "router" | "host" },
|
|
51
65
|
): Plugin {
|
|
52
66
|
// Build virtual modules map based on which entries use virtual IDs
|
|
53
67
|
const virtualModules: Record<string, string> = {};
|
|
@@ -95,7 +109,9 @@ export function createVirtualEntriesPlugin(
|
|
|
95
109
|
: routerPathRef.path;
|
|
96
110
|
// Normalize backslashes for Windows (path.join/slice preserve native separators)
|
|
97
111
|
const absoluteRouterPath = raw.replaceAll("\\", "/");
|
|
98
|
-
return
|
|
112
|
+
return routerPathRef.kind === "host"
|
|
113
|
+
? getVirtualEntryRSCHost(absoluteRouterPath)
|
|
114
|
+
: getVirtualEntryRSC(absoluteRouterPath);
|
|
99
115
|
}
|
|
100
116
|
}
|
|
101
117
|
return null;
|
|
@@ -103,14 +119,54 @@ export function createVirtualEntriesPlugin(
|
|
|
103
119
|
};
|
|
104
120
|
}
|
|
105
121
|
|
|
122
|
+
// Matches rollup's FILE_NAME_CONFLICT message and reports whether the colliding
|
|
123
|
+
// file is a content-hashed asset, e.g.
|
|
124
|
+
// The emitted file "assets/index-DlGNrvnU.css" overwrites a previously ...
|
|
125
|
+
// The emitted file "assets/inter-latin-Dx4kXJAl.woff2" overwrites a ...
|
|
126
|
+
// The match is UNANCHORED on purpose: by the time the warning reaches this user
|
|
127
|
+
// onwarn handler, Vite's logger has wrapped rollup's raw message with an ANSI
|
|
128
|
+
// color sequence and a "[CODE] " label, e.g.
|
|
129
|
+
// "[33m[FILE_NAME_CONFLICT] [0mThe emitted file \"...\" overwrites ..."
|
|
130
|
+
// A "^The emitted file" anchor sits behind that prefix and never matches; and
|
|
131
|
+
// Vite also strips the JSON.stringify quotes rollup puts around the filename, so
|
|
132
|
+
// the match is UNANCHORED and quote-OPTIONAL ("?...?"?). The non-whitespace
|
|
133
|
+
// capture stops at the space before "overwrites" (Vite's unquoted display form)
|
|
134
|
+
// or the closing quote (raw rollup form); either way it carries no ANSI.
|
|
135
|
+
// A content-hashed name ends with a "-" separator + a Vite content hash. The
|
|
136
|
+
// hash is a FIXED-LENGTH base64url run ([A-Za-z0-9_-], default 8), so it can
|
|
137
|
+
// itself contain "-"/"_": it CANNOT be located by splitting on the last "-"
|
|
138
|
+
// (that lands inside the hash whenever it carries a dash, e.g. "...-Cabi7G8-" ->
|
|
139
|
+
// "" or "...-CkhJZR-_" -> "_", which let those conflicts leak). Instead take the
|
|
140
|
+
// trailing HASH_LEN chars and require the "-" separator right before them. The
|
|
141
|
+
// hash must hold an uppercase letter or digit (a real hash is never an
|
|
142
|
+
// all-lowercase word), so stable names like "assets/manifest.json" or
|
|
143
|
+
// "assets/loading-skeleton.css" still surface as potential genuine overwrites.
|
|
144
|
+
function isContentHashedAssetConflict(message: string | undefined): boolean {
|
|
145
|
+
if (!message) return false;
|
|
146
|
+
const match =
|
|
147
|
+
/The emitted file "?([^"\s]+)"? overwrites a previously emitted file/.exec(
|
|
148
|
+
message,
|
|
149
|
+
);
|
|
150
|
+
if (!match) return false;
|
|
151
|
+
const fileName = match[1];
|
|
152
|
+
const base = fileName.slice(fileName.lastIndexOf("/") + 1);
|
|
153
|
+
const dot = base.lastIndexOf(".");
|
|
154
|
+
if (dot <= 0) return false;
|
|
155
|
+
const stem = base.slice(0, dot);
|
|
156
|
+
// HASH_LEN tracks Vite's default [hash] width; bump it if an app sets a custom
|
|
157
|
+
// assetFileNames hash length.
|
|
158
|
+
const HASH_LEN = 8;
|
|
159
|
+
if (stem.length < HASH_LEN + 1 || stem[stem.length - HASH_LEN - 1] !== "-") {
|
|
160
|
+
return false;
|
|
161
|
+
}
|
|
162
|
+
const hash = stem.slice(-HASH_LEN);
|
|
163
|
+
return /^[A-Za-z0-9_-]+$/.test(hash) && /[A-Z0-9]/.test(hash);
|
|
164
|
+
}
|
|
165
|
+
|
|
106
166
|
/**
|
|
107
|
-
*
|
|
108
|
-
*
|
|
109
|
-
*
|
|
110
|
-
* - sourcemap incomplete: plugins that transform without generating sourcemaps (router + RSC plugin)
|
|
111
|
-
* - dynamic/static mixed imports: expected for router internals (e.g. request-context, cache-scope)
|
|
112
|
-
* - empty bundle: @vitejs/plugin-rsc scan build (step 1/5) produces an empty "index" chunk
|
|
113
|
-
* because the RSC entry is fully externalized during client-reference analysis
|
|
167
|
+
* Suppress known harmless warnings: "use client" directives, sourcemap errors,
|
|
168
|
+
* mixed imports (expected for router internals), empty bundles, and content-hashed
|
|
169
|
+
* asset collisions from @vitejs/plugin-rsc copying RSC-env assets to the client bundle.
|
|
114
170
|
*/
|
|
115
171
|
export function onwarn(
|
|
116
172
|
warning: Vite.Rollup.RollupLog,
|
|
@@ -119,14 +175,17 @@ export function onwarn(
|
|
|
119
175
|
if (
|
|
120
176
|
warning.code === "MODULE_LEVEL_DIRECTIVE" ||
|
|
121
177
|
warning.code === "SOURCEMAP_ERROR" ||
|
|
122
|
-
warning.code === "EMPTY_BUNDLE"
|
|
178
|
+
warning.code === "EMPTY_BUNDLE" ||
|
|
179
|
+
warning.code === "INEFFECTIVE_DYNAMIC_IMPORT"
|
|
180
|
+
) {
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
if (
|
|
184
|
+
warning.code === "FILE_NAME_CONFLICT" &&
|
|
185
|
+
isContentHashedAssetConflict(warning.message)
|
|
123
186
|
) {
|
|
124
187
|
return;
|
|
125
188
|
}
|
|
126
|
-
// @vitejs/plugin-rsc@0.5.14: rsc:virtual:vite-rsc/assets-manifest renderChunk
|
|
127
|
-
// returns { code } without map, causing Rollup to warn about incorrect sourcemaps.
|
|
128
|
-
// This is harmless (simple string replacement). Remove this suppression if a
|
|
129
|
-
// future version of @vitejs/plugin-rsc fixes the missing sourcemap.
|
|
130
189
|
if (warning.message?.includes("Sourcemap is likely to be incorrect")) {
|
|
131
190
|
return;
|
|
132
191
|
}
|
|
@@ -141,10 +200,6 @@ export function onwarn(
|
|
|
141
200
|
defaultHandler(warning);
|
|
142
201
|
}
|
|
143
202
|
|
|
144
|
-
/**
|
|
145
|
-
* Manual chunks configuration for client build.
|
|
146
|
-
* Splits React and router packages into separate chunks for better caching.
|
|
147
|
-
*/
|
|
148
203
|
export function getManualChunks(id: string): string | undefined {
|
|
149
204
|
const normalized = Vite.normalizePath(id);
|
|
150
205
|
|
|
@@ -156,13 +211,10 @@ export function getManualChunks(id: string): string | undefined {
|
|
|
156
211
|
) {
|
|
157
212
|
return "react";
|
|
158
213
|
}
|
|
159
|
-
// Use dynamic package name from package.json
|
|
160
|
-
// Check both npm install path and workspace symlink resolved path
|
|
161
214
|
const packageName = getPublishedPackageName();
|
|
162
215
|
if (
|
|
163
216
|
normalized.includes(`node_modules/${packageName}/`) ||
|
|
164
|
-
|
|
165
|
-
normalized.includes("packages/rangojs-router/")
|
|
217
|
+
/\/packages\/(rsc-router|rangojs-router)\/(src|dist)\//.test(normalized)
|
|
166
218
|
) {
|
|
167
219
|
return "router";
|
|
168
220
|
}
|
|
@@ -1,99 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Discriminated union of post-reconciliation action response scenarios.
|
|
3
|
-
*
|
|
4
|
-
* Error and full-update-unsupported are handled inline in the bridge
|
|
5
|
-
* before reconciliation. This classifier only runs for partial responses
|
|
6
|
-
* that have been successfully reconciled.
|
|
7
|
-
*/
|
|
8
|
-
export type ActionScenario =
|
|
9
|
-
| {
|
|
10
|
-
type: "navigated-away";
|
|
11
|
-
historyKeyChanged: boolean;
|
|
12
|
-
onInterceptRoute: boolean;
|
|
13
|
-
}
|
|
14
|
-
| { type: "hmr-missing" }
|
|
15
|
-
| { type: "consolidation-needed"; segmentIds: string[] }
|
|
16
|
-
| { type: "concurrent-skip"; otherFetchingCount: number }
|
|
17
|
-
| { type: "normal" };
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* Pure data inputs for classifying a partial action response.
|
|
21
|
-
* All values come from the bridge but no browser APIs or side effects.
|
|
22
|
-
*/
|
|
23
|
-
export interface ClassifierInput {
|
|
24
|
-
/** window.location.pathname captured at action start */
|
|
25
|
-
actionStartPathname: string;
|
|
26
|
-
/** window.location.pathname at classification time */
|
|
27
|
-
currentPathname: string;
|
|
28
|
-
/** window.history.state?.key captured at action start */
|
|
29
|
-
actionStartLocationKey: string | undefined;
|
|
30
|
-
/** window.history.state?.key at classification time */
|
|
31
|
-
currentLocationKey: string | undefined;
|
|
32
|
-
/** Number of segments after reconciliation */
|
|
33
|
-
reconciledSegmentCount: number;
|
|
34
|
-
/** Number of matched segment IDs from server */
|
|
35
|
-
matchedCount: number;
|
|
36
|
-
/** Segment IDs needing consolidation (from concurrent action tracking) */
|
|
37
|
-
consolidationSegments: string[] | null;
|
|
38
|
-
/** Number of other actions still in "fetching" phase */
|
|
39
|
-
otherFetchingActionCount: number;
|
|
40
|
-
/** Current intercept source URL (null when not on intercept route) */
|
|
41
|
-
currentInterceptSource: string | null;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* Classify a partial action response into one of 5 post-reconciliation
|
|
46
|
-
* scenarios.
|
|
47
|
-
*
|
|
48
|
-
* Called after error and full-update cases are handled inline by the bridge.
|
|
49
|
-
* The classification order matches the priority chain:
|
|
50
|
-
* 1. User navigated away during action
|
|
51
|
-
* 2. HMR missing segments (fewer reconciled than matched)
|
|
52
|
-
* 3. Consolidation needed (concurrent actions finished)
|
|
53
|
-
* 4. Concurrent skip (other actions still fetching)
|
|
54
|
-
* 5. Normal (single action, no issues)
|
|
55
|
-
*
|
|
56
|
-
* This is a pure function with no side effects - the bridge handles
|
|
57
|
-
* all UI updates, store mutations, and network requests based on the
|
|
58
|
-
* returned scenario.
|
|
59
|
-
*/
|
|
60
|
-
export function classifyActionResponse(input: ClassifierInput): ActionScenario {
|
|
61
|
-
// Check if user navigated away during the action
|
|
62
|
-
const userNavigatedAway =
|
|
63
|
-
input.currentPathname !== input.actionStartPathname ||
|
|
64
|
-
input.currentLocationKey !== input.actionStartLocationKey;
|
|
65
|
-
|
|
66
|
-
if (userNavigatedAway) {
|
|
67
|
-
const historyKeyChanged =
|
|
68
|
-
input.currentLocationKey !== input.actionStartLocationKey;
|
|
69
|
-
return {
|
|
70
|
-
type: "navigated-away",
|
|
71
|
-
historyKeyChanged,
|
|
72
|
-
onInterceptRoute: input.currentInterceptSource !== null,
|
|
73
|
-
};
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
// HMR resilience: segments missing after reconciliation
|
|
77
|
-
if (input.reconciledSegmentCount < input.matchedCount) {
|
|
78
|
-
return { type: "hmr-missing" };
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
// Consolidation needed for concurrent actions
|
|
82
|
-
if (input.consolidationSegments && input.consolidationSegments.length > 0) {
|
|
83
|
-
return {
|
|
84
|
-
type: "consolidation-needed",
|
|
85
|
-
segmentIds: input.consolidationSegments,
|
|
86
|
-
};
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
// Other actions still fetching - skip UI update
|
|
90
|
-
if (input.otherFetchingActionCount > 0) {
|
|
91
|
-
return {
|
|
92
|
-
type: "concurrent-skip",
|
|
93
|
-
otherFetchingCount: input.otherFetchingActionCount,
|
|
94
|
-
};
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
// Normal single-action completion
|
|
98
|
-
return { type: "normal" };
|
|
99
|
-
}
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
|
|
3
|
-
import { useContext, useCallback } from "react";
|
|
4
|
-
import { NavigationStoreContext } from "./context.js";
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Return type for useClientCache hook
|
|
8
|
-
*/
|
|
9
|
-
export interface ClientCacheControls {
|
|
10
|
-
/**
|
|
11
|
-
* Clear the client-side navigation cache.
|
|
12
|
-
* Call this after data changes that happen outside of server actions
|
|
13
|
-
* (e.g., REST API calls, WebSocket updates, etc.)
|
|
14
|
-
*
|
|
15
|
-
* This will also broadcast to other tabs to clear their caches.
|
|
16
|
-
*/
|
|
17
|
-
clear: () => void;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* Hook to access client-side cache controls
|
|
22
|
-
*
|
|
23
|
-
* Use this when you need to manually invalidate the navigation cache
|
|
24
|
-
* after data changes that happen outside of server actions.
|
|
25
|
-
*
|
|
26
|
-
* Server actions automatically clear the cache, so you only need this for:
|
|
27
|
-
* - REST API mutations
|
|
28
|
-
* - WebSocket-driven updates
|
|
29
|
-
* - Other non-RSC data changes
|
|
30
|
-
*
|
|
31
|
-
* @example
|
|
32
|
-
* ```tsx
|
|
33
|
-
* function DataEditor() {
|
|
34
|
-
* const { clear } = useClientCache();
|
|
35
|
-
*
|
|
36
|
-
* async function handleSave() {
|
|
37
|
-
* await fetch('/api/data', { method: 'POST', body: JSON.stringify(data) });
|
|
38
|
-
* // Clear cache so back/forward navigation shows fresh data
|
|
39
|
-
* clear();
|
|
40
|
-
* }
|
|
41
|
-
*
|
|
42
|
-
* return <button onClick={handleSave}>Save</button>;
|
|
43
|
-
* }
|
|
44
|
-
* ```
|
|
45
|
-
*/
|
|
46
|
-
export function useClientCache(): ClientCacheControls {
|
|
47
|
-
const ctx = useContext(NavigationStoreContext);
|
|
48
|
-
|
|
49
|
-
if (!ctx) {
|
|
50
|
-
throw new Error("useClientCache must be used within NavigationProvider");
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
const clear = useCallback(() => {
|
|
54
|
-
ctx.store.clearHistoryCache();
|
|
55
|
-
}, [ctx]);
|
|
56
|
-
|
|
57
|
-
return { clear };
|
|
58
|
-
}
|
package/src/browser/shallow.ts
DELETED
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Shallow comparison utility for selector optimization
|
|
3
|
-
*
|
|
4
|
-
* Used by useNavigation hook to prevent unnecessary re-renders
|
|
5
|
-
* when the selected value hasn't changed.
|
|
6
|
-
*
|
|
7
|
-
* @param a - First value
|
|
8
|
-
* @param b - Second value
|
|
9
|
-
* @returns true if values are shallowly equal
|
|
10
|
-
*/
|
|
11
|
-
export function shallow<T>(a: T, b: T): boolean {
|
|
12
|
-
// Same reference or primitive equality
|
|
13
|
-
if (Object.is(a, b)) return true;
|
|
14
|
-
|
|
15
|
-
// Different types or non-objects
|
|
16
|
-
if (typeof a !== "object" || typeof b !== "object") return false;
|
|
17
|
-
|
|
18
|
-
// Null checks
|
|
19
|
-
if (a === null || b === null) return false;
|
|
20
|
-
|
|
21
|
-
// Compare object keys
|
|
22
|
-
const keysA = Object.keys(a);
|
|
23
|
-
const keysB = Object.keys(b);
|
|
24
|
-
|
|
25
|
-
if (keysA.length !== keysB.length) return false;
|
|
26
|
-
|
|
27
|
-
// Check each key's value with Object.is
|
|
28
|
-
for (const key of keysA) {
|
|
29
|
-
if (
|
|
30
|
-
!Object.is(
|
|
31
|
-
(a as Record<string, unknown>)[key],
|
|
32
|
-
(b as Record<string, unknown>)[key],
|
|
33
|
-
)
|
|
34
|
-
) {
|
|
35
|
-
return false;
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
return true;
|
|
40
|
-
}
|
package/src/handles/index.ts
DELETED
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Cookie Utilities
|
|
3
|
-
*
|
|
4
|
-
* Parsing and serialization for HTTP cookies used by middleware context.
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import type { CookieOptions } from "./middleware-types.js";
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* Parse cookies from Cookie header
|
|
11
|
-
*/
|
|
12
|
-
export function parseCookies(
|
|
13
|
-
cookieHeader: string | null,
|
|
14
|
-
): Record<string, string> {
|
|
15
|
-
if (!cookieHeader) return {};
|
|
16
|
-
|
|
17
|
-
const cookies: Record<string, string> = {};
|
|
18
|
-
const pairs = cookieHeader.split(";");
|
|
19
|
-
|
|
20
|
-
for (const pair of pairs) {
|
|
21
|
-
const [name, ...rest] = pair.trim().split("=");
|
|
22
|
-
if (name) {
|
|
23
|
-
const raw = rest.join("=");
|
|
24
|
-
try {
|
|
25
|
-
cookies[name] = decodeURIComponent(raw);
|
|
26
|
-
} catch {
|
|
27
|
-
// Malformed percent-encoded value (e.g. %zz) - fall back to raw value
|
|
28
|
-
cookies[name] = raw;
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
return cookies;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* Serialize a cookie for Set-Cookie header
|
|
38
|
-
*/
|
|
39
|
-
export function serializeCookie(
|
|
40
|
-
name: string,
|
|
41
|
-
value: string,
|
|
42
|
-
options: CookieOptions = {},
|
|
43
|
-
): string {
|
|
44
|
-
let cookie = `${encodeURIComponent(name)}=${encodeURIComponent(value)}`;
|
|
45
|
-
|
|
46
|
-
if (options.domain) cookie += `; Domain=${options.domain}`;
|
|
47
|
-
if (options.path) cookie += `; Path=${options.path}`;
|
|
48
|
-
if (options.maxAge !== undefined) cookie += `; Max-Age=${options.maxAge}`;
|
|
49
|
-
if (options.expires) cookie += `; Expires=${options.expires.toUTCString()}`;
|
|
50
|
-
if (options.httpOnly) cookie += "; HttpOnly";
|
|
51
|
-
if (options.secure) cookie += "; Secure";
|
|
52
|
-
if (options.sameSite) cookie += `; SameSite=${options.sameSite}`;
|
|
53
|
-
|
|
54
|
-
return cookie;
|
|
55
|
-
}
|