@bleedingdev/modern-js-renderer-solid 3.9.3-ultramodern.1 → 3.9.3-ultramodern.10

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 (99) 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/create.js +22 -21
  37. package/dist/esm-node/plugin/index.js +1 -4
  38. package/dist/esm-node/plugin/profile.js +10 -11
  39. package/dist/esm-node/route-completion.js +2 -1
  40. package/dist/esm-node/router-binding/Asset.js +3 -2
  41. package/dist/esm-node/router-binding/CatchBoundary.js +3 -3
  42. package/dist/esm-node/router-binding/Matches.js +30 -30
  43. package/dist/esm-node/router-binding/PROVENANCE.json +3 -3
  44. package/dist/esm-node/router-binding/RouterProvider.js +2 -1
  45. package/dist/esm-node/router-binding/Transitioner.js +10 -4
  46. package/dist/esm-node/router-binding/fileRoute.js +1 -1
  47. package/dist/esm-node/router-binding/headContentUtils.js +9 -3
  48. package/dist/esm-node/router-binding/index.js +1 -1
  49. package/dist/esm-node/router-binding/link.js +2 -2
  50. package/dist/esm-node/router-binding/registryTransfer.js +16 -3
  51. package/dist/esm-node/router-binding/router.js +2 -1
  52. package/dist/esm-node/router-binding/routerOptions.js +1 -0
  53. package/dist/esm-node/router-binding/useLoaderData.js +1 -2
  54. package/dist/esm-node/router-binding/useNavigate.js +8 -2
  55. package/dist/esm-node/router-binding/useParams.js +1 -3
  56. package/dist/esm-node/router-binding/useSearch.js +1 -3
  57. package/dist/types/federation-ssr.d.ts +3 -5
  58. package/dist/types/i18n/LocalizedLink.d.ts +5 -33
  59. package/dist/types/i18n/index.d.ts +1 -1
  60. package/dist/types/index.d.ts +5 -5
  61. package/dist/types/manifest.d.ts +1 -1
  62. package/dist/types/router-binding/RouterProvider.d.ts +2 -1
  63. package/dist/types/router-binding/index.d.ts +3 -2
  64. package/dist/types/router-binding/registryTransfer.d.ts +2 -0
  65. package/dist/types/router-binding/routerOptions.d.ts +6 -0
  66. package/dist/types/router.d.ts +3 -3
  67. package/package.json +29 -22
  68. package/src/actions.tsx +5 -1
  69. package/src/application-router.tsx +9 -3
  70. package/src/entry-client.tsx +1 -0
  71. package/src/federation-ssr.ts +32 -13
  72. package/src/federation.tsx +9 -5
  73. package/src/i18n/LocalizedLink.tsx +44 -83
  74. package/src/i18n/index.ts +1 -5
  75. package/src/index.ts +5 -5
  76. package/src/manifest.ts +1 -1
  77. package/src/plugin/create.ts +22 -21
  78. package/src/plugin/index.ts +0 -3
  79. package/src/plugin/preserve-import-loader.cjs +1 -1
  80. package/src/plugin/profile.ts +10 -10
  81. package/src/route-completion.tsx +5 -1
  82. package/src/router-binding/Asset.tsx +10 -9
  83. package/src/router-binding/Matches.tsx +10 -10
  84. package/src/router-binding/PROVENANCE.json +3 -3
  85. package/src/router-binding/RouterProvider.tsx +4 -5
  86. package/src/router-binding/Transitioner.tsx +6 -1
  87. package/src/router-binding/fileRoute.ts +1 -1
  88. package/src/router-binding/headContentUtils.tsx +5 -3
  89. package/src/router-binding/index.tsx +1 -4
  90. package/src/router-binding/link.tsx +2 -2
  91. package/src/router-binding/registryTransfer.ts +23 -6
  92. package/src/router-binding/route.tsx +1 -1
  93. package/src/router-binding/router.ts +2 -0
  94. package/src/router-binding/routerOptions.ts +26 -0
  95. package/src/router-binding/useLoaderData.tsx +4 -3
  96. package/src/router-binding/useNavigate.tsx +5 -3
  97. package/src/router-binding/useParams.tsx +1 -3
  98. package/src/router-binding/useSearch.tsx +1 -3
  99. package/src/router.ts +3 -3
@@ -2,7 +2,7 @@ import { mergeProps } from "@solidjs/web";
2
2
  import { isServer } from "@tanstack/router-core/isServer";
3
3
  import { setupFlightDataConsumer } from "./flightData.js";
4
4
  import { Matches } from "./Matches.js";
5
- import { requireManagedPublicRouter, serializeMatchTransfer } from "./registryTransfer.js";
5
+ import { assertNativeSerializationOptions, requireManagedPublicRouter, serializeMatchTransfer } from "./registryTransfer.js";
6
6
  import { routerContext } from "./routerContext.js";
7
7
  import { SafeFragment } from "./SafeFragment.js";
8
8
  import * as __rspack_external_solid_js_0ac0db99 from "solid-js";
