@octanejs/tanstack-router 0.1.10 → 0.1.12

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.
Files changed (61) hide show
  1. package/README.md +24 -11
  2. package/package.json +26 -11
  3. package/src/Asset.tsrx +122 -0
  4. package/src/Asset.tsrx.d.ts +9 -0
  5. package/src/Await.tsrx +2 -1
  6. package/src/Await.tsrx.d.ts +8 -6
  7. package/src/Body.ts +31 -0
  8. package/src/CatchBoundary.tsrx +1 -3
  9. package/src/ClientOnly.tsrx +4 -2
  10. package/src/Head.ts +22 -0
  11. package/src/HeadContent.tsrx +41 -0
  12. package/src/HeadContent.tsrx.d.ts +8 -0
  13. package/src/Html.ts +19 -0
  14. package/src/Link.tsrx +25 -7
  15. package/src/Link.tsrx.d.ts +3 -4
  16. package/src/Match.tsrx +40 -13
  17. package/src/Matches.tsrx +7 -7
  18. package/src/Outlet.tsrx +3 -3
  19. package/src/RouteNotFound.tsrx +1 -1
  20. package/src/RouterProvider.tsrx +2 -1
  21. package/src/ScriptOnce.tsrx +23 -0
  22. package/src/ScriptOnce.tsrx.d.ts +3 -0
  23. package/src/Scripts.tsrx +42 -0
  24. package/src/Scripts.tsrx.d.ts +3 -0
  25. package/src/Transitioner.tsrx +15 -13
  26. package/src/assetKeys.ts +11 -0
  27. package/src/context.ts +6 -3
  28. package/src/externalHydration.ts +77 -0
  29. package/src/fileRoute.ts +277 -0
  30. package/src/frameworkTypes.ts +42 -0
  31. package/src/generator-plugin.d.ts +20 -0
  32. package/src/generator-plugin.js +108 -0
  33. package/src/headContentUtils.ts +172 -0
  34. package/src/hooks.ts +151 -0
  35. package/src/index.ts +84 -4
  36. package/src/lazyRouteComponent.ts +2 -1
  37. package/src/link.ts +25 -4
  38. package/src/linkTypes.ts +95 -0
  39. package/src/not-found.tsrx +2 -2
  40. package/src/octane-compiler.d.ts +12 -0
  41. package/src/route.ts +438 -42
  42. package/src/routeHookTypes.ts +228 -0
  43. package/src/router.ts +31 -6
  44. package/src/scriptContentUtils.ts +64 -0
  45. package/src/scroll-restoration.tsrx +16 -0
  46. package/src/scroll-restoration.tsrx.d.ts +3 -0
  47. package/src/ssr/RouterClient.tsrx +36 -0
  48. package/src/ssr/RouterClient.tsrx.d.ts +4 -0
  49. package/src/ssr/RouterServer.tsrx +6 -0
  50. package/src/ssr/RouterServer.tsrx.d.ts +4 -0
  51. package/src/ssr/client.ts +4 -0
  52. package/src/ssr/defaultRenderHandler.ts +11 -0
  53. package/src/ssr/defaultStreamHandler.ts +12 -0
  54. package/src/ssr/renderRouterToStream.ts +195 -0
  55. package/src/ssr/renderRouterToString.ts +58 -0
  56. package/src/ssr/server.ts +8 -0
  57. package/src/structuralSharing.ts +41 -0
  58. package/src/typePrimitives.ts +77 -0
  59. package/src/useAwaited.ts +7 -2
  60. package/src/useBlocker.tsrx +2 -1
  61. package/src/useRouterState.ts +20 -0
