@bleedingdev/modern-js-renderer-solid 3.9.3-ultramodern.7 → 3.9.3-ultramodern.9

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 (97) hide show
  1. package/dist/esm/actions.js +3 -4
  2. package/dist/esm/application-router.js +7 -2
  3. package/dist/esm/entry-client.js +1 -0
  4. package/dist/esm/federation-ssr.js +17 -9
  5. package/dist/esm/federation.js +8 -4
  6. package/dist/esm/i18n/LocalizedLink.js +28 -50
  7. package/dist/esm/i18n/index.js +1 -1
  8. package/dist/esm/index.js +5 -5
  9. package/dist/esm/manifest.js +1 -1
  10. package/dist/esm/route-completion.js +2 -1
  11. package/dist/esm/router-binding/Asset.js +3 -2
  12. package/dist/esm/router-binding/Matches.js +19 -12
  13. package/dist/esm/router-binding/PROVENANCE.json +3 -3
  14. package/dist/esm/router-binding/RouterProvider.js +2 -1
  15. package/dist/esm/router-binding/Transitioner.js +10 -4
  16. package/dist/esm/router-binding/fileRoute.js +1 -1
  17. package/dist/esm/router-binding/headContentUtils.js +9 -3
  18. package/dist/esm/router-binding/index.js +1 -1
  19. package/dist/esm/router-binding/link.js +3 -5
  20. package/dist/esm/router-binding/registryTransfer.js +16 -3
  21. package/dist/esm/router-binding/router.js +2 -1
  22. package/dist/esm/router-binding/routerOptions.js +0 -0
  23. package/dist/esm/router-binding/useLoaderData.js +1 -2
  24. package/dist/esm/router-binding/useNavigate.js +8 -2
  25. package/dist/esm/router-binding/useParams.js +1 -3
  26. package/dist/esm/router-binding/useSearch.js +1 -3
  27. package/dist/esm-node/actions.js +2 -2
  28. package/dist/esm-node/application-router.js +7 -2
  29. package/dist/esm-node/entry-client.js +1 -0
  30. package/dist/esm-node/federation-ssr.js +17 -9
  31. package/dist/esm-node/federation.js +8 -4
  32. package/dist/esm-node/i18n/LocalizedLink.js +43 -97
  33. package/dist/esm-node/i18n/index.js +1 -1
  34. package/dist/esm-node/index.js +5 -5
  35. package/dist/esm-node/manifest.js +1 -1
  36. package/dist/esm-node/plugin/index.js +1 -4
  37. package/dist/esm-node/plugin/profile.js +10 -11
  38. package/dist/esm-node/route-completion.js +2 -1
  39. package/dist/esm-node/router-binding/Asset.js +3 -2
  40. package/dist/esm-node/router-binding/CatchBoundary.js +3 -3
  41. package/dist/esm-node/router-binding/Matches.js +30 -30
  42. package/dist/esm-node/router-binding/PROVENANCE.json +3 -3
  43. package/dist/esm-node/router-binding/RouterProvider.js +2 -1
  44. package/dist/esm-node/router-binding/Transitioner.js +10 -4
  45. package/dist/esm-node/router-binding/fileRoute.js +1 -1
  46. package/dist/esm-node/router-binding/headContentUtils.js +9 -3
  47. package/dist/esm-node/router-binding/index.js +1 -1
  48. package/dist/esm-node/router-binding/link.js +2 -2
  49. package/dist/esm-node/router-binding/registryTransfer.js +16 -3
  50. package/dist/esm-node/router-binding/router.js +2 -1
  51. package/dist/esm-node/router-binding/routerOptions.js +1 -0
  52. package/dist/esm-node/router-binding/useLoaderData.js +1 -2
  53. package/dist/esm-node/router-binding/useNavigate.js +8 -2
  54. package/dist/esm-node/router-binding/useParams.js +1 -3
  55. package/dist/esm-node/router-binding/useSearch.js +1 -3
  56. package/dist/types/federation-ssr.d.ts +3 -5
  57. package/dist/types/i18n/LocalizedLink.d.ts +5 -33
  58. package/dist/types/i18n/index.d.ts +1 -1
  59. package/dist/types/index.d.ts +5 -5
  60. package/dist/types/manifest.d.ts +1 -1
  61. package/dist/types/router-binding/RouterProvider.d.ts +2 -1
  62. package/dist/types/router-binding/index.d.ts +3 -2
  63. package/dist/types/router-binding/registryTransfer.d.ts +2 -0
  64. package/dist/types/router-binding/routerOptions.d.ts +6 -0
  65. package/dist/types/router.d.ts +3 -3
  66. package/package.json +29 -22
  67. package/src/actions.tsx +5 -1
  68. package/src/application-router.tsx +9 -3
  69. package/src/entry-client.tsx +1 -0
  70. package/src/federation-ssr.ts +32 -13
  71. package/src/federation.tsx +9 -5
  72. package/src/i18n/LocalizedLink.tsx +44 -83
  73. package/src/i18n/index.ts +1 -5
  74. package/src/index.ts +5 -5
  75. package/src/manifest.ts +1 -1
  76. package/src/plugin/index.ts +0 -3
  77. package/src/plugin/preserve-import-loader.cjs +1 -1
  78. package/src/plugin/profile.ts +10 -10
  79. package/src/route-completion.tsx +5 -1
  80. package/src/router-binding/Asset.tsx +10 -9
  81. package/src/router-binding/Matches.tsx +10 -10
  82. package/src/router-binding/PROVENANCE.json +3 -3
  83. package/src/router-binding/RouterProvider.tsx +4 -5
  84. package/src/router-binding/Transitioner.tsx +6 -1
  85. package/src/router-binding/fileRoute.ts +1 -1
  86. package/src/router-binding/headContentUtils.tsx +5 -3
  87. package/src/router-binding/index.tsx +1 -4
  88. package/src/router-binding/link.tsx +2 -2
  89. package/src/router-binding/registryTransfer.ts +23 -6
  90. package/src/router-binding/route.tsx +1 -1
  91. package/src/router-binding/router.ts +2 -0
  92. package/src/router-binding/routerOptions.ts +26 -0
  93. package/src/router-binding/useLoaderData.tsx +4 -3
  94. package/src/router-binding/useNavigate.tsx +5 -3
  95. package/src/router-binding/useParams.tsx +1 -3
  96. package/src/router-binding/useSearch.tsx +1 -3
  97. package/src/router.ts +3 -3