@@ -61,6 +61,7 @@ function _P$3(_p7, _p8, _p9) {
61
61
  _P$3.prototype = Object.prototype;
62
62
  const RouterContext = routerContext;
63
63
  function RouterContextProvider({ router, children, ...rest }) {
64
+ assertNativeSerializationOptions(rest);
64
65
  requireManagedPublicRouter(router);
65
66
  if (Object.keys(rest).length > 0) __rspack_external_solid_js_0ac0db99.runWithOwner(null, ()=>{
66
67
  router.update({
@@ -93,10 +93,16 @@ function Rendered() {
93
93
  const router = useRouter();
94
94
  __rspack_external_solid_js_0ac0db99.onSettled(()=>{
95
95
  const resolvedLocation = getResolvedLocation(router);
96
- if (resolvedLocation) router.emit({
97
- type: "onRendered",
98
- ...getLocationChangeInfo(resolvedLocation, resolvedLocation)
99
- });
96
+ if (resolvedLocation) {
97
+ const { fromLocation, ...changeInfo } = getLocationChangeInfo(resolvedLocation, resolvedLocation);
98
+ router.emit({
99
+ type: "onRendered",
100
+ ...changeInfo,
101
+ ...void 0 !== fromLocation ? {
102
+ fromLocation
103
+ } : {}
104
+ });
105
+ }
100
106
  });
101
107
  return null;
102
108
  }
@@ -25,7 +25,7 @@ class FileRoute {
25
25
  route.isRoot = false;
26
26
  return route;
27
27
  };
28
- this.silent = _opts?.silent;
28
+ if (_opts) this.silent = _opts.silent;
29
29
  }
30
30
  }
31
31
  function FileRouteLoader(_path) {
@@ -91,7 +91,9 @@ const useTags = (assetCrossOrigin)=>{
91
91
  ...manifest.inlineStyle.attrs,
92
92
  nonce
93
93
  },
94
- children: manifest.inlineStyle.children,
94
+ ...void 0 !== manifest.inlineStyle.children ? {
95
+ children: manifest.inlineStyle.children
96
+ } : {},
95
97
  inlineCss: true
96
98
  });
97
99
  return tags;
@@ -114,7 +116,9 @@ const useTags = (assetCrossOrigin)=>{
114
116
  ...attrs,
115
117
  nonce
116
118
  },
117
- children: children
119
+ ...null != children ? {
120
+ children: String(children)
121
+ } : {}
118
122
  })));
119
123
  const headScripts = __rspack_external_solid_js_0ac0db99.createMemo(()=>activeMatches().flatMap((match)=>match.headScripts ?? []).filter((script)=>void 0 !== script).map(({ children, ...attrs })=>({
120
124
  tag: "script",
@@ -122,7 +126,9 @@ const useTags = (assetCrossOrigin)=>{
122
126
  ...attrs,
123
127
  nonce
124
128
  },
125
- children: children
129
+ ...null != children ? {
130
+ children: String(children)
131
+ } : {}
126
132
  })));