@@ -0,0 +1,58 @@
1
+ import { renderToString as octaneRenderToString } from 'octane/server';
2
+ import type { ComponentBody } from 'octane';
3
+ import type { AnyRouter } from '@tanstack/router-core';
4
+
5
+ type RouterApp = ComponentBody<{ router: AnyRouter }>;
6
+ type ServerComponent = Parameters<typeof octaneRenderToString>[0];
7
+
8
+ // eslint-disable-next-line @typescript-eslint/require-await -- framework render handlers share an async contract
9
+ export async function renderRouterToString({
10
+ router,
11
+ responseHeaders,
12
+ App,
13
+ }: {
14
+ router: AnyRouter;
15
+ responseHeaders: Headers;
16
+ App: RouterApp;
17
+ }) {
18
+ try {
19
+ const result = octaneRenderToString(
20
+ App as unknown as ServerComponent,
21
+ { router },
22
+ { nonce: router.options.ssr?.nonce },
23
+ );
24
+ router.serverSsr!.setRenderFinished();
25
+
26
+ return new Response(
27
+ finalizeBufferedHtml(result.html, result.css, router.serverSsr!.takeBufferedHtml()),
28
+ {
29
+ status: router.stores.statusCode.get(),
30
+ headers: responseHeaders,
31
+ },
32
+ );
33
+ } catch (error) {
34
+ console.error('Render to string error:', error);
35
+ return new Response('Internal Server Error', {
36
+ status: 500,
37
+ headers: responseHeaders,
38
+ });
39
+ } finally {
40
+ router.serverSsr?.cleanup();
41
+ }
42
+ }
43
+
44
+ export function finalizeBufferedHtml(renderedHtml: string, css: string, injectedHtml?: string) {
45
+ let html = renderedHtml;
46
+
47
+ if (css) {
48
+ html = html.includes('</head>') ? html.replace('</head>', `${css}</head>`) : `${css}${html}`;
49
+ }
50
+
51
+ if (injectedHtml) {
52
+ html = html.includes('</body>')
53
+ ? html.replace('</body>', `${injectedHtml}</body>`)
54
+ : `${html}${injectedHtml}`;
55
+ }
56
+
57
+ return `<!DOCTYPE html>${html}`;
58
+ }
@@ -0,0 +1,8 @@
1
+ import '../frameworkTypes';
2
+
3
+ export { RouterServer } from './RouterServer.tsrx';
4
+ export { defaultRenderHandler } from './defaultRenderHandler';
5
+ export { defaultStreamHandler } from './defaultStreamHandler';
6
+ export { renderRouterToStream } from './renderRouterToStream';
7
+ export { renderRouterToString } from './renderRouterToString';
8
+ export * from '@tanstack/router-core/ssr/server';
@@ -0,0 +1,41 @@
1
+ import type {
2
+ AnyRouter,
3
+ Constrain,
4
+ OptionalStructuralSharing,
5
+ ValidateJSON,
6
+ } from '@tanstack/router-core';
7
+
8
+ export type DefaultStructuralSharingEnabled<TRouter extends AnyRouter> =
9
+ boolean extends TRouter['options']['defaultStructuralSharing']
10
+ ? false
11
+ : NonNullable<TRouter['options']['defaultStructuralSharing']>;
12
+
13
+ export interface RequiredStructuralSharing<TStructuralSharing, TConstraint> {
14
+ readonly structuralSharing: Constrain<TStructuralSharing, TConstraint>;
15
+ }
16
+
17
+ export type StructuralSharingOption<
18
+ TRouter extends AnyRouter,
19
+ TSelected,
20
+ TStructuralSharing,
21
+ > = unknown extends TSelected
22
+ ? OptionalStructuralSharing<TStructuralSharing, boolean>
23
+ : unknown extends TRouter['routeTree']
24
+ ? OptionalStructuralSharing<TStructuralSharing, boolean>
25
+ : TSelected extends ValidateJSON<TSelected>
26
+ ? OptionalStructuralSharing<TStructuralSharing, boolean>
27
+ : DefaultStructuralSharingEnabled<TRouter> extends true
28
+ ? RequiredStructuralSharing<TStructuralSharing, false>
29
+ : OptionalStructuralSharing<TStructuralSharing, false>;
30
+
31
+ export type StructuralSharingEnabled<
32
+ TRouter extends AnyRouter,
33
+ TStructuralSharing,
34
+ > = boolean extends TStructuralSharing
35
+ ? DefaultStructuralSharingEnabled<TRouter>
36
+ : TStructuralSharing;
37
+
38
+ export type ValidateSelected<TRouter extends AnyRouter, TSelected, TStructuralSharing> =
39
+ StructuralSharingEnabled<TRouter, TStructuralSharing> extends true
40
+ ? ValidateJSON<TSelected>
41
+ : TSelected;
@@ -0,0 +1,77 @@
1
+ import type {
2
+ AnyRouter,
3
+ Constrain,
4
+ InferFrom,
5
+ InferMaskFrom,
6
+ InferMaskTo,
7
+ InferSelected,
8
+ InferShouldThrow,
9
+ InferStrict,
10
+ InferTo,
11
+ RegisteredRouter,
12
+ } from '@tanstack/router-core';
13
+ import type { LinkComponentProps } from './linkTypes';
14
+ import type { UseParamsOptions, UseSearchOptions } from './routeHookTypes';
15
+
16
+ export type ValidateLinkOptions<
17
+ TRouter extends AnyRouter = RegisteredRouter,
18
+ TOptions = unknown,
19
+ TDefaultFrom extends string = string,
20
+ TComp = 'a',
21
+ > = Constrain<
22
+ TOptions,
23
+ LinkComponentProps<
24
+ TComp,
25
+ TRouter,
26
+ InferFrom<TOptions, TDefaultFrom>,
27
+ InferTo<TOptions>,
28
+ InferMaskFrom<TOptions>,
29
+ InferMaskTo<TOptions>
30
+ >
31
+ >;
32
+
33
+ /** @private */
34
+ export type InferStructuralSharing<TOptions> = TOptions extends {
35
+ structuralSharing: infer TStructuralSharing;
36
+ }
37
+ ? TStructuralSharing
38
+ : unknown;
39
+
40
+ export type ValidateUseSearchOptions<
41
+ TOptions,
42
+ TRouter extends AnyRouter = RegisteredRouter,
43
+ > = Constrain<
44
+ TOptions,
45
+ UseSearchOptions<
46
+ TRouter,
47
+ InferFrom<TOptions>,
48
+ InferStrict<TOptions>,
49
+ InferShouldThrow<TOptions>,
50
+ InferSelected<TOptions>,
51
+ InferStructuralSharing<TOptions>
52
+ >
53
+ >;
54
+
55
+ export type ValidateUseParamsOptions<
56
+ TOptions,
57
+ TRouter extends AnyRouter = RegisteredRouter,
58
+ > = Constrain<
59
+ TOptions,
60
+ UseParamsOptions<
61
+ TRouter,
62
+ InferFrom<TOptions>,
63
+ InferStrict<TOptions>,
64
+ InferShouldThrow<TOptions>,
65
+ InferSelected<TOptions>,
66
+ InferStructuralSharing<TOptions>
67
+ >
68
+ >;
69
+
70
+ export type ValidateLinkOptionsArray<
71
+ TRouter extends AnyRouter = RegisteredRouter,
72
+ TOptions extends ReadonlyArray<unknown> = ReadonlyArray<unknown>,
73
+ TDefaultFrom extends string = string,
74
+ TComp = 'a',
75
+ > = {
76
+ [K in keyof TOptions]: ValidateLinkOptions<TRouter, TOptions[K], TDefaultFrom, TComp>;
77
+ };
package/src/useAwaited.ts CHANGED
@@ -3,7 +3,12 @@
3
3
  // this is a one-liner. The promise is typically produced by router-core's `defer()`