@@ -1,11 +1,11 @@
1
1
  import {
2
- canonicalPath,
3
2
  configuredLanguage,
4
3
  localizePath,
5
4
  } from '@modern-js/i18n-runtime-extensions/paths';
6
5
  import type { JSX } from '@solidjs/web';
7
6
  import * as Solid from 'solid-js';
8
7
  import {
8
+ type AnyRouter,
9
9
  Link,
10
10
  type LinkComponentProps,
11
11
  useLocation,
@@ -13,110 +13,71 @@ import {
13
13
  } from '../router';
14
14
  import { I18nContext } from './context';
15
15
 
16
- export interface LocalizedLinkProps {
16
+ export interface LocalizedLinkProps
17
+ extends Omit<
18
+ LinkComponentProps<'a', AnyRouter, string, string>,
19
+ 'to' | 'mask' | 'href' | 'publicHref' | '_fromLocation'
20
+ > {
17
21
  /** A canonical, language-agnostic target, e.g. `/products/red-shoe`. */
18
22
  to: string;
19
23
  /** Localize for a specific language instead of the current one. */
20
24
  language?: string;
21
- children?: LinkComponentProps<'a'>['children'];
22
- class?: string;
23
- activeProps?: LinkComponentProps<'a'>['activeProps'];
24
- inactiveProps?: LinkComponentProps<'a'>['inactiveProps'];
25
- activeOptions?: LinkComponentProps<'a'>['activeOptions'];
26
- replace?: boolean;
27
- preload?: LinkComponentProps<'a'>['preload'];
28
25
  [key: `data-${string}`]: unknown;
29
26
  }
30
27
 
31
28
  /**
32
- * A thin wrapper over the native Solid router `Link` that localizes a
33
- * canonical `to` for the current (or an explicit) language before handing it
34
- * to the real link, the same contract as `@modern-js/plugin-i18n`'s React
35
- * `Link`. It resolves the href itself via the shared pathname helpers, so it
36
- * works with or without the router's i18n `rewrite`. Every link, including
37
- * one to another language, is the native `Link`: navigation, preloading and
38
- * active state stay with the router.
39
- *
40
- * Under the i18n `rewrite` the router matches canonical paths and localizes
41
- * outgoing locations to the current language, so a link to another language
42
- * routes to the canonical `to` and publishes the target language's URL as a
43
- * route mask (the rewrite keeps a mask's explicit language). The entry's
44
- * router language synchronization (`syncWithRouter`) switches the i18next
45
- * instance from the navigated URL, as it does for history navigation.
46
- *
47
- * Props are forwarded explicitly (not via object-rest or a missing
48
- * `splitProps`/`mergeProps` primitive — Solid 2 only exports `merge`) so
49
- * each one is read directly from `props` in JSX position and keeps its
50
- * per-key reactivity.
29
+ * The native router owns navigation, preloading and active state. A route mask
30
+ * publishes the selected language URL while keeping the canonical route;
31
+ * the entry's router subscription synchronizes the i18next instance.
51
32
  */
52
33
  export function LocalizedLink(props: LocalizedLinkProps): JSX.Element {
53
34
  const context = Solid.useContext(I18nContext);
54
35
  const router = useRouter();
55
- const rewrite = Boolean(router.options.rewrite);
56
-
57
- // An explicit language must be configured: it becomes the locale prefix.
36
+ const location = useLocation();
37
+ const options = Solid.omit(props, 'to', 'language', 'children');
58
38
  const targetLanguage = () =>
59
39
  props.language === undefined
60
40
  ? context.language()
61
41
  : configuredLanguage(props.language, context.languages);
62
- const href = Solid.createMemo(() =>
63
- localizePath(props.to, targetLanguage(), {
42
+ const externalTarget = () =>
43
+ props.to.startsWith('//') || URL.canParse(props.to);
44
+ const canonicalTarget = () => ({
45
+ to: props.to,
46
+ from: props.from,
47
+ params: props.params,
48
+ unsafeRelative: props.unsafeRelative,
49
+ });
50
+ const pathname = Solid.createMemo(() => {
51
+ if (externalTarget()) return props.to;
52
+ const target = router.buildLocation({
53
+ ...canonicalTarget(),
54
+ _fromLocation: location(),
55
+ });
56
+ return localizePath(target.pathname, targetLanguage(), {
64
57
  languages: [...context.languages],
65
58
  localisedUrls: context.localisedUrls,
66
- }),
67
- );
68
- const crossLanguage = () => targetLanguage() !== context.language();
69
- const masked = () => rewrite && crossLanguage();
70
- // Declared `data-*` attributes reach the anchor through getters, so each
71
- // keeps its own reactivity like the explicitly forwarded props.
72
- const dataAttributes = Object.defineProperties(
73
- {},
74
- Object.fromEntries(
75
- Object.keys(props)
76
- .filter(key => key.startsWith('data-'))
77
- .map(key => [
78
- key,
79
- {
80
- enumerable: true,
81
- get: () => props[key as `data-${string}`],
82
- },
83
- ]),
84
- ),
85
- );
59
+ });
60
+ });
86
61
 
87
62
  return (
88
- <Link
89
- {...dataAttributes}
90
- // A masked link routes to the canonical `to`. Otherwise `href` wins over
91
- // `to` in router-core's `buildLocation` (it checks `dest.href` first);
92
- // `to="."` only satisfies the type-level requirement that a `to` be
93
- // present and is otherwise inert.
94
- to={masked() ? props.to : '.'}
95
- href={masked() ? undefined : href()}
96
- mask={masked() ? { to: href() } : undefined}
97
- hreflang={crossLanguage() ? targetLanguage() : undefined}
98
- class={props.class}
99
- activeProps={props.activeProps}
100
- inactiveProps={props.inactiveProps}
101
- activeOptions={props.activeOptions}
102
- replace={props.replace}
103
- preload={props.preload}
63
+ <Link<AnyRouter, string, string, string, string>
64
+ {...options}
65
+ to={router.options.rewrite ? props.to : pathname()}
66
+ mask={
67
+ router.options.rewrite && !externalTarget()
68
+ ? {
69
+ to: pathname(),
70
+ inheritSearch: true,
71
+ hash: props.hash,
72
+ state: props.state,
73
+ }
74
+ : undefined
75
+ }
76
+ hreflang={
77
+ targetLanguage() === context.language() ? undefined : targetLanguage()
78
+ }
104
79
  >
105
80
  {props.children}
106
81
  </Link>
107
82
  );
108
83
  }
109
-
110
- /**
111
- * Language-invariant active check: `to="/products"` is active whether the
112
- * current location is `/en/products` or `/produkty` under a mapped locale.
113
- */
114
- export function useIsLocalizedActive(canonicalTarget: string): () => boolean {
115
- const context = Solid.useContext(I18nContext);
116
- const location = useLocation();
117
- return () =>
118
- canonicalPath(location().pathname, {
119
- languages: [...context.languages],
120
- localisedUrls: context.localisedUrls,
121
- }) === canonicalTarget;
122
- }
package/src/i18n/index.ts CHANGED
@@ -22,11 +22,7 @@ export {
22
22
  } from '@modern-js/i18n-runtime-extensions/urlRewrite';
23
23
  export { I18nContext } from './context';
24
24
  export { I18nProvider, type I18nProviderProps } from './I18nProvider';
25
- export {
26
- LocalizedLink,
27
- type LocalizedLinkProps,
28
- useIsLocalizedActive,
29
- } from './LocalizedLink';
25
+ export { LocalizedLink, type LocalizedLinkProps } from './LocalizedLink';
30
26
  export {
31
27
  createLatestLanguageSync,
32
28
  type SolidLatestLanguageSyncOptions,
package/src/index.ts CHANGED
@@ -1,12 +1,12 @@
1
1
  /** This entry contains identity only. Select client, router or server explicitly. */
2
2
  export const SOLID_RENDERER_PROFILE = {
3
3
  renderer: 'solid',
4
- solid: '2.0.0-rc.13',
5
- web: '2.0.0-rc.13',
4
+ solid: '2.0.0-rc.15',
5
+ web: '2.0.0-rc.15',
6
6
  router: '@modern-js/renderer-solid/router@3.8.3',
7
7
  routerSource: '4fbd65c5c3b40be87a6248867c22021c1c19bba8',
8
- routerCore: '1.171.34',
9
- history: '1.162.4',
8
+ routerCore: '1.171.38',
9
+ history: '1.162.5',
10
10
  publicRouteData: {
11
11
  containers: ['plain-record', 'null-record', 'array'],
12
12
  values: 'canonical-scalars',
@@ -19,7 +19,7 @@ export const SOLID_RENDERER_PROFILE = {
19
19
  providerOverrides: 'unsupported',
20
20
  },
21
21
  nativePromiseMetadata: {
22
- runtime: '2.0.0-rc.13',
22
+ runtime: '2.0.0-rc.15',
23
23
  fields: ['s', 'v'],
24
24
  status: [0, 1, 2],
25
25
  handle: 'sealed-with-checked-metadata',
package/src/manifest.ts CHANGED
@@ -5,7 +5,7 @@ import {
5
5
  readRendererIdentity,
6
6
  } from '@modern-js/renderer-core/identity';
7
7
 
8
- export const SOLID_COMPILER_VERSION = '2.0.0-rc.13';
8
+ export const SOLID_COMPILER_VERSION = '2.0.0-rc.15';
9
9
  export function solidModuleManifestFilename(entryName: string): string {
10
10
  return nativeModuleManifestFilename('solid', entryName);
11
11
  }
@@ -32,8 +32,6 @@ export const rendererAdapter: NativeRendererAdapter<'solid'> =
32
32
  'solid-js',
33
33
  '@solidjs/web',
34
34
  '@solidjs/signals',
35
- 'seroval',
36
- 'seroval-plugins',
37
35
  '@modern-js/renderer-solid',
38
36
  '@modern-js/renderer-solid/client',
39
37
  '@modern-js/renderer-solid/router',
@@ -64,7 +62,6 @@ export const rendererAdapter: NativeRendererAdapter<'solid'> =
64
62
  },
65
63
  devDependencies: {
66
64
  [profile.compiler.name]: profile.compiler.version,
67
- '@solidjs/babel-plugin': profile.compiler.version,
68
65
  },
69
66
  }),
70
67
  generateAppSources: generateSolidAppSources,
@@ -36,7 +36,7 @@ module.exports = function preserveSolidImport(source, inputMap) {
36
36
  });
37
37
  if (matched !== 1 || !result) {
38
38
  throw new Error(
39
- 'Solid native browser URL import contract changed. Expected one import(entryUrl) in @solidjs/web 2.0.0-rc.13; update and revalidate the compiler integration.',
39
+ 'Solid native browser URL import contract changed. Expected one import(entryUrl) in @solidjs/web 2.0.0-rc.15; update and revalidate the compiler integration.',
40
40
  );
41
41
  }
42
42
  callback(null, result.code, result.map);
@@ -4,7 +4,7 @@ export const solidProfile: RendererBuildProfile<'solid'> = {
4
4
  renderer: 'solid',
5
5
  status: 'preview',
6
6
  protocolVersion: 1,
7
- minimumNode: '26.10.0',
7
+ minimumNode: '26.12.0',
8
8
  hmr: {
9
9
  editedBoundary: 'may-reset',
10
10
  unaffectedComponents: 'preserved',
@@ -12,24 +12,24 @@ export const solidProfile: RendererBuildProfile<'solid'> = {
12
12
  roots: 'single',
13
13
  cleanup: 'exactly-once',
14
14
  },
15
- compiler: { name: '@solidjs/compiler', version: '2.0.0-rc.13' },
16
- hydration: { name: '@solidjs/web', version: '2.0.0-rc.13' },
15
+ compiler: { name: '@solidjs/compiler', version: '2.0.0-rc.15' },
16
+ hydration: { name: '@solidjs/web', version: '2.0.0-rc.15' },
17
17
  router: {
18
18
  name: '@modern-js/renderer-solid',
19
19
  version: '3.8.3',
20
20
  coreName: '@tanstack/router-core',
21
- coreVersion: '1.171.34',
21
+ coreVersion: '1.171.38',
22
22
  },
23
23
  sourceExtensions: ['.tsx', '.ts', '.jsx', '.js'],
24
24
  jsxImportSource: '@solidjs/web',
25
25
  dependencies: {
26
- 'solid-js': '2.0.0-rc.13',
27
- '@solidjs/web': '2.0.0-rc.13',
28
- '@solidjs/signals': '2.0.0-rc.13',
29
- '@solidjs/compiler': '2.0.0-rc.13',
26
+ '@tanstack/router-core':
27
+ 'https://github.com/BleedingDev/router/releases/download/ultramodern-router-core-585d3233f7f5/tanstack-router-core-1.171.38.tgz',
28
+ 'solid-js': '2.0.0-rc.15',
29
+ '@solidjs/web': '2.0.0-rc.15',
30
+ '@solidjs/signals': '2.0.0-rc.15',
31
+ '@solidjs/compiler': '2.0.0-rc.15',
30
32
  '@modern-js/renderer-solid': '3.8.3',
31
- seroval: '1.6.8',
32
- 'seroval-plugins': '1.6.8',
33
33
  },
34
34
  capabilities: {
35
35
  worker: true,
@@ -10,7 +10,10 @@ import {
10
10
  preparePublicContextData,
11
11
  useMatch,
12
12
  } from './router-binding/index';
13
- import { registerPublicRouteDataOwner } from './router-binding/registryTransfer';
13
+ import {
14
+ assertNativeSerializationOptions,
15
+ registerPublicRouteDataOwner,
16
+ } from './router-binding/registryTransfer';
14
17
 
15
18
  interface CompletionRecord {
16
19
  readonly failure: Accessor<{ reason: unknown } | undefined>;
@@ -52,6 +55,7 @@ export function registerRouteCompletionScope(
52
55
  }
53
56
 
54
57
  export const createApplicationRouter: CreateRouterFn = options => {
58
+ assertNativeSerializationOptions(options);
55
59
  const scope = options.routeTree
56
60
  ? routeScopes.get(options.routeTree)
57
61
  : undefined;
@@ -62,7 +62,7 @@ function InlineCssStyle({
62
62
  attrs,
63
63
  children,
64
64
  }: {
65
- attrs?: Record<string, any>;
65
+ attrs: Record<string, any> | undefined;
66
66
  children?: RouterManagedTag['children'];
67
67
  }) {
68
68
  const isInlineCssPlaceholder = children === undefined;
@@ -85,7 +85,7 @@ function InlineCssStyle({
85
85
 
86
86
  function HeadElement(props: {
87
87
  tag: 'meta' | 'link' | 'style';
88
- attrs?: Record<string, any>;
88
+ attrs: Record<string, any> | undefined;
89
89
  children?: unknown;
90
90
  }): JSX.Element | null {
91
91
  // Each branch must live in its own `case` block so the Solid compiler emits
@@ -101,11 +101,12 @@ function HeadElement(props: {
101
101
  let element: Element;
102
102
  switch (props.tag) {
103
103
  case 'style': {
104
- const attrs = {
105
- ...props.attrs,
106
- innerHTML:
107
- typeof props.children === 'string' ? props.children : undefined,
108
- };
104
+ const attrs = { ...props.attrs };
105
+ // The managed child text owns this field, including when it is absent.
106
+ delete attrs.innerHTML;
107
+ if (typeof props.children === 'string') {
108
+ attrs.innerHTML = props.children;
109
+ }
109
110
  element = (<style {...attrs} />) as unknown as Element;
110
111
  break;
111
112
  }
@@ -125,7 +126,7 @@ function HeadElement(props: {
125
126
  }
126
127
 
127
128
  function Title(props: {
128
- attrs?: Record<string, any>;
129
+ attrs: Record<string, any> | undefined;
129
130
  children?: unknown;
130
131
  }): JSX.Element | null {
131
132
  let el: HTMLTitleElement | undefined;
@@ -158,7 +159,7 @@ function Title(props: {
158
159
  }
159
160
 
160
161
  function Script(props: {
161
- attrs?: Record<string, any>;
162
+ attrs: Record<string, any> | undefined;
162
163
  children?: unknown;
163
164
  }): JSX.Element | null {
164
165
  const router = useRouter();
@@ -79,16 +79,16 @@ function MatchesInner() {
79
79
  getResetKey={() => router.stores.matches.get()}
80
80
  render={matchContent}
81
81
  errorComponent={ErrorComponent}
82
- onCatch={
83
- process.env.NODE_ENV !== 'production'
84
- ? error => {
82
+ {...(process.env.NODE_ENV !== 'production'
83
+ ? {
84
+ onCatch: (error: Error) => {
85
85
  console.warn(
86
86
  `Warning: The following error wasn't caught by any route! At the very least, consider setting an 'errorComponent' in your RootRoute!`,
87
87
  );
88
88
  console.warn(`Warning: ${error.message || error.toString()}`);
89
- }
90
- : undefined
91
- }
89
+ },
90
+ }
91
+ : {})}
92
92
  />
93
93
  </NearestMatchContext>
94
94
  );
@@ -126,10 +126,10 @@ export function useMatchRoute<TRouter extends AnyRouter = RegisteredRouter>() {
126
126
  router.stores.resolvedLocation.get();
127
127
  router.stores.status.get();
128
128
  return router.matchRoute(rest as any, {
129
- pending,
130
- caseSensitive,
131
- fuzzy,
132
- includeSearch,
129
+ ...(pending !== undefined ? { pending } : {}),
130
+ ...(caseSensitive !== undefined ? { caseSensitive } : {}),
131
+ ...(fuzzy !== undefined ? { fuzzy } : {}),
132
+ ...(includeSearch !== undefined ? { includeSearch } : {}),
133
133
  });
134
134
  });
135
135
  };
@@ -14,7 +14,7 @@
14
14
  "sourcePath": "packages/solid-router/src",
15
15
  "upstreamPackage": "@tanstack/solid-router",
16
16
  "upstreamVersion": "1.170.36",
17
- "routerCoreVersion": "1.171.34",
17
+ "routerCoreVersion": "1.171.37",
18
18
  "files": ["Scripts.tsx", "link.tsx"],
19
19
  "adaptation": "Native body-script composition and positional search equality are ported from the matching router-core release. The owned binding retains Solid 2 RC.13 JSX, NoHydration, keyed public match transfer and its module-keyed client-assets resolver."
20
20
  }
@@ -67,7 +67,7 @@
67
67
  "utils.ts": "a398c76ac378efe6f8b9aa859a5335d4f07cc692a31754fa93c8bf3e5df0b6ff"
68
68
  },
69
69
  "localChanges": [
70
- "The public router surface omits InjectedHtmlEntry, isPlainArray and isPlainObject, which router-core 1.171.34 no longer exports. SSR options use the current top-level serializationAdapters contract and the public Solid 2 option types without legacy fallbacks or type assertions.",
70
+ "The public router surface omits InjectedHtmlEntry, isPlainArray and isPlainObject, which router-core 1.171.37 no longer exports. Managed SSR uses immutable public route data and native Solid 2 promise serialization. Custom serializationAdapters are unsupported and rejected before router construction or document commitment; the local public option types do not admit them.",
71
71
  "Authored JSX types import @solidjs/web and have explicit return annotations for Solid 2 declaration generation.",
72
72
  "Hydration state and keyed match transfer use Solid 2 RC.13 public isHydrating, isHydratable, getHydrationWriter and takeHydrationValue APIs.",
73
73
  "Explicit public beforeLoad results transfer after canonical validation; private request context stays in owner closures. Initial hydration inherits checked server beforeLoad contributions, invokes the native client route-context callback and preserves client options context without rerunning initial beforeLoad callbacks or loaders.",
@@ -83,7 +83,7 @@
83
83
  ],
84
84
  "nativeProtocolLimitations": [
85
85
  {
86
- "runtime": "@solidjs/web@2.0.0-rc.13 with Seroval 1.6.8",
86
+ "runtime": "@solidjs/web@2.0.0-rc.15 with Seroval 1.6.8",
87
87
  "trigger": "Direct native writer injection of a rejected whole-match Promise before the client binding loads",
88
88
  "observed": "Native inline resolver scripts reject registry Promises without a rejection handler; browser page errors occur before router construction. Binding claims cannot retroactively handle those errors.",
89
89
  "supportedProducer": "The maintained match producer writes only settled synchronous records and excludes pending matches. Critical public-data failures are rejected before headers; unsupported deferred values fail the owning session and abort native serialization.",
@@ -1,18 +1,16 @@
1
1
  import type { JSX } from '@solidjs/web';
2
- import type {
3
- AnyRouter,
4
- RegisteredRouter,
5
- RouterOptions,
6
- } from '@tanstack/router-core';
2
+ import type { AnyRouter, RegisteredRouter } from '@tanstack/router-core';
7
3
  import { isServer } from '@tanstack/router-core/isServer';
8
4
  import * as Solid from 'solid-js';
9
5
  import { setupFlightDataConsumer } from './flightData';
10
6
  import { Matches } from './Matches';
11
7
  import {
8
+ assertNativeSerializationOptions,
12
9
  requireManagedPublicRouter,
13
10
  serializeMatchTransfer,
14
11
  } from './registryTransfer';
15
12
  import { routerContext } from './routerContext';
13
+ import type { RouterOptions } from './routerOptions';
16
14
  import { SafeFragment } from './SafeFragment';
17
15
 
18
16
  const RouterContext = routerContext as unknown as Solid.Component<{
@@ -30,6 +28,7 @@ export function RouterContextProvider<
30
28
  }: RouterProps<TRouter, TDehydrated> & {
31
29
  children: () => JSX.Element;
32
30
  }) {
31
+ assertNativeSerializationOptions(rest);
33
32
  requireManagedPublicRouter(router);
34
33
  if (Object.keys(rest).length > 0) {
35
34
  Solid.runWithOwner(null, () => {
@@ -162,9 +162,14 @@ export function Rendered() {
162
162
  Solid.onSettled(() => {
163
163
  const resolvedLocation = getResolvedLocation(router);
164
164
  if (resolvedLocation) {
165
+ const { fromLocation, ...changeInfo } = getLocationChangeInfo(
166
+ resolvedLocation,
167
+ resolvedLocation,
168
+ );
165
169
  router.emit({
166
170
  type: 'onRendered',
167
- ...getLocationChangeInfo(resolvedLocation, resolvedLocation),
171
+ ...changeInfo,
172
+ ...(fromLocation !== undefined ? { fromLocation } : {}),
168
173
  });
169
174
  }
170
175
  });
@@ -69,7 +69,7 @@ export class FileRoute<
69
69
  public path?: TFilePath,
70
70
  _opts?: { silent: boolean },
71
71
  ) {
72
- this.silent = _opts?.silent;
72
+ if (_opts) this.silent = _opts.silent;
73
73
  }
74
74
 
75
75
  createRoute = <
@@ -154,7 +154,9 @@ export const useTags = (assetCrossOrigin?: AssetCrossOriginConfig) => {
154
154
  ...manifest.inlineStyle.attrs,
155
155
  nonce,
156
156
  },
157
- children: manifest.inlineStyle.children,
157
+ ...(manifest.inlineStyle.children !== undefined
158
+ ? { children: manifest.inlineStyle.children }
159
+ : {}),
158
160
  inlineCss: true,
159
161
  });
160
162
  }
@@ -192,7 +194,7 @@ export const useTags = (assetCrossOrigin?: AssetCrossOriginConfig) => {
192
194
  ...attrs,
193
195
  nonce,
194
196
  },
195
- children: children as string | undefined,
197
+ ...(children != null ? { children: String(children) } : {}),
196
198
  })) satisfies Array<RouterManagedTag>;
197
199
  });
198
200
 
@@ -206,7 +208,7 @@ export const useTags = (assetCrossOrigin?: AssetCrossOriginConfig) => {
206
208
  ...attrs,
207
209
  nonce,
208
210
  },
209
- children: children as string | undefined,
211
+ ...(children != null ? { children: String(children) } : {}),
210
212
  })) satisfies Array<RouterManagedTag>;
211
213
  });
212
214
 
@@ -26,7 +26,6 @@ export type {
26
26
  AnyRouterWithContext,
27
27
  AnyRouteWithContext,
28
28
  AnySchema,
29
- AnySerializationAdapter,
30
29
  AnyValidator,
31
30
  AnyValidatorAdapter,
32
31
  AnyValidatorFn,
@@ -153,7 +152,6 @@ export type {
153
152
  RouterEvents,
154
153
  RouterListener,
155
154
  RouterManagedTag,
156
- RouterOptions,
157
155
  RouterState,
158
156
  RoutesById,
159
157
  RoutesByPath,
@@ -163,7 +161,6 @@ export type {
163
161
  SearchSchemaInput,
164
162
  SearchSerializer,
165
163
  SerializableExtensions,
166
- SerializationAdapter,
167
164
  StaticDataRouteOption,
168
165
  StringifyParamsFn,
169
166
  ToMaskOptions,
@@ -197,7 +194,6 @@ export {
197
194
  cleanPath,
198
195
  composeRewrites,
199
196
  createControlledPromise,
200
- createSerializationAdapter,
201
197
  DEFAULT_PROTOCOL_ALLOWLIST,
202
198
  deepEqual,
203
199
  defaultParseSearch,
@@ -291,6 +287,7 @@ export {
291
287
  rootRouteWithContext,
292
288
  } from './route';
293
289
  export { createRouter, Router } from './router';
290
+ export type { RouterOptions } from './routerOptions';
294
291
  export { ScriptOnce } from './ScriptOnce';
295
292
  export { Scripts } from './Scripts';
296
293
  export {
@@ -505,9 +505,9 @@ export function useLinkProps<
505
505
  }
506
506
 
507
507
  const defineGetters = (getters: Record<string, () => any>) => {
508
- for (const key of Object.keys(getters)) {
508
+ for (const [key, get] of Object.entries(getters)) {
509
509
  Object.defineProperty(linkProps, key, {
510
- get: getters[key],
510
+ get,
511
511
  enumerable: true,
512
512
  configurable: true,
513
513
  });
@@ -78,8 +78,21 @@ export function registerPublicRouteDataOwner(
78
78
  });
79
79
  }
80
80
 
81
+ /** Managed match transfer uses the immutable public-data contract, not custom adapters. */
82
+ export function assertNativeSerializationOptions(options: object): void {
83
+ if ('serializationAdapters' in options) {
84
+ const error = new DataProtocolError(
85
+ 'Solid serializationAdapters are unsupported by the immutable public-data profile; return public records, arrays and scalars instead',
86
+ );
87
+ const owner: RequestSession | undefined = getRequestEvent()?.locals.session;
88
+ owner?.fail(error);
89
+ throw error;
90
+ }
91
+ }
92
+
81
93
  /** Framework SSR accepts only routers that passed its public-data factory boundary. */
82
94
  export function requireManagedPublicRouter(router: AnyRouter): void {
95
+ assertNativeSerializationOptions(router.options);
83
96
  const owner: RequestSession | undefined = getRequestEvent()?.locals.session;
84
97
  if (
85
98
  !owner ||
@@ -268,6 +281,11 @@ export function primeRouterFromRegistry(router: AnyRouter): boolean {
268
281
  try {
269
282
  for (const [index, match] of matches.entries()) {
270
283
  const entry = entries[index]!;
284
+ const beforeLoadContext = preparePublicContextData(
285
+ entry.beforeLoadContext,
286
+ owner,
287
+ privateContexts,
288
+ ) as Record<string, unknown> | undefined;
271
289
  const checked: TransferredMatch = {
272
290
  ...entry,
273
291
  loaderData: prepareHydratedLoaderData(
@@ -275,11 +293,7 @@ export function primeRouterFromRegistry(router: AnyRouter): boolean {
275
293
  owner,
276
294
  privateContexts,
277
295
  ),
278
- beforeLoadContext: preparePublicContextData(
279
- entry.beforeLoadContext,
280
- owner,
281
- privateContexts,
282
- ) as Record<string, unknown> | undefined,
296
+ ...(beforeLoadContext !== undefined ? { beforeLoadContext } : {}),
283
297
  error: preparePublicContextData(entry.error, owner, privateContexts),
284
298
  };
285
299
  entries[index] = checked;
@@ -356,7 +370,10 @@ function applyTransferredMatch(
356
370
  __beforeLoadContext: entry.beforeLoadContext,
357
371
  } as AnyRouteMatch;
358
372
  if ('loaderData' in entry) next.loaderData = entry.loaderData;
359
- if ('ssr' in entry) next.ssr = entry.ssr;
373
+ if ('ssr' in entry) {
374
+ if (entry.ssr === undefined) delete next.ssr;
375
+ else next.ssr = entry.ssr;
376
+ }
360
377
  return next;
361
378
  }
362
379
 
@@ -133,7 +133,7 @@ export class RouteApi<
133
133
  return useNavigate({ from: router.routesById[this.id as string].fullPath });
134
134
  };
135
135
 
136
- notFound = (opts?: NotFoundError) => {
136
+ override notFound = (opts?: NotFoundError) => {
137
137
  return notFound({ routeId: this.id as string, ...opts });
138
138
  };
139
139
 
@@ -9,6 +9,7 @@ import type {
9
9
  import { RouterCore } from '@tanstack/router-core';
10
10
  import { isServer } from '@tanstack/router-core/isServer';
11
11
  import {
12
+ assertNativeSerializationOptions,
12
13
  installPublicContextPublication,
13
14
  primeRouterFromRegistry,
14
15
  } from './registryTransfer';
@@ -104,6 +105,7 @@ export class Router<
104
105
  TDehydrated
105
106
  >,
106
107
  ) {
108
+ assertNativeSerializationOptions(options);
107
109
  super(options, getStoreFactory);
108
110
  installPublicContextPublication(this);
109
111
  // The hydration-claiming boot (see registryTransfer). Router creation is