@tanstack/router-core 1.125.4 → 1.127.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/dist/cjs/Matches.cjs.map +1 -1
- package/dist/cjs/Matches.d.cts +1 -1
- package/dist/cjs/RouterProvider.d.cts +1 -0
- package/dist/cjs/index.d.cts +1 -2
- package/dist/cjs/router.cjs +26 -33
- package/dist/cjs/router.cjs.map +1 -1
- package/dist/cjs/router.d.cts +10 -57
- package/dist/cjs/ssr/client.cjs +0 -2
- package/dist/cjs/ssr/client.cjs.map +1 -1
- package/dist/cjs/ssr/client.d.cts +1 -2
- package/dist/cjs/ssr/createRequestHandler.cjs +2 -1
- package/dist/cjs/ssr/createRequestHandler.cjs.map +1 -1
- package/dist/cjs/ssr/seroval-plugins.cjs +34 -0
- package/dist/cjs/ssr/seroval-plugins.cjs.map +1 -0
- package/dist/cjs/ssr/seroval-plugins.d.cts +10 -0
- package/dist/cjs/ssr/server.cjs +0 -4
- package/dist/cjs/ssr/server.cjs.map +1 -1
- package/dist/cjs/ssr/server.d.cts +1 -3
- package/dist/cjs/ssr/ssr-client.cjs +18 -56
- package/dist/cjs/ssr/ssr-client.cjs.map +1 -1
- package/dist/cjs/ssr/ssr-client.d.cts +17 -57
- package/dist/cjs/ssr/ssr-server.cjs +75 -220
- package/dist/cjs/ssr/ssr-server.cjs.map +1 -1
- package/dist/cjs/ssr/ssr-server.d.cts +14 -28
- package/dist/cjs/ssr/transformStreamWithRouter.cjs +1 -0
- package/dist/cjs/ssr/transformStreamWithRouter.cjs.map +1 -1
- package/dist/cjs/ssr/tsrScript.cjs +1 -1
- package/dist/cjs/ssr/tsrScript.cjs.map +1 -1
- package/dist/cjs/ssr/tsrScript.d.cts +0 -1
- package/dist/esm/Matches.d.ts +1 -1
- package/dist/esm/Matches.js.map +1 -1
- package/dist/esm/RouterProvider.d.ts +1 -0
- package/dist/esm/index.d.ts +1 -2
- package/dist/esm/router.d.ts +10 -57
- package/dist/esm/router.js +26 -33
- package/dist/esm/router.js.map +1 -1
- package/dist/esm/ssr/client.d.ts +1 -2
- package/dist/esm/ssr/client.js +1 -3
- package/dist/esm/ssr/client.js.map +1 -1
- package/dist/esm/ssr/createRequestHandler.js +3 -2
- package/dist/esm/ssr/createRequestHandler.js.map +1 -1
- package/dist/esm/ssr/seroval-plugins.d.ts +10 -0
- package/dist/esm/ssr/seroval-plugins.js +34 -0
- package/dist/esm/ssr/seroval-plugins.js.map +1 -0
- package/dist/esm/ssr/server.d.ts +1 -3
- package/dist/esm/ssr/server.js +1 -5
- package/dist/esm/ssr/ssr-client.d.ts +17 -57
- package/dist/esm/ssr/ssr-client.js +18 -56
- package/dist/esm/ssr/ssr-client.js.map +1 -1
- package/dist/esm/ssr/ssr-server.d.ts +14 -28
- package/dist/esm/ssr/ssr-server.js +76 -221
- package/dist/esm/ssr/ssr-server.js.map +1 -1
- package/dist/esm/ssr/transformStreamWithRouter.js +1 -0
- package/dist/esm/ssr/transformStreamWithRouter.js.map +1 -1
- package/dist/esm/ssr/tsrScript.d.ts +0 -1
- package/dist/esm/ssr/tsrScript.js +1 -1
- package/dist/esm/ssr/tsrScript.js.map +1 -1
- package/package.json +3 -1
- package/src/Matches.ts +1 -1
- package/src/RouterProvider.ts +1 -0
- package/src/index.ts +0 -18
- package/src/router.ts +41 -89
- package/src/ssr/client.ts +1 -11
- package/src/ssr/createRequestHandler.ts +2 -2
- package/src/ssr/seroval-plugins.ts +43 -0
- package/src/ssr/server.ts +1 -14
- package/src/ssr/ssr-client.ts +35 -128
- package/src/ssr/ssr-server.ts +89 -307
- package/src/ssr/transformStreamWithRouter.ts +1 -0
- package/src/ssr/tsrScript.ts +4 -88
- package/dist/cjs/serializer.cjs +0 -146
- package/dist/cjs/serializer.cjs.map +0 -1
- package/dist/cjs/serializer.d.cts +0 -28
- package/dist/esm/serializer.d.ts +0 -28
- package/dist/esm/serializer.js +0 -146
- package/dist/esm/serializer.js.map +0 -1
- package/src/serializer.ts +0 -205
package/dist/cjs/router.d.cts
CHANGED
|
@@ -4,13 +4,11 @@ import { AnyRedirect, ResolvedRedirect } from './redirect.cjs';
|
|
|
4
4
|
import { HistoryLocation, HistoryState, ParsedHistoryState, RouterHistory } from '@tanstack/history';
|
|
5
5
|
import { Awaitable, ControlledPromise, NoInfer, NonNullableUpdater, PickAsRequired, Updater } from './utils.cjs';
|
|
6
6
|
import { ParsedLocation } from './location.cjs';
|
|
7
|
-
import { DeferredPromiseState } from './defer.cjs';
|
|
8
7
|
import { AnyContext, AnyRoute, AnyRouteWithContext, MakeRemountDepsOptionsUnion, RouteMask } from './route.cjs';
|
|
9
8
|
import { FullSearchSchema, RouteById, RoutePaths, RoutesById, RoutesByPath } from './routeInfo.cjs';
|
|
10
9
|
import { AnyRouteMatch, MakeRouteMatch, MakeRouteMatchUnion, MatchRouteOptions } from './Matches.cjs';
|
|
11
10
|
import { BuildLocationFn, CommitLocationOptions, NavigateFn } from './RouterProvider.cjs';
|
|
12
11
|
import { Manifest } from './manifest.cjs';
|
|
13
|
-
import { TsrSerializer } from './serializer.cjs';
|
|
14
12
|
import { AnySchema } from './validators.cjs';
|
|
15
13
|
import { NavigateOptions, ResolveRelativePath, ToOptions } from './link.cjs';
|
|
16
14
|
import { NotFoundError } from './not-found.cjs';
|
|
@@ -202,7 +200,7 @@ export interface RouterOptions<TRouteTree extends AnyRoute, TTrailingSlashOption
|
|
|
202
200
|
* @link [API Docs](https://tanstack.com/router/latest/docs/framework/react/api/router/RouterOptionsType#dehydrate-method)
|
|
203
201
|
* @link [Guide](https://tanstack.com/router/latest/docs/framework/react/guide/external-data-loading#critical-dehydrationhydration)
|
|
204
202
|
*/
|
|
205
|
-
dehydrate?: () => TDehydrated
|
|
203
|
+
dehydrate?: () => Awaitable<TDehydrated>;
|
|
206
204
|
/**
|
|
207
205
|
* A function that will be called when the router is hydrated.
|
|
208
206
|
*
|
|
@@ -340,6 +338,7 @@ export interface BuildNextOptions {
|
|
|
340
338
|
href?: string;
|
|
341
339
|
_fromLocation?: ParsedLocation;
|
|
342
340
|
unsafeRelative?: 'path';
|
|
341
|
+
_isNavigate?: boolean;
|
|
343
342
|
}
|
|
344
343
|
type NavigationEventInfo = {
|
|
345
344
|
fromLocation?: ParsedLocation;
|
|
@@ -348,7 +347,7 @@ type NavigationEventInfo = {
|
|
|
348
347
|
hrefChanged: boolean;
|
|
349
348
|
hashChanged: boolean;
|
|
350
349
|
};
|
|
351
|
-
export
|
|
350
|
+
export interface RouterEvents {
|
|
352
351
|
onBeforeNavigate: {
|
|
353
352
|
type: 'onBeforeNavigate';
|
|
354
353
|
} & NavigationEventInfo;
|
|
@@ -364,20 +363,17 @@ export type RouterEvents = {
|
|
|
364
363
|
onBeforeRouteMount: {
|
|
365
364
|
type: 'onBeforeRouteMount';
|
|
366
365
|
} & NavigationEventInfo;
|
|
367
|
-
onInjectedHtml: {
|
|
368
|
-
type: 'onInjectedHtml';
|
|
369
|
-
promise: Promise<string>;
|
|
370
|
-
};
|
|
371
366
|
onRendered: {
|
|
372
367
|
type: 'onRendered';
|
|
373
368
|
} & NavigationEventInfo;
|
|
374
|
-
}
|
|
369
|
+
}
|
|
375
370
|
export type RouterEvent = RouterEvents[keyof RouterEvents];
|
|
376
371
|
export type ListenerFn<TEvent extends RouterEvent> = (event: TEvent) => void;
|
|
377
372
|
export type RouterListener<TRouterEvent extends RouterEvent> = {
|
|
378
373
|
eventType: TRouterEvent['type'];
|
|
379
374
|
fn: ListenerFn<TRouterEvent>;
|
|
380
375
|
};
|
|
376
|
+
export type SubscribeFn = <TType extends keyof RouterEvents>(eventType: TType, fn: ListenerFn<RouterEvents[TType]>) => () => void;
|
|
381
377
|
export interface MatchRoutesOpts {
|
|
382
378
|
preload?: boolean;
|
|
383
379
|
throwOnError?: boolean;
|
|
@@ -391,10 +387,6 @@ export type RouterContextOptions<TRouteTree extends AnyRoute> = AnyContext exten
|
|
|
391
387
|
context: InferRouterContext<TRouteTree>;
|
|
392
388
|
};
|
|
393
389
|
export type RouterConstructorOptions<TRouteTree extends AnyRoute, TTrailingSlashOption extends TrailingSlashOption, TDefaultStructuralSharingOption extends boolean, TRouterHistory extends RouterHistory, TDehydrated extends Record<string, any>> = Omit<RouterOptions<TRouteTree, TTrailingSlashOption, TDefaultStructuralSharingOption, TRouterHistory, TDehydrated>, 'context'> & RouterContextOptions<TRouteTree>;
|
|
394
|
-
export interface RouterErrorSerializer<TSerializedError> {
|
|
395
|
-
serialize: (err: unknown) => TSerializedError;
|
|
396
|
-
deserialize: (err: TSerializedError) => unknown;
|
|
397
|
-
}
|
|
398
390
|
export type PreloadRouteFn<TRouteTree extends AnyRoute, TTrailingSlashOption extends TrailingSlashOption, TDefaultStructuralSharingOption extends boolean, TRouterHistory extends RouterHistory> = <TFrom extends RoutePaths<TRouteTree> | string = string, TTo extends string | undefined = undefined, TMaskFrom extends RoutePaths<TRouteTree> | string = TFrom, TMaskTo extends string = ''>(opts: NavigateOptions<RouterCore<TRouteTree, TTrailingSlashOption, TDefaultStructuralSharingOption, TRouterHistory>, TFrom, TTo, TMaskFrom, TMaskTo>) => Promise<Array<AnyRouteMatch> | undefined>;
|
|
399
391
|
export type MatchRouteFn<TRouteTree extends AnyRoute, TTrailingSlashOption extends TrailingSlashOption, TDefaultStructuralSharingOption extends boolean, TRouterHistory extends RouterHistory> = <TFrom extends RoutePaths<TRouteTree> = '/', TTo extends string | undefined = undefined, TResolved = ResolveRelativePath<TFrom, NoInfer<TTo>>>(location: ToOptions<RouterCore<TRouteTree, TTrailingSlashOption, TDefaultStructuralSharingOption, TRouterHistory>, TFrom, TTo>, opts?: MatchRouteOptions) => false | RouteById<TRouteTree, TResolved>['types']['allParams'];
|
|
400
392
|
export type UpdateFn<TRouteTree extends AnyRoute, TTrailingSlashOption extends TrailingSlashOption, TDefaultStructuralSharingOption extends boolean, TRouterHistory extends RouterHistory, TDehydrated extends Record<string, any>> = (newOptions: RouterConstructorOptions<TRouteTree, TTrailingSlashOption, TDefaultStructuralSharingOption, TRouterHistory, TDehydrated>) => void;
|
|
@@ -415,7 +407,6 @@ export type LoadFn = (opts?: {
|
|
|
415
407
|
}) => Promise<void>;
|
|
416
408
|
export type CommitLocationFn = ({ viewTransition, ignoreBlocker, ...next }: ParsedLocation & CommitLocationOptions) => Promise<void>;
|
|
417
409
|
export type StartTransitionFn = (fn: () => void) => void;
|
|
418
|
-
export type SubscribeFn = <TType extends keyof RouterEvents>(eventType: TType, fn: ListenerFn<RouterEvents[TType]>) => () => void;
|
|
419
410
|
export interface MatchRoutesFn {
|
|
420
411
|
(pathname: string, locationSearch: AnySchema, opts?: MatchRoutesOpts): Array<AnyRouteMatch>;
|
|
421
412
|
(next: ParsedLocation, opts?: MatchRoutesOpts): Array<AnyRouteMatch>;
|
|
@@ -428,18 +419,15 @@ export type ResolveRedirect = (err: AnyRedirect) => ResolvedRedirect;
|
|
|
428
419
|
export type ClearCacheFn<TRouter extends AnyRouter> = (opts?: {
|
|
429
420
|
filter?: (d: MakeRouteMatchUnion<TRouter>) => boolean;
|
|
430
421
|
}) => void;
|
|
431
|
-
export interface
|
|
422
|
+
export interface ServerSsr {
|
|
432
423
|
injectedHtml: Array<InjectedHtmlEntry>;
|
|
433
424
|
injectHtml: (getHtml: () => string | Promise<string>) => Promise<void>;
|
|
434
425
|
injectScript: (getScript: () => string | Promise<string>, opts?: {
|
|
435
426
|
logScript?: boolean;
|
|
436
427
|
}) => Promise<void>;
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
router: AnyRouter;
|
|
441
|
-
match: AnyRouteMatch;
|
|
442
|
-
}) => any;
|
|
428
|
+
isDehydrated: () => boolean;
|
|
429
|
+
onRenderFinished: (listener: () => void) => void;
|
|
430
|
+
dehydrate: () => Promise<void>;
|
|
443
431
|
}
|
|
444
432
|
export type AnyRouterWithContext<TContext> = RouterCore<AnyRouteWithContext<TContext>, any, any, any, any>;
|
|
445
433
|
export type AnyRouter = RouterCore<any, any, any, any, any>;
|
|
@@ -458,25 +446,6 @@ export declare function defaultSerializeError(err: unknown): {
|
|
|
458
446
|
} | {
|
|
459
447
|
data: unknown;
|
|
460
448
|
};
|
|
461
|
-
export interface ExtractedBaseEntry {
|
|
462
|
-
dataType: '__beforeLoadContext' | 'loaderData';
|
|
463
|
-
type: string;
|
|
464
|
-
path: Array<string>;
|
|
465
|
-
id: number;
|
|
466
|
-
matchIndex: number;
|
|
467
|
-
}
|
|
468
|
-
export interface ExtractedStream extends ExtractedBaseEntry {
|
|
469
|
-
type: 'stream';
|
|
470
|
-
streamState: StreamState;
|
|
471
|
-
}
|
|
472
|
-
export interface ExtractedPromise extends ExtractedBaseEntry {
|
|
473
|
-
type: 'promise';
|
|
474
|
-
promiseState: DeferredPromiseState<any>;
|
|
475
|
-
}
|
|
476
|
-
export type ExtractedEntry = ExtractedStream | ExtractedPromise;
|
|
477
|
-
export type StreamState = {
|
|
478
|
-
promises: Array<ControlledPromise<string | null>>;
|
|
479
|
-
};
|
|
480
449
|
export type TrailingSlashOption = 'always' | 'never' | 'preserve';
|
|
481
450
|
export declare function getLocationChangeInfo(routerState: {
|
|
482
451
|
resolvedLocation?: ParsedLocation;
|
|
@@ -567,24 +536,8 @@ export declare class RouterCore<in out TRouteTree extends AnyRoute, in out TTrai
|
|
|
567
536
|
matchRoute: MatchRouteFn<TRouteTree, TTrailingSlashOption, TDefaultStructuralSharingOption, TRouterHistory>;
|
|
568
537
|
ssr?: {
|
|
569
538
|
manifest: Manifest | undefined;
|
|
570
|
-
serializer: TsrSerializer;
|
|
571
|
-
};
|
|
572
|
-
serverSsr?: {
|
|
573
|
-
injectedHtml: Array<InjectedHtmlEntry>;
|
|
574
|
-
injectHtml: (getHtml: () => string | Promise<string>) => Promise<void>;
|
|
575
|
-
injectScript: (getScript: () => string | Promise<string>, opts?: {
|
|
576
|
-
logScript?: boolean;
|
|
577
|
-
}) => Promise<void>;
|
|
578
|
-
streamValue: (key: string, value: any) => void;
|
|
579
|
-
streamedKeys: Set<string>;
|
|
580
|
-
onMatchSettled: (opts: {
|
|
581
|
-
router: AnyRouter;
|
|
582
|
-
match: AnyRouteMatch;
|
|
583
|
-
}) => any;
|
|
584
|
-
};
|
|
585
|
-
clientSsr?: {
|
|
586
|
-
getStreamedValue: <T>(key: string) => T | undefined;
|
|
587
539
|
};
|
|
540
|
+
serverSsr?: ServerSsr;
|
|
588
541
|
_handleNotFound: (matches: Array<AnyRouteMatch>, err: NotFoundError, { updateMatch, }?: {
|
|
589
542
|
updateMatch?: (id: string, updater: (match: AnyRouteMatch) => AnyRouteMatch) => void;
|
|
590
543
|
}) => void;
|
package/dist/cjs/ssr/client.cjs
CHANGED
|
@@ -3,10 +3,8 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
|
3
3
|
const headers = require("./headers.cjs");
|
|
4
4
|
const json = require("./json.cjs");
|
|
5
5
|
const ssrClient = require("./ssr-client.cjs");
|
|
6
|
-
const serializer = require("../serializer.cjs");
|
|
7
6
|
exports.headersInitToObject = headers.headersInitToObject;
|
|
8
7
|
exports.mergeHeaders = headers.mergeHeaders;
|
|
9
8
|
exports.json = json.json;
|
|
10
9
|
exports.hydrate = ssrClient.hydrate;
|
|
11
|
-
exports.tsrSerializer = serializer.tsrSerializer;
|
|
12
10
|
//# sourceMappingURL=client.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.cjs","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"client.cjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;"}
|
|
@@ -2,5 +2,4 @@ export { mergeHeaders, headersInitToObject } from './headers.cjs';
|
|
|
2
2
|
export { json } from './json.cjs';
|
|
3
3
|
export type { JsonResponse } from './json.cjs';
|
|
4
4
|
export { hydrate } from './ssr-client.cjs';
|
|
5
|
-
export
|
|
6
|
-
export { tsrSerializer } from '../serializer.cjs';
|
|
5
|
+
export * from './ssr-client.cjs';
|
|
@@ -9,6 +9,7 @@ function createRequestHandler({
|
|
|
9
9
|
getRouterManifest
|
|
10
10
|
}) {
|
|
11
11
|
return async (cb) => {
|
|
12
|
+
var _a;
|
|
12
13
|
const router = createRouter();
|
|
13
14
|
ssrServer.attachRouterServerSsrUtils(router, await (getRouterManifest == null ? void 0 : getRouterManifest()));
|
|
14
15
|
const url = new URL(request.url, "http://localhost");
|
|
@@ -20,7 +21,7 @@ function createRequestHandler({
|
|
|
20
21
|
history: history$1
|
|
21
22
|
});
|
|
22
23
|
await router.load();
|
|
23
|
-
|
|
24
|
+
await ((_a = router.serverSsr) == null ? void 0 : _a.dehydrate());
|
|
24
25
|
const responseHeaders = getRequestHeaders({
|
|
25
26
|
router
|
|
26
27
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createRequestHandler.cjs","sources":["../../../src/ssr/createRequestHandler.ts"],"sourcesContent":["import { createMemoryHistory } from '@tanstack/history'\nimport { mergeHeaders } from './headers'\nimport { attachRouterServerSsrUtils
|
|
1
|
+
{"version":3,"file":"createRequestHandler.cjs","sources":["../../../src/ssr/createRequestHandler.ts"],"sourcesContent":["import { createMemoryHistory } from '@tanstack/history'\nimport { mergeHeaders } from './headers'\nimport { attachRouterServerSsrUtils } from './ssr-server'\nimport type { HandlerCallback } from './handlerCallback'\nimport type { AnyRouter } from '../router'\nimport type { Manifest } from '../manifest'\n\nexport type RequestHandler<TRouter extends AnyRouter> = (\n cb: HandlerCallback<TRouter>,\n) => Promise<Response>\n\nexport function createRequestHandler<TRouter extends AnyRouter>({\n createRouter,\n request,\n getRouterManifest,\n}: {\n createRouter: () => TRouter\n request: Request\n getRouterManifest?: () => Manifest | Promise<Manifest>\n}): RequestHandler<TRouter> {\n return async (cb) => {\n const router = createRouter()\n\n attachRouterServerSsrUtils(router, await getRouterManifest?.())\n\n const url = new URL(request.url, 'http://localhost')\n\n const href = url.href.replace(url.origin, '')\n\n // Create a history for the router\n const history = createMemoryHistory({\n initialEntries: [href],\n })\n\n // Update the router with the history and context\n router.update({\n history,\n })\n\n await router.load()\n\n await router.serverSsr?.dehydrate()\n\n const responseHeaders = getRequestHeaders({\n router,\n })\n\n return cb({\n request,\n router,\n responseHeaders,\n } as any)\n }\n}\n\nfunction getRequestHeaders(opts: { router: AnyRouter }): Headers {\n let headers = mergeHeaders(\n {\n 'Content-Type': 'text/html; charset=UTF-8',\n },\n ...opts.router.state.matches.map((match) => {\n return match.headers\n }),\n )\n\n // Handle Redirects\n const { redirect } = opts.router.state\n\n if (redirect) {\n headers = mergeHeaders(headers, redirect.headers)\n }\n\n return headers\n}\n"],"names":["attachRouterServerSsrUtils","history","createMemoryHistory","headers","mergeHeaders"],"mappings":";;;;;AAWO,SAAS,qBAAgD;AAAA,EAC9D;AAAA,EACA;AAAA,EACA;AACF,GAI4B;AAC1B,SAAO,OAAO,OAAO;;AACnB,UAAM,SAAS,aAAa;AAEDA,yCAAA,QAAQ,OAAM,yDAAqB;AAE9D,UAAM,MAAM,IAAI,IAAI,QAAQ,KAAK,kBAAkB;AAEnD,UAAM,OAAO,IAAI,KAAK,QAAQ,IAAI,QAAQ,EAAE;AAG5C,UAAMC,YAAUC,QAAAA,oBAAoB;AAAA,MAClC,gBAAgB,CAAC,IAAI;AAAA,IAAA,CACtB;AAGD,WAAO,OAAO;AAAA,MACZD,SAAAA;AAAAA,IAAA,CACD;AAED,UAAM,OAAO,KAAK;AAEZ,YAAA,YAAO,cAAP,mBAAkB;AAExB,UAAM,kBAAkB,kBAAkB;AAAA,MACxC;AAAA,IAAA,CACD;AAED,WAAO,GAAG;AAAA,MACR;AAAA,MACA;AAAA,MACA;AAAA,IAAA,CACM;AAAA,EACV;AACF;AAEA,SAAS,kBAAkB,MAAsC;AAC/D,MAAIE,YAAUC,QAAA;AAAA,IACZ;AAAA,MACE,gBAAgB;AAAA,IAClB;AAAA,IACA,GAAG,KAAK,OAAO,MAAM,QAAQ,IAAI,CAAC,UAAU;AAC1C,aAAO,MAAM;AAAA,IACd,CAAA;AAAA,EACH;AAGA,QAAM,EAAE,SAAA,IAAa,KAAK,OAAO;AAEjC,MAAI,UAAU;AACFD,gBAAAC,QAAA,aAAaD,WAAS,SAAS,OAAO;AAAA,EAAA;AAG3C,SAAAA;AACT;;"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
const seroval = require("seroval");
|
|
4
|
+
const ShallowErrorPlugin = /* @__PURE__ */ seroval.createPlugin({
|
|
5
|
+
tag: "tanstack-start:seroval-plugins/Error",
|
|
6
|
+
test(value) {
|
|
7
|
+
return value instanceof Error;
|
|
8
|
+
},
|
|
9
|
+
parse: {
|
|
10
|
+
sync(value, ctx) {
|
|
11
|
+
return {
|
|
12
|
+
message: ctx.parse(value.message)
|
|
13
|
+
};
|
|
14
|
+
},
|
|
15
|
+
async async(value, ctx) {
|
|
16
|
+
return {
|
|
17
|
+
message: await ctx.parse(value.message)
|
|
18
|
+
};
|
|
19
|
+
},
|
|
20
|
+
stream(value, ctx) {
|
|
21
|
+
return {
|
|
22
|
+
message: ctx.parse(value.message)
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
serialize(node, ctx) {
|
|
27
|
+
return "new Error(" + ctx.serialize(node.message) + ")";
|
|
28
|
+
},
|
|
29
|
+
deserialize(node, ctx) {
|
|
30
|
+
return new Error(ctx.deserialize(node.message));
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
exports.ShallowErrorPlugin = ShallowErrorPlugin;
|
|
34
|
+
//# sourceMappingURL=seroval-plugins.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"seroval-plugins.cjs","sources":["../../../src/ssr/seroval-plugins.ts"],"sourcesContent":["import { createPlugin } from 'seroval'\nimport type { SerovalNode } from 'seroval'\n\ninterface ErrorNode {\n message: SerovalNode\n}\n\n/**\n * this plugin serializes only the `message` part of an Error\n * this helps with serializing e.g. a ZodError which has functions attached that cannot be serialized\n */\nexport const ShallowErrorPlugin = /* @__PURE__ */ createPlugin<\n Error,\n ErrorNode\n>({\n tag: 'tanstack-start:seroval-plugins/Error',\n test(value) {\n return value instanceof Error\n },\n parse: {\n sync(value, ctx) {\n return {\n message: ctx.parse(value.message),\n }\n },\n async async(value, ctx) {\n return {\n message: await ctx.parse(value.message),\n }\n },\n stream(value, ctx) {\n return {\n message: ctx.parse(value.message),\n }\n },\n },\n serialize(node, ctx) {\n return 'new Error(' + ctx.serialize(node.message) + ')'\n },\n deserialize(node, ctx) {\n return new Error(ctx.deserialize(node.message) as string)\n },\n})\n"],"names":["createPlugin"],"mappings":";;;AAWO,MAAM,qBAGXA,wBAAAA,aAAA;AAAA,EACA,KAAK;AAAA,EACL,KAAK,OAAO;AACV,WAAO,iBAAiB;AAAA,EAC1B;AAAA,EACA,OAAO;AAAA,IACL,KAAK,OAAO,KAAK;AACR,aAAA;AAAA,QACL,SAAS,IAAI,MAAM,MAAM,OAAO;AAAA,MAClC;AAAA,IACF;AAAA,IACA,MAAM,MAAM,OAAO,KAAK;AACf,aAAA;AAAA,QACL,SAAS,MAAM,IAAI,MAAM,MAAM,OAAO;AAAA,MACxC;AAAA,IACF;AAAA,IACA,OAAO,OAAO,KAAK;AACV,aAAA;AAAA,QACL,SAAS,IAAI,MAAM,MAAM,OAAO;AAAA,MAClC;AAAA,IAAA;AAAA,EAEJ;AAAA,EACA,UAAU,MAAM,KAAK;AACnB,WAAO,eAAe,IAAI,UAAU,KAAK,OAAO,IAAI;AAAA,EACtD;AAAA,EACA,YAAY,MAAM,KAAK;AACrB,WAAO,IAAI,MAAM,IAAI,YAAY,KAAK,OAAO,CAAW;AAAA,EAAA;AAE5D,CAAC;;"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { SerovalNode } from 'seroval';
|
|
2
|
+
interface ErrorNode {
|
|
3
|
+
message: SerovalNode;
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* this plugin serializes only the `message` part of an Error
|
|
7
|
+
* this helps with serializing e.g. a ZodError which has functions attached that cannot be serialized
|
|
8
|
+
*/
|
|
9
|
+
export declare const ShallowErrorPlugin: import('seroval').Plugin<Error, ErrorNode>;
|
|
10
|
+
export {};
|
package/dist/cjs/ssr/server.cjs
CHANGED
|
@@ -10,8 +10,4 @@ exports.transformPipeableStreamWithRouter = transformStreamWithRouter.transformP
|
|
|
10
10
|
exports.transformReadableStreamWithRouter = transformStreamWithRouter.transformReadableStreamWithRouter;
|
|
11
11
|
exports.transformStreamWithRouter = transformStreamWithRouter.transformStreamWithRouter;
|
|
12
12
|
exports.attachRouterServerSsrUtils = ssrServer.attachRouterServerSsrUtils;
|
|
13
|
-
exports.dehydrateRouter = ssrServer.dehydrateRouter;
|
|
14
|
-
exports.extractAsyncLoaderData = ssrServer.extractAsyncLoaderData;
|
|
15
|
-
exports.onMatchSettled = ssrServer.onMatchSettled;
|
|
16
|
-
exports.replaceBy = ssrServer.replaceBy;
|
|
17
13
|
//# sourceMappingURL=server.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.cjs","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"server.cjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;"}
|
|
@@ -3,6 +3,4 @@ export type { RequestHandler } from './createRequestHandler.cjs';
|
|
|
3
3
|
export { defineHandlerCallback } from './handlerCallback.cjs';
|
|
4
4
|
export type { HandlerCallback } from './handlerCallback.cjs';
|
|
5
5
|
export { transformPipeableStreamWithRouter, transformStreamWithRouter, transformReadableStreamWithRouter, } from './transformStreamWithRouter.cjs';
|
|
6
|
-
export { attachRouterServerSsrUtils
|
|
7
|
-
export type { ServerExtractedBaseEntry, ServerExtractedEntry, ServerExtractedPromise, ServerExtractedStream, } from './ssr-server.cjs';
|
|
8
|
-
export * from './tsrScript.cjs';
|
|
6
|
+
export { attachRouterServerSsrUtils } from './ssr-server.cjs';
|
|
@@ -1,36 +1,26 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
3
|
const invariant = require("tiny-invariant");
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
function hydrateMatch(deyhydratedMatch) {
|
|
5
|
+
return {
|
|
6
|
+
id: deyhydratedMatch.i,
|
|
7
|
+
__beforeLoadContext: deyhydratedMatch.b,
|
|
8
|
+
loaderData: deyhydratedMatch.l,
|
|
9
|
+
status: deyhydratedMatch.s,
|
|
10
|
+
ssr: deyhydratedMatch.ssr,
|
|
11
|
+
updatedAt: deyhydratedMatch.u,
|
|
12
|
+
error: deyhydratedMatch.e
|
|
13
|
+
};
|
|
14
|
+
}
|
|
6
15
|
async function hydrate(router) {
|
|
7
16
|
var _a, _b, _c;
|
|
8
17
|
invariant(
|
|
9
|
-
(_a = window
|
|
10
|
-
"Expected to find a dehydrated data on window.
|
|
11
|
-
);
|
|
12
|
-
const { manifest, dehydratedData, lastMatchId } = serializer.tsrSerializer.parse(
|
|
13
|
-
window.__TSR_SSR__.dehydrated
|
|
18
|
+
(_a = window.$_TSR) == null ? void 0 : _a.router,
|
|
19
|
+
"Expected to find a dehydrated data on window.$_TSR.router, but we did not. Please file an issue!"
|
|
14
20
|
);
|
|
21
|
+
const { manifest, dehydratedData, lastMatchId } = window.$_TSR.router;
|
|
15
22
|
router.ssr = {
|
|
16
|
-
manifest
|
|
17
|
-
serializer: serializer.tsrSerializer
|
|
18
|
-
};
|
|
19
|
-
router.clientSsr = {
|
|
20
|
-
getStreamedValue: (key) => {
|
|
21
|
-
var _a2;
|
|
22
|
-
if (router.isServer) {
|
|
23
|
-
return void 0;
|
|
24
|
-
}
|
|
25
|
-
const streamedValue = (_a2 = window.__TSR_SSR__) == null ? void 0 : _a2.streamedValues[key];
|
|
26
|
-
if (!streamedValue) {
|
|
27
|
-
return;
|
|
28
|
-
}
|
|
29
|
-
if (!streamedValue.parsed) {
|
|
30
|
-
streamedValue.parsed = router.ssr.serializer.parse(streamedValue.value);
|
|
31
|
-
}
|
|
32
|
-
return streamedValue.parsed;
|
|
33
|
-
}
|
|
23
|
+
manifest
|
|
34
24
|
};
|
|
35
25
|
const matches = router.matchRoutes(router.state.location);
|
|
36
26
|
const routeChunkPromise = Promise.all(
|
|
@@ -41,15 +31,14 @@ async function hydrate(router) {
|
|
|
41
31
|
);
|
|
42
32
|
let firstNonSsrMatchIndex = void 0;
|
|
43
33
|
matches.forEach((match) => {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
(d) => d.id === match.id
|
|
34
|
+
const dehydratedMatch = window.$_TSR.router.matches.find(
|
|
35
|
+
(d) => d.i === match.id
|
|
47
36
|
);
|
|
48
37
|
if (!dehydratedMatch) {
|
|
49
38
|
Object.assign(match, { dehydrated: false, ssr: false });
|
|
50
39
|
return;
|
|
51
40
|
}
|
|
52
|
-
Object.assign(match, dehydratedMatch);
|
|
41
|
+
Object.assign(match, hydrateMatch(dehydratedMatch));
|
|
53
42
|
if (match.ssr === false) {
|
|
54
43
|
match._dehydrated = false;
|
|
55
44
|
} else {
|
|
@@ -64,22 +53,6 @@ async function hydrate(router) {
|
|
|
64
53
|
if (match.ssr === false) {
|
|
65
54
|
return;
|
|
66
55
|
}
|
|
67
|
-
if (dehydratedMatch.__beforeLoadContext) {
|
|
68
|
-
match.__beforeLoadContext = router.ssr.serializer.parse(
|
|
69
|
-
dehydratedMatch.__beforeLoadContext
|
|
70
|
-
);
|
|
71
|
-
}
|
|
72
|
-
if (dehydratedMatch.loaderData) {
|
|
73
|
-
match.loaderData = router.ssr.serializer.parse(
|
|
74
|
-
dehydratedMatch.loaderData
|
|
75
|
-
);
|
|
76
|
-
}
|
|
77
|
-
if (dehydratedMatch.error) {
|
|
78
|
-
match.error = router.ssr.serializer.parse(dehydratedMatch.error);
|
|
79
|
-
}
|
|
80
|
-
(_a2 = match.extracted) == null ? void 0 : _a2.forEach((ex) => {
|
|
81
|
-
deepMutableSetByPath(match, ["loaderData", ...ex.path], ex.value);
|
|
82
|
-
});
|
|
83
56
|
});
|
|
84
57
|
router.__store.setState((s) => {
|
|
85
58
|
return {
|
|
@@ -153,16 +126,5 @@ async function hydrate(router) {
|
|
|
153
126
|
}
|
|
154
127
|
return routeChunkPromise;
|
|
155
128
|
}
|
|
156
|
-
function deepMutableSetByPath(obj, path, value) {
|
|
157
|
-
if (path.length === 1) {
|
|
158
|
-
obj[path[0]] = value;
|
|
159
|
-
}
|
|
160
|
-
const [key, ...rest] = path;
|
|
161
|
-
if (Array.isArray(obj)) {
|
|
162
|
-
deepMutableSetByPath(obj[Number(key)], rest, value);
|
|
163
|
-
} else if (utils.isPlainObject(obj)) {
|
|
164
|
-
deepMutableSetByPath(obj[key], rest, value);
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
129
|
exports.hydrate = hydrate;
|
|
168
130
|
//# sourceMappingURL=ssr-client.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ssr-client.cjs","sources":["../../../src/ssr/ssr-client.ts"],"sourcesContent":["import invariant from 'tiny-invariant'\nimport { isPlainObject } from '../utils'\nimport { tsrSerializer } from '../serializer'\nimport type { DeferredPromiseState } from '../defer'\nimport type { MakeRouteMatch } from '../Matches'\nimport type { AnyRouter, ControllablePromise } from '../router'\nimport type { Manifest } from '../manifest'\nimport type { RouteContextOptions } from '../route'\n\ndeclare global {\n interface Window {\n __TSR_SSR__?: TsrSsrGlobal\n }\n}\n\nexport interface TsrSsrGlobal {\n matches: Array<SsrMatch>\n streamedValues: Record<\n string,\n {\n value: any\n parsed: any\n }\n >\n cleanScripts: () => void\n dehydrated?: any\n initMatch: (match: SsrMatch) => void\n resolvePromise: (opts: {\n matchId: string\n id: number\n promiseState: DeferredPromiseState<any>\n }) => void\n injectChunk: (opts: { matchId: string; id: number; chunk: string }) => void\n closeStream: (opts: { matchId: string; id: number }) => void\n}\n\nexport interface SsrMatch {\n id: string\n __beforeLoadContext: string\n loaderData?: string\n error?: string\n extracted?: Array<ClientExtractedEntry>\n updatedAt: MakeRouteMatch['updatedAt']\n status: MakeRouteMatch['status']\n ssr?: boolean | 'data-only'\n}\n\nexport type ClientExtractedEntry =\n | ClientExtractedStream\n | ClientExtractedPromise\n\nexport interface ClientExtractedPromise extends ClientExtractedBaseEntry {\n type: 'promise'\n value?: ControllablePromise<any>\n}\n\nexport interface ClientExtractedStream extends ClientExtractedBaseEntry {\n type: 'stream'\n value?: ReadableStream & { controller?: ReadableStreamDefaultController }\n}\n\nexport interface ClientExtractedBaseEntry {\n type: string\n path: Array<string>\n}\n\nexport interface ResolvePromiseState {\n matchId: string\n id: number\n promiseState: DeferredPromiseState<any>\n}\n\nexport interface DehydratedRouter {\n manifest: Manifest | undefined\n dehydratedData: any\n lastMatchId: string\n}\n\nexport async function hydrate(router: AnyRouter): Promise<any> {\n invariant(\n window.__TSR_SSR__?.dehydrated,\n 'Expected to find a dehydrated data on window.__TSR_SSR__.dehydrated... but we did not. Please file an issue!',\n )\n\n const { manifest, dehydratedData, lastMatchId } = tsrSerializer.parse(\n window.__TSR_SSR__.dehydrated,\n ) as DehydratedRouter\n\n router.ssr = {\n manifest,\n serializer: tsrSerializer,\n }\n\n router.clientSsr = {\n getStreamedValue: <T>(key: string): T | undefined => {\n if (router.isServer) {\n return undefined\n }\n\n const streamedValue = window.__TSR_SSR__?.streamedValues[key]\n\n if (!streamedValue) {\n return\n }\n\n if (!streamedValue.parsed) {\n streamedValue.parsed = router.ssr!.serializer.parse(streamedValue.value)\n }\n\n return streamedValue.parsed\n },\n }\n\n // Hydrate the router state\n const matches = router.matchRoutes(router.state.location)\n\n // kick off loading the route chunks\n const routeChunkPromise = Promise.all(\n matches.map((match) => {\n const route = router.looseRoutesById[match.routeId]!\n return router.loadRouteChunk(route)\n }),\n )\n\n // Right after hydration and before the first render, we need to rehydrate each match\n // First step is to reyhdrate loaderData and __beforeLoadContext\n let firstNonSsrMatchIndex: number | undefined = undefined\n matches.forEach((match) => {\n const dehydratedMatch = window.__TSR_SSR__!.matches.find(\n (d) => d.id === match.id,\n )\n\n if (!dehydratedMatch) {\n Object.assign(match, { dehydrated: false, ssr: false })\n return\n }\n\n Object.assign(match, dehydratedMatch)\n\n if (match.ssr === false) {\n match._dehydrated = false\n } else {\n match._dehydrated = true\n }\n\n if (match.ssr === 'data-only' || match.ssr === false) {\n if (firstNonSsrMatchIndex === undefined) {\n firstNonSsrMatchIndex = match.index\n match._forcePending = true\n }\n }\n\n if (match.ssr === false) {\n return\n }\n\n // Handle beforeLoadContext\n if (dehydratedMatch.__beforeLoadContext) {\n match.__beforeLoadContext = router.ssr!.serializer.parse(\n dehydratedMatch.__beforeLoadContext,\n ) as any\n }\n\n // Handle loaderData\n if (dehydratedMatch.loaderData) {\n match.loaderData = router.ssr!.serializer.parse(\n dehydratedMatch.loaderData,\n )\n }\n\n // Handle error\n if (dehydratedMatch.error) {\n match.error = router.ssr!.serializer.parse(dehydratedMatch.error)\n }\n\n // Handle extracted\n ;(match as unknown as SsrMatch).extracted?.forEach((ex) => {\n deepMutableSetByPath(match, ['loaderData', ...ex.path], ex.value)\n })\n })\n\n router.__store.setState((s) => {\n return {\n ...s,\n matches,\n }\n })\n\n // Allow the user to handle custom hydration data\n await router.options.hydrate?.(dehydratedData)\n\n // now that all necessary data is hydrated:\n // 1) fully reconstruct the route context\n // 2) execute `head()` and `scripts()` for each match\n await Promise.all(\n router.state.matches.map(async (match) => {\n const route = router.looseRoutesById[match.routeId]!\n\n const parentMatch = router.state.matches[match.index - 1]\n const parentContext = parentMatch?.context ?? router.options.context ?? {}\n\n // `context()` was already executed by `matchRoutes`, however route context was not yet fully reconstructed\n // so run it again and merge route context\n const contextFnContext: RouteContextOptions<any, any, any, any> = {\n deps: match.loaderDeps,\n params: match.params,\n context: parentContext,\n location: router.state.location,\n navigate: (opts: any) =>\n router.navigate({ ...opts, _fromLocation: router.state.location }),\n buildLocation: router.buildLocation,\n cause: match.cause,\n abortController: match.abortController,\n preload: false,\n matches,\n }\n match.__routeContext = route.options.context?.(contextFnContext) ?? {}\n\n match.context = {\n ...parentContext,\n ...match.__routeContext,\n ...match.__beforeLoadContext,\n }\n\n const assetContext = {\n matches: router.state.matches,\n match,\n params: match.params,\n loaderData: match.loaderData,\n }\n const headFnContent = await route.options.head?.(assetContext)\n\n const scripts = await route.options.scripts?.(assetContext)\n\n match.meta = headFnContent?.meta\n match.links = headFnContent?.links\n match.headScripts = headFnContent?.scripts\n match.styles = headFnContent?.styles\n match.scripts = scripts\n }),\n )\n\n // schedule router.load() to run after the next tick so we can store the promise in the match before loading starts\n const loadPromise = Promise.resolve()\n .then(() => router.load())\n .catch((err) => {\n console.error('Error during router hydration:', err)\n })\n\n // in SPA mode we need to keep the outermost match pending until router.load() is finished\n // this will prevent that other pending components are rendered but hydration is not blocked\n if (matches[matches.length - 1]!.id !== lastMatchId) {\n const matchId = matches[0]!.id\n router.updateMatch(matchId, (prev) => {\n return {\n ...prev,\n _displayPending: true,\n displayPendingPromise: loadPromise,\n // make sure that the pending component is displayed for at least pendingMinMs\n _forcePending: true,\n }\n })\n // hide the pending component once the load is finished\n loadPromise.then(() => {\n router.updateMatch(matchId, (prev) => {\n return {\n ...prev,\n _displayPending: undefined,\n displayPendingPromise: undefined,\n }\n })\n })\n }\n\n return routeChunkPromise\n}\n\nfunction deepMutableSetByPath<T>(obj: T, path: Array<string>, value: any) {\n // mutable set by path retaining array and object references\n if (path.length === 1) {\n ;(obj as any)[path[0]!] = value\n }\n\n const [key, ...rest] = path\n\n if (Array.isArray(obj)) {\n deepMutableSetByPath(obj[Number(key)], rest, value)\n } else if (isPlainObject(obj)) {\n deepMutableSetByPath((obj as any)[key!], rest, value)\n }\n}\n"],"names":["tsrSerializer","_a","_b","_c","isPlainObject"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ssr-client.cjs","sources":["../../../src/ssr/ssr-client.ts"],"sourcesContent":["import invariant from 'tiny-invariant'\nimport type { MakeRouteMatch } from '../Matches'\nimport type { AnyRouter } from '../router'\nimport type { Manifest } from '../manifest'\nimport type { RouteContextOptions } from '../route'\nimport type { GLOBAL_TSR } from './ssr-server'\n\ndeclare global {\n interface Window {\n [GLOBAL_TSR]?: TsrSsrGlobal\n }\n}\n\nexport interface TsrSsrGlobal {\n router?: DehydratedRouter\n // clean scripts, shortened since this is sent for each streamed script\n c: () => void\n}\n\nfunction hydrateMatch(\n deyhydratedMatch: DehydratedMatch,\n): Partial<MakeRouteMatch> {\n return {\n id: deyhydratedMatch.i,\n __beforeLoadContext: deyhydratedMatch.b,\n loaderData: deyhydratedMatch.l,\n status: deyhydratedMatch.s,\n ssr: deyhydratedMatch.ssr,\n updatedAt: deyhydratedMatch.u,\n error: deyhydratedMatch.e,\n }\n}\nexport interface DehydratedMatch {\n i: MakeRouteMatch['id']\n b?: MakeRouteMatch['__beforeLoadContext']\n l?: MakeRouteMatch['loaderData']\n e?: MakeRouteMatch['error']\n u: MakeRouteMatch['updatedAt']\n s: MakeRouteMatch['status']\n ssr?: MakeRouteMatch['ssr']\n}\n\nexport interface DehydratedRouter {\n manifest: Manifest | undefined\n dehydratedData?: any\n lastMatchId?: string\n matches: Array<DehydratedMatch>\n}\n\nexport async function hydrate(router: AnyRouter): Promise<any> {\n invariant(\n window.$_TSR?.router,\n 'Expected to find a dehydrated data on window.$_TSR.router, but we did not. Please file an issue!',\n )\n\n const { manifest, dehydratedData, lastMatchId } = window.$_TSR.router\n\n router.ssr = {\n manifest,\n }\n\n // Hydrate the router state\n const matches = router.matchRoutes(router.state.location)\n\n // kick off loading the route chunks\n const routeChunkPromise = Promise.all(\n matches.map((match) => {\n const route = router.looseRoutesById[match.routeId]!\n return router.loadRouteChunk(route)\n }),\n )\n\n // Right after hydration and before the first render, we need to rehydrate each match\n // First step is to reyhdrate loaderData and __beforeLoadContext\n let firstNonSsrMatchIndex: number | undefined = undefined\n matches.forEach((match) => {\n const dehydratedMatch = window.$_TSR!.router!.matches.find(\n (d) => d.i === match.id,\n )\n if (!dehydratedMatch) {\n Object.assign(match, { dehydrated: false, ssr: false })\n return\n }\n\n Object.assign(match, hydrateMatch(dehydratedMatch))\n\n if (match.ssr === false) {\n match._dehydrated = false\n } else {\n match._dehydrated = true\n }\n\n if (match.ssr === 'data-only' || match.ssr === false) {\n if (firstNonSsrMatchIndex === undefined) {\n firstNonSsrMatchIndex = match.index\n match._forcePending = true\n }\n }\n\n if (match.ssr === false) {\n return\n }\n })\n\n router.__store.setState((s) => {\n return {\n ...s,\n matches,\n }\n })\n\n // Allow the user to handle custom hydration data\n await router.options.hydrate?.(dehydratedData)\n\n // now that all necessary data is hydrated:\n // 1) fully reconstruct the route context\n // 2) execute `head()` and `scripts()` for each match\n await Promise.all(\n router.state.matches.map(async (match) => {\n const route = router.looseRoutesById[match.routeId]!\n\n const parentMatch = router.state.matches[match.index - 1]\n const parentContext = parentMatch?.context ?? router.options.context ?? {}\n\n // `context()` was already executed by `matchRoutes`, however route context was not yet fully reconstructed\n // so run it again and merge route context\n const contextFnContext: RouteContextOptions<any, any, any, any> = {\n deps: match.loaderDeps,\n params: match.params,\n context: parentContext,\n location: router.state.location,\n navigate: (opts: any) =>\n router.navigate({ ...opts, _fromLocation: router.state.location }),\n buildLocation: router.buildLocation,\n cause: match.cause,\n abortController: match.abortController,\n preload: false,\n matches,\n }\n match.__routeContext = route.options.context?.(contextFnContext) ?? {}\n\n match.context = {\n ...parentContext,\n ...match.__routeContext,\n ...match.__beforeLoadContext,\n }\n\n const assetContext = {\n matches: router.state.matches,\n match,\n params: match.params,\n loaderData: match.loaderData,\n }\n const headFnContent = await route.options.head?.(assetContext)\n\n const scripts = await route.options.scripts?.(assetContext)\n\n match.meta = headFnContent?.meta\n match.links = headFnContent?.links\n match.headScripts = headFnContent?.scripts\n match.styles = headFnContent?.styles\n match.scripts = scripts\n }),\n )\n\n // schedule router.load() to run after the next tick so we can store the promise in the match before loading starts\n const loadPromise = Promise.resolve()\n .then(() => router.load())\n .catch((err) => {\n console.error('Error during router hydration:', err)\n })\n\n // in SPA mode we need to keep the outermost match pending until router.load() is finished\n // this will prevent that other pending components are rendered but hydration is not blocked\n if (matches[matches.length - 1]!.id !== lastMatchId) {\n const matchId = matches[0]!.id\n router.updateMatch(matchId, (prev) => {\n return {\n ...prev,\n _displayPending: true,\n displayPendingPromise: loadPromise,\n // make sure that the pending component is displayed for at least pendingMinMs\n _forcePending: true,\n }\n })\n // hide the pending component once the load is finished\n loadPromise.then(() => {\n router.updateMatch(matchId, (prev) => {\n return {\n ...prev,\n _displayPending: undefined,\n displayPendingPromise: undefined,\n }\n })\n })\n }\n return routeChunkPromise\n}\n"],"names":["_b","_a","_c"],"mappings":"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"}
|
|
@@ -1,69 +1,29 @@
|
|
|
1
|
-
import { DeferredPromiseState } from '../defer.cjs';
|
|
2
1
|
import { MakeRouteMatch } from '../Matches.cjs';
|
|
3
|
-
import { AnyRouter
|
|
2
|
+
import { AnyRouter } from '../router.cjs';
|
|
4
3
|
import { Manifest } from '../manifest.cjs';
|
|
4
|
+
import { GLOBAL_TSR } from './ssr-server.cjs';
|
|
5
5
|
declare global {
|
|
6
6
|
interface Window {
|
|
7
|
-
|
|
7
|
+
[GLOBAL_TSR]?: TsrSsrGlobal;
|
|
8
8
|
}
|
|
9
9
|
}
|
|
10
10
|
export interface TsrSsrGlobal {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
promiseState: DeferredPromiseState<any>;
|
|
23
|
-
}) => void;
|
|
24
|
-
injectChunk: (opts: {
|
|
25
|
-
matchId: string;
|
|
26
|
-
id: number;
|
|
27
|
-
chunk: string;
|
|
28
|
-
}) => void;
|
|
29
|
-
closeStream: (opts: {
|
|
30
|
-
matchId: string;
|
|
31
|
-
id: number;
|
|
32
|
-
}) => void;
|
|
33
|
-
}
|
|
34
|
-
export interface SsrMatch {
|
|
35
|
-
id: string;
|
|
36
|
-
__beforeLoadContext: string;
|
|
37
|
-
loaderData?: string;
|
|
38
|
-
error?: string;
|
|
39
|
-
extracted?: Array<ClientExtractedEntry>;
|
|
40
|
-
updatedAt: MakeRouteMatch['updatedAt'];
|
|
41
|
-
status: MakeRouteMatch['status'];
|
|
42
|
-
ssr?: boolean | 'data-only';
|
|
43
|
-
}
|
|
44
|
-
export type ClientExtractedEntry = ClientExtractedStream | ClientExtractedPromise;
|
|
45
|
-
export interface ClientExtractedPromise extends ClientExtractedBaseEntry {
|
|
46
|
-
type: 'promise';
|
|
47
|
-
value?: ControllablePromise<any>;
|
|
48
|
-
}
|
|
49
|
-
export interface ClientExtractedStream extends ClientExtractedBaseEntry {
|
|
50
|
-
type: 'stream';
|
|
51
|
-
value?: ReadableStream & {
|
|
52
|
-
controller?: ReadableStreamDefaultController;
|
|
53
|
-
};
|
|
54
|
-
}
|
|
55
|
-
export interface ClientExtractedBaseEntry {
|
|
56
|
-
type: string;
|
|
57
|
-
path: Array<string>;
|
|
58
|
-
}
|
|
59
|
-
export interface ResolvePromiseState {
|
|
60
|
-
matchId: string;
|
|
61
|
-
id: number;
|
|
62
|
-
promiseState: DeferredPromiseState<any>;
|
|
11
|
+
router?: DehydratedRouter;
|
|
12
|
+
c: () => void;
|
|
13
|
+
}
|
|
14
|
+
export interface DehydratedMatch {
|
|
15
|
+
i: MakeRouteMatch['id'];
|
|
16
|
+
b?: MakeRouteMatch['__beforeLoadContext'];
|
|
17
|
+
l?: MakeRouteMatch['loaderData'];
|
|
18
|
+
e?: MakeRouteMatch['error'];
|
|
19
|
+
u: MakeRouteMatch['updatedAt'];
|
|
20
|
+
s: MakeRouteMatch['status'];
|
|
21
|
+
ssr?: MakeRouteMatch['ssr'];
|
|
63
22
|
}
|
|
64
23
|
export interface DehydratedRouter {
|
|
65
24
|
manifest: Manifest | undefined;
|
|
66
|
-
dehydratedData
|
|
67
|
-
lastMatchId
|
|
25
|
+
dehydratedData?: any;
|
|
26
|
+
lastMatchId?: string;
|
|
27
|
+
matches: Array<DehydratedMatch>;
|
|
68
28
|
}
|
|
69
29
|
export declare function hydrate(router: AnyRouter): Promise<any>;
|