4
4
  // in a loader and streamed to the client.
5
5
  import { use } from 'octane';
6
+ import { toExternalHydrationThenable } from './externalHydration';
6
7
 
7
- export function useAwaited(opts: { promise: any }): any {
8
- return use(opts.promise);
8
+ export type AwaitOptions<T> = {
9
+ promise: Promise<T>;
10
+ };
11
+
12
+ export function useAwaited<T>(opts: AwaitOptions<T>): T {
13
+ return use(toExternalHydrationThenable(opts.promise));
9
14
  }
@@ -180,7 +180,8 @@ export function useBlocker(
180
180
 
181
181
  // Upstream's PromptProps: the blocker options plus optional children (a render
182
182
  // prop receiving the resolver, or plain renderables).
183
- export type PromptProps = (UseBlockerOpts | LegacyBlockerOpts) & {
183
+ export type PromptProps =
184
+ (UseBlockerOpts | LegacyBlockerOpts) & {
184
185
  children?: OctaneNode | ((params: BlockerResolver) => OctaneNode);
185
186
  };
186
187
 
@@ -3,7 +3,27 @@
3
3
  import { useStore } from './useStore';
4
4
  import { useRouter } from './context';
5
5
  import { splitSlot, subSlot } from './internal';
6
+ import type { AnyRouter, RegisteredRouter, RouterState } from '@tanstack/router-core';
7
+ import type { StructuralSharingOption, ValidateSelected } from './structuralSharing';
6
8
 
9
+ export type UseRouterStateOptions<TRouter extends AnyRouter, TSelected, TStructuralSharing> = {
10
+ router?: TRouter;
11
+ select?: (
12
+ state: RouterState<TRouter['routeTree']>,
13
+ ) => ValidateSelected<TRouter, TSelected, TStructuralSharing>;
14
+ } & StructuralSharingOption<TRouter, TSelected, TStructuralSharing>;
15
+
16
+ export type UseRouterStateResult<TRouter extends AnyRouter, TSelected> = unknown extends TSelected
17
+ ? RouterState<TRouter['routeTree']>
18
+ : TSelected;
19
+
20
+ export function useRouterState<
21
+ TRouter extends AnyRouter = RegisteredRouter,
22
+ TSelected = unknown,
23
+ TStructuralSharing extends boolean = boolean,
24
+ >(
25
+ opts?: UseRouterStateOptions<TRouter, TSelected, TStructuralSharing>,
26
+ ): UseRouterStateResult<TRouter, TSelected>;
7
27
  export function useRouterState(...args: any[]): any {
8
28
  const [user, slot] = splitSlot(args);
9
29
  const opts = (user[0] ?? {}) as { select?: (s: any) => any; router?: any };