react-router 8.2.0 → 8.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +67 -0
- package/dist/development/dom-export.js +1 -1
- package/dist/development/index-react-server-client.js +1 -1
- package/dist/development/index-react-server.d.ts +106 -17
- package/dist/development/index-react-server.js +168 -42
- package/dist/development/index.js +1 -1
- package/dist/development/lib/actions.js +1 -1
- package/dist/development/lib/components.js +1 -1
- package/dist/development/lib/context.js +1 -1
- package/dist/development/lib/dom/dom.d.ts +24 -24
- package/dist/development/lib/dom/dom.js +25 -25
- package/dist/development/lib/dom/lib.d.ts +2 -1
- package/dist/development/lib/dom/lib.js +5 -4
- package/dist/development/lib/dom/server.js +1 -1
- package/dist/development/lib/dom/ssr/components.js +1 -1
- package/dist/development/lib/dom/ssr/data.js +1 -1
- package/dist/development/lib/dom/ssr/errorBoundaries.js +1 -1
- package/dist/development/lib/dom/ssr/fallback.js +1 -1
- package/dist/development/lib/dom/ssr/fog-of-war.js +26 -21
- package/dist/development/lib/dom/ssr/hydration.js +1 -1
- package/dist/development/lib/dom/ssr/invariant.js +1 -1
- package/dist/development/lib/dom/ssr/links.js +1 -1
- package/dist/development/lib/dom/ssr/markup.js +1 -1
- package/dist/development/lib/dom/ssr/routeModules.js +1 -1
- package/dist/development/lib/dom/ssr/routes-test-stub.d.ts +13 -0
- package/dist/development/lib/dom/ssr/routes-test-stub.js +14 -1
- package/dist/development/lib/dom/ssr/routes.js +1 -1
- package/dist/development/lib/dom/ssr/server.js +1 -1
- package/dist/development/lib/dom/ssr/single-fetch.js +1 -1
- package/dist/development/lib/dom-export/dom-router-provider.js +1 -1
- package/dist/development/lib/dom-export/hydrated-router.js +1 -1
- package/dist/development/lib/errors.js +1 -1
- package/dist/development/lib/hooks.js +1 -1
- package/dist/development/lib/href.d.ts +24 -8
- package/dist/development/lib/href.js +28 -11
- package/dist/development/lib/router/history.d.ts +6 -0
- package/dist/development/lib/router/history.js +7 -1
- package/dist/development/lib/router/instrumentation.js +1 -1
- package/dist/development/lib/router/router.js +1 -1
- package/dist/development/lib/router/url.js +1 -1
- package/dist/development/lib/router/utils.d.ts +12 -0
- package/dist/development/lib/router/utils.js +57 -3
- package/dist/development/lib/rsc/browser.js +34 -24
- package/dist/development/lib/rsc/errorBoundaries.js +1 -1
- package/dist/development/lib/rsc/html-stream/browser.js +1 -1
- package/dist/development/lib/rsc/html-stream/server.js +29 -10
- package/dist/development/lib/rsc/route-modules.js +1 -1
- package/dist/development/lib/rsc/server.rsc.d.ts +5 -1
- package/dist/development/lib/rsc/server.ssr.d.ts +29 -6
- package/dist/development/lib/rsc/server.ssr.js +27 -12
- package/dist/development/lib/server-runtime/cookies.d.ts +28 -2
- package/dist/development/lib/server-runtime/cookies.js +17 -3
- package/dist/development/lib/server-runtime/crypto.js +1 -1
- package/dist/development/lib/server-runtime/data.js +1 -1
- package/dist/development/lib/server-runtime/dev.js +1 -1
- package/dist/development/lib/server-runtime/entry.js +1 -1
- package/dist/development/lib/server-runtime/errors.js +1 -1
- package/dist/development/lib/server-runtime/headers.js +1 -1
- package/dist/development/lib/server-runtime/invariant.js +1 -1
- package/dist/development/lib/server-runtime/mode.js +1 -1
- package/dist/development/lib/server-runtime/routeMatching.js +1 -1
- package/dist/development/lib/server-runtime/routes.js +1 -1
- package/dist/development/lib/server-runtime/server.d.ts +12 -0
- package/dist/development/lib/server-runtime/server.js +13 -1
- package/dist/development/lib/server-runtime/serverHandoff.js +1 -1
- package/dist/development/lib/server-runtime/sessions/cookieStorage.d.ts +8 -0
- package/dist/development/lib/server-runtime/sessions/cookieStorage.js +9 -1
- package/dist/development/lib/server-runtime/sessions/memoryStorage.d.ts +10 -4
- package/dist/development/lib/server-runtime/sessions/memoryStorage.js +12 -6
- package/dist/development/lib/server-runtime/sessions.d.ts +31 -2
- package/dist/development/lib/server-runtime/sessions.js +20 -3
- package/dist/development/lib/server-runtime/single-fetch.js +1 -1
- package/dist/development/lib/server-runtime/urls.js +1 -1
- package/dist/development/lib/server-runtime/warnings.js +1 -1
- package/dist/development/lib/types/internal.js +1 -1
- package/dist/development/vendor/turbo-stream-v2/flatten.js +1 -1
- package/dist/development/vendor/turbo-stream-v2/turbo-stream.js +1 -1
- package/dist/development/vendor/turbo-stream-v2/unflatten.js +1 -1
- package/dist/development/vendor/turbo-stream-v2/utils.js +1 -1
- package/dist/production/dom-export.js +1 -1
- package/dist/production/index-react-server-client.js +1 -1
- package/dist/production/index-react-server.d.ts +106 -17
- package/dist/production/index-react-server.js +168 -42
- package/dist/production/index.js +1 -1
- package/dist/production/lib/actions.js +1 -1
- package/dist/production/lib/components.js +1 -1
- package/dist/production/lib/context.js +1 -1
- package/dist/production/lib/dom/dom.d.ts +24 -24
- package/dist/production/lib/dom/dom.js +25 -25
- package/dist/production/lib/dom/lib.d.ts +2 -1
- package/dist/production/lib/dom/lib.js +5 -4
- package/dist/production/lib/dom/server.js +1 -1
- package/dist/production/lib/dom/ssr/components.js +1 -1
- package/dist/production/lib/dom/ssr/data.js +1 -1
- package/dist/production/lib/dom/ssr/errorBoundaries.js +1 -1
- package/dist/production/lib/dom/ssr/fallback.js +1 -1
- package/dist/production/lib/dom/ssr/fog-of-war.js +26 -21
- package/dist/production/lib/dom/ssr/hydration.js +1 -1
- package/dist/production/lib/dom/ssr/invariant.js +1 -1
- package/dist/production/lib/dom/ssr/links.js +1 -1
- package/dist/production/lib/dom/ssr/markup.js +1 -1
- package/dist/production/lib/dom/ssr/routeModules.js +1 -1
- package/dist/production/lib/dom/ssr/routes-test-stub.d.ts +13 -0
- package/dist/production/lib/dom/ssr/routes-test-stub.js +14 -1
- package/dist/production/lib/dom/ssr/routes.js +1 -1
- package/dist/production/lib/dom/ssr/server.js +1 -1
- package/dist/production/lib/dom/ssr/single-fetch.js +1 -1
- package/dist/production/lib/dom-export/dom-router-provider.js +1 -1
- package/dist/production/lib/dom-export/hydrated-router.js +1 -1
- package/dist/production/lib/errors.js +1 -1
- package/dist/production/lib/hooks.js +1 -1
- package/dist/production/lib/href.d.ts +24 -8
- package/dist/production/lib/href.js +28 -11
- package/dist/production/lib/router/history.d.ts +6 -0
- package/dist/production/lib/router/history.js +7 -1
- package/dist/production/lib/router/instrumentation.js +1 -1
- package/dist/production/lib/router/router.js +1 -1
- package/dist/production/lib/router/url.js +1 -1
- package/dist/production/lib/router/utils.d.ts +12 -0
- package/dist/production/lib/router/utils.js +57 -3
- package/dist/production/lib/rsc/browser.js +34 -24
- package/dist/production/lib/rsc/errorBoundaries.js +1 -1
- package/dist/production/lib/rsc/html-stream/browser.js +1 -1
- package/dist/production/lib/rsc/html-stream/server.js +29 -10
- package/dist/production/lib/rsc/route-modules.js +1 -1
- package/dist/production/lib/rsc/server.rsc.d.ts +5 -1
- package/dist/production/lib/rsc/server.ssr.d.ts +29 -6
- package/dist/production/lib/rsc/server.ssr.js +27 -12
- package/dist/production/lib/server-runtime/cookies.d.ts +28 -2
- package/dist/production/lib/server-runtime/cookies.js +17 -3
- package/dist/production/lib/server-runtime/crypto.js +1 -1
- package/dist/production/lib/server-runtime/data.js +1 -1
- package/dist/production/lib/server-runtime/dev.js +1 -1
- package/dist/production/lib/server-runtime/entry.js +1 -1
- package/dist/production/lib/server-runtime/errors.js +1 -1
- package/dist/production/lib/server-runtime/headers.js +1 -1
- package/dist/production/lib/server-runtime/invariant.js +1 -1
- package/dist/production/lib/server-runtime/mode.js +1 -1
- package/dist/production/lib/server-runtime/routeMatching.js +1 -1
- package/dist/production/lib/server-runtime/routes.js +1 -1
- package/dist/production/lib/server-runtime/server.d.ts +12 -0
- package/dist/production/lib/server-runtime/server.js +13 -1
- package/dist/production/lib/server-runtime/serverHandoff.js +1 -1
- package/dist/production/lib/server-runtime/sessions/cookieStorage.d.ts +8 -0
- package/dist/production/lib/server-runtime/sessions/cookieStorage.js +9 -1
- package/dist/production/lib/server-runtime/sessions/memoryStorage.d.ts +10 -4
- package/dist/production/lib/server-runtime/sessions/memoryStorage.js +12 -6
- package/dist/production/lib/server-runtime/sessions.d.ts +31 -2
- package/dist/production/lib/server-runtime/sessions.js +20 -3
- package/dist/production/lib/server-runtime/single-fetch.js +1 -1
- package/dist/production/lib/server-runtime/urls.js +1 -1
- package/dist/production/lib/server-runtime/warnings.js +1 -1
- package/dist/production/lib/types/internal.js +1 -1
- package/dist/production/vendor/turbo-stream-v2/flatten.js +1 -1
- package/dist/production/vendor/turbo-stream-v2/turbo-stream.js +1 -1
- package/dist/production/vendor/turbo-stream-v2/unflatten.js +1 -1
- package/dist/production/vendor/turbo-stream-v2/utils.js +1 -1
- package/docs/explanation/sessions-and-cookies.md +13 -13
- package/docs/explanation/state-management.md +2 -2
- package/docs/how-to/presets.md +2 -2
- package/docs/how-to/react-server-components.md +53 -1
- package/docs/how-to/security.md +8 -1
- package/docs/how-to/server-bundles.md +2 -2
- package/docs/start/data/route-object.md +2 -2
- package/docs/start/data/routing.md +1 -1
- package/docs/start/framework/pending-ui.md +1 -1
- package/docs/start/framework/route-module.md +8 -8
- package/docs/start/framework/routing.md +1 -1
- package/package.json +1 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* react-router v8.
|
|
2
|
+
* react-router v8.3.0
|
|
3
3
|
*
|
|
4
4
|
* Copyright (c) Remix Software Inc.
|
|
5
5
|
*
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
* @license MIT
|
|
10
10
|
*/
|
|
11
11
|
import { PROTOCOL_RELATIVE_URL_REGEX } from "../router/url.js";
|
|
12
|
-
import { createBrowserHistory, invariant } from "../router/history.js";
|
|
12
|
+
import { createBrowserHistory, createPath, invariant } from "../router/history.js";
|
|
13
13
|
import { ErrorResponseImpl, createContext, resolvePath } from "../router/utils.js";
|
|
14
14
|
import { createRouter, hasInvalidProtocol, isMutationMethod } from "../router/router.js";
|
|
15
15
|
import { RSCRouterContext } from "../context.js";
|
|
@@ -17,7 +17,7 @@ import { RouterProvider } from "../components.js";
|
|
|
17
17
|
import { createRequestInit } from "../dom/ssr/data.js";
|
|
18
18
|
import { getSingleFetchDataStrategyImpl, singleFetchUrl, stripIndexParam } from "../dom/ssr/single-fetch.js";
|
|
19
19
|
import { noActionDefinedError, shouldHydrateRouteLoader } from "../dom/ssr/routes.js";
|
|
20
|
-
import { getPathsWithAncestors } from "../dom/ssr/fog-of-war.js";
|
|
20
|
+
import { getPathsWithAncestors, handleClientVersionMismatch } from "../dom/ssr/fog-of-war.js";
|
|
21
21
|
import { FrameworkContext, setIsHydrated } from "../dom/ssr/components.js";
|
|
22
22
|
import { RSCRouterGlobalErrorBoundary } from "./errorBoundaries.js";
|
|
23
23
|
import { populateRSCRouteModules } from "./route-modules.js";
|
|
@@ -133,6 +133,7 @@ function createRouterFromPayload({ fetchImplementation, createFromReadableStream
|
|
|
133
133
|
routeModules: globalVar.__reactRouterRouteModules
|
|
134
134
|
};
|
|
135
135
|
if (payload.type !== "render") throw new Error("Invalid payload type");
|
|
136
|
+
let { clientVersion } = payload;
|
|
136
137
|
globalVar.__reactRouterRouteModules = globalVar.__reactRouterRouteModules ?? {};
|
|
137
138
|
populateRSCRouteModules(globalVar.__reactRouterRouteModules, payload.matches);
|
|
138
139
|
let routes = payload.matches.reduceRight((previous, match) => {
|
|
@@ -167,7 +168,7 @@ function createRouterFromPayload({ fetchImplementation, createFromReadableStream
|
|
|
167
168
|
basename: payload.basename,
|
|
168
169
|
isSpaMode: false
|
|
169
170
|
}),
|
|
170
|
-
async patchRoutesOnNavigation({ path, signal }) {
|
|
171
|
+
async patchRoutesOnNavigation({ path, signal, fetcherKey }) {
|
|
171
172
|
if (payload.routeDiscovery.mode === "initial") {
|
|
172
173
|
if (!applyPatchesPromise) applyPatchesPromise = (async () => {
|
|
173
174
|
if (!payload.patches) return;
|
|
@@ -182,9 +183,10 @@ function createRouterFromPayload({ fetchImplementation, createFromReadableStream
|
|
|
182
183
|
return;
|
|
183
184
|
}
|
|
184
185
|
if (discoveredPaths.has(path)) return;
|
|
185
|
-
|
|
186
|
+
let { state } = globalVar.__reactRouterDataRouter;
|
|
187
|
+
await fetchAndApplyManifestPatches([path], createFromReadableStream, fetchImplementation, clientVersion, fetcherKey ? window.location.href : createPath(state.navigation.location || state.location), signal);
|
|
186
188
|
},
|
|
187
|
-
dataStrategy: getRSCSingleFetchDataStrategy(() => globalVar.__reactRouterDataRouter, true, createFromReadableStream, fetchImplementation)
|
|
189
|
+
dataStrategy: getRSCSingleFetchDataStrategy(() => globalVar.__reactRouterDataRouter, true, createFromReadableStream, fetchImplementation, clientVersion)
|
|
188
190
|
});
|
|
189
191
|
if (globalVar.__reactRouterDataRouter.state.initialized) {
|
|
190
192
|
globalVar.__routerInitialized = true;
|
|
@@ -237,19 +239,16 @@ function createRouterFromPayload({ fetchImplementation, createFromReadableStream
|
|
|
237
239
|
};
|
|
238
240
|
}
|
|
239
241
|
const renderedRoutesContext = createContext();
|
|
240
|
-
function getRSCSingleFetchDataStrategy(getRouter, ssr, createFromReadableStream, fetchImplementation) {
|
|
242
|
+
function getRSCSingleFetchDataStrategy(getRouter, ssr, createFromReadableStream, fetchImplementation, clientVersion) {
|
|
241
243
|
let dataStrategy = getSingleFetchDataStrategyImpl(getRouter, (match) => {
|
|
242
244
|
let M = match;
|
|
243
245
|
return {
|
|
244
246
|
hasLoader: M.route.hasLoader,
|
|
245
|
-
hasClientLoader: M.route.hasClientLoader
|
|
246
|
-
hasComponent: M.route.hasComponent,
|
|
247
|
-
hasAction: M.route.hasAction,
|
|
248
|
-
hasClientAction: M.route.hasClientAction
|
|
247
|
+
hasClientLoader: M.route.hasClientLoader
|
|
249
248
|
};
|
|
250
|
-
}, getFetchAndDecodeViaRSC(createFromReadableStream, fetchImplementation), ssr, (match) => {
|
|
249
|
+
}, getFetchAndDecodeViaRSC(getRouter, createFromReadableStream, fetchImplementation, clientVersion), ssr, (match) => {
|
|
251
250
|
let M = match;
|
|
252
|
-
return M.route.hasComponent
|
|
251
|
+
return !M.route.hasComponent || M.route.element != null;
|
|
253
252
|
});
|
|
254
253
|
return async (args) => args.runClientMiddleware(async () => {
|
|
255
254
|
args.context.set(renderedRoutesContext, []);
|
|
@@ -268,7 +267,7 @@ function getRSCSingleFetchDataStrategy(getRouter, ssr, createFromReadableStream,
|
|
|
268
267
|
return results;
|
|
269
268
|
});
|
|
270
269
|
}
|
|
271
|
-
function getFetchAndDecodeViaRSC(createFromReadableStream, fetchImplementation) {
|
|
270
|
+
function getFetchAndDecodeViaRSC(getRouter, createFromReadableStream, fetchImplementation, clientVersion) {
|
|
272
271
|
return async (args, targetRoutes) => {
|
|
273
272
|
let { request, context } = args;
|
|
274
273
|
let url = singleFetchUrl(request.url, "rsc");
|
|
@@ -292,6 +291,7 @@ function getFetchAndDecodeViaRSC(createFromReadableStream, fetchImplementation)
|
|
|
292
291
|
} }
|
|
293
292
|
};
|
|
294
293
|
if (payload.type !== "render") throw new Error("Unexpected payload type");
|
|
294
|
+
if (clientVersion !== void 0 && await handleClientVersionMismatch(payload.clientVersion !== clientVersion, clientVersion, createPath(getRouter().state.navigation.location || getRouter().state.location))) return new Promise(() => {});
|
|
295
295
|
context.get(renderedRoutesContext).push(...payload.matches);
|
|
296
296
|
let results = { routes: {} };
|
|
297
297
|
const dataKey = isMutationMethod(request.method) ? "actionData" : "loaderData";
|
|
@@ -347,7 +347,7 @@ function getFetchAndDecodeViaRSC(createFromReadableStream, fetchImplementation)
|
|
|
347
347
|
*/
|
|
348
348
|
function RSCHydratedRouter({ createFromReadableStream, fetch: fetchImplementation = fetch, payload, getContext }) {
|
|
349
349
|
if (payload.type !== "render") throw new Error("Invalid payload type");
|
|
350
|
-
let { routeDiscovery } = payload;
|
|
350
|
+
let { routeDiscovery, clientVersion } = payload;
|
|
351
351
|
let { router, routeModules } = React$1.useMemo(() => createRouterFromPayload({
|
|
352
352
|
payload,
|
|
353
353
|
fetchImplementation,
|
|
@@ -413,7 +413,7 @@ function RSCHydratedRouter({ createFromReadableStream, fetch: fetchImplementatio
|
|
|
413
413
|
});
|
|
414
414
|
if (paths.length === 0) return;
|
|
415
415
|
try {
|
|
416
|
-
await fetchAndApplyManifestPatches(paths, createFromReadableStream, fetchImplementation);
|
|
416
|
+
await fetchAndApplyManifestPatches(paths, createFromReadableStream, fetchImplementation, clientVersion, null);
|
|
417
417
|
} catch (e) {
|
|
418
418
|
console.error("Failed to fetch manifest patches", e);
|
|
419
419
|
}
|
|
@@ -433,7 +433,8 @@ function RSCHydratedRouter({ createFromReadableStream, fetch: fetchImplementatio
|
|
|
433
433
|
}, [
|
|
434
434
|
routeDiscovery,
|
|
435
435
|
createFromReadableStream,
|
|
436
|
-
fetchImplementation
|
|
436
|
+
fetchImplementation,
|
|
437
|
+
clientVersion
|
|
437
438
|
]);
|
|
438
439
|
const frameworkContext = {
|
|
439
440
|
future: {},
|
|
@@ -506,6 +507,7 @@ function createRouteFromServerManifest(match, payload) {
|
|
|
506
507
|
shouldRevalidate: match.shouldRevalidate,
|
|
507
508
|
hasLoader: true,
|
|
508
509
|
hasClientLoader: match.clientLoader != null,
|
|
510
|
+
hasComponent: match.hasComponent,
|
|
509
511
|
hasAction: match.hasAction,
|
|
510
512
|
hasClientAction: match.clientAction != null
|
|
511
513
|
};
|
|
@@ -526,23 +528,31 @@ function preventInvalidServerHandlerCall(type, routeId, hasHandler) {
|
|
|
526
528
|
const nextPaths = /* @__PURE__ */ new Set();
|
|
527
529
|
const discoveredPathsMaxSize = 1e3;
|
|
528
530
|
const discoveredPaths = /* @__PURE__ */ new Set();
|
|
529
|
-
function getManifestUrl(paths) {
|
|
531
|
+
function getManifestUrl(paths, clientVersion) {
|
|
530
532
|
if (paths.length === 0) return null;
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
533
|
+
let url;
|
|
534
|
+
if (paths.length === 1) url = new URL(`${paths[0]}.manifest`, window.location.origin);
|
|
535
|
+
else {
|
|
536
|
+
let basename = (window.__reactRouterDataRouter.basename ?? "").replace(/^\/|\/$/g, "");
|
|
537
|
+
url = new URL(`${basename}/.manifest`, window.location.origin);
|
|
538
|
+
url.searchParams.set("paths", paths.sort().join(","));
|
|
539
|
+
}
|
|
540
|
+
if (clientVersion !== void 0) url.searchParams.set("version", clientVersion);
|
|
535
541
|
return url;
|
|
536
542
|
}
|
|
537
|
-
async function fetchAndApplyManifestPatches(paths, createFromReadableStream, fetchImplementation, signal) {
|
|
543
|
+
async function fetchAndApplyManifestPatches(paths, createFromReadableStream, fetchImplementation, clientVersion, errorReloadPath, signal) {
|
|
538
544
|
paths = getPathsWithAncestors(paths);
|
|
539
|
-
let url = getManifestUrl(paths);
|
|
545
|
+
let url = getManifestUrl(paths, clientVersion);
|
|
540
546
|
if (url == null) return;
|
|
541
547
|
if (url.toString().length > 7680) {
|
|
542
548
|
nextPaths.clear();
|
|
543
549
|
return;
|
|
544
550
|
}
|
|
545
551
|
let response = await fetchImplementation(new Request(url, { signal }));
|
|
552
|
+
if (clientVersion !== void 0 && response.status === 204 && response.headers.has("X-Remix-Reload-Document")) {
|
|
553
|
+
await handleClientVersionMismatch(true, clientVersion, errorReloadPath);
|
|
554
|
+
return;
|
|
555
|
+
}
|
|
546
556
|
if (!response.body || response.status < 200 || response.status >= 300) throw new Error("Unable to fetch new route matches from the server");
|
|
547
557
|
let payload = await createFromReadableStream(response.body, { temporaryReferences: void 0 });
|
|
548
558
|
if (payload.type !== "manifest") throw new Error("Failed to patch routes");
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* react-router v8.
|
|
2
|
+
* react-router v8.3.0
|
|
3
3
|
*
|
|
4
4
|
* Copyright (c) Remix Software Inc.
|
|
5
5
|
*
|
|
@@ -11,11 +11,13 @@
|
|
|
11
11
|
//#region lib/rsc/html-stream/server.ts
|
|
12
12
|
const encoder = new TextEncoder();
|
|
13
13
|
const trailer = "</body></html>";
|
|
14
|
-
function injectRSCPayload(rscStream) {
|
|
14
|
+
function injectRSCPayload(rscStream, { nonce } = {}) {
|
|
15
15
|
let decoder = new TextDecoder();
|
|
16
16
|
let resolveFlightDataPromise;
|
|
17
17
|
let flightDataPromise = new Promise((resolve) => resolveFlightDataPromise = resolve);
|
|
18
18
|
let startedRSC = false;
|
|
19
|
+
let cancelled = false;
|
|
20
|
+
let rscReader = null;
|
|
19
21
|
let buffered = [];
|
|
20
22
|
let timeout = null;
|
|
21
23
|
function flushBufferedChunks(controller) {
|
|
@@ -32,10 +34,12 @@ function injectRSCPayload(rscStream) {
|
|
|
32
34
|
buffered.push(chunk);
|
|
33
35
|
if (timeout) return;
|
|
34
36
|
timeout = setTimeout(async () => {
|
|
37
|
+
if (cancelled) return;
|
|
35
38
|
flushBufferedChunks(controller);
|
|
36
39
|
if (!startedRSC) {
|
|
37
40
|
startedRSC = true;
|
|
38
|
-
|
|
41
|
+
rscReader = rscStream.getReader();
|
|
42
|
+
writeRSCStream(rscReader, controller, () => cancelled, nonce).catch((err) => controller.error(err)).then(resolveFlightDataPromise);
|
|
39
43
|
}
|
|
40
44
|
}, 0);
|
|
41
45
|
},
|
|
@@ -46,30 +50,45 @@ function injectRSCPayload(rscStream) {
|
|
|
46
50
|
flushBufferedChunks(controller);
|
|
47
51
|
}
|
|
48
52
|
controller.enqueue(encoder.encode("</body></html>"));
|
|
53
|
+
},
|
|
54
|
+
async cancel(reason) {
|
|
55
|
+
cancelled = true;
|
|
56
|
+
if (timeout) {
|
|
57
|
+
clearTimeout(timeout);
|
|
58
|
+
timeout = null;
|
|
59
|
+
}
|
|
60
|
+
buffered.length = 0;
|
|
61
|
+
if (rscReader) await rscReader.cancel(reason).catch(() => {});
|
|
62
|
+
else await rscStream.cancel(reason).catch(() => {});
|
|
63
|
+
resolveFlightDataPromise();
|
|
49
64
|
}
|
|
50
65
|
});
|
|
51
66
|
}
|
|
52
|
-
async function writeRSCStream(
|
|
67
|
+
async function writeRSCStream(reader, controller, isCancelled, nonce) {
|
|
53
68
|
let decoder = new TextDecoder("utf-8", { fatal: true });
|
|
54
|
-
const reader = rscStream.getReader();
|
|
55
69
|
try {
|
|
56
70
|
let read;
|
|
57
71
|
while ((read = await reader.read()) && !read.done) {
|
|
72
|
+
if (isCancelled()) return;
|
|
58
73
|
const chunk = read.value;
|
|
59
74
|
try {
|
|
60
|
-
writeChunk(JSON.stringify(decoder.decode(chunk, { stream: true })), controller);
|
|
75
|
+
writeChunk(JSON.stringify(decoder.decode(chunk, { stream: true })), controller, nonce);
|
|
61
76
|
} catch (e) {
|
|
62
|
-
writeChunk(`Uint8Array.from(atob(${JSON.stringify(btoa(String.fromCodePoint(...chunk)))}), m => m.codePointAt(0))`, controller);
|
|
77
|
+
writeChunk(`Uint8Array.from(atob(${JSON.stringify(btoa(String.fromCodePoint(...chunk)))}), m => m.codePointAt(0))`, controller, nonce);
|
|
63
78
|
}
|
|
64
79
|
}
|
|
65
80
|
} finally {
|
|
66
81
|
reader.releaseLock();
|
|
67
82
|
}
|
|
68
83
|
let remaining = decoder.decode();
|
|
69
|
-
if (remaining.length) writeChunk(JSON.stringify(remaining), controller);
|
|
84
|
+
if (remaining.length && !isCancelled()) writeChunk(JSON.stringify(remaining), controller, nonce);
|
|
85
|
+
}
|
|
86
|
+
function writeChunk(chunk, controller, nonce) {
|
|
87
|
+
let nonceAttr = nonce == null ? "" : ` nonce="${escapeAttribute(nonce)}"`;
|
|
88
|
+
controller.enqueue(encoder.encode(`<script${nonceAttr}>${escapeScript(`(self.__FLIGHT_DATA||=[]).push(${chunk})`)}<\/script>`));
|
|
70
89
|
}
|
|
71
|
-
function
|
|
72
|
-
|
|
90
|
+
function escapeAttribute(value) {
|
|
91
|
+
return value.replace(/&/g, "&").replace(/"/g, """).replace(/</g, "<").replace(/>/g, ">");
|
|
73
92
|
}
|
|
74
93
|
function escapeScript(script) {
|
|
75
94
|
return script.replace(/<!--/g, "<\\!--").replace(/<\/(script)/gi, "</\\$1");
|
|
@@ -65,13 +65,13 @@ type RSCRenderPayload = {
|
|
|
65
65
|
type: "render";
|
|
66
66
|
actionData: Record<string, any> | null;
|
|
67
67
|
basename: string | undefined;
|
|
68
|
+
clientVersion?: string;
|
|
68
69
|
errors: Record<string, any> | null;
|
|
69
70
|
loaderData: Record<string, any>;
|
|
70
71
|
location: Location;
|
|
71
72
|
routeDiscovery: RouteDiscovery;
|
|
72
73
|
matches: RSCRouteMatch[];
|
|
73
74
|
patches?: Promise<RSCRouteManifest[]>;
|
|
74
|
-
nonce?: string;
|
|
75
75
|
formState?: ReactFormState;
|
|
76
76
|
};
|
|
77
77
|
type RSCManifestPayload = {
|
|
@@ -168,6 +168,8 @@ type RouteDiscovery = {
|
|
|
168
168
|
* encoding the {@link unstable_RSCPayload}.
|
|
169
169
|
* @param opts.loadServerAction Your `react-server-dom-xyz/server`'s
|
|
170
170
|
* `loadServerAction` function, used to load a server action by ID.
|
|
171
|
+
* @param opts.clientVersion A version derived from the client build output used
|
|
172
|
+
* to detect stale clients during lazy route discovery.
|
|
171
173
|
* @param opts.onError An optional error handler that will be called with any
|
|
172
174
|
* errors that occur during the request processing.
|
|
173
175
|
* @param opts.request The [`Request`](https://developer.mozilla.org/en-US/docs/Web/API/Request)
|
|
@@ -191,6 +193,7 @@ declare function matchRSCServerRequest({
|
|
|
191
193
|
loadServerAction,
|
|
192
194
|
decodeAction,
|
|
193
195
|
decodeFormState,
|
|
196
|
+
clientVersion,
|
|
194
197
|
onError,
|
|
195
198
|
request,
|
|
196
199
|
routes,
|
|
@@ -204,6 +207,7 @@ declare function matchRSCServerRequest({
|
|
|
204
207
|
decodeFormState?: DecodeFormStateFunction;
|
|
205
208
|
requestContext?: RouterContextProvider;
|
|
206
209
|
loadServerAction?: LoadServerActionFunction;
|
|
210
|
+
clientVersion?: string;
|
|
207
211
|
onError?: (error: unknown) => void;
|
|
208
212
|
request: Request;
|
|
209
213
|
routes: RSCRouteConfigEntry[];
|
|
@@ -26,12 +26,17 @@ type SSRCreateFromReadableStreamFunction = (body: ReadableStream<Uint8Array>) =>
|
|
|
26
26
|
* request,
|
|
27
27
|
* serverResponse,
|
|
28
28
|
* createFromReadableStream,
|
|
29
|
-
*
|
|
29
|
+
* nonce,
|
|
30
|
+
* async renderHTML(getPayload, options) {
|
|
30
31
|
* const payload = getPayload();
|
|
31
32
|
*
|
|
32
33
|
* return await renderHTMLToReadableStream(
|
|
33
|
-
* <RSCStaticRouter
|
|
34
|
+
* <RSCStaticRouter
|
|
35
|
+
* getPayload={getPayload}
|
|
36
|
+
* nonce={options.nonce}
|
|
37
|
+
* />,
|
|
34
38
|
* {
|
|
39
|
+
* ...options,
|
|
35
40
|
* bootstrapScriptContent,
|
|
36
41
|
* formState: await payload.formState,
|
|
37
42
|
* }
|
|
@@ -49,6 +54,8 @@ type SSRCreateFromReadableStreamFunction = (body: ReadableStream<Uint8Array>) =>
|
|
|
49
54
|
* @param opts.serverResponse A Response or partial response generated by the [RSC](https://react.dev/reference/rsc/server-components) handler containing a serialized {@link unstable_RSCPayload}.
|
|
50
55
|
* @param opts.hydrate Whether to hydrate the server response with the RSC payload.
|
|
51
56
|
* Defaults to `true`.
|
|
57
|
+
* @param opts.nonce An optional [`nonce`](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Global_attributes/nonce)
|
|
58
|
+
* for inline scripts generated while rendering the HTML document.
|
|
52
59
|
* @param opts.renderHTML A function that renders the {@link unstable_RSCPayload} to
|
|
53
60
|
* HTML, usually using a {@link unstable_RSCStaticRouter | `<RSCStaticRouter>`}.
|
|
54
61
|
* @param opts.request The request to route.
|
|
@@ -61,16 +68,19 @@ declare function routeRSCServerRequest({
|
|
|
61
68
|
serverResponse,
|
|
62
69
|
createFromReadableStream,
|
|
63
70
|
renderHTML,
|
|
64
|
-
hydrate
|
|
71
|
+
hydrate,
|
|
72
|
+
nonce
|
|
65
73
|
}: {
|
|
66
74
|
request: Request;
|
|
67
75
|
serverResponse: Response;
|
|
68
76
|
createFromReadableStream: SSRCreateFromReadableStreamFunction;
|
|
69
77
|
renderHTML: (getPayload: () => DecodedPayload, options: {
|
|
78
|
+
nonce?: string;
|
|
70
79
|
onError(error: unknown): string | undefined;
|
|
71
80
|
onHeaders(headers: Headers): void;
|
|
72
81
|
}) => ReadableStream<Uint8Array> | Promise<ReadableStream<Uint8Array>>;
|
|
73
82
|
hydrate?: boolean;
|
|
83
|
+
nonce?: string;
|
|
74
84
|
}): Promise<Response>;
|
|
75
85
|
/**
|
|
76
86
|
* Props for the {@link unstable_RSCStaticRouter} component.
|
|
@@ -84,6 +94,12 @@ interface RSCStaticRouterProps {
|
|
|
84
94
|
* through from {@link unstable_routeRSCServerRequest}'s `renderHTML`.
|
|
85
95
|
*/
|
|
86
96
|
getPayload: () => DecodedPayload;
|
|
97
|
+
/**
|
|
98
|
+
* An optional [`nonce`](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Global_attributes/nonce)
|
|
99
|
+
* used as the default for nonce-aware components such as `<Links>` and
|
|
100
|
+
* `<ScrollRestoration>`.
|
|
101
|
+
*/
|
|
102
|
+
nonce?: string;
|
|
87
103
|
}
|
|
88
104
|
/**
|
|
89
105
|
* Pre-renders an {@link unstable_RSCPayload} to HTML. Usually used in
|
|
@@ -101,12 +117,17 @@ interface RSCStaticRouterProps {
|
|
|
101
117
|
* request,
|
|
102
118
|
* serverResponse,
|
|
103
119
|
* createFromReadableStream,
|
|
104
|
-
*
|
|
120
|
+
* nonce,
|
|
121
|
+
* async renderHTML(getPayload, options) {
|
|
105
122
|
* const payload = getPayload();
|
|
106
123
|
*
|
|
107
124
|
* return await renderHTMLToReadableStream(
|
|
108
|
-
* <RSCStaticRouter
|
|
125
|
+
* <RSCStaticRouter
|
|
126
|
+
* getPayload={getPayload}
|
|
127
|
+
* nonce={options.nonce}
|
|
128
|
+
* />,
|
|
109
129
|
* {
|
|
130
|
+
* ...options,
|
|
110
131
|
* bootstrapScriptContent,
|
|
111
132
|
* formState: await payload.formState,
|
|
112
133
|
* }
|
|
@@ -120,10 +141,12 @@ interface RSCStaticRouterProps {
|
|
|
120
141
|
* @mode data
|
|
121
142
|
* @param props Props
|
|
122
143
|
* @param {unstable_RSCStaticRouterProps.getPayload} props.getPayload n/a
|
|
144
|
+
* @param {unstable_RSCStaticRouterProps.nonce} props.nonce n/a
|
|
123
145
|
* @returns A React component that renders the {@link unstable_RSCPayload} as HTML.
|
|
124
146
|
*/
|
|
125
147
|
declare function RSCStaticRouter({
|
|
126
|
-
getPayload
|
|
148
|
+
getPayload,
|
|
149
|
+
nonce
|
|
127
150
|
}: RSCStaticRouterProps): React$1.JSX.Element | null;
|
|
128
151
|
//#endregion
|
|
129
152
|
export { RSCStaticRouter, RSCStaticRouterProps, SSRCreateFromReadableStreamFunction, routeRSCServerRequest };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* react-router v8.
|
|
2
|
+
* react-router v8.3.0
|
|
3
3
|
*
|
|
4
4
|
* Copyright (c) Remix Software Inc.
|
|
5
5
|
*
|
|
@@ -40,12 +40,17 @@ const defaultManifestPath = "/__manifest";
|
|
|
40
40
|
* request,
|
|
41
41
|
* serverResponse,
|
|
42
42
|
* createFromReadableStream,
|
|
43
|
-
*
|
|
43
|
+
* nonce,
|
|
44
|
+
* async renderHTML(getPayload, options) {
|
|
44
45
|
* const payload = getPayload();
|
|
45
46
|
*
|
|
46
47
|
* return await renderHTMLToReadableStream(
|
|
47
|
-
* <RSCStaticRouter
|
|
48
|
+
* <RSCStaticRouter
|
|
49
|
+
* getPayload={getPayload}
|
|
50
|
+
* nonce={options.nonce}
|
|
51
|
+
* />,
|
|
48
52
|
* {
|
|
53
|
+
* ...options,
|
|
49
54
|
* bootstrapScriptContent,
|
|
50
55
|
* formState: await payload.formState,
|
|
51
56
|
* }
|
|
@@ -63,6 +68,8 @@ const defaultManifestPath = "/__manifest";
|
|
|
63
68
|
* @param opts.serverResponse A Response or partial response generated by the [RSC](https://react.dev/reference/rsc/server-components) handler containing a serialized {@link unstable_RSCPayload}.
|
|
64
69
|
* @param opts.hydrate Whether to hydrate the server response with the RSC payload.
|
|
65
70
|
* Defaults to `true`.
|
|
71
|
+
* @param opts.nonce An optional [`nonce`](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Global_attributes/nonce)
|
|
72
|
+
* for inline scripts generated while rendering the HTML document.
|
|
66
73
|
* @param opts.renderHTML A function that renders the {@link unstable_RSCPayload} to
|
|
67
74
|
* HTML, usually using a {@link unstable_RSCStaticRouter | `<RSCStaticRouter>`}.
|
|
68
75
|
* @param opts.request The request to route.
|
|
@@ -70,7 +77,7 @@ const defaultManifestPath = "/__manifest";
|
|
|
70
77
|
* that either contains the [RSC](https://react.dev/reference/rsc/server-components)
|
|
71
78
|
* payload for data requests, or renders the HTML for document requests.
|
|
72
79
|
*/
|
|
73
|
-
async function routeRSCServerRequest({ request, serverResponse, createFromReadableStream, renderHTML, hydrate = true }) {
|
|
80
|
+
async function routeRSCServerRequest({ request, serverResponse, createFromReadableStream, renderHTML, hydrate = true, nonce }) {
|
|
74
81
|
const url = new URL(request.url);
|
|
75
82
|
if (isReactServerRequest(url) || isManifestRequest(url) || request.headers.has("rsc-action-id") || serverResponse.headers.get("React-Router-Resource") === "true") return serverResponse;
|
|
76
83
|
if (!serverResponse.body) throw new Error("Missing body in server response");
|
|
@@ -140,6 +147,7 @@ async function routeRSCServerRequest({ request, serverResponse, createFromReadab
|
|
|
140
147
|
let status = serverResponse.status;
|
|
141
148
|
let statusText = serverResponse.statusText;
|
|
142
149
|
let html = await renderHTML(getPayload, {
|
|
150
|
+
nonce,
|
|
143
151
|
onError(error) {
|
|
144
152
|
if (typeof error === "object" && error && "digest" in error && typeof error.digest === "string") {
|
|
145
153
|
renderRedirect = decodeRedirectErrorDigest(error.digest);
|
|
@@ -180,7 +188,7 @@ async function routeRSCServerRequest({ request, serverResponse, createFromReadab
|
|
|
180
188
|
headers
|
|
181
189
|
});
|
|
182
190
|
if (!serverResponseB?.body) throw new Error("Failed to clone server response");
|
|
183
|
-
const body = html.pipeThrough(injectRSCPayload(serverResponseB.body)).pipeThrough(redirectTransform);
|
|
191
|
+
const body = html.pipeThrough(injectRSCPayload(serverResponseB.body, { nonce })).pipeThrough(redirectTransform);
|
|
184
192
|
return new Response(body, {
|
|
185
193
|
status,
|
|
186
194
|
statusText,
|
|
@@ -219,6 +227,7 @@ async function routeRSCServerRequest({ request, serverResponse, createFromReadab
|
|
|
219
227
|
} }
|
|
220
228
|
});
|
|
221
229
|
}, {
|
|
230
|
+
nonce,
|
|
222
231
|
onError(error) {
|
|
223
232
|
if (typeof error === "object" && error && "digest" in error && typeof error.digest === "string") {
|
|
224
233
|
retryRedirect = decodeRedirectErrorDigest(error.digest);
|
|
@@ -258,7 +267,7 @@ async function routeRSCServerRequest({ request, serverResponse, createFromReadab
|
|
|
258
267
|
headers
|
|
259
268
|
});
|
|
260
269
|
if (!serverResponseB?.body) throw new Error("Failed to clone server response");
|
|
261
|
-
const body = html.pipeThrough(injectRSCPayload(serverResponseB.body)).pipeThrough(retryRedirectTransform);
|
|
270
|
+
const body = html.pipeThrough(injectRSCPayload(serverResponseB.body, { nonce })).pipeThrough(retryRedirectTransform);
|
|
262
271
|
return new Response(body, {
|
|
263
272
|
status,
|
|
264
273
|
statusText,
|
|
@@ -284,12 +293,17 @@ async function routeRSCServerRequest({ request, serverResponse, createFromReadab
|
|
|
284
293
|
* request,
|
|
285
294
|
* serverResponse,
|
|
286
295
|
* createFromReadableStream,
|
|
287
|
-
*
|
|
296
|
+
* nonce,
|
|
297
|
+
* async renderHTML(getPayload, options) {
|
|
288
298
|
* const payload = getPayload();
|
|
289
299
|
*
|
|
290
300
|
* return await renderHTMLToReadableStream(
|
|
291
|
-
* <RSCStaticRouter
|
|
301
|
+
* <RSCStaticRouter
|
|
302
|
+
* getPayload={getPayload}
|
|
303
|
+
* nonce={options.nonce}
|
|
304
|
+
* />,
|
|
292
305
|
* {
|
|
306
|
+
* ...options,
|
|
293
307
|
* bootstrapScriptContent,
|
|
294
308
|
* formState: await payload.formState,
|
|
295
309
|
* }
|
|
@@ -303,9 +317,10 @@ async function routeRSCServerRequest({ request, serverResponse, createFromReadab
|
|
|
303
317
|
* @mode data
|
|
304
318
|
* @param props Props
|
|
305
319
|
* @param {unstable_RSCStaticRouterProps.getPayload} props.getPayload n/a
|
|
320
|
+
* @param {unstable_RSCStaticRouterProps.nonce} props.nonce n/a
|
|
306
321
|
* @returns A React component that renders the {@link unstable_RSCPayload} as HTML.
|
|
307
322
|
*/
|
|
308
|
-
function RSCStaticRouter({ getPayload }) {
|
|
323
|
+
function RSCStaticRouter({ getPayload, nonce }) {
|
|
309
324
|
const decoded = getPayload();
|
|
310
325
|
const payload = React$1.use(decoded);
|
|
311
326
|
if (payload.type === "redirect") {
|
|
@@ -385,13 +400,13 @@ function RSCStaticRouter({ getPayload }) {
|
|
|
385
400
|
mode: "lazy",
|
|
386
401
|
manifestPath: payload.routeDiscovery.manifestPath || defaultManifestPath
|
|
387
402
|
},
|
|
388
|
-
routeModules: createRSCRouteModules(payload)
|
|
403
|
+
routeModules: createRSCRouteModules(payload),
|
|
404
|
+
nonce
|
|
389
405
|
};
|
|
390
406
|
return /* @__PURE__ */ React$1.createElement(RSCRouterContext.Provider, { value: true }, /* @__PURE__ */ React$1.createElement(RSCRouterGlobalErrorBoundary, { location: payload.location }, /* @__PURE__ */ React$1.createElement(FrameworkContext.Provider, { value: frameworkContext }, /* @__PURE__ */ React$1.createElement(StaticRouterProvider, {
|
|
391
407
|
context,
|
|
392
408
|
router,
|
|
393
|
-
hydrate: false
|
|
394
|
-
nonce: payload.nonce
|
|
409
|
+
hydrate: false
|
|
395
410
|
}))));
|
|
396
411
|
}
|
|
397
412
|
function isReactServerRequest(url) {
|
|
@@ -53,13 +53,39 @@ interface Cookie {
|
|
|
53
53
|
}
|
|
54
54
|
/**
|
|
55
55
|
* Creates a logical container for managing a browser cookie from the server.
|
|
56
|
+
*
|
|
57
|
+
* @public
|
|
58
|
+
* @category Utils
|
|
59
|
+
* @mode framework
|
|
60
|
+
* @mode data
|
|
61
|
+
* @param name The name of the cookie.
|
|
62
|
+
* @param cookieOptions Options for parsing and serializing the cookie.
|
|
63
|
+
* @returns A {@link Cookie} object for parsing and serializing the cookie.
|
|
56
64
|
*/
|
|
57
65
|
declare const createCookie: (name: string, cookieOptions?: CookieOptions) => Cookie;
|
|
66
|
+
/**
|
|
67
|
+
* A function that determines whether a value is a React Router {@link Cookie}
|
|
68
|
+
* object.
|
|
69
|
+
*
|
|
70
|
+
* @public
|
|
71
|
+
* @category Utils
|
|
72
|
+
* @mode framework
|
|
73
|
+
* @mode data
|
|
74
|
+
* @param object The value to check.
|
|
75
|
+
* @returns `true` if the value is a React Router {@link Cookie} object;
|
|
76
|
+
* otherwise, `false`.
|
|
77
|
+
*/
|
|
58
78
|
type IsCookieFunction = (object: any) => object is Cookie;
|
|
59
79
|
/**
|
|
60
|
-
* Returns true if
|
|
80
|
+
* Returns `true` if a value is a React Router {@link Cookie} object.
|
|
61
81
|
*
|
|
62
|
-
* @
|
|
82
|
+
* @public
|
|
83
|
+
* @category Utils
|
|
84
|
+
* @mode framework
|
|
85
|
+
* @mode data
|
|
86
|
+
* @param object The value to check.
|
|
87
|
+
* @returns `true` if the value is a React Router {@link Cookie} object;
|
|
88
|
+
* otherwise, `false`.
|
|
63
89
|
*/
|
|
64
90
|
declare const isCookie: IsCookieFunction;
|
|
65
91
|
//#endregion
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* react-router v8.
|
|
2
|
+
* react-router v8.3.0
|
|
3
3
|
*
|
|
4
4
|
* Copyright (c) Remix Software Inc.
|
|
5
5
|
*
|
|
@@ -14,6 +14,14 @@ import { parse, serialize } from "cookie-es";
|
|
|
14
14
|
//#region lib/server-runtime/cookies.ts
|
|
15
15
|
/**
|
|
16
16
|
* Creates a logical container for managing a browser cookie from the server.
|
|
17
|
+
*
|
|
18
|
+
* @public
|
|
19
|
+
* @category Utils
|
|
20
|
+
* @mode framework
|
|
21
|
+
* @mode data
|
|
22
|
+
* @param name The name of the cookie.
|
|
23
|
+
* @param cookieOptions Options for parsing and serializing the cookie.
|
|
24
|
+
* @returns A {@link Cookie} object for parsing and serializing the cookie.
|
|
17
25
|
*/
|
|
18
26
|
const createCookie = (name, cookieOptions = {}) => {
|
|
19
27
|
let { secrets = [], ...options } = {
|
|
@@ -53,9 +61,15 @@ const createCookie = (name, cookieOptions = {}) => {
|
|
|
53
61
|
};
|
|
54
62
|
};
|
|
55
63
|
/**
|
|
56
|
-
* Returns true if
|
|
64
|
+
* Returns `true` if a value is a React Router {@link Cookie} object.
|
|
57
65
|
*
|
|
58
|
-
* @
|
|
66
|
+
* @public
|
|
67
|
+
* @category Utils
|
|
68
|
+
* @mode framework
|
|
69
|
+
* @mode data
|
|
70
|
+
* @param object The value to check.
|
|
71
|
+
* @returns `true` if the value is a React Router {@link Cookie} object;
|
|
72
|
+
* otherwise, `false`.
|
|
59
73
|
*/
|
|
60
74
|
const isCookie = (object) => {
|
|
61
75
|
return object != null && typeof object.name === "string" && typeof object.isSigned === "boolean" && typeof object.parse === "function" && typeof object.serialize === "function";
|