127
133
  return __rspack_external_solid_js_0ac0db99.createMemo(()=>{
128
134
  const next = [];
@@ -1,6 +1,6 @@
1
1
  export * from "./history.js";
2
2
  export { createBrowserHistory, createHashHistory, createHistory, createMemoryHistory } from "@tanstack/history";
3
- export { DEFAULT_PROTOCOL_ALLOWLIST, SearchParamError, cleanPath, composeRewrites, createControlledPromise, createSerializationAdapter, deepEqual, defaultParseSearch, defaultStringifySearch, defer, functionalUpdate, interpolatePath, isMatch, isNotFound, isRedirect, joinPaths, lazyFn, notFound, parseSearchWith, redirect, replaceEqualDeep, resolvePath, retainSearchParams, rootRouteId, stringifySearchWith, stripSearchParams, trimPath, trimPathLeft, trimPathRight } from "@tanstack/router-core";
3
+ export { DEFAULT_PROTOCOL_ALLOWLIST, SearchParamError, cleanPath, composeRewrites, createControlledPromise, deepEqual, defaultParseSearch, defaultStringifySearch, defer, functionalUpdate, interpolatePath, isMatch, isNotFound, isRedirect, joinPaths, lazyFn, notFound, parseSearchWith, redirect, replaceEqualDeep, resolvePath, retainSearchParams, rootRouteId, stringifySearchWith, stripSearchParams, trimPath, trimPathLeft, trimPathRight } from "@tanstack/router-core";
4
4
  export { Asset } from "./Asset.js";
5
5
  export { Await, useAwaited } from "./awaited.js";
6
6
  export { CatchBoundary, ErrorComponent } from "./CatchBoundary.js";
@@ -267,8 +267,8 @@ function useLinkProps(options) {
267
267
  configurable: true
268
268
  });
269
269
  const defineGetters = (getters)=>{
270
- for (const key of Object.keys(getters))Object.defineProperty(linkProps, key, {
271
- get: getters[key],
270
+ for (const [key, get] of Object.entries(getters))Object.defineProperty(linkProps, key, {
271
+ get,
272
272
  enumerable: true,
273
273
  configurable: true
274
274
  });
@@ -12,7 +12,16 @@ function registerPublicRouteDataOwner(routeTree, owner, privateContexts = []) {
12
12
  privateContexts: privateContexts.map((value)=>new WeakRef(value))
13
13
  });
14
14
  }
15
+ function assertNativeSerializationOptions(options) {
16
+ if ("serializationAdapters" in options) {
17
+ const error = new DataProtocolError("Solid serializationAdapters are unsupported by the immutable public-data profile; return public records, arrays and scalars instead");
18
+ const owner = getRequestEvent()?.locals.session;
19
+ owner?.fail(error);
20
+ throw error;
21
+ }
22
+ }
15
23
  function requireManagedPublicRouter(router) {
24
+ assertNativeSerializationOptions(router.options);
16
25
  const owner = getRequestEvent()?.locals.session;
17
26
  if (!owner || publicRouteDataOwners.get(router.options.routeTree)?.owner.deref()) return;
18
27
  const error = new DataProtocolError("Custom native Solid routers are unsupported by UltraModern SSR. Use the managed filesystem route tree and application router public-data boundary.");
@@ -129,10 +138,13 @@ function primeRouterFromRegistry(router) {
129
138
  try {
130
139
  for (const [index, match] of matches.entries()){
131
140
  const entry = entries[index];
141
+ const beforeLoadContext = preparePublicContextData(entry.beforeLoadContext, owner, privateContexts);
132
142
  const checked = {
133
143
  ...entry,
134
144
  loaderData: prepareHydratedLoaderData(entry.loaderData, owner, privateContexts),
135
- beforeLoadContext: preparePublicContextData(entry.beforeLoadContext, owner, privateContexts),
145
+ ...void 0 !== beforeLoadContext ? {
146
+ beforeLoadContext
147
+ } : {},
136
148
  error: preparePublicContextData(entry.error, owner, privateContexts)
137
149
  };
138
150
  entries[index] = checked;
@@ -196,7 +208,8 @@ function applyTransferredMatch(match, entry) {
196
208
  __beforeLoadContext: entry.beforeLoadContext
197
209
  };
198
210
  if ("loaderData" in entry) next.loaderData = entry.loaderData;
199
- if ("ssr" in entry) next.ssr = entry.ssr;
211
+ if ("ssr" in entry) if (void 0 === entry.ssr) delete next.ssr;
212
+ else next.ssr = entry.ssr;
200
213
  return next;
201
214
  }
202
215
  function isRouteDataErrorSnapshot(value) {
@@ -207,4 +220,4 @@ function nativeContextField(match, key) {
207
220
  if (descriptor?.get || descriptor?.set) throw new DataProtocolError("Native route context must not contain accessor fields");
208
221
  return descriptor?.value;
209
222
  }
210
- export { MATCH_KEY_PREFIX, installPublicContextPublication, prepareRouterMatchTransfer, primeRouterFromRegistry, registerPublicRouteDataOwner, requireManagedPublicRouter, serializeMatchTransfer };
223
+ export { MATCH_KEY_PREFIX, assertNativeSerializationOptions, installPublicContextPublication, prepareRouterMatchTransfer, primeRouterFromRegistry, registerPublicRouteDataOwner, requireManagedPublicRouter, serializeMatchTransfer };
@@ -1,10 +1,11 @@
1
1
  import { RouterCore } from "@tanstack/router-core";
2
2
  import { isServer } from "@tanstack/router-core/isServer";
3
- import { installPublicContextPublication, primeRouterFromRegistry } from "./registryTransfer.js";
3
+ import { assertNativeSerializationOptions, installPublicContextPublication, primeRouterFromRegistry } from "./registryTransfer.js";
4
4
  import { getStoreFactory } from "./routerStores.js";
5
5
  const createRouter = (options)=>new Router(options);
6
6
  class Router extends RouterCore {
7
7
  constructor(options){
8
+ assertNativeSerializationOptions(options);
8
9
  super(options, getStoreFactory);
9
10
  installPublicContextPublication(this);
10
11
  if (!(isServer ?? this.isServer)) primeRouterFromRegistry(this);
@@ -0,0 +1 @@
1
+ export { };
@@ -1,8 +1,7 @@
1
1
  import { useMatch } from "./useMatch.js";
2
2
  function useLoaderData(opts) {
3
3
  return useMatch({
4
- from: opts.from,
5
- strict: opts.strict,
4
+ ...opts,
6
5
  select: (match)=>opts.select ? opts.select(match.loaderData) : match.loaderData
7
6
  });
8
7
  }
@@ -2,10 +2,16 @@ import { useRouter } from "./useRouter.js";
2
2
  import * as __rspack_external_solid_js_0ac0db99 from "solid-js";
3
3
  function useNavigate(_defaultOpts) {
4
4
  const router = useRouter();
5
- return (options)=>router.navigate({
5
+ const navigate = (options)=>{
6
+ const from = options.from ?? _defaultOpts?.from;
7
+ return router.navigate({
6
8
  ...options,
7
- from: options.from ?? _defaultOpts?.from
9
+ ...void 0 === from ? {} : {
10
+ from
11
+ }
8
12
  });
13
+ };
14
+ return navigate;
9
15
  }
10
16
  function Navigate(props) {
11
17
  const { navigate } = useRouter();
@@ -1,9 +1,7 @@
1
1
  import { useMatch } from "./useMatch.js";
2
2
  function useParams(opts) {
3
3
  return useMatch({
4
- from: opts.from,
5
- strict: opts.strict,
6
- shouldThrow: opts.shouldThrow,
4
+ ...opts,
7
5
  select: (match)=>{
8
6
  const params = false === opts.strict ? match.params : match._strictParams;
9
7
  return opts.select ? opts.select(params) : params;
@@ -1,9 +1,7 @@
1
1
  import { useMatch } from "./useMatch.js";
2
2
  function useSearch(opts) {
3
3
  return useMatch({
4
- from: opts.from,
5
- strict: opts.strict,
6
- shouldThrow: opts.shouldThrow,
4
+ ...opts,
7
5
  select: (match)=>{
8
6
  const search = match.search;
9
7
  return opts.select ? opts.select(search) : search;
@@ -1,3 +1,4 @@
1
+ import type { FederatedAssets } from '@modern-js/renderer-core/federation';
1
2
  import type { SolidFederationScope } from './federation-context.js';
2
3
  /**
3
4
  * The server half of same-renderer Module Federation. federatedComponent()
@@ -6,11 +7,8 @@ import type { SolidFederationScope } from './federation-context.js';
6
7
  */
7
8
  /** Asset keys for server-rendered remotes, e.g. `ultramodern-federation:remote/Widget`. */
8
9
  export declare const FEDERATED_ASSET_PREFIX = "ultramodern-federation:";
9
- /** The host's server state for a remote: its browser assets and hydration module. */
10
- export declare function federatedServerAssets(scope: SolidFederationScope | undefined, id: string): {
11
- hydration: string;
12
- assets: import("@modern-js/renderer-core/federation").FederatedAssets;
13
- } | undefined;
10
+ /** Retain the assets admitted with this module until its response resolves them. */
11
+ export declare function captureFederatedServerAssets(scope: SolidFederationScope, id: string, assets: FederatedAssets | undefined): string | undefined;
14
12
  export declare function federatedAssetKey(id: string): string;
15
13
  /**
16
14
  * Extend a static Solid asset manifest with the remotes this response
@@ -1,43 +1,15 @@
1
1
  import type { JSX } from '@solidjs/web';
2
- import { type LinkComponentProps } from '../router.js';
3
- export interface LocalizedLinkProps {
2
+ import { type AnyRouter, type LinkComponentProps } from '../router.js';
3
+ export interface LocalizedLinkProps extends Omit<LinkComponentProps<'a', AnyRouter, string, string>, 'to' | 'mask' | 'href' | 'publicHref' | '_fromLocation'> {
4
4
  /** A canonical, language-agnostic target, e.g. `/products/red-shoe`. */
5
5
  to: string;
6
6
  /** Localize for a specific language instead of the current one. */
7
7
  language?: string;
8
- children?: LinkComponentProps<'a'>['children'];
9
- class?: string;
10
- activeProps?: LinkComponentProps<'a'>['activeProps'];
11
- inactiveProps?: LinkComponentProps<'a'>['inactiveProps'];
12
- activeOptions?: LinkComponentProps<'a'>['activeOptions'];
13
- replace?: boolean;
14
- preload?: LinkComponentProps<'a'>['preload'];
15
8
  [key: `data-${string}`]: unknown;
16
9
  }
17
10
  /**
18
- * A thin wrapper over the native Solid router `Link` that localizes a
19
- * canonical `to` for the current (or an explicit) language before handing it
20
- * to the real link, the same contract as `@modern-js/plugin-i18n`'s React
21
- * `Link`. It resolves the href itself via the shared pathname helpers, so it
22
- * works with or without the router's i18n `rewrite`. Every link, including
23
- * one to another language, is the native `Link`: navigation, preloading and
24
- * active state stay with the router.
25
- *
26
- * Under the i18n `rewrite` the router matches canonical paths and localizes
27
- * outgoing locations to the current language, so a link to another language
28
- * routes to the canonical `to` and publishes the target language's URL as a
29
- * route mask (the rewrite keeps a mask's explicit language). The entry's
30
- * router language synchronization (`syncWithRouter`) switches the i18next
31
- * instance from the navigated URL, as it does for history navigation.
32
- *
33
- * Props are forwarded explicitly (not via object-rest or a missing
34
- * `splitProps`/`mergeProps` primitive — Solid 2 only exports `merge`) so
35
- * each one is read directly from `props` in JSX position and keeps its
36
- * per-key reactivity.
11
+ * The native router owns navigation, preloading and active state. A route mask
12
+ * publishes the selected language URL while keeping the canonical route;
13
+ * the entry's router subscription synchronizes the i18next instance.
37
14
  */
38
15
  export declare function LocalizedLink(props: LocalizedLinkProps): JSX.Element;
39
- /**
40
- * Language-invariant active check: `to="/products"` is active whether the
41
- * current location is `/en/products` or `/produkty` under a mapped locale.
42
- */
43
- export declare function useIsLocalizedActive(canonicalTarget: string): () => boolean;
@@ -3,7 +3,7 @@ export { createI18nSsrHandoffInlineData, I18N_SSR_HANDOFF_ELEMENT_ID, type I18nS
3
3
  export { type CreateI18nUrlRewriteOptions, createI18nUrlRewrite, type I18nLocationRewrite, } from '@modern-js/i18n-runtime-extensions/urlRewrite';
4
4
  export { I18nContext } from './context.js';
5
5
  export { I18nProvider, type I18nProviderProps } from './I18nProvider.js';
6
- export { LocalizedLink, type LocalizedLinkProps, useIsLocalizedActive, } from './LocalizedLink.js';
6
+ export { LocalizedLink, type LocalizedLinkProps } from './LocalizedLink.js';
7
7
  export { createLatestLanguageSync, type SolidLatestLanguageSyncOptions, } from './languageSync.js';
8
8
  export type { I18nContextValue, I18nInstanceLike } from './types.js';
9
9
  export { type UseI18nReturn, useI18n } from './useI18n.js';
@@ -1,12 +1,12 @@
1
1
  /** This entry contains identity only. Select client, router or server explicitly. */
2
2
  export declare const SOLID_RENDERER_PROFILE: {
3
3
  readonly renderer: 'solid';
4
- readonly solid: '2.0.0-rc.13';
5
- readonly web: '2.0.0-rc.13';
4
+ readonly solid: '2.0.0-rc.15';
5
+ readonly web: '2.0.0-rc.15';
6
6
  readonly router: '@modern-js/renderer-solid/router@3.8.3';
7
7
  readonly routerSource: '4fbd65c5c3b40be87a6248867c22021c1c19bba8';
8
- readonly routerCore: '1.171.34';
9
- readonly history: '1.162.4';
8
+ readonly routerCore: '1.171.38';
9
+ readonly history: '1.162.5';
10
10
  readonly publicRouteData: {
11
11
  readonly containers: readonly ['plain-record', 'null-record', 'array'];
12
12
  readonly values: 'canonical-scalars';
@@ -19,7 +19,7 @@ export declare const SOLID_RENDERER_PROFILE: {
19
19
  readonly providerOverrides: 'unsupported';
20
20
  };
21
21
  readonly nativePromiseMetadata: {
22
- readonly runtime: '2.0.0-rc.13';
22
+ readonly runtime: '2.0.0-rc.15';
23
23
  readonly fields: readonly ['s', 'v'];
24
24
  readonly status: readonly [0, 1, 2];
25
25
  readonly handle: 'sealed-with-checked-metadata';
@@ -1,6 +1,6 @@
1
1
  import type { NativeCompilerArtifacts } from '@modern-js/renderer-core/adapter';
2
2
  import { type RendererIdentity } from '@modern-js/renderer-core/identity';
3
- export declare const SOLID_COMPILER_VERSION = "2.0.0-rc.13";
3
+ export declare const SOLID_COMPILER_VERSION = "2.0.0-rc.15";
4
4
  export declare function solidModuleManifestFilename(entryName: string): string;
5
5
  /** The compiler's structural JSON boundary matches native Solid AssetManifest. */
6
6
  interface SolidPreloadAttributes {
@@ -1,5 +1,6 @@
1
1
  import type { JSX } from '@solidjs/web';
2
- import type { AnyRouter, RegisteredRouter, RouterOptions } from '@tanstack/router-core';
2
+ import type { AnyRouter, RegisteredRouter } from '@tanstack/router-core';
3
+ import type { RouterOptions } from './routerOptions.js';
3
4
  export declare function RouterContextProvider<TRouter extends AnyRouter = RegisteredRouter, TDehydrated extends Record<string, any> = Record<string, any>>({ router, children, ...rest }: RouterProps<TRouter, TDehydrated> & {
4
5
  children: () => JSX.Element;
5
6
  }): JSX.Element;
@@ -1,7 +1,7 @@
1
1
  export type { BlockerFn, HistoryLocation, HistoryState, ParsedPath, RouterHistory, } from '@tanstack/history';
2
2
  export { createBrowserHistory, createHashHistory, createHistory, createMemoryHistory, } from '@tanstack/history';
3
- export type { AbsoluteToPath, ActiveOptions, AllContext, AllLoaderData, AllParams, AnyContext, AnyPathParams, AnyRedirect, AnyRoute, AnyRouteMatch, AnyRouter, AnyRouterWithContext, AnyRouteWithContext, AnySchema, AnySerializationAdapter, AnyValidator, AnyValidatorAdapter, AnyValidatorFn, AnyValidatorObj, Assign, BaseRouteOptions, BeforeLoadContextOptions, BeforeLoadContextParameter, BuildLocationFn, BuildNextOptions, CommitLocationOptions, Constrain, ContextAsyncReturnType, ContextOptions, ContextReturnType, ControllablePromise, ControlledPromise, CreateFileRoute, CreateLazyFileRoute, DefaultValidator, DeferredPromise, DeferredPromiseState, ErrorComponentProps, ErrorRouteProps, Expand, FileBaseRouteOptions, FileRoutesByPath, FileRouteTypes, FullSearchSchema, FullSearchSchemaInput, FullSearchSchemaOption, InferAllContext, InferAllParams, InferDescendantToPaths, InferFrom, InferFullSearchSchema, InferFullSearchSchemaInput, InferMaskFrom, InferMaskTo, InferSelected, InferShouldThrow, InferStrict, InferTo, IntersectAssign, LazyRouteOptions, LinkOptions, ListenerFn, LoaderFnContext, LocationRewrite, LocationRewriteFunction, LooseAsyncReturnType, LooseReturnType, MakeOptionalPathParams, MakeRemountDepsOptionsUnion, MakeRouteMatch, MakeRouteMatchUnion, Manifest, MatchLocation, MatchRouteOptions, MergeAll, MetaDescriptor, NavigateFn, NavigateOptions, NotFoundError, NotFoundRouteProps, ParamsOptions, ParsedLocation, ParseParamsFn, ParseRoute, PathParamOptions, PreloadableObj, Redirect, RedirectOptions, Register, RegisteredRouter, RelativeToCurrentPath, RelativeToParentPath, RelativeToPath, RelativeToPathAutoComplete, RemountDepsOptions, RemoveLeadingSlashes, RemoveTrailingSlashes, ResolveAllContext, ResolveAllParamsFromParent, ResolvedRedirect, ResolveFullPath, ResolveFullSearchSchema, ResolveFullSearchSchemaInput, ResolveId, ResolveLoaderData, ResolveOptionalParams, ResolveParams, ResolveRelativePath, ResolveRequiredParams, ResolveRoute, ResolveRouteContext, ResolveSearchValidatorInput, ResolveSearchValidatorInputFn, ResolveValidatorInput, ResolveValidatorInputFn, ResolveValidatorOutput, ResolveValidatorOutputFn, RootRouteId, RootRouteOptions, RouteById, RouteByPath, RouteConstraints, RouteContext, RouteContextFn, RouteContextOptions, RouteContextParameter, RouteIds, RouteLinkEntry, RouteLoaderFn, RouteMask, RouteMatch, RouteOptions, RoutePathOptions, RoutePathOptionsIntersection, RoutePaths, RouterConstructorOptions, RouterContextOptions, RouterEvent, RouterEvents, RouterListener, RouterManagedTag, RouterOptions, RouterState, RoutesById, RoutesByPath, SearchFilter, SearchParamOptions, SearchParser, SearchSchemaInput, SearchSerializer, SerializableExtensions, SerializationAdapter, StaticDataRouteOption, StringifyParamsFn, ToMaskOptions, ToOptions, ToPathOption, ToSubOptions, TrailingSlashOption, TrimPath, TrimPathLeft, TrimPathRight, UpdatableRouteOptions, UpdatableStaticRouteOption, UseNavigateResult, ValidateFromPath, ValidateId, ValidateNavigateOptions, ValidateNavigateOptionsArray, ValidateParams, ValidateRedirectOptions, ValidateRedirectOptionsArray, ValidateSearch, ValidateToPath, ValidateUseParamsResult, ValidateUseSearchResult, Validator, ValidatorAdapter, ValidatorFn, ValidatorObj, } from '@tanstack/router-core';
4
- export { cleanPath, composeRewrites, createControlledPromise, createSerializationAdapter, DEFAULT_PROTOCOL_ALLOWLIST, deepEqual, defaultParseSearch, defaultStringifySearch, defer, functionalUpdate, interpolatePath, isMatch, isNotFound, isRedirect, joinPaths, lazyFn, notFound, parseSearchWith, redirect, replaceEqualDeep, resolvePath, retainSearchParams, rootRouteId, SearchParamError, stringifySearchWith, stripSearchParams, trimPath, trimPathLeft, trimPathRight, } from '@tanstack/router-core';
3
+ export type { AbsoluteToPath, ActiveOptions, AllContext, AllLoaderData, AllParams, AnyContext, AnyPathParams, AnyRedirect, AnyRoute, AnyRouteMatch, AnyRouter, AnyRouterWithContext, AnyRouteWithContext, AnySchema, AnyValidator, AnyValidatorAdapter, AnyValidatorFn, AnyValidatorObj, Assign, BaseRouteOptions, BeforeLoadContextOptions, BeforeLoadContextParameter, BuildLocationFn, BuildNextOptions, CommitLocationOptions, Constrain, ContextAsyncReturnType, ContextOptions, ContextReturnType, ControllablePromise, ControlledPromise, CreateFileRoute, CreateLazyFileRoute, DefaultValidator, DeferredPromise, DeferredPromiseState, ErrorComponentProps, ErrorRouteProps, Expand, FileBaseRouteOptions, FileRoutesByPath, FileRouteTypes, FullSearchSchema, FullSearchSchemaInput, FullSearchSchemaOption, InferAllContext, InferAllParams, InferDescendantToPaths, InferFrom, InferFullSearchSchema, InferFullSearchSchemaInput, InferMaskFrom, InferMaskTo, InferSelected, InferShouldThrow, InferStrict, InferTo, IntersectAssign, LazyRouteOptions, LinkOptions, ListenerFn, LoaderFnContext, LocationRewrite, LocationRewriteFunction, LooseAsyncReturnType, LooseReturnType, MakeOptionalPathParams, MakeRemountDepsOptionsUnion, MakeRouteMatch, MakeRouteMatchUnion, Manifest, MatchLocation, MatchRouteOptions, MergeAll, MetaDescriptor, NavigateFn, NavigateOptions, NotFoundError, NotFoundRouteProps, ParamsOptions, ParsedLocation, ParseParamsFn, ParseRoute, PathParamOptions, PreloadableObj, Redirect, RedirectOptions, Register, RegisteredRouter, RelativeToCurrentPath, RelativeToParentPath, RelativeToPath, RelativeToPathAutoComplete, RemountDepsOptions, RemoveLeadingSlashes, RemoveTrailingSlashes, ResolveAllContext, ResolveAllParamsFromParent, ResolvedRedirect, ResolveFullPath, ResolveFullSearchSchema, ResolveFullSearchSchemaInput, ResolveId, ResolveLoaderData, ResolveOptionalParams, ResolveParams, ResolveRelativePath, ResolveRequiredParams, ResolveRoute, ResolveRouteContext, ResolveSearchValidatorInput, ResolveSearchValidatorInputFn, ResolveValidatorInput, ResolveValidatorInputFn, ResolveValidatorOutput, ResolveValidatorOutputFn, RootRouteId, RootRouteOptions, RouteById, RouteByPath, RouteConstraints, RouteContext, RouteContextFn, RouteContextOptions, RouteContextParameter, RouteIds, RouteLinkEntry, RouteLoaderFn, RouteMask, RouteMatch, RouteOptions, RoutePathOptions, RoutePathOptionsIntersection, RoutePaths, RouterConstructorOptions, RouterContextOptions, RouterEvent, RouterEvents, RouterListener, RouterManagedTag, RouterState, RoutesById, RoutesByPath, SearchFilter, SearchParamOptions, SearchParser, SearchSchemaInput, SearchSerializer, SerializableExtensions, StaticDataRouteOption, StringifyParamsFn, ToMaskOptions, ToOptions, ToPathOption, ToSubOptions, TrailingSlashOption, TrimPath, TrimPathLeft, TrimPathRight, UpdatableRouteOptions, UpdatableStaticRouteOption, UseNavigateResult, ValidateFromPath, ValidateId, ValidateNavigateOptions, ValidateNavigateOptionsArray, ValidateParams, ValidateRedirectOptions, ValidateRedirectOptionsArray, ValidateSearch, ValidateToPath, ValidateUseParamsResult, ValidateUseSearchResult, Validator, ValidatorAdapter, ValidatorFn, ValidatorObj, } from '@tanstack/router-core';
4
+ export { cleanPath, composeRewrites, createControlledPromise, DEFAULT_PROTOCOL_ALLOWLIST, deepEqual, defaultParseSearch, defaultStringifySearch, defer, functionalUpdate, interpolatePath, isMatch, isNotFound, isRedirect, joinPaths, lazyFn, notFound, parseSearchWith, redirect, replaceEqualDeep, resolvePath, retainSearchParams, rootRouteId, SearchParamError, stringifySearchWith, stripSearchParams, trimPath, trimPathLeft, trimPathRight, } from '@tanstack/router-core';
5
5
  export { Asset } from './Asset.js';
6
6
  export type { AwaitOptions } from './awaited.js';
7
7
  export { Await, useAwaited } from './awaited.js';
@@ -26,6 +26,7 @@ export { prepareRouterMatchTransfer } from './registryTransfer.js';
26
26
  export type { AnyRootRoute, AsyncRouteComponent, ErrorRouteComponent, NotFoundRouteComponent, RouteComponent, SolidNode, } from './route.js';
27
27
  export { createRootRoute, createRootRouteWithContext, createRoute, createRouteMask, getRouteApi, NotFoundRoute, RootRoute, Route, RouteApi, rootRouteWithContext, } from './route.js';
28
28
  export { createRouter, Router } from './router.js';
29
+ export type { RouterOptions } from './routerOptions.js';
29
30
  export { ScriptOnce } from './ScriptOnce.js';
30
31
  export { Scripts } from './Scripts.js';
31
32
  export { ScrollRestoration, useElementScrollRestoration, } from './ScrollRestoration.js';
@@ -26,6 +26,8 @@ import { type PublicSnapshotOwner } from './publicMatchData.js';
26
26
  export declare const MATCH_KEY_PREFIX = "tsr:";
27
27
  /** Bind the managed public-data scope before native router construction claims hydration. */
28
28
  export declare function registerPublicRouteDataOwner(routeTree: object, owner: PublicSnapshotOwner, privateContexts?: readonly object[]): void;
29
+ /** Managed match transfer uses the immutable public-data contract, not custom adapters. */
30
+ export declare function assertNativeSerializationOptions(options: object): void;
29
31
  /** Framework SSR accepts only routers that passed its public-data factory boundary. */
30
32
  export declare function requireManagedPublicRouter(router: AnyRouter): void;
31
33
  /** Project composed public context before every native match-store publication. */
@@ -0,0 +1,6 @@
1
+ import type { RouterHistory } from '@tanstack/history';
2
+ import type { AnyRoute, RouterOptions as CoreRouterOptions, TrailingSlashOption } from '@tanstack/router-core';
3
+ /** Native managed hydration transfers immutable public data only. */
4
+ export type RouterOptions<TRouteTree extends AnyRoute, TTrailingSlashOption extends TrailingSlashOption, TDefaultStructuralSharingOption extends boolean = false, TRouterHistory extends RouterHistory = RouterHistory, TDehydrated = undefined> = Omit<CoreRouterOptions<TRouteTree, TTrailingSlashOption, TDefaultStructuralSharingOption, TRouterHistory, TDehydrated>, 'serializationAdapters'> & {
5
+ serializationAdapters?: never;
6
+ };
@@ -14,11 +14,11 @@ export interface FileSystemRouteModule {
14
14
  pendingComponent?: RouteComponent;
15
15
  errorComponent?: ErrorRouteComponent;
16
16
  notFoundComponent?: NotFoundRouteComponent;
17
- head?: AnyRoute['options']['head'];
17
+ head?: NonNullable<AnyRoute['options']['head']>;
18
18
  /** Explicit returned context becomes immutable public native route context. */
19
- beforeLoad?: AnyRoute['options']['beforeLoad'];
19
+ beforeLoad?: NonNullable<AnyRoute['options']['beforeLoad']>;
20
20
  /** Native synchronous context contributions are checked before composition. */
21
- context?: AnyRoute['options']['context'];
21
+ context?: NonNullable<AnyRoute['options']['context']>;
22
22
  validateSearch?: (search: Record<string, unknown>) => Record<string, unknown>;
23
23
  }
24
24
  /** Resolve location through the native router before committing HTTP headers. */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bleedingdev/modern-js-renderer-solid",
3
- "version": "3.9.3-ultramodern.1",
3
+ "version": "3.9.3-ultramodern.10",
4
4
  "description": "UltraModern native Solid 2 application runtime.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -63,25 +63,23 @@
63
63
  "./package.json": "./package.json"
64
64
  },
65
65
  "engines": {
66
- "node": ">=26.10.0"
66
+ "node": ">=26.12.0"
67
67
  },
68
68
  "dependencies": {
69
69
  "@babel/core": "7.29.7",
70
70
  "@jridgewell/remapping": "2.3.5",
71
- "@modern-js/renderer-core": "npm:@bleedingdev/modern-js-renderer-core@3.9.3-ultramodern.1",
72
- "@solidjs/signals": "2.0.0-rc.13",
73
- "@solidjs/web": "2.0.0-rc.13",
74
- "@tanstack/history": "1.162.4",
75
- "@tanstack/router-core": "1.171.34",
71
+ "@modern-js/renderer-core": "npm:@bleedingdev/modern-js-renderer-core@3.9.3-ultramodern.10",
72
+ "@solidjs/signals": "2.0.0-rc.15",
73
+ "@solidjs/web": "2.0.0-rc.15",
74
+ "@tanstack/history": "1.162.5",
76
75
  "isbot": "5.2.2",
77
- "seroval": "1.6.8",
78
- "seroval-plugins": "1.6.8",
79
- "solid-js": "2.0.0-rc.13"
76
+ "solid-js": "2.0.0-rc.15"
80
77
  },
81
78
  "peerDependencies": {
82
- "@modern-js/i18n-runtime-extensions": "3.9.3-ultramodern.1",
83
- "@rsbuild/core": "2.2.11",
84
- "@solidjs/compiler": "2.0.0-rc.13",
79
+ "@modern-js/i18n-runtime-extensions": "3.9.3-ultramodern.10",
80
+ "@rsbuild/core": "2.2.13",
81
+ "@solidjs/compiler": "2.0.0-rc.15",
82
+ "@tanstack/router-core": "1.171.38",
85
83
  "i18next": ">=25.7.4"
86
84
  },
87
85
  "peerDependenciesMeta": {
@@ -99,27 +97,36 @@
99
97
  }
100
98
  },
101
99
  "devDependencies": {
102
- "@modern-js/i18n-runtime-extensions": "npm:@bleedingdev/modern-js-i18n-runtime-extensions@3.9.3-ultramodern.1",
103
- "@modern-js/tsconfig": "npm:@bleedingdev/modern-js-tsconfig@3.9.3-ultramodern.1",
104
- "@rsbuild/core": "2.2.11",
100
+ "@modern-js/i18n-runtime-extensions": "npm:@bleedingdev/modern-js-i18n-runtime-extensions@3.9.3-ultramodern.10",
101
+ "@modern-js/tsconfig": "npm:@bleedingdev/modern-js-tsconfig@3.9.3-ultramodern.10",
102
+ "@rsbuild/core": "2.2.13",
105
103
  "@rslib/core": "1.0.3",
106
104
  "@scripts/rstest-config": "2.66.0",
107
- "@solidjs/compiler": "2.0.0-rc.13",
108
- "@types/node": "^26.6.3"
105
+ "@solidjs/compiler": "2.0.0-rc.15",
106
+ "@tanstack/router-core": "https://github.com/BleedingDev/router/releases/download/ultramodern-router-core-585d3233f7f5/tanstack-router-core-1.171.38.tgz",
107
+ "@types/node": "^26.6.5"
109
108
  },
110
109
  "sideEffects": false,
111
110
  "publishConfig": {
112
111
  "access": "public"
113
112
  },
113
+ "ultramodern": {
114
+ "nativeArtifacts": {
115
+ "@tanstack/router-core": {
116
+ "request": "https://github.com/BleedingDev/router/releases/download/ultramodern-router-core-585d3233f7f5/tanstack-router-core-1.171.38.tgz",
117
+ "version": "1.171.38",
118
+ "integrity": "sha512-d/aGvcyEVwDh2Cn9MuZM1n1dqTIqkFYi7AHY2Na/6x/a0jVSDVTNVVVY7QEsuKFXktaJF9zjVwetaRm/0MALZg=="
119
+ }
120
+ },
121
+ "sourceName": "@modern-js/renderer-solid"
122
+ },
114
123
  "scripts": {
115
124
  "build": "rslib build",
116
- "test": "rstest"
125
+ "test": "rstest",
126
+ "test:types": "tsc -p tests/types/tsconfig.json"
117
127
  },
118
128
  "homepage": "https://github.com/ultramodernjs/ultramodern.js#readme",
119
129
  "bugs": {
120
130
  "url": "https://github.com/ultramodernjs/ultramodern.js/issues"
121
- },
122
- "ultramodern": {
123
- "sourceName": "@modern-js/renderer-solid"
124
131
  }
125
132
  }
package/src/actions.tsx CHANGED
@@ -165,7 +165,11 @@ export function createRouteAction(options: RouteActionOptions): RouteAction {
165
165
  assertRendererIdentity(options.rendererIdentity, configuredIdentity);
166
166
  }
167
167
  const identity = Object.freeze({ ...options.rendererIdentity });
168
- const client = createDataClient(routeId, identity, { fetch: options.fetch });
168
+ const client = createDataClient(
169
+ routeId,
170
+ identity,
171
+ options.fetch ? { fetch: options.fetch } : {},
172
+ );
169
173
  // Capture the request while the native SSR request scope is active.
170
174
  const requestURL = getRequestEvent()?.request.url;
171
175
  const url = () => {
@@ -1,5 +1,6 @@
1
1
  import { DataProtocolError } from '@modern-js/renderer-core/data';
2
- import { type JSX, useHead } from '@solidjs/web';
2
+ import type { RequestSession } from '@modern-js/renderer-core/session';
3
+ import { getRequestEvent, type JSX, useHead } from '@solidjs/web';
3
4
  import type { AnyRouter, RegisteredRouter } from '@tanstack/router-core';
4
5
  import { ownApplicationRouteData } from './route-completion';
5
6
  import { toHeadTags, useTags } from './router-binding/headContentUtils';
@@ -22,10 +23,15 @@ export function ApplicationRouter<
22
23
  TRouter extends AnyRouter = RegisteredRouter,
23
24
  TDehydrated extends Record<string, unknown> = Record<string, unknown>,
24
25
  >(props: Omit<RouterProps<TRouter, TDehydrated>, 'context'>): JSX.Element {
25
- if (Object.hasOwn(props, 'context'))
26
- throw new DataProtocolError(
26
+ if (Object.hasOwn(props, 'context')) {
27
+ const error = new DataProtocolError(
27
28
  'Set public Solid router context in createApplicationRouter; ApplicationRouter context overrides are unsupported',
28
29
  );
30
+ const session: RequestSession | undefined =
31
+ getRequestEvent()?.locals.session;
32
+ session?.fail(error);
33
+ throw error;
34
+ }
29
35
  const { router, ...rest } = props;
30
36
  ownApplicationRouteData(router);
31
37
  return (
@@ -27,6 +27,7 @@ export function startNativeClient(options: SolidClientEntryOptions): void {
27
27
  readBootstrap: readSolidDocumentBootstrap,
28
28
  createRouter: (application, routerOptions) =>
29
29
  createNativeRouter(application, routerOptions, solidRouterFactory),
30
+ disposeRouter: router => router.history.destroy(),
30
31
  async prepareRouter(router, hydrating) {
31
32
  // Hydration adopts the server's matches; a fresh mount loads its own.
32
33
  if (!hydrating) await router.load();
@@ -1,4 +1,4 @@
1
- import { remoteBrowserAssets } from '@modern-js/renderer-core/federation';
1
+ import type { FederatedAssets } from '@modern-js/renderer-core/federation';
2
2
  import type { SolidFederationScope } from './federation-context';
3
3
 
4
4
  /**
@@ -10,17 +10,39 @@ import type { SolidFederationScope } from './federation-context';
10
10
  /** Asset keys for server-rendered remotes, e.g. `ultramodern-federation:remote/Widget`. */
11
11
  export const FEDERATED_ASSET_PREFIX = 'ultramodern-federation:';
12
12
 
13
- /** The host's server state for a remote: its browser assets and hydration module. */
14
- export function federatedServerAssets(
15
- scope: SolidFederationScope | undefined,
13
+ interface CapturedServerAssets {
14
+ readonly hydration: string;
15
+ readonly assets: FederatedAssets;
16
+ }
17
+
18
+ const capturedAssets = new WeakMap<
19
+ SolidFederationScope,
20
+ Map<string, CapturedServerAssets>
21
+ >();
22
+
23
+ /** Retain the assets admitted with this module until its response resolves them. */
24
+ export function captureFederatedServerAssets(
25
+ scope: SolidFederationScope,
16
26
  id: string,
17
- ) {
18
- const instance = scope?.instance;
19
- const assets = instance && remoteBrowserAssets(instance, id);
20
- if (!assets || !scope?.hydrationModule || !instance.name) return undefined;
27
+ assets: FederatedAssets | undefined,
28
+ ): string | undefined {
29
+ const instance = scope.instance;
30
+ if (!assets || !scope.hydrationModule || !instance?.name) return undefined;
21
31
  // The browser module finds this host by name among the realm's instances.
22
32
  const hydration = `${scope.hydrationModule}?id=${encodeURIComponent(id)}&host=${encodeURIComponent(instance.name)}`;
23
- return { hydration, assets };
33
+ let records = capturedAssets.get(scope);
34
+ if (!records) {
35
+ records = new Map();
36
+ capturedAssets.set(scope, records);
37
+ }
38
+ const baseKey = federatedAssetKey(id);
39
+ let key = baseKey;
40
+ // Two loads of one remote may straddle a development revision in one response.
41
+ // Give each loaded module its own key rather than replacing earlier assets.
42
+ for (let revision = 1; records.has(key); revision += 1)
43
+ key = `${baseKey}:${revision}`;
44
+ records.set(key, { hydration, assets });
45
+ return key;
24
46
  }
25
47
 
26
48
  export function federatedAssetKey(id: string): string {
@@ -103,10 +125,7 @@ export function withFederatedAssets<Manifest>(
103
125
  const resolve = (key: string): ResolvedDocumentAssets | null => {
104
126
  if (!key.startsWith(FEDERATED_ASSET_PREFIX))
105
127
  return resolveStaticAssets(modules, key);
106
- const remote = federatedServerAssets(
107
- scope,
108
- key.slice(FEDERATED_ASSET_PREFIX.length),
109
- );
128
+ const remote = capturedAssets.get(scope)?.get(key);
110
129
  if (!remote) return null;
111
130
  return {
112
131
  js: [joinAssetPath(modules._base, remote.hydration), ...remote.assets.